✨ 新增项目变更菜单列表与MK审批对接

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-27 16:45:38 +08:00
parent 5f167aae50
commit 2b51619728
8 changed files with 771 additions and 11 deletions
+165 -10
View File
@@ -810,7 +810,21 @@
<template v-if="isChangeDialog">
<el-button v-if="!isProjectFormPage" @click="handleCancelProject">取消</el-button>
<el-button v-if="isProjectFormPage" @click="closeProjectForm">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="submitChangeProject">
<el-button
v-if="isProjectChangeModule && !dialogReadonly"
type="primary"
plain
:loading="submitLoading"
@click="saveProjectChangeDraft"
>
保存
</el-button>
<el-button
v-if="!dialogReadonly"
type="primary"
:loading="submitLoading"
@click="submitChangeProject"
>
提交
</el-button>
</template>
@@ -985,6 +999,7 @@ import {
projectTypeOptions,
} from '@/option/business/common';
import { config, option } from '@/option/business/project-apply';
import * as projectChangeApi from '@/api/business/project-change';
const emptyForm = () => ({
projectType: '',
@@ -1060,6 +1075,9 @@ const attachmentViewerPlugins = [
const projectApplyListRoute = '/business/project-apply';
const projectApplyFormRoute = '/business/project-apply/form';
const projectApplyListRefreshKey = 'project-apply-list-refresh';
const projectChangeListRoute = '/business/project-change';
const projectChangeFormRoute = '/business/project-change/form';
const projectChangeListRefreshKey = 'project-change-list-refresh';
const otherAttachmentType = { label: '其他附件', value: '其他附件' };
@@ -1245,7 +1263,40 @@ export default {
},
],
changeReason: [
{ max: 2000, message: '变更原因不能超过2000个字符', trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (!this.isChangeDialog) {
callback();
return;
}
if (!value || !String(value).trim()) {
callback(new Error('请输入变更原因'));
return;
}
if (String(value).length > 2000) {
callback(new Error('变更原因不能超过2000个字符'));
return;
}
callback();
},
trigger: 'blur',
},
],
changeType: [
{
validator: (rule, value, callback) => {
if (!this.isChangeDialog) {
callback();
return;
}
if (!value) {
callback(new Error('请选择变更类型'));
return;
}
callback();
},
trigger: 'change',
},
],
projectIntro: [
{ max: 1000, message: '项目简介不能超过1000个字符', trigger: 'blur' },
@@ -1374,8 +1425,11 @@ export default {
isMajorProjectSupplementDialog() {
return this.dialogType === 'majorSupplement';
},
isProjectChangeModule() {
return this.$route.path === projectChangeFormRoute;
},
isChangeDialog() {
return this.dialogType === 'change';
return this.dialogType === 'change' || this.isProjectChangeModule;
},
isNewProjectDialog() {
return ['add', 'majorSupplement'].includes(this.dialogType);
@@ -1384,7 +1438,13 @@ export default {
return this.isFormPageInstance;
},
isPublicViewPage() {
return this.$route.path === '/business/project-apply/public-view';
return (
this.$route.path === '/business/project-apply/public-view' ||
this.$route.path === '/business/project-change/public-view'
);
},
publicBizType() {
return this.$route.meta?.bizType || 'project-apply';
},
projectFormContainer() {
// 表单页实例始终用页面容器,避免 keep-alive 失活时误切弹窗
@@ -1451,7 +1511,7 @@ export default {
this.loadCargoTypeOptions();
this.loadTransportTypeOptions();
this.loadSettlementModeOptions();
if (this.$route.path === projectApplyFormRoute) {
if (this.$route.path === projectApplyFormRoute || this.$route.path === projectChangeFormRoute) {
this.isFormPageInstance = true;
this.openProjectFormPage();
}
@@ -1517,14 +1577,14 @@ export default {
},
openPublicProjectForm() {
const id = this.$route.query.id;
this.dialogType = 'view';
this.dialogType = this.publicBizType === 'project-change' ? 'change' : 'view';
this.dialogReadonly = true;
this.projectBox = true;
if (!id) {
this.$message.error('缺少项目ID');
return;
}
getMkPublicDetail('project-apply', id)
getMkPublicDetail(this.publicBizType, id)
.then(res => {
const detail = res.data?.data || {};
this.applyPublicDictOptions(detail);
@@ -1587,9 +1647,25 @@ export default {
openProjectFormPage() {
const type = this.$route.query.mode || 'add';
const id = this.$route.query.id;
this.dialogType = type;
this.dialogType = this.isProjectChangeModule ? (type === 'view' ? 'view' : 'change') : type;
this.dialogReadonly = type === 'view';
this.projectBox = true;
if (this.isProjectChangeModule) {
if (!id) {
this.$message.error('缺少项目变更ID');
return;
}
projectChangeApi.getDetail(id).then(res => {
const detail = res.data.data || {};
this.applyProjectDetail({
...detail,
changeType: detail.changeType || '项目变更',
changeNo: detail.changeNo || '',
changeDate: detail.changeDate || this.$dayjs().format('YYYY-MM-DD'),
});
});
return;
}
if (['add', 'majorSupplement'].includes(type)) {
this.applyProjectDetail({
...emptyForm(),
@@ -1613,6 +1689,12 @@ export default {
},
closeProjectForm() {
if (this.isProjectFormPage) {
if (this.isProjectChangeModule) {
sessionStorage.setItem(projectChangeListRefreshKey, '1');
this.$router.$avueRouter?.closeTag?.();
this.$router.push(projectChangeListRoute);
return;
}
this.markProjectApplyListNeedRefresh();
this.$router.$avueRouter?.closeTag?.();
this.$router.push(projectApplyListRoute);
@@ -1858,7 +1940,7 @@ export default {
},
handleCustomOperation(operation, row) {
if (operation.action === 'startChange') {
this.openProjectDialog('change', row);
this.startIndependentProjectChange(row);
return;
}
if (operation.action === 'mkAudit') {
@@ -2169,6 +2251,52 @@ export default {
this.closeProjectForm();
});
},
startIndependentProjectChange(row) {
if (!row?.id) {
this.$message.warning('项目ID为空,无法发起变更');
return;
}
const loading = this.$loading({
lock: true,
text: '正在创建项目变更单…',
background: 'rgba(255, 255, 255, 0.6)',
});
projectChangeApi
.createFromProject(row.id)
.then(res => {
if (res.data?.success === false) {
this.$message.error(res.data?.msg || '创建项目变更失败');
return;
}
const detail = res.data?.data || {};
if (!detail.id) {
this.$message.error('创建项目变更失败:未返回变更单ID');
return;
}
this.$router.push({
path: projectChangeFormRoute,
query: { mode: 'edit', id: detail.id, name: '项目变更' },
});
})
.finally(() => loading.close());
},
saveProjectChangeDraft() {
if (!this.isProjectChangeModule) return;
this.submitLoading = true;
projectChangeApi
.saveDraft(this.normalizeSubmitForm({ includeChangeType: true }))
.then(res => {
if (res.data?.success === false || res.data?.data === false) {
this.$message.error(res.data?.msg || '保存失败,请联系管理员');
return;
}
this.$message.success('保存成功!');
this.closeProjectForm();
})
.finally(() => {
this.submitLoading = false;
});
},
submitChangeProject() {
this.$refs.projectForm.validate(valid => {
if (!valid) {
@@ -2177,7 +2305,34 @@ export default {
}
if (!this.validateAttachmentFileTypes()) return;
this.submitLoading = true;
// 变更记录仅在提交时生成,保存草稿不落记录
if (this.isProjectChangeModule) {
const payload = this.normalizeSubmitForm({ includeChangeType: true });
const approvalStatus = this.form.approvalStatus || '';
projectChangeApi
.submit(payload)
.then(res => {
if (res.data?.success === false || res.data?.data === false) {
this.$message.error(res.data?.msg || '提交失败,请联系管理员');
return;
}
const id = this.form.id;
return submitMkApprovalFlow({
bizType: 'project-change',
bizId: id,
subjectName: this.form.projectName || '',
approvalStatus,
mkEnabled: this.mkEnabled,
}).then(() => {
this.$message.success('提交成功!');
this.closeProjectForm();
});
})
.finally(() => {
this.submitLoading = false;
});
return;
}
// 兼容旧入口:变更记录仅在提交时生成,保存草稿不落记录
this.api
.submitChange(this.normalizeSubmitForm({ includeChangeType: true }))
.then(res => {