384 lines
12 KiB
Vue
384 lines
12 KiB
Vue
<script setup lang="ts">
|
|
import { computed, onMounted, provide, ref } from 'vue';
|
|
import { Icon } from '@iconify/vue'
|
|
import { useThemeStore } from '@/store/modules/theme';
|
|
import { getColorWithOpacity } from "@/utils/common";
|
|
import { localStg } from '@/utils/storage';
|
|
import { queryUnsavedApi, saveChangeApi, submitChangeApi } from '@/service/api/change';
|
|
import { systemConfigApi, templateListApi, } from '@/service/api/system';
|
|
import { orgListApi } from '@/service/api/user';
|
|
import ChangePre from "./modules/changePre.vue";
|
|
import ChangeApply from "./modules/changeApply.vue";
|
|
import ChangeTraining from "./modules/changeTraining.vue";
|
|
import RiskAnalysis from "./modules/riskAnalysis.vue";
|
|
import Pssr from "./modules/pssr.vue";
|
|
import Evaluation from "./modules/evaluation.vue";
|
|
import CloseConfirm from "./modules/closeConfirm.vue";
|
|
|
|
const themeStore = useThemeStore();
|
|
|
|
const saveLoading = ref<boolean>(false)
|
|
const btnDisabled = ref<boolean>(false);
|
|
provide('generalLoading', {saveLoading,btnDisabled})
|
|
// **********************通用字段***********************
|
|
const changePreRef = ref<any>(null);
|
|
const changeApplyRef = ref<any>(null);
|
|
const riskAnalysisRef = ref<any>(null);
|
|
const changeTrainingRef = ref<any>(null);
|
|
const pssrRef = ref<any>(null);
|
|
const evaluationRef = ref<any>(null);
|
|
const closeConfirmRef = ref<any>(null);
|
|
// 组织树
|
|
const orgTree = ref<any>([]);
|
|
// 变更类型选项
|
|
const typeList = ref<{label: string, value: number, color: string}[]>([]);
|
|
// 变更等级选项
|
|
const levelList = ref<{label: string, value: number, color: string}[]>([]);
|
|
// 模板列表
|
|
const templateList = ref<any[]>([]);
|
|
|
|
// 是否开启ai功能
|
|
const aiEnabled = ref<boolean>(localStg.get('userInfo')?.ai_assist_enabled=='1' ? true : false);
|
|
// 变更名称
|
|
const title = ref<string>('');
|
|
// 变更编号
|
|
const changeNo = ref<string>('');
|
|
// 当前id
|
|
const currentId = ref<number>(0);
|
|
// 是否确认
|
|
const confirmed = ref<{[key: string]: boolean}>({
|
|
'pre': false,
|
|
'form': false,
|
|
'risk': false,
|
|
'train': false,
|
|
'pssr': false,
|
|
'evaluation': false,
|
|
// 'close': false,
|
|
});
|
|
|
|
// 变更预分析表单数据
|
|
const changePreForm = ref<any>(null)
|
|
const changeApplyForm = ref<any>(null)
|
|
|
|
// **********************tab切换***********************
|
|
const TABS = [
|
|
{ id: "pre", name: "变更预识别", icon: 'lucide:sparkles' },
|
|
{ id: "form", name: "变更申请表", icon: 'akar-icons:file' },
|
|
{ id: "risk", name: "风险分析记录表", icon: 'proicons:alert-triangle' },
|
|
{ id: "train", name: "变更培训内容", icon: 'lucide:graduation-cap' },
|
|
{ id: "pssr", name: "PSSR 检查内容", icon: 'tabler:clipboard-check' },
|
|
{ id: "evaluation", name: "验收评价", icon: 'material-symbols:check-circle-outline' },
|
|
// { id: "close", name: "变更关闭确认表", icon: 'quill:folder-open' },
|
|
];
|
|
// 当前标签
|
|
const tab = ref<string>(aiEnabled.value ? "pre" : "form");
|
|
// tab 列表
|
|
const tabList = computed(() => {
|
|
return aiEnabled.value ? TABS : TABS.filter((x) => x.id !== "pre");
|
|
});
|
|
// tab 切换
|
|
const tabChange = (id: string) => {
|
|
if(tab.value==='pre'){
|
|
changePreForm.value = changePreRef.value?.form;
|
|
// if(!changePreForm.value?.description){
|
|
// return window.$message?.warning('请先填写变更内容描述');
|
|
// }
|
|
}
|
|
if(tab.value==='form'){
|
|
changeApplyForm.value = changeApplyRef.value?.form;
|
|
}
|
|
if(tab.value === id) {
|
|
return;
|
|
}
|
|
tab.value = id;
|
|
}
|
|
|
|
// 标签内容确认
|
|
const confirmTab = (tab: string, val: boolean) => {
|
|
confirmed.value[tab] = val;
|
|
}
|
|
|
|
// 查询变更未保存数据
|
|
const getId = async () => {
|
|
const {data,error} = await queryUnsavedApi();
|
|
if(!error){
|
|
currentId.value = data.id;
|
|
changeNo.value = data.change_no;
|
|
}
|
|
}
|
|
// 获取配置
|
|
const getConfig = async () => {
|
|
const {data,error} = await systemConfigApi();
|
|
if(!error){
|
|
// 解析 变更类型设置
|
|
const changeTypeGroup = data.find((group:{group_key:string}) => group.group_key === 'change_type');
|
|
if (changeTypeGroup) {
|
|
typeList.value = changeTypeGroup.items.map((item:any) => ({
|
|
label: item.label,
|
|
value: Number(item.value), // 或者 parseInt(item.value, 10)
|
|
color: item.color
|
|
}));
|
|
}
|
|
// 解析 变更等级设置
|
|
const changeLevelGroup = data.find((group:{group_key:string}) => group.group_key === 'change_level');
|
|
if (changeLevelGroup) {
|
|
levelList.value = changeLevelGroup.items.map((item:any) => ({
|
|
label: item.label,
|
|
value: Number(item.value), // 或者 parseInt(item.value, 10)
|
|
color: item.color
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
// 获取模板配置
|
|
const getTemplateConfig = async () => {
|
|
const {data,error} = await templateListApi();
|
|
if(!error){
|
|
templateList.value = data;
|
|
}
|
|
}
|
|
// 获取组织列表
|
|
const getOrgList = async () => {
|
|
const {data,error} = await orgListApi();
|
|
if(!error){
|
|
orgTree.value = data;
|
|
}
|
|
}
|
|
|
|
|
|
// 获取所有表单数据
|
|
const getAllFormData = () => {
|
|
let changePreForm = changePreRef.value?.form;
|
|
let changeApplyForm = changeApplyRef.value?.form;
|
|
let changeRiskForm = riskAnalysisRef.value?.form;
|
|
let changeTrainingForm = changeTrainingRef.value?.form;
|
|
let pssrForm = pssrRef.value?.list;
|
|
let evaluationForm = evaluationRef.value?.list;
|
|
// let closeConfirmForm = closeConfirmRef.value?.form;
|
|
return {
|
|
title: title.value,
|
|
...changePreForm,
|
|
...changeApplyForm,
|
|
...changeRiskForm,
|
|
...changeTrainingForm,
|
|
...pssrForm,
|
|
...evaluationForm,
|
|
};
|
|
}
|
|
|
|
// 保存草稿
|
|
const saveDraft = async () => {
|
|
let form = getAllFormData();
|
|
saveLoading.value = true;
|
|
btnDisabled.value = true;
|
|
const {error} = await saveChangeApi(currentId.value, form);
|
|
if(!error){
|
|
window.$message?.success("已保存为草稿,可在左侧「我的草稿」中继续编辑");
|
|
}
|
|
saveLoading.value = false;
|
|
btnDisabled.value = false;
|
|
}
|
|
|
|
// 变更申请表表单必填判断
|
|
const changeApplyRules = (form:any) => {
|
|
if(form.org_id === null){
|
|
window.$message?.warning('请选择申请部门');
|
|
return true
|
|
}
|
|
if(form.main_changes?.length===0){
|
|
window.$message?.warning('请添加主要变更内容');
|
|
return true
|
|
}
|
|
if(form.main_changes.some((str:string)=>str.trim()==='')){
|
|
window.$message?.warning('请填写主要变更内容');
|
|
return true
|
|
}
|
|
if(form.change_type===null){
|
|
window.$message?.warning('请选择变更类型');
|
|
return true
|
|
}
|
|
if(form.change_level===null){
|
|
window.$message?.warning('请选择变更等级');
|
|
return true
|
|
}
|
|
if(form.duration_type===null){
|
|
window.$message?.warning('请选择变更时限');
|
|
return true
|
|
}
|
|
if(form.duration_type === 1 && form.restore_deadline===null){
|
|
window.$message?.warning('请选择计划恢复时间');
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// 提交
|
|
const submitConfirm = async (type: string) => {
|
|
if(aiEnabled.value){
|
|
const allTrue = Object.values(confirmed.value).every(value => value === true);
|
|
if(!allTrue){
|
|
return window.$message?.warning('全部标签页确认后方可提交(标签栏已用红点标出)');
|
|
}
|
|
}
|
|
let form = getAllFormData();
|
|
if(form.title.trim() === ''){
|
|
return window.$message?.warning('请填写变更名称');
|
|
}
|
|
// 变更申请表
|
|
if(type==='form'){
|
|
if(changeApplyRules(form)){
|
|
return;
|
|
}
|
|
}
|
|
// 变更培训内容
|
|
if(type==='train'){
|
|
if(form.content.trim() === ''){
|
|
return window.$message?.warning('请填写培训内容');
|
|
}
|
|
}
|
|
const {error} = await submitChangeApi(currentId.value, form);
|
|
if(!error){
|
|
window.$message?.success("提交成功");
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
getOrgList();
|
|
getConfig();
|
|
getTemplateConfig();
|
|
getId();
|
|
});
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<NSpace vertical :size="16">
|
|
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
|
<div class="border" :style="{ borderRadius: themeStore.themeRadius + 'px', height: '100%' }">
|
|
<!-- 顶部 -->
|
|
<div class="border-b bg-[var(--bg-color)]" :style="{'--bg-color': getColorWithOpacity(themeStore.themeColor, 0.1)}">
|
|
<div
|
|
class="flex flex-wrap items-center gap-x-3 gap-y-2 border-b px-4 py-2 border-[var(--border-color)]"
|
|
:style="{'--border-color': getColorWithOpacity(themeStore.themeColor, 0.2)}"
|
|
>
|
|
<span class="whitespace-nowrap text-sm font-medium text-slate-600">变更名称 <span class="text-red-500">*</span></span>
|
|
<NInput v-model:value="title" maxlength="28" show-count placeholder="AI 自动总结(28 字以内),可手动修改" class="!w-420px" />
|
|
<span class="ml-auto whitespace-nowrap text-sm text-slate-500">变更编号</span>
|
|
<NInput :value="changeNo" disabled class="!w-44" placeholder="" />
|
|
</div>
|
|
<div class="flex items-center gap-1 overflow-x-auto px-3 pt-2">
|
|
<div v-for="t in tabList" :key="t.id" @click="tabChange(t.id)"
|
|
class="flex items-center gap-1.5 whitespace-nowrap px-3 py-2 text-sm transition cursor-pointer border hover:bg-white/60 rounded-t-lg"
|
|
:class="tab === t.id ? 'border-b-transparent border-[var(--border-color)] bg-white text-[var(--active-color)]':'border-transparent text-slate-500'"
|
|
:style="{
|
|
'--border-color': getColorWithOpacity(themeStore.themeColor, 0.3),
|
|
'--active-color': themeStore.themeColor
|
|
}"
|
|
>
|
|
<Icon :icon="t.icon" class="size-14px" />
|
|
{{ t.name }}
|
|
<span v-if="!confirmed[t.id] && t.id!=='pre' && aiEnabled" class="h-1.5 w-1.5 rounded-full bg-red-500"></span>
|
|
<Icon v-if="confirmed[t.id] && t.id!=='pre' && aiEnabled" icon="material-symbols:check-circle-outline" class="size-14px text-emerald-500" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- ===== 变更预识别 ===== -->
|
|
<div v-show="tab === 'pre'">
|
|
<ChangePre
|
|
ref="changePreRef"
|
|
:title="title"
|
|
:currentId="currentId"
|
|
@save="saveDraft"
|
|
/>
|
|
</div>
|
|
<!-- ===== 变更申请表 ===== -->
|
|
<div v-show="tab === 'form'">
|
|
<ChangeApply
|
|
ref="changeApplyRef"
|
|
:type="tab"
|
|
:orgTree="orgTree"
|
|
:templateList="templateList"
|
|
:typeList="typeList"
|
|
:levelList="levelList"
|
|
:isAiOpen="aiEnabled"
|
|
:title="title"
|
|
:currentId="currentId"
|
|
:formInfo="changePreForm"
|
|
@save="saveDraft"
|
|
@submit="submitConfirm"
|
|
@confirmTab="confirmTab"
|
|
/>
|
|
</div>
|
|
<!-- ===== 风险分析记录表 ===== -->
|
|
<div v-show="tab === 'risk'">
|
|
<RiskAnalysis
|
|
ref="riskAnalysisRef"
|
|
:type="tab"
|
|
:isAiOpen="aiEnabled"
|
|
:title="title"
|
|
:currentId="currentId"
|
|
:formInfo="changeApplyForm"
|
|
@save="saveDraft"
|
|
@submit="submitConfirm"
|
|
@confirmTab="confirmTab"
|
|
/>
|
|
</div>
|
|
<!-- 变更培训内容 -->
|
|
<div v-show="tab === 'train'">
|
|
<ChangeTraining
|
|
ref="changeTrainingRef"
|
|
:type="tab"
|
|
:isAiOpen="aiEnabled"
|
|
:title="title"
|
|
:currentId="currentId"
|
|
@save="saveDraft"
|
|
@submit="submitConfirm"
|
|
@confirmTab="confirmTab"
|
|
/>
|
|
</div>
|
|
<!-- PSSR 检查内容 -->
|
|
<div v-show="tab === 'pssr'">
|
|
<Pssr
|
|
ref="pssrRef"
|
|
:type="tab"
|
|
:isAiOpen="aiEnabled"
|
|
:title="title"
|
|
:currentId="currentId"
|
|
@save="saveDraft"
|
|
@submit="submitConfirm"
|
|
@confirmTab="confirmTab"
|
|
/>
|
|
</div>
|
|
<!-- 验收评价 -->
|
|
<div v-show="tab === 'evaluation'">
|
|
<Evaluation
|
|
ref="evaluationRef"
|
|
:type="tab"
|
|
:orgTree="orgTree"
|
|
:isAiOpen="aiEnabled"
|
|
:title="title"
|
|
:currentId="currentId"
|
|
:formInfo="changeApplyForm"
|
|
@save="saveDraft"
|
|
@submit="submitConfirm"
|
|
@confirmTab="confirmTab"
|
|
/>
|
|
</div>
|
|
<!-- 变更关闭确认表 -->
|
|
<div v-show="tab === 'close'">
|
|
<CloseConfirm
|
|
ref="closeConfirmRef"
|
|
:type="tab"
|
|
:isAiOpen="aiEnabled"
|
|
:title="title"
|
|
:currentId="currentId"
|
|
@save="saveDraft"
|
|
@submit="submitConfirm"
|
|
@confirmTab="confirmTab"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</NCard>
|
|
</NSpace>
|
|
</template>
|