You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

857 lines
31 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="p-2">
<el-card shadow="never" style="margin-top: 0">
<!-- 审批按钮组件标准流程场景 -->
<approvalButton
v-if="!isLimitedMode"
@submitForm="submitForm"
@approvalVerifyOpen="approvalVerifyOpen"
@handleApprovalRecord="handleApprovalRecord"
:buttonLoading="buttonLoading"
:id="form.projectPlanId"
:status="form.flowStatus"
:pageType="routeParams.type"
:mode="false"
/>
<!-- 审批完成后维护模式(仅可编辑延期天数、进度备注等) -->
<div v-else class="mb-3 flex items-center justify-between">
<div>
<el-button type="primary" :loading="buttonLoading" @click="saveLimited">保存</el-button>
<el-button type="primary" @click="handleApprovalRecord">流程进度</el-button>
</div>
<div>
<el-button @click="goBack">返回</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" style="margin-top: 0">
<el-form ref="projectPlanFormRef" :model="form" :rules="rules" :disabled="isViewMode" label-width="120px">
<el-divider content-position="left">基本信息</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目名称" prop="projectId">
<el-input v-model="selectedProjectName" placeholder="请选择项目" readonly :disabled="!isBasicEditable">
<template #suffix>
<el-icon style="cursor: pointer" @click="openProjectSelect" :disabled="!isBasicEditable">
<Search />
</el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目计划编号" prop="projectPlanCode">
<el-input v-model="form.projectPlanCode" placeholder="由系统自动生成" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目经理" prop="managerId">
<el-input v-model="form.managerName" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目经理部门">
<el-input v-model="form.managerDeptName" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门负责人" prop="chargeId">
<el-input v-model="form.chargeName" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目编号">
<el-input v-model="selectedProjectCode" placeholder="选择项目后自动显示" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="付款方式" prop="paymentMethod">
<el-input v-model="form.paymentMethod" placeholder="3-3-3-1" :disabled="!isBasicEditable" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目计划状态" prop="projectPlanStatus">
<!-- <el-select v-model="form.projectPlanStatus" placeholder="请选择项目计划状态" :disabled="!isBasicEditable"> -->
<el-select v-model="form.projectPlanStatus" placeholder="请选择项目计划状态" :disabled="true">
<el-option v-for="dict in project_plan_status" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="附件" prop="ossId">
<template v-if="isViewMode">
<el-button type="primary" plain icon="View" @click="handlePreview" :disabled="!form.ossId">预览附件</el-button>
</template>
<template v-else>
<el-button type="primary" plain icon="Upload" @click="handleFile">上传附件</el-button>
</template>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" :disabled="!isBasicEditable" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">项目阶段计划</el-divider>
<el-row :gutter="10" class="mb8" v-if="isBasicEditable">
<el-col :span="1.5">
<el-button type="primary" icon="Plus" @click="handleAddStage">添加阶段</el-button>
</el-col>
</el-row>
<el-table :data="form.planStageList" border stripe max-height="600">
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="项目阶段" width="150" align="center">
<template #default="scope">
<el-select v-model="scope.row.projectPhases" placeholder="请选择项目阶段" style="width: 100%" :disabled="!isBasicEditable">
<el-option v-for="dict in project_phases" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="计划开始时间" width="160" align="center">
<template #default="scope">
<el-date-picker
v-model="scope.row.planStartTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 100%"
:disabled="!isBasicEditable"
/>
</template>
</el-table-column>
<el-table-column label="计划结束时间" width="160" align="center">
<template #default="scope">
<el-date-picker
v-model="scope.row.planEndTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 100%"
:disabled="!isBasicEditable"
/>
</template>
</el-table-column>
<el-table-column label="回款阶段" width="150" align="center">
<template #default="scope">
<el-select v-model="scope.row.collectionStage" placeholder="请选择回款阶段" style="width: 100%" :disabled="!isBasicEditable">
<el-option v-for="dict in collection_stage" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="回款比例(%)" width="120" align="center">
<template #default="scope">
<el-input-number
v-model="scope.row.repaymentRate"
:min="0"
:max="100"
:precision="2"
controls-position="right"
style="width: 100%"
:disabled="!isBasicEditable"
/>
</template>
</el-table-column>
<el-table-column label="预计回款金额" width="140" align="center">
<template #default="scope">
<el-input-number
v-model="scope.row.repaymentAmount"
:min="0"
:precision="2"
controls-position="right"
style="width: 100%"
:disabled="!isBasicEditable"
/>
</template>
</el-table-column>
<el-table-column label="预计回款时间" width="160" align="center">
<template #default="scope">
<el-date-picker
v-model="scope.row.repaymentTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 100%"
:disabled="!isBasicEditable"
@change="recalcReceivableDate(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="回款延期天数" width="140" align="center">
<template #default="scope">
<el-input-number
v-model="scope.row.delayDay"
:min="0"
:step="1"
controls-position="right"
style="width: 100%"
:disabled="!canEditLimited"
@change="recalcReceivableDate(scope.row)"
/>
</template>
</el-table-column>
<!-- <el-table-column label="应收款日期" width="160" align="center">
<template #default="scope">
<el-date-picker v-model="scope.row.receivableDate" type="date" value-format="YYYY-MM-DD" placeholder="自动计算" style="width: 100%" disabled/>
</template>
</el-table-column>-->
<el-table-column label="实际开始" min-width="140" align="center">
<template #default="scope">
<el-date-picker v-model="scope.row.realStartTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="实际结束" min-width="140" align="center">
<template #default="scope">
<el-date-picker v-model="scope.row.realEndTime" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" style="width: 100%" />
</template>
</el-table-column>
<el-table-column label="进度备注" width="200" align="center">
<template #default="scope">
<el-input v-model="scope.row.scheduleRemark" placeholder="请输入进度备注" :disabled="!canEditLimited" />
</template>
</el-table-column>
<el-table-column label="操作" width="80" align="center" fixed="right" v-if="isBasicEditable">
<template #default="scope">
<el-button type="danger" link icon="Delete" @click="handleDeleteStage(scope.$index)">删除</el-button>
</template>
</el-table-column>
<!-- 动态变更列(多列合并展示) -->
<el-table-column
v-for="(change, changeIndex) in projectChangeList"
:key="`change-${change.projectChangeId || changeIndex}`"
:label="`第${change.changeNumber || changeIndex + 1}次变更`"
align="center"
>
<el-table-column label="变更开始" width="110" align="center">
<template #default="scope">
<span v-if="getChangeProgressByStage(change, scope.row.planStageId)" class="change-highlight">
{{ (getChangeProgressByStage(change, scope.row.planStageId).changedStart || '').substring(0, 10) || '-' }}
</span>
<span v-else class="text-gray-300">-</span>
</template>
</el-table-column>
<el-table-column label="变更结束" width="110" align="center">
<template #default="scope">
<span v-if="getChangeProgressByStage(change, scope.row.planStageId)" class="change-highlight">
{{ (getChangeProgressByStage(change, scope.row.planStageId).changedEnd || '').substring(0, 10) || '-' }}
</span>
<span v-else class="text-gray-300">-</span>
</template>
</el-table-column>
<el-table-column label="里程碑" width="100" align="center">
<template #default="scope">
<span v-if="getChangeProgressByStage(change, scope.row.planStageId)" class="change-highlight">
{{ getChangeProgressByStage(change, scope.row.planStageId).milestoneName || '-' }}
</span>
<span v-else class="text-gray-300">-</span>
</template>
</el-table-column>
<el-table-column label="完成度" width="80" align="center">
<template #default="scope">
<span v-if="getChangeProgressByStage(change, scope.row.planStageId)" class="change-highlight">
{{
getChangeProgressByStage(change, scope.row.planStageId).completionDegree != null
? getChangeProgressByStage(change, scope.row.planStageId).completionDegree + '%'
: '-'
}}
</span>
<span v-else class="text-gray-300">-</span>
</template>
</el-table-column>
<el-table-column label="备注" width="120" align="center" show-overflow-tooltip>
<template #default="scope">
<span v-if="getChangeProgressByStage(change, scope.row.planStageId)" class="change-highlight">
{{ getChangeProgressByStage(change, scope.row.planStageId).remark || '-' }}
</span>
<span v-else class="text-gray-300">-</span>
</template>
</el-table-column>
</el-table-column>
</el-table>
</el-form>
</el-card>
<!-- 提交审批组件 -->
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<!-- 审批记录 -->
<approvalRecord ref="approvalRecordRef" />
<!-- 项目选择弹窗 -->
<ProjectSelect ref="projectSelectRef" :multiple="false" @confirm-call-back="projectInfoSelectCallBack" />
<!-- 附件上传/预览对话框 -->
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
<el-form label-width="80px">
<el-form-item label="文件名">
<fileUpload v-if="type === 0" v-model="ossFileModel" :disabled="isViewMode" />
<imageUpload v-if="type === 1" v-model="ossFileModel" :disabled="isViewMode" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button v-if="!isViewMode" type="primary" @click="submitOss">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="ErpProjectPlanEdit">
import { useRoute, useRouter } from 'vue-router';
import { addErpProjectPlan, getErpProjectPlan, projectPlanSubmitAndFlowStart, updateErpProjectPlan } from '@/api/oa/erp/erpProjectPlan';
import { ErpProjectPlanForm } from '@/api/oa/erp/erpProjectPlan/types';
import { queryProjectChangeByProjectPlanId } from '@/api/oa/erp/erpProjectChange';
import { getErpProjectInfoList } from '@/api/oa/erp/projectInfo';
import type { ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
import SubmitVerify from '@/components/Process/submitVerify.vue';
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
import ApprovalButton from '@/components/Process/approvalButton.vue';
import ProjectSelect from '@/components/ProjectSelect/index.vue';
import { useUserStore } from '@/store/modules/user';
import { FlowCodeEnum } from '@/enums/OAEnum';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { project_plan_status, project_phases, collection_stage, project_change_status } = toRefs<any>(
proxy?.useDict('project_plan_status', 'project_phases', 'collection_stage', 'project_change_status')
);
const route = useRoute();
const router = useRouter();
const userStore = useUserStore();
const refreshFlagKey = 'erpProjectPlanListShouldRefresh';
// 审批相关组件引用
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
// 路由参数(与项目信息保持一致)
const routeParams = ref<Record<string, any>>({});
// 是否只读模式(与项目信息保持一致)
const isViewMode = computed(() => routeParams.value.type === 'view' || routeParams.value.type === 'approval');
// 流程相关数据
const taskVariables = ref<any>({});
// 计算属性:判断基础信息是否可编辑
const isBasicEditable = computed(() => {
if (isViewMode.value) {
return false;
}
// 草稿、驳回、撤回均允许项目经理完整编辑
return form.value.projectPlanStatus === '1' || ['back', 'cancel'].includes(form.value.flowStatus as string);
});
// 计算属性:判断是否可编辑延迟/备注等有限字段
const canEditLimited = computed(() => {
if (isViewMode.value) {
return false;
}
if (isBasicEditable.value) {
return true;
}
// 审批完成允许维护延期与进度备注
return form.value.projectPlanStatus === '3' || form.value.flowStatus === 'finish';
});
// 限制模式(审批完成,仅维护部分字段:延期天数、进度备注等)
const isLimitedMode = computed(() => !isBasicEditable.value && canEditLimited.value);
const projectPlanFormRef = ref<ElFormInstance>();
const buttonLoading = ref(false);
const projectInfoList = ref<Partial<ProjectInfoVO>[]>([]);
const selectedProjectCode = ref<string>(''); // 展示选中项目的编号
const selectedProjectName = ref<string>(''); // 展示选中项目的名称
const baseDataLoaded = ref(false);
const projectSelectRef = ref<InstanceType<typeof ProjectSelect>>();
// 项目计划变更记录相关
const projectChangeList = ref<any[]>([]); // 变更记录列表
const activeChangeTab = ref<string>('0'); // 当前活跃的变更标签
// 附件上传对话框状态
const type = ref(0);
const dialog = reactive<{ visible: boolean; title: string }>({
visible: false,
title: ''
});
const ossFileModel = ref<string | string[] | undefined>(undefined);
const createEmptyForm = (): ErpProjectPlanForm => ({
projectPlanId: undefined,
projectId: undefined,
managerId: undefined,
chargeId: undefined,
managerName: undefined,
chargeName: undefined,
managerDeptName: undefined,
projectPlanCode: undefined,
paymentMethod: undefined,
projectPlanStatus: '1',
flowStatus: 'draft',
contractId: undefined,
ossId: undefined,
remark: undefined,
activeFlag: '1',
planStageList: []
});
const form = ref<ErpProjectPlanForm>(createEmptyForm());
const rules = reactive({
projectId: [{ required: true, message: '请选择项目', trigger: 'change' }],
managerId: [{ required: true, message: '请选择项目经理', trigger: 'change' }]
});
const notifyListRefresh = () => {
sessionStorage.setItem(refreshFlagKey, Date.now().toString());
};
const resetForm = () => {
form.value = createEmptyForm();
selectedProjectCode.value = '';
};
/** 获取项目列表 */
const getProjectInfoList = async () => {
const res = await getErpProjectInfoList({});
projectInfoList.value = (res.data || []) as Partial<ProjectInfoVO>[];
};
const initBaseData = async () => {
if (baseDataLoaded.value) {
return;
}
await getProjectInfoList();
baseDataLoaded.value = true;
};
/** 打开项目选择弹窗 */
const openProjectSelect = () => {
if (!isBasicEditable.value) {
return;
}
projectSelectRef.value?.open();
};
/** 项目选择回调,自动填充项目相关信息 */
const projectInfoSelectCallBack = (data: ProjectInfoVO[]) => {
if (data && data.length > 0) {
const project = data[0];
form.value.projectId = project.projectId;
selectedProjectCode.value = project.projectCode || '';
selectedProjectName.value = project.projectName || '';
// 调用 handleProjectChange 填充其他关联字段
handleProjectChange(project.projectId, { syncManagerAndCharge: true, syncPaymentMethod: true });
}
};
/** 添加阶段 */
const handleAddStage = () => {
const newStage = {
planStageId: undefined,
projectId: form.value.projectId,
projectPlanId: form.value.projectPlanId,
projectPhases: undefined,
planStartTime: undefined,
planEndTime: undefined,
collectionStage: undefined,
repaymentRate: undefined,
repaymentAmount: undefined,
repaymentTime: undefined,
delayDay: undefined,
receivableDate: undefined,
reasonsExplanation: undefined,
scheduleRemark: undefined,
realStartTime: undefined,
realEndTime: undefined,
sortOrder: (form.value.planStageList?.length || 0) + 1
};
if (!form.value.planStageList) {
form.value.planStageList = [];
}
form.value.planStageList.push(newStage);
};
/** 删除阶段 */
const handleDeleteStage = (index: number) => {
form.value.planStageList?.splice(index, 1);
};
interface ProjectSyncOptions {
syncManagerAndCharge?: boolean;
syncPaymentMethod?: boolean;
}
/** 处理项目选择变化,自动填充项目经理、部门负责人、付款方式和项目编号 */
const handleProjectChange = (projectId?: string | number, { syncManagerAndCharge = true, syncPaymentMethod = true }: ProjectSyncOptions = {}) => {
const isEmptySelection = projectId === undefined || projectId === null || projectId === '';
if (isEmptySelection) {
if (syncManagerAndCharge) {
form.value.managerId = undefined;
form.value.chargeId = undefined;
}
if (syncPaymentMethod) {
form.value.paymentMethod = undefined;
}
selectedProjectCode.value = '';
return;
}
const project = projectInfoList.value.find((item) => String(item.projectId) === String(projectId));
if (!project) {
return;
}
if (syncManagerAndCharge) {
form.value.managerId = project.managerId ?? undefined;
form.value.chargeId = project.chargeId ?? undefined;
// 名称字段从后端项目信息连表数据带出
form.value.managerName = ((project as any).managerName as string) ?? '';
form.value.chargeName = ((project as any).chargeName as string) ?? '';
}
if (syncPaymentMethod) {
form.value.paymentMethod = (project.paymentMethod as string) ?? undefined;
}
// 项目编号与项目经理部门均从后端项目信息中带出
selectedProjectCode.value = (project.projectCode as string) || '';
// ProjectInfoVO中deptName来源于后端连表ErpProjectInfoVo.deptName
form.value.managerDeptName = ((project as any).deptName as string) ?? '';
};
/** 根据回款时间与延期天数生成应收款日期 */
const recalcReceivableDate = (row: any) => {
if (!row) return;
const time = row.repaymentTime;
const delay = Number(row.delayDay || 0);
if (!time) {
row.receivableDate = undefined;
return;
}
const base = new Date(time as string);
if (isNaN(base.getTime())) {
row.receivableDate = undefined;
return;
}
const target = new Date(base.getTime());
target.setDate(target.getDate() + delay);
// 使用系统已有的parseTime进行格式化保持与全局一致
row.receivableDate = proxy?.parseTime ? proxy.parseTime(target, '{y}-{m}-{d}') : target.toISOString().slice(0, 10);
};
// 打开附件上传对话框(编辑模式)
const handleFile = () => {
type.value = 0;
dialog.visible = true;
dialog.title = '上传项目计划附件';
// 回显已有附件
ossFileModel.value = form.value.ossId as any;
};
// 查看模式下预览附件
const handlePreview = () => {
if (!form.value.ossId) {
proxy?.$modal.msgWarning('暂无附件可预览');
return;
}
type.value = 0;
dialog.visible = true;
dialog.title = '预览项目计划附件';
ossFileModel.value = form.value.ossId as any;
};
// 提交附件
const submitOss = () => {
form.value.ossId = ossFileModel.value as any;
dialog.visible = false;
proxy?.$modal.msgSuccess('附件已更新');
};
// 关闭附件对话框
const cancel = () => {
dialog.visible = false;
};
/** 提交按钮(与项目信息保持一致的处理方式) */
const submitForm = (status: string, mode: boolean) => {
projectPlanFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
try {
// 权限校验:只有项目经理才能提交(超级管理员跳过校验)
if (!form.value.managerId) {
proxy?.$modal.msgError('请先选择项目');
buttonLoading.value = false;
return;
}
const isSuperAdmin = userStore.roles.includes('admin') || userStore.roles.includes('superadmin');
if (!isSuperAdmin && userStore.userId !== form.value.managerId) {
proxy?.$modal.msgError('只有项目经理才能提交项目计划');
buttonLoading.value = false;
return;
}
// 更新阶段的projectId
if (form.value.planStageList) {
form.value.planStageList.forEach((stage) => {
stage.projectId = form.value.projectId;
});
}
// 提交审批(与项目信息保持一致)
if (status !== 'draft') {
const project = projectInfoList.value.find((p) => p.projectId === form.value.projectId);
form.value.flowCode = FlowCodeEnum.PROJECT_PLAN_CODE; //OAPS
form.value.variables = {
projectId: form.value.projectId,
projectName: project?.projectName,
managerId: form.value.managerId
};
// 流程实例业务扩展字段
form.value.bizExt = {
businessTitle: project?.projectName,
businessCode: form.value.projectPlanCode
};
form.value.projectPlanStatus = '2';
form.value.flowStatus = 'waiting';
const res = await projectPlanSubmitAndFlowStart(form.value);
form.value = res.data;
proxy?.$modal.msgSuccess('操作成功');
notifyListRefresh();
proxy?.$tab.closePage();
router.go(-1);
} else {
// 暂存
form.value.projectPlanStatus = '1';
form.value.flowStatus = 'draft';
if (form.value.projectPlanId) {
await updateErpProjectPlan(form.value);
} else {
await addErpProjectPlan(form.value);
}
proxy?.$modal.msgSuccess('暂存成功');
notifyListRefresh();
proxy?.$tab.closePage();
router.go(-1);
}
} finally {
buttonLoading.value = false;
}
}
});
};
/** 审批完成后的保存逻辑 */
const saveLimited = () => {
projectPlanFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return;
buttonLoading.value = true;
try {
if (form.value.planStageList) {
form.value.planStageList.forEach((stage) => {
stage.projectId = form.value.projectId;
});
}
await updateErpProjectPlan(form.value);
proxy?.$modal.msgSuccess('保存成功');
notifyListRefresh();
proxy?.$tab.closePage();
router.go(-1);
} finally {
buttonLoading.value = false;
}
});
};
/** 审批对话框 */
const approvalVerifyOpen = async () => {
await submitVerifyRef.value?.openDialog(routeParams.value.taskId);
};
/** 审批记录 */
const handleApprovalRecord = () => {
approvalRecordRef.value?.init(form.value.projectPlanId);
};
/**
* 获取指定阶段在某个变更中的进度信息
* @param change 变更记录
* @param planStageId 项目阶段ID
*/
const getChangeProgressByStage = (change: any, planStageId: any) => {
if (!change.progressList || change.progressList.length === 0) {
return null;
}
return change.progressList.find((progress: any) => progress.planStageId === planStageId);
};
/**
* 获取对齐的进度变更数据
* 将项目阶段与变更进度对齐显示
*/
const getAlignedProgressData = (change: any) => {
if (!form.value.planStageList || form.value.planStageList.length === 0) {
return [];
}
// 构建变更进度的Mapkey为planStageId
const progressMap = new Map();
if (change.progressList && change.progressList.length > 0) {
change.progressList.forEach((progress: any) => {
progressMap.set(progress.planStageId, progress);
});
}
// 将项目阶段与对应的变更进度合并
return form.value.planStageList.map((stage: any) => ({
...stage,
changeProgress: progressMap.get(stage.planStageId)
}));
};
/**
* 加载项目计划的变更记录
*/
const loadProjectChangeList = async () => {
if (!form.value.projectPlanId) {
projectChangeList.value = [];
return;
}
try {
const res = await queryProjectChangeByProjectPlanId(form.value.projectPlanId);
projectChangeList.value = res.data || [];
activeChangeTab.value = '0'; // 重置为第一个标签
} catch (error) {
projectChangeList.value = [];
console.error('加载项目计划变更记录失败:', error);
}
};
const loadFormData = async () => {
await initBaseData();
// 获取路由参数(与项目信息保持一致)
routeParams.value = route.query;
buttonLoading.value = false;
const id = routeParams.value.id as string;
if (id && (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval')) {
proxy?.$modal.loading('正在加载数据,请稍后...');
const res = await getErpProjectPlan(id);
Object.assign(form.value, res.data);
if (!form.value.flowStatus) {
form.value.flowStatus = 'draft';
}
if (!form.value.planStageList) {
form.value.planStageList = [];
}
if (form.value.projectId) {
// 编辑模式下,同步项目名称和编号
const project = projectInfoList.value.find((item) => String(item.projectId) === String(form.value.projectId));
if (project) {
selectedProjectName.value = (project.projectName as string) || '';
selectedProjectCode.value = (project.projectCode as string) || '';
}
handleProjectChange(form.value.projectId, {
syncManagerAndCharge: false,
syncPaymentMethod: false
});
}
// 在查看模式或审批完成状态下加载变更记录
if (isViewMode.value || form.value.projectPlanStatus === '3') {
await loadProjectChangeList();
}
proxy?.$modal.closeLoading();
} else {
resetForm();
form.value.flowStatus = 'draft';
projectChangeList.value = [];
}
};
/** 返回列表 */
const goBack = () => {
router.back();
};
// 提交回调
const submitCallback = async () => {
notifyListRefresh();
await proxy?.$tab.closePage(route);
router.go(-1);
};
watch(
() => route.fullPath,
() => {
loadFormData();
}
);
onMounted(async () => {
await loadFormData();
});
</script>
<style scoped lang="scss">
.el-divider {
margin: 20px 0;
}
//
.change-cell {
padding: 8px;
background-color: #fffacd;
border-radius: 4px;
font-size: 12px;
.change-item {
margin-bottom: 6px;
display: flex;
align-items: center;
&:last-child {
margin-bottom: 0;
}
.label {
font-weight: 500;
color: #333;
margin-right: 8px;
min-width: 60px;
}
.value {
color: #666;
word-break: break-word;
}
}
}
.change-highlight {
display: inline-block;
padding: 2px 6px;
background-color: #fffacd;
border-radius: 3px;
color: #333;
}
.info-item {
margin-bottom: 12px;
.label {
font-weight: 500;
color: #333;
margin-right: 8px;
}
.value {
color: #666;
}
}
</style>