删除和更新规则

This commit is contained in:
Rewrite0
2023-05-28 00:35:00 +08:00
parent ffe1139d60
commit 4fc92de4b0
14 changed files with 284 additions and 46 deletions

View File

@@ -4,9 +4,9 @@ import { NMessageProvider } from 'naive-ui';
<template>
<Suspense>
<n-message-provider>
<NMessageProvider>
<RouterView></RouterView>
</n-message-provider>
</NMessageProvider>
</Suspense>
</template>

View File

@@ -34,7 +34,7 @@ export const apiAuth = {
const message = useMessage();
if (password.length < 8) {
message.error('密码至少8个字符!');
return;
} else {
const { data } = await axios.post<Update>('api/v1/auth/update', {
username,

View File

@@ -30,12 +30,15 @@ export const apiBangumi = {
* @returns axios 请求返回的数据
*/
async updateRule(bangumiRule: BangumiRule) {
const { data } = await axios.post('api/v1/bangumi/updateData', bangumiRule);
const { data } = await axios.post<{
msg: string;
status: 'success';
}>('api/v1/bangumi/updateRule', bangumiRule);
return data;
},
/**
* 删除指定 bangumiId 的数据
* 删除指定 bangumiId 的数据库规则,会在重新匹配到后重建
* @param bangumiId - 需要删除的 bangumi 的 id
* @returns axios 请求返回的数据
*/
@@ -53,14 +56,14 @@ export const apiBangumi = {
* @returns axios 请求返回的数据
*/
async deleteRule(bangumiId: number, file: boolean) {
const { data } = await axios.delete(
`api/v1/bangumi/deleteRule/${bangumiId}`,
{
params: {
file,
},
}
);
const { data } = await axios.delete<{
msg: string;
status: 'success';
}>(`api/v1/bangumi/deleteRule/${bangumiId}`, {
params: {
file,
},
});
return data;
},

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { Write } from '@icon-park/vue-next';
import { ErrorPicture , Write } from '@icon-park/vue-next';
withDefaults(
defineProps<{
@@ -16,7 +16,17 @@ defineEmits(['click']);
<template>
<div w-150px is-btn @click="() => $emit('click')">
<div rounded-4px overflow-hidden poster-shandow rel>
<img :src="`https://mikanani.me${poster}`" alt="poster" w-full h-210px />
<div w-full h-210px>
<template v-if="poster !== ''">
<img :src="`https://mikanani.me${poster}`" alt="poster" wh-full />
</template>
<template v-else>
<div wh-full f-cer border="1 white">
<ErrorPicture theme="outline" size="24" fill="#333" />
</div>
</template>
</div>
<div
abs

View File

@@ -0,0 +1,119 @@
<script lang="ts" setup>
import type { AbEditRule, SettingItem } from '#/components';
const emit = defineEmits<{
delete: [{ id: number; deleteFile: boolean }];
apply: [item: AbEditRule];
}>();
const show = defineModel('show', { default: false });
const item = defineModel<AbEditRule>('item', {
default: () => {
return {
id: -1,
official_title: '',
year: '',
season: 1,
offset: 0,
filter: [],
};
},
});
const deleteRuleDialog = ref(false);
watch(show, (val) => {
if (!val) {
deleteRuleDialog.value = false;
}
});
function emitDelete(deleteFile: boolean) {
emit('delete', {
id: item.value.id,
deleteFile,
});
}
function emitApply() {
emit('apply', item.value);
}
const items: SettingItem<AbEditRule>[] = [
{
configKey: 'official_title',
label: 'Officical Ttile',
type: 'input',
prop: {
type: 'text',
},
},
{
configKey: 'year',
label: 'Year',
type: 'input',
css: 'w-72px',
prop: {
type: 'text',
},
},
{
configKey: 'season',
label: 'Season',
type: 'input',
css: 'w-72px',
prop: {
type: 'number',
},
bottomLine: true,
},
{
configKey: 'offset',
label: 'Offset',
type: 'input',
css: 'w-72px',
prop: {
type: 'number',
},
},
{
configKey: 'filter',
label: 'Exclude',
type: 'dynamic-tags',
bottomLine: true,
},
];
</script>
<template>
<ab-popup v-model:show="show" title="Edit Rule" css="w-380px">
<div space-y-12px>
<ab-setting
v-for="i in items"
:key="i.configKey"
v-bind="i"
v-model:data="item[i.configKey]"
></ab-setting>
<div fx-cer justify-end space-x-10px>
<ab-button
size="small"
type="warn"
@click="() => (deleteRuleDialog = true)"
>Delete</ab-button
>
<ab-button size="small" @click="emitApply">Apply</ab-button>
</div>
</div>
<ab-popup v-model:show="deleteRuleDialog" title="Delete">
<div>Delete Local File?</div>
<div line my-8px></div>
<div fx-cer justify-center space-x-10px>
<ab-button size="small" type="warn" @click="emitDelete(true)"
>Yes</ab-button
>
<ab-button size="small" @click="emitDelete(false)">No</ab-button>
</div>
</ab-popup>
</ab-popup>
</template>

View File

@@ -1,8 +1,8 @@
<script lang="ts" setup>
import { NDynamicTags } from 'naive-ui';
import AbSwitch from '../basic/ab-switch.vue';
import AbSelect from '../basic/ab-select.vue';
import type { AbSettingProps } from '#/components';
import { NDynamicTags } from 'naive-ui';
withDefaults(defineProps<AbSettingProps>(), {
css: '',
@@ -37,8 +37,8 @@ const data = defineModel<any>('data');
v-bind="prop"
/>
<div max-w-200px v-else-if="type === 'dynamic-tags'">
<n-dynamic-tags v-model:value="data" size="small"></n-dynamic-tags>
<div v-else-if="type === 'dynamic-tags'" max-w-200px>
<NDynamicTags v-model:value="data" size="small"></NDynamicTags>
</div>
</ab-label>

View File

@@ -52,7 +52,7 @@ export const useAuth = createSharedComposable(() => {
auth.value = '';
message.success('Logout Success!');
} else {
message.error('Logout Fail!');
message.error('Logout Failed!');
}
};
@@ -66,7 +66,7 @@ export const useAuth = createSharedComposable(() => {
message.success('Update Success!');
clearUser();
} else if (res === false) {
message.error('Update Fail!');
message.error('Update Failed!');
} else {
user.password = '';
}

View File

@@ -1,8 +1,65 @@
<script lang="ts" setup>
const { data } = storeToRefs(useBangumiStore());
const { getAll } = useBangumiStore();
import type { BangumiRule } from '#/bangumi';
import { AbEditRule } from '#/components';
getAll();
const { data } = storeToRefs(useBangumiStore());
const { getAll, updateRule, removeRule } = useBangumiStore();
const editRule = reactive<{
show: boolean;
item: AbEditRule;
}>({
show: false,
item: {
id: -1,
official_title: '',
year: '',
season: 1,
offset: 0,
filter: [],
},
});
function open(data: BangumiRule) {
editRule.show = true;
editRule.item = {
id: data.id,
official_title: data.official_title,
year: data.year ?? '',
season: data.season,
offset: data.offset,
filter: data.filter,
};
}
async function deleteRule({
id,
deleteFile,
}: {
id: number;
deleteFile: boolean;
}) {
const res = await removeRule(id, deleteFile);
if (res) {
editRule.show = false;
getAll();
}
}
async function applyRule(newData: AbEditRule) {
const id = newData.id;
const oldData = await apiBangumi.getRule(id);
const data = Object.assign(oldData, newData);
const res = await updateRule(data);
if (res) {
editRule.show = false;
getAll();
}
}
onActivated(() => {
getAll();
});
definePage({
name: 'Bangumi List',
@@ -10,13 +67,22 @@ definePage({
</script>
<template>
<div flex="~ wrap" space-y-12px space-x-50px>
<div flex="~ wrap" gap-y-12px gap-x-50px>
<ab-bangumi-card
v-for="i in data"
v-show="!i.deleted"
:key="i.id"
:poster="i.poster_link"
:poster="i.poster_link ?? ''"
:name="i.official_title"
:season="i.season"
@click="open(i)"
></ab-bangumi-card>
<AbEditRule
v-model:show="editRule.show"
:item="editRule.item"
@delete="deleteRule"
@apply="applyRule"
></AbEditRule>
</div>
</template>

View File

@@ -1,12 +1,41 @@
import type { BangumiItem } from '#/bangumi';
import type { BangumiRule } from '#/bangumi';
export const useBangumiStore = defineStore('bangumi', () => {
const data = ref<BangumiItem[]>();
const message = useMessage();
const data = ref<BangumiRule[]>();
const getAll = async () => {
const res = await apiBangumi.getAll();
data.value = res;
};
return { data, getAll };
const updateRule = async (newRule: BangumiRule) => {
try {
const res = await apiBangumi.updateRule(newRule);
if (res.status === 'success') {
message.success('Update Success!');
return true;
} else {
message.error('Update Failed!');
}
} catch (error) {
message.error('Operation Failed!');
}
};
const removeRule = async (bangumiId: number, deleteFile = false) => {
try {
const res = await apiBangumi.deleteRule(bangumiId, deleteFile);
if (res.status === 'success') {
message.success(`${res.msg} Success!`);
return true;
} else {
message.error('Delete Failed!');
}
} catch (error) {
message.error('Operation Failed!');
}
};
return { data, getAll, updateRule, removeRule };
});

View File

@@ -59,9 +59,9 @@ export const useConfigStore = defineStore('config', () => {
const setConfig = async () => {
const status = await apiConfig.updateConfig(config.value);
if (status) {
message.success('apply success!');
message.success('Apply Success!');
} else {
message.error('apply fail!');
message.error('Apply Failed!');
}
};

View File

@@ -24,7 +24,7 @@ export const useProgramStore = defineStore('program', () => {
if (success) {
message.success(`${handle} Success!`);
} else {
message.error(`${handle} Fail!`);
message.error(`${handle} Failed!`);
}
}

View File

@@ -1,18 +1,21 @@
export interface BangumiItem {
export interface BangumiRule {
added: boolean;
deleted: boolean;
dpi: string;
eps_collect: boolean;
filter: string[];
group_name: string;
id: number;
official_title: string;
year: string | null;
title_raw: string;
offset: number;
poster_link: string | null;
rss_link: string[];
rule_name: string;
save_path: string;
season: number;
season_raw: string;
group_name: string;
dpi: string;
source: string;
source: string | null;
subtitle: string;
eps_collect: boolean;
offset: number;
filter: string[];
rss_link: string[];
poster_link: string;
added: boolean;
title_raw: string;
year: string | null;
}

View File

@@ -15,5 +15,13 @@ export interface AbSettingProps {
export type SettingItem<T> = AbSettingProps & {
configKey: keyof T;
data?: any;
};
export interface AbEditRule {
id: number;
official_title: string;
year: string;
season: number;
offset: number;
filter: string[];
}

View File

@@ -4,7 +4,7 @@ export type LoginError = 'Password error' | 'User not found';
export type ApiErrorMessage = AuthError | LoginError;
export type ApiError = {
export interface ApiError {
status: 401 | 404 | 422;
detail: ApiErrorMessage;
};
}