feat: govern knowledge assets and source citations

This commit is contained in:
key
2026-08-02 01:43:43 +08:00
parent cafb836cda
commit 699cc08050
144 changed files with 17205 additions and 453 deletions
File diff suppressed because it is too large Load Diff
+43 -14
View File
@@ -131,7 +131,7 @@
:loading="reviewingFeedbackId === row.id"
@click="markFeedbackReviewed(row)"
>
标记已复核
处理争议
</el-button>
<span v-else class="review-done">已复核</span>
</template>
@@ -174,7 +174,7 @@
<script setup name="KnowledgeSop" lang="ts">
import { DocumentChecked, Reading, Tickets, Upload } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import type { UploadFile } from 'element-plus';
import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
@@ -309,7 +309,7 @@ const apiPill = computed(() => {
const flowStatus = computed(() => {
if (trainingGenerated.value) return { label: '已完成闭环', type: 'pill-success' };
if (searched.value) return { label: `已命中 ${snippets.value.length} 段`, type: 'pill-primary' };
return { label: '可引用 SOP 内容', type: 'pill-success' };
return { label: '演示内容预览', type: 'pill-warning' };
});
const canReview = computed(() => apiMode.value === 'api' && Boolean(apiResult.value?.reviewId));
const reviewMessage = computed(() => {
@@ -323,7 +323,7 @@ const seedRecords = [
title: '投诉处理 SOP v1.0',
category: '投诉处理',
version: 'v1.0',
status: '已入库',
status: '演示数据',
owner: '品质组',
summary: '业主投诉的接待、记录、派单、反馈和闭环确认。',
source: 'demo'
@@ -332,7 +332,7 @@ const seedRecords = [
title: '催缴沟通 SOP v1.0',
category: '催缴沟通',
version: 'v1.0',
status: '已入库',
status: '演示数据',
owner: '财务组',
summary: '缴费提醒、费用争议回应、服务问题承接。',
source: 'demo'
@@ -423,13 +423,43 @@ async function loadPendingReviews() {
}
async function markFeedbackReviewed(row: AnswerFeedbackItem) {
reviewingFeedbackId.value = row.id;
try {
await reviewAnswerFeedback(row.id);
let reviewAction: 'KEEP' | 'WITHDRAW';
try {
await ElMessageBox.confirm(
'保留资料表示该来源经核对仍可用;撤回来源会立即停止 MySQL 检索,并排队清除向量。',
'处理答案争议',
{
confirmButtonText: '保留资料',
cancelButtonText: '撤回来源',
distinguishCancelAndClose: true,
type: 'warning'
}
);
reviewAction = 'KEEP';
} catch (choice) {
if (choice === 'close') return;
reviewAction = 'WITHDRAW';
}
const { value: note } = await ElMessageBox.prompt(
'选择“保留资料”表示该来源经核对仍可用;选择“撤回来源”会立即停止 MySQL 检索,并排队清除向量。',
reviewAction === 'KEEP' ? '填写保留依据' : '填写撤回原因',
{
confirmButtonText: '提交复核',
cancelButtonText: '取消',
inputPlaceholder: '填写复核依据或撤回原因',
inputValidator: (input) => Boolean(input?.trim()) || '请填写复核结论'
}
);
reviewingFeedbackId.value = row.id;
await reviewAnswerFeedback(row.id, {
action: reviewAction,
note: note.trim()
});
pendingReviews.value = pendingReviews.value.filter((item) => item.id !== row.id);
ElMessage.success('答案已标记为已复核');
} catch {
ElMessage.error('答案复核失败');
ElMessage.success(reviewAction === 'KEEP' ? '已记录保留依据' : '来源已撤回并进入索引清理队列');
} catch (error) {
if (error !== 'cancel' && error !== 'close') ElMessage.error('答案复核失败');
} finally {
reviewingFeedbackId.value = null;
}
@@ -461,14 +491,13 @@ async function handleDocSelected(uploadFile: UploadFile) {
title: data.fileName,
category: data.category.replace(' SOP', ''),
version: '上传',
status: '已入库',
status: '待审核',
owner: 'MinIO',
summary: `OSS #${data.ossId},已解析 ${data.fragments} 个片段`,
summary: `OSS #${data.ossId},已生成 ${data.fragments} 个候选片段,批准前不可检索`,
source: 'uploaded'
});
queryText.value = data.snippets[0]?.text.slice(0, 40) || queryText.value;
ElMessage.success(`已入库 ${data.fragments} 个片段`);
await runSearch();
ElMessage.success(`已提交审核,共 ${data.fragments} 个候选片段`);
} finally {
uploading.value = false;
}