feat(ops): kb doc edit, validation auto-tickets, support batch ops

Add knowledge document GET/PUT and admin edit UI; auto-create support tickets on client 400 validation errors across user/shop/partner apps; batch create tasks and publish from support tickets; restore mini-user store env single-column layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-05 00:08:40 +08:00
parent 16c386f165
commit 02d89e6385
18 changed files with 677 additions and 24 deletions
+92 -19
View File
@@ -18,6 +18,7 @@ import type { ColumnsType } from 'antd/es/table';
import { UploadOutlined } from '@ant-design/icons';
import type {
KnowledgeBaseDto,
KnowledgeDocumentDetailDto,
KnowledgeDocumentDto,
} from '@dukang/shared-types';
import { request } from '../lib/api';
@@ -49,6 +50,10 @@ export default function KnowledgeBasesPage() {
const [docsLoading, setDocsLoading] = useState(false);
const [docModalOpen, setDocModalOpen] = useState(false);
const [docSaving, setDocSaving] = useState(false);
const [editingDoc, setEditingDoc] = useState<KnowledgeDocumentDto | null>(null);
const [editDocModalOpen, setEditDocModalOpen] = useState(false);
const [editDocSaving, setEditDocSaving] = useState(false);
const [editDocForm] = Form.useForm<DocForm>();
const { data, loading, page, pageSize, setPage, setPageSize, reload } =
useAdminList<KnowledgeBaseDto>(
@@ -195,28 +200,52 @@ export default function KnowledgeBasesPage() {
},
{
title: '操作',
width: 80,
width: 140,
render: (_, row) =>
drawerKb?.canEditFull ? (
<Popconfirm
title="删除文档?"
onConfirm={async () => {
try {
await request(`/admin/knowledge-bases/${drawerKb.id}/documents/${row.id}`, {
method: 'DELETE',
});
message.success('已删除');
void loadDocs(drawerKb);
reload();
} catch (e) {
message.error(e instanceof Error ? e.message : String(e));
}
}}
>
<Button type="link" size="small" danger>
<Space>
<Button
type="link"
size="small"
onClick={async () => {
if (!drawerKb) return;
try {
const detail = await request<KnowledgeDocumentDetailDto>(
`/admin/knowledge-bases/${drawerKb.id}/documents/${row.id}`,
);
setEditingDoc(row);
editDocForm.setFieldsValue({
title: detail.title,
contentText: detail.contentText || '',
});
setEditDocModalOpen(true);
} catch (e) {
message.error(e instanceof Error ? e.message : String(e));
}
}}
>
</Button>
</Popconfirm>
<Popconfirm
title="删除文档?"
onConfirm={async () => {
try {
await request(`/admin/knowledge-bases/${drawerKb.id}/documents/${row.id}`, {
method: 'DELETE',
});
message.success('已删除');
void loadDocs(drawerKb);
reload();
} catch (e) {
message.error(e instanceof Error ? e.message : String(e));
}
}}
>
<Button type="link" size="small" danger>
</Button>
</Popconfirm>
</Space>
) : null,
},
];
@@ -398,6 +427,50 @@ export default function KnowledgeBasesPage() {
</Form.Item>
</Form>
</Modal>
<Modal
title="编辑知识文档"
open={editDocModalOpen}
onCancel={() => {
setEditDocModalOpen(false);
setEditingDoc(null);
}}
confirmLoading={editDocSaving}
onOk={async () => {
if (!drawerKb || !editingDoc) return;
const values = await editDocForm.validateFields();
setEditDocSaving(true);
try {
await request(`/admin/knowledge-bases/${drawerKb.id}/documents/${editingDoc.id}`, {
method: 'PUT',
body: JSON.stringify({
title: values.title,
contentText: values.contentText || null,
}),
});
message.success('已保存');
setEditDocModalOpen(false);
setEditingDoc(null);
void loadDocs(drawerKb);
reload();
} catch (e) {
message.error(e instanceof Error ? e.message : String(e));
} finally {
setEditDocSaving(false);
}
}}
destroyOnClose
width={640}
>
<Form form={editDocForm} layout="vertical">
<Form.Item name="title" label="标题" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="contentText" label="正文(可粘贴)">
<Input.TextArea rows={8} placeholder="支持 Markdown / 纯文本" />
</Form.Item>
</Form>
</Modal>
</div>
);
}