Files
moc/src/views/details/closeDoc/index.vue
T
2026-09-16 17:16:17 +08:00

276 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { useRouterPush } from '@/hooks/common/router';
import { useRoute } from 'vue-router';
import { getColorWithOpacity, tagTextColor, tagBgColor, tagBorderColor } from '@/utils/common';
import { systemConfigApi } from '@/service/api/system';
import { getChangeDetailApi } from '@/service/api/change';
const themeStore = useThemeStore();
const { routerPushByKey } = useRouterPush();
const route = useRoute();
const loading = ref<boolean>(false);
// 当前变更详情
const currentInfo = ref<any>(null);
// 当前变更id
const currentId = ref<number>(0);
// 是否开启 AI 辅助功能
const isAiOn = ref<boolean>(false);
// 变更等级选项
const levelList = ref<any>([]);
// 变更类型选项
const typeList = ref<any>([]);
// 实际投用日期
const useDate = ref<number | null>(null);
// 变更材料和实施费(万元)
const price = ref<number | null>(null);
const list = ref<any>([
{isArchiving:0,name:'变更申请表及审批记录',files:[{file_name:'审批记录(含会签意见).pdf',file_type:'pdf',file_url:''}]},
{isArchiving:1,name:'风险分析记录(风险预分析 / HAZOP / FMEA / 风险检查表)',files:[]},
{isArchiving:0,name:'培训签到与考核记录',files:[]},
{isArchiving:0,name:'PSSR 检查记录(含现场照片)',files:[]},
{isArchiving:2,name:'验收报告与运行数据',files:[]},
{isArchiving:0,name:'更新后的 P&ID / 操作规程(受控最新版)',files:[]},
{isArchiving:0,name:'设备 / 联锁台账更新记录',files:[]},
{isArchiving:0,name:'应急预案修订',files:[]},
]);
// 删除文件
const removeFile = (item:any, fileIndex:number) => {
item.files.splice(fileIndex, 1);
}
// 返回
const back = () => {
routerPushByKey('my_mytask');
};
// 获取变更详情
const getDetail = async () => {
loading.value = true;
const {data,error} = await getChangeDetailApi(currentId.value)
if(!error){
currentInfo.value = data;
console.log(data)
}
loading.value = false;
};
// 获取系统配置
const getConfig = async () => {
loading.value = true;
const {data,error} = await systemConfigApi();
if(!error){
// 解析 AI 辅助功能
const aiAssistGroup = data.find((group:{group_key:string}) => group.group_key === 'ai_assist');
if (aiAssistGroup) {
const target = aiAssistGroup?.items?.find((item:any) => item.item_key === 'enabled');
if (target) {
isAiOn.value = target.value==1?true:false;
}
}
// 解析 变更类型设置
const changeTypeGroup = data.find((group:{group_key:string}) => group.group_key === 'change_type');
if (changeTypeGroup) {
typeList.value = changeTypeGroup.items.map((item:any) => ({
...item,
value: Number(item.value)
}));
}
// 解析 变更等级设置
const changeLevelGroup = data.find((group:{group_key:string}) => group.group_key === 'change_level');
if (changeLevelGroup) {
levelList.value = changeLevelGroup.items.map((item:any) => ({
...item,
value: Number(item.value)
}));
}
getDetail();
}
loading.value = false;
}
onMounted(async () => {
if(route.query && route.query.id){
if(route.query.id){
currentId.value = Number(route.query.id);
getConfig();
}
}
})
</script>
<template>
<NSpace vertical :size="16">
<!-- 本专业高风险 -->
<NSpin :show="loading" size="small">
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
<div
class="flex flex-wrap items-center gap-3 border border-slate-200 px-3 py-2 mb-3"
:style="{ borderRadius: themeStore.themeRadius + 'px' }"
>
<NButton ghost type="primary" @click="back">
<Icon icon="ep:back" class="size-16px mr-1" />返回
</NButton>
<div class="min-w-0 flex-1 truncate text-base font-bold text-slate-800">{{ currentInfo?.title }}</div>
<NTag size="small" type="info" class="font-mono text-xs">编号{{ currentInfo?.change_no }}</NTag>
</div>
<div class="space-y-3 scroll">
<!-- 投用前确认 -->
<div class="border rounded-md">
<div class="flex items-center gap-x-3 px-4 py-2.5 border-b">
<p class="font-600 text-slate-800 text-sm">投用前确认含变更培训投用前检查</p>
<span class="text-slate-400 text-xs">上传线下纸质表照片 / 扫描件即视为完成确认上传后可查阅下载也可在移动端 / PC 端逐条确认空白模板可下载</span>
</div>
<div class="p-3">
<div class="border rounded-lg py-3 px-4 flex items-center gap-3">
<Icon icon="bi:upload" class="size-18px" :style="{ color: themeStore.themeColor }" />
<div class="flex-1">
<p class="text-slate-800 text-sm font-600">上传 PSSR 检查</p>
<p class="text-slate-400 text-xs mt-0.5 leading-4">PSSR 纸质确认表照片或扫描件上传后视为 PSSR 全项确认完成具备投用条件</p>
</div>
<NButton ghost type="primary" size="small" class="text-xs">
<Icon icon="akar-icons:download" class="size-14px mr-1" />
下载PSSR检查表
</NButton>
<NButton type="primary" size="small" class="text-xs">上传</NButton>
</div>
</div>
</div>
<!-- 变更投用时间 -->
<div class="border rounded-md">
<div class="flex items-center gap-x-3 px-4 py-2.5 border-b">
<p class="font-600 text-slate-800 text-sm">变更投用时间</p>
</div>
<div class="p-3">
<div class="flex items-center gap-2">
<p class="text-sm text-slate-600">实际投用时间</p>
<NDatePicker v-model:value="useDate" type="date" size="small" />
<p class="text-xs text-slate-400 mt-1px">默认为当天日期可按实际投用日期调整</p>
</div>
<div class="mt-2.5 rounded-lg border px-3 py-2 text-[11px] leading-5 border-amber-200 bg-amber-50/60 text-amber-700"> 投用提示投用前应完成 PSSR 检查和培训上方入口上传或移动端 / PC 端逐条确认)。 当前培训签到PSSR 检查尚未确认未完成的变更不得投用</div>
</div>
</div>
<!-- 变更验收 -->
<div class="border rounded-md">
<div class="flex items-center gap-x-3 px-4 py-2.5 border-b">
<p class="font-600 text-slate-800 text-sm">变更验收</p>
<span class="text-slate-400 text-xs">投用后组织验收上传验收资料并选择验收结论上传后可查阅下载验收表可下载</span>
</div>
<div class="p-3 space-y-2.5">
<div class="border rounded-lg py-3 px-4 flex items-center gap-3">
<Icon icon="bi:upload" class="size-18px" :style="{ color: themeStore.themeColor }" />
<div class="flex-1">
<p class="text-slate-800 text-sm font-600">上传验收资料</p>
<p class="text-slate-400 text-xs mt-0.5 leading-4">验收报告运行数据记录等验收证明材料上传后纳入归档清单</p>
</div>
<NButton ghost type="primary" size="small" class="text-xs">
<Icon icon="akar-icons:download" class="size-14px mr-1" />
下载验收表
</NButton>
<NButton type="primary" size="small" class="text-xs">上传</NButton>
</div>
<div class="border rounded-lg py-3 px-4 flex items-center gap-3">
<p class="text-xs font-600" :style="{ color: themeStore.themeColor }">变更材料和实施费万元</p>
<NInputNumber v-model:value="price" size="small" :min="0" :show-button="false" placeholder="如 12.6" />
<p class="text-xs text-slate-400 mt-1px">非必填 · 填报本次变更材料与实施费用合计用于变更投入与效果统计</p>
</div>
</div>
</div>
<!-- 变更关闭资料归档确认 -->
<div class="border rounded-md">
<div class="flex items-center gap-x-3 px-4 py-2.5 border-b">
<p class="font-600 text-slate-800 text-sm">变更关闭资料归档确认</p>
<span class="text-slate-400 text-xs"> = 已归档 · = 待归档本地上传或从变更附件选择完成后自动转为」)· 不涉及 = 无需处理</span>
<NButton size="small" type="primary" ghost class="ml-auto text-xs">AI辅助判定</NButton>
</div>
<div class="p-3">
<NTable size="small">
<thead>
<tr>
<th>资料名称</th>
<th class="!text-center">是否归档</th>
<th class="w-200px !text-center">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in list" :key="index">
<td>
<p>{{item.name}}</p>
<div v-if="item.files.length" class="flex flex-wrap">
<div
v-for="(file, fileIndex) in item.files"
:key="fileIndex"
class="text-11px flex items-center gap-2 border py-0.5 px-1.5 rounded-md text-[#17407F] border-[#ACC6E5] bg-[#EAF0F9]"
>
<Icon icon="akar-icons:file" class="size-12px" />
{{file.file_name}}
<NButton text type="primary" class="text-11px">预览</NButton>
<NButton text type="primary" class="text-11px">下载</NButton>
<NPopconfirm
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
@positive-click="removeFile(item, fileIndex)"
>
<template #trigger>
<NButton text type="error" class="text-11px">删除</NButton>
</template>
确定删除吗
</NPopconfirm>
</div>
</div>
</td>
<td>
<div class="flex justify-center gap-2">
<NButton size="small" :type="item.isArchiving === 1 ? 'primary' : 'default'" class="text-xs"></NButton>
<NButton size="small" :type="item.isArchiving === 0 ? 'primary' : 'default'" class="text-xs"></NButton>
<NButton size="small" :type="item.isArchiving === 2 ? 'primary' : 'default'" class="text-xs">不涉及</NButton>
</div>
</td>
<td>
<div v-if="item.isArchiving === 0" class="flex justify-center gap-2">
<NButton size="small" class="text-xs">从变更附件选择</NButton>
<NButton size="small" type="primary" ghost class="text-xs">本地上传</NButton>
</div>
<div v-if="item.isArchiving === 1" class="flex justify-end gap-2">
<NTag size="small" type="success" class="text-xs">
<template #icon>
<Icon icon="akar-icons:circle-check" class="size-12px" />
</template>
已归档1件
</NTag>
</div>
<div v-if="item.isArchiving === 2" class="flex justify-end gap-2">
<span class="text-xs text-slate-400">无需处理</span>
</div>
</td>
</tr>
</tbody>
</NTable>
</div>
</div>
</div>
<div class="flex items-center justify-between border-t pt-3 mt-3">
<p class="text-xs text-slate-400">待归档 5 培训签到与考核记录PSSR 检查记录含现场照片)、验收报告与运行数据更新后的 P&ID / 操作规程受控最新版)、设备 / 联锁台账更新记录</p>
<div class="flex gap-2">
<NButton ghost size="small" @click="back">取消</NButton>
<NButton ghost type="primary" size="small">保存</NButton>
<NButton type="primary" size="small">申请关闭</NButton>
</div>
</div>
</NCard>
</NSpin>
</NSpace>
</template>
<style scoped lang="scss">
.scroll {
height: calc(100vh - 263px);
overflow-y: auto;
}
</style>