变更关闭确认表完成
This commit is contained in:
@@ -31,7 +31,7 @@ const form = ref<ApplyForm>({
|
||||
name: "", dept: "", mainChanges: [""], related: "", purposes: [], effect: "",
|
||||
type: "", level: "", duration: "", urgent: false, date: null, restoreDate: null,
|
||||
});
|
||||
const tab = ref<string>("accept");
|
||||
const tab = ref<string>("close");
|
||||
const TABS = [
|
||||
{ id: "pre", name: "变更预识别", icon: 'lucide:sparkles' },
|
||||
{ id: "form", name: "变更申请表", icon: 'akar-icons:file' },
|
||||
@@ -527,6 +527,42 @@ const acceptRows = ref([
|
||||
]);
|
||||
const acceptNote = ref("");
|
||||
|
||||
// ---------- 变更关闭确认表 ----------
|
||||
const closeFold = ref<Record<string, boolean>>({});
|
||||
const uploadDoc = ref<string | null>(null);
|
||||
const uploadSel = ref<string | null>(null);
|
||||
const UPDATE_DOC_KW: Record<string, string> = { PID图纸: "PID", 操作规程: "操作规程", 总图: "总图", 设备台账: "设备台账", 工艺卡片: "工艺卡片", 联锁台账: "联锁台账", 应急预案: "应急预案" };
|
||||
const needUpdate = (name: string) => updateDocs.value.some((d:any) => name.includes(UPDATE_DOC_KW[d] ?? d));
|
||||
|
||||
const changeScope = (d: any, v: string) => {
|
||||
closeDocs.value = closeDocs.value.map((x:any) => (x.name === d.name ? { ...x, scope: v } : x));
|
||||
if (v !== d.scope) window.$message?.info(`演示:「${d.name}」改判为「${v}」,改判理由与操作人已留痕`);
|
||||
}
|
||||
const uploadDocInfo = computed(() => {
|
||||
if (!uploadDoc.value) return null;
|
||||
const doc = closeDocs.value.find((x) => x.name === uploadDoc.value);
|
||||
const base = uploadDoc.value.replace(/[((].*$/, "");
|
||||
return {
|
||||
storePath: `\\\\PLANT-DMS\\变更管理\\2026\\MOC-2026-R01-0041\\${doc?.cat ?? ""}\\`,
|
||||
candidates: [`${base}_RevC_受控版.pdf`, `${base}_2026-08 更新版.docx`],
|
||||
base,
|
||||
};
|
||||
});
|
||||
const openDir = () => {
|
||||
window.$message?.info('演示:已在文档管理系统中打开该目录')
|
||||
}
|
||||
const uploadFiles = () => {
|
||||
uploadSel.value = `本地文件:${uploadDocInfo.value?.base}_最新版.pdf`;
|
||||
window.$message?.info('演示:已接收拖拽 / 选择的本地文件');
|
||||
}
|
||||
const uploadConfirm = () => {
|
||||
closeDocs.value = closeDocs.value.map((x) => (x.name === uploadDoc.value ? { ...x, archived: true } : x));
|
||||
window.$message?.success(`「${uploadDoc.value}」已上传并归档(${uploadSel.value},受控版本,哈希留痕)`);
|
||||
uploadDoc.value = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -1250,6 +1286,81 @@ const acceptNote = ref("");
|
||||
流程说明:投用运行满验收周期后,系统向车间(属地)与涉及专业推送验收任务;各责任单位按上表逐项给出评估结论并上传佐证(数据报表 / 化验报告 / 现场照片),全部完成后汇总至综合验收结论,结论与佐证资料一并纳入变更关闭校验,验收不通过时退回整改或评估恢复原状。
|
||||
</div>
|
||||
</template>
|
||||
<!-- 变更关闭确认表 -->
|
||||
<template v-if="tab === 'close'">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<span class="flex items-center gap-1.5 text-sm font-semibold text-slate-700">
|
||||
<Icon icon="quill:folder-open" class="size-16px" />
|
||||
变更关闭确认表(资料归档清单)
|
||||
</span>
|
||||
<span class="inline-flex items-center gap-1 rounded-full border border-violet-200 bg-violet-100 px-2 py-0.5 text-xs font-medium text-violet-700">
|
||||
✨ AI 生成 · 需人工确认
|
||||
</span>
|
||||
<NTag size="small" class="text-xs">AI 辅助判定一次 · 支持人工改判留痕</NTag>
|
||||
<span class="ml-auto text-xs text-slate-400">判定为「是」的资料全部归档后,变更主管部门专责方可确认关闭</span>
|
||||
</div>
|
||||
<div class="border" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||
<div class="flex items-center gap-3 bg-slate-100 px-3 py-2 text-xs font-medium text-slate-500">
|
||||
<span class="w-5" />
|
||||
<span class="flex-1">资料名称(与申请表「需更新的资料」勾选联动,勾选资料标记「需更新版本」)</span>
|
||||
<span class="w-48 text-center">是否涉及(AI 判定,可改判)</span>
|
||||
<span class="w-32 text-center">归档状态</span>
|
||||
</div>
|
||||
<template v-for="cat in (['图纸与规程类', '台账与制度类', '过程与结果文件类'])" :key="cat">
|
||||
<div v-if="closeDocs.filter((d) => d.cat === cat).length">
|
||||
<button @click="closeFold = { ...closeFold, [cat]: !closeFold[cat] }"
|
||||
class="flex w-full items-center gap-2 border-t bg-slate-50 px-3 py-2 text-left text-xs font-semibold text-slate-600 transition hover:bg-[#EAF0F9]">
|
||||
<Icon icon="formkit:right" class="size-14px text-slate-400 transition" :class="closeFold[cat] ? '' : 'rotate-90'" />
|
||||
{{ cat }}
|
||||
<span class="font-normal text-slate-400">
|
||||
{{ closeDocs.filter((d) => d.cat === cat).length }} 项 · 已归档
|
||||
{{ closeDocs.filter((d) => d.cat === cat && d.scope === '是' && d.archived).length }}/{{ closeDocs.filter((d) => d.cat === cat && d.scope === '是').length }}
|
||||
</span>
|
||||
<span class="ml-auto text-[11px] font-normal text-slate-400">{{ closeFold[cat] ? '点击展开' : '点击折叠' }}</span>
|
||||
</button>
|
||||
<template v-if="!closeFold[cat]">
|
||||
<div v-for="d in closeDocs.filter((x) => x.cat === cat)" :key="d.name" class="flex flex-wrap items-center gap-3 border-t px-3 py-2.5 text-sm">
|
||||
<span class="w-5 text-slate-400">{{ closeDocs.indexOf(d) + 1 }}</span>
|
||||
<span class="min-w-0 flex-1 text-slate-800">
|
||||
{{ d.name }}
|
||||
<NTag v-if="needUpdate(d.name)" size="small" type="info" class="ml-2">需更新版本</NTag>
|
||||
</span>
|
||||
<span class="flex w-48 shrink-0 justify-center gap-1.5">
|
||||
<NButton size="tiny" round v-for="v in (['是', '否', '不涉及'])" :key="v"
|
||||
@click="changeScope(d, v)"
|
||||
class="text-[11px]"
|
||||
:type="d.scope === v ? 'primary' : 'default'">
|
||||
{{ v }}
|
||||
</NButton>
|
||||
</span>
|
||||
<span class="flex w-32 shrink-0 items-center justify-center gap-2">
|
||||
<template v-if="d.scope === '是'">
|
||||
<NTag v-if="d.archived" size="small" type="success">已归档</NTag>
|
||||
<template v-else>
|
||||
<NTag size="small" type="warning">待上传</NTag>
|
||||
<NButton text type="primary" class="text-xs hover:underline" @click="uploadDoc = d.name; uploadSel = null;">上传</NButton>
|
||||
</template>
|
||||
</template>
|
||||
<NTag v-else size="small">{{ d.scope }}</NTag>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-4 text-xs text-slate-500">
|
||||
<span>
|
||||
统计:涉及 <b class="text-[#17407F]">{{ closeDocs.filter((d) => d.scope === '是').length }}</b> 项 ·
|
||||
已归档 <b class="text-emerald-600">{{ closeDocs.filter((d) => d.scope === '是' && d.archived).length }}</b> 项 ·
|
||||
待上传 <b class="text-amber-600">{{ closeDocs.filter((d) => d.scope === '是' && !d.archived).length }}</b> 项 ·
|
||||
需更新版本 <b class="text-[#1D4E9C]">{{ closeDocs.filter((d) => needUpdate(d.name)).length }}</b> 项(联动申请表勾选)
|
||||
</span>
|
||||
<span class="text-slate-400">资料上传支持 PC / 移动端(拍照上传),版本受控</span>
|
||||
</div>
|
||||
<div class="rounded-lg bg-[#EAF0F9] px-4 py-2.5 text-xs leading-5 text-[#17407F]">
|
||||
关闭校验说明:判定为「是」的资料项全部归档后,系统将全部流程完毕信号推送变更主管部门专责,专责确认后点击关闭,系统记录变更关闭时间;「否 / 不涉及」由 AI 辅助判定一次,人工改判须填写理由并留痕。临时变更恢复完成后,恢复操作票与参数核对记录自动追加至本清单。
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -1464,11 +1575,71 @@ const acceptNote = ref("");
|
||||
</div>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
<!-- 资料上传弹窗 -->
|
||||
<NModal
|
||||
:show="uploadDoc !== null"
|
||||
preset="card"
|
||||
:auto-focus="false"
|
||||
:style="{ width: '550px', height: 'auto' }"
|
||||
:segmented="{ content: true, footer: true }"
|
||||
@update:show="(v: boolean) => !v && (uploadDoc = null)"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2 text-base font-semibold text-slate-800">
|
||||
<Icon icon="material-symbols:upload" class="size-20px" /> 资料上传归档 — {{ uploadDoc }}
|
||||
</div>
|
||||
</template>
|
||||
<div class="space-y-3">
|
||||
<div>
|
||||
<div class="mb-1 text-xs font-medium text-slate-500">系统文档存储地址(受控目录)</div>
|
||||
<div class="flex items-center gap-2 rounded-lg border bg-slate-50 px-3 py-2">
|
||||
<Icon icon="quill:folder-open" class="size-16px" />
|
||||
<code class="min-w-0 flex-1 truncate text-xs text-slate-600">{{ uploadDocInfo?.storePath }}</code>
|
||||
<NButton text type="primary" class="text-xs hover:underline" @click="openDir">打开目录</NButton>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-1 text-xs font-medium text-slate-500">方式一:从存储地址选择资料</div>
|
||||
<div class="space-y-1.5">
|
||||
<p v-for="f in uploadDocInfo?.candidates" :key="f" @click="uploadSel = f"
|
||||
class="flex w-full items-center gap-2 rounded-lg border px-3 py-2 text-left text-xs transition cursor-pointer"
|
||||
:class="uploadSel === f ? 'border-[var(--theme-color)] bg-[var(--theme-color)] text-[var(--theme-color)] text-white' : 'bg-white text-slate-600 hover:border-[var(--theme-color)] hover:text-[var(--theme-color)]'"
|
||||
:style="{'--theme-color': themeStore.themeColor}"
|
||||
>
|
||||
<Icon icon="akar-icons:file" class="size-14px mr-1" /> {{ f }}
|
||||
<Icon v-if="uploadSel === f" icon="ix:success" class="ml-auto size-16px" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-1 text-xs font-medium text-slate-500">方式二:拖拽本地文件到区域</div>
|
||||
<button @click="uploadFiles"
|
||||
class="flex h-20 w-full flex-col items-center justify-center gap-1 rounded-lg border-2 border-dashed px-3 text-xs transition"
|
||||
:class="uploadSel?.startsWith('本地文件') ? 'border-[var(--theme-color)] bg-[#EAF0F9] text-[var(--theme-color)]' : 'border-slate-300 text-slate-400 hover:border-[var(--theme-color)] hover:text-[var(--theme-color)]'"
|
||||
:style="{'--theme-color': themeStore.themeColor}"
|
||||
>
|
||||
<Icon icon="material-symbols:upload" class="size-24px" />
|
||||
{{ uploadSel?.startsWith('本地文件') ? uploadSel : '将资料文件拖拽到此处,或点击选择本地文件' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-2">
|
||||
<NButton @click="uploadDoc = null">取消</NButton>
|
||||
<NButton type="primary" :disabled="!uploadSel" @click="uploadConfirm">
|
||||
确认上传归档
|
||||
</NButton>
|
||||
</div>
|
||||
</template>
|
||||
</NModal>
|
||||
</NCard>
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.n-button .n-button__content) {
|
||||
width: 100%;
|
||||
}
|
||||
.scroll {
|
||||
height: calc(100vh - 326px);
|
||||
overflow-y: auto;
|
||||
|
||||
Reference in New Issue
Block a user