发起变更审批流程弹框板块修改
This commit is contained in:
@@ -1,42 +1,24 @@
|
||||
<!-- 变更申请表 -->
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, h, watch } from 'vue';
|
||||
import { ref, computed, h, watch, nextTick } from 'vue';
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { tagTextColor, tagBgColor, tagBorderColor, downloadFileFun } from '@/utils/common';
|
||||
import { localStg } from '@/utils/storage';
|
||||
import { useChangeStore } from '@/store/modules/change';
|
||||
import { AiError, aiTypeJudge, aiLevelScore, aiApplication } from "@/service/api/ai";
|
||||
import { uploadFileApi, deleteFileApi } from "@/service/api/file";
|
||||
import Footer from './footer.vue'
|
||||
import previewComponent from '@/components/previewFile/index.vue'
|
||||
|
||||
const themeStore = useThemeStore();
|
||||
const changeStore = useChangeStore();
|
||||
|
||||
const props = defineProps(['type','orgTree','templateList','typeList','levelList','isAiOpen','title','currentId','formInfo', 'currentForm', 'confirmed','members'])
|
||||
const emit = defineEmits(['save','submit','confirmTab','update:title']);
|
||||
const props = defineProps([
|
||||
'type','orgTree','templateList','typeList','levelList','isAiOpen',
|
||||
'title','currentId','formInfo', 'currentForm', 'confirmed','members','steps'
|
||||
])
|
||||
const emit = defineEmits(['save','submit','confirmTab','update:title','update:steps']);
|
||||
|
||||
watch(() => props.currentForm, (newVal:any) => {
|
||||
// 过滤出需要的字段
|
||||
const {
|
||||
approval_flow,
|
||||
attachments,
|
||||
change_id,
|
||||
created_at,
|
||||
id,
|
||||
updated_at,
|
||||
...rest
|
||||
} = newVal;
|
||||
form.value = rest;
|
||||
// 用 Map 建立 question_id -> score 的映射,查找 O(1)
|
||||
const scoreMap = new Map(form.value?.level_score?.map((item:any) => [item.question_id, item.score]) || []);
|
||||
questions.value = questions.value.map((item:any) => ({
|
||||
...item,
|
||||
score: scoreMap.has(item.question_id) ? scoreMap.get(item.question_id) : item.score
|
||||
}));
|
||||
totalScore.value = questions.value.reduce((sum:number, item:any) => sum + (item.score || 0), 0);
|
||||
})
|
||||
const isSyncingFromParent = ref(false);
|
||||
|
||||
const aiFail = (e: any) => {
|
||||
if (e instanceof AiError) window.$message?.warning(`AI 分析失败:${e.message},可手动填写`);
|
||||
@@ -58,11 +40,10 @@ const previewFile = ref<any>(null);
|
||||
const sheet = ref<string>('');
|
||||
// 上传文件
|
||||
const uploadFile = ref<{id:number, file_name:string, file_url:string, uploader_name:string, file_type:string, created_at:string, version:string | null}[]>([]);
|
||||
|
||||
// 表单
|
||||
const form = ref<{
|
||||
change_type: number | null,
|
||||
change_level: any,
|
||||
change_level: number | null,
|
||||
duration_type: number | null,
|
||||
restore_deadline: number | null,
|
||||
org_id: number | null,
|
||||
@@ -79,7 +60,7 @@ const form = ref<{
|
||||
level_score: any[],
|
||||
}>({
|
||||
change_type: null,
|
||||
change_level: computed(() => totalScore.value >= 20 ? 2 : 1),
|
||||
change_level: null,
|
||||
duration_type: null,
|
||||
restore_deadline: null,
|
||||
org_id: null,
|
||||
@@ -185,10 +166,59 @@ const questions = ref<any>([
|
||||
},
|
||||
]);
|
||||
|
||||
// 当前模板步骤
|
||||
const currentSteps = ref<any>(null);
|
||||
|
||||
watch(() => props.currentForm, (newVal:any) => {
|
||||
if (!newVal) return;
|
||||
isSyncingFromParent.value = true;
|
||||
// 过滤出需要的字段
|
||||
const {
|
||||
approval_flow,
|
||||
attachments,
|
||||
change_id,
|
||||
created_at,
|
||||
id,
|
||||
updated_at,
|
||||
...rest
|
||||
} = newVal;
|
||||
form.value = rest;
|
||||
// 用 Map 建立 question_id -> score 的映射,查找 O(1)
|
||||
const scoreMap = new Map(form.value?.level_score?.map((item:any) => [item.question_id, item.score]) || []);
|
||||
questions.value = questions.value.map((item:any) => ({
|
||||
...item,
|
||||
score: scoreMap.has(item.question_id) ? scoreMap.get(item.question_id) : item.score
|
||||
}));
|
||||
totalScore.value = questions.value.reduce((sum:number, item:any) => sum + (item.score || 0), 0);
|
||||
nextTick(() => { // ★ form 的 watch 跑完后再释放
|
||||
isSyncingFromParent.value = false;
|
||||
});
|
||||
},{ immediate: true })
|
||||
// 监听总分数变化,自动更新等级
|
||||
watch(() => totalScore.value, (v:number) => {
|
||||
form.value.change_level = v >= 20 ? 2 : 1;
|
||||
});
|
||||
// 变更类型 / 变更等级 / 变更时限,任一改变 → 更新模板
|
||||
watch(
|
||||
() => [
|
||||
form.value?.change_type,
|
||||
form.value?.change_level,
|
||||
form.value?.duration_type,
|
||||
],
|
||||
() => {
|
||||
if (isSyncingFromParent.value) return;
|
||||
updateCurrentTemplate()
|
||||
}
|
||||
);
|
||||
// 监听步骤变化,更新本地步骤
|
||||
watch(() => props.steps, (v:any) => {
|
||||
currentSteps.value = v;
|
||||
},{ immediate: true })
|
||||
|
||||
// 筛选涉及专业的人员和部门
|
||||
const filterMembersBySpecialties = (data: any, specialties: string[]) => {
|
||||
const filterMembersBySpecialties = (steps: any, specialties: string[]) => {
|
||||
const result: any[] = [];
|
||||
data.steps.forEach((step: any) => {
|
||||
steps.forEach((step: any) => {
|
||||
step.members.forEach((member: any) => {
|
||||
if (member.specialty && specialties.includes(member.specialty)) {
|
||||
result.push({
|
||||
@@ -200,27 +230,20 @@ const filterMembersBySpecialties = (data: any, specialties: string[]) => {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// 当前模板
|
||||
const currentTemplate = computed(() => {
|
||||
let template = null;
|
||||
if(props.currentForm?.approval_flow?.steps && props.currentForm?.approval_flow?.steps.length){
|
||||
template = props.currentForm?.approval_flow;
|
||||
}else{
|
||||
template = props.templateList.find((item: any) =>
|
||||
item.level === form.value?.change_level &&
|
||||
item.category === form.value?.change_type &&
|
||||
item.duration === form.value?.duration_type
|
||||
) || null;
|
||||
}
|
||||
footerRef.value?.clearApprovers();
|
||||
changeStore.setStepsInfo(template?template.steps:[]);
|
||||
return template?template:null;
|
||||
});
|
||||
// 更新当前模板步骤
|
||||
const updateCurrentTemplate = () => {
|
||||
let template = props.templateList.find((item: any) =>
|
||||
item.level === form.value?.change_level &&
|
||||
item.category === form.value?.change_type &&
|
||||
item.duration === form.value?.duration_type
|
||||
) || null;
|
||||
currentSteps.value = template?.steps || [];
|
||||
emit('update:steps', currentSteps.value);
|
||||
}
|
||||
// 联动专业会签人员
|
||||
const signers = computed(() => {
|
||||
if(currentTemplate.value){
|
||||
const matchedMembers = filterMembersBySpecialties(currentTemplate.value, form.value.disciplines);
|
||||
if(currentSteps.value){
|
||||
const matchedMembers = filterMembersBySpecialties(currentSteps.value || [], form.value.disciplines);
|
||||
return matchedMembers
|
||||
}
|
||||
return null
|
||||
@@ -414,6 +437,11 @@ const confirmTab = (tab:string, val:boolean) => {
|
||||
emit('confirmTab', tab, val);
|
||||
}
|
||||
|
||||
// 更新审批流程
|
||||
const updateSteps = (steps:any[]) => {
|
||||
emit('update:steps', steps);
|
||||
}
|
||||
|
||||
defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
|
||||
|
||||
</script>
|
||||
@@ -678,10 +706,12 @@ defineExpose({form, questions, applyAiResult, generateLevel: useAiLevel})
|
||||
:currentForm="form"
|
||||
:confirmed="props.confirmed"
|
||||
:members="props.members"
|
||||
:steps="currentSteps"
|
||||
@save="saveDraft"
|
||||
@submit="submitConfirm"
|
||||
@confirmTab="confirmTab"
|
||||
@regenerate="onRegenerate"
|
||||
@update:steps="updateSteps"
|
||||
/>
|
||||
<!-- 侧边抽屉:AI 类型判定 / 等级判定表 -->
|
||||
<NDrawer :show="sheet !== ''" @update:show="(v) => !v && (sheet = '')" placement="right" :width="sheet === 'level' ? '45rem' : '28rem'">
|
||||
|
||||
Reference in New Issue
Block a user