276 lines
15 KiB
Vue
276 lines
15 KiB
Vue
<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>
|