✨ 多业务接入MK审核流,提交改传bizId并由后端生成表单实例

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-29 02:23:24 +08:00
parent 8b9c908237
commit 4641d0a5dd
28 changed files with 644 additions and 391 deletions
+4 -3
View File
@@ -6,8 +6,9 @@ import request from '@/axios';
* @param {string} data.templateCode 模板编码 * @param {string} data.templateCode 模板编码
* @param {string} data.submitIdentity 提交人(手机号) * @param {string} data.submitIdentity 提交人(手机号)
* @param {string} data.loginName 登录账号(手机号) * @param {string} data.loginName 登录账号(手机号)
* @param {string} data.formInstanceId 业务表单实例 id * @param {string} data.bizId 业务主键(后端生成/复用 formInstanceId)
* @param {string} [data.subject] 流程标题 * @param {string} [data.subject] 流程标题
* @param {string} [data.bizType] 业务类型
*/ */
export const processSubmit = data => { export const processSubmit = data => {
return request({ return request({
@@ -20,7 +21,7 @@ export const processSubmit = data => {
/** /**
* 调用 MK processDelete 删除审核流(驳回后重新提交前使用) * 调用 MK processDelete 删除审核流(驳回后重新提交前使用)
* @param {Object} data * @param {Object} data
* @param {string} data.formInstanceId 业务表单实例 id * @param {string} data.bizId 业务主键
*/ */
export const processDelete = data => { export const processDelete = data => {
return request({ return request({
@@ -33,7 +34,7 @@ export const processDelete = data => {
/** /**
* 查询 MK 流程实例是否仍存在(有数据则无需删除/重新提交) * 查询 MK 流程实例是否仍存在(有数据则无需删除/重新提交)
* @param {Object} params * @param {Object} params
* @param {string} params.bizId 业务 id(formInstanceId) * @param {string} params.bizId 业务主键
*/ */
export const hasMkProcessInstance = params => { export const hasMkProcessInstance = params => {
return request({ return request({
+12 -2
View File
@@ -57,16 +57,24 @@ export const config = {
action: 'submitApproval', action: 'submitApproval',
label: '提交', label: '提交',
statusProp: 'approvalStatus', statusProp: 'approvalStatus',
status: ['draft'], status: ['draft', 'rejected', 'withdrawn'],
permission: 'project_apply_submit', permission: 'project_apply_submit',
}, },
{ {
action: 'withdraw', action: 'withdraw',
label: '撤回', label: '撤回',
statusProp: 'approvalStatus', statusProp: 'approvalStatus',
status: ['reviewing'], status: ['draft', 'reviewing'],
permission: 'project_apply_withdraw', permission: 'project_apply_withdraw',
}, },
{
action: 'mkAudit',
label: '流程',
statusProp: 'approvalStatus',
status: ['reviewing', 'change_reviewing'],
permission: 'project_apply_approve',
mkOnly: true,
},
{ {
action: 'approve', action: 'approve',
label: '通过', label: '通过',
@@ -74,6 +82,7 @@ export const config = {
statusProp: 'approvalStatus', statusProp: 'approvalStatus',
status: ['reviewing', 'change_reviewing'], status: ['reviewing', 'change_reviewing'],
permission: 'project_apply_approve', permission: 'project_apply_approve',
localOnly: true,
}, },
{ {
action: 'reject', action: 'reject',
@@ -82,6 +91,7 @@ export const config = {
statusProp: 'approvalStatus', statusProp: 'approvalStatus',
status: ['reviewing', 'change_reviewing'], status: ['reviewing', 'change_reviewing'],
permission: 'project_apply_reject', permission: 'project_apply_reject',
localOnly: true,
}, },
{ {
action: 'startChange', action: 'startChange',
+33 -11
View File
@@ -106,17 +106,6 @@ export default [
bizType: 'contract-manage', bizType: 'contract-manage',
}, },
}, },
{
path: '/business/waybill-manage/public-view',
name: '查看运单信息',
component: () => import('@/views/business/waybill-manage-public-view.vue'),
meta: {
keepAlive: false,
isTab: false,
isAuth: false,
bizType: 'waybill-manage',
},
},
{ {
path: '/settlement/pre-settlement/public-view', path: '/settlement/pre-settlement/public-view',
name: '查看预结算信息', name: '查看预结算信息',
@@ -150,6 +139,39 @@ export default [
bizType: 'payment-application', bizType: 'payment-application',
}, },
}, },
{
path: '/payment/invoice-application/public-view',
name: '查看开票申请信息',
component: () => import('@/views/payment/invoice-application-public-view.vue'),
meta: {
keepAlive: false,
isTab: false,
isAuth: false,
bizType: 'invoice-application',
},
},
{
path: '/payment/invoice-receipt/public-view',
name: '查看收票登记信息',
component: () => import('@/views/payment/invoice-receipt-public-view.vue'),
meta: {
keepAlive: false,
isTab: false,
isAuth: false,
bizType: 'invoice-receipt',
},
},
{
path: '/payment/bill-payment/public-view',
name: '查看汇票付款信息',
component: () => import('@/views/payment/bill-payment-public-view.vue'),
meta: {
keepAlive: false,
isTab: false,
isAuth: false,
bizType: 'bill-payment',
},
},
{ {
path: '/', path: '/',
name: '主页', name: '主页',
+32 -10
View File
@@ -18,11 +18,6 @@ export const MK_BIZ = {
subjectPrefix: '合同审批', subjectPrefix: '合同审批',
rejected: ['rejected', 'change_rejected', 'withdrawn'], rejected: ['rejected', 'change_rejected', 'withdrawn'],
}, },
'waybill-manage': {
dictName: '提交运单审核流',
subjectPrefix: '运单审批',
rejected: ['rejected', 'returned'],
},
'pre-settlement': { 'pre-settlement': {
dictName: '提交预结算审核流', dictName: '提交预结算审核流',
subjectPrefix: '预结算审批', subjectPrefix: '预结算审批',
@@ -38,6 +33,21 @@ export const MK_BIZ = {
subjectPrefix: '付款审批', subjectPrefix: '付款审批',
rejected: ['returned'], rejected: ['returned'],
}, },
'invoice-application': {
dictName: '提交开票审核流',
subjectPrefix: '开票审批',
rejected: ['returned'],
},
'invoice-receipt': {
dictName: '提交收票审核流',
subjectPrefix: '收票审批',
rejected: ['returned'],
},
'bill-payment': {
dictName: '提交汇票付款审核流',
subjectPrefix: '汇票付款审批',
rejected: ['returned'],
},
}; };
const MK_SWITCH_NAME = '开启MK'; const MK_SWITCH_NAME = '开启MK';
@@ -70,9 +80,17 @@ export async function resolveMkTemplateCode(dictName, list) {
return String(templateCode); return String(templateCode);
} }
/**
* 提交 MK 审核流
* @param {Object} options
* @param {string} options.bizType 业务类型
* @param {string|number} options.bizId 业务主键(后端据此生成/复用 formInstanceId)
* @param {string} [options.subjectName] 标题后缀
* @param {string} [options.approvalStatus] 当前审批状态(驳回态会先 delete)
*/
export async function submitMkApprovalFlow({ export async function submitMkApprovalFlow({
bizType, bizType,
formInstanceId, bizId,
subjectName = '', subjectName = '',
approvalStatus = '', approvalStatus = '',
}) { }) {
@@ -80,25 +98,29 @@ export async function submitMkApprovalFlow({
if (!conf) { if (!conf) {
return Promise.reject(new Error(`不支持的MK业务类型:${bizType}`)); return Promise.reject(new Error(`不支持的MK业务类型:${bizType}`));
} }
if (bizId == null || bizId === '') {
return Promise.reject(new Error('业务id不能为空'));
}
const list = await loadMkTemplateList(); const list = await loadMkTemplateList();
if (!isMkEnabled(list)) { if (!isMkEnabled(list)) {
return; return;
} }
const bizIdText = String(bizId);
// 先查 MK 流程实例:已有数据则不删除、不重新提交 // 先查 MK 流程实例:已有数据则不删除、不重新提交
const existsRes = await hasMkProcessInstance({ bizId: String(formInstanceId) }); const existsRes = await hasMkProcessInstance({ bizId: bizIdText });
if (existsRes?.data?.data) { if (existsRes?.data?.data) {
return; return;
} }
if ((conf.rejected || []).includes(approvalStatus)) { if ((conf.rejected || []).includes(approvalStatus)) {
await processDelete({ formInstanceId: String(formInstanceId) }); await processDelete({ bizId: bizIdText });
} }
const templateCode = await resolveMkTemplateCode(conf.dictName, list); const templateCode = await resolveMkTemplateCode(conf.dictName, list);
const subject = subjectName const subject = subjectName
? `${conf.subjectPrefix}:${subjectName}` ? `${conf.subjectPrefix}:${subjectName}`
: `${conf.subjectPrefix}:${formInstanceId}`; : `${conf.subjectPrefix}:${bizIdText}`;
return processSubmit({ return processSubmit({
templateCode, templateCode,
formInstanceId: String(formInstanceId), bizId: bizIdText,
subject, subject,
bizType, bizType,
}); });
+41 -11
View File
@@ -275,7 +275,12 @@ export default {
return (data && data.records) || []; return (data && data.records) || [];
}, },
defaultDeptId() { defaultDeptId() {
return (this.userInfo && (this.userInfo.deptId || this.userInfo.dept_id)) || ''; // 用户可能绑定多个组织(逗号分隔),搜索下拉是单选,只取当前会话第一个组织 ID。
const raw = (this.userInfo && (this.userInfo.deptId || this.userInfo.dept_id)) || '';
return String(raw)
.split(',')
.map(item => item.trim())
.filter(Boolean)[0] || '';
}, },
applyDefaultDeptSearch() { applyDefaultDeptSearch() {
const deptId = this.defaultDeptId(); const deptId = this.defaultDeptId();
@@ -296,6 +301,18 @@ export default {
if (deptColumn) { if (deptColumn) {
deptColumn.dicData = this.deptOptions; deptColumn.dicData = this.deptOptions;
} }
// dicData 异步到位后再回填,避免下拉选项为空时清空已选组织,导致请求丢失 deptId。
const deptId = String(this.query.deptId || this.defaultDeptId() || '');
if (!deptId) return;
if (deptColumn) {
deptColumn.searchValue = deptId;
}
this.query = { ...this.query, deptId };
this.$nextTick(() => {
if (this.$refs.crud?.searchForm) {
this.$refs.crud.searchForm.searchDeptId = deptId;
}
});
}); });
}, },
loadPriceUnitOptions() { loadPriceUnitOptions() {
@@ -323,9 +340,13 @@ export default {
flattenDept(tree, level = 0) { flattenDept(tree, level = 0) {
const result = []; const result = [];
tree.forEach(item => { tree.forEach(item => {
// 雪花 ID 必须保持字符串,避免 JS Number 精度丢失导致筛错组织。
const id =
item.id === undefined || item.id === null || item.id === '' ? '' : String(item.id);
if (!id) return;
result.push({ result.push({
label: `${' '.repeat(level)}${item.title || item.deptName || item.name}`, label: `${' '.repeat(level)}${item.title || item.deptName || item.name}`,
value: item.id, value: id,
}); });
if (item.children && item.children.length) { if (item.children && item.children.length) {
result.push(...this.flattenDept(item.children, level + 1)); result.push(...this.flattenDept(item.children, level + 1));
@@ -333,6 +354,18 @@ export default {
}); });
return result; return result;
}, },
normalizeListQuery(params = {}) {
const query = { ...params, ...this.query };
const rawDeptId = query.deptId ?? query.searchDeptId;
delete query.searchDeptId;
if (rawDeptId !== undefined && rawDeptId !== null && String(rawDeptId).trim() !== '') {
query.deptId = String(rawDeptId).split(',')[0].trim();
} else {
delete query.deptId;
}
query.allDept = this.isAdmin ? 1 : 0;
return query;
},
normalizeCargoTypeOptions(list = []) { normalizeCargoTypeOptions(list = []) {
return list return list
.map(item => ({ .map(item => ({
@@ -640,9 +673,9 @@ export default {
this.onLoad(this.page, this.query); this.onLoad(this.page, this.query);
}, },
searchChange(params, done) { searchChange(params, done) {
this.query = params; this.query = this.normalizeListQuery(params);
this.page.currentPage = 1; this.page.currentPage = 1;
this.onLoad(this.page, params); this.onLoad(this.page, this.query);
done(); done();
}, },
selectionChange(list) { selectionChange(list) {
@@ -665,12 +698,10 @@ export default {
}, },
onLoad(page, params = {}) { onLoad(page, params = {}) {
this.loading = true; this.loading = true;
const query = this.normalizeListQuery(params);
this.query = query;
api api
.getList(page.currentPage, page.pageSize, { .getList(page.currentPage, page.pageSize, query)
...params,
...this.query,
allDept: this.isAdmin ? 1 : 0,
})
.then(res => { .then(res => {
const result = res.data.data; const result = res.data.data;
this.page.total = result.total; this.page.total = result.total;
@@ -683,8 +714,7 @@ export default {
}, },
buildExportParams() { buildExportParams() {
return { return {
...this.query, ...this.normalizeListQuery(this.query),
allDept: this.isAdmin ? 1 : 0,
ids: this.ids, ids: this.ids,
[this.website.tokenHeader]: getToken(), [this.website.tokenHeader]: getToken(),
}; };
@@ -2348,7 +2348,7 @@
</div> </div>
</template> </template>
</div> </div>
<div v-if="detailPageLocked && !isPublicWaybillView" class="waybill-manage-page__detail-footer"> <div v-if="detailPageLocked" class="waybill-manage-page__detail-footer">
<el-button type="primary" @click="closeDetail">关闭</el-button> <el-button type="primary" @click="closeDetail">关闭</el-button>
</div> </div>
<template v-if="!detailPageLocked" #footer> <template v-if="!detailPageLocked" #footer>
@@ -3088,7 +3088,6 @@ import {
} from '@/api/business/process-config'; } from '@/api/business/process-config';
import { getPunchRecords as getWaybillPunchRecords, locateVehicle, trackVehicle } from '@/api/business/waybill-manage'; import { getPunchRecords as getWaybillPunchRecords, locateVehicle, trackVehicle } from '@/api/business/waybill-manage';
import VoucherExecutionDetail from './voucher-execution-detail.vue'; import VoucherExecutionDetail from './voucher-execution-detail.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { getList as getDriverList } from '@/api/transportCapacity/driver'; import { getList as getDriverList } from '@/api/transportCapacity/driver';
import { import {
fetchDriversByCarrierOrganizations, fetchDriversByCarrierOrganizations,
@@ -3098,7 +3097,6 @@ import { getDictionary as getSystemDictionary } from '@/api/system/dict';
import { addressTypeOptions } from '@/option/base/common-address'; import { addressTypeOptions } from '@/option/base/common-address';
import { packageOptions } from '@/option/business/common'; import { packageOptions } from '@/option/business/common';
import { formatUpdateUserName } from '@/utils/audit'; import { formatUpdateUserName } from '@/utils/audit';
import { submitMkApprovalFlow } from '@/utils/mk-approval';
import { getToken } from '@/utils/auth'; import { getToken } from '@/utils/auth';
import { openImportDialog } from '@/utils/import-excel'; import { openImportDialog } from '@/utils/import-excel';
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search'; import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
@@ -3607,7 +3605,6 @@ export default {
this.formPageLocked = this.isStandaloneWaybillFormPage; this.formPageLocked = this.isStandaloneWaybillFormPage;
this.detailPageLocked = this.isStandaloneWaybillDetailPage; this.detailPageLocked = this.isStandaloneWaybillDetailPage;
this.formModeLocked = this.$route.query.mode || ''; this.formModeLocked = this.$route.query.mode || '';
if (this.isPublicWaybillView) return;
this.setupSearchAutocompletes(); this.setupSearchAutocompletes();
if (this.config.enableAllDept && this.isAdmin) { if (this.config.enableAllDept && this.isAdmin) {
this.allDept = 1; this.allDept = 1;
@@ -3680,14 +3677,8 @@ export default {
isStandaloneWaybillFormPage() { isStandaloneWaybillFormPage() {
return this.isStandaloneWaybillPage && ['add', 'edit'].includes(this.$route.query.mode); return this.isStandaloneWaybillPage && ['add', 'edit'].includes(this.$route.query.mode);
}, },
isPublicWaybillView() {
return this.$route.path === '/business/waybill-manage/public-view';
},
isStandaloneWaybillDetailPage() { isStandaloneWaybillDetailPage() {
return ( return this.standaloneDetailPage && this.$route.path === standaloneWaybillDetailRoute;
(this.standaloneDetailPage && this.$route.path === standaloneWaybillDetailRoute) ||
this.isPublicWaybillView
);
}, },
// 容器形态读实例创建时锁定的标志,不随 $route 翻转(详见 data 中 formPageLocked 的说明) // 容器形态读实例创建时锁定的标志,不随 $route 翻转(详见 data 中 formPageLocked 的说明)
// 当前路由是否仍属于本实例(tab.js 按 fullPath 建实例,一个实例只对应一个 path)。 // 当前路由是否仍属于本实例(tab.js 按 fullPath 建实例,一个实例只对应一个 path)。
@@ -4640,19 +4631,14 @@ export default {
this.waybillVoucherFolder = null; this.waybillVoucherFolder = null;
this.waybillVoucherFolderView = false; this.waybillVoucherFolderView = false;
this.waybillVoucherImagesLoaded = false; this.waybillVoucherImagesLoaded = false;
const request = this.isPublicWaybillView const request =
? getMkPublicDetail('waybill-manage', row.id) typeof this.api.getDetail === 'function'
: typeof this.api.getDetail === 'function'
? this.api.getDetail(row.id) ? this.api.getDetail(row.id)
: Promise.resolve({ data: { data: row } }); : Promise.resolve({ data: { data: row } });
request request
.then(res => { .then(res => {
const detail = res?.data?.data || res?.data || row; const detail = res?.data?.data || res?.data || row;
this.detailRow = detail; this.detailRow = detail;
if (this.isPublicWaybillView) {
this.applyFormDetail(detail);
return;
}
this.loadWaybillPunchRecords(); this.loadWaybillPunchRecords();
this.loadWaybillVoucherImages(); this.loadWaybillVoucherImages();
if (detail.contractId) { if (detail.contractId) {
@@ -4728,7 +4714,6 @@ export default {
return row.id || row.customerId || ''; return row.id || row.customerId || '';
}, },
canOpenWaybillDetailSummaryLink(prop) { canOpenWaybillDetailSummaryLink(prop) {
if (this.isPublicWaybillView) return false;
const row = this.detailRow || {}; const row = this.detailRow || {};
const value = this.formatDetailValue(row, prop); const value = this.formatDetailValue(row, prop);
if (!value || value === '-') return false; if (!value || value === '-') return false;
@@ -5655,23 +5640,11 @@ export default {
} }
this.getSaveRequest()(submitRow).then( this.getSaveRequest()(submitRow).then(
res => { res => {
const data = res.data?.data || {}; this.markWaybillListNeedRefresh();
const id = data.id || submitRow.id; this.onLoad(this.page);
const after = id this.$message({ type: 'success', message: '提交成功!' });
? submitMkApprovalFlow({ done();
bizType: 'waybill-manage', if (this.isStandaloneWaybillPage) this.closeCrudDialog();
formInstanceId: id,
subjectName: data.waybillNo || submitRow.waybillNo || '',
approvalStatus: data.approvalStatus || submitRow.approvalStatus || '',
})
: Promise.resolve();
return after.then(() => {
this.markWaybillListNeedRefresh();
this.onLoad(this.page);
this.$message({ type: 'success', message: '提交成功!' });
done();
if (this.isStandaloneWaybillPage) this.closeCrudDialog();
});
}, },
error => { error => {
window.console.log(error); window.console.log(error);
@@ -5690,27 +5663,14 @@ export default {
? this.api.updateAttachments ? this.api.updateAttachments
: this.getSaveRequest(); : this.getSaveRequest();
request(submitRow).then( request(submitRow).then(
res => { () => {
const skipMk = this.attachmentUploadMode; const skipMk = this.attachmentUploadMode;
const data = res.data?.data || {}; this.attachmentUploadMode = false;
const id = data.id || submitRow.id; this.markWaybillListNeedRefresh();
const after = this.onLoad(this.page);
skipMk || !id this.$message({ type: 'success', message: skipMk ? '操作成功!' : '提交成功!' });
? Promise.resolve() done();
: submitMkApprovalFlow({ if (this.isStandaloneWaybillPage) this.closeCrudDialog();
bizType: 'waybill-manage',
formInstanceId: id,
subjectName: data.waybillNo || submitRow.waybillNo || '',
approvalStatus: data.approvalStatus || submitRow.approvalStatus || '',
});
return after.then(() => {
this.attachmentUploadMode = false;
this.markWaybillListNeedRefresh();
this.onLoad(this.page);
this.$message({ type: 'success', message: skipMk ? '操作成功!' : '提交成功!' });
done();
if (this.isStandaloneWaybillPage) this.closeCrudDialog();
});
}, },
error => { error => {
this.attachmentUploadMode = false; this.attachmentUploadMode = false;
@@ -678,7 +678,7 @@ export default {
removeCustomPeriodRow(index) { if (index <= 0) return; const periods = [...(this.settlementRule.customPeriods || [])]; periods.splice(index, 1); this.settlementRule.customPeriods = normalizeCustomPeriods(periods); }, removeCustomPeriodRow(index) { if (index <= 0) return; const periods = [...(this.settlementRule.customPeriods || [])]; periods.splice(index, 1); this.settlementRule.customPeriods = normalizeCustomPeriods(periods); },
validateCustomPeriods(periods = [], label) { const rows = normalizeCustomPeriods(periods); if (!rows.length) { this.$message.warning(`${label}:请至少配置一段自定义周期`); return false; } for (let index = 0; index < rows.length; index += 1) { const row = rows[index]; const startDay = Number(row.startDay); const endDay = Number(row.endDay); if (!Number.isFinite(startDay) || startDay < 1 || startDay > 31) { this.$message.warning(`${label}:请选择第${index + 1}行运单区间开始日`); return false; } if (!Number.isFinite(endDay) || endDay < 1 || endDay > 31) { this.$message.warning(`${label}:请选择第${index + 1}行运单区间结束日`); return false; } if (endDay < startDay) { this.$message.warning(`${label}:第${index + 1}行结束日不能早于开始日`); return false; } if (index > 0 && startDay !== Number(rows[index - 1].endDay) + 1) { this.$message.warning(`${label}:自定义多周期区间必须连续,不允许重叠或存在日期缺口`); return false; } } return true; }, validateCustomPeriods(periods = [], label) { const rows = normalizeCustomPeriods(periods); if (!rows.length) { this.$message.warning(`${label}:请至少配置一段自定义周期`); return false; } for (let index = 0; index < rows.length; index += 1) { const row = rows[index]; const startDay = Number(row.startDay); const endDay = Number(row.endDay); if (!Number.isFinite(startDay) || startDay < 1 || startDay > 31) { this.$message.warning(`${label}:请选择第${index + 1}行运单区间开始日`); return false; } if (!Number.isFinite(endDay) || endDay < 1 || endDay > 31) { this.$message.warning(`${label}:请选择第${index + 1}行运单区间结束日`); return false; } if (endDay < startDay) { this.$message.warning(`${label}:第${index + 1}行结束日不能早于开始日`); return false; } if (index > 0 && startDay !== Number(rows[index - 1].endDay) + 1) { 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; }, 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() { await this.$refs.formRef.validate(); const total = this.paymentRatioRows.reduce((sum, row) => sum + Number(row.ratioLimit || 0), 0); if (this.paymentRatioRows.length && Math.abs(total - 100) > 0.0001) { this.$message.warning('付款比例上限合计必须等于100%'); return; } if (this.settlementConfigTab === 'pre') this.preSettlementConfig = { ...this.settlementRule }; else this.formalSettlementConfig = { ...this.settlementRule }; if (!this.validateSettlementRule(this.preSettlementConfig, '预结算配置') || !this.validateSettlementRule(this.formalSettlementConfig, '正式结算配置')) return; const settlementRule = { preSettlementConfig: this.preSettlementConfig, formalSettlementConfig: this.formalSettlementConfig }; await api.submitChange({ ...this.form, 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 submitMkApprovalFlow({ bizType: 'contract-manage', formInstanceId: this.form.id, subjectName: this.form.contractName || '', approvalStatus: this.form.approvalStatus || 'change_rejected' }); this.$message.success('变更已提交'); this.$router.back(); }, async submit() { await this.$refs.formRef.validate(); const total = this.paymentRatioRows.reduce((sum, row) => sum + Number(row.ratioLimit || 0), 0); if (this.paymentRatioRows.length && Math.abs(total - 100) > 0.0001) { this.$message.warning('付款比例上限合计必须等于100%'); return; } if (this.settlementConfigTab === 'pre') this.preSettlementConfig = { ...this.settlementRule }; else this.formalSettlementConfig = { ...this.settlementRule }; if (!this.validateSettlementRule(this.preSettlementConfig, '预结算配置') || !this.validateSettlementRule(this.formalSettlementConfig, '正式结算配置')) return; const settlementRule = { preSettlementConfig: this.preSettlementConfig, formalSettlementConfig: this.formalSettlementConfig }; await api.submitChange({ ...this.form, 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 submitMkApprovalFlow({ bizType: 'contract-manage', bizId: this.form.id, subjectName: this.form.contractName || '', approvalStatus: this.form.approvalStatus || 'change_rejected' }); this.$message.success('变更已提交'); this.$router.back(); },
}, },
}; };
</script> </script>
+3 -3
View File
@@ -1890,7 +1890,7 @@ export default {
).then(() => ).then(() =>
submitMkApprovalFlow({ submitMkApprovalFlow({
bizType: 'contract-manage', bizType: 'contract-manage',
formInstanceId: id, bizId: id,
subjectName: saved.contractName || submit.contractName || '', subjectName: saved.contractName || submit.contractName || '',
approvalStatus: saved.approvalStatus || submit.approvalStatus || '', approvalStatus: saved.approvalStatus || submit.approvalStatus || '',
}) })
@@ -1928,7 +1928,7 @@ export default {
} }
return submitMkApprovalFlow({ return submitMkApprovalFlow({
bizType: 'contract-manage', bizType: 'contract-manage',
formInstanceId: payload.id || this.form.id, bizId: payload.id || this.form.id,
subjectName: payload.contractName || this.form.contractName || '', subjectName: payload.contractName || this.form.contractName || '',
approvalStatus: this.form.approvalStatus || 'change_rejected', approvalStatus: this.form.approvalStatus || 'change_rejected',
}).then(() => { }).then(() => {
@@ -2875,7 +2875,7 @@ export default {
? request().then(() => ? request().then(() =>
submitMkApprovalFlow({ submitMkApprovalFlow({
bizType: 'contract-manage', bizType: 'contract-manage',
formInstanceId: row.id, bizId: row.id,
subjectName: row.contractName || '', subjectName: row.contractName || '',
approvalStatus: row.approvalStatus || '', approvalStatus: row.approvalStatus || '',
}) })
+40 -5
View File
@@ -913,7 +913,8 @@ import { getDictionary as getBizDictionary } from '@/api/system/dictbiz';
import { getList as getUserList } from '@/api/system/user'; import { getList as getUserList } from '@/api/system/user';
import { getToken } from '@/utils/auth'; import { getToken } from '@/utils/auth';
import { downloadFileByUrl, downloadXls } from '@/utils/util'; import { downloadFileByUrl, downloadXls } from '@/utils/util';
import { submitMkApprovalFlow } from '@/utils/mk-approval'; import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
import { ElImageViewer } from 'element-plus'; import { ElImageViewer } from 'element-plus';
import { OpenFileViewer } from '@open-file-viewer/vue'; import { OpenFileViewer } from '@open-file-viewer/vue';
import PdfPreview from '@/components/pdf-preview/main.vue'; import PdfPreview from '@/components/pdf-preview/main.vue';
@@ -1117,6 +1118,7 @@ export default {
// 否则 isProjectFormPage 变 false 后容器会从 div 切成 el-dialog(append-to-body), // 否则 isProjectFormPage 变 false 后容器会从 div 切成 el-dialog(append-to-body),
// 盖住后续打开的页面(如客商档案)。 // 盖住后续打开的页面(如客商档案)。
isFormPageInstance: false, isFormPageInstance: false,
mkEnabled: false,
projectBox: false, projectBox: false,
dialogType: 'add', dialogType: 'add',
dialogReadonly: false, dialogReadonly: false,
@@ -1367,6 +1369,13 @@ export default {
this.openPublicProjectForm(); this.openPublicProjectForm();
return; return;
} }
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
this.loadDeptOptions(); this.loadDeptOptions();
this.loadCargoTypeOptions(); this.loadCargoTypeOptions();
this.loadTransportTypeOptions(); this.loadTransportTypeOptions();
@@ -1563,7 +1572,11 @@ export default {
); );
}, },
customOperations(row) { customOperations(row) {
return (this.config.operations || []).filter(operation => this.canOperation(operation, 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);
});
}, },
canOperation(operation, row) { canOperation(operation, row) {
const permission = operation.permission || `${this.config.permission}_${operation.action}`; const permission = operation.permission || `${this.config.permission}_${operation.action}`;
@@ -1689,6 +1702,10 @@ export default {
this.openProjectDialog('change', row); this.openProjectDialog('change', row);
return; return;
} }
if (operation.action === 'mkAudit') {
this.handleMkAudit(row);
return;
}
const run = value => { const run = value => {
const args = operation.prompt ? [row.id, value] : [row.id]; const args = operation.prompt ? [row.id, value] : [row.id];
const request = () => this.api[operation.action](...args); const request = () => this.api[operation.action](...args);
@@ -1696,7 +1713,7 @@ export default {
operation.action === 'submitApproval' operation.action === 'submitApproval'
? submitMkApprovalFlow({ ? submitMkApprovalFlow({
bizType: 'project-apply', bizType: 'project-apply',
formInstanceId: row.id, bizId: row.id,
subjectName: row.projectName || '', subjectName: row.projectName || '',
approvalStatus: row.approvalStatus || '', approvalStatus: row.approvalStatus || '',
}).then(() => request()) }).then(() => request())
@@ -1725,6 +1742,24 @@ export default {
type: 'warning', type: 'warning',
}).then(() => run()); }).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('获取审核跳转地址失败');
});
},
buildExportParams() { buildExportParams() {
return { return {
...this.query, ...this.query,
@@ -1881,7 +1916,7 @@ export default {
} }
return submitMkApprovalFlow({ return submitMkApprovalFlow({
bizType: 'project-apply', bizType: 'project-apply',
formInstanceId: id, bizId: id,
subjectName: name, subjectName: name,
approvalStatus: status, approvalStatus: status,
}).then(() => { }).then(() => {
@@ -1952,7 +1987,7 @@ export default {
const id = this.form.id; const id = this.form.id;
return submitMkApprovalFlow({ return submitMkApprovalFlow({
bizType: 'project-apply', bizType: 'project-apply',
formInstanceId: id, bizId: id,
subjectName: this.form.projectName || '', subjectName: this.form.projectName || '',
approvalStatus: this.form.approvalStatus || 'change_rejected', approvalStatus: this.form.approvalStatus || 'change_rejected',
}).then(() => { }).then(() => {
@@ -1,38 +0,0 @@
<template>
<mk-public-shell biz-type="waybill-manage" :get-form="getForm">
<waybill-manage-page
ref="page"
:api="api"
:config="config"
:crud-option="option"
:detail-id="detailId"
standalone-detail-page
/>
</mk-public-shell>
</template>
<script>
import MkPublicShell from '@/views/mk/mk-public-shell.vue';
import WaybillManagePage from '@/views/business/components/waybill-manage-page.vue';
import * as api from '@/api/business/waybill-manage';
import { config, option } from '@/option/business/waybill-manage';
export default {
name: 'WaybillManagePublicView',
components: { MkPublicShell, WaybillManagePage },
data() {
return { api, config, option };
},
computed: {
detailId() {
return this.$route.query.id || '';
},
},
methods: {
getForm() {
const row = this.$refs.page?.detailRow || {};
return { ...row, subject: row.waybillNo || '' };
},
},
};
</script>
-12
View File
@@ -42,17 +42,6 @@ const FIELD_MAP = {
{ label: '乙方', prop: 'partyB' }, { label: '乙方', prop: 'partyB' },
{ label: '项目名称', prop: 'projectName', span: 2 }, { label: '项目名称', prop: 'projectName', span: 2 },
], ],
'waybill-manage': [
{ label: '运单号', prop: 'waybillNo' },
{ label: '项目', prop: 'projectName' },
{ label: '客户合同', prop: 'contractName' },
{ label: '客户名称', prop: 'customerName' },
{ label: '货物名称', prop: 'cargoName' },
{ label: '承运商', prop: 'carrierName' },
{ label: '当前过程节点', prop: 'currentProcessNode' },
{ label: '发货地', prop: 'departureName' },
{ label: '收货地', prop: 'arrivalName' },
],
'pre-settlement': [ 'pre-settlement': [
{ label: '预结算单号', prop: 'preSettlementNo' }, { label: '预结算单号', prop: 'preSettlementNo' },
{ label: '合同名称', prop: 'contractName' }, { label: '合同名称', prop: 'contractName' },
@@ -88,7 +77,6 @@ const FIELD_MAP = {
const TITLE_MAP = { const TITLE_MAP = {
'project-apply': '查看项目信息', 'project-apply': '查看项目信息',
'contract-manage': '查看合同信息', 'contract-manage': '查看合同信息',
'waybill-manage': '查看运单信息',
'pre-settlement': '查看预结算信息', 'pre-settlement': '查看预结算信息',
'formal-settlement': '查看正式结算信息', 'formal-settlement': '查看正式结算信息',
'payment-application': '查看付款申请信息', 'payment-application': '查看付款申请信息',
+26 -2
View File
@@ -78,7 +78,7 @@
<vehicle-attachment-table v-model="form.attachments" :readonly="readonly" :max-size="10" /> <vehicle-attachment-table v-model="form.attachments" :readonly="readonly" :max-size="10" />
</section-card> </section-card>
<div class="bill-payment-form-page__actions"> <div v-if="!isPublicViewPage" class="bill-payment-form-page__actions">
<template v-if="!readonly"> <template v-if="!readonly">
<el-button type="primary" :loading="saving" :disabled="submitting" @click="saveDraft"> <el-button type="primary" :loading="saving" :disabled="submitting" @click="saveDraft">
保存 保存
@@ -139,6 +139,8 @@ import { mapGetters } from 'vuex';
import * as api from '@/api/payment/billPayment'; import * as api from '@/api/payment/billPayment';
import * as billLedgerApi from '@/api/payment/billLedger'; import * as billLedgerApi from '@/api/payment/billLedger';
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue'; import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { submitMkApprovalFlow } from '@/utils/mk-approval';
const emptyForm = () => ({ const emptyForm = () => ({
id: null, id: null,
@@ -194,7 +196,10 @@ export default {
return this.$route.query.id || ''; return this.$route.query.id || '';
}, },
readonly() { readonly() {
return this.$route.query.mode === 'view'; return this.$route.query.mode === 'view' || this.isPublicViewPage;
},
isPublicViewPage() {
return this.$route.path === '/payment/bill-payment/public-view';
}, },
}, },
created() { created() {
@@ -215,6 +220,10 @@ export default {
} }
}, },
async initialize() { async initialize() {
if (this.isPublicViewPage) {
await this.loadPublicDetail();
return;
}
if (this.recordId) { if (this.recordId) {
const data = this.unwrapData(await api.getDetail(this.recordId)); const data = this.unwrapData(await api.getDetail(this.recordId));
this.form = { this.form = {
@@ -228,6 +237,15 @@ export default {
this.form.deptName = this.userInfo?.deptName || this.userInfo?.dept_name || ''; this.form.deptName = this.userInfo?.deptName || this.userInfo?.dept_name || '';
this.form.paymentDate = this.$dayjs().format('YYYY-MM-DD'); this.form.paymentDate = this.$dayjs().format('YYYY-MM-DD');
}, },
async loadPublicDetail() {
if (!this.recordId) return;
const data = this.unwrapData(await getMkPublicDetail('bill-payment', this.recordId));
this.form = {
...emptyForm(),
...data,
attachments: this.parse(data.attachmentsJson),
};
},
validateUsedAmount(rule, value, callback) { validateUsedAmount(rule, value, callback) {
const amount = Number(value); const amount = Number(value);
const balance = Number(this.form.availableBalance || 0); const balance = Number(this.form.availableBalance || 0);
@@ -324,6 +342,12 @@ export default {
const id = this.unwrapData(await api.save(this.payload())); const id = this.unwrapData(await api.save(this.payload()));
this.form.id = id; this.form.id = id;
await api.submit({ id: this.form.id }); await api.submit({ id: this.form.id });
await submitMkApprovalFlow({
bizType: 'bill-payment',
bizId: this.form.id,
subjectName: this.form.paymentNo || this.form.billNo || '',
approvalStatus: this.form.approvalStatus || '',
});
this.$message.success('提交成功'); this.$message.success('提交成功');
this.goBack(); this.goBack();
} finally { } finally {
@@ -0,0 +1,21 @@
<template>
<mk-public-shell biz-type="bill-payment" :get-form="getForm">
<bill-payment-form ref="page" />
</mk-public-shell>
</template>
<script>
import MkPublicShell from '@/views/mk/mk-public-shell.vue';
import BillPaymentForm from '@/views/payment/bill-payment-form.vue';
export default {
name: 'BillPaymentPublicView',
components: { MkPublicShell, BillPaymentForm },
methods: {
getForm() {
const form = this.$refs.page?.form || {};
return { ...form, subject: form.paymentNo || form.billNo || '' };
},
},
};
</script>
+41 -21
View File
@@ -10,38 +10,26 @@
:rows="rows" :rows="rows"
:loading="loading" :loading="loading"
:page="page" :page="page"
:mk-enabled="mkEnabled"
@add="openCreate" @add="openCreate"
@view="openView" @view="openView"
@edit="openEdit" @edit="openEdit"
@delete="handleDelete" @delete="handleDelete"
@flow="openFlow" @submit="handleSubmit"
@mk-audit="handleMkAudit"
@approve="handleApprove" @approve="handleApprove"
@return="handleReturn" @return="handleReturn"
@void="handleVoid" @void="handleVoid"
@page-change="handlePageChange" @page-change="handlePageChange"
@size-change="handleSizeChange" @size-change="handleSizeChange"
/> />
<el-dialog v-model="flowDialog.visible" title="审批流程" width="620px" append-to-body>
<el-descriptions :column="1" border>
<el-descriptions-item label="单据号">
{{ flowDialog.row.paymentNo || '-' }}
</el-descriptions-item>
<el-descriptions-item label="单据状态">
{{ flowDialog.row.approvalStatusName || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前节点">
{{ flowDialog.row.currentNode || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前处理人">
{{ flowDialog.row.currentProcessor || '-' }}
</el-descriptions-item>
</el-descriptions>
</el-dialog>
</basic-container> </basic-container>
</template> </template>
<script> <script>
import * as api from '@/api/payment/billPayment'; import * as api from '@/api/payment/billPayment';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
import BillPaymentSearch from './components/bill-payment-search.vue'; import BillPaymentSearch from './components/bill-payment-search.vue';
import BillPaymentTable from './components/bill-payment-table.vue'; import BillPaymentTable from './components/bill-payment-table.vue';
@@ -62,11 +50,18 @@ export default {
rows: [], rows: [],
loading: false, loading: false,
page: { current: 1, size: 10, total: 0 }, page: { current: 1, size: 10, total: 0 },
flowDialog: { visible: false, row: {} }, mkEnabled: false,
}; };
}, },
mounted() { mounted() {
this.loadTable(); this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
}, },
methods: { methods: {
unwrapData(response) { unwrapData(response) {
@@ -125,9 +120,34 @@ export default {
if (this.rows.length === 1 && this.page.current > 1) this.page.current -= 1; if (this.rows.length === 1 && this.page.current > 1) this.page.current -= 1;
this.loadTable(); this.loadTable();
}, },
openFlow(row) { async handleSubmit(row) {
this.flowDialog.row = row; await api.submit({ id: row.id });
this.flowDialog.visible = true; await submitMkApprovalFlow({
bizType: 'bill-payment',
bizId: row.id,
subjectName: row.paymentNo || row.billNo || '',
approvalStatus: row.approvalStatus || '',
});
this.$message.success('提交成功');
this.loadTable();
},
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('获取审核跳转地址失败');
});
}, },
async handleApprove(row) { async handleApprove(row) {
await api.approve({ id: row.id }); await api.approve({ id: row.id });
@@ -50,19 +50,40 @@
>编辑</el-link >编辑</el-link
> >
<el-link <el-link
v-if="row.approvalStatus !== 'draft'" v-if="
['draft', 'returned'].includes(row.approvalStatus) &&
hasPermission('bill_payment_submit')
"
type="primary" type="primary"
@click="$emit('flow', row)" @click="$emit('submit', row)"
>提交</el-link
>
<el-link
v-if="
mkEnabled &&
row.approvalStatus === 'reviewing' &&
hasPermission('bill_payment_approve')
"
type="primary"
@click="$emit('mk-audit', row)"
>流程</el-link >流程</el-link
> >
<el-link <el-link
v-if="row.approvalStatus === 'reviewing' && hasPermission('bill_payment_approve')" v-if="
!mkEnabled &&
row.approvalStatus === 'reviewing' &&
hasPermission('bill_payment_approve')
"
type="primary" type="primary"
@click="$emit('approve', row)" @click="$emit('approve', row)"
>通过</el-link >通过</el-link
> >
<el-link <el-link
v-if="row.approvalStatus === 'reviewing' && hasPermission('bill_payment_approve')" v-if="
!mkEnabled &&
row.approvalStatus === 'reviewing' &&
hasPermission('bill_payment_approve')
"
type="danger" type="danger"
@click="$emit('return', row)" @click="$emit('return', row)"
>驳回</el-link >驳回</el-link
@@ -101,13 +122,15 @@ export default {
rows: { type: Array, default: () => [] }, rows: { type: Array, default: () => [] },
loading: { type: Boolean, default: false }, loading: { type: Boolean, default: false },
page: { type: Object, required: true }, page: { type: Object, required: true },
mkEnabled: { type: Boolean, default: false },
}, },
emits: [ emits: [
'add', 'add',
'view', 'view',
'edit', 'edit',
'delete', 'delete',
'flow', 'submit',
'mk-audit',
'approve', 'approve',
'return', 'return',
'void', 'void',
+32 -8
View File
@@ -405,7 +405,7 @@
</el-form-item> </el-form-item>
</section-card> </section-card>
<div class="invoice-form-page__actions"> <div v-if="!isPublicViewPage" class="invoice-form-page__actions">
<el-button @click="goBack">取消</el-button> <el-button @click="goBack">取消</el-button>
<el-button v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button> <el-button v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button>
<el-button v-if="!readonly && canSave" type="primary" plain @click="saveDraft" <el-button v-if="!readonly && canSave" type="primary" plain @click="saveDraft"
@@ -491,6 +491,8 @@ import { getList as getReceivablePayableDetailList } from '@/api/settlement/rece
import { getDictionary } from '@/api/system/dictbiz'; import { getDictionary } from '@/api/system/dictbiz';
import { invoiceApplicationDetailColumns } from '@/option/payment/invoiceApplication'; import { invoiceApplicationDetailColumns } from '@/option/payment/invoiceApplication';
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue'; import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { submitMkApprovalFlow } from '@/utils/mk-approval';
let localId = 0; let localId = 0;
const emptyLine = () => ({ const emptyLine = () => ({
@@ -583,7 +585,10 @@ export default {
return this.$route.query.id || ''; return this.$route.query.id || '';
}, },
readonly() { readonly() {
return this.$route.query.mode === 'view'; return this.$route.query.mode === 'view' || this.isPublicViewPage;
},
isPublicViewPage() {
return this.$route.path === '/payment/invoice-application/public-view';
}, },
canSave() { canSave() {
const code = this.recordId ? 'invoice_application_edit' : 'invoice_application_add'; const code = this.recordId ? 'invoice_application_edit' : 'invoice_application_add';
@@ -655,6 +660,10 @@ export default {
.filter(Boolean); .filter(Boolean);
}, },
async initialize() { async initialize() {
if (this.isPublicViewPage) {
await this.loadPublicDetail();
return;
}
await Promise.all([this.loadInvoiceItems(), this.loadTransportTypeOptions()]); await Promise.all([this.loadInvoiceItems(), this.loadTransportTypeOptions()]);
const userInfo = this.$store.getters.userInfo || {}; const userInfo = this.$store.getters.userInfo || {};
if (!this.recordId) { if (!this.recordId) {
@@ -662,6 +671,21 @@ export default {
return; return;
} }
const data = this.unwrapData(await api.getDetail(this.recordId)); const data = this.unwrapData(await api.getDetail(this.recordId));
this.applyDetail(data);
if (this.settlementIds.length) {
await Promise.all([this.loadReceiverInformation(), this.loadSettlementDetails(false)]);
}
if (this.readonly)
this.$nextTick(() => this.$refs.formRef?.clearValidate('departmentEmails'));
this.$nextTick(this.restoreDetailSelection);
},
async loadPublicDetail() {
if (!this.recordId) return;
const data = this.unwrapData(await getMkPublicDetail('invoice-application', this.recordId));
this.applyDetail(data);
this.$nextTick(() => this.$refs.formRef?.clearValidate('departmentEmails'));
},
applyDetail(data) {
this.form = { this.form = {
...emptyForm(), ...emptyForm(),
...data, ...data,
@@ -682,12 +706,6 @@ export default {
sheet.lines.forEach(line => this.syncInvoiceItemLine(line, false)) sheet.lines.forEach(line => this.syncInvoiceItemLine(line, false))
); );
this.selectedDetailIds = (data.details || []).map(item => item.formalSettlementDetailId); this.selectedDetailIds = (data.details || []).map(item => item.formalSettlementDetailId);
if (this.settlementIds.length) {
await Promise.all([this.loadReceiverInformation(), this.loadSettlementDetails(false)]);
}
if (this.readonly)
this.$nextTick(() => this.$refs.formRef?.clearValidate('departmentEmails'));
this.$nextTick(this.restoreDetailSelection);
}, },
async loadInvoiceItems() { async loadInvoiceItems() {
const data = this.unwrapData(await getInvoiceItems()); const data = this.unwrapData(await getInvoiceItems());
@@ -1177,6 +1195,12 @@ export default {
const saved = await this.saveDraft(); const saved = await this.saveDraft();
if (!saved) return; if (!saved) return;
await api.submit({ id: this.form.id }); await api.submit({ id: this.form.id });
await submitMkApprovalFlow({
bizType: 'invoice-application',
bizId: this.form.id,
subjectName: this.form.applicationNo || '',
approvalStatus: this.form.approvalStatus || '',
});
this.$message.success('提交成功'); this.$message.success('提交成功');
this.goBack(); this.goBack();
}, },
@@ -0,0 +1,21 @@
<template>
<mk-public-shell biz-type="invoice-application" :get-form="getForm">
<invoice-application-form ref="page" />
</mk-public-shell>
</template>
<script>
import MkPublicShell from '@/views/mk/mk-public-shell.vue';
import InvoiceApplicationForm from '@/views/payment/invoice-application-form.vue';
export default {
name: 'InvoiceApplicationPublicView',
components: { MkPublicShell, InvoiceApplicationForm },
methods: {
getForm() {
const form = this.$refs.page?.form || {};
return { ...form, subject: form.applicationNo || form.projectName || '' };
},
},
};
</script>
+46 -67
View File
@@ -151,14 +151,20 @@
>提交</el-link >提交</el-link
> >
<el-link <el-link
v-if="hasPermission('invoice_application_view') && row.approvalStatus !== 'draft'" v-if="
mkEnabled &&
hasPermission('invoice_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary" type="primary"
@click="openFlow(row)" @click="handleMkAudit(row)"
>流程</el-link >流程</el-link
> >
<el-link <el-link
v-if=" v-if="
hasPermission('invoice_application_approve') && row.approvalStatus === 'reviewing' !mkEnabled &&
hasPermission('invoice_application_approve') &&
row.approvalStatus === 'reviewing'
" "
type="primary" type="primary"
@click="handleApprove(row)" @click="handleApprove(row)"
@@ -166,7 +172,9 @@
> >
<el-link <el-link
v-if=" v-if="
hasPermission('invoice_application_approve') && row.approvalStatus === 'reviewing' !mkEnabled &&
hasPermission('invoice_application_approve') &&
row.approvalStatus === 'reviewing'
" "
type="danger" type="danger"
@click="handleReturn(row)" @click="handleReturn(row)"
@@ -197,42 +205,6 @@
/> />
</div> </div>
</section> </section>
<el-dialog v-model="flowDialog.visible" title="审批流程" width="900px" append-to-body>
<el-descriptions :column="2" border>
<el-descriptions-item label="开票申请单号">
{{ flowDialog.row.applicationNo || '-' }}
</el-descriptions-item>
<el-descriptions-item label="状态">
{{ flowDialog.row.approvalStatusName || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前节点">
{{ flowDialog.row.currentNode || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前处理人">
{{ flowDialog.row.currentProcessor || '-' }}
</el-descriptions-item>
</el-descriptions>
<el-table
v-loading="flowDialog.loading"
:data="flowDialog.records"
border
class="invoice-page__flow-table"
>
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column prop="actionName" label="操作" min-width="110" align="center" />
<el-table-column label="原状态" min-width="100" align="center">
<template #default="{ row }">{{ statusName(row.fromStatus) }}</template>
</el-table-column>
<el-table-column label="新状态" min-width="100" align="center">
<template #default="{ row }">{{ statusName(row.toStatus) }}</template>
</el-table-column>
<el-table-column prop="operatorName" label="操作人" min-width="110" align="center" />
<el-table-column prop="createTime" label="操作时间" min-width="170" align="center" />
<el-table-column prop="reason" label="原因" min-width="160" show-overflow-tooltip />
<el-table-column prop="kingdeeBillNo" label="金蝶单据号" min-width="150" />
</el-table>
</el-dialog>
</basic-container> </basic-container>
</template> </template>
@@ -244,6 +216,8 @@ import * as api from '@/api/payment/invoiceApplication';
import * as formalSettlementApi from '@/api/settlement/formalSettlement'; import * as formalSettlementApi from '@/api/settlement/formalSettlement';
import { invoiceApplicationTableColumns } from '@/option/payment/invoiceApplication'; import { invoiceApplicationTableColumns } from '@/option/payment/invoiceApplication';
import organizationSearch from '@/mixins/organization-search'; import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
const emptyQuery = () => ({ const emptyQuery = () => ({
applicationNo: '', applicationNo: '',
@@ -271,7 +245,7 @@ export default {
selection: [], selection: [],
loading: false, loading: false,
page: { current: 1, size: 10, total: 0 }, page: { current: 1, size: 10, total: 0 },
flowDialog: { visible: false, loading: false, row: {}, records: [] }, mkEnabled: false,
}; };
}, },
computed: { computed: {
@@ -280,6 +254,13 @@ export default {
mounted() { mounted() {
this.loadOrganizationOptions(); this.loadOrganizationOptions();
this.loadTable(); this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
}, },
methods: { methods: {
hasPermission(code) { hasPermission(code) {
@@ -356,19 +337,6 @@ export default {
this.$message.error('正式结算单详情加载失败'); this.$message.error('正式结算单详情加载失败');
} }
}, },
async openFlow(row) {
this.flowDialog.row = { ...row };
this.flowDialog.records = [];
this.flowDialog.visible = true;
this.flowDialog.loading = true;
try {
const detail = this.unwrapData(await api.getDetail(row.id));
this.flowDialog.row = { ...row, ...detail };
this.flowDialog.records = detail.records || [];
} finally {
this.flowDialog.loading = false;
}
},
async handleDelete(row) { async handleDelete(row) {
await this.$confirm('确认删除该开票申请?', '提示', { type: 'warning' }); await this.$confirm('确认删除该开票申请?', '提示', { type: 'warning' });
await api.remove(row.id); await api.remove(row.id);
@@ -377,9 +345,33 @@ export default {
}, },
async handleSubmit(row) { async handleSubmit(row) {
await api.submit({ id: row.id }); await api.submit({ id: row.id });
await submitMkApprovalFlow({
bizType: 'invoice-application',
bizId: row.id,
subjectName: row.applicationNo || '',
approvalStatus: row.approvalStatus || '',
});
this.$message.success('提交成功'); this.$message.success('提交成功');
this.loadTable(); this.loadTable();
}, },
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('获取审核跳转地址失败');
});
},
async handleApprove(row) { async handleApprove(row) {
await this.$confirm('确认审批通过该开票申请?', '提示', { type: 'warning' }); await this.$confirm('确认审批通过该开票申请?', '提示', { type: 'warning' });
await api.approve({ id: row.id }); await api.approve({ id: row.id });
@@ -436,19 +428,6 @@ export default {
'' ''
); );
}, },
statusName(status) {
return (
{
draft: '草稿',
reviewing: '审批中',
approved: '审批通过',
returned: '已驳回',
voided: '已作废',
}[status] ||
status ||
'-'
);
},
displayValue(value) { displayValue(value) {
return value === null || value === undefined || value === '' ? '-' : value; return value === null || value === undefined || value === '' ? '-' : value;
}, },
+26 -3
View File
@@ -134,7 +134,7 @@
</el-form-item> </el-form-item>
</section-card> </section-card>
<div class="receipt-form-page__actions"> <div v-if="!isPublicViewPage" class="receipt-form-page__actions">
<el-button @click="goBack">取消</el-button> <el-button @click="goBack">取消</el-button>
<el-button v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button> <el-button v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button>
<el-button v-if="!readonly && canSave" type="primary" plain @click="saveDraft" <el-button v-if="!readonly && canSave" type="primary" plain @click="saveDraft"
@@ -261,6 +261,8 @@ import { mapGetters } from 'vuex';
import * as api from '@/api/payment/invoiceReceipt'; import * as api from '@/api/payment/invoiceReceipt';
import { getList as getCustomerList } from '@/api/vehicle/customer-archive'; import { getList as getCustomerList } from '@/api/vehicle/customer-archive';
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue'; import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { submitMkApprovalFlow } from '@/utils/mk-approval';
const mockInvoiceTypes = ['增值税专用发票', '增值税普通发票']; const mockInvoiceTypes = ['增值税专用发票', '增值税普通发票'];
const mockTaxRates = [3, 6, 9, 13]; const mockTaxRates = [3, 6, 9, 13];
@@ -401,7 +403,10 @@ export default {
return this.$route.query.id || ''; return this.$route.query.id || '';
}, },
readonly() { readonly() {
return this.$route.query.mode === 'view'; return this.$route.query.mode === 'view' || this.isPublicViewPage;
},
isPublicViewPage() {
return this.$route.path === '/payment/invoice-receipt/public-view';
}, },
canSave() { canSave() {
const code = this.recordId ? 'invoice_receipt_edit' : 'invoice_receipt_add'; const code = this.recordId ? 'invoice_receipt_edit' : 'invoice_receipt_add';
@@ -444,6 +449,10 @@ export default {
.filter(Boolean); .filter(Boolean);
}, },
async initialize() { async initialize() {
if (this.isPublicViewPage) {
await this.loadPublicDetail();
return;
}
const userInfo = this.$store.getters.userInfo || {}; const userInfo = this.$store.getters.userInfo || {};
const userEmail = userInfo.email || ''; const userEmail = userInfo.email || '';
this.departmentEmailOptions = userEmail ? [userEmail] : []; this.departmentEmailOptions = userEmail ? [userEmail] : [];
@@ -452,6 +461,15 @@ export default {
return; return;
} }
const data = this.unwrapData(await api.getDetail(this.recordId)); const data = this.unwrapData(await api.getDetail(this.recordId));
this.applyDetail(data);
if (this.settlementIds.length) await this.loadReferenceInformation();
},
async loadPublicDetail() {
if (!this.recordId) return;
const data = this.unwrapData(await getMkPublicDetail('invoice-receipt', this.recordId));
this.applyDetail(data);
},
applyDetail(data) {
this.form = { this.form = {
...emptyForm(), ...emptyForm(),
...data, ...data,
@@ -463,7 +481,6 @@ export default {
})), })),
attachments: this.parse(data.attachmentsJson), attachments: this.parse(data.attachmentsJson),
}; };
if (this.settlementIds.length) await this.loadReferenceInformation();
}, },
validateInvoice(rule, value, callback) { validateInvoice(rule, value, callback) {
if (!value || !this.form.kingdeeInvoicePoolId) { if (!value || !this.form.kingdeeInvoicePoolId) {
@@ -750,6 +767,12 @@ export default {
const saved = await this.saveDraft(); const saved = await this.saveDraft();
if (!saved) return; if (!saved) return;
await api.submit({ id: this.form.id }); await api.submit({ id: this.form.id });
await submitMkApprovalFlow({
bizType: 'invoice-receipt',
bizId: this.form.id,
subjectName: this.form.invoiceNo || '',
approvalStatus: this.form.approvalStatus || '',
});
this.$message.success('提交成功'); this.$message.success('提交成功');
this.goBack(); this.goBack();
}, },
@@ -0,0 +1,21 @@
<template>
<mk-public-shell biz-type="invoice-receipt" :get-form="getForm">
<invoice-receipt-form ref="page" />
</mk-public-shell>
</template>
<script>
import MkPublicShell from '@/views/mk/mk-public-shell.vue';
import InvoiceReceiptForm from '@/views/payment/invoice-receipt-form.vue';
export default {
name: 'InvoiceReceiptPublicView',
components: { MkPublicShell, InvoiceReceiptForm },
methods: {
getForm() {
const form = this.$refs.page?.form || {};
return { ...form, subject: form.invoiceNo || form.projectName || '' };
},
},
};
</script>
+46 -67
View File
@@ -146,14 +146,20 @@
>提交</el-link >提交</el-link
> >
<el-link <el-link
v-if="hasPermission('invoice_receipt_view') && row.approvalStatus !== 'draft'" v-if="
mkEnabled &&
hasPermission('invoice_receipt_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary" type="primary"
@click="openFlow(row)" @click="handleMkAudit(row)"
>流程</el-link >流程</el-link
> >
<el-link <el-link
v-if=" v-if="
hasPermission('invoice_receipt_approve') && row.approvalStatus === 'reviewing' !mkEnabled &&
hasPermission('invoice_receipt_approve') &&
row.approvalStatus === 'reviewing'
" "
type="primary" type="primary"
@click="handleApprove(row)" @click="handleApprove(row)"
@@ -161,7 +167,9 @@
> >
<el-link <el-link
v-if=" v-if="
hasPermission('invoice_receipt_approve') && row.approvalStatus === 'reviewing' !mkEnabled &&
hasPermission('invoice_receipt_approve') &&
row.approvalStatus === 'reviewing'
" "
type="danger" type="danger"
@click="handleReturn(row)" @click="handleReturn(row)"
@@ -190,42 +198,6 @@
/> />
</div> </div>
</section> </section>
<el-dialog v-model="flowDialog.visible" title="审批流程" width="900px" append-to-body>
<el-descriptions :column="2" border>
<el-descriptions-item label="发票号码">
{{ flowDialog.row.invoiceNo || '-' }}
</el-descriptions-item>
<el-descriptions-item label="审核状态">
{{ flowDialog.row.approvalStatusName || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前节点">
{{ flowDialog.row.currentNode || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前处理人">
{{ flowDialog.row.currentProcessor || '-' }}
</el-descriptions-item>
</el-descriptions>
<el-table
v-loading="flowDialog.loading"
:data="flowDialog.records"
border
class="receipt-page__flow-table"
>
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column prop="actionName" label="操作" min-width="110" align="center" />
<el-table-column label="原状态" min-width="100" align="center">
<template #default="{ row }">{{ statusName(row.fromStatus) }}</template>
</el-table-column>
<el-table-column label="新状态" min-width="100" align="center">
<template #default="{ row }">{{ statusName(row.toStatus) }}</template>
</el-table-column>
<el-table-column prop="operatorName" label="操作人" min-width="110" align="center" />
<el-table-column prop="createTime" label="操作时间" min-width="170" align="center" />
<el-table-column prop="reason" label="原因" min-width="160" show-overflow-tooltip />
<el-table-column prop="kingdeeBillNo" label="金蝶单据号" min-width="150" />
</el-table>
</el-dialog>
</basic-container> </basic-container>
</template> </template>
@@ -236,6 +208,8 @@ import * as XLSX from 'xlsx';
import * as api from '@/api/payment/invoiceReceipt'; import * as api from '@/api/payment/invoiceReceipt';
import { invoiceReceiptTableColumns } from '@/option/payment/invoiceReceipt'; import { invoiceReceiptTableColumns } from '@/option/payment/invoiceReceipt';
import organizationSearch from '@/mixins/organization-search'; import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
const emptyQuery = () => ({ const emptyQuery = () => ({
invoiceNo: '', invoiceNo: '',
@@ -264,7 +238,7 @@ export default {
selection: [], selection: [],
loading: false, loading: false,
page: { current: 1, size: 10, total: 0 }, page: { current: 1, size: 10, total: 0 },
flowDialog: { visible: false, loading: false, row: {}, records: [] }, mkEnabled: false,
}; };
}, },
computed: { computed: {
@@ -273,6 +247,13 @@ export default {
mounted() { mounted() {
this.loadOrganizationOptions(); this.loadOrganizationOptions();
this.loadTable(); this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
}, },
methods: { methods: {
hasPermission(code) { hasPermission(code) {
@@ -321,19 +302,6 @@ export default {
query: { mode: 'view', id: row.id }, query: { mode: 'view', id: row.id },
}); });
}, },
async openFlow(row) {
this.flowDialog.row = { ...row };
this.flowDialog.records = [];
this.flowDialog.visible = true;
this.flowDialog.loading = true;
try {
const detail = this.unwrapData(await api.getDetail(row.id));
this.flowDialog.row = { ...row, ...detail };
this.flowDialog.records = detail.records || [];
} finally {
this.flowDialog.loading = false;
}
},
async handleDelete(row) { async handleDelete(row) {
await this.$confirm('确认删除该收票登记?', '提示', { type: 'warning' }); await this.$confirm('确认删除该收票登记?', '提示', { type: 'warning' });
await api.remove(row.id); await api.remove(row.id);
@@ -342,9 +310,33 @@ export default {
}, },
async handleSubmit(row) { async handleSubmit(row) {
await api.submit({ id: row.id }); await api.submit({ id: row.id });
await submitMkApprovalFlow({
bizType: 'invoice-receipt',
bizId: row.id,
subjectName: row.invoiceNo || '',
approvalStatus: row.approvalStatus || '',
});
this.$message.success('提交成功'); this.$message.success('提交成功');
this.loadTable(); this.loadTable();
}, },
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('获取审核跳转地址失败');
});
},
async handleApprove(row) { async handleApprove(row) {
await this.$confirm('确认审批通过该收票登记?', '提示', { type: 'warning' }); await this.$confirm('确认审批通过该收票登记?', '提示', { type: 'warning' });
await api.approve({ id: row.id }); await api.approve({ id: row.id });
@@ -401,19 +393,6 @@ export default {
'' ''
); );
}, },
statusName(status) {
return (
{
draft: '草稿',
reviewing: '审批中',
approved: '审批通过',
returned: '已驳回',
voided: '已作废',
}[status] ||
status ||
'-'
);
},
displayValue(value) { displayValue(value) {
return value === null || value === undefined || value === '' ? '-' : value; return value === null || value === undefined || value === '' ? '-' : value;
}, },
@@ -2635,7 +2635,7 @@ export default {
await api.submit({ id: this.form.id }); await api.submit({ id: this.form.id });
await submitMkApprovalFlow({ await submitMkApprovalFlow({
bizType: 'payment-application', bizType: 'payment-application',
formInstanceId: this.form.id, bizId: this.form.id,
subjectName: this.form.paymentNo || '', subjectName: this.form.paymentNo || '',
approvalStatus: this.form.approvalStatus || '', approvalStatus: this.form.approvalStatus || '',
}); });
+49 -32
View File
@@ -151,14 +151,29 @@
>编辑</el-link >编辑</el-link
> >
<el-link <el-link
v-if="hasPermission('payment_application_submit') && row.approvalStatus === 'draft'" v-if="
hasPermission('payment_application_submit') &&
['draft', 'returned'].includes(row.approvalStatus)
"
type="primary" type="primary"
@click="handleSubmit(row)" @click="handleSubmit(row)"
>提交</el-link >提交</el-link
> >
<el-link <el-link
v-if=" v-if="
hasPermission('payment_application_approve') && row.approvalStatus === 'reviewing' mkEnabled &&
hasPermission('payment_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="handleMkAudit(row)"
>流程</el-link
>
<el-link
v-if="
!mkEnabled &&
hasPermission('payment_application_approve') &&
row.approvalStatus === 'reviewing'
" "
type="primary" type="primary"
@click="handleApprove(row)" @click="handleApprove(row)"
@@ -166,18 +181,14 @@
> >
<el-link <el-link
v-if=" v-if="
hasPermission('payment_application_approve') && row.approvalStatus === 'reviewing' !mkEnabled &&
hasPermission('payment_application_approve') &&
row.approvalStatus === 'reviewing'
" "
type="danger" type="danger"
@click="handleReturn(row)" @click="handleReturn(row)"
>驳回</el-link >驳回</el-link
> >
<el-link
v-if="hasPermission('payment_application_view') && row.approvalStatus !== 'draft'"
type="primary"
@click="openFlow(row)"
>流程</el-link
>
<el-link <el-link
v-if=" v-if="
hasPermission('payment_application_void') && row.approvalStatus === 'approved' hasPermission('payment_application_void') && row.approvalStatus === 'approved'
@@ -208,22 +219,6 @@
/> />
</div> </div>
</section> </section>
<el-dialog v-model="flowDialog.visible" title="审批流程" width="620px" append-to-body>
<el-descriptions :column="1" border>
<el-descriptions-item label="付款申请单号">
{{ flowDialog.row.paymentNo || '-' }}
</el-descriptions-item>
<el-descriptions-item label="审核状态">
{{ flowDialog.row.approvalStatusName || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前节点">
{{ flowDialog.row.currentNode || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前处理人">
{{ flowDialog.row.currentProcessor || '-' }}
</el-descriptions-item>
</el-descriptions>
</el-dialog>
</basic-container> </basic-container>
</template> </template>
@@ -233,7 +228,8 @@ import { mapGetters } from 'vuex';
import * as api from '@/api/payment/paymentApplication'; import * as api from '@/api/payment/paymentApplication';
import { paymentApplicationTableColumns } from '@/option/payment/paymentApplication'; import { paymentApplicationTableColumns } from '@/option/payment/paymentApplication';
import organizationSearch from '@/mixins/organization-search'; import organizationSearch from '@/mixins/organization-search';
import { submitMkApprovalFlow } from '@/utils/mk-approval'; import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
const emptyQuery = () => ({ const emptyQuery = () => ({
paymentNo: '', paymentNo: '',
@@ -265,7 +261,7 @@ export default {
selection: [], selection: [],
loading: false, loading: false,
page: { current: 1, size: 10, total: 0 }, page: { current: 1, size: 10, total: 0 },
flowDialog: { visible: false, row: {} }, mkEnabled: false,
}; };
}, },
computed: { computed: {
@@ -277,6 +273,13 @@ export default {
mounted() { mounted() {
this.loadOrganizationOptions(); this.loadOrganizationOptions();
this.loadTable(); this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
}, },
methods: { methods: {
hasPermission(code) { hasPermission(code) {
@@ -364,7 +367,7 @@ export default {
await api.submit({ id: row.id }); await api.submit({ id: row.id });
await submitMkApprovalFlow({ await submitMkApprovalFlow({
bizType: 'payment-application', bizType: 'payment-application',
formInstanceId: row.id, bizId: row.id,
subjectName: row.paymentNo || '', subjectName: row.paymentNo || '',
approvalStatus: row.approvalStatus || '', approvalStatus: row.approvalStatus || '',
}); });
@@ -376,16 +379,30 @@ export default {
this.$message.success('审批通过'); this.$message.success('审批通过');
this.loadTable(); this.loadTable();
}, },
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('获取审核跳转地址失败');
});
},
async handleReturn(row) { async handleReturn(row) {
const { value } = await this.$prompt('请输入驳回原因', '审批驳回'); const { value } = await this.$prompt('请输入驳回原因', '审批驳回');
await api.returnBill({ id: row.id, reason: value }); await api.returnBill({ id: row.id, reason: value });
this.$message.success('已驳回'); this.$message.success('已驳回');
this.loadTable(); this.loadTable();
}, },
openFlow(row) {
this.flowDialog.row = row;
this.flowDialog.visible = true;
},
async handleVoid(row) { async handleVoid(row) {
const { value } = await this.$prompt('请输入作废原因', '作废付款申请'); const { value } = await this.$prompt('请输入作废原因', '作废付款申请');
await api.voidBill({ id: row.id, reason: value }); await api.voidBill({ id: row.id, reason: value });
@@ -134,6 +134,7 @@ export default {
loading: { type: Boolean, default: false }, loading: { type: Boolean, default: false },
page: { type: Object, required: true }, page: { type: Object, required: true },
hasPermission: { type: Function, required: true }, hasPermission: { type: Function, required: true },
mkEnabled: { type: Boolean, default: false },
}, },
emits: [ emits: [
'create', 'create',
@@ -193,7 +194,10 @@ export default {
actions.push({ type: 'delete', label: '删除', danger: true }); actions.push({ type: 'delete', label: '删除', danger: true });
if (this.hasPermission('formal_settlement_submit') && this.isEditable(row)) if (this.hasPermission('formal_settlement_submit') && this.isEditable(row))
actions.push({ type: 'submit', label: '提交' }); actions.push({ type: 'submit', label: '提交' });
if (this.hasPermission('formal_settlement_approve') && row.approvalStatus === 'reviewing') { if (this.mkEnabled && this.hasPermission('formal_settlement_approve') && row.approvalStatus === 'reviewing') {
actions.push({ type: 'mkAudit', label: '流程' });
}
if (!this.mkEnabled && this.hasPermission('formal_settlement_approve') && row.approvalStatus === 'reviewing') {
actions.push({ type: 'approve', label: '通过' }); actions.push({ type: 'approve', label: '通过' });
actions.push({ type: 'return', label: '驳回', danger: true }); actions.push({ type: 'return', label: '驳回', danger: true });
} }
@@ -1604,7 +1604,7 @@ export default {
await submit({ id: this.form.id }); await submit({ id: this.form.id });
await submitMkApprovalFlow({ await submitMkApprovalFlow({
bizType: 'pre-settlement', bizType: 'pre-settlement',
formInstanceId: this.form.id, bizId: this.form.id,
subjectName: this.form.preSettlementNo || this.form.contractName || '', subjectName: this.form.preSettlementNo || this.form.contractName || '',
approvalStatus: this.form.approvalStatus || '', approvalStatus: this.form.approvalStatus || '',
}); });
+32 -2
View File
@@ -64,6 +64,7 @@
:loading="loading" :loading="loading"
:page="page" :page="page"
:has-permission="hasPermissionFn" :has-permission="hasPermissionFn"
:mk-enabled="mkEnabled"
@create="openCreate" @create="openCreate"
@payment="openPaymentDialog" @payment="openPaymentDialog"
@sync="handleSync" @sync="handleSync"
@@ -82,6 +83,7 @@
:loading="loading" :loading="loading"
:page="page" :page="page"
:has-permission="hasPermissionFn" :has-permission="hasPermissionFn"
:mk-enabled="mkEnabled"
@create="openCreate" @create="openCreate"
@payment="openPaymentDialog" @payment="openPaymentDialog"
@sync="handleSync" @sync="handleSync"
@@ -182,7 +184,8 @@ import organizationSearch from '@/mixins/organization-search';
import { formalSettlementTableColumns } from '@/option/settlement/formalSettlementTable'; import { formalSettlementTableColumns } from '@/option/settlement/formalSettlementTable';
import FormalSettlementEditor from './components/formal-settlement-editor.vue'; import FormalSettlementEditor from './components/formal-settlement-editor.vue';
import FormalSettlementTablePanel from './components/formal-settlement-table-panel.vue'; import FormalSettlementTablePanel from './components/formal-settlement-table-panel.vue';
import { submitMkApprovalFlow } from '@/utils/mk-approval'; import { submitMkApprovalFlow, loadMkEnabled } from '@/utils/mk-approval';
import { getMKApprovalUrl } from '@/api/system/business-process';
const emptyQuery = () => ({ const emptyQuery = () => ({
formalSettlementNo: '', formalSettlementNo: '',
@@ -224,6 +227,7 @@ export default {
rows: [], rows: [],
form: { appliedAmount: 0, remark: '' }, form: { appliedAmount: 0, remark: '' },
}, },
mkEnabled: false,
}; };
}, },
computed: { computed: {
@@ -247,6 +251,13 @@ export default {
this.loadOrganizationOptions(); this.loadOrganizationOptions();
this.loadTable(); this.loadTable();
this.openRouteDetail(); this.openRouteDetail();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
}, },
methods: { methods: {
hasPermission(code) { hasPermission(code) {
@@ -290,6 +301,7 @@ export default {
edit: () => this.openEdit(row), edit: () => this.openEdit(row),
delete: () => this.handleDelete(row), delete: () => this.handleDelete(row),
submit: () => this.handleSubmit(row), submit: () => this.handleSubmit(row),
mkAudit: () => this.handleMkAudit(row),
approve: () => this.handleApprove(row), approve: () => this.handleApprove(row),
return: () => this.handleReturn(row), return: () => this.handleReturn(row),
void: () => this.handleVoid(row), void: () => this.handleVoid(row),
@@ -340,13 +352,31 @@ export default {
await api.submit({ id: row.id }); await api.submit({ id: row.id });
await submitMkApprovalFlow({ await submitMkApprovalFlow({
bizType: 'formal-settlement', bizType: 'formal-settlement',
formInstanceId: row.id, bizId: row.id,
subjectName: row.formalSettlementNo || '', subjectName: row.formalSettlementNo || '',
approvalStatus: row.approvalStatus || '', approvalStatus: row.approvalStatus || '',
}); });
this.$message.success('提交成功'); this.$message.success('提交成功');
this.loadTable(); this.loadTable();
}, },
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('获取审核跳转地址失败');
});
},
async handleApprove(row) { async handleApprove(row) {
await this.$confirm( await this.$confirm(
'审核通过后正式结算生效,金额只能通过结算调整单处理,确认通过?', '审核通过后正式结算生效,金额只能通过结算调整单处理,确认通过?',
+65 -28
View File
@@ -172,21 +172,43 @@
删除 删除
</el-link> </el-link>
<el-link <el-link
v-if="hasPermission('pre_settlement_view') && row.approvalStatus !== 'draft'" v-if="
hasPermission('pre_settlement_submit') &&
['draft', 'returned'].includes(row.approvalStatus)
"
type="primary" type="primary"
@click="openFlow(row)" @click="handleSubmit(row)"
>
提交
</el-link>
<el-link
v-if="
mkEnabled &&
hasPermission('pre_settlement_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="handleMkAudit(row)"
> >
流程 流程
</el-link> </el-link>
<el-link <el-link
v-if="hasPermission('pre_settlement_approve') && row.approvalStatus === 'reviewing'" v-if="
!mkEnabled &&
hasPermission('pre_settlement_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary" type="primary"
@click="handleApprove(row)" @click="handleApprove(row)"
> >
通过 通过
</el-link> </el-link>
<el-link <el-link
v-if="hasPermission('pre_settlement_approve') && row.approvalStatus === 'reviewing'" v-if="
!mkEnabled &&
hasPermission('pre_settlement_approve') &&
row.approvalStatus === 'reviewing'
"
type="danger" type="danger"
@click="handleReturn(row)" @click="handleReturn(row)"
> >
@@ -259,23 +281,6 @@
</el-button> </el-button>
</template> </template>
</el-dialog> </el-dialog>
<el-dialog v-model="flowDialog.visible" title="审批流程" width="620px" append-to-body>
<el-descriptions :column="1" border>
<el-descriptions-item label="预结算单号">
{{ flowDialog.row.preSettlementNo || '-' }}
</el-descriptions-item>
<el-descriptions-item label="审核状态">
{{ flowDialog.row.approvalStatusName || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前节点">
{{ flowDialog.row.currentNode || '-' }}
</el-descriptions-item>
<el-descriptions-item label="当前处理人">
{{ flowDialog.row.currentProcessor || '-' }}
</el-descriptions-item>
</el-descriptions>
</el-dialog>
</basic-container> </basic-container>
</template> </template>
@@ -290,6 +295,7 @@ import {
getPrintTemplates, getPrintTemplates,
remove, remove,
returnBill, returnBill,
submit,
voidBill, voidBill,
} from '@/api/settlement/preSettlement'; } from '@/api/settlement/preSettlement';
import { preSettlementSearchFields } from '@/option/settlement/preSettlementSearch'; import { preSettlementSearchFields } from '@/option/settlement/preSettlementSearch';
@@ -297,6 +303,8 @@ import organizationSearch from '@/mixins/organization-search';
import { preSettlementTableColumns } from '@/option/settlement/preSettlementTable'; import { preSettlementTableColumns } from '@/option/settlement/preSettlementTable';
import { createSettlementTransfer } from '@/utils/settlement-transfer'; import { createSettlementTransfer } from '@/utils/settlement-transfer';
import { downloadFile } from '@/utils/util'; import { downloadFile } from '@/utils/util';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
import PreSettlementEditor from './components/pre-settlement-editor.vue'; import PreSettlementEditor from './components/pre-settlement-editor.vue';
const emptyQuery = () => ({ const emptyQuery = () => ({
@@ -345,10 +353,7 @@ export default {
templates: [], templates: [],
template: '', template: '',
}, },
flowDialog: { mkEnabled: false,
visible: false,
row: {},
},
}; };
}, },
computed: { computed: {
@@ -372,6 +377,13 @@ export default {
this.loadOrganizationOptions(); this.loadOrganizationOptions();
this.loadTable(); this.loadTable();
this.openRouteDetail(); this.openRouteDetail();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
}, },
methods: { methods: {
hasPermission(code) { hasPermission(code) {
@@ -628,9 +640,34 @@ export default {
const { data } = await exportList(params); const { data } = await exportList(params);
downloadFile(data, `预结算单${this.$dayjs().format('YYYY-MM-DD HH-mm-ss')}.xlsx`); downloadFile(data, `预结算单${this.$dayjs().format('YYYY-MM-DD HH-mm-ss')}.xlsx`);
}, },
openFlow(row) { async handleSubmit(row) {
this.flowDialog.row = row; await submit({ id: row.id });
this.flowDialog.visible = true; await submitMkApprovalFlow({
bizType: 'pre-settlement',
bizId: row.id,
subjectName: row.preSettlementNo || '',
approvalStatus: row.approvalStatus || '',
});
this.$message.success('提交成功');
this.loadTable();
},
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('获取审核跳转地址失败');
});
}, },
async handleApprove(row) { async handleApprove(row) {
await this.$confirm('确认审批通过该预结算单?', '提示', { type: 'warning' }); await this.$confirm('确认审批通过该预结算单?', '提示', { type: 'warning' });
+1 -1
View File
@@ -4288,7 +4288,7 @@ export default {
submitCustomerApproval(id, fullName = '', approvalStatus = '') { submitCustomerApproval(id, fullName = '', approvalStatus = '') {
return submitMkApprovalFlow({ return submitMkApprovalFlow({
bizType: 'customer-archive', bizType: 'customer-archive',
formInstanceId: id, bizId: id,
subjectName: fullName, subjectName: fullName,
approvalStatus, approvalStatus,
}).then(() => submitApproval(id)); }).then(() => submitApproval(id));