fix(aihr): clarify review and SOP data provenance

This commit is contained in:
2026-07-14 12:30:47 +08:00
parent e6b3ad11bc
commit 7ca03f8240
5 changed files with 52 additions and 8 deletions
+1
View File
@@ -25,6 +25,7 @@ export type SopRecord = {
status: string;
owner: string;
summary: string;
source?: 'demo' | 'uploaded' | string;
};
export type SopSearchResponse = {
+23 -4
View File
@@ -140,11 +140,26 @@
<el-icon><Tickets /></el-icon>
<h2>知识库文档</h2>
</div>
<el-alert
v-if="records.some((item) => item.source === 'demo')"
class="record-warning"
type="warning"
:closable="false"
show-icon
title="列表含内置演示记录,不代表这些文档已真实入库。"
/>
<el-table :data="records" size="small" class="record-table">
<el-table-column prop="title" label="文档" min-width="180" />
<el-table-column prop="category" label="分类" width="140" />
<el-table-column prop="version" label="版本" width="100" />
<el-table-column prop="status" label="状态" width="120" />
<el-table-column label="来源" width="110">
<template #default="{ row }">
<el-tag :type="row.source === 'demo' ? 'warning' : 'success'" size="small">
{{ row.source === 'demo' ? '内置演示' : '已上传' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="owner" label="维护人" width="120" />
<el-table-column prop="summary" label="摘要" min-width="300" />
</el-table>
@@ -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} 个片段`);
+24 -4
View File
@@ -22,9 +22,18 @@
</el-select>
</section>
<el-alert
v-if="reviewsFallback || metricsFallback"
class="data-warning"
type="warning"
:closable="false"
show-icon
title="部分真实数据接口暂不可用;当前页面不展示演示复盘记录或猜测性试点指标。"
/>
<section class="metric-grid">
<div class="metric-card">
<span>校准样本</span><strong>{{ metrics.calibrationCount }} / 20</strong>
<span>校准样本</span><strong>{{ calibrationMetric }}</strong>
</div>
<div class="metric-card">
<span>分档一致率</span><strong>{{ metrics.consistency }}</strong>
@@ -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<Record<string, string>>({});
const audioLoading = ref<Record<string, boolean>>({});
const audioErrors = ref<Record<string, string>>({});
@@ -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;
}
};