统一前端报告卡片展示与追加逻辑
This commit is contained in:
parent
d05be62e02
commit
ca9fc9ee9d
@ -15,11 +15,12 @@ import { computed, ref } from "vue";
|
|||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
import type { AssistantResponseCard } from "@/types/conversation";
|
import type { AssistantResponseCard } from "@/types/conversation";
|
||||||
|
import type { ReportCard } from "@/types/risk";
|
||||||
|
|
||||||
const props = defineProps<{ card: AssistantResponseCard }>();
|
const props = defineProps<{ card: AssistantResponseCard }>();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
generateReport: [card: AssistantResponseCard];
|
generateReport: [card: ReportCard];
|
||||||
}>();
|
}>();
|
||||||
interface CardData extends AssistantResponseCard {
|
interface CardData extends AssistantResponseCard {
|
||||||
name?: string;
|
name?: string;
|
||||||
@ -119,7 +120,7 @@ function formatCount(value: unknown) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function generateReport() {
|
function generateReport() {
|
||||||
emit("generateReport", props.card);
|
emit("generateReport", JSON.parse(JSON.stringify(props.card)) as ReportCard);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -389,8 +390,7 @@ function generateReport() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="response-actions__primary"
|
class="response-actions__primary"
|
||||||
:disabled="card.type !== 'solution'"
|
title="追加到当前风险报告"
|
||||||
:title="card.type === 'solution' ? '追加到当前风险报告' : '功能开发中'"
|
|
||||||
@click="generateReport"
|
@click="generateReport"
|
||||||
>
|
>
|
||||||
<CheckCircle2 :size="14" />生成报告
|
<CheckCircle2 :size="14" />生成报告
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { computed } from "vue";
|
|||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
import { downloadReportPdf, downloadReportWord } from "@/api/reports";
|
import { downloadReportPdf, downloadReportWord } from "@/api/reports";
|
||||||
import type { RiskReportResult } from "@/types/risk";
|
import type { ReportCard, RiskReportResult } from "@/types/risk";
|
||||||
import { formatRiskLevel } from "@/utils/risk";
|
import { formatRiskLevel } from "@/utils/risk";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -16,6 +16,24 @@ try {
|
|||||||
parsed = null;
|
parsed = null;
|
||||||
}
|
}
|
||||||
const report = computed(() => parsed);
|
const report = computed(() => parsed);
|
||||||
|
const reportCards = computed<ReportCard[]>(
|
||||||
|
() => {
|
||||||
|
if (!report.value) return [];
|
||||||
|
if (report.value.reportCards?.length) return report.value.reportCards;
|
||||||
|
return (report.value.aiSolutionCards ?? []).map((solution) => ({
|
||||||
|
type: "solution" as const,
|
||||||
|
title: solution.title || "AI 案例推理生成",
|
||||||
|
confidence: solution.confidence,
|
||||||
|
analysisBase: solution.analysisBase,
|
||||||
|
standardFallbackEnabled: solution.standardFallbackEnabled,
|
||||||
|
standards: solution.standards,
|
||||||
|
similarCases: solution.similarCases,
|
||||||
|
risks: solution.risks,
|
||||||
|
suggestions: solution.suggestions,
|
||||||
|
warning: solution.warning,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
);
|
||||||
const dimensionRows = computed(() => {
|
const dimensionRows = computed(() => {
|
||||||
if (!report.value) return [];
|
if (!report.value) return [];
|
||||||
if (report.value.dimensionScores?.length) {
|
if (report.value.dimensionScores?.length) {
|
||||||
@ -277,47 +295,6 @@ function dimensionConclusion(item: {
|
|||||||
</template>
|
</template>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<template v-if="report.aiSolutionCards?.length">
|
|
||||||
<h3 class="report-subsection-title">AI 案例推理方案明细(已追加)</h3>
|
|
||||||
<section
|
|
||||||
v-for="(solution, index) in report.aiSolutionCards"
|
|
||||||
:key="`${solution.title || 'solution'}-${index}`"
|
|
||||||
class="ai-solution-report"
|
|
||||||
>
|
|
||||||
<header>
|
|
||||||
<strong>{{ solution.title || "AI 案例推理生成" }}</strong>
|
|
||||||
<span v-if="solution.confidence"
|
|
||||||
>置信度:{{ solution.confidence }}</span
|
|
||||||
>
|
|
||||||
</header>
|
|
||||||
<p v-if="solution.analysisBase">
|
|
||||||
<b>分析基础:</b>{{ solution.analysisBase }}
|
|
||||||
</p>
|
|
||||||
<template v-if="solution.risks?.length">
|
|
||||||
<h3>风险项</h3>
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
v-for="risk in solution.risks"
|
|
||||||
:key="`${risk.title}-${risk.detail}`"
|
|
||||||
>
|
|
||||||
<b>{{ risk.level }} · {{ risk.title }}:</b>{{ risk.detail }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</template>
|
|
||||||
<template v-if="solution.suggestions?.length">
|
|
||||||
<h3>建议方案</h3>
|
|
||||||
<ol>
|
|
||||||
<li v-for="suggestion in solution.suggestions" :key="suggestion">
|
|
||||||
{{ suggestion }}
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</template>
|
|
||||||
<p v-if="solution.warning" class="ai-solution-report__warning">
|
|
||||||
{{ solution.warning }}
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<h2>七、标准判定结果</h2>
|
<h2>七、标准判定结果</h2>
|
||||||
<template v-if="report.standardJudgment?.length">
|
<template v-if="report.standardJudgment?.length">
|
||||||
<table>
|
<table>
|
||||||
@ -347,6 +324,41 @@ function dimensionConclusion(item: {
|
|||||||
双引擎融合:历史异常经验引擎提供风险优先级,标准库提供可执行的检测阈值与验证任务。
|
双引擎融合:历史异常经验引擎提供风险优先级,标准库提供可执行的检测阈值与验证任务。
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<template v-if="reportCards.length">
|
||||||
|
<h2>八、追加卡片分析</h2>
|
||||||
|
<section
|
||||||
|
v-for="(card, index) in reportCards"
|
||||||
|
:key="`${card.type}-${card.title}-${index}`"
|
||||||
|
class="report-card-detail"
|
||||||
|
>
|
||||||
|
<header><strong>{{ card.title }}</strong><span>{{ card.type }}</span></header>
|
||||||
|
<p v-if="card.name || card.material || card.category"><b>分析对象:</b>{{ card.name || card.material || card.category }}</p>
|
||||||
|
<p v-if="card.partyType"><b>对象类型:</b>{{ card.partyType }}</p>
|
||||||
|
<p v-if="card.question"><b>原始问题:</b>{{ card.question }}</p>
|
||||||
|
<p v-if="card.anomalyCount != null"><b>历史异常:</b>{{ card.anomalyCount }} 条</p>
|
||||||
|
<p v-if="card.cooperationCount != null"><b>合作次数:</b>{{ card.cooperationCount }} 次</p>
|
||||||
|
<p v-if="card.frequencyBasis"><b>数据口径:</b>{{ card.frequencyBasis }}</p>
|
||||||
|
<p v-if="card.dataAvailable != null"><b>数据状态:</b>{{ card.dataAvailable ? "有匹配数据" : "暂无匹配数据" }}</p>
|
||||||
|
<p v-if="card.frequencyCoefficient != null"><b>频次系数:</b>×{{ card.frequencyCoefficient.toFixed(2) }}</p>
|
||||||
|
<p v-if="card.supplierBaseScore != null"><b>供应商基础分:</b>{{ card.supplierBaseScore.toFixed(2) }} 分</p>
|
||||||
|
<p v-if="card.supplierScore != null"><b>供应商得分:</b>{{ card.supplierScore.toFixed(2) }} 分</p>
|
||||||
|
<p v-if="card.tier"><b>层级:</b>{{ card.tier }}</p>
|
||||||
|
<p v-if="card.matchedCount != null"><b>匹配数量:</b>{{ card.matchedCount }} 条</p>
|
||||||
|
<p v-if="card.analysisBase"><b>分析基础:</b>{{ card.analysisBase }}</p>
|
||||||
|
<p v-if="card.confidence"><b>置信度:</b>{{ card.confidence }}</p>
|
||||||
|
<p v-if="card.standardFallbackEnabled"><b>标准兜底校验:</b>已启用(无直接历史案例)</p>
|
||||||
|
<p v-if="card.detectedValues?.length"><b>检测值:</b>{{ card.detectedValues.map((item) => `${item.name}:${item.value}`).join("、") }}</p>
|
||||||
|
<p v-if="card.topProblems?.length"><b>高频问题:</b>{{ card.topProblems.map((item) => `${item.name}(${item.count}次)`).join("、") }}</p>
|
||||||
|
<p v-if="card.frequentProblems?.length"><b>常见问题:</b>{{ card.frequentProblems.map((item) => `${item.name}(${item.count}次)`).join("、") }}</p>
|
||||||
|
<template v-if="card.standards?.length"><p><b>关联标准:</b></p><ul class="report-card-detail__standards"><li v-for="standard in card.standards" :key="`${standard.category}-${standard.riskPoint}`">{{ standard.category }} · {{ standard.riskPoint }}:{{ standard.rule }}({{ standard.source || "标准文件.xlsx" }})· {{ standard.status }}</li></ul></template>
|
||||||
|
<template v-if="card.similarCases?.length"><p><b>相似案例:</b></p><ul class="report-card-detail__standards"><li v-for="(item, caseIndex) in card.similarCases" :key="`${item.date || 'case'}-${caseIndex}`">{{ item.date || "日期未知" }} · {{ item.product || "未命名产品" }} · {{ item.problem || item.description || "异常问题未填写" }} → {{ item.solution || "解决方案未填写" }}<template v-if="item.similarity != null">(相似度 {{ Math.round(item.similarity * 100) }}%)</template></li></ul></template>
|
||||||
|
<ul v-if="card.risks?.length"><li v-for="risk in card.risks" :key="`${risk.title}-${risk.detail}`"><b>{{ risk.level }} · {{ risk.title }}:</b>{{ risk.detail }}</li></ul>
|
||||||
|
<ol v-if="card.suggestions?.length"><li v-for="suggestion in card.suggestions" :key="suggestion">{{ suggestion }}</li></ol>
|
||||||
|
<p v-if="card.note"><b>备注:</b>{{ card.note }}</p>
|
||||||
|
<p v-if="card.warning" class="report-card-detail__warning">{{ card.warning }}</p>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
<footer class="report-footer">
|
<footer class="report-footer">
|
||||||
<span>编制:蝶雅风险预估系统</span
|
<span>编制:蝶雅风险预估系统</span
|
||||||
><span>生成时间:{{ generatedAt }}</span>
|
><span>生成时间:{{ generatedAt }}</span>
|
||||||
@ -494,6 +506,45 @@ ol {
|
|||||||
color: #334155;
|
color: #334155;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
.report-card-detail {
|
||||||
|
margin: 0 0 14px;
|
||||||
|
border: 1px solid #dbe3ef;
|
||||||
|
border-left: 3px solid #2563eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
background: #fafcff;
|
||||||
|
}
|
||||||
|
.report-card-detail header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 7px;
|
||||||
|
color: #1d4ed8;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.report-card-detail header span {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
.report-card-detail p,
|
||||||
|
.report-card-detail li {
|
||||||
|
margin: 4px 0;
|
||||||
|
color: #334155;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.report-card-detail ul {
|
||||||
|
margin: 4px 0;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.report-card-detail__standards {
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
.report-card-detail__warning {
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
background: #fffbeb;
|
||||||
|
color: #92400e !important;
|
||||||
|
}
|
||||||
.ai-solution-report header {
|
.ai-solution-report header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import OcrRecognitionDialog from "@/components/ocr/OcrRecognitionDialog.vue";
|
|||||||
import { useConversationStore } from "@/stores/conversation.store";
|
import { useConversationStore } from "@/stores/conversation.store";
|
||||||
import { useAuthStore } from "@/stores/auth.store";
|
import { useAuthStore } from "@/stores/auth.store";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import type { AiSolutionReport, RiskAssessmentResult } from "@/types/risk";
|
import type { ReportCard, RiskAssessmentResult } from "@/types/risk";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -69,6 +69,29 @@ const toolLabel = computed(() => {
|
|||||||
if (tool.value === "cases") return "案例关键词";
|
if (tool.value === "cases") return "案例关键词";
|
||||||
return "方案主题";
|
return "方案主题";
|
||||||
});
|
});
|
||||||
|
const toolDescription = computed(() => {
|
||||||
|
if (tool.value === "assessment")
|
||||||
|
return "填写品类、包装材质(必填),可补充规格、供应商、加工厂和开发阶段。";
|
||||||
|
if (tool.value === "material")
|
||||||
|
return "输入物料名称或组合,例如:软管、PET瓶、铝瓶+喷头、泵头。";
|
||||||
|
if (tool.value === "cases")
|
||||||
|
return "描述要检索的异常现象,例如:软管印刷遇水脱落、泵头漏液。";
|
||||||
|
if (tool.value === "solution")
|
||||||
|
return "描述需要生成方案的新品、品类、材质或风险问题,例如:铝瓶+喷头的密封验证方案。";
|
||||||
|
return "填写必要信息后,将生成一条带上下文的对话请求。";
|
||||||
|
});
|
||||||
|
const toolPlaceholder = computed(() => {
|
||||||
|
if (tool.value === "material") return "如:软管 / PET瓶 / 铝瓶+喷头";
|
||||||
|
if (tool.value === "cases") return "如:软管印刷遇水脱落,如何处理";
|
||||||
|
if (tool.value === "solution")
|
||||||
|
return "如:次氯酸消毒喷雾,铝瓶+喷头,生成验证方案";
|
||||||
|
return "请输入内容";
|
||||||
|
});
|
||||||
|
const toolSubmitLabel = computed(() =>
|
||||||
|
["assessment", "material", "cases", "solution"].includes(tool.value ?? "")
|
||||||
|
? "开始分析"
|
||||||
|
: "带入对话",
|
||||||
|
);
|
||||||
|
|
||||||
const loadingText = computed(() =>
|
const loadingText = computed(() =>
|
||||||
loading.value ? "正在调用风险评分引擎…" : "",
|
loading.value ? "正在调用风险评分引擎…" : "",
|
||||||
@ -155,6 +178,27 @@ function submitTool() {
|
|||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(",");
|
.join(",");
|
||||||
|
} else if (selectedTool === "material") {
|
||||||
|
const value = toolInput.value.trim();
|
||||||
|
if (!value) {
|
||||||
|
toolError.value = "请输入要查询的物料名称";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toolInput.value = `查物料风险:${value}`;
|
||||||
|
} else if (selectedTool === "cases") {
|
||||||
|
const value = toolInput.value.trim();
|
||||||
|
if (!value) {
|
||||||
|
toolError.value = "请输入要检索的异常现象或关键词";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toolInput.value = `搜索相似案例:${value}`;
|
||||||
|
} else if (selectedTool === "solution") {
|
||||||
|
const value = toolInput.value.trim();
|
||||||
|
if (!value) {
|
||||||
|
toolError.value = "请输入需要生成方案的产品或风险问题";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toolInput.value = `生成 AI 案例推理方案:${value}`;
|
||||||
}
|
}
|
||||||
const finalValue = toolInput.value.trim();
|
const finalValue = toolInput.value.trim();
|
||||||
if (!finalValue && !toolFile.value) {
|
if (!finalValue && !toolFile.value) {
|
||||||
@ -243,24 +287,54 @@ async function openFromRoute() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readStoredReport() {
|
||||||
|
try {
|
||||||
|
const raw = sessionStorage.getItem("dieya-risk-report");
|
||||||
|
return raw ? (JSON.parse(raw) as RiskAssessmentResult) : null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function legacySolutionCards(result: RiskAssessmentResult): ReportCard[] {
|
||||||
|
return (result.aiSolutionCards ?? []).map((item) => ({
|
||||||
|
type: "solution" as const,
|
||||||
|
title: item.title || "AI 案例推理生成",
|
||||||
|
confidence: item.confidence,
|
||||||
|
analysisBase: item.analysisBase,
|
||||||
|
standardFallbackEnabled: item.standardFallbackEnabled,
|
||||||
|
standards: item.standards,
|
||||||
|
similarCases: item.similarCases,
|
||||||
|
risks: item.risks,
|
||||||
|
suggestions: item.suggestions,
|
||||||
|
warning: item.warning,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function openReport(result: RiskAssessmentResult) {
|
function openReport(result: RiskAssessmentResult) {
|
||||||
sessionStorage.setItem("dieya-risk-report", JSON.stringify(result));
|
const stored = readStoredReport();
|
||||||
|
const merged: RiskAssessmentResult =
|
||||||
|
stored?.subjectId === result.subjectId
|
||||||
|
? {
|
||||||
|
...structuredClone(result),
|
||||||
|
reportCards: stored.reportCards?.length
|
||||||
|
? stored.reportCards
|
||||||
|
: result.reportCards ?? [],
|
||||||
|
aiSolutionCards: stored.aiSolutionCards?.length
|
||||||
|
? stored.aiSolutionCards
|
||||||
|
: result.aiSolutionCards ?? [],
|
||||||
|
}
|
||||||
|
: structuredClone(result);
|
||||||
|
sessionStorage.setItem("dieya-risk-report", JSON.stringify(merged));
|
||||||
void router.push({ name: "report" });
|
void router.push({ name: "report" });
|
||||||
}
|
}
|
||||||
|
|
||||||
function openSolutionReport(card: Record<string, unknown>) {
|
function openSolutionReport(card: ReportCard) {
|
||||||
const solution = card as AiSolutionReport;
|
|
||||||
const current = conversation.value?.messages
|
const current = conversation.value?.messages
|
||||||
.slice()
|
.slice()
|
||||||
.reverse()
|
.reverse()
|
||||||
.find((message) => message.riskResult)?.riskResult;
|
.find((message) => message.riskResult)?.riskResult;
|
||||||
let stored: RiskAssessmentResult | null = null;
|
const stored = readStoredReport();
|
||||||
try {
|
|
||||||
const raw = sessionStorage.getItem("dieya-risk-report");
|
|
||||||
stored = raw ? (JSON.parse(raw) as RiskAssessmentResult) : null;
|
|
||||||
} catch {
|
|
||||||
stored = null;
|
|
||||||
}
|
|
||||||
const sameReport = Boolean(
|
const sameReport = Boolean(
|
||||||
current && stored && current.subjectId === stored.subjectId,
|
current && stored && current.subjectId === stored.subjectId,
|
||||||
);
|
);
|
||||||
@ -276,19 +350,23 @@ function openSolutionReport(card: Record<string, unknown>) {
|
|||||||
modelVersion: "ai-solution-card",
|
modelVersion: "ai-solution-card",
|
||||||
factors: [],
|
factors: [],
|
||||||
};
|
};
|
||||||
const existing = base.aiSolutionCards ?? [];
|
const existingCards = base.reportCards ?? [];
|
||||||
const merged: RiskAssessmentResult = {
|
const merged: RiskAssessmentResult = {
|
||||||
...base,
|
...base,
|
||||||
aiSolutionCards: [...existing, solution],
|
// All newly appended cards use one canonical collection. Migrate old
|
||||||
aiSuggestions: [
|
// AI-only entries once so they are not lost when the first generic card
|
||||||
...(base.aiSuggestions ?? []),
|
// is appended to an existing session.
|
||||||
...(solution.suggestions ?? []),
|
aiSolutionCards: base.aiSolutionCards,
|
||||||
|
reportCards: [
|
||||||
|
...(existingCards.length ? existingCards : legacySolutionCards(base)),
|
||||||
|
card,
|
||||||
],
|
],
|
||||||
similarCases: solution.similarCases?.length
|
aiSuggestions: [...(base.aiSuggestions ?? []), ...(card.suggestions ?? [])],
|
||||||
? [...(base.similarCases ?? []), ...solution.similarCases]
|
similarCases: card.similarCases?.length
|
||||||
|
? [...(base.similarCases ?? []), ...card.similarCases]
|
||||||
: base.similarCases,
|
: base.similarCases,
|
||||||
standardJudgment: solution.standards?.length
|
standardJudgment: card.standards?.length
|
||||||
? [...(base.standardJudgment ?? []), ...solution.standards]
|
? [...(base.standardJudgment ?? []), ...card.standards]
|
||||||
: base.standardJudgment,
|
: base.standardJudgment,
|
||||||
};
|
};
|
||||||
sessionStorage.setItem("dieya-risk-report", JSON.stringify(merged));
|
sessionStorage.setItem("dieya-risk-report", JSON.stringify(merged));
|
||||||
@ -464,9 +542,7 @@ async function scrollToBottom(behavior: "smooth" | "auto" = "smooth") {
|
|||||||
</button>
|
</button>
|
||||||
<p class="eyebrow">CHAT TOOL</p>
|
<p class="eyebrow">CHAT TOOL</p>
|
||||||
<h2>{{ toolTitle }}</h2>
|
<h2>{{ toolTitle }}</h2>
|
||||||
<p class="dialog-description">
|
<p class="dialog-description">{{ toolDescription }}</p>
|
||||||
填写必要信息后,将生成一条带上下文的对话请求。
|
|
||||||
</p>
|
|
||||||
<div v-if="tool === 'assessment'" class="assessment-fields">
|
<div v-if="tool === 'assessment'" class="assessment-fields">
|
||||||
<label
|
<label
|
||||||
>产品品类<input v-model="assessmentFields.category" autofocus
|
>产品品类<input v-model="assessmentFields.category" autofocus
|
||||||
@ -499,6 +575,7 @@ async function scrollToBottom(behavior: "smooth" | "auto" = "smooth") {
|
|||||||
v-if="tool !== 'ocr' && tool !== 'voice'"
|
v-if="tool !== 'ocr' && tool !== 'voice'"
|
||||||
v-model="toolInput"
|
v-model="toolInput"
|
||||||
:maxlength="tool === 'cases' ? 50 : 2000"
|
:maxlength="tool === 'cases' ? 50 : 2000"
|
||||||
|
:placeholder="toolPlaceholder"
|
||||||
autofocus
|
autofocus
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
@ -517,7 +594,9 @@ async function scrollToBottom(behavior: "smooth" | "auto" = "smooth") {
|
|||||||
<button type="button" class="dialog-secondary" @click="closeTool">
|
<button type="button" class="dialog-secondary" @click="closeTool">
|
||||||
取消
|
取消
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" class="dialog-primary">带入对话</button>
|
<button type="submit" class="dialog-primary">
|
||||||
|
{{ toolSubmitLabel }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -54,6 +54,7 @@ export interface RiskAssessmentResult {
|
|||||||
}>;
|
}>;
|
||||||
aiSuggestions?: string[];
|
aiSuggestions?: string[];
|
||||||
aiSolutionCards?: AiSolutionReport[];
|
aiSolutionCards?: AiSolutionReport[];
|
||||||
|
reportCards?: ReportCard[];
|
||||||
riskBadge?: string | null;
|
riskBadge?: string | null;
|
||||||
alertText?: string | null;
|
alertText?: string | null;
|
||||||
categoryWarning?: {
|
categoryWarning?: {
|
||||||
@ -103,6 +104,43 @@ export interface AiSolutionReport {
|
|||||||
warning?: string | null;
|
warning?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ReportCard {
|
||||||
|
type: "supplier" | "material" | "standard" | "compliance" | "solution";
|
||||||
|
title: string;
|
||||||
|
name?: string;
|
||||||
|
partyType?: string;
|
||||||
|
material?: string;
|
||||||
|
category?: string;
|
||||||
|
anomalyCount?: number | null;
|
||||||
|
cooperationCount?: number | null;
|
||||||
|
frequencyCoefficient?: number | null;
|
||||||
|
supplierBaseScore?: number | null;
|
||||||
|
supplierScore?: number | null;
|
||||||
|
tier?: string | null;
|
||||||
|
matchedCount?: number | null;
|
||||||
|
topProblems?: Array<{ name: string; count: number }>;
|
||||||
|
frequentProblems?: Array<{ name: string; count: number }>;
|
||||||
|
standards?: Array<{
|
||||||
|
category: string;
|
||||||
|
riskPoint: string;
|
||||||
|
rule: string;
|
||||||
|
source: string | null;
|
||||||
|
status: string;
|
||||||
|
}>;
|
||||||
|
similarCases?: NonNullable<RiskAssessmentResult["similarCases"]>;
|
||||||
|
confidence?: string | null;
|
||||||
|
analysisBase?: string | null;
|
||||||
|
risks?: Array<{ level: string; title: string; detail: string }>;
|
||||||
|
suggestions?: string[];
|
||||||
|
note?: string | null;
|
||||||
|
warning?: string | null;
|
||||||
|
question?: string | null;
|
||||||
|
detectedValues?: Array<{ name: string; value: string }>;
|
||||||
|
standardFallbackEnabled?: boolean;
|
||||||
|
frequencyBasis?: string | null;
|
||||||
|
dataAvailable?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export type RiskReportResult = RiskAssessmentResult;
|
export type RiskReportResult = RiskAssessmentResult;
|
||||||
|
|
||||||
export interface ModelInfo {
|
export interface ModelInfo {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user