diff --git a/docs/BRD_IMPLEMENTATION_AUDIT.md b/docs/BRD_IMPLEMENTATION_AUDIT.md index 996ec1ef..0e39765f 100644 --- a/docs/BRD_IMPLEMENTATION_AUDIT.md +++ b/docs/BRD_IMPLEMENTATION_AUDIT.md @@ -224,3 +224,4 @@ - 2026-07-14 BRD 6.3 模型配置回退语义复核:模型供应商/模型接口失败时原先会静默保留内置默认清单,仅通过一次性 toast 提示;现增加持久的“当前显示内置默认清单,不代表真实租户配置”提示,接口恢复后自动消失。该修复不改变模型配置、密钥或调用降级规则。 - 2026-07-14 BRD 6.3 提示词模板回退语义复核:模型配置页的提示词模板接口失败时原先直接显示空列表,无法区分真实无模板与接口不可用;现增加持久的“当前列表不代表真实租户模板数据”提示,接口恢复后自动消失。该修复不创建默认模板,也不改变模板写入权限。 - 2026-07-14 BRD 6.3 AI 面试记录回退语义复核:面试记录接口成功返回空列表时原先会错误替换为内置历史记录,接口失败时也只静默回退;现保留真实空列表,仅失败时展示演示记录并增加持久提示“当前显示演示记录,不代表真实面试数据”。该修复不改变面试题生成、评分或复核流程。 +- 2026-07-14 BRD 6.3 复盘与 SOP 数据来源复核:复盘页在试点指标接口失败时原先用待复盘记录数代替校准样本数,现改为显示未知并持久提示接口不可用;SOP 文档表继续保留断网演示样例,但为内置演示/已上传记录增加来源标识和提示,避免把演示文档或列表数量误当真实库覆盖与 M5 指标。 diff --git a/frontend/src/api/aihr/sop.ts b/frontend/src/api/aihr/sop.ts index 98ea095d..d88c0fb0 100644 --- a/frontend/src/api/aihr/sop.ts +++ b/frontend/src/api/aihr/sop.ts @@ -25,6 +25,7 @@ export type SopRecord = { status: string; owner: string; summary: string; + source?: 'demo' | 'uploaded' | string; }; export type SopSearchResponse = { diff --git a/frontend/src/views/knowledge/sop.vue b/frontend/src/views/knowledge/sop.vue index 353e920f..cfd2d550 100644 --- a/frontend/src/views/knowledge/sop.vue +++ b/frontend/src/views/knowledge/sop.vue @@ -140,11 +140,26 @@

知识库文档

+ + + + @@ -302,7 +317,8 @@ const seedRecords = [ version: 'v1.0', status: '已入库', owner: '品质组', - summary: '业主投诉的接待、记录、派单、反馈和闭环确认。' + summary: '业主投诉的接待、记录、派单、反馈和闭环确认。', + source: 'demo' }, { title: '催缴沟通 SOP v1.0', @@ -310,7 +326,8 @@ const seedRecords = [ version: 'v1.0', status: '已入库', owner: '财务组', - summary: '缴费提醒、费用争议回应、服务问题承接。' + summary: '缴费提醒、费用争议回应、服务问题承接。', + source: 'demo' }, { title: '报修跟进 SOP v1.0', @@ -318,7 +335,8 @@ const seedRecords = [ version: 'v1.0', status: '待审核', owner: '工程组', - summary: '报修接单、派工、现场反馈、复核关闭。' + summary: '报修接单、派工、现场反馈、复核关闭。', + source: 'demo' } ]; @@ -427,7 +445,8 @@ async function handleDocSelected(uploadFile: UploadFile) { version: '上传', 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} 个片段`); diff --git a/frontend/src/views/train/reviews.vue b/frontend/src/views/train/reviews.vue index 141baf29..3359c740 100644 --- a/frontend/src/views/train/reviews.vue +++ b/frontend/src/views/train/reviews.vue @@ -22,9 +22,18 @@ + +
- 校准样本{{ metrics.calibrationCount }} / 20 + 校准样本{{ calibrationMetric }}
分档一致率{{ metrics.consistency }} @@ -169,9 +178,11 @@ const selectedProjectCode = ref(''); const selectedExtPartyId = ref(''); const selectedPosition = ref('生活顾问'); const exporting = ref(false); +const reviewsFallback = ref(false); +const metricsFallback = ref(false); const startDate = ref('2026-07-01'); const endDate = ref('2026-07-31'); -const metrics = reactive({ calibrationCount: 0, consistency: '--', sopUsable: '--', ready: false }); +const metrics = reactive({ calibrationCount: null as number | null, consistency: '--', sopUsable: '--', ready: false }); const audioSources = ref>({}); const audioLoading = ref>({}); const audioErrors = ref>({}); @@ -189,6 +200,7 @@ const reviewForm = reactive({ const orgPeople = computed(() => orgSnapshot.value?.rows || []); const visibleReviews = computed(() => reviews.value); +const calibrationMetric = computed(() => (metrics.calibrationCount === null ? '--' : `${metrics.calibrationCount} / 20`)); type ReviewDialogueTurn = ReviewDetail['dialogue'][number]; const audioKey = (index: number) => `${detail.value?.id || 'review'}-${index}`; @@ -251,8 +263,13 @@ const loadReviews = async () => { limit: 50 }); reviews.value = result.data || []; + reviewsFallback.value = false; await selectFirstVisibleReview(); } catch (error) { + reviews.value = []; + detail.value = null; + releaseAudioSources(); + reviewsFallback.value = true; ElMessage.error('待复盘列表加载失败'); } finally { loading.value = false; @@ -262,10 +279,11 @@ const loadReviews = async () => { const loadMetrics = async () => { const dateWindow = pilotDateWindow.value; if (!dateWindow) { - metrics.calibrationCount = 0; + metrics.calibrationCount = null; metrics.consistency = '--'; metrics.sopUsable = '--'; metrics.ready = false; + metricsFallback.value = false; return; } try { @@ -276,11 +294,13 @@ const loadMetrics = async () => { metrics.consistency = value('ai_human_band_consistency_rate') || '--'; metrics.sopUsable = value('sop_answer_usable_rate') || '--'; metrics.ready = value('pilot_metric_ready') === 'true'; + metricsFallback.value = false; } catch { - metrics.calibrationCount = reviews.value.length; + metrics.calibrationCount = null; metrics.consistency = '--'; metrics.sopUsable = '--'; metrics.ready = false; + metricsFallback.value = true; } }; diff --git a/scripts/demo-check.sh b/scripts/demo-check.sh index 178d95e1..3c097603 100755 --- a/scripts/demo-check.sh +++ b/scripts/demo-check.sh @@ -397,6 +397,8 @@ contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service contains frontend/src/views/index.vue "待同步" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java "核心流程待确认" contains frontend/src/views/knowledge/sop.vue "训练题已生成" +contains frontend/src/views/knowledge/sop.vue "不代表这些文档已真实入库" +contains frontend/src/views/knowledge/sop.vue "内置演示" contains frontend/src/views/knowledge/processing.vue "当前显示演示数据,不代表真实库统计" contains frontend/src/views/knowledge/cases.vue "不代表真实案例库数据" contains frontend/src/views/recruit/interview.vue "不代表真实面试数据" @@ -455,6 +457,7 @@ contains frontend/src/views/train/practice.vue "提示词模板" contains frontend/src/views/train/practice.vue "导出试点CSV" contains frontend/src/views/train/reviews.vue "导出试点 CSV" contains frontend/src/views/train/reviews.vue "人工校准总分" +contains frontend/src/views/train/reviews.vue "不展示演示复盘记录或猜测性试点指标" contains frontend/src/api/aihr/practice.ts "/api/train/practice/export" contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrPracticeSeedService.java "final_adopted_score" contains backend/script/sql/aihr_practice_mysql8.sql "aihr_practice_calibration"