初步完成ai插件对接
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user