详情页-风险评估方法显示修改
This commit is contained in:
@@ -185,7 +185,7 @@ const opinion = ref<string>("");
|
|||||||
// 已阅 AI 建议
|
// 已阅 AI 建议
|
||||||
const readSuggest = () => {
|
const readSuggest = () => {
|
||||||
aiRead.value = true;
|
aiRead.value = true;
|
||||||
window.$message?.success(`${roleName} 已阅 AI 建议,时间与操作已写入审批留痕`);
|
window.$message?.success(`${roleName.value} 已阅 AI 建议,时间与操作已写入审批留痕`);
|
||||||
}
|
}
|
||||||
// 采纳为行动项
|
// 采纳为行动项
|
||||||
const acceptSuggest = (s: any) => {
|
const acceptSuggest = (s: any) => {
|
||||||
@@ -426,7 +426,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpace vertical :size="16">
|
<NSpace vertical :size="16">
|
||||||
<NSpin :show="loading" size="small">
|
<NSpin :show="loading" size="small">
|
||||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
<div
|
<div
|
||||||
@@ -456,7 +456,9 @@ onMounted(() => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>变更申请表</p>
|
>
|
||||||
|
变更申请表
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
|
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -485,16 +487,16 @@ onMounted(() => {
|
|||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更等级</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更等级</p>
|
||||||
<div class="flex items-center flex-wrap gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="flex items-center flex-wrap gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<NRadioGroup v-model:value="level">
|
<NRadioGroup v-model:value="level">
|
||||||
<NRadio v-for="item in levelList" :key="item.value" :value="item.value" :disabled="true">{{item.label}}</NRadio>
|
<NRadio v-for="item in levelList" :key="item.value" :value="item.value" :disabled="true">{{ item.label }}</NRadio>
|
||||||
</NRadioGroup>
|
</NRadioGroup>
|
||||||
<NTag type="error" size="small">合计 {{totalScore}} 分</NTag>
|
<NTag type="error" size="small">合计 {{ totalScore }} 分</NTag>
|
||||||
<NButton ghost type="warning" size="small" round class="text-xs" @click="levelDrawer = true">
|
<NButton ghost type="warning" size="small" round class="text-xs" @click="levelDrawer = true">
|
||||||
<Icon icon="lucide:eye" class="size-12px mr-1" />查看等级判定
|
<Icon icon="lucide:eye" class="size-12px mr-1" />查看等级判定
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更类别</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更类别</p>
|
||||||
<div class="flex items-center gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="flex items-center gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{matchLabel(typeList,currentInfo?.apply_form?.change_type)?.label}}
|
{{ matchLabel(typeList,currentInfo?.apply_form?.change_type)?.label }}
|
||||||
<NButton v-if="isAiOn" ghost type="primary" size="small" round class="text-xs" @click="openTypeSheet">
|
<NButton v-if="isAiOn" ghost type="primary" size="small" round class="text-xs" @click="openTypeSheet">
|
||||||
<Icon icon="lucide:sparkles" class="size-12px mr-1" />判定说明
|
<Icon icon="lucide:sparkles" class="size-12px mr-1" />判定说明
|
||||||
</NButton>
|
</NButton>
|
||||||
@@ -503,49 +505,54 @@ onMounted(() => {
|
|||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更目的</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更目的</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.purposes?.join('、')}}
|
{{ currentInfo?.apply_form?.purposes?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">预期效果</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">预期效果</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.effect}}
|
{{ currentInfo?.apply_form?.effect }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">主要变更</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">主要变更</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<p v-for="(main,mIndex) in currentInfo?.apply_form?.main_changes" :key="mIndex">{{Number(mIndex)+1}}.{{main}}</p>
|
<p v-for="(main,mIndex) in currentInfo?.apply_form?.main_changes" :key="mIndex">{{ Number(mIndex)+1 }}.{{ main }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">连带变更</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">连带变更</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<p v-for="(related,rIndex) in currentInfo?.apply_form?.related_changes" :key="rIndex">{{Number(rIndex)+1}}.{{related}}</p>
|
<p v-for="(related,rIndex) in currentInfo?.apply_form?.related_changes" :key="rIndex">{{ Number(rIndex)+1 }}.{{ related }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.risk_tools?.join('、')}}
|
<template v-for="(item,index) in currentInfo?.apply_form?.risk_tools" :key="index">
|
||||||
|
<span v-if="index!==0">、</span>
|
||||||
|
<span v-if="item==='RISK'">风险预分析</span>
|
||||||
|
<span v-else-if="item==='RISK_CHECK'">风险检查表</span>
|
||||||
|
<span v-else>{{ item }}</span>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">所需材料</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">所需材料</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.materials}}
|
{{ currentInfo?.apply_form?.materials }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">需更新资料</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">需更新资料</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.update_docs?.join('、')}}
|
{{ currentInfo?.apply_form?.update_docs?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-[100px_1fr]">
|
<div class="grid grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">涉及专业</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">涉及专业</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.disciplines?.join('、')}}
|
{{ currentInfo?.apply_form?.disciplines?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -554,7 +561,9 @@ onMounted(() => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>变更附带资料</p>
|
>
|
||||||
|
变更附带资料
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
|
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -572,10 +581,10 @@ onMounted(() => {
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(doc,dIndex) in currentInfo?.apply_form?.attachments" :key="dIndex">
|
<tr v-for="(doc,dIndex) in currentInfo?.apply_form?.attachments" :key="dIndex">
|
||||||
<td class="text-center">1</td>
|
<td class="text-center">1</td>
|
||||||
<td>{{doc.file_name}}</td>
|
<td>{{ doc.file_name }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.file_type}}</td>
|
<td class="text-center text-xs">{{ doc?.file_type }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.file_size}}</td>
|
<td class="text-center text-xs">{{ doc?.file_size }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.created_at?.slice(0,16)}}</td>
|
<td class="text-center text-xs">{{ doc?.created_at?.slice(0,16) }}</td>
|
||||||
<td class="text-center text-xs">
|
<td class="text-center text-xs">
|
||||||
<span v-if="doc?.step_no===1">变更申请表</span>
|
<span v-if="doc?.step_no===1">变更申请表</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -594,7 +603,9 @@ onMounted(() => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>风险分析记录表</p>
|
>
|
||||||
|
风险分析记录表
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
|
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -612,13 +623,13 @@ onMounted(() => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(risk,index) in currentInfo?.risk_records?.records" :key="index">
|
<tr v-for="(risk,index) in currentInfo?.risk_records?.records" :key="index">
|
||||||
<td class="text-center">{{Number(index)+1}}</td>
|
<td class="text-center">{{ Number(index)+1 }}</td>
|
||||||
<td>{{risk.item}}</td>
|
<td>{{ risk.item }}</td>
|
||||||
<td>{{risk.scene}}</td>
|
<td>{{ risk.scene }}</td>
|
||||||
<td class="text-center">{{risk.inherent_level}}</td>
|
<td class="text-center">{{ risk.inherent_level }}</td>
|
||||||
<td>{{risk.safeguards}}</td>
|
<td>{{ risk.safeguards }}</td>
|
||||||
<td>{{risk.suggestions}}</td>
|
<td>{{ risk.suggestions }}</td>
|
||||||
<td class="text-center">{{risk.residual_level}}</td>
|
<td class="text-center">{{ risk.residual_level }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<NTag size="small" type="info" class="text-11px">{{ risk.source==='RISK'?'风险预分析':risk.source==='RISK_CHECK'?'风险检查': risk.source }}</NTag>
|
<NTag size="small" type="info" class="text-11px">{{ risk.source==='RISK'?'风险预分析':risk.source==='RISK_CHECK'?'风险检查': risk.source }}</NTag>
|
||||||
</td>
|
</td>
|
||||||
@@ -633,7 +644,7 @@ onMounted(() => {
|
|||||||
<span class="text-sm font-semibold text-slate-700">变更培训内容</span>
|
<span class="text-sm font-semibold text-slate-700">变更培训内容</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<p>{{currentInfo?.train?.content}}</p>
|
<p>{{ currentInfo?.train?.content }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- PSSR 检查内容 -->
|
<!-- PSSR 检查内容 -->
|
||||||
@@ -643,10 +654,10 @@ onMounted(() => {
|
|||||||
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
|
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<div v-for="(pssr,index) in pssrlist" class="border" :key="index" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div v-for="(pssr,index) in pssrlist" :key="index" class="border" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{pssr.g}}</div>
|
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{ pssr.g }}</div>
|
||||||
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
|
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
|
||||||
<p class="flex-1">{{item.content}}</p>
|
<p class="flex-1">{{ item.content }}</p>
|
||||||
<NTag v-if="item.phase===1" size="small" type="info">投用前完成</NTag>
|
<NTag v-if="item.phase===1" size="small" type="info">投用前完成</NTag>
|
||||||
<NTag v-else size="small" type="info">关闭前完成</NTag>
|
<NTag v-else size="small" type="info">关闭前完成</NTag>
|
||||||
</div>
|
</div>
|
||||||
@@ -671,10 +682,10 @@ onMounted(() => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(accept,index) in acceptList" :key="index">
|
<tr v-for="(accept,index) in acceptList" :key="index">
|
||||||
<td class="text-xs">{{accept.item}}</td>
|
<td class="text-xs">{{ accept.item }}</td>
|
||||||
<td class="text-xs">{{accept.standard}}</td>
|
<td class="text-xs">{{ accept.standard }}</td>
|
||||||
<td class="text-xs">{{accept.method}}</td>
|
<td class="text-xs">{{ accept.method }}</td>
|
||||||
<td class="text-xs text-center">{{accept.org_name}}</td>
|
<td class="text-xs text-center">{{ accept.org_name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</NTable>
|
</NTable>
|
||||||
@@ -685,7 +696,9 @@ onMounted(() => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>审批记录</p>
|
>
|
||||||
|
审批记录
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -698,10 +711,10 @@ onMounted(() => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(record,index) in currentInfo?.approval_records" :key="index">
|
<tr v-for="(record,index) in currentInfo?.approval_records" :key="index">
|
||||||
<td class="text-xs">{{record.action}}</td>
|
<td class="text-xs">{{ record.action }}</td>
|
||||||
<td class="text-xs">{{record.user_name}}</td>
|
<td class="text-xs">{{ record.user_name }}</td>
|
||||||
<td class="text-center text-xs">{{record.updated_at?.slice(0,16)}}</td>
|
<td class="text-center text-xs">{{ record.updated_at?.slice(0,16) }}</td>
|
||||||
<td class="text-xs">{{record.remark}}</td>
|
<td class="text-xs">{{ record.remark }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</NTable>
|
</NTable>
|
||||||
@@ -713,8 +726,10 @@ onMounted(() => {
|
|||||||
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
|
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
|
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
|
||||||
<div class="rounded-lg border px-3 py-2 text-center"
|
<div
|
||||||
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'">
|
class="rounded-lg border px-3 py-2 text-center"
|
||||||
|
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'"
|
||||||
|
>
|
||||||
<p class="text-xs font-medium">
|
<p class="text-xs font-medium">
|
||||||
{{ n.name }}
|
{{ n.name }}
|
||||||
</p>
|
</p>
|
||||||
@@ -776,7 +791,9 @@ onMounted(() => {
|
|||||||
textColor: tagTextColor(matchLabel(levelList,level)?.color),
|
textColor: tagTextColor(matchLabel(levelList,level)?.color),
|
||||||
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
|
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
|
||||||
}"
|
}"
|
||||||
>{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}</NTag>
|
>
|
||||||
|
{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}
|
||||||
|
</NTag>
|
||||||
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(<20 分为一般,≥20 分为重要)</span>
|
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(<20 分为一般,≥20 分为重要)</span>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -906,7 +923,9 @@ onMounted(() => {
|
|||||||
<div
|
<div
|
||||||
class="mt-0.5 text-[11px] leading-snug"
|
class="mt-0.5 text-[11px] leading-snug"
|
||||||
:class="d.over ? 'text-[var(--error-color)]' : 'text-slate-400'"
|
:class="d.over ? 'text-[var(--error-color)]' : 'text-slate-400'"
|
||||||
>{{ d.note }}</div>
|
>
|
||||||
|
{{ d.note }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- AI 审批建议(版本冻结 · 建议分级 · 已阅留痕 · 无感审计) -->
|
<!-- AI 审批建议(版本冻结 · 建议分级 · 已阅留痕 · 无感审计) -->
|
||||||
@@ -947,12 +966,16 @@ onMounted(() => {
|
|||||||
<div class="leading-relaxed text-slate-700">{{ s.text }}</div>
|
<div class="leading-relaxed text-slate-700">{{ s.text }}</div>
|
||||||
<div class="mt-1.5">
|
<div class="mt-1.5">
|
||||||
<div v-if="s.st === '待定'" class="flex gap-3">
|
<div v-if="s.st === '待定'" class="flex gap-3">
|
||||||
<NButton text type="success" class="text-xs hover:underline"
|
<NButton
|
||||||
@click="acceptSuggest(s)">
|
text type="success" class="text-xs hover:underline"
|
||||||
|
@click="acceptSuggest(s)"
|
||||||
|
>
|
||||||
采纳为行动项
|
采纳为行动项
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton text class="text-xs hover:underline"
|
<NButton
|
||||||
@click="rejectSuggest(s)">
|
text class="text-xs hover:underline"
|
||||||
|
@click="rejectSuggest(s)"
|
||||||
|
>
|
||||||
已知悉,不采纳
|
已知悉,不采纳
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -980,7 +1003,6 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</NDrawerContent>
|
</NDrawerContent>
|
||||||
</NDrawer>
|
</NDrawer>
|
||||||
@@ -1004,7 +1026,7 @@ onMounted(() => {
|
|||||||
<span>上传时间:{{ previewFile?.created_at }}</span>
|
<span>上传时间:{{ previewFile?.created_at }}</span>
|
||||||
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
||||||
</div>
|
</div>
|
||||||
<previewComponent v-if="previewFile" :previewFile="previewFile" />
|
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NModal>
|
</NModal>
|
||||||
@@ -1027,8 +1049,8 @@ onMounted(() => {
|
|||||||
<NTag v-for="item in rejectQuick" :key="item" class="cursor-pointer" size="small" type="error" @click="rejectReason += item + ';'">{{ item }}</NTag>
|
<NTag v-for="item in rejectQuick" :key="item" class="cursor-pointer" size="small" type="error" @click="rejectReason += item + ';'">{{ item }}</NTag>
|
||||||
</div>
|
</div>
|
||||||
<NInput
|
<NInput
|
||||||
class="mt-3"
|
|
||||||
v-model:value="rejectReason"
|
v-model:value="rejectReason"
|
||||||
|
class="mt-3"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:autosize="{ minRows: 3 }"
|
:autosize="{ minRows: 3 }"
|
||||||
placeholder="驳回意见(必填),将退回至申请人/指定节点…"
|
placeholder="驳回意见(必填),将退回至申请人/指定节点…"
|
||||||
@@ -1042,7 +1064,7 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</NModal>
|
</NModal>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ const getDetail = async () => {
|
|||||||
flowList.value = data?.disposal_approval_flow?.steps || [];
|
flowList.value = data?.disposal_approval_flow?.steps || [];
|
||||||
steps.value = data?.disposal_approval_flow?.steps || [];
|
steps.value = data?.disposal_approval_flow?.steps || [];
|
||||||
}else{
|
}else{
|
||||||
let template = templateList.value.find((item: any) =>
|
const template = templateList.value.find((item: any) =>
|
||||||
item.level === data?.apply_form?.change_level &&
|
item.level === data?.apply_form?.change_level &&
|
||||||
item.category === data?.apply_form?.change_type &&
|
item.category === data?.apply_form?.change_type &&
|
||||||
item.duration === data?.apply_form?.duration_type
|
item.duration === data?.apply_form?.duration_type
|
||||||
@@ -553,7 +553,7 @@ const togglePicker = (s: any) => {
|
|||||||
// 添加审批步骤人员
|
// 添加审批步骤人员
|
||||||
const addMember = (s: any, v: string | null) => {
|
const addMember = (s: any, v: string | null) => {
|
||||||
if (v && !s.members.some((m:any) => m.user_name === v)){
|
if (v && !s.members.some((m:any) => m.user_name === v)){
|
||||||
let info = findUserInTree(memberList.value, v);
|
const info = findUserInTree(memberList.value, v);
|
||||||
s.members.push({ user_id: Number(v), user_name: info?.user_name || '', org_id: info?.org_id || '', org_name: info?.org_name || '', specialty: "", is_sign: 0 });
|
s.members.push({ user_id: Number(v), user_name: info?.user_name || '', org_id: info?.org_id || '', org_name: info?.org_name || '', specialty: "", is_sign: 0 });
|
||||||
pick.value = null;
|
pick.value = null;
|
||||||
pickerStepId.value = null;
|
pickerStepId.value = null;
|
||||||
@@ -636,9 +636,9 @@ onMounted(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpace vertical :size="16">
|
<NSpace vertical :size="16">
|
||||||
<!-- 处置申请详情 -->
|
<!-- 处置申请详情 -->
|
||||||
<NSpin :show="loading" size="small">
|
<NSpin :show="loading" size="small">
|
||||||
<!-- 顶部 -->
|
<!-- 顶部 -->
|
||||||
<div
|
<div
|
||||||
class="flex flex-wrap items-center gap-3 px-3 py-2 mb-3 bg-[#fff]"
|
class="flex flex-wrap items-center gap-3 px-3 py-2 mb-3 bg-[#fff]"
|
||||||
@@ -665,7 +665,9 @@ onMounted(async () => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>变更申请表</p>
|
>
|
||||||
|
变更申请表
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
|
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -694,16 +696,16 @@ onMounted(async () => {
|
|||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更等级</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更等级</p>
|
||||||
<div class="flex items-center flex-wrap gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="flex items-center flex-wrap gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<NRadioGroup v-model:value="level">
|
<NRadioGroup v-model:value="level">
|
||||||
<NRadio v-for="item in levelList" :key="item.value" :value="item.value" :disabled="true">{{item.label}}</NRadio>
|
<NRadio v-for="item in levelList" :key="item.value" :value="item.value" :disabled="true">{{ item.label }}</NRadio>
|
||||||
</NRadioGroup>
|
</NRadioGroup>
|
||||||
<NTag type="error" size="small">合计 {{totalScore}} 分</NTag>
|
<NTag type="error" size="small">合计 {{ totalScore }} 分</NTag>
|
||||||
<NButton ghost type="warning" size="small" round class="text-xs" @click="levelDrawer = true">
|
<NButton ghost type="warning" size="small" round class="text-xs" @click="levelDrawer = true">
|
||||||
<Icon icon="lucide:eye" class="size-12px mr-1" />查看等级判定
|
<Icon icon="lucide:eye" class="size-12px mr-1" />查看等级判定
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更类别</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更类别</p>
|
||||||
<div class="flex items-center gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="flex items-center gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{matchLabel(typeList,currentInfo?.apply_form?.change_type)?.label}}
|
{{ matchLabel(typeList,currentInfo?.apply_form?.change_type)?.label }}
|
||||||
<NButton v-if="isAiOn" ghost type="primary" size="small" round class="text-xs" @click="openTypeSheet">
|
<NButton v-if="isAiOn" ghost type="primary" size="small" round class="text-xs" @click="openTypeSheet">
|
||||||
<Icon icon="lucide:sparkles" class="size-12px mr-1" />判定说明
|
<Icon icon="lucide:sparkles" class="size-12px mr-1" />判定说明
|
||||||
</NButton>
|
</NButton>
|
||||||
@@ -712,49 +714,54 @@ onMounted(async () => {
|
|||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更目的</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更目的</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.purposes?.join('、')}}
|
{{ currentInfo?.apply_form?.purposes?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">预期效果</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">预期效果</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.effect}}
|
{{ currentInfo?.apply_form?.effect }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">主要变更</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">主要变更</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<p v-for="(main,mIndex) in currentInfo?.apply_form?.main_changes" :key="mIndex">{{Number(mIndex)+1}}.{{main}}</p>
|
<p v-for="(main,mIndex) in currentInfo?.apply_form?.main_changes" :key="mIndex">{{ Number(mIndex)+1 }}.{{ main }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">连带变更</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">连带变更</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<p v-for="(related,rIndex) in currentInfo?.apply_form?.related_changes" :key="rIndex">{{Number(rIndex)+1}}.{{related}}</p>
|
<p v-for="(related,rIndex) in currentInfo?.apply_form?.related_changes" :key="rIndex">{{ Number(rIndex)+1 }}.{{ related }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.risk_tools?.join('、')}}
|
<template v-for="(item,index) in currentInfo?.apply_form?.risk_tools" :key="index">
|
||||||
|
<span v-if="index!==0">、</span>
|
||||||
|
<span v-if="item==='RISK'">风险预分析</span>
|
||||||
|
<span v-else-if="item==='RISK_CHECK'">风险检查表</span>
|
||||||
|
<span v-else>{{ item }}</span>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">所需材料</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">所需材料</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.materials}}
|
{{ currentInfo?.apply_form?.materials }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">需更新资料</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">需更新资料</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.update_docs?.join('、')}}
|
{{ currentInfo?.apply_form?.update_docs?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-[100px_1fr]">
|
<div class="grid grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">涉及专业</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">涉及专业</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.disciplines?.join('、')}}
|
{{ currentInfo?.apply_form?.disciplines?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -763,7 +770,9 @@ onMounted(async () => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>变更附带资料</p>
|
>
|
||||||
|
变更附带资料
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
|
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -781,10 +790,10 @@ onMounted(async () => {
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(doc,dIndex) in currentInfo?.apply_form?.attachments" :key="dIndex">
|
<tr v-for="(doc,dIndex) in currentInfo?.apply_form?.attachments" :key="dIndex">
|
||||||
<td class="text-center">1</td>
|
<td class="text-center">1</td>
|
||||||
<td>{{doc.file_name}}</td>
|
<td>{{ doc.file_name }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.file_type}}</td>
|
<td class="text-center text-xs">{{ doc?.file_type }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.file_size}}</td>
|
<td class="text-center text-xs">{{ doc?.file_size }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.created_at?.slice(0,16)}}</td>
|
<td class="text-center text-xs">{{ doc?.created_at?.slice(0,16) }}</td>
|
||||||
<td class="text-center text-xs">
|
<td class="text-center text-xs">
|
||||||
<span v-if="doc?.step_no===1">变更申请表</span>
|
<span v-if="doc?.step_no===1">变更申请表</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -803,7 +812,9 @@ onMounted(async () => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>风险分析记录表</p>
|
>
|
||||||
|
风险分析记录表
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
|
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -821,13 +832,13 @@ onMounted(async () => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(risk,index) in currentInfo?.risk_records?.records" :key="index">
|
<tr v-for="(risk,index) in currentInfo?.risk_records?.records" :key="index">
|
||||||
<td class="text-center">{{Number(index)+1}}</td>
|
<td class="text-center">{{ Number(index)+1 }}</td>
|
||||||
<td>{{risk.item}}</td>
|
<td>{{ risk.item }}</td>
|
||||||
<td>{{risk.scene}}</td>
|
<td>{{ risk.scene }}</td>
|
||||||
<td class="text-center">{{risk.inherent_level}}</td>
|
<td class="text-center">{{ risk.inherent_level }}</td>
|
||||||
<td>{{risk.safeguards}}</td>
|
<td>{{ risk.safeguards }}</td>
|
||||||
<td>{{risk.suggestions}}</td>
|
<td>{{ risk.suggestions }}</td>
|
||||||
<td class="text-center">{{risk.residual_level}}</td>
|
<td class="text-center">{{ risk.residual_level }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<NTag size="small" type="info" class="text-11px">{{ risk.source==='RISK'?'风险预分析':risk.source==='RISK_CHECK'?'风险检查': risk.source }}</NTag>
|
<NTag size="small" type="info" class="text-11px">{{ risk.source==='RISK'?'风险预分析':risk.source==='RISK_CHECK'?'风险检查': risk.source }}</NTag>
|
||||||
</td>
|
</td>
|
||||||
@@ -842,7 +853,7 @@ onMounted(async () => {
|
|||||||
<span class="text-sm font-semibold text-slate-700">变更培训内容</span>
|
<span class="text-sm font-semibold text-slate-700">变更培训内容</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<p>{{currentInfo?.train?.content}}</p>
|
<p>{{ currentInfo?.train?.content }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- PSSR 检查内容 -->
|
<!-- PSSR 检查内容 -->
|
||||||
@@ -852,10 +863,10 @@ onMounted(async () => {
|
|||||||
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
|
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<div v-for="(pssr,index) in pssrList" class="border" :key="index" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div v-for="(pssr,index) in pssrList" :key="index" class="border" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{pssr.g}}</div>
|
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{ pssr.g }}</div>
|
||||||
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
|
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
|
||||||
<p class="flex-1">{{item.content}}</p>
|
<p class="flex-1">{{ item.content }}</p>
|
||||||
<NTag v-if="item.phase===1" size="small" type="info">投用前完成</NTag>
|
<NTag v-if="item.phase===1" size="small" type="info">投用前完成</NTag>
|
||||||
<NTag v-else size="small" type="info">关闭前完成</NTag>
|
<NTag v-else size="small" type="info">关闭前完成</NTag>
|
||||||
</div>
|
</div>
|
||||||
@@ -880,10 +891,10 @@ onMounted(async () => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(accept,index) in acceptList" :key="index">
|
<tr v-for="(accept,index) in acceptList" :key="index">
|
||||||
<td class="text-xs">{{accept.item}}</td>
|
<td class="text-xs">{{ accept.item }}</td>
|
||||||
<td class="text-xs">{{accept.standard}}</td>
|
<td class="text-xs">{{ accept.standard }}</td>
|
||||||
<td class="text-xs">{{accept.method}}</td>
|
<td class="text-xs">{{ accept.method }}</td>
|
||||||
<td class="text-xs text-center">{{accept.org_name}}</td>
|
<td class="text-xs text-center">{{ accept.org_name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</NTable>
|
</NTable>
|
||||||
@@ -894,7 +905,9 @@ onMounted(async () => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>审批记录</p>
|
>
|
||||||
|
审批记录
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -907,10 +920,10 @@ onMounted(async () => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(record,index) in currentInfo?.approval_records" :key="index">
|
<tr v-for="(record,index) in currentInfo?.approval_records" :key="index">
|
||||||
<td class="text-xs">{{record.action}}</td>
|
<td class="text-xs">{{ record.action }}</td>
|
||||||
<td class="text-xs">{{record.user_name}}</td>
|
<td class="text-xs">{{ record.user_name }}</td>
|
||||||
<td class="text-center text-xs">{{record.updated_at?.slice(0,16)}}</td>
|
<td class="text-center text-xs">{{ record.updated_at?.slice(0,16) }}</td>
|
||||||
<td class="text-xs">{{record.remark}}</td>
|
<td class="text-xs">{{ record.remark }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</NTable>
|
</NTable>
|
||||||
@@ -922,8 +935,10 @@ onMounted(async () => {
|
|||||||
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
|
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
|
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
|
||||||
<div class="rounded-lg border px-3 py-2 text-center"
|
<div
|
||||||
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'">
|
class="rounded-lg border px-3 py-2 text-center"
|
||||||
|
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'"
|
||||||
|
>
|
||||||
<p class="text-xs font-medium">
|
<p class="text-xs font-medium">
|
||||||
{{ n.name }}
|
{{ n.name }}
|
||||||
</p>
|
</p>
|
||||||
@@ -951,7 +966,8 @@ onMounted(async () => {
|
|||||||
</template>
|
</template>
|
||||||
{{ m.user_name }}
|
{{ m.user_name }}
|
||||||
</NTag>
|
</NTag>
|
||||||
<div v-if="m.status === 'PENDING'"
|
<div
|
||||||
|
v-if="m.status === 'PENDING'"
|
||||||
class="cursor-pointer inline-flex h-6 items-center gap-1 rounded-md border border-amber-300 bg-white px-2 text-[11px] text-amber-700 transition hover:bg-amber-100"
|
class="cursor-pointer inline-flex h-6 items-center gap-1 rounded-md border border-amber-300 bg-white px-2 text-[11px] text-amber-700 transition hover:bg-amber-100"
|
||||||
@click="handleReminder(m)"
|
@click="handleReminder(m)"
|
||||||
>
|
>
|
||||||
@@ -961,7 +977,6 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</NCard>
|
</NCard>
|
||||||
</NGi>
|
</NGi>
|
||||||
@@ -986,7 +1001,7 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
<!-- 影响判定 -->
|
<!-- 影响判定 -->
|
||||||
<div class="space-y-1 mt-3">
|
<div class="space-y-1 mt-3">
|
||||||
<p class="text-xs font-600 text-slate-600 flex items-center">{{isAiOn?'影响判定(AI 辅助)':'影响判定'}}</p>
|
<p class="text-xs font-600 text-slate-600 flex items-center">{{ isAiOn?'影响判定(AI 辅助)':'影响判定' }}</p>
|
||||||
<NInput v-model:value="judge" type="textarea" :autosize="{minRows: 3}" placeholder="风险分析内容(AI 预分析草稿,可手动修改)…" class="w-full"></NInput>
|
<NInput v-model:value="judge" type="textarea" :autosize="{minRows: 3}" placeholder="风险分析内容(AI 预分析草稿,可手动修改)…" class="w-full"></NInput>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -999,7 +1014,7 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
<!-- 影响判定 -->
|
<!-- 影响判定 -->
|
||||||
<div class="space-y-1 mt-3">
|
<div class="space-y-1 mt-3">
|
||||||
<p class="text-xs font-600 text-slate-600 flex items-center">{{isAiOn?'影响判定(AI 辅助)':'影响判定'}}</p>
|
<p class="text-xs font-600 text-slate-600 flex items-center">{{ isAiOn?'影响判定(AI 辅助)':'影响判定' }}</p>
|
||||||
<NInput v-model:value="judge" type="textarea" :autosize="{minRows: 3}" placeholder="风险分析内容(AI 预分析草稿,可手动修改)…" class="w-full"></NInput>
|
<NInput v-model:value="judge" type="textarea" :autosize="{minRows: 3}" placeholder="风险分析内容(AI 预分析草稿,可手动修改)…" class="w-full"></NInput>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -1052,25 +1067,25 @@ onMounted(async () => {
|
|||||||
<div class="rounded-md mt-4 border">
|
<div class="rounded-md mt-4 border">
|
||||||
<div class="flex items-center gap-2 py-2 px-2 border-b">
|
<div class="flex items-center gap-2 py-2 px-2 border-b">
|
||||||
<span class="text-xs font-600 text-slate-600 flex items-center">风险分析行动项落实</span>
|
<span class="text-xs font-600 text-slate-600 flex items-center">风险分析行动项落实</span>
|
||||||
<p class="text-xs text-slate-400">{{confirmedPssr}}/{{totalPssr}} 已确认</p>
|
<p class="text-xs text-slate-400">{{ confirmedPssr }}/{{ totalPssr }} 已确认</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 space-y-2">
|
<div class="p-2 space-y-2">
|
||||||
<div v-for="(pssr,index) in pssrList" class="border" :key="index" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div v-for="(pssr,index) in pssrList" :key="index" class="border" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<div class="bg-slate-100 px-2 py-1.5 font-medium text-xs text-slate-600 flex items-center justify-between">
|
<div class="bg-slate-100 px-2 py-1.5 font-medium text-xs text-slate-600 flex items-center justify-between">
|
||||||
{{pssr.g}}
|
{{ pssr.g }}
|
||||||
<NButton text size="small" type="primary" class="text-xs" @click="addItem(index)">
|
<NButton text size="small" type="primary" class="text-xs" @click="addItem(index)">
|
||||||
<Icon icon="ic:round-plus" class="size-12px" />添加检查项
|
<Icon icon="ic:round-plus" class="size-12px" />添加检查项
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(item,subIndex) in pssr.items" :key="subIndex" class="flex items-center border-t px-2 py-1 gap-2">
|
<div v-for="(item,subIndex) in pssr.items" :key="subIndex" class="flex items-center border-t px-2 py-1 gap-2">
|
||||||
<NInput v-if="!item.id" v-model:value="item.content" size="small" type="textarea" :autosize="{minRows: 1}" placeholder="填写检查项内容" class="w-full text-xs"></NInput>
|
<NInput v-if="!item.id" v-model:value="item.content" size="small" type="textarea" :autosize="{minRows: 1}" placeholder="填写检查项内容" class="w-full text-xs"></NInput>
|
||||||
<NButton v-if="!item.id" text type="success" @click="saveItem(index, subIndex)" title="保存检查项">
|
<NButton v-if="!item.id" text type="success" title="保存检查项" @click="saveItem(index, subIndex)">
|
||||||
<Icon icon="boxicons:save" class="size-16px" />
|
<Icon icon="boxicons:save" class="size-16px" />
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton v-if="!item.id" text type="error" @click="pssrList[index].items.splice(subIndex, 1)" title="删除">
|
<NButton v-if="!item.id" text type="error" title="删除" @click="pssrList[index].items.splice(subIndex, 1)">
|
||||||
<Icon icon="ep:delete" class="size-14px" />
|
<Icon icon="ep:delete" class="size-14px" />
|
||||||
</NButton>
|
</NButton>
|
||||||
<p v-if="item.id" class="flex-1 text-xs">{{item.content}}</p>
|
<p v-if="item.id" class="flex-1 text-xs">{{ item.content }}</p>
|
||||||
<NButton v-if="item.confirm_flag" size="tiny" ghost type="success" class="text-xs" @click="item.confirm_flag = 0">已确认</NButton>
|
<NButton v-if="item.confirm_flag" size="tiny" ghost type="success" class="text-xs" @click="item.confirm_flag = 0">已确认</NButton>
|
||||||
<NButton v-else size="tiny" ghost type="warning" class="text-xs" @click="item.confirm_flag = 1">待确认</NButton>
|
<NButton v-else size="tiny" ghost type="warning" class="text-xs" @click="item.confirm_flag = 1">待确认</NButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -1084,7 +1099,7 @@ onMounted(async () => {
|
|||||||
<p class="text-xs text-slate-400">提交后纳入资料关闭流程统一归档</p>
|
<p class="text-xs text-slate-400">提交后纳入资料关闭流程统一归档</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="item in closeConfirmList" :key="item.doc_id" class="flex items-center gap-2 py-2 px-2 border-t">
|
<div v-for="item in closeConfirmList" :key="item.doc_id" class="flex items-center gap-2 py-2 px-2 border-t">
|
||||||
<p class="flex-1 text-xs flex items-center">{{item.name}}</p>
|
<p class="flex-1 text-xs flex items-center">{{ item.name }}</p>
|
||||||
<NButton :type="item.status===1?'primary':'default'" size="tiny" class="text-xs" @click="item.status = 1">已归档</NButton>
|
<NButton :type="item.status===1?'primary':'default'" size="tiny" class="text-xs" @click="item.status = 1">已归档</NButton>
|
||||||
<NButton :type="item.status===2?'primary':'default'" size="tiny" class="text-xs" @click="item.status = 2">待归档</NButton>
|
<NButton :type="item.status===2?'primary':'default'" size="tiny" class="text-xs" @click="item.status = 2">待归档</NButton>
|
||||||
<NButton :type="item.status===0?'primary':'default'" size="tiny" class="text-xs" @click="item.status = 0">不涉及</NButton>
|
<NButton :type="item.status===0?'primary':'default'" size="tiny" class="text-xs" @click="item.status = 0">不涉及</NButton>
|
||||||
@@ -1143,7 +1158,9 @@ onMounted(async () => {
|
|||||||
textColor: tagTextColor(matchLabel(levelList,level)?.color),
|
textColor: tagTextColor(matchLabel(levelList,level)?.color),
|
||||||
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
|
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
|
||||||
}"
|
}"
|
||||||
>{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}</NTag>
|
>
|
||||||
|
{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}
|
||||||
|
</NTag>
|
||||||
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(<20 分为一般,≥20 分为重要)</span>
|
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(<20 分为一般,≥20 分为重要)</span>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -1175,12 +1192,12 @@ onMounted(async () => {
|
|||||||
<p class="text-xs leading-relaxed text-slate-400">审批链:{{ approvalFlowText }}。专业会签人由申请表「涉及专业」勾选自动增减,可在此调整人选;重要变更自动追加安全审查与分管领导终批。</p>
|
<p class="text-xs leading-relaxed text-slate-400">审批链:{{ approvalFlowText }}。专业会签人由申请表「涉及专业」勾选自动增减,可在此调整人选;重要变更自动追加安全审查与分管领导终批。</p>
|
||||||
<div v-for="(s, idx) in flowList" :key="s.id" class="rounded-lg border border-slate-100 bg-slate-50/40 p-3">
|
<div v-for="(s, idx) in flowList" :key="s.id" class="rounded-lg border border-slate-100 bg-slate-50/40 p-3">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<NTag type="info" size="small">{{Number(idx)+1}}</NTag>
|
<NTag type="info" size="small">{{ Number(idx)+1 }}</NTag>
|
||||||
<p class="text-sm">{{s.name}}</p>
|
<p class="text-sm">{{ s.name }}</p>
|
||||||
<NCheckbox :checked="s.countersign" size="small" @update:checked="(v) => setStepCountersign(s, v)">
|
<NCheckbox :checked="s.countersign" size="small" @update:checked="(v) => setStepCountersign(s, v)">
|
||||||
<span class="text-xs text-slate-500">专业会签步骤</span>
|
<span class="text-xs text-slate-500">专业会签步骤</span>
|
||||||
</NCheckbox>
|
</NCheckbox>
|
||||||
<NButton ghost type="primary" size="tiny" @click="togglePicker(s)" title="添加预设人员" class="ml-auto">
|
<NButton ghost type="primary" size="tiny" title="添加预设人员" class="ml-auto" @click="togglePicker(s)">
|
||||||
<Icon icon="ic:round-plus" class="size-16px" />
|
<Icon icon="ic:round-plus" class="size-16px" />
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -1192,11 +1209,13 @@ onMounted(async () => {
|
|||||||
<span class="shrink-0 truncate text-xs font-medium text-slate-700">{{ m.user_name }}</span>
|
<span class="shrink-0 truncate text-xs font-medium text-slate-700">{{ m.user_name }}</span>
|
||||||
<template v-if="s.countersign">
|
<template v-if="s.countersign">
|
||||||
<span class="text-xs text-slate-400"><span class="text-red-500">*</span>专业:</span>
|
<span class="text-xs text-slate-400"><span class="text-red-500">*</span>专业:</span>
|
||||||
<NSelect :value="m.specialty || null" clearable size="small" placeholder="请选择专业" class="w-28"
|
<NSelect
|
||||||
|
:value="m.specialty || null" clearable size="small" placeholder="请选择专业" class="w-28"
|
||||||
:options="SPECIALTIES"
|
:options="SPECIALTIES"
|
||||||
@update:value="(v) => selectSpecialty(Number(idx), Number(mIdx), v)"
|
@update:value="(v) => selectSpecialty(Number(idx), Number(mIdx), v)"
|
||||||
/>
|
/>
|
||||||
<NCheckbox :checked="m.is_sign" size="small"
|
<NCheckbox
|
||||||
|
:checked="m.is_sign" size="small"
|
||||||
:checked-value="1"
|
:checked-value="1"
|
||||||
:unchecked-value="0"
|
:unchecked-value="0"
|
||||||
@update:checked="(v) => selectSign(Number(idx), Number(mIdx), v)"
|
@update:checked="(v) => selectSign(Number(idx), Number(mIdx), v)"
|
||||||
@@ -1204,16 +1223,18 @@ onMounted(async () => {
|
|||||||
<span class="text-xs text-slate-500">必须参与会签</span>
|
<span class="text-xs text-slate-500">必须参与会签</span>
|
||||||
</NCheckbox>
|
</NCheckbox>
|
||||||
</template>
|
</template>
|
||||||
<NButton text type="error" @click="delMember(s, m.user_id)" title="删除该人员">
|
<NButton text type="error" title="删除该人员" @click="delMember(s, m.user_id)">
|
||||||
<Icon icon="iconamoon:trash" class="size-16px" />
|
<Icon icon="iconamoon:trash" class="size-16px" />
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="s.countersign && s.members.length" class="text-[11px] leading-5 text-slate-400">
|
<p v-if="s.countersign && s.members.length" class="text-[11px] leading-5 text-slate-400">
|
||||||
必须参与会签:勾选的人员必须参与专业会签,未勾选的人员为可选会签(按需参加)
|
必须参与会签:勾选的人员必须参与专业会签,未勾选的人员为可选会签(按需参加)
|
||||||
</p>
|
</p>
|
||||||
<NCascader v-if="pickerStepId === s.id" :value="pick" :options="memberList"
|
<NCascader
|
||||||
|
v-if="pickerStepId === s.id" :value="pick" :options="memberList"
|
||||||
placeholder="请选择人员" size="small" check-strategy="child" :show-path="false" expand-trigger="click"
|
placeholder="请选择人员" size="small" check-strategy="child" :show-path="false" expand-trigger="click"
|
||||||
class="w-56" :on-update:value="(v) => addMember(s, v)" />
|
class="w-56" :on-update:value="(v) => addMember(s, v)"
|
||||||
|
/>
|
||||||
|
|
||||||
<span v-if="s.members.length === 0" class="text-xs leading-7 text-slate-300">未预设</span>
|
<span v-if="s.members.length === 0" class="text-xs leading-7 text-slate-300">未预设</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -1245,12 +1266,12 @@ onMounted(async () => {
|
|||||||
<span>上传时间:{{ previewFile?.created_at }}</span>
|
<span>上传时间:{{ previewFile?.created_at }}</span>
|
||||||
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
||||||
</div>
|
</div>
|
||||||
<previewComponent v-if="previewFile" :previewFile="previewFile" />
|
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NModal>
|
</NModal>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpace vertical :size="16">
|
<NSpace vertical :size="16">
|
||||||
<!-- 高风险 -->
|
<!-- 高风险 -->
|
||||||
<NSpin :show="loading" size="small">
|
<NSpin :show="loading" size="small">
|
||||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
@@ -342,7 +342,9 @@ onMounted(() => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>变更申请表</p>
|
>
|
||||||
|
变更申请表
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
|
<NButton ghost size="small" class="text-xs" @click="exportFile('change')"><Icon icon="material-symbols:download" class="size-16px" />导出变更申请表</NButton>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -371,16 +373,16 @@ onMounted(() => {
|
|||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更等级</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更等级</p>
|
||||||
<div class="flex items-center flex-wrap gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="flex items-center flex-wrap gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<NRadioGroup v-model:value="level">
|
<NRadioGroup v-model:value="level">
|
||||||
<NRadio v-for="item in levelList" :key="item.value" :value="item.value" :disabled="true">{{item.label}}</NRadio>
|
<NRadio v-for="item in levelList" :key="item.value" :value="item.value" :disabled="true">{{ item.label }}</NRadio>
|
||||||
</NRadioGroup>
|
</NRadioGroup>
|
||||||
<NTag type="error" size="small">合计 {{totalScore}} 分</NTag>
|
<NTag type="error" size="small">合计 {{ totalScore }} 分</NTag>
|
||||||
<NButton ghost type="warning" size="small" round class="text-xs" @click="levelDrawer = true">
|
<NButton ghost type="warning" size="small" round class="text-xs" @click="levelDrawer = true">
|
||||||
<Icon icon="lucide:eye" class="size-12px mr-1" />查看等级判定
|
<Icon icon="lucide:eye" class="size-12px mr-1" />查看等级判定
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更类别</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更类别</p>
|
||||||
<div class="flex items-center gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="flex items-center gap-2 px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{matchLabel(typeList,currentInfo?.apply_form?.change_type)?.label}}
|
{{ matchLabel(typeList,currentInfo?.apply_form?.change_type)?.label }}
|
||||||
<NButton v-if="isAiOn" ghost type="primary" size="small" round class="text-xs" @click="openTypeSheet">
|
<NButton v-if="isAiOn" ghost type="primary" size="small" round class="text-xs" @click="openTypeSheet">
|
||||||
<Icon icon="lucide:sparkles" class="size-12px mr-1" />判定说明
|
<Icon icon="lucide:sparkles" class="size-12px mr-1" />判定说明
|
||||||
</NButton>
|
</NButton>
|
||||||
@@ -389,49 +391,54 @@ onMounted(() => {
|
|||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更目的</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">变更目的</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.purposes?.join('、')}}
|
{{ currentInfo?.apply_form?.purposes?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">预期效果</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">预期效果</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.effect}}
|
{{ currentInfo?.apply_form?.effect }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">主要变更</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">主要变更</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<p v-for="(main,mIndex) in currentInfo?.apply_form?.main_changes" :key="mIndex">{{Number(mIndex)+1}}.{{main}}</p>
|
<p v-for="(main,mIndex) in currentInfo?.apply_form?.main_changes" :key="mIndex">{{ Number(mIndex)+1 }}.{{ main }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">连带变更</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">连带变更</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
<p v-for="(related,rIndex) in currentInfo?.apply_form?.related_changes" :key="rIndex">{{Number(rIndex)+1}}.{{related}}</p>
|
<p v-for="(related,rIndex) in currentInfo?.apply_form?.related_changes" :key="rIndex">{{ Number(rIndex)+1 }}.{{ related }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">风险评估方法</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.risk_tools?.join('、')}}
|
<template v-for="(item,index) in currentInfo?.apply_form?.risk_tools" :key="index">
|
||||||
|
<span v-if="index!==0">、</span>
|
||||||
|
<span v-if="item==='RISK'">风险预分析</span>
|
||||||
|
<span v-else-if="item==='RISK_CHECK'">风险检查表</span>
|
||||||
|
<span v-else>{{ item }}</span>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">所需材料</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">所需材料</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.materials}}
|
{{ currentInfo?.apply_form?.materials }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid border-b grid-cols-[100px_1fr]">
|
<div class="grid border-b grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">需更新资料</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">需更新资料</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.update_docs?.join('、')}}
|
{{ currentInfo?.apply_form?.update_docs?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-[100px_1fr]">
|
<div class="grid grid-cols-[100px_1fr]">
|
||||||
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">涉及专业</p>
|
<p class="flex items-center justify-end px-3 py-1.6 text-xs text-slate-500 bg-[#fafafc]">涉及专业</p>
|
||||||
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
<div class="px-3 py-1.6 text-sm leading-relaxed text-slate-800">
|
||||||
{{currentInfo?.apply_form?.disciplines?.join('、')}}
|
{{ currentInfo?.apply_form?.disciplines?.join('、') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -440,7 +447,9 @@ onMounted(() => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>变更附带资料</p>
|
>
|
||||||
|
变更附带资料
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
|
<NButton ghost size="small" class="text-xs" @click="downloadFile(null)"><Icon icon="material-symbols:download" class="size-16px" />一键下载</NButton>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -458,10 +467,10 @@ onMounted(() => {
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(doc,dIndex) in currentInfo?.apply_form?.attachments" :key="dIndex">
|
<tr v-for="(doc,dIndex) in currentInfo?.apply_form?.attachments" :key="dIndex">
|
||||||
<td class="text-center">1</td>
|
<td class="text-center">1</td>
|
||||||
<td>{{doc.file_name}}</td>
|
<td>{{ doc.file_name }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.file_type}}</td>
|
<td class="text-center text-xs">{{ doc?.file_type }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.file_size}}</td>
|
<td class="text-center text-xs">{{ doc?.file_size }}</td>
|
||||||
<td class="text-center text-xs">{{doc?.created_at?.slice(0,16)}}</td>
|
<td class="text-center text-xs">{{ doc?.created_at?.slice(0,16) }}</td>
|
||||||
<td class="text-center text-xs">
|
<td class="text-center text-xs">
|
||||||
<span v-if="doc?.step_no===1">变更申请表</span>
|
<span v-if="doc?.step_no===1">变更申请表</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -480,7 +489,9 @@ onMounted(() => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>风险分析记录表</p>
|
>
|
||||||
|
风险分析记录表
|
||||||
|
</p>
|
||||||
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
|
<NButton ghost size="small" class="text-xs" @click="exportFile('risk')"><Icon icon="material-symbols:download" class="size-16px" />导出风险分析记录表</NButton>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -498,13 +509,13 @@ onMounted(() => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(risk,index) in currentInfo?.risk_records?.records" :key="index">
|
<tr v-for="(risk,index) in currentInfo?.risk_records?.records" :key="index">
|
||||||
<td class="text-center">{{Number(index)+1}}</td>
|
<td class="text-center">{{ Number(index)+1 }}</td>
|
||||||
<td>{{risk.item}}</td>
|
<td>{{ risk.item }}</td>
|
||||||
<td>{{risk.scene}}</td>
|
<td>{{ risk.scene }}</td>
|
||||||
<td class="text-center">{{risk.inherent_level}}</td>
|
<td class="text-center">{{ risk.inherent_level }}</td>
|
||||||
<td>{{risk.safeguards}}</td>
|
<td>{{ risk.safeguards }}</td>
|
||||||
<td>{{risk.suggestions}}</td>
|
<td>{{ risk.suggestions }}</td>
|
||||||
<td class="text-center">{{risk.residual_level}}</td>
|
<td class="text-center">{{ risk.residual_level }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<NTag size="small" type="info" class="text-11px">{{ risk.source==='RISK'?'风险预分析':risk.source==='RISK_CHECK'?'风险检查': risk.source }}</NTag>
|
<NTag size="small" type="info" class="text-11px">{{ risk.source==='RISK'?'风险预分析':risk.source==='RISK_CHECK'?'风险检查': risk.source }}</NTag>
|
||||||
</td>
|
</td>
|
||||||
@@ -519,7 +530,7 @@ onMounted(() => {
|
|||||||
<span class="text-sm font-semibold text-slate-700">变更培训内容</span>
|
<span class="text-sm font-semibold text-slate-700">变更培训内容</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<p>{{currentInfo?.train?.content}}</p>
|
<p>{{ currentInfo?.train?.content }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- PSSR 检查内容 -->
|
<!-- PSSR 检查内容 -->
|
||||||
@@ -529,10 +540,10 @@ onMounted(() => {
|
|||||||
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
|
<span class="text-sm font-semibold text-slate-700">PSSR 检查内容</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div class="space-y-2.5 border p-3" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<div v-for="(pssr,index) in pssrlist" class="border" :key="index" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
<div v-for="(pssr,index) in pssrlist" :key="index" class="border" :style="{borderRadius: themeStore.themeRadius + 'px'}">
|
||||||
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{pssr.g}}</div>
|
<div class="bg-slate-100 px-3 py-1.6 font-medium text-slate-600">{{ pssr.g }}</div>
|
||||||
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
|
<div v-for="item in pssr.items" :key="item.id" class="flex items-center border-t px-3 py-1.6">
|
||||||
<p class="flex-1">{{item.content}}</p>
|
<p class="flex-1">{{ item.content }}</p>
|
||||||
<NTag v-if="item.phase===1" size="small" type="info">投用前完成</NTag>
|
<NTag v-if="item.phase===1" size="small" type="info">投用前完成</NTag>
|
||||||
<NTag v-else size="small" type="info">关闭前完成</NTag>
|
<NTag v-else size="small" type="info">关闭前完成</NTag>
|
||||||
</div>
|
</div>
|
||||||
@@ -557,10 +568,10 @@ onMounted(() => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(accept,index) in acceptList" :key="index">
|
<tr v-for="(accept,index) in acceptList" :key="index">
|
||||||
<td class="text-xs">{{accept.item}}</td>
|
<td class="text-xs">{{ accept.item }}</td>
|
||||||
<td class="text-xs">{{accept.standard}}</td>
|
<td class="text-xs">{{ accept.standard }}</td>
|
||||||
<td class="text-xs">{{accept.method}}</td>
|
<td class="text-xs">{{ accept.method }}</td>
|
||||||
<td class="text-xs text-center">{{accept.org_name}}</td>
|
<td class="text-xs text-center">{{ accept.org_name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</NTable>
|
</NTable>
|
||||||
@@ -571,7 +582,9 @@ onMounted(() => {
|
|||||||
<p
|
<p
|
||||||
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
class="rounded-sm bg-[var(--theme-color)] px-3 py-1 text-xs font-semibold text-white"
|
||||||
:style="{'--theme-color': themeStore.themeColor}"
|
:style="{'--theme-color': themeStore.themeColor}"
|
||||||
>审批记录</p>
|
>
|
||||||
|
审批记录
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -584,10 +597,10 @@ onMounted(() => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(record,index) in currentInfo?.approval_records" :key="index">
|
<tr v-for="(record,index) in currentInfo?.approval_records" :key="index">
|
||||||
<td class="text-xs">{{record.action}}</td>
|
<td class="text-xs">{{ record.action }}</td>
|
||||||
<td class="text-xs">{{record.user_name}}</td>
|
<td class="text-xs">{{ record.user_name }}</td>
|
||||||
<td class="text-center text-xs">{{record.updated_at?.slice(0,16)}}</td>
|
<td class="text-center text-xs">{{ record.updated_at?.slice(0,16) }}</td>
|
||||||
<td class="text-xs">{{record.remark}}</td>
|
<td class="text-xs">{{ record.remark }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</NTable>
|
</NTable>
|
||||||
@@ -599,8 +612,10 @@ onMounted(() => {
|
|||||||
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
|
<template v-for="(n, i) in currentInfo?.approval_flow?.steps" :key="n.name">
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
|
<Icon v-if="i !== 0" icon="formkit:right" class="size-14px text-slate-300" />
|
||||||
<div class="rounded-lg border px-3 py-2 text-center"
|
<div
|
||||||
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'">
|
class="rounded-lg border px-3 py-2 text-center"
|
||||||
|
:class="n.status === 'PASSED' ? 'border-emerald-300 bg-emerald-50' : n.status === 'PENDING' ? 'border-amber-400 bg-amber-50' : n.status === 'REJECTED' ? 'border-red-300 bg-red-50' :'border-amber-400 bg-amber-50'"
|
||||||
|
>
|
||||||
<p class="text-xs font-medium">
|
<p class="text-xs font-medium">
|
||||||
{{ n.name }}
|
{{ n.name }}
|
||||||
</p>
|
</p>
|
||||||
@@ -628,7 +643,8 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
{{ m.user_name }}
|
{{ m.user_name }}
|
||||||
</NTag>
|
</NTag>
|
||||||
<div v-if="m.status === 'PENDING'"
|
<div
|
||||||
|
v-if="m.status === 'PENDING'"
|
||||||
class="cursor-pointer inline-flex h-6 items-center gap-1 rounded-md border border-amber-300 bg-white px-2 text-[11px] text-amber-700 transition hover:bg-amber-100"
|
class="cursor-pointer inline-flex h-6 items-center gap-1 rounded-md border border-amber-300 bg-white px-2 text-[11px] text-amber-700 transition hover:bg-amber-100"
|
||||||
@click="handleReminder(m)"
|
@click="handleReminder(m)"
|
||||||
>
|
>
|
||||||
@@ -638,7 +654,6 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</NCard>
|
</NCard>
|
||||||
<!-- 变更类型判定说明(右侧抽屉) -->
|
<!-- 变更类型判定说明(右侧抽屉) -->
|
||||||
@@ -681,7 +696,9 @@ onMounted(() => {
|
|||||||
textColor: tagTextColor(matchLabel(levelList,level)?.color),
|
textColor: tagTextColor(matchLabel(levelList,level)?.color),
|
||||||
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
|
borderColor: tagBorderColor(matchLabel(levelList,level)?.color),
|
||||||
}"
|
}"
|
||||||
>{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}</NTag>
|
>
|
||||||
|
{{ matchLabel(levelList,level)?.label? matchLabel(levelList,level)?.label+'变更':'' }}
|
||||||
|
</NTag>
|
||||||
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(<20 分为一般,≥20 分为重要)</span>
|
<span class="text-xs text-slate-400">合计得分 <b class="text-[#17407F]">{{ totalScore }}</b> 分(<20 分为一般,≥20 分为重要)</span>
|
||||||
</div>
|
</div>
|
||||||
<NTable size="small">
|
<NTable size="small">
|
||||||
@@ -723,12 +740,12 @@ onMounted(() => {
|
|||||||
<span>上传时间:{{ previewFile?.created_at }}</span>
|
<span>上传时间:{{ previewFile?.created_at }}</span>
|
||||||
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
<span v-if="previewFile?.version">{{ `版本:${previewFile?.version}(受控)` }}</span>
|
||||||
</div>
|
</div>
|
||||||
<previewComponent v-if="previewFile" :previewFile="previewFile" />
|
<PreviewComponent v-if="previewFile" :preview-file="previewFile" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</NModal>
|
</NModal>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -170,8 +170,8 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NSpin :show="loading" size="small">
|
<NSpin :show="loading" size="small">
|
||||||
<div class="space-y-3.5">
|
<div class="space-y-3.5">
|
||||||
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
|
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive>
|
||||||
<NGi span="24 s:24 m:8">
|
<NGi span="24 s:24 m:8">
|
||||||
@@ -186,7 +186,7 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</NGi>
|
</NGi>
|
||||||
<NGi span="24 s:24 m:16" class="flex items-center justify-end gap-12px">
|
<NGi span="24 s:24 m:16" class="flex items-center justify-end gap-12px">
|
||||||
<p class="text-#999 text-xs">{{clock}}</p>
|
<p class="text-#999 text-xs">{{ clock }}</p>
|
||||||
<NButton ghost size="small" @click="jumpTo('workshopstatistics')">
|
<NButton ghost size="small" @click="jumpTo('workshopstatistics')">
|
||||||
车间变更看板
|
车间变更看板
|
||||||
</NButton>
|
</NButton>
|
||||||
@@ -288,18 +288,19 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<template v-if="homeData?.todo_approvals?.total > 0">
|
<template v-if="homeData?.todo_approvals?.total > 0">
|
||||||
<div v-for="row in homeData?.todo_approvals?.items || []" :key="row.change_id" @click="jumpTo('details_approval',row.change_id)"
|
<div
|
||||||
class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition"
|
v-for="row in homeData?.todo_approvals?.items || []" :key="row.change_id" class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition"
|
||||||
:style="{
|
:style="{
|
||||||
borderRadius: themeStore.themeRadius + 'px',
|
borderRadius: themeStore.themeRadius + 'px',
|
||||||
borderColor: row.overdue_status===2?getColorWithOpacity(themeStore.otherColor.error, 0.25):getColorWithOpacity(themeStore.themeColor, 0.25),
|
borderColor: row.overdue_status===2?getColorWithOpacity(themeStore.otherColor.error, 0.25):getColorWithOpacity(themeStore.themeColor, 0.25),
|
||||||
backgroundColor: row.overdue_status===2?getColorWithOpacity(themeStore.otherColor.error, 0.05):getColorWithOpacity(themeStore.themeColor, 0.05),
|
backgroundColor: row.overdue_status===2?getColorWithOpacity(themeStore.otherColor.error, 0.05):getColorWithOpacity(themeStore.themeColor, 0.05),
|
||||||
}"
|
}"
|
||||||
|
@click="jumpTo('details_approval',row.change_id)"
|
||||||
>
|
>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<span class="font-mono text-[11px] text-slate-400">{{ row.change_no }}</span>
|
<span class="font-mono text-[11px] text-slate-400">{{ row.change_no }}</span>
|
||||||
<NTag class="text-[11px]" v-if="row.urgent===1" type="error" size="small">紧急</NTag>
|
<NTag v-if="row.urgent===1" class="text-[11px]" type="error" size="small">紧急</NTag>
|
||||||
<!-- 变更等级 -->
|
<!-- 变更等级 -->
|
||||||
<NTag
|
<NTag
|
||||||
size="small"
|
size="small"
|
||||||
@@ -308,7 +309,9 @@ onUnmounted(() => {
|
|||||||
textColor: tagTextColor(matchObj(levelList,row.change_level)?.color),
|
textColor: tagTextColor(matchObj(levelList,row.change_level)?.color),
|
||||||
borderColor: tagBorderColor(matchObj(levelList,row.change_level)?.color),
|
borderColor: tagBorderColor(matchObj(levelList,row.change_level)?.color),
|
||||||
}"
|
}"
|
||||||
>{{matchObj(levelList,row.change_level)?.label}}</NTag>
|
>
|
||||||
|
{{ matchObj(levelList,row.change_level)?.label }}
|
||||||
|
</NTag>
|
||||||
<!-- 变更类型 -->
|
<!-- 变更类型 -->
|
||||||
<NTag
|
<NTag
|
||||||
size="small"
|
size="small"
|
||||||
@@ -317,22 +320,24 @@ onUnmounted(() => {
|
|||||||
textColor: tagTextColor(matchObj(typeList,row.change_type)?.color),
|
textColor: tagTextColor(matchObj(typeList,row.change_type)?.color),
|
||||||
borderColor: tagBorderColor(matchObj(typeList,row.change_type)?.color),
|
borderColor: tagBorderColor(matchObj(typeList,row.change_type)?.color),
|
||||||
}"
|
}"
|
||||||
>{{matchObj(typeList,row.change_type)?.label}}</NTag>
|
>
|
||||||
|
{{ matchObj(typeList,row.change_type)?.label }}
|
||||||
|
</NTag>
|
||||||
|
|
||||||
<NTag class="text-[11px]" v-if="row.duration_type===2" type="warning" size="small">临时</NTag>
|
<NTag v-if="row.duration_type===2" class="text-[11px]" type="warning" size="small">临时</NTag>
|
||||||
<NTag class="text-[11px]" v-else type="info" size="small">永久</NTag>
|
<NTag v-else class="text-[11px]" type="info" size="small">永久</NTag>
|
||||||
<span v-if="row.overdue_status===2" class="text-xs" :style="{ color: themeStore.otherColor.error }">已超期 {{row.overdue_days}} 天</span>
|
<span v-if="row.overdue_status===2" class="text-xs" :style="{ color: themeStore.otherColor.error }">已超期 {{ row.overdue_days }} 天</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1 flex items-center gap-2">
|
<div class="mt-1 flex items-center gap-2">
|
||||||
<span class="min-w-0 flex-1 truncate text-sm font-medium text-slate-800 dark:text-white">{{ row.title }}</span>
|
<span class="min-w-0 flex-1 truncate text-sm font-medium text-slate-800 dark:text-white">{{ row.title }}</span>
|
||||||
<NTag size="small" type="warning">审批:{{row.step_name}}</NTag>
|
<NTag size="small" type="warning">审批:{{ row.step_name }}</NTag>
|
||||||
<NButton size="small" type="primary" class="text-xs">
|
<NButton size="small" type="primary" class="text-xs">
|
||||||
去审批
|
去审批
|
||||||
<Icon icon="akar-icons:arrow-right" class="size-13px ml-1" />
|
<Icon icon="akar-icons:arrow-right" class="size-13px ml-1" />
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-0.5 truncate text-[11px] text-slate-400 flex items-center gap-2">
|
<div class="mt-0.5 truncate text-[11px] text-slate-400 flex items-center gap-2">
|
||||||
<p>申请人:{{row.applicant_name}}</p>
|
<p>申请人:{{ row.applicant_name }}</p>
|
||||||
<span v-if="row.apply_time" class="text-[11px] text-slate-400">{{ row.apply_time?.slice(0, 10) }}</span>
|
<span v-if="row.apply_time" class="text-[11px] text-slate-400">{{ row.apply_time?.slice(0, 10) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -360,13 +365,14 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<template v-if="homeData?.unclosed_progress?.total > 0">
|
<template v-if="homeData?.unclosed_progress?.total > 0">
|
||||||
<div v-for="row in homeData?.unclosed_progress?.items || []" :key="row.change_id" @click="jumpTo('details_index',row.change_id)"
|
<div
|
||||||
class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition hover:border-[var(--hover-border)] hover:bg-[var(--hover-bg)]"
|
v-for="row in homeData?.unclosed_progress?.items || []" :key="row.change_id" class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition hover:border-[var(--hover-border)] hover:bg-[var(--hover-bg)]"
|
||||||
:style="{
|
:style="{
|
||||||
borderRadius: themeStore.themeRadius + 'px',
|
borderRadius: themeStore.themeRadius + 'px',
|
||||||
'--hover-border': getColorWithOpacity(themeStore.themeColor, 0.25),
|
'--hover-border': getColorWithOpacity(themeStore.themeColor, 0.25),
|
||||||
'--hover-bg': getColorWithOpacity(themeStore.themeColor, 0.05)
|
'--hover-bg': getColorWithOpacity(themeStore.themeColor, 0.05)
|
||||||
}"
|
}"
|
||||||
|
@click="jumpTo('details_index',row.change_id)"
|
||||||
>
|
>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
@@ -387,12 +393,14 @@ onUnmounted(() => {
|
|||||||
textColor: tagTextColor(matchObj(levelList,row.change_level)?.color),
|
textColor: tagTextColor(matchObj(levelList,row.change_level)?.color),
|
||||||
borderColor: tagBorderColor(matchObj(levelList,row.change_level)?.color),
|
borderColor: tagBorderColor(matchObj(levelList,row.change_level)?.color),
|
||||||
}"
|
}"
|
||||||
>{{matchObj(levelList,row.change_level)?.label}}</NTag>
|
>
|
||||||
|
{{ matchObj(levelList,row.change_level)?.label }}
|
||||||
|
</NTag>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1 flex items-center gap-2 font-mono text-[11px] text-slate-400">
|
<div class="mt-1 flex items-center gap-2 font-mono text-[11px] text-slate-400">
|
||||||
<span>{{row.change_no}}</span>
|
<span>{{ row.change_no }}</span>
|
||||||
<span>{{row.org_name}}</span>
|
<span>{{ row.org_name }}</span>
|
||||||
<span>{{row.applicant_name}}</span>
|
<span>{{ row.applicant_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 审批流程 -->
|
<!-- 审批流程 -->
|
||||||
<div v-if="row.flow" class="mt-0.5 truncate text-[11px] flex items-center gap-2">
|
<div v-if="row.flow" class="mt-0.5 truncate text-[11px] flex items-center gap-2">
|
||||||
@@ -400,16 +408,16 @@ onUnmounted(() => {
|
|||||||
<Icon v-if="index!==0" icon="formkit:right" class="size-12px text-slate-400" />
|
<Icon v-if="index!==0" icon="formkit:right" class="size-12px text-slate-400" />
|
||||||
<!-- 通过 -->
|
<!-- 通过 -->
|
||||||
<div v-if="item.status==='PASSED'" class="w-6px h-6px rounded-6px" :style="{ backgroundColor: themeStore.otherColor.success }"></div>
|
<div v-if="item.status==='PASSED'" class="w-6px h-6px rounded-6px" :style="{ backgroundColor: themeStore.otherColor.success }"></div>
|
||||||
<p v-if="item.status==='PASSED'" :style="{ color: themeStore.otherColor.success }">{{item.name}}</p>
|
<p v-if="item.status==='PASSED'" :style="{ color: themeStore.otherColor.success }">{{ item.name }}</p>
|
||||||
<!-- 进行中 -->
|
<!-- 进行中 -->
|
||||||
<div v-if="item.status==='ACTIVE'" class="w-6px h-6px rounded-6px" :style="{ backgroundColor: themeStore.otherColor.warning }"></div>
|
<div v-if="item.status==='ACTIVE'" class="w-6px h-6px rounded-6px" :style="{ backgroundColor: themeStore.otherColor.warning }"></div>
|
||||||
<p v-if="item.status==='ACTIVE'" :style="{ color: themeStore.otherColor.warning }">{{item.name}}</p>
|
<p v-if="item.status==='ACTIVE'" :style="{ color: themeStore.otherColor.warning }">{{ item.name }}</p>
|
||||||
<!-- 待 -->
|
<!-- 待 -->
|
||||||
<div v-if="item.status==='PENDING'" class="w-6px h-6px rounded-6px bg-slate-400"></div>
|
<div v-if="item.status==='PENDING'" class="w-6px h-6px rounded-6px bg-slate-400"></div>
|
||||||
<p v-if="item.status==='PENDING'" class="text-slate-400">{{item.name}}</p>
|
<p v-if="item.status==='PENDING'" class="text-slate-400">{{ item.name }}</p>
|
||||||
<!-- 驳回 -->
|
<!-- 驳回 -->
|
||||||
<div v-if="item.status==='REJECTED'" class="w-6px h-6px rounded-6px" :style="{ backgroundColor: themeStore.otherColor.error }"></div>
|
<div v-if="item.status==='REJECTED'" class="w-6px h-6px rounded-6px" :style="{ backgroundColor: themeStore.otherColor.error }"></div>
|
||||||
<p v-if="item.status==='REJECTED'" :style="{ color: themeStore.otherColor.error }">{{item.name}}</p>
|
<p v-if="item.status==='REJECTED'" :style="{ color: themeStore.otherColor.error }">{{ item.name }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -433,7 +441,8 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<template v-if="homeData?.temp_after_use?.total > 0">
|
<template v-if="homeData?.temp_after_use?.total > 0">
|
||||||
<div v-for="row in homeData?.temp_after_use?.items || []" :key="row.change_id"
|
<div
|
||||||
|
v-for="row in homeData?.temp_after_use?.items || []" :key="row.change_id"
|
||||||
class="flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition"
|
class="flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition"
|
||||||
:style="{
|
:style="{
|
||||||
borderRadius: themeStore.themeRadius + 'px',
|
borderRadius: themeStore.themeRadius + 'px',
|
||||||
@@ -444,7 +453,7 @@ onUnmounted(() => {
|
|||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<span class="min-w-0 flex-1 truncate text-sm font-medium text-slate-800 dark:text-white">{{ row.title }}</span>
|
<span class="min-w-0 flex-1 truncate text-sm font-medium text-slate-800 dark:text-white">{{ row.title }}</span>
|
||||||
<NTag v-if="row.overdue_status===2" size="small" type="error">已超期{{row.overdue_days}}天</NTag>
|
<NTag v-if="row.overdue_status===2" size="small" type="error">已超期{{ row.overdue_days }}天</NTag>
|
||||||
<NButton v-if="row.overdue_status===2" size="tiny" :disabled="btnLoading" @click="urge(row.change_id)">去催办</NButton>
|
<NButton v-if="row.overdue_status===2" size="tiny" :disabled="btnLoading" @click="urge(row.change_id)">去催办</NButton>
|
||||||
<NButton v-else size="tiny" @click="jumpTo('changeledger')">查看</NButton>
|
<NButton v-else size="tiny" @click="jumpTo('changeledger')">查看</NButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -458,10 +467,10 @@ onUnmounted(() => {
|
|||||||
<span v-if="row.status==='CLOSED'">已关闭</span>
|
<span v-if="row.status==='CLOSED'">已关闭</span>
|
||||||
<span v-if="row.status==='WITHDRAWN'">已撤回</span>
|
<span v-if="row.status==='WITHDRAWN'">已撤回</span>
|
||||||
<span v-if="row.status==='REJECTED'">已驳回</span>
|
<span v-if="row.status==='REJECTED'">已驳回</span>
|
||||||
<span v-if="row.use_time">{{row.use_time?.slice(0, 16)}} 投用</span>
|
<span v-if="row.use_time">{{ row.use_time?.slice(0, 16) }} 投用</span>
|
||||||
<span v-else>尚未投用</span>
|
<span v-else>尚未投用</span>
|
||||||
<p v-if="row.use_time">计划恢复 {{row.restore_deadline?.slice(0, 10)}}<span>(已延期 1 次)</span></p>
|
<p v-if="row.use_time">计划恢复 {{ row.restore_deadline?.slice(0, 10) }}<span>(已延期 1 次)</span></p>
|
||||||
<span v-else>原计划恢复 {{row.restore_deadline?.slice(0, 10)}}</span>
|
<span v-else>原计划恢复 {{ row.restore_deadline?.slice(0, 10) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -484,15 +493,16 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<template v-if="homeData?.key_attention?.total > 0">
|
<template v-if="homeData?.key_attention?.total > 0">
|
||||||
<div v-for="row in homeData?.key_attention?.items || []" :key="row.change_id"
|
<div
|
||||||
|
v-for="row in homeData?.key_attention?.items || []" :key="row.change_id"
|
||||||
class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition !hover:border-[var(--hover-border)]"
|
class="cursor-pointer flex w-full items-center gap-3 border px-3.5 py-2.5 text-left transition !hover:border-[var(--hover-border)]"
|
||||||
@click="jumpTo('details_index',row.change_id)"
|
|
||||||
:style="{
|
:style="{
|
||||||
borderRadius: themeStore.themeRadius + 'px',
|
borderRadius: themeStore.themeRadius + 'px',
|
||||||
'--hover-border': getColorWithOpacity(themeStore.otherColor.error, 0.3),
|
'--hover-border': getColorWithOpacity(themeStore.otherColor.error, 0.3),
|
||||||
backgroundColor: getColorWithOpacity(themeStore.otherColor.error, 0.05),
|
backgroundColor: getColorWithOpacity(themeStore.otherColor.error, 0.05),
|
||||||
borderColor: getColorWithOpacity(themeStore.otherColor.error, 0.05),
|
borderColor: getColorWithOpacity(themeStore.otherColor.error, 0.05),
|
||||||
}"
|
}"
|
||||||
|
@click="jumpTo('details_index',row.change_id)"
|
||||||
>
|
>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
@@ -509,7 +519,7 @@ onUnmounted(() => {
|
|||||||
<span v-if="row.status==='CLOSED'">已关闭</span>
|
<span v-if="row.status==='CLOSED'">已关闭</span>
|
||||||
<span v-if="row.status==='WITHDRAWN'">已撤回</span>
|
<span v-if="row.status==='WITHDRAWN'">已撤回</span>
|
||||||
<span v-if="row.status==='REJECTED'">已驳回</span>
|
<span v-if="row.status==='REJECTED'">已驳回</span>
|
||||||
<span>{{row.applicant_name}}</span>
|
<span>{{ row.applicant_name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<NButton text><Icon icon="formkit:right" class="size-14px text-slate-400" /></NButton>
|
<NButton text><Icon icon="formkit:right" class="size-14px text-slate-400" /></NButton>
|
||||||
@@ -623,13 +633,13 @@ onUnmounted(() => {
|
|||||||
<RingChart v-if="homeData" :data="homeData?.accept_conclusion?.items || []" :total="homeData?.accept_conclusion?.total_count || 0" />
|
<RingChart v-if="homeData" :data="homeData?.accept_conclusion?.items || []" :total="homeData?.accept_conclusion?.total_count || 0" />
|
||||||
<div class="flex items-center justify-between border-slate-200 border-t pt-2 border-dashed">
|
<div class="flex items-center justify-between border-slate-200 border-t pt-2 border-dashed">
|
||||||
<span class="text-[11px] text-slate-400">投入合计(变更材料和实施费)</span>
|
<span class="text-[11px] text-slate-400">投入合计(变更材料和实施费)</span>
|
||||||
<span class="text-xs font-bold" :style="{ color: themeStore.themeColor }">{{homeData?.accept_conclusion?.total_fee || 0}} 万元</span>
|
<span class="text-xs font-bold" :style="{ color: themeStore.themeColor }">{{ homeData?.accept_conclusion?.total_fee || 0 }} 万元</span>
|
||||||
</div>
|
</div>
|
||||||
</NCard>
|
</NCard>
|
||||||
</NGi>
|
</NGi>
|
||||||
</NGrid>
|
</NGrid>
|
||||||
</div>
|
</div>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
Reference in New Issue
Block a user