fix(aihr): clarify review and SOP data provenance
This commit is contained in:
@@ -224,3 +224,4 @@
|
|||||||
- 2026-07-14 BRD 6.3 模型配置回退语义复核:模型供应商/模型接口失败时原先会静默保留内置默认清单,仅通过一次性 toast 提示;现增加持久的“当前显示内置默认清单,不代表真实租户配置”提示,接口恢复后自动消失。该修复不改变模型配置、密钥或调用降级规则。
|
- 2026-07-14 BRD 6.3 模型配置回退语义复核:模型供应商/模型接口失败时原先会静默保留内置默认清单,仅通过一次性 toast 提示;现增加持久的“当前显示内置默认清单,不代表真实租户配置”提示,接口恢复后自动消失。该修复不改变模型配置、密钥或调用降级规则。
|
||||||
- 2026-07-14 BRD 6.3 提示词模板回退语义复核:模型配置页的提示词模板接口失败时原先直接显示空列表,无法区分真实无模板与接口不可用;现增加持久的“当前列表不代表真实租户模板数据”提示,接口恢复后自动消失。该修复不创建默认模板,也不改变模板写入权限。
|
- 2026-07-14 BRD 6.3 提示词模板回退语义复核:模型配置页的提示词模板接口失败时原先直接显示空列表,无法区分真实无模板与接口不可用;现增加持久的“当前列表不代表真实租户模板数据”提示,接口恢复后自动消失。该修复不创建默认模板,也不改变模板写入权限。
|
||||||
- 2026-07-14 BRD 6.3 AI 面试记录回退语义复核:面试记录接口成功返回空列表时原先会错误替换为内置历史记录,接口失败时也只静默回退;现保留真实空列表,仅失败时展示演示记录并增加持久提示“当前显示演示记录,不代表真实面试数据”。该修复不改变面试题生成、评分或复核流程。
|
- 2026-07-14 BRD 6.3 AI 面试记录回退语义复核:面试记录接口成功返回空列表时原先会错误替换为内置历史记录,接口失败时也只静默回退;现保留真实空列表,仅失败时展示演示记录并增加持久提示“当前显示演示记录,不代表真实面试数据”。该修复不改变面试题生成、评分或复核流程。
|
||||||
|
- 2026-07-14 BRD 6.3 复盘与 SOP 数据来源复核:复盘页在试点指标接口失败时原先用待复盘记录数代替校准样本数,现改为显示未知并持久提示接口不可用;SOP 文档表继续保留断网演示样例,但为内置演示/已上传记录增加来源标识和提示,避免把演示文档或列表数量误当真实库覆盖与 M5 指标。
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export type SopRecord = {
|
|||||||
status: string;
|
status: string;
|
||||||
owner: string;
|
owner: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
|
source?: 'demo' | 'uploaded' | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SopSearchResponse = {
|
export type SopSearchResponse = {
|
||||||
|
|||||||
@@ -140,11 +140,26 @@
|
|||||||
<el-icon><Tickets /></el-icon>
|
<el-icon><Tickets /></el-icon>
|
||||||
<h2>知识库文档</h2>
|
<h2>知识库文档</h2>
|
||||||
</div>
|
</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 :data="records" size="small" class="record-table">
|
||||||
<el-table-column prop="title" label="文档" min-width="180" />
|
<el-table-column prop="title" label="文档" min-width="180" />
|
||||||
<el-table-column prop="category" label="分类" width="140" />
|
<el-table-column prop="category" label="分类" width="140" />
|
||||||
<el-table-column prop="version" label="版本" width="100" />
|
<el-table-column prop="version" label="版本" width="100" />
|
||||||
<el-table-column prop="status" label="状态" width="120" />
|
<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="owner" label="维护人" width="120" />
|
||||||
<el-table-column prop="summary" label="摘要" min-width="300" />
|
<el-table-column prop="summary" label="摘要" min-width="300" />
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -302,7 +317,8 @@ const seedRecords = [
|
|||||||
version: 'v1.0',
|
version: 'v1.0',
|
||||||
status: '已入库',
|
status: '已入库',
|
||||||
owner: '品质组',
|
owner: '品质组',
|
||||||
summary: '业主投诉的接待、记录、派单、反馈和闭环确认。'
|
summary: '业主投诉的接待、记录、派单、反馈和闭环确认。',
|
||||||
|
source: 'demo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '催缴沟通 SOP v1.0',
|
title: '催缴沟通 SOP v1.0',
|
||||||
@@ -310,7 +326,8 @@ const seedRecords = [
|
|||||||
version: 'v1.0',
|
version: 'v1.0',
|
||||||
status: '已入库',
|
status: '已入库',
|
||||||
owner: '财务组',
|
owner: '财务组',
|
||||||
summary: '缴费提醒、费用争议回应、服务问题承接。'
|
summary: '缴费提醒、费用争议回应、服务问题承接。',
|
||||||
|
source: 'demo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '报修跟进 SOP v1.0',
|
title: '报修跟进 SOP v1.0',
|
||||||
@@ -318,7 +335,8 @@ const seedRecords = [
|
|||||||
version: 'v1.0',
|
version: 'v1.0',
|
||||||
status: '待审核',
|
status: '待审核',
|
||||||
owner: '工程组',
|
owner: '工程组',
|
||||||
summary: '报修接单、派工、现场反馈、复核关闭。'
|
summary: '报修接单、派工、现场反馈、复核关闭。',
|
||||||
|
source: 'demo'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -427,7 +445,8 @@ async function handleDocSelected(uploadFile: UploadFile) {
|
|||||||
version: '上传',
|
version: '上传',
|
||||||
status: '已入库',
|
status: '已入库',
|
||||||
owner: 'MinIO',
|
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;
|
queryText.value = data.snippets[0]?.text.slice(0, 40) || queryText.value;
|
||||||
ElMessage.success(`已入库 ${data.fragments} 个片段`);
|
ElMessage.success(`已入库 ${data.fragments} 个片段`);
|
||||||
|
|||||||
@@ -22,9 +22,18 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<el-alert
|
||||||
|
v-if="reviewsFallback || metricsFallback"
|
||||||
|
class="data-warning"
|
||||||
|
type="warning"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
title="部分真实数据接口暂不可用;当前页面不展示演示复盘记录或猜测性试点指标。"
|
||||||
|
/>
|
||||||
|
|
||||||
<section class="metric-grid">
|
<section class="metric-grid">
|
||||||
<div class="metric-card">
|
<div class="metric-card">
|
||||||
<span>校准样本</span><strong>{{ metrics.calibrationCount }} / 20</strong>
|
<span>校准样本</span><strong>{{ calibrationMetric }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="metric-card">
|
<div class="metric-card">
|
||||||
<span>分档一致率</span><strong>{{ metrics.consistency }}</strong>
|
<span>分档一致率</span><strong>{{ metrics.consistency }}</strong>
|
||||||
@@ -169,9 +178,11 @@ const selectedProjectCode = ref('');
|
|||||||
const selectedExtPartyId = ref('');
|
const selectedExtPartyId = ref('');
|
||||||
const selectedPosition = ref('生活顾问');
|
const selectedPosition = ref('生活顾问');
|
||||||
const exporting = ref(false);
|
const exporting = ref(false);
|
||||||
|
const reviewsFallback = ref(false);
|
||||||
|
const metricsFallback = ref(false);
|
||||||
const startDate = ref('2026-07-01');
|
const startDate = ref('2026-07-01');
|
||||||
const endDate = ref('2026-07-31');
|
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 audioSources = ref<Record<string, string>>({});
|
||||||
const audioLoading = ref<Record<string, boolean>>({});
|
const audioLoading = ref<Record<string, boolean>>({});
|
||||||
const audioErrors = ref<Record<string, string>>({});
|
const audioErrors = ref<Record<string, string>>({});
|
||||||
@@ -189,6 +200,7 @@ const reviewForm = reactive({
|
|||||||
|
|
||||||
const orgPeople = computed(() => orgSnapshot.value?.rows || []);
|
const orgPeople = computed(() => orgSnapshot.value?.rows || []);
|
||||||
const visibleReviews = computed(() => reviews.value);
|
const visibleReviews = computed(() => reviews.value);
|
||||||
|
const calibrationMetric = computed(() => (metrics.calibrationCount === null ? '--' : `${metrics.calibrationCount} / 20`));
|
||||||
type ReviewDialogueTurn = ReviewDetail['dialogue'][number];
|
type ReviewDialogueTurn = ReviewDetail['dialogue'][number];
|
||||||
|
|
||||||
const audioKey = (index: number) => `${detail.value?.id || 'review'}-${index}`;
|
const audioKey = (index: number) => `${detail.value?.id || 'review'}-${index}`;
|
||||||
@@ -251,8 +263,13 @@ const loadReviews = async () => {
|
|||||||
limit: 50
|
limit: 50
|
||||||
});
|
});
|
||||||
reviews.value = result.data || [];
|
reviews.value = result.data || [];
|
||||||
|
reviewsFallback.value = false;
|
||||||
await selectFirstVisibleReview();
|
await selectFirstVisibleReview();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
reviews.value = [];
|
||||||
|
detail.value = null;
|
||||||
|
releaseAudioSources();
|
||||||
|
reviewsFallback.value = true;
|
||||||
ElMessage.error('待复盘列表加载失败');
|
ElMessage.error('待复盘列表加载失败');
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@@ -262,10 +279,11 @@ const loadReviews = async () => {
|
|||||||
const loadMetrics = async () => {
|
const loadMetrics = async () => {
|
||||||
const dateWindow = pilotDateWindow.value;
|
const dateWindow = pilotDateWindow.value;
|
||||||
if (!dateWindow) {
|
if (!dateWindow) {
|
||||||
metrics.calibrationCount = 0;
|
metrics.calibrationCount = null;
|
||||||
metrics.consistency = '--';
|
metrics.consistency = '--';
|
||||||
metrics.sopUsable = '--';
|
metrics.sopUsable = '--';
|
||||||
metrics.ready = false;
|
metrics.ready = false;
|
||||||
|
metricsFallback.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -276,11 +294,13 @@ const loadMetrics = async () => {
|
|||||||
metrics.consistency = value('ai_human_band_consistency_rate') || '--';
|
metrics.consistency = value('ai_human_band_consistency_rate') || '--';
|
||||||
metrics.sopUsable = value('sop_answer_usable_rate') || '--';
|
metrics.sopUsable = value('sop_answer_usable_rate') || '--';
|
||||||
metrics.ready = value('pilot_metric_ready') === 'true';
|
metrics.ready = value('pilot_metric_ready') === 'true';
|
||||||
|
metricsFallback.value = false;
|
||||||
} catch {
|
} catch {
|
||||||
metrics.calibrationCount = reviews.value.length;
|
metrics.calibrationCount = null;
|
||||||
metrics.consistency = '--';
|
metrics.consistency = '--';
|
||||||
metrics.sopUsable = '--';
|
metrics.sopUsable = '--';
|
||||||
metrics.ready = false;
|
metrics.ready = false;
|
||||||
|
metricsFallback.value = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -397,6 +397,8 @@ contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service
|
|||||||
contains frontend/src/views/index.vue "待同步"
|
contains frontend/src/views/index.vue "待同步"
|
||||||
contains backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/service/AihrDashboardService.java "核心流程待确认"
|
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/sop.vue "内置演示"
|
||||||
contains frontend/src/views/knowledge/processing.vue "当前显示演示数据,不代表真实库统计"
|
contains frontend/src/views/knowledge/processing.vue "当前显示演示数据,不代表真实库统计"
|
||||||
contains frontend/src/views/knowledge/cases.vue "不代表真实案例库数据"
|
contains frontend/src/views/knowledge/cases.vue "不代表真实案例库数据"
|
||||||
contains frontend/src/views/recruit/interview.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/practice.vue "导出试点CSV"
|
||||||
contains frontend/src/views/train/reviews.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/views/train/reviews.vue "不展示演示复盘记录或猜测性试点指标"
|
||||||
contains frontend/src/api/aihr/practice.ts "/api/train/practice/export"
|
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/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"
|
contains backend/script/sql/aihr_practice_mysql8.sql "aihr_practice_calibration"
|
||||||
|
|||||||
Reference in New Issue
Block a user