@@ -0,0 +1,52 @@
|
|||||||
|
import { createCrudApi } from './common';
|
||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
const baseUrl = '/blade-transport/project-change';
|
||||||
|
const api = createCrudApi(baseUrl);
|
||||||
|
|
||||||
|
export const getList = api.getList;
|
||||||
|
export const getDetail = api.getDetail;
|
||||||
|
export const submit = api.submit;
|
||||||
|
export const remove = api.remove;
|
||||||
|
|
||||||
|
export const createFromProject = (projectId, changeType) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/create-from-project`,
|
||||||
|
method: 'post',
|
||||||
|
params: { projectId, changeType },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const saveDraft = row =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/save-draft`,
|
||||||
|
method: 'post',
|
||||||
|
data: row,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const submitApproval = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/submit-approval`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const approve = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/approve`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const reject = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/reject`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const withdraw = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/withdraw`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import {
|
||||||
|
approvalStatusOptions,
|
||||||
|
createCrudOption,
|
||||||
|
hcsSyncStatusOptions,
|
||||||
|
projectTypeOptions,
|
||||||
|
} from './common';
|
||||||
|
|
||||||
|
export const changeTypeOptions = [
|
||||||
|
{ label: '项目变更', value: '项目变更' },
|
||||||
|
{ label: '项目备案调整', value: '项目备案调整' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
title: '项目变更',
|
||||||
|
permission: 'project_change',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
statusTextProp: 'approvalStatusName',
|
||||||
|
deleteStatus: ['draft', 'withdrawn', 'rejected'],
|
||||||
|
editStatus: ['draft', 'withdrawn', 'rejected'],
|
||||||
|
viewStatus: ['approved', 'rejected', 'withdrawn'],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
action: 'submitApproval',
|
||||||
|
label: '提交',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['draft'],
|
||||||
|
permission: 'project_change_submit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'withdraw',
|
||||||
|
label: '撤回',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'project_change_withdraw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'mkAudit',
|
||||||
|
label: '流程',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'project_change_approve',
|
||||||
|
mkOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'approve',
|
||||||
|
label: '通过',
|
||||||
|
type: 'success',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'project_change_approve',
|
||||||
|
localOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'reject',
|
||||||
|
label: '驳回',
|
||||||
|
type: 'warning',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'project_change_reject',
|
||||||
|
localOnly: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const option = createCrudOption([
|
||||||
|
{
|
||||||
|
label: '项目编号',
|
||||||
|
prop: 'projectCode',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 70,
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目名称',
|
||||||
|
prop: 'projectName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 60,
|
||||||
|
minWidth: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '变更类型',
|
||||||
|
prop: 'changeType',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 10,
|
||||||
|
dicData: changeTypeOptions,
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目类型',
|
||||||
|
prop: 'projectType',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 20,
|
||||||
|
dicData: projectTypeOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '客户名称',
|
||||||
|
prop: 'customerNames',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '下游承运商',
|
||||||
|
prop: 'carrierNames',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '承办部门',
|
||||||
|
prop: 'undertakeDeptName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 50,
|
||||||
|
minWidth: 140,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '项目负责人',
|
||||||
|
prop: 'principalUserName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 40,
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '审批状态',
|
||||||
|
prop: 'approvalStatus',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 30,
|
||||||
|
dicData: approvalStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '当前节点',
|
||||||
|
prop: 'currentNode',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '当前处理人',
|
||||||
|
prop: 'currentProcessor',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '审核通过时间',
|
||||||
|
prop: 'approvedTime',
|
||||||
|
type: 'datetime',
|
||||||
|
minWidth: 170,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '同步状态',
|
||||||
|
prop: 'syncStatus',
|
||||||
|
type: 'select',
|
||||||
|
dicData: hcsSyncStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
]);
|
||||||
@@ -95,6 +95,17 @@ export default [
|
|||||||
bizType: 'project-apply',
|
bizType: 'project-apply',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/business/project-change/public-view',
|
||||||
|
name: '查看项目变更信息',
|
||||||
|
component: () => import('@/views/business/project-apply-public-view.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: false,
|
||||||
|
isTab: false,
|
||||||
|
isAuth: false,
|
||||||
|
bizType: 'project-change',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/business/contract-manage/public-view',
|
path: '/business/contract-manage/public-view',
|
||||||
name: '查看合同信息',
|
name: '查看合同信息',
|
||||||
|
|||||||
@@ -198,6 +198,18 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/business/project-change/form',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: '项目变更表单',
|
||||||
|
meta: { keepAlive: false, activeMenu: '/business/project-change' },
|
||||||
|
component: loadView(() => import('@/views/business/project-apply.vue')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/business/waybill-manage/form',
|
path: '/business/waybill-manage/form',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ export const MK_BIZ = {
|
|||||||
rejected: ['rejected', 'change_rejected', 'withdrawn'],
|
rejected: ['rejected', 'change_rejected', 'withdrawn'],
|
||||||
approved: ['approved', 'change_approved'],
|
approved: ['approved', 'change_approved'],
|
||||||
},
|
},
|
||||||
|
'project-change': {
|
||||||
|
dictName: '提交项目变更审核流',
|
||||||
|
subjectPrefix: '项目变更审批',
|
||||||
|
rejected: ['rejected', 'withdrawn'],
|
||||||
|
approved: ['approved'],
|
||||||
|
},
|
||||||
'contract-manage': {
|
'contract-manage': {
|
||||||
dictName: '提交合同审核流',
|
dictName: '提交合同审核流',
|
||||||
subjectPrefix: '合同审批',
|
subjectPrefix: '合同审批',
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ export default {
|
|||||||
this.postFormData('save', lbpmFormValues, this.buildFormData());
|
this.postFormData('save', lbpmFormValues, this.buildFormData());
|
||||||
},
|
},
|
||||||
postFormData(status, formValues, formData) {
|
postFormData(status, formValues, formData) {
|
||||||
postMkPublicProcessMessage('project-apply', {
|
const bizType = this.$route.meta?.bizType || 'project-apply';
|
||||||
|
postMkPublicProcessMessage(bizType, {
|
||||||
status,
|
status,
|
||||||
formValues: formValues || {},
|
formValues: formValues || {},
|
||||||
formData,
|
formData,
|
||||||
|
|||||||
@@ -810,7 +810,21 @@
|
|||||||
<template v-if="isChangeDialog">
|
<template v-if="isChangeDialog">
|
||||||
<el-button v-if="!isProjectFormPage" @click="handleCancelProject">取消</el-button>
|
<el-button v-if="!isProjectFormPage" @click="handleCancelProject">取消</el-button>
|
||||||
<el-button v-if="isProjectFormPage" @click="closeProjectForm">取消</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>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -985,6 +999,7 @@ import {
|
|||||||
projectTypeOptions,
|
projectTypeOptions,
|
||||||
} from '@/option/business/common';
|
} from '@/option/business/common';
|
||||||
import { config, option } from '@/option/business/project-apply';
|
import { config, option } from '@/option/business/project-apply';
|
||||||
|
import * as projectChangeApi from '@/api/business/project-change';
|
||||||
|
|
||||||
const emptyForm = () => ({
|
const emptyForm = () => ({
|
||||||
projectType: '',
|
projectType: '',
|
||||||
@@ -1060,6 +1075,9 @@ const attachmentViewerPlugins = [
|
|||||||
const projectApplyListRoute = '/business/project-apply';
|
const projectApplyListRoute = '/business/project-apply';
|
||||||
const projectApplyFormRoute = '/business/project-apply/form';
|
const projectApplyFormRoute = '/business/project-apply/form';
|
||||||
const projectApplyListRefreshKey = 'project-apply-list-refresh';
|
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: '其他附件' };
|
const otherAttachmentType = { label: '其他附件', value: '其他附件' };
|
||||||
|
|
||||||
@@ -1245,7 +1263,40 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
changeReason: [
|
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: [
|
projectIntro: [
|
||||||
{ max: 1000, message: '项目简介不能超过1000个字符', trigger: 'blur' },
|
{ max: 1000, message: '项目简介不能超过1000个字符', trigger: 'blur' },
|
||||||
@@ -1374,8 +1425,11 @@ export default {
|
|||||||
isMajorProjectSupplementDialog() {
|
isMajorProjectSupplementDialog() {
|
||||||
return this.dialogType === 'majorSupplement';
|
return this.dialogType === 'majorSupplement';
|
||||||
},
|
},
|
||||||
|
isProjectChangeModule() {
|
||||||
|
return this.$route.path === projectChangeFormRoute;
|
||||||
|
},
|
||||||
isChangeDialog() {
|
isChangeDialog() {
|
||||||
return this.dialogType === 'change';
|
return this.dialogType === 'change' || this.isProjectChangeModule;
|
||||||
},
|
},
|
||||||
isNewProjectDialog() {
|
isNewProjectDialog() {
|
||||||
return ['add', 'majorSupplement'].includes(this.dialogType);
|
return ['add', 'majorSupplement'].includes(this.dialogType);
|
||||||
@@ -1384,7 +1438,13 @@ export default {
|
|||||||
return this.isFormPageInstance;
|
return this.isFormPageInstance;
|
||||||
},
|
},
|
||||||
isPublicViewPage() {
|
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() {
|
projectFormContainer() {
|
||||||
// 表单页实例始终用页面容器,避免 keep-alive 失活时误切弹窗
|
// 表单页实例始终用页面容器,避免 keep-alive 失活时误切弹窗
|
||||||
@@ -1451,7 +1511,7 @@ export default {
|
|||||||
this.loadCargoTypeOptions();
|
this.loadCargoTypeOptions();
|
||||||
this.loadTransportTypeOptions();
|
this.loadTransportTypeOptions();
|
||||||
this.loadSettlementModeOptions();
|
this.loadSettlementModeOptions();
|
||||||
if (this.$route.path === projectApplyFormRoute) {
|
if (this.$route.path === projectApplyFormRoute || this.$route.path === projectChangeFormRoute) {
|
||||||
this.isFormPageInstance = true;
|
this.isFormPageInstance = true;
|
||||||
this.openProjectFormPage();
|
this.openProjectFormPage();
|
||||||
}
|
}
|
||||||
@@ -1517,14 +1577,14 @@ export default {
|
|||||||
},
|
},
|
||||||
openPublicProjectForm() {
|
openPublicProjectForm() {
|
||||||
const id = this.$route.query.id;
|
const id = this.$route.query.id;
|
||||||
this.dialogType = 'view';
|
this.dialogType = this.publicBizType === 'project-change' ? 'change' : 'view';
|
||||||
this.dialogReadonly = true;
|
this.dialogReadonly = true;
|
||||||
this.projectBox = true;
|
this.projectBox = true;
|
||||||
if (!id) {
|
if (!id) {
|
||||||
this.$message.error('缺少项目ID');
|
this.$message.error('缺少项目ID');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getMkPublicDetail('project-apply', id)
|
getMkPublicDetail(this.publicBizType, id)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const detail = res.data?.data || {};
|
const detail = res.data?.data || {};
|
||||||
this.applyPublicDictOptions(detail);
|
this.applyPublicDictOptions(detail);
|
||||||
@@ -1587,9 +1647,25 @@ export default {
|
|||||||
openProjectFormPage() {
|
openProjectFormPage() {
|
||||||
const type = this.$route.query.mode || 'add';
|
const type = this.$route.query.mode || 'add';
|
||||||
const id = this.$route.query.id;
|
const id = this.$route.query.id;
|
||||||
this.dialogType = type;
|
this.dialogType = this.isProjectChangeModule ? (type === 'view' ? 'view' : 'change') : type;
|
||||||
this.dialogReadonly = type === 'view';
|
this.dialogReadonly = type === 'view';
|
||||||
this.projectBox = true;
|
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)) {
|
if (['add', 'majorSupplement'].includes(type)) {
|
||||||
this.applyProjectDetail({
|
this.applyProjectDetail({
|
||||||
...emptyForm(),
|
...emptyForm(),
|
||||||
@@ -1613,6 +1689,12 @@ export default {
|
|||||||
},
|
},
|
||||||
closeProjectForm() {
|
closeProjectForm() {
|
||||||
if (this.isProjectFormPage) {
|
if (this.isProjectFormPage) {
|
||||||
|
if (this.isProjectChangeModule) {
|
||||||
|
sessionStorage.setItem(projectChangeListRefreshKey, '1');
|
||||||
|
this.$router.$avueRouter?.closeTag?.();
|
||||||
|
this.$router.push(projectChangeListRoute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.markProjectApplyListNeedRefresh();
|
this.markProjectApplyListNeedRefresh();
|
||||||
this.$router.$avueRouter?.closeTag?.();
|
this.$router.$avueRouter?.closeTag?.();
|
||||||
this.$router.push(projectApplyListRoute);
|
this.$router.push(projectApplyListRoute);
|
||||||
@@ -1858,7 +1940,7 @@ export default {
|
|||||||
},
|
},
|
||||||
handleCustomOperation(operation, row) {
|
handleCustomOperation(operation, row) {
|
||||||
if (operation.action === 'startChange') {
|
if (operation.action === 'startChange') {
|
||||||
this.openProjectDialog('change', row);
|
this.startIndependentProjectChange(row);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (operation.action === 'mkAudit') {
|
if (operation.action === 'mkAudit') {
|
||||||
@@ -2169,6 +2251,52 @@ export default {
|
|||||||
this.closeProjectForm();
|
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() {
|
submitChangeProject() {
|
||||||
this.$refs.projectForm.validate(valid => {
|
this.$refs.projectForm.validate(valid => {
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
@@ -2177,7 +2305,34 @@ export default {
|
|||||||
}
|
}
|
||||||
if (!this.validateAttachmentFileTypes()) return;
|
if (!this.validateAttachmentFileTypes()) return;
|
||||||
this.submitLoading = true;
|
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
|
this.api
|
||||||
.submitChange(this.normalizeSubmitForm({ includeChangeType: true }))
|
.submitChange(this.normalizeSubmitForm({ includeChangeType: true }))
|
||||||
.then(res => {
|
.then(res => {
|
||||||
|
|||||||
@@ -0,0 +1,362 @@
|
|||||||
|
<template>
|
||||||
|
<basic-container class="project-change-page">
|
||||||
|
<avue-crud
|
||||||
|
:option="tableOption"
|
||||||
|
:table-loading="loading"
|
||||||
|
:data="data"
|
||||||
|
v-model:page="page"
|
||||||
|
v-model="tableForm"
|
||||||
|
ref="crud"
|
||||||
|
:permission="permissionList"
|
||||||
|
@search-change="searchChange"
|
||||||
|
@search-reset="searchReset"
|
||||||
|
@selection-change="selectionChange"
|
||||||
|
@current-change="currentChange"
|
||||||
|
@size-change="sizeChange"
|
||||||
|
@refresh-change="refreshChange"
|
||||||
|
@on-load="onLoad"
|
||||||
|
>
|
||||||
|
<template #menu-left>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
plain
|
||||||
|
v-if="hasPermission(`${config.permission}_delete`)"
|
||||||
|
@click="handleDelete"
|
||||||
|
>
|
||||||
|
批量删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #approvalStatus="{ row }">
|
||||||
|
{{ row.approvalStatusName || statusLabel(row.approvalStatus) }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #syncStatus="{ row }">
|
||||||
|
<el-tag v-if="row.syncStatus" :type="syncTagType(row.syncStatus)" class="status-text">
|
||||||
|
{{ syncLabel(row.syncStatus) }}
|
||||||
|
</el-tag>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #menu="{ row }">
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="canView(row)"
|
||||||
|
@click="openForm('view', row)"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</el-link>
|
||||||
|
<el-link type="primary" v-if="canEdit(row)" @click="openForm('edit', row)">
|
||||||
|
编辑
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
type="danger"
|
||||||
|
v-if="canDelete(row)"
|
||||||
|
@click="rowDel(row)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
v-for="operation in customOperations(row)"
|
||||||
|
:key="operation.action"
|
||||||
|
:type="operation.type === 'warning' ? 'warning' : operation.type === 'success' ? 'success' : 'primary'"
|
||||||
|
@click="handleCustomOperation(operation, row)"
|
||||||
|
>
|
||||||
|
{{ operation.label }}
|
||||||
|
</el-link>
|
||||||
|
</template>
|
||||||
|
</avue-crud>
|
||||||
|
</basic-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as api from '@/api/business/project-change';
|
||||||
|
import { getMKApprovalUrl } from '@/api/system/business-process';
|
||||||
|
import { config, option } from '@/option/business/project-change';
|
||||||
|
import { approvalStatusOptions } from '@/option/business/common';
|
||||||
|
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||||
|
import { isAdministrator } from '@/utils/auth';
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
const projectChangeFormRoute = '/business/project-change/form';
|
||||||
|
const projectChangeListRefreshKey = 'project-change-list-refresh';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ProjectChange',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
api,
|
||||||
|
config,
|
||||||
|
tableForm: {},
|
||||||
|
tableOption: this.buildTableOption(),
|
||||||
|
loading: true,
|
||||||
|
data: [],
|
||||||
|
page: {
|
||||||
|
pageSize: 10,
|
||||||
|
currentPage: 1,
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
query: {},
|
||||||
|
selectionList: [],
|
||||||
|
mkEnabled: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['permission', 'userInfo', 'website']),
|
||||||
|
permissionList() {
|
||||||
|
return {
|
||||||
|
addBtn: false,
|
||||||
|
viewBtn: false,
|
||||||
|
delBtn: false,
|
||||||
|
editBtn: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
isAdmin() {
|
||||||
|
return isAdministrator(this.userInfo);
|
||||||
|
},
|
||||||
|
ids() {
|
||||||
|
return this.selectionList.map(item => item.id).join(',');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
loadMkEnabled()
|
||||||
|
.then(enabled => {
|
||||||
|
this.mkEnabled = enabled;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.mkEnabled = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
if (sessionStorage.getItem(projectChangeListRefreshKey)) {
|
||||||
|
sessionStorage.removeItem(projectChangeListRefreshKey);
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
buildTableOption() {
|
||||||
|
return {
|
||||||
|
...option,
|
||||||
|
addBtn: false,
|
||||||
|
viewBtn: false,
|
||||||
|
editBtn: false,
|
||||||
|
delBtn: false,
|
||||||
|
menuWidth: 320,
|
||||||
|
column: (option.column || []).map(column => ({
|
||||||
|
...column,
|
||||||
|
display: false,
|
||||||
|
align: 'center',
|
||||||
|
headerAlign: 'center',
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
hasPermission(code) {
|
||||||
|
return this.isAdmin || this.validData(this.permission && this.permission[code], false);
|
||||||
|
},
|
||||||
|
statusLabel(status) {
|
||||||
|
return approvalStatusOptions.find(item => item.value === status)?.label || status || '-';
|
||||||
|
},
|
||||||
|
syncLabel(value) {
|
||||||
|
return { unsynced: '待推送', synced: '已推送', failed: '推送失败' }[value] || value;
|
||||||
|
},
|
||||||
|
syncTagType(value) {
|
||||||
|
return { unsynced: 'info', synced: 'success', failed: 'danger' }[value] || 'info';
|
||||||
|
},
|
||||||
|
inStatus(row, statusList) {
|
||||||
|
if (!statusList || !statusList.length) return true;
|
||||||
|
return statusList.includes(row.approvalStatus);
|
||||||
|
},
|
||||||
|
canEdit(row) {
|
||||||
|
return (
|
||||||
|
this.hasPermission(`${this.config.permission}_edit`) &&
|
||||||
|
!row.readonly &&
|
||||||
|
this.inStatus(row, this.config.editStatus)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
canDelete(row) {
|
||||||
|
return (
|
||||||
|
this.hasPermission(`${this.config.permission}_delete`) &&
|
||||||
|
!row.readonly &&
|
||||||
|
this.inStatus(row, this.config.deleteStatus)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
canView(row) {
|
||||||
|
return (
|
||||||
|
this.hasPermission(`${this.config.permission}_view`) &&
|
||||||
|
this.inStatus(row, this.config.viewStatus)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
canOperation(operation, row) {
|
||||||
|
if (operation.permission && !this.hasPermission(operation.permission)) return false;
|
||||||
|
if (row.readonly && ['submitApproval', 'withdraw', 'approve', 'reject'].includes(operation.action)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.inStatus(row, operation.status);
|
||||||
|
},
|
||||||
|
customOperations(row) {
|
||||||
|
return (this.config.operations || []).filter(operation => {
|
||||||
|
if (operation.mkOnly && !this.mkEnabled) return false;
|
||||||
|
if (operation.localOnly && this.mkEnabled) return false;
|
||||||
|
return this.canOperation(operation, row);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openForm(mode, row = {}) {
|
||||||
|
const query = { mode, id: row.id };
|
||||||
|
if (mode === 'edit') query.name = '编辑项目变更';
|
||||||
|
else if (mode === 'view') query.name = '查看项目变更';
|
||||||
|
this.$router.push({ path: projectChangeFormRoute, query });
|
||||||
|
},
|
||||||
|
handleCustomOperation(operation, row) {
|
||||||
|
if (operation.action === 'mkAudit') {
|
||||||
|
this.handleMkAudit(row);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const run = () => {
|
||||||
|
const request = () => this.api[operation.action](row.id);
|
||||||
|
const afterMk =
|
||||||
|
operation.action === 'submitApproval'
|
||||||
|
? submitMkApprovalFlow({
|
||||||
|
bizType: 'project-change',
|
||||||
|
bizId: row.id,
|
||||||
|
subjectName: row.projectName || '',
|
||||||
|
approvalStatus: row.approvalStatus || '',
|
||||||
|
mkEnabled: this.mkEnabled,
|
||||||
|
}).then(() => request())
|
||||||
|
: request();
|
||||||
|
const loading =
|
||||||
|
operation.action === 'approve'
|
||||||
|
? this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '正在推送合规,请稍候…',
|
||||||
|
background: 'rgba(255, 255, 255, 0.6)',
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
afterMk
|
||||||
|
.then(res => {
|
||||||
|
if (operation.action === 'approve' && res.data?.data === false) {
|
||||||
|
this.$message.warning(res.data?.msg);
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.data?.success === false) {
|
||||||
|
this.$message.error(res.data?.msg || `${operation.label}失败,请联系管理员`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$message.success(`${operation.label}成功`);
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
})
|
||||||
|
.finally(() => loading && loading.close());
|
||||||
|
};
|
||||||
|
this.$confirm(operation.confirm || `确定${operation.label}该${this.config.title}?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => run());
|
||||||
|
},
|
||||||
|
handleMkAudit(row) {
|
||||||
|
if (!row?.id) {
|
||||||
|
this.$message.warning('变更单ID为空,无法打开审核页');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getMKApprovalUrl({ bizId: String(row.id) })
|
||||||
|
.then(res => {
|
||||||
|
const url = res?.data?.data;
|
||||||
|
if (!url) {
|
||||||
|
this.$message.error('获取审核跳转地址失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.open(url, '_blank');
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.$message.error('获取审核跳转地址失败');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
searchReset() {
|
||||||
|
this.query = {};
|
||||||
|
this.onLoad(this.page);
|
||||||
|
},
|
||||||
|
searchChange(params, done) {
|
||||||
|
this.query = params;
|
||||||
|
this.page.currentPage = 1;
|
||||||
|
this.onLoad(this.page, params);
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
selectionChange(list) {
|
||||||
|
this.selectionList = list;
|
||||||
|
},
|
||||||
|
selectionClear() {
|
||||||
|
this.selectionList = [];
|
||||||
|
this.$refs.crud?.toggleSelection?.();
|
||||||
|
},
|
||||||
|
currentChange(currentPage) {
|
||||||
|
this.page.currentPage = currentPage;
|
||||||
|
},
|
||||||
|
sizeChange(pageSize) {
|
||||||
|
this.page.pageSize = pageSize;
|
||||||
|
},
|
||||||
|
refreshChange() {
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
},
|
||||||
|
rowDel(row) {
|
||||||
|
this.$confirm('确定将选择数据删除?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
this.api.remove(row.id).then(() => {
|
||||||
|
this.$message.success('删除成功!');
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleDelete() {
|
||||||
|
if (!this.selectionList.length) {
|
||||||
|
this.$message.warning('请选择至少一条数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$confirm('确定将选择数据删除?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
this.api.remove(this.ids).then(() => {
|
||||||
|
this.$message.success('删除成功!');
|
||||||
|
this.selectionClear();
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onLoad(page, params = {}) {
|
||||||
|
this.loading = true;
|
||||||
|
const values = {
|
||||||
|
...this.query,
|
||||||
|
...params,
|
||||||
|
};
|
||||||
|
this.api
|
||||||
|
.getList(page.currentPage, page.pageSize, values)
|
||||||
|
.then(res => {
|
||||||
|
const data = res.data.data || {};
|
||||||
|
this.page.total = data.total || 0;
|
||||||
|
this.data = data.records || [];
|
||||||
|
this.loading = false;
|
||||||
|
this.selectionClear();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.project-change-page {
|
||||||
|
:deep(.avue-crud__menu) {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user