初步完成ai插件对接

This commit is contained in:
2026-08-26 22:10:04 +08:00
parent 26192167f3
commit f5176ada20
13 changed files with 4367 additions and 3540 deletions
+123 -12
View File
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import { ref, onMounted, computed, watch } from 'vue';
import { aiApprovalAssist, pollTask, AiError } from '@/service/api/ai';
import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { useRouterPush } from '@/hooks/common/router';
@@ -69,13 +70,14 @@ const confirmClose = () => {
window.$message?.success('强制合规项已确认闭环,操作已留痕');
}
const conflictHide = ref<boolean>(false);
const PARAM_DIFF = [
// 关键参数对比(静态示例作 fallback,AI 审批辅助完成后回填)
const paramDiff = ref([
{ k: "反应温度", before: "80℃", after: "90℃", over: false, note: "仍在溶剂沸点与物料分解温度的安全裕度内" },
{ k: "保温时间", before: "8 h", after: "4 h", over: false, note: "终点判断窗口变窄,须修订操作规程" },
{ k: "DCS 温度高报警", before: "85℃", after: "95℃", over: true, note: "超出原报警裕度,须重新整定验证" },
{ k: "联锁高高报", before: "90℃", after: "100℃", over: true, note: "接近设备设计温度上限,投用前须完成联锁测试" },
{ k: "未知杂质含量", before: "0.05%", after: "0.12%", over: false, note: "结构未定,须纳入日常分析计划" },
];
]);
const aiRead = ref<boolean>(false);
const roleName = ref<string>('张工艺');
const suggs = ref([
@@ -152,6 +154,109 @@ const handleReminder = (m: any) => {
}
// AI 审批辅助(抽屉打开时触发,异步任务轮询;失败保留静态示例,不阻塞页面)
const aiAssistLoading = ref<boolean>(false);
const aiAssistStep = ref<string>('');
const aiAssistProgress = ref<number>(0);
const aiAssistLoaded = ref<boolean>(false);
// 强制合规描述(静态示例作 fallback)
const mandText = ref<string>('本次变更涉及 DCS 联锁设定值修改,依据 AQ/T 3034《化工企业工艺安全管理实施导则》,投用前须完成联锁测试并留存记录。');
const mandItem = ref<string>('联锁测试记录须在投用前完成并上传归档');
// 冲突提示
const conflictText = ref<string>('涉及设备 R-101 关联变更 MOC-2026-0038「机封冲洗方案调整」正在审批中,请确认施工时序与隔离方案无冲突。');
// 属地影响摘要
const deptRows = ref([
{ label: '涉及单元:', text: '一车间 R-201 反应釜及配套 DCS 回路,不影响相邻单元。' },
{ label: '现行规程影响:', text: '操作规程第 4.2 节(报警处置)需同步修订,变更关闭前完成受控换版。' },
{ label: '交接班提示:', text: '投用后首个班次需向班组交代新报警值与处置卡位置,建议纳入班前会内容。' },
]);
// 参考信息(相似变更 / 历史经验)
const similarText = ref<string>('相似变更 MOC-2025-0112「酯化反应温度上调」投用后运行正常,无异常记录');
const experienceText = ref<string>('历史经验:温度类变更投用后首周超温报警占比约 38%,建议关注投用首周报警趋势');
const toTextList = (v: any): string[] => {
if (!v) return [];
if (typeof v === 'string') return [v];
if (Array.isArray(v)) return v.map((x: any) => (typeof x === 'string' ? x : x?.text ?? x?.content ?? '')).filter(Boolean);
return [];
};
const runAiAssist = async () => {
if (aiAssistLoading.value || aiAssistLoaded.value) return;
aiAssistLoading.value = true;
aiAssistStep.value = '提交分析任务…';
aiAssistProgress.value = 0;
try {
const snapshot = {
apply_form: currentInfo.value ?? {},
compare_rows: [],
risk_records: [],
materials: []
};
const { task_id } = await aiApprovalAssist({
snapshot,
change_id_ref: currentInfo.value?.cid,
submit_version: 1
});
const result: any = await pollTask(task_id, {
onProgress: t => {
aiAssistStep.value = t.current_step || 'AI 分析中…';
aiAssistProgress.value = t.progress ?? 0;
}
});
const r = result?.result ?? result ?? {};
// 强制合规(mandatory 可能为字符串或数组)
const mand = toTextList(r.mandatory);
if (mand.length) {
mandText.value = mand.join('');
mandItem.value = mand[0];
}
// 冲突提示
const conflicts = toTextList(r.conflicts);
if (conflicts.length) conflictText.value = conflicts.join('');
// 关键参数对比
if (Array.isArray(r.param_diff) && r.param_diff.length) {
paramDiff.value = r.param_diff.map((d: any) => ({
k: d.k ?? d.item ?? d.name ?? '',
before: d.before ?? '',
after: d.after ?? '',
over: Boolean(d.over),
note: d.note ?? d.basis ?? ''
}));
}
// 推荐改进项
const sugs = toTextList(r.suggestions);
if (sugs.length) suggs.value = sugs.map((text, i) => ({ id: i + 1, text, st: '待定' }));
// 相似变更 / 历史经验
const similar = toTextList(r.similar_changes);
if (similar.length) similarText.value = similar[0];
const exp = toTextList(r.experience);
if (exp.length) experienceText.value = exp[0];
// 属地影响摘要(字符串或数组,兼容对象形态)
if (r.dept_summary) {
const rows = toTextList(r.dept_summary).map((t: string) => {
const idx = t.indexOf('');
return idx > 0 ? { label: `${t.slice(0, idx + 1)}`, text: t.slice(idx + 1) } : { label: '', text: t };
});
if (rows.length) deptRows.value = rows;
}
aiAssistLoaded.value = true;
window.$message?.success('AI 审批辅助分析完成,结果仅供参考,需人工确认');
} catch (e: any) {
if (e instanceof AiError) {
window.$message?.warning(`AI 分析失败:${e.message},展示静态示例,可人工判断`);
} else {
window.$message?.warning('AI 分析失败,展示静态示例,可人工判断');
}
} finally {
aiAssistLoading.value = false;
}
};
watch(aiDrawer, v => {
if (v) runAiAssist();
});
onMounted(() => {
if(route.query && route.query.params){
currentInfo.value = JSON.parse(route.query.params as string);
@@ -1038,6 +1143,14 @@ onMounted(() => {
</span>
</template>
<div class="space-y-4">
<!-- AI 分析进度异步任务轮询 -->
<div v-if="aiAssistLoading" class="rounded-lg border border-violet-200 bg-violet-50 px-3 py-2.5 text-xs text-violet-700">
<div class="flex items-center gap-2">
<Icon icon="eos-icons:loading" class="size-14px" />
<span>{{ aiAssistStep || 'AI 分析中…' }}{{ aiAssistProgress }}%</span>
</div>
<NProgress type="line" :percentage="aiAssistProgress" :show-indicator="false" class="mt-1.5" processing />
</div>
<!-- 合规警告条强制合规项不可关闭闭环后转绿 -->
<div
class="px-3 py-2.5 text-sm"
@@ -1064,7 +1177,7 @@ onMounted(() => {
</span>
</div>
<p class="mt-1 text-xs leading-relaxed">
本次变更涉及 DCS 联锁设定值修改依据 AQ/T 3034化工企业工艺安全管理实施导则投用前须完成联锁测试并留存记录
{{ mandText }}
</p>
<div v-if="!mandClosed" class="mt-1 text-right">
<NButton text type="primary" class="text-xs" @click="confirmClose">确认闭环留痕</NButton>
@@ -1086,7 +1199,7 @@ onMounted(() => {
<NButton text type="primary" class="ml-auto shrink-0 text-xs" @click="conflictHide = true">知道了</NButton>
</div>
<p class="mt-1 text-xs leading-relaxed">
涉及设备 R-101 关联变更 <b>MOC-2026-0038机封冲洗方案调整</b>正在审批中请确认施工时序与隔离方案无冲突
{{ conflictText }}
</p>
</div>
<!-- 属地影响摘要仅属地负责人视角 -->
@@ -1099,9 +1212,7 @@ onMounted(() => {
</span>
</div>
<div class="space-y-1.5 px-3 py-2.5 text-xs leading-relaxed text-slate-600">
<p><b class="text-slate-700">涉及单元</b>一车间 R-201 反应釜及配套 DCS 回路不影响相邻单元</p>
<p><b class="text-slate-700">现行规程影响</b>操作规程第 4.2 报警处置需同步修订变更关闭前完成受控换版</p>
<p><b class="text-slate-700">交接班提示</b>投用后首个班次需向班组交代新报警值与处置卡位置建议纳入班前会内容</p>
<p v-for="(r, i) in deptRows" :key="i"><b class="text-slate-700">{{ r.label }}</b>{{ r.text }}</p>
</div>
</div>
<!-- 变更前后关键参数对比变化标蓝 / 超限标红 -->
@@ -1116,7 +1227,7 @@ onMounted(() => {
<div class="border-b bg-slate-50/70 px-3 py-2 text-xs font-semibold text-slate-600">
关键参数对比AI 提取 · <span class="font-bold text-[var(--theme-color)]">=变化</span> · <span class="font-bold text-[var(--error-color)]">=超限</span>
</div>
<div v-for="d in PARAM_DIFF" :key="d.k" class="border-b px-3 py-2 last:border-b-0">
<div v-for="d in paramDiff" :key="d.k" class="border-b px-3 py-2 last:border-b-0">
<div class="flex flex-wrap items-baseline gap-x-2 text-sm">
<span class="w-24 shrink-0 text-xs text-slate-500">{{ d.k }}</span>
<span class="text-xs text-slate-400">{{ d.before }}</span>
@@ -1159,7 +1270,7 @@ onMounted(() => {
<!-- 强制合规项 -->
<div class="mb-1 flex items-center gap-1.5 text-xs font-semibold text-[var(--error-color)]"><span class="inline-block h-2 w-2 rounded-full bg-[var(--error-color)]" /> 强制合规项驳回前必须处理否则无法通过</div>
<div class="flex flex-wrap items-center gap-2 rounded-lg border border-red-100 bg-red-50/50 px-3 py-2 text-sm">
<span class="min-w-0 flex-1 text-slate-700">联锁测试记录须在投用前完成并上传归档</span>
<span class="min-w-0 flex-1 text-slate-700">{{ mandItem }}</span>
<NTag v-if="mandClosed" size="small" type="success">已闭环</NTag>
<NTag v-else size="small" type="warning">未闭环</NTag>
</div>
@@ -1191,11 +1302,11 @@ onMounted(() => {
<div class="mb-1 flex items-center gap-1.5 text-xs font-semibold text-[var(--theme-color)]"><span class="inline-block h-2 w-2 rounded-full bg-[var(--theme-color)]" /> 参考信息纯参考无强制力</div>
<div class="space-y-1.5">
<div class="flex flex-wrap items-center gap-2 rounded-lg border border-[#DFE9F6] bg-[#EAF0F9]/60 px-3 py-2 text-sm">
<span class="min-w-0 flex-1 text-slate-700">相似变更 <b>MOC-2025-0112酯化反应温度上调</b>投用后运行正常无异常记录</span>
<span class="min-w-0 flex-1 text-slate-700">{{ similarText }}</span>
<NButton text type="primary" class="hover:underline text-xs" @click="viewArchive('MOC-2025-0112')">查看归档包</NButton>
</div>
<div class="rounded-lg border border-[#DFE9F6] bg-[#EAF0F9]/60 px-3 py-2 text-sm text-slate-700">
历史经验温度类变更投用后首周超温报警占比约 38%建议关注投用首周报警趋势
{{ experienceText }}
</div>
</div>
</div>