from pathlib import Path root=Path('C:/kefu') p=root/'wechat_rpa/knowledge_review.py';s=p.read_text(encoding='utf-8').replace(" db.execute('INSERT INTO knowledge_review_job", " db.execute(\"UPDATE knowledge_review_job SET status='expired' WHERE created_by=? AND status='preview'\", (actor,))\n db.execute('INSERT INTO knowledge_review_job") s=s.replace("COALESCE(k.title,'知识已删除') title FROM knowledge_review_target", """COALESCE(k.title,'知识已删除') title, COALESCE((SELECT id FROM desktop_accounts WHERE tenant_id=t.tenant_id LIMIT 1),0) account_id, COALESCE((SELECT CASE WHEN nickname='' THEN zyt_sn ELSE nickname||'('||zyt_sn||')' END FROM desktop_accounts WHERE tenant_id=t.tenant_id LIMIT 1),'旧版未归属数据') account_name FROM knowledge_review_target""") p.write_text(s,encoding='utf-8',newline='\n') p=root/'admin-web/apps/web-antd/src/api/knowledge.ts';s=p.read_text(encoding='utf-8');s+=''' export interface KnowledgeReviewJob { id: string; account_id: number; scope_label: string; status: string; total: number; processed: number; approved: number; skipped: number; error: string; created_at: string; progress_percent: number; preview: { total: number; eligible: number; blocked: number; snapshot_at: string; reasons: { code: string; reason: string; count: number }[]; accounts: { tenant_id: string; name: string; total: number; eligible: number }[] }; } export interface KnowledgeReviewResult { item_id: string; tenant_id: string; revision: number; result: string; reason: string; reason_text: string; title: string; account_id: number; account_name: string; } export const previewKnowledgeReview = (accountId: number) => requestClient.post(path('review-tasks/preview', accountId), {}, { timeout: 120000 }); export const fetchKnowledgeReviewJobs = (signal?: AbortSignal) => requestClient.get<{ items: KnowledgeReviewJob[] }>('/knowledge/review-tasks', { signal }); export const knowledgeReviewAction = (jobId: string, action: string, confirmed = false) => requestClient.post(`/knowledge/review-tasks/${jobId}/${action}`, { confirmed }); export const fetchKnowledgeReviewResults = (jobId: string, result: string, page: number) => requestClient.get<{ items: KnowledgeReviewResult[]; total: number }>(`/knowledge/review-tasks/${jobId}/results`, { params: { result, page } }); ''';p.write_text(s,encoding='utf-8',newline='\n') p=root/'admin-web/apps/web-antd/src/views/knowledge/center.vue';s=p.read_text(encoding='utf-8') s=s.replace('KnowledgeItem, KnowledgeJob,', 'KnowledgeItem, KnowledgeJob, KnowledgeReviewJob,') s=s.replace('exportKnowledge, fetchKnowledgeItem,', 'exportKnowledge, fetchKnowledgeReviewJobs, fetchKnowledgeItem,') s=s.replace("import KnowledgeBatchDialog from './batch-dialog.vue';", "import KnowledgeBatchDialog from './batch-dialog.vue';\nimport KnowledgeReviewAll from './review-all.vue';") s=s.replace('const jobs = ref([]);', "const jobs = ref([]);\nconst reviewJobs = ref([]);\nconst reviewOpen = ref(false);\nconst reviewTab = ref('new');\nfunction openFullReview(view: string) { reviewTab.value = view; reviewOpen.value = true; }\nasync function inspectReviewed(itemId: string, targetAccount: number) {\n reviewOpen.value = false; accountId.value = targetAccount;\n await accountChanged();\n if (accountId.value === targetAccount) await inspect(itemId);\n}") s=s.replace('const [summary, entries, tasks, logs] = await Promise.all([', 'const [summary, entries, tasks, logs, reviews] = await Promise.all([') s=s.replace("canTrace.value ? fetchKnowledgeTraces(id, signal) : Promise.resolve({ items: [] }),", "canTrace.value ? fetchKnowledgeTraces(id, signal) : Promise.resolve({ items: [] }),\n canReview.value ? fetchKnowledgeReviewJobs(signal) : Promise.resolve({ items: [] }),") s=s.replace('return { summary, entries, tasks, logs };', 'return { summary, entries, tasks, logs, reviews };') s=s.replace('jobs.value = data.tasks.items; traces.value', 'jobs.value = data.tasks.items; reviewJobs.value = data.reviews.items; traces.value') s=s.replace("!jobs.value.some((j) => ['queued', 'running'].includes(j.status))", "![...jobs.value, ...reviewJobs.value].some((j) => ['queued', 'running'].includes(j.status))") s=s.replace('busy || createOpen || batchOpen || configOpen', 'busy || createOpen || batchOpen || configOpen || reviewOpen') s=s.replace("message=\"当前汇总全部授权账号。整理、审核、发布和测试前,请选择具体账号。\"", "message=\"当前汇总全部授权账号,可一键审核全部授权账号的草稿。整理聊天、单条编辑、发布和检索测试需选择具体账号。\"") needle=' 后台审核进行中 '''+needle) s=s.replace(' \n