import type { TableColumnType } from 'antdv-next'; import type { PropType } from 'vue'; import type { WordpressBlogApi } from '#/api/blog'; import type { KtTableApi, KtTableButton, KtTableRowAction, } from '#/components/ktTable'; import { computed, defineComponent, onMounted, ref, watch } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import { Page, useVbenModal } from '@vben/common-ui'; import { Plus } from '@vben/icons'; import { message } from 'antdv-next'; import { useVbenForm } from '#/adapter/form'; import { createCategory, createTag, deleteCategory, deleteTag, getCategoryList, getTagList, updateCategory, updateTag, } from '#/api/blog'; import { KtTable, useKtTable } from '#/components/ktTable'; import { setBlogArticleFilters } from './use-article-filters'; type TermSearchValues = { search?: string; }; const AKtTable = KtTable as any; export default defineComponent({ name: 'BlogTermManagement', props: { kind: { required: true, type: String as PropType<'category' | 'tag'>, }, title: { required: true, type: String, }, }, setup(props) { const route = useRoute(); const router = useRouter(); const editingId = ref(); const tableRows = ref([]); const parentOptions = computed(() => tableRows.value .filter((item) => item.id !== editingId.value) .map((item) => ({ label: item.name, value: item.id })), ); const [TermForm, termFormApi] = useVbenForm({ commonConfig: { labelClass: 'w-24', }, layout: 'horizontal', schema: [ { component: 'Input', componentProps: () => ({ placeholder: `请输入${props.title}名称`, }), fieldName: 'name', label: '名称', rules: 'required', }, { component: 'Input', componentProps: { placeholder: '可选,默认由名称生成', }, fieldName: 'slug', label: '别名', }, { component: 'Select', componentProps: () => ({ allowClear: true, options: parentOptions.value, placeholder: '选择父级分类', }), dependencies: { if: () => props.kind === 'category', triggerFields: ['name'], }, fieldName: 'parent', label: '父级分类', }, { component: 'Textarea', componentProps: { autoSize: { maxRows: 6, minRows: 3 }, placeholder: '可选', }, fieldName: 'description', label: '描述', }, ], showDefaultActions: false, wrapperClass: 'grid-cols-1', }); const modalTitle = computed(() => editingId.value ? `编辑${props.title}` : `新建${props.title}`, ); const [TermModal, termModalApi] = useVbenModal({ class: 'w-[620px]', fullscreenButton: false, async onConfirm() { await submitTerm(); }, onOpenChange(isOpen: boolean) { if (!isOpen) return; const { values } = termModalApi.getData<{ values?: WordpressBlogApi.TermBody; }>(); void resetTermForm(values || getTermFormDefaults()); }, }); const permissionModule = computed(() => props.kind === 'category' ? 'Blog:Category' : 'Blog:Tag', ); const columns = computed>>( () => [ { dataIndex: 'name', key: 'name', title: '名称', width: 220 }, { dataIndex: 'slug', key: 'slug', title: '别名', width: 180 }, { dataIndex: 'count', key: 'count', title: '文章数', width: 100 }, { dataIndex: 'description', key: 'description', title: '描述', width: 300, }, ], ); const api: KtTableApi = { list: async (params) => { const requestParams = { hide_empty: false, pageNo: params.pageNo, pageSize: params.pageSize, search: params.search, }; return props.kind === 'category' ? await getCategoryList(requestParams) : await getTagList(requestParams); }, }; const buttons = computed< Array> >(() => [ { icon: , key: 'create', label: `新建${props.title}`, onClick: openCreate, permissionCodes: [`${permissionModule.value}:Create`], type: 'primary', }, ]); const rowActions = computed< Array> >(() => [ { key: 'articles', label: '查看文章', onClick: openRelatedArticles, permissionCodes: ['Blog:Article:List'], }, { key: 'edit', label: '编辑', onClick: openEdit, permissionCodes: [`${permissionModule.value}:Edit`], }, { confirm: (row) => `确认删除${props.title}「${row.name}」吗?本操作不会删除已关联文章。`, danger: true, key: 'delete', label: '删除', onClick: async (row, context) => { await (props.kind === 'category' ? deleteCategory(row.id) : deleteTag(row.id)); message.success(`${props.title}删除成功`); await context.reload(); }, permissionCodes: [`${permissionModule.value}:Delete`], }, ]); const [registerTable, tableApi] = useKtTable< WordpressBlogApi.Term, TermSearchValues >({ afterFetch: (result) => { tableRows.value = Array.isArray(result) ? result : result.list || result.records || result.items || []; return result; }, api, buttons: buttons.value, columns: columns.value, formOptions: { schema: [ { component: 'Input', componentProps: { allowClear: true, placeholder: `搜索${props.title}名称`, }, fieldName: 'search', label: '关键词', }, ], }, immediate: false, rowActions: rowActions.value, tableTitle: props.title, }); function getRouteSearch() { const value = route.query.search; return Array.isArray(value) ? value[0] || '' : value || ''; } function syncTableProps() { tableApi.setProps({ buttons: buttons.value, columns: columns.value, formOptions: { schema: [ { component: 'Input', componentProps: { allowClear: true, placeholder: `搜索${props.title}名称`, }, fieldName: 'search', label: '关键词', }, ], }, rowActions: rowActions.value, tableTitle: props.title, }); } function getTermFormDefaults(): WordpressBlogApi.TermBody { return { description: '', name: '', parent: undefined, slug: '', }; } async function resetTermForm(values: WordpressBlogApi.TermBody) { await termFormApi.resetForm(); await termFormApi.setValues(values); await termFormApi.resetValidate(); } function openCreate() { editingId.value = undefined; termModalApi.setData({ values: getTermFormDefaults() }).open(); } function openEdit(row: WordpressBlogApi.Term) { editingId.value = row.id; termModalApi .setData({ values: { description: row.description || '', id: row.id, name: row.name, parent: row.parent || undefined, slug: row.slug || '', }, }) .open(); } async function submitTerm() { const { valid } = await termFormApi.validate(); if (!valid) return; const values = await termFormApi.getValues(); const name = values.name?.trim(); if (!name) { message.warning(`请填写${props.title}名称`); return; } termModalApi.lock(); try { const payload = { ...values, id: editingId.value, name, }; if (props.kind === 'category') { await (editingId.value ? updateCategory(payload) : createCategory(payload)); } else { await (editingId.value ? updateTag(payload) : createTag(payload)); } message.success(`${props.title}保存成功`); await termModalApi.close(); await tableApi.reload(); } finally { termModalApi.unlock(); } } function openRelatedArticles(row: WordpressBlogApi.Term) { setBlogArticleFilters( props.kind === 'category' ? { categories: [row.name] } : { tags: [row.name] }, ); router.push({ name: 'BlogArticle', }); } async function reloadWithRouteSearch() { syncTableProps(); await tableApi.setSearchValues({ search: getRouteSearch() }); await tableApi.reload(); } watch( () => props.kind, () => { reloadWithRouteSearch(); }, ); onMounted(() => { reloadWithRouteSearch(); }); return () => ( { const term = record as WordpressBlogApi.Term; if (column.key === 'description') { return ( {term.description || '-'} ); } return undefined; }, }} /> ); }, });