83 lines
5.8 KiB
TypeScript
83 lines
5.8 KiB
TypeScript
import { CATEGORY_LABELS, GROUP_LABELS, type AssistantResult, type QueryPlan } from "../../../shared/assets/assistant.js";
|
||
|
||
/** Only simplify verified, single-scope count queries; never infer zero from missing data. */
|
||
export function simplifyCountAnswer(result: AssistantResult, question: string): boolean {
|
||
const p = result.plan;
|
||
const metric = result.metrics.find(m => m.label === CATEGORY_LABELS[p.category] && m.unit === "台");
|
||
if (result.sections?.length || p.kind !== "assets" || p.responseMode ||
|
||
p.groupBy !== "none" || p.secondaryGroupBy || p.view !== "chart" ||
|
||
(p.analysis && p.analysis !== "distribution") || p.comparePrevious || p.topN ||
|
||
result.warning || result.unanswered?.length || result.gap ||
|
||
!["complete", "empty"].includes(result.outcome || "") ||
|
||
!metric || !Number.isFinite(metric.value) || metric.value < 0 ||
|
||
!/(多少|几台|几辆|数量|总数)/.test(question) ||
|
||
/(分别|各|分布|占比|比例|运营率|对比|比较|趋势|变化|原因|为什么|分析|明细|清单|列表|表格|图表|排行|最多|最少|以及|和|与|、)/.test(question)) return false;
|
||
const scope = result.scope || resultScope(p, null);
|
||
const filters = scope.filters.slice(1);
|
||
result.conciseCount = true;
|
||
result.summary = `${scope.company}${filters.length ? `,${filters.join(",")}` : ""},当前${CATEGORY_LABELS[p.category]}为 ${metric.value.toLocaleString()} 台。`;
|
||
result.metrics = [metric];
|
||
result.suggestions = [];
|
||
// A successful zero count is an answer, not a query failure or missing dataset.
|
||
result.outcome = "complete";
|
||
delete result.presentation;
|
||
delete result.presentationStatus;
|
||
delete result.presentationWarning;
|
||
return true;
|
||
}
|
||
|
||
export function resultScope(plan: QueryPlan, subject: string | null): NonNullable<AssistantResult["scope"]> {
|
||
const filters = [
|
||
plan.kind === "flow" ? "交退换车业务" : CATEGORY_LABELS[plan.category],
|
||
...Object.entries(plan.filters).map(([key, values]) => `${GROUP_LABELS[key as keyof typeof GROUP_LABELS]}:${values.join("、")}`),
|
||
...Object.entries(plan.excludeFilters || {}).map(([key, values]) => `排除${GROUP_LABELS[key as keyof typeof GROUP_LABELS]}:${values.join("、")}`),
|
||
...(plan.vehicleIds ? [`指定 ${plan.vehicleIds.length} 台车辆`] : []),
|
||
...(plan.exception ? [{ overdue: "异动已超预计完成时间", dueSoon: "异动未来7天到期", missingDueDate: "异动未填写预计完成时间" }[plan.exception]] : []),
|
||
];
|
||
const definitions = plan.responseMode === "vehicle-status" ? ["状态来自当前资产台账,不代表车辆实时位置、行驶或故障状态。", "运营状态、库存归属、异动及待交车分别展示,不互相替代。"] : plan.kind === "flow" ? [
|
||
"按运维签章日期统计业务车次,替换交车已计入交车,不能重复相加。",
|
||
"按当前账号本人或部门权限及当前筛选条件查询流转记录(全量权限不受此限);车次差额不代表净增车辆,增减本身不能证明经营改善。",
|
||
] : [
|
||
"库存含可运营、待运营、异动及待交车;异动、待交车是库存子集,不与总库存相加。",
|
||
"待运营是运营状态,待交车是交车流程状态,两者不可替代。",
|
||
"运营率 = 当前筛选范围内运营车辆数 ÷ 当前筛选范围内车辆总数。",
|
||
"车型按吨位归类;4.5T包含普货和冷链,车型细分可拆开查看,与首页分开展示的口径不同。",
|
||
];
|
||
if (plan.topN) definitions.push(`仅展示前 ${plan.topN} 个分组,指标总量和占比仍按完整筛选范围计算。`);
|
||
return {
|
||
company: subject || "全部公司(当前账号可见)",
|
||
permission: plan.kind === "flow" ? "交退换记录沿用当前账号原有数据权限" : "库存(含待交车、异动)全量可见,非库存车辆按当前账号数据权限查看",
|
||
filters,
|
||
grouping: plan.kind === "flow" ? "按日" : plan.groupBy === "none" ? "不分组" : `按${GROUP_LABELS[plan.groupBy]}${plan.secondaryGroupBy ? ` × ${GROUP_LABELS[plan.secondaryGroupBy]}` : ""}`,
|
||
period: plan.kind === "flow" ? `${plan.start} 至 ${plan.end}(含首尾日期)` : "当前车辆状态(非历史快照)",
|
||
definitions,
|
||
sourceUpdatedAt: null,
|
||
};
|
||
}
|
||
|
||
export function followupSuggestions(result: AssistantResult): string[] {
|
||
const p = result.plan;
|
||
if (p.responseMode === "vehicle-status") return result.rows.length ? ["查看全部库存"] : ["取消所有筛选"];
|
||
if (p.kind === "clarify") return [...new Set(result.suggestions || [])].slice(0, 3);
|
||
const suggestions: string[] = [];
|
||
if (p.kind === "flow") {
|
||
if (!p.comparePrevious) suggestions.push("与上一等长周期对比");
|
||
if (p.view !== "list") suggestions.push("查看交退换车明细");
|
||
if (p.view !== "table") suggestions.push("按天用表格展示");
|
||
return suggestions.slice(0, 3);
|
||
}
|
||
if (!result.rows.length) {
|
||
if (Object.keys(p.filters).length || Object.keys(p.excludeFilters || {}).length || p.exception || p.vehicleIds) suggestions.push("取消所有筛选");
|
||
if (p.category !== "all") suggestions.push("查看全部资产");
|
||
return suggestions;
|
||
}
|
||
if (p.analysis === "briefing") suggestions.push("按车型细分查看当前库存");
|
||
else {
|
||
const next = ["vehicleClass", "region", "city", "model", "department"].find(d => d !== p.groupBy && d !== p.secondaryGroupBy && !p.filters[d as keyof typeof p.filters] && (d !== "vehicleClass" || p.groupBy === "type" || p.filters.type?.includes("4.5T")));
|
||
if (next) suggestions.push(`保持当前筛选,按${GROUP_LABELS[next as keyof typeof GROUP_LABELS]}拆分`);
|
||
}
|
||
if (p.view !== "list") suggestions.push("查看当前范围车辆明细");
|
||
if (p.category === "inventory" && !p.exception) suggestions.push("当前库存中待交车有多少");
|
||
return suggestions.slice(0, 3);
|
||
}
|