🔀 合并主干 master 到 dev
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
/dist
|
/dist
|
||||||
|
/dist.zip
|
||||||
|
|
||||||
/tests/e2e/videos/
|
/tests/e2e/videos/
|
||||||
/tests/e2e/screenshots/
|
/tests/e2e/screenshots/
|
||||||
|
|||||||
+3
-2
@@ -4,8 +4,9 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite --host",
|
||||||
"prod": "vite --mode production",
|
"prod": "vite --mode production",
|
||||||
"build": "vite build",
|
"build": "vite build && node scripts/zip-dist.mjs",
|
||||||
"build:prod": "vite build --mode production",
|
"build:prod": "vite build --mode production && node scripts/zip-dist.mjs",
|
||||||
|
"zip:dist": "node scripts/zip-dist.mjs",
|
||||||
"serve": "vite preview --host",
|
"serve": "vite preview --host",
|
||||||
"typecheck": "vue-tsc --noEmit"
|
"typecheck": "vue-tsc --noEmit"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { execFileSync } from 'node:child_process';
|
||||||
|
import { existsSync, rmSync, statSync } from 'node:fs';
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
|
const root = process.cwd();
|
||||||
|
const distDir = resolve(root, 'dist');
|
||||||
|
const zipPath = resolve(root, 'dist.zip');
|
||||||
|
|
||||||
|
if (!existsSync(distDir) || !statSync(distDir).isDirectory()) {
|
||||||
|
console.error('[zip-dist] dist 目录不存在,请先完成构建');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existsSync(zipPath)) {
|
||||||
|
rmSync(zipPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 压缩 dist 内文件到根级(解压即 index.html / assets,便于直接上传部署)
|
||||||
|
execFileSync('zip', ['-qr', zipPath, '.', '-x', '*.DS_Store', '-x', '__MACOSX/*'], {
|
||||||
|
cwd: distDir,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
|
||||||
|
const sizeMb = (statSync(zipPath).size / (1024 * 1024)).toFixed(2);
|
||||||
|
console.log(`[zip-dist] 已生成 ${zipPath}(${sizeMb} MB)`);
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { createCrudApi } from './common';
|
||||||
|
import request from '@/axios';
|
||||||
|
|
||||||
|
const baseUrl = '/blade-transport/contract-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 createFromContract = (contractId, changeType) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/create-from-contract`,
|
||||||
|
method: 'post',
|
||||||
|
params: { contractId, 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 },
|
||||||
|
// 审批通过后同步推送合规(附件转传可达 20s+),覆盖全局 10s 超时
|
||||||
|
timeout: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const reject = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/reject`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const withdraw = id =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/withdraw`,
|
||||||
|
method: 'post',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
export const markSyncStatus = (ids, syncStatus) =>
|
||||||
|
request({
|
||||||
|
url: `${baseUrl}/mark-sync-status`,
|
||||||
|
method: 'post',
|
||||||
|
params: { ids, syncStatus },
|
||||||
|
});
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
import {
|
||||||
|
approvalStatusOptions,
|
||||||
|
contractCategoryOptions,
|
||||||
|
createCrudOption,
|
||||||
|
hcsSyncStatusOptions,
|
||||||
|
signTypeOptions,
|
||||||
|
} from './common';
|
||||||
|
|
||||||
|
const listDicFormatter = res => {
|
||||||
|
const data = res?.data || res;
|
||||||
|
if (Array.isArray(data)) return data;
|
||||||
|
if (Array.isArray(data?.records)) return data.records;
|
||||||
|
if (Array.isArray(data?.data)) return data.data;
|
||||||
|
if (Array.isArray(data?.data?.records)) return data.data.records;
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const projectNameDicFormatter = res => {
|
||||||
|
const list = listDicFormatter(res);
|
||||||
|
return list.filter(item => item && item.projectName && String(item.projectName).trim());
|
||||||
|
};
|
||||||
|
|
||||||
|
export const changeTypeOptions = [
|
||||||
|
{ label: '合同信息变更', value: '合同信息变更' },
|
||||||
|
{ label: '结算规则变更', value: '结算规则变更' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
title: '合同变更',
|
||||||
|
permission: 'contract_change',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
statusTextProp: 'approvalStatusName',
|
||||||
|
deleteStatus: ['draft', 'withdrawn', 'rejected'],
|
||||||
|
editStatus: ['draft', 'withdrawn', 'rejected'],
|
||||||
|
viewStatus: ['approved'],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
action: 'submitApproval',
|
||||||
|
label: '提交',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['draft'],
|
||||||
|
permission: 'contract_change_submit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'withdraw',
|
||||||
|
label: '撤回',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'contract_change_withdraw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'mkAudit',
|
||||||
|
label: '流程',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing', 'rejected', 'approved'],
|
||||||
|
permission: 'contract_change_approve',
|
||||||
|
mkOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'approve',
|
||||||
|
label: '通过',
|
||||||
|
type: 'success',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'contract_change_approve',
|
||||||
|
localOnly: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: 'reject',
|
||||||
|
label: '驳回',
|
||||||
|
type: 'warning',
|
||||||
|
statusProp: 'approvalStatus',
|
||||||
|
status: ['reviewing'],
|
||||||
|
permission: 'contract_change_reject',
|
||||||
|
localOnly: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const option = createCrudOption([
|
||||||
|
{
|
||||||
|
label: '合同编号',
|
||||||
|
prop: 'contractNo',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 20,
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '合同名称',
|
||||||
|
prop: 'contractName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 30,
|
||||||
|
minWidth: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属项目',
|
||||||
|
prop: 'projectName',
|
||||||
|
search: true,
|
||||||
|
searchType: 'select',
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 60,
|
||||||
|
dicUrl: '/blade-transport/project-apply/list?current=1&size=9999&contractSelectable=true',
|
||||||
|
dicFormatter: projectNameDicFormatter,
|
||||||
|
props: {
|
||||||
|
label: 'projectName',
|
||||||
|
value: 'projectName',
|
||||||
|
},
|
||||||
|
filterable: true,
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '所属组织',
|
||||||
|
prop: 'organizationName',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请输入',
|
||||||
|
searchOrder: 10,
|
||||||
|
minWidth: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '合同类别',
|
||||||
|
prop: 'contractCategory',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 70,
|
||||||
|
dicData: contractCategoryOptions,
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '签约类型',
|
||||||
|
prop: 'signType',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 50,
|
||||||
|
dicData: signTypeOptions,
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '甲方',
|
||||||
|
prop: 'partyA',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '乙方',
|
||||||
|
prop: 'partyB',
|
||||||
|
minWidth: 160,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '开始日期',
|
||||||
|
prop: 'startDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '结束日期',
|
||||||
|
prop: 'endDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '临时效力起',
|
||||||
|
prop: 'temporaryStartDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '临时效力止',
|
||||||
|
prop: 'temporaryEndDate',
|
||||||
|
type: 'date',
|
||||||
|
format: 'YYYY-MM-DD',
|
||||||
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
minWidth: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '经办人',
|
||||||
|
prop: 'handlerUserName',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '创建时间',
|
||||||
|
prop: 'createTime',
|
||||||
|
type: 'datetime',
|
||||||
|
minWidth: 170,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '审核状态',
|
||||||
|
prop: 'approvalStatus',
|
||||||
|
type: 'select',
|
||||||
|
search: true,
|
||||||
|
searchPlaceholder: '请选择',
|
||||||
|
searchOrder: 40,
|
||||||
|
dicData: approvalStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '当前节点',
|
||||||
|
prop: 'currentNode',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '当前处理人',
|
||||||
|
prop: 'currentProcessor',
|
||||||
|
minWidth: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '同步状态',
|
||||||
|
prop: 'syncStatus',
|
||||||
|
type: 'select',
|
||||||
|
dicData: hcsSyncStatusOptions,
|
||||||
|
minWidth: 110,
|
||||||
|
},
|
||||||
|
]);
|
||||||
@@ -117,6 +117,17 @@ export default [
|
|||||||
bizType: 'contract-manage',
|
bizType: 'contract-manage',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/business/contract-change/public-view',
|
||||||
|
name: '查看合同变更信息',
|
||||||
|
component: () => import('@/views/business/contract-change-public-view.vue'),
|
||||||
|
meta: {
|
||||||
|
keepAlive: false,
|
||||||
|
isTab: false,
|
||||||
|
isAuth: false,
|
||||||
|
bizType: 'contract-change',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/settlement/pre-settlement/public-view',
|
path: '/settlement/pre-settlement/public-view',
|
||||||
name: '查看预付结算单信息',
|
name: '查看预付结算单信息',
|
||||||
|
|||||||
@@ -354,6 +354,18 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/business/contract-change/form',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
name: '合同变更表单',
|
||||||
|
meta: { keepAlive: false, activeMenu: '/business/contract-change' },
|
||||||
|
component: loadView(() => import('@/views/business/contract-manage-change.vue')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/wel',
|
path: '/wel',
|
||||||
component: () =>
|
component: () =>
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ export const MK_BIZ = {
|
|||||||
rejected: ['rejected', 'change_rejected', 'withdrawn'],
|
rejected: ['rejected', 'change_rejected', 'withdrawn'],
|
||||||
approved: ['approved', 'change_approved'],
|
approved: ['approved', 'change_approved'],
|
||||||
},
|
},
|
||||||
|
'contract-change': {
|
||||||
|
dictName: '提交合同变更审核流',
|
||||||
|
subjectPrefix: '合同变更审批',
|
||||||
|
rejected: ['rejected', 'withdrawn'],
|
||||||
|
approved: ['approved'],
|
||||||
|
},
|
||||||
'pre-settlement': {
|
'pre-settlement': {
|
||||||
dictName: '提交预结算审核流',
|
dictName: '提交预结算审核流',
|
||||||
subjectPrefix: '预付结算审批',
|
subjectPrefix: '预付结算审批',
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<mk-public-shell biz-type="contract-change" :get-form="getForm">
|
||||||
|
<contract-manage-change ref="page" />
|
||||||
|
</mk-public-shell>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MkPublicShell from '@/views/mk/mk-public-shell.vue';
|
||||||
|
import ContractManageChange from '@/views/business/contract-manage-change.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ContractChangePublicView',
|
||||||
|
components: { MkPublicShell, ContractManageChange },
|
||||||
|
methods: {
|
||||||
|
getForm() {
|
||||||
|
const row = this.$refs.page?.form || {};
|
||||||
|
return { ...row, subject: row.contractName || row.contractNo || '' };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,407 @@
|
|||||||
|
<template>
|
||||||
|
<basic-container class="contract-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="primary" plain :loading="hcsRepushingId === 'batch'" @click="handleHcsBatchRepush">
|
||||||
|
批量同步
|
||||||
|
</el-button>
|
||||||
|
<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/contract-change';
|
||||||
|
import { repushBatch as hcsRepushBatch } from '@/api/business/hcs';
|
||||||
|
import { getMKApprovalUrl } from '@/api/system/business-process';
|
||||||
|
import { config, option } from '@/option/business/contract-change';
|
||||||
|
import { approvalStatusOptions } from '@/option/business/common';
|
||||||
|
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||||
|
import { isAdministrator } from '@/utils/auth';
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
const contractChangeFormRoute = '/business/contract-change/form';
|
||||||
|
const contractChangeListRefreshKey = 'contract-change-list-refresh';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ContractChange',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
api,
|
||||||
|
config,
|
||||||
|
tableForm: {},
|
||||||
|
tableOption: this.buildTableOption(),
|
||||||
|
loading: true,
|
||||||
|
data: [],
|
||||||
|
page: {
|
||||||
|
pageSize: 10,
|
||||||
|
currentPage: 1,
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
query: {},
|
||||||
|
selectionList: [],
|
||||||
|
mkEnabled: false,
|
||||||
|
hcsRepushingId: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
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(contractChangeListRefreshKey)) {
|
||||||
|
sessionStorage.removeItem(contractChangeListRefreshKey);
|
||||||
|
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';
|
||||||
|
},
|
||||||
|
canHcsRepush(row) {
|
||||||
|
return row.approvalStatus === 'approved' && row.contractId && row.syncStatus !== 'synced';
|
||||||
|
},
|
||||||
|
handleHcsBatchRepush() {
|
||||||
|
if (this.hcsRepushingId) return;
|
||||||
|
if (!this.selectionList.length) {
|
||||||
|
this.$message.warning('请选择至少一条数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rows = this.selectionList.filter(item => this.canHcsRepush(item));
|
||||||
|
if (!rows.length) {
|
||||||
|
this.$message.warning('请选择审批通过且未同步成功的变更单');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$confirm(`确定同步选中的${rows.length}条合同变更到合规系统?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}).then(() => {
|
||||||
|
const loading = this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '正在推送合规,请稍候…',
|
||||||
|
background: 'rgba(255, 255, 255, 0.6)',
|
||||||
|
});
|
||||||
|
this.hcsRepushingId = 'batch';
|
||||||
|
const contractIds = [...new Set(rows.map(item => item.contractId))];
|
||||||
|
const changeIds = rows.map(item => item.id).join(',');
|
||||||
|
hcsRepushBatch('contract', contractIds)
|
||||||
|
.then(res => {
|
||||||
|
if (res.data?.success === false) {
|
||||||
|
this.$message.error(res.data?.msg || '批量同步失败');
|
||||||
|
return api.markSyncStatus(changeIds, 'failed');
|
||||||
|
}
|
||||||
|
return api.markSyncStatus(changeIds, 'synced').then(() => {
|
||||||
|
this.$message.success(res.data?.data || '批量同步成功');
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => api.markSyncStatus(changeIds, 'failed'))
|
||||||
|
.finally(() => {
|
||||||
|
this.hcsRepushingId = null;
|
||||||
|
loading.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
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: contractChangeFormRoute, 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: 'contract-change',
|
||||||
|
bizId: row.id,
|
||||||
|
subjectName: row.contractName || '',
|
||||||
|
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">
|
||||||
|
.contract-change-page {
|
||||||
|
:deep(.avue-crud__menu) {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,12 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<basic-container class="contract-change-page">
|
<basic-container class="contract-change-page">
|
||||||
<div class="archive-page-form__title">{{ pageTitle }}</div>
|
<div class="archive-page-form__title">{{ pageTitle }}</div>
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="right" label-width="auto" class="contract-change-form">
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
:disabled="pageReadonly"
|
||||||
|
label-position="right"
|
||||||
|
label-width="auto"
|
||||||
|
class="contract-change-form"
|
||||||
|
>
|
||||||
<section class="change-section contract-basic-section">
|
<section class="change-section contract-basic-section">
|
||||||
<div class="dialog-section-title">基本信息</div>
|
<div class="dialog-section-title">基本信息</div>
|
||||||
<div class="contract-basic-section__grid">
|
<div class="contract-basic-section__grid">
|
||||||
<el-form-item label="变更类型" class="contract-basic-section__change-type">
|
<el-form-item label="变更类型" class="contract-basic-section__change-type">
|
||||||
<el-radio-group v-model="form.changeType">
|
<el-radio-group v-model="form.changeType" :disabled="pageReadonly">
|
||||||
<el-radio label="合同信息变更" />
|
<el-radio label="合同信息变更" />
|
||||||
<el-radio label="结算规则变更" />
|
<el-radio label="结算规则变更" />
|
||||||
<el-radio label="终止合同" />
|
<el-radio label="终止合同" />
|
||||||
@@ -280,7 +288,7 @@
|
|||||||
<div class="section-head">
|
<div class="section-head">
|
||||||
<div class="dialog-section-title">计费信息</div>
|
<div class="dialog-section-title">计费信息</div>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="feeGenerationMode !== 'manual'"
|
v-if="!pageReadonly && feeGenerationMode !== 'manual'"
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
@click="addPlan"
|
@click="addPlan"
|
||||||
@@ -301,6 +309,7 @@
|
|||||||
row.defaultPlan ? '是' : '否'
|
row.defaultPlan ? '是' : '否'
|
||||||
}}</template></el-table-column
|
}}</template></el-table-column
|
||||||
><el-table-column prop="remark" label="备注" min-width="260" /><el-table-column
|
><el-table-column prop="remark" label="备注" min-width="260" /><el-table-column
|
||||||
|
v-if="!pageReadonly"
|
||||||
label="操作"
|
label="操作"
|
||||||
width="180"
|
width="180"
|
||||||
><template #default="{ row, $index }"
|
><template #default="{ row, $index }"
|
||||||
@@ -416,7 +425,7 @@
|
|||||||
:value="item.value"
|
:value="item.value"
|
||||||
/></el-select></template
|
/></el-select></template
|
||||||
></el-table-column>
|
></el-table-column>
|
||||||
<el-table-column label="操作" width="100"
|
<el-table-column v-if="!pageReadonly" label="操作" width="100"
|
||||||
><template #default="{ $index }"
|
><template #default="{ $index }"
|
||||||
><el-link v-if="$index === 0" type="primary" @click="addCustomPeriodRow">添加</el-link
|
><el-link v-if="$index === 0" type="primary" @click="addCustomPeriodRow">添加</el-link
|
||||||
><el-link v-else type="danger" @click="removeCustomPeriodRow($index)"
|
><el-link v-else type="danger" @click="removeCustomPeriodRow($index)"
|
||||||
@@ -425,7 +434,7 @@
|
|||||||
></el-table-column
|
></el-table-column
|
||||||
>
|
>
|
||||||
<template #empty
|
<template #empty
|
||||||
><el-link type="primary" @click="addCustomPeriodRow">添加</el-link></template
|
><el-link v-if="!pageReadonly" type="primary" @click="addCustomPeriodRow">添加</el-link></template
|
||||||
>
|
>
|
||||||
</el-table>
|
</el-table>
|
||||||
</section>
|
</section>
|
||||||
@@ -461,7 +470,7 @@
|
|||||||
:disabled="isSettlementRuleChange"
|
:disabled="isSettlementRuleChange"
|
||||||
/></template
|
/></template
|
||||||
></el-table-column>
|
></el-table-column>
|
||||||
<el-table-column v-if="!isSettlementRuleChange" label="操作" width="100"
|
<el-table-column v-if="!pageReadonly && !isSettlementRuleChange" label="操作" width="100"
|
||||||
><template #default="{ $index }"
|
><template #default="{ $index }"
|
||||||
><el-link type="danger" @click="paymentRatioRows.splice($index, 1)"
|
><el-link type="danger" @click="paymentRatioRows.splice($index, 1)"
|
||||||
>删除</el-link
|
>删除</el-link
|
||||||
@@ -470,7 +479,7 @@
|
|||||||
>
|
>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="!isSettlementRuleChange"
|
v-if="!pageReadonly && !isSettlementRuleChange"
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
@click="addPaymentRatioRow"
|
@click="addPaymentRatioRow"
|
||||||
@@ -525,8 +534,9 @@
|
|||||||
@update:rows="changeMaterials = $event"
|
@update:rows="changeMaterials = $event"
|
||||||
@upload-to-location="handleAttachmentUploadToLocation"
|
@upload-to-location="handleAttachmentUploadToLocation"
|
||||||
/>
|
/>
|
||||||
<div class="page-footer">
|
<div v-if="!pageReadonly" class="page-footer">
|
||||||
<el-button @click="$router.back()">取消</el-button>
|
<el-button @click="goBack">取消</el-button>
|
||||||
|
<el-button v-if="isContractChangeModule" @click="saveDraft">保存草稿</el-button>
|
||||||
<el-button type="primary" @click="submit">提交</el-button>
|
<el-button type="primary" @click="submit">提交</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -539,7 +549,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as api from '@/api/business/contract-manage';
|
import * as contractApi from '@/api/business/contract-manage';
|
||||||
|
import * as changeApi from '@/api/business/contract-change';
|
||||||
|
import { getMkPublicDetail } from '@/api/mk-process';
|
||||||
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||||
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
import BillingPlanEditor from './components/billing-plan-editor.vue';
|
||||||
import ContractAttachmentSection, {
|
import ContractAttachmentSection, {
|
||||||
@@ -577,6 +589,8 @@ const defaultContractFormatOptions = [
|
|||||||
{ label: '电子合同', value: '电子合同' },
|
{ label: '电子合同', value: '电子合同' },
|
||||||
{ label: '纸质合同', value: '纸质合同' },
|
{ label: '纸质合同', value: '纸质合同' },
|
||||||
];
|
];
|
||||||
|
const contractChangeListRoute = '/business/contract-change';
|
||||||
|
const contractChangeListRefreshKey = 'contract-change-list-refresh';
|
||||||
const normalizeOptionalPositiveInteger = value => {
|
const normalizeOptionalPositiveInteger = value => {
|
||||||
if (value === undefined || value === null || value === '') return null;
|
if (value === undefined || value === null || value === '') return null;
|
||||||
const number = Number(value);
|
const number = Number(value);
|
||||||
@@ -713,8 +727,21 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
pageTitle() {
|
pageTitle() {
|
||||||
|
if (this.pageReadonly) return this.$route.query.name || '查看合同变更';
|
||||||
return this.$route.query.name || '合同变更';
|
return this.$route.query.name || '合同变更';
|
||||||
},
|
},
|
||||||
|
isContractChangeModule() {
|
||||||
|
return (
|
||||||
|
this.$route.path === '/business/contract-change/form' ||
|
||||||
|
this.$route.path === '/business/contract-change/public-view'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
isPublicViewPage() {
|
||||||
|
return this.$route.path === '/business/contract-change/public-view';
|
||||||
|
},
|
||||||
|
pageReadonly() {
|
||||||
|
return this.isPublicViewPage || this.$route.query.mode === 'view';
|
||||||
|
},
|
||||||
// 高风险/黑名单客商提示:按合同推送合规留痕 hcs_risk_level/hcs_black_status 判定(与合同详情口径一致)
|
// 高风险/黑名单客商提示:按合同推送合规留痕 hcs_risk_level/hcs_black_status 判定(与合同详情口径一致)
|
||||||
riskTipText() {
|
riskTipText() {
|
||||||
const riskLevel = String(this.form.hcsRiskLevel || '').trim();
|
const riskLevel = String(this.form.hcsRiskLevel || '').trim();
|
||||||
@@ -833,13 +860,25 @@ export default {
|
|||||||
async load() {
|
async load() {
|
||||||
const id = this.$route.query.id;
|
const id = this.$route.query.id;
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
const res = await api.getDetail(id);
|
let data = {};
|
||||||
const data = res.data?.data || res.data || {};
|
if (this.isPublicViewPage) {
|
||||||
|
const res = await getMkPublicDetail('contract-change', id);
|
||||||
|
data = res.data?.data || res.data || {};
|
||||||
|
} else if (this.isContractChangeModule) {
|
||||||
|
const res = await changeApi.getDetail(id);
|
||||||
|
data = res.data?.data || res.data || {};
|
||||||
|
} else {
|
||||||
|
const res = await contractApi.getDetail(id);
|
||||||
|
data = res.data?.data || res.data || {};
|
||||||
|
}
|
||||||
|
const isChangeRecord = this.isContractChangeModule || this.isPublicViewPage;
|
||||||
this.form = {
|
this.form = {
|
||||||
...data,
|
...data,
|
||||||
changeContent: '',
|
// 独立变更单保留 contractId;旧路由以合同 id 作为主键
|
||||||
changeReason: '',
|
contractId: data.contractId || (isChangeRecord ? data.contractId : data.id),
|
||||||
changeAttachmentsJson: '',
|
changeContent: isChangeRecord ? data.changeContent || '' : '',
|
||||||
|
changeReason: isChangeRecord ? data.changeReason || '' : '',
|
||||||
|
changeAttachmentsJson: data.changeAttachmentsJson || '',
|
||||||
copyCount: normalizeOptionalPositiveInteger(data.copyCount),
|
copyCount: normalizeOptionalPositiveInteger(data.copyCount),
|
||||||
invoiceCycle: normalizeOptionalPositiveInteger(data.invoiceCycle),
|
invoiceCycle: normalizeOptionalPositiveInteger(data.invoiceCycle),
|
||||||
paymentDays: normalizeOptionalPositiveInteger(data.paymentDays),
|
paymentDays: normalizeOptionalPositiveInteger(data.paymentDays),
|
||||||
@@ -847,14 +886,14 @@ export default {
|
|||||||
templateFlag: data.templateFlag ?? 0,
|
templateFlag: data.templateFlag ?? 0,
|
||||||
electronicSealFlag: data.electronicSealFlag ?? 0,
|
electronicSealFlag: data.electronicSealFlag ?? 0,
|
||||||
archiveStatus: data.archiveStatus || '未归档',
|
archiveStatus: data.archiveStatus || '未归档',
|
||||||
changeType: '合同信息变更',
|
changeType: data.changeType || '合同信息变更',
|
||||||
};
|
};
|
||||||
this.changeMaterials = [];
|
this.changeMaterials = this.parse(data.changeAttachmentsJson);
|
||||||
this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : [];
|
this.period = data.startDate && data.endDate ? [data.startDate, data.endDate] : [];
|
||||||
this.plans = this.parse(data.billingPlanJson);
|
this.plans = this.parse(data.billingPlanJson);
|
||||||
this.attachments = this.mergeChangeAttachments(
|
this.attachments = this.mergeChangeAttachments(
|
||||||
this.parse(data.attachmentsJson),
|
this.parse(data.attachmentsJson),
|
||||||
this.parse(data.changeAttachmentsJson)
|
isChangeRecord ? [] : this.parse(data.changeAttachmentsJson)
|
||||||
);
|
);
|
||||||
this.contractFileRows = normalizeContractFileRows(this.parse(data.contractFileJson));
|
this.contractFileRows = normalizeContractFileRows(this.parse(data.contractFileJson));
|
||||||
const rules = this.parseObject(data.settlementRuleJson);
|
const rules = this.parseObject(data.settlementRuleJson);
|
||||||
@@ -896,6 +935,70 @@ export default {
|
|||||||
data.feeGenerationMode || (Number(data.billingEnabled) === 0 ? 'manual' : 'system');
|
data.feeGenerationMode || (Number(data.billingEnabled) === 0 ? 'manual' : 'system');
|
||||||
this.paymentRatioRows = this.parse(data.paymentRatioJson);
|
this.paymentRatioRows = this.parse(data.paymentRatioJson);
|
||||||
},
|
},
|
||||||
|
goBack() {
|
||||||
|
if (this.isContractChangeModule) {
|
||||||
|
this.$router.push(contractChangeListRoute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$router.back();
|
||||||
|
},
|
||||||
|
buildChangePayload() {
|
||||||
|
if (this.settlementConfigTab === 'pre') this.preSettlementConfig = { ...this.settlementRule };
|
||||||
|
else this.formalSettlementConfig = { ...this.settlementRule };
|
||||||
|
const settlementRule = {
|
||||||
|
preSettlementConfig: this.preSettlementConfig,
|
||||||
|
formalSettlementConfig: this.formalSettlementConfig,
|
||||||
|
};
|
||||||
|
if (this.isSettlementRuleChange) {
|
||||||
|
return {
|
||||||
|
id: this.form.id,
|
||||||
|
contractId: this.form.contractId,
|
||||||
|
changeType: this.form.changeType,
|
||||||
|
changeContent: this.form.changeContent,
|
||||||
|
changeReason: this.form.changeReason,
|
||||||
|
feeGenerationMode: this.feeGenerationMode,
|
||||||
|
billingEnabled: this.feeGenerationMode === 'system' ? 1 : 0,
|
||||||
|
billingPlanJson: JSON.stringify(this.plans),
|
||||||
|
settlementRuleJson: JSON.stringify(settlementRule),
|
||||||
|
preSettlementConfigJson: JSON.stringify(this.preSettlementConfig),
|
||||||
|
formalSettlementConfigJson: JSON.stringify(this.formalSettlementConfig),
|
||||||
|
changeAttachmentsJson: JSON.stringify(this.changeMaterials),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...this.form,
|
||||||
|
contractId: this.form.contractId,
|
||||||
|
changeType: this.form.changeType || '合同信息变更',
|
||||||
|
settlementCurrency: String(this.form.settlementCurrency || '').trim() || 'RMB',
|
||||||
|
copyCount: normalizeOptionalPositiveInteger(this.form.copyCount),
|
||||||
|
invoiceCycle: normalizeOptionalPositiveInteger(this.form.invoiceCycle),
|
||||||
|
paymentDays: normalizeOptionalPositiveInteger(this.form.paymentDays),
|
||||||
|
contractAmount: normalizeOptionalAmount(this.form.contractAmount),
|
||||||
|
startDate: this.period[0],
|
||||||
|
endDate: this.period[1],
|
||||||
|
feeGenerationMode: this.feeGenerationMode,
|
||||||
|
billingEnabled: this.feeGenerationMode === 'system' ? 1 : 0,
|
||||||
|
billingPlanJson: JSON.stringify(this.plans),
|
||||||
|
settlementRuleJson: JSON.stringify(settlementRule),
|
||||||
|
preSettlementConfigJson: JSON.stringify(this.preSettlementConfig),
|
||||||
|
formalSettlementConfigJson: JSON.stringify(this.formalSettlementConfig),
|
||||||
|
paymentRatioJson: JSON.stringify(this.paymentRatioRows),
|
||||||
|
contractFileJson: JSON.stringify(this.contractFileRows),
|
||||||
|
attachmentsJson: JSON.stringify(this.attachments),
|
||||||
|
changeContent: this.form.changeContent,
|
||||||
|
changeReason: this.form.changeReason,
|
||||||
|
changeAttachmentsJson: JSON.stringify(this.changeMaterials),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async saveDraft() {
|
||||||
|
if (this.form.changeType === '终止合同') {
|
||||||
|
this.$message.warning('终止合同无需保存草稿,请直接提交');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const payload = this.buildChangePayload();
|
||||||
|
await changeApi.saveDraft(payload);
|
||||||
|
this.$message.success('草稿已保存');
|
||||||
|
},
|
||||||
parse(value) {
|
parse(value) {
|
||||||
try {
|
try {
|
||||||
const result = JSON.parse(value || '[]');
|
const result = JSON.parse(value || '[]');
|
||||||
@@ -989,9 +1092,10 @@ export default {
|
|||||||
validateSettlementRule(rule, label) { if (Number(rule.autoGenerate) !== 1) return true; if (!rule.billStartDate || !rule.settlementType) { this.$message.warning(`${label}:请完整填写账单起始日和结算类型`); return false; } if (rule.settlementType === '月结' && !rule.billCycleType) { this.$message.warning(`${label}:请选择结算周期`); return false; } if (rule.settlementType === '月结' && rule.billCycleType === '固定截单日' && !rule.billCutoffDay) { this.$message.warning(`${label}:请选择账单截单日`); return false; } if (rule.settlementType === '月结' && rule.billCycleType === '自定义多周期') return this.validateCustomPeriods(rule.customPeriods, label); if (rule.settlementType === '固定天数周期结算' && !rule.cycleDays) { this.$message.warning(`${label}:请选择周期天数`); return false; } return true; },
|
validateSettlementRule(rule, label) { if (Number(rule.autoGenerate) !== 1) return true; if (!rule.billStartDate || !rule.settlementType) { this.$message.warning(`${label}:请完整填写账单起始日和结算类型`); return false; } if (rule.settlementType === '月结' && !rule.billCycleType) { this.$message.warning(`${label}:请选择结算周期`); return false; } if (rule.settlementType === '月结' && rule.billCycleType === '固定截单日' && !rule.billCutoffDay) { this.$message.warning(`${label}:请选择账单截单日`); return false; } if (rule.settlementType === '月结' && rule.billCycleType === '自定义多周期') return this.validateCustomPeriods(rule.customPeriods, label); if (rule.settlementType === '固定天数周期结算' && !rule.cycleDays) { this.$message.warning(`${label}:请选择周期天数`); return false; } return true; },
|
||||||
async submit() {
|
async submit() {
|
||||||
if (this.form.changeType === '终止合同') {
|
if (this.form.changeType === '终止合同') {
|
||||||
await api.terminate(this.form.id, this.form.changeReason);
|
const contractId = this.form.contractId || this.form.id;
|
||||||
|
await contractApi.terminate(contractId, this.form.changeReason);
|
||||||
this.$message.success('合同已终止');
|
this.$message.success('合同已终止');
|
||||||
this.$router.back();
|
this.goBack();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.$refs.formRef.validate();
|
await this.$refs.formRef.validate();
|
||||||
@@ -1020,48 +1124,22 @@ export default {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const settlementRule = {
|
const payload = this.buildChangePayload();
|
||||||
preSettlementConfig: this.preSettlementConfig,
|
if (this.isContractChangeModule) {
|
||||||
formalSettlementConfig: this.formalSettlementConfig,
|
await changeApi.submit(payload);
|
||||||
};
|
await submitMkApprovalFlow({
|
||||||
const payload = this.isSettlementRuleChange
|
bizType: 'contract-change',
|
||||||
? {
|
bizId: this.form.id,
|
||||||
id: this.form.id,
|
subjectName: this.form.contractName || '',
|
||||||
changeType: this.form.changeType,
|
approvalStatus: this.form.approvalStatus || '',
|
||||||
changeContent: this.form.changeContent,
|
mkEnabled: await loadMkEnabled().catch(() => false),
|
||||||
changeReason: this.form.changeReason,
|
});
|
||||||
feeGenerationMode: this.feeGenerationMode,
|
sessionStorage.setItem(contractChangeListRefreshKey, '1');
|
||||||
billingEnabled: this.feeGenerationMode === 'system' ? 1 : 0,
|
this.$message.success('变更已提交');
|
||||||
billingPlanJson: JSON.stringify(this.plans),
|
this.$router.push(contractChangeListRoute);
|
||||||
settlementRuleJson: JSON.stringify(settlementRule),
|
return;
|
||||||
preSettlementConfigJson: JSON.stringify(this.preSettlementConfig),
|
}
|
||||||
formalSettlementConfigJson: JSON.stringify(this.formalSettlementConfig),
|
await contractApi.submitChange(payload);
|
||||||
changeAttachmentsJson: JSON.stringify(this.changeMaterials),
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
...this.form,
|
|
||||||
changeType: this.form.changeType || '合同信息变更',
|
|
||||||
settlementCurrency: String(this.form.settlementCurrency || '').trim() || 'RMB',
|
|
||||||
copyCount: normalizeOptionalPositiveInteger(this.form.copyCount),
|
|
||||||
invoiceCycle: normalizeOptionalPositiveInteger(this.form.invoiceCycle),
|
|
||||||
paymentDays: normalizeOptionalPositiveInteger(this.form.paymentDays),
|
|
||||||
contractAmount: normalizeOptionalAmount(this.form.contractAmount),
|
|
||||||
startDate: this.period[0],
|
|
||||||
endDate: this.period[1],
|
|
||||||
feeGenerationMode: this.feeGenerationMode,
|
|
||||||
billingEnabled: this.feeGenerationMode === 'system' ? 1 : 0,
|
|
||||||
billingPlanJson: JSON.stringify(this.plans),
|
|
||||||
settlementRuleJson: JSON.stringify(settlementRule),
|
|
||||||
preSettlementConfigJson: JSON.stringify(this.preSettlementConfig),
|
|
||||||
formalSettlementConfigJson: JSON.stringify(this.formalSettlementConfig),
|
|
||||||
paymentRatioJson: JSON.stringify(this.paymentRatioRows),
|
|
||||||
contractFileJson: JSON.stringify(this.contractFileRows),
|
|
||||||
attachmentsJson: JSON.stringify(this.attachments),
|
|
||||||
changeContent: this.form.changeContent,
|
|
||||||
changeReason: this.form.changeReason,
|
|
||||||
changeAttachmentsJson: JSON.stringify(this.changeMaterials),
|
|
||||||
};
|
|
||||||
await api.submitChange(payload);
|
|
||||||
await submitMkApprovalFlow({
|
await submitMkApprovalFlow({
|
||||||
bizType: 'contract-manage',
|
bizType: 'contract-manage',
|
||||||
bizId: this.form.id,
|
bizId: this.form.id,
|
||||||
|
|||||||
@@ -1089,6 +1089,7 @@ import NProgress from 'nprogress';
|
|||||||
import 'nprogress/nprogress.css';
|
import 'nprogress/nprogress.css';
|
||||||
import { exportBlob } from '@/api/common';
|
import { exportBlob } from '@/api/common';
|
||||||
import * as api from '@/api/business/contract-manage';
|
import * as api from '@/api/business/contract-manage';
|
||||||
|
import { createFromContract } from '@/api/business/contract-change';
|
||||||
import { repush as hcsRepush, repushBatch as hcsRepushBatch, getRisk } from '@/api/business/hcs';
|
import { repush as hcsRepush, repushBatch as hcsRepushBatch, getRisk } from '@/api/business/hcs';
|
||||||
import { Position } from '@element-plus/icons-vue';
|
import { Position } from '@element-plus/icons-vue';
|
||||||
import { getMkPublicDetail } from '@/api/mk-process';
|
import { getMkPublicDetail } from '@/api/mk-process';
|
||||||
@@ -3220,12 +3221,33 @@ export default {
|
|||||||
if (value === undefined || value === null || value === '') return '-';
|
if (value === undefined || value === null || value === '') return '-';
|
||||||
return options.find(item => String(item.value) === String(value))?.label || value;
|
return options.find(item => String(item.value) === String(value))?.label || value;
|
||||||
},
|
},
|
||||||
|
handleStartContractChange(row) {
|
||||||
|
if (!row?.id) {
|
||||||
|
this.$message.warning('合同ID为空,无法发起变更');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const loading = this.$loading({
|
||||||
|
lock: true,
|
||||||
|
text: '正在创建变更单…',
|
||||||
|
background: 'rgba(255, 255, 255, 0.6)',
|
||||||
|
});
|
||||||
|
createFromContract(row.id)
|
||||||
|
.then(res => {
|
||||||
|
const data = res?.data?.data || res?.data || {};
|
||||||
|
if (!data.id) {
|
||||||
|
this.$message.error(res?.data?.msg || '创建合同变更草稿失败');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$router.push({
|
||||||
|
path: '/business/contract-change/form',
|
||||||
|
query: { mode: 'edit', id: data.id, name: '合同变更' },
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => loading.close());
|
||||||
|
},
|
||||||
handleOperation(operation, row) {
|
handleOperation(operation, row) {
|
||||||
if (operation.action === 'startChange') {
|
if (operation.action === 'startChange') {
|
||||||
this.$router.push({
|
this.handleStartContractChange(row);
|
||||||
path: '/business/contract-manage/change',
|
|
||||||
query: { id: row.id, name: '合同变更' },
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (operation.action === 'flow') {
|
if (operation.action === 'flow') {
|
||||||
|
|||||||
Reference in New Issue
Block a user