✨ 多业务接入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.submitIdentity 提交人(手机号)
* @param {string} data.loginName 登录账号(手机号)
* @param {string} data.formInstanceId 业务表单实例 id
* @param {string} data.bizId 业务主键(后端生成/复用 formInstanceId)
* @param {string} [data.subject] 流程标题
* @param {string} [data.bizType] 业务类型
*/
export const processSubmit = data => {
return request({
@@ -20,7 +21,7 @@ export const processSubmit = data => {
/**
* 调用 MK processDelete 删除审核流(驳回后重新提交前使用)
* @param {Object} data
* @param {string} data.formInstanceId 业务表单实例 id
* @param {string} data.bizId 业务主键
*/
export const processDelete = data => {
return request({
@@ -33,7 +34,7 @@ export const processDelete = data => {
/**
* 查询 MK 流程实例是否仍存在(有数据则无需删除/重新提交)
* @param {Object} params
* @param {string} params.bizId 业务 id(formInstanceId)
* @param {string} params.bizId 业务主键
*/
export const hasMkProcessInstance = params => {
return request({
+12 -2
View File
@@ -57,16 +57,24 @@ export const config = {
action: 'submitApproval',
label: '提交',
statusProp: 'approvalStatus',
status: ['draft'],
status: ['draft', 'rejected', 'withdrawn'],
permission: 'project_apply_submit',
},
{
action: 'withdraw',
label: '撤回',
statusProp: 'approvalStatus',
status: ['reviewing'],
status: ['draft', 'reviewing'],
permission: 'project_apply_withdraw',
},
{
action: 'mkAudit',
label: '流程',
statusProp: 'approvalStatus',
status: ['reviewing', 'change_reviewing'],
permission: 'project_apply_approve',
mkOnly: true,
},
{
action: 'approve',
label: '通过',
@@ -74,6 +82,7 @@ export const config = {
statusProp: 'approvalStatus',
status: ['reviewing', 'change_reviewing'],
permission: 'project_apply_approve',
localOnly: true,
},
{
action: 'reject',
@@ -82,6 +91,7 @@ export const config = {
statusProp: 'approvalStatus',
status: ['reviewing', 'change_reviewing'],
permission: 'project_apply_reject',
localOnly: true,
},
{
action: 'startChange',
+33 -11
View File
@@ -106,17 +106,6 @@ export default [
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',
name: '查看预结算信息',
@@ -150,6 +139,39 @@ export default [
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: '/',
name: '主页',
+32 -10
View File
@@ -18,11 +18,6 @@ export const MK_BIZ = {
subjectPrefix: '合同审批',
rejected: ['rejected', 'change_rejected', 'withdrawn'],
},
'waybill-manage': {
dictName: '提交运单审核流',
subjectPrefix: '运单审批',
rejected: ['rejected', 'returned'],
},
'pre-settlement': {
dictName: '提交预结算审核流',
subjectPrefix: '预结算审批',
@@ -38,6 +33,21 @@ export const MK_BIZ = {
subjectPrefix: '付款审批',
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';
@@ -70,9 +80,17 @@ export async function resolveMkTemplateCode(dictName, list) {
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({
bizType,
formInstanceId,
bizId,
subjectName = '',
approvalStatus = '',
}) {
@@ -80,25 +98,29 @@ export async function submitMkApprovalFlow({
if (!conf) {
return Promise.reject(new Error(`不支持的MK业务类型:${bizType}`));
}
if (bizId == null || bizId === '') {
return Promise.reject(new Error('业务id不能为空'));
}
const list = await loadMkTemplateList();
if (!isMkEnabled(list)) {
return;
}
const bizIdText = String(bizId);
// 先查 MK 流程实例:已有数据则不删除、不重新提交
const existsRes = await hasMkProcessInstance({ bizId: String(formInstanceId) });
const existsRes = await hasMkProcessInstance({ bizId: bizIdText });
if (existsRes?.data?.data) {
return;
}
if ((conf.rejected || []).includes(approvalStatus)) {
await processDelete({ formInstanceId: String(formInstanceId) });
await processDelete({ bizId: bizIdText });
}
const templateCode = await resolveMkTemplateCode(conf.dictName, list);
const subject = subjectName
? `${conf.subjectPrefix}:${subjectName}`
: `${conf.subjectPrefix}:${formInstanceId}`;
: `${conf.subjectPrefix}:${bizIdText}`;
return processSubmit({
templateCode,
formInstanceId: String(formInstanceId),
bizId: bizIdText,
subject,
bizType,
});
+41 -11
View File
@@ -275,7 +275,12 @@ export default {
return (data && data.records) || [];
},
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() {
const deptId = this.defaultDeptId();
@@ -296,6 +301,18 @@ export default {
if (deptColumn) {
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() {
@@ -323,9 +340,13 @@ export default {
flattenDept(tree, level = 0) {
const result = [];
tree.forEach(item => {
// 雪花 ID 必须保持字符串,避免 JS Number 精度丢失导致筛错组织。
const id =
item.id === undefined || item.id === null || item.id === '' ? '' : String(item.id);
if (!id) return;
result.push({
label: `${' '.repeat(level)}${item.title || item.deptName || item.name}`,
value: item.id,
value: id,
});
if (item.children && item.children.length) {
result.push(...this.flattenDept(item.children, level + 1));
@@ -333,6 +354,18 @@ export default {
});
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 = []) {
return list
.map(item => ({
@@ -640,9 +673,9 @@ export default {
this.onLoad(this.page, this.query);
},
searchChange(params, done) {
this.query = params;
this.query = this.normalizeListQuery(params);
this.page.currentPage = 1;
this.onLoad(this.page, params);
this.onLoad(this.page, this.query);
done();
},
selectionChange(list) {
@@ -665,12 +698,10 @@ export default {
},
onLoad(page, params = {}) {
this.loading = true;
const query = this.normalizeListQuery(params);
this.query = query;
api
.getList(page.currentPage, page.pageSize, {
...params,
...this.query,
allDept: this.isAdmin ? 1 : 0,
})
.getList(page.currentPage, page.pageSize, query)
.then(res => {
const result = res.data.data;
this.page.total = result.total;
@@ -683,8 +714,7 @@ export default {
},
buildExportParams() {
return {
...this.query,
allDept: this.isAdmin ? 1 : 0,
...this.normalizeListQuery(this.query),
ids: this.ids,
[this.website.tokenHeader]: getToken(),
};
@@ -2348,7 +2348,7 @@
</div>
</template>
</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>
</div>
<template v-if="!detailPageLocked" #footer>
@@ -3088,7 +3088,6 @@ import {
} from '@/api/business/process-config';
import { getPunchRecords as getWaybillPunchRecords, locateVehicle, trackVehicle } from '@/api/business/waybill-manage';
import VoucherExecutionDetail from './voucher-execution-detail.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { getList as getDriverList } from '@/api/transportCapacity/driver';
import {
fetchDriversByCarrierOrganizations,
@@ -3098,7 +3097,6 @@ import { getDictionary as getSystemDictionary } from '@/api/system/dict';
import { addressTypeOptions } from '@/option/base/common-address';
import { packageOptions } from '@/option/business/common';
import { formatUpdateUserName } from '@/utils/audit';
import { submitMkApprovalFlow } from '@/utils/mk-approval';
import { getToken } from '@/utils/auth';
import { openImportDialog } from '@/utils/import-excel';
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
@@ -3607,7 +3605,6 @@ export default {
this.formPageLocked = this.isStandaloneWaybillFormPage;
this.detailPageLocked = this.isStandaloneWaybillDetailPage;
this.formModeLocked = this.$route.query.mode || '';
if (this.isPublicWaybillView) return;
this.setupSearchAutocompletes();
if (this.config.enableAllDept && this.isAdmin) {
this.allDept = 1;
@@ -3680,14 +3677,8 @@ export default {
isStandaloneWaybillFormPage() {
return this.isStandaloneWaybillPage && ['add', 'edit'].includes(this.$route.query.mode);
},
isPublicWaybillView() {
return this.$route.path === '/business/waybill-manage/public-view';
},
isStandaloneWaybillDetailPage() {
return (
(this.standaloneDetailPage && this.$route.path === standaloneWaybillDetailRoute) ||
this.isPublicWaybillView
);
return this.standaloneDetailPage && this.$route.path === standaloneWaybillDetailRoute;
},
// 容器形态读实例创建时锁定的标志,不随 $route 翻转(详见 data 中 formPageLocked 的说明)
// 当前路由是否仍属于本实例(tab.js 按 fullPath 建实例,一个实例只对应一个 path)。
@@ -4640,19 +4631,14 @@ export default {
this.waybillVoucherFolder = null;
this.waybillVoucherFolderView = false;
this.waybillVoucherImagesLoaded = false;
const request = this.isPublicWaybillView
? getMkPublicDetail('waybill-manage', row.id)
: typeof this.api.getDetail === 'function'
const request =
typeof this.api.getDetail === 'function'
? this.api.getDetail(row.id)
: Promise.resolve({ data: { data: row } });
request
.then(res => {
const detail = res?.data?.data || res?.data || row;
this.detailRow = detail;
if (this.isPublicWaybillView) {
this.applyFormDetail(detail);
return;
}
this.loadWaybillPunchRecords();
this.loadWaybillVoucherImages();
if (detail.contractId) {
@@ -4728,7 +4714,6 @@ export default {
return row.id || row.customerId || '';
},
canOpenWaybillDetailSummaryLink(prop) {
if (this.isPublicWaybillView) return false;
const row = this.detailRow || {};
const value = this.formatDetailValue(row, prop);
if (!value || value === '-') return false;
@@ -5655,23 +5640,11 @@ export default {
}
this.getSaveRequest()(submitRow).then(
res => {
const data = res.data?.data || {};
const id = data.id || submitRow.id;
const after = id
? submitMkApprovalFlow({
bizType: 'waybill-manage',
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();
});
this.markWaybillListNeedRefresh();
this.onLoad(this.page);
this.$message({ type: 'success', message: '提交成功!' });
done();
if (this.isStandaloneWaybillPage) this.closeCrudDialog();
},
error => {
window.console.log(error);
@@ -5690,27 +5663,14 @@ export default {
? this.api.updateAttachments
: this.getSaveRequest();
request(submitRow).then(
res => {
() => {
const skipMk = this.attachmentUploadMode;
const data = res.data?.data || {};
const id = data.id || submitRow.id;
const after =
skipMk || !id
? Promise.resolve()
: submitMkApprovalFlow({
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();
});
this.attachmentUploadMode = false;
this.markWaybillListNeedRefresh();
this.onLoad(this.page);
this.$message({ type: 'success', message: skipMk ? '操作成功!' : '提交成功!' });
done();
if (this.isStandaloneWaybillPage) this.closeCrudDialog();
},
error => {
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); },
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; },
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>
+3 -3
View File
@@ -1890,7 +1890,7 @@ export default {
).then(() =>
submitMkApprovalFlow({
bizType: 'contract-manage',
formInstanceId: id,
bizId: id,
subjectName: saved.contractName || submit.contractName || '',
approvalStatus: saved.approvalStatus || submit.approvalStatus || '',
})
@@ -1928,7 +1928,7 @@ export default {
}
return submitMkApprovalFlow({
bizType: 'contract-manage',
formInstanceId: payload.id || this.form.id,
bizId: payload.id || this.form.id,
subjectName: payload.contractName || this.form.contractName || '',
approvalStatus: this.form.approvalStatus || 'change_rejected',
}).then(() => {
@@ -2875,7 +2875,7 @@ export default {
? request().then(() =>
submitMkApprovalFlow({
bizType: 'contract-manage',
formInstanceId: row.id,
bizId: row.id,
subjectName: row.contractName || '',
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 { getToken } from '@/utils/auth';
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 { OpenFileViewer } from '@open-file-viewer/vue';
import PdfPreview from '@/components/pdf-preview/main.vue';
@@ -1117,6 +1118,7 @@ export default {
// 否则 isProjectFormPage 变 false 后容器会从 div 切成 el-dialog(append-to-body),
// 盖住后续打开的页面(如客商档案)。
isFormPageInstance: false,
mkEnabled: false,
projectBox: false,
dialogType: 'add',
dialogReadonly: false,
@@ -1367,6 +1369,13 @@ export default {
this.openPublicProjectForm();
return;
}
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
this.loadDeptOptions();
this.loadCargoTypeOptions();
this.loadTransportTypeOptions();
@@ -1563,7 +1572,11 @@ export default {
);
},
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) {
const permission = operation.permission || `${this.config.permission}_${operation.action}`;
@@ -1689,6 +1702,10 @@ export default {
this.openProjectDialog('change', row);
return;
}
if (operation.action === 'mkAudit') {
this.handleMkAudit(row);
return;
}
const run = value => {
const args = operation.prompt ? [row.id, value] : [row.id];
const request = () => this.api[operation.action](...args);
@@ -1696,7 +1713,7 @@ export default {
operation.action === 'submitApproval'
? submitMkApprovalFlow({
bizType: 'project-apply',
formInstanceId: row.id,
bizId: row.id,
subjectName: row.projectName || '',
approvalStatus: row.approvalStatus || '',
}).then(() => request())
@@ -1725,6 +1742,24 @@ export default {
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('获取审核跳转地址失败');
});
},
buildExportParams() {
return {
...this.query,
@@ -1881,7 +1916,7 @@ export default {
}
return submitMkApprovalFlow({
bizType: 'project-apply',
formInstanceId: id,
bizId: id,
subjectName: name,
approvalStatus: status,
}).then(() => {
@@ -1952,7 +1987,7 @@ export default {
const id = this.form.id;
return submitMkApprovalFlow({
bizType: 'project-apply',
formInstanceId: id,
bizId: id,
subjectName: this.form.projectName || '',
approvalStatus: this.form.approvalStatus || 'change_rejected',
}).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: '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': [
{ label: '预结算单号', prop: 'preSettlementNo' },
{ label: '合同名称', prop: 'contractName' },
@@ -88,7 +77,6 @@ const FIELD_MAP = {
const TITLE_MAP = {
'project-apply': '查看项目信息',
'contract-manage': '查看合同信息',
'waybill-manage': '查看运单信息',
'pre-settlement': '查看预结算信息',
'formal-settlement': '查看正式结算信息',
'payment-application': '查看付款申请信息',
+26 -2
View File
@@ -78,7 +78,7 @@
<vehicle-attachment-table v-model="form.attachments" :readonly="readonly" :max-size="10" />
</section-card>
<div class="bill-payment-form-page__actions">
<div v-if="!isPublicViewPage" class="bill-payment-form-page__actions">
<template v-if="!readonly">
<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 billLedgerApi from '@/api/payment/billLedger';
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { submitMkApprovalFlow } from '@/utils/mk-approval';
const emptyForm = () => ({
id: null,
@@ -194,7 +196,10 @@ export default {
return this.$route.query.id || '';
},
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() {
@@ -215,6 +220,10 @@ export default {
}
},
async initialize() {
if (this.isPublicViewPage) {
await this.loadPublicDetail();
return;
}
if (this.recordId) {
const data = this.unwrapData(await api.getDetail(this.recordId));
this.form = {
@@ -228,6 +237,15 @@ export default {
this.form.deptName = this.userInfo?.deptName || this.userInfo?.dept_name || '';
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) {
const amount = Number(value);
const balance = Number(this.form.availableBalance || 0);
@@ -324,6 +342,12 @@ export default {
const id = this.unwrapData(await api.save(this.payload()));
this.form.id = 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.goBack();
} 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"
:loading="loading"
:page="page"
:mk-enabled="mkEnabled"
@add="openCreate"
@view="openView"
@edit="openEdit"
@delete="handleDelete"
@flow="openFlow"
@submit="handleSubmit"
@mk-audit="handleMkAudit"
@approve="handleApprove"
@return="handleReturn"
@void="handleVoid"
@page-change="handlePageChange"
@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>
</template>
<script>
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 BillPaymentTable from './components/bill-payment-table.vue';
@@ -62,11 +50,18 @@ export default {
rows: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
flowDialog: { visible: false, row: {} },
mkEnabled: false,
};
},
mounted() {
this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
},
methods: {
unwrapData(response) {
@@ -125,9 +120,34 @@ export default {
if (this.rows.length === 1 && this.page.current > 1) this.page.current -= 1;
this.loadTable();
},
openFlow(row) {
this.flowDialog.row = row;
this.flowDialog.visible = true;
async handleSubmit(row) {
await api.submit({ id: row.id });
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) {
await api.approve({ id: row.id });
@@ -50,19 +50,40 @@
>编辑</el-link
>
<el-link
v-if="row.approvalStatus !== 'draft'"
v-if="
['draft', 'returned'].includes(row.approvalStatus) &&
hasPermission('bill_payment_submit')
"
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
v-if="row.approvalStatus === 'reviewing' && hasPermission('bill_payment_approve')"
v-if="
!mkEnabled &&
row.approvalStatus === 'reviewing' &&
hasPermission('bill_payment_approve')
"
type="primary"
@click="$emit('approve', row)"
>通过</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"
@click="$emit('return', row)"
>驳回</el-link
@@ -101,13 +122,15 @@ export default {
rows: { type: Array, default: () => [] },
loading: { type: Boolean, default: false },
page: { type: Object, required: true },
mkEnabled: { type: Boolean, default: false },
},
emits: [
'add',
'view',
'edit',
'delete',
'flow',
'submit',
'mk-audit',
'approve',
'return',
'void',
+32 -8
View File
@@ -405,7 +405,7 @@
</el-form-item>
</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 v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button>
<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 { invoiceApplicationDetailColumns } from '@/option/payment/invoiceApplication';
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { submitMkApprovalFlow } from '@/utils/mk-approval';
let localId = 0;
const emptyLine = () => ({
@@ -583,7 +585,10 @@ export default {
return this.$route.query.id || '';
},
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() {
const code = this.recordId ? 'invoice_application_edit' : 'invoice_application_add';
@@ -655,6 +660,10 @@ export default {
.filter(Boolean);
},
async initialize() {
if (this.isPublicViewPage) {
await this.loadPublicDetail();
return;
}
await Promise.all([this.loadInvoiceItems(), this.loadTransportTypeOptions()]);
const userInfo = this.$store.getters.userInfo || {};
if (!this.recordId) {
@@ -662,6 +671,21 @@ export default {
return;
}
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 = {
...emptyForm(),
...data,
@@ -682,12 +706,6 @@ export default {
sheet.lines.forEach(line => this.syncInvoiceItemLine(line, false))
);
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() {
const data = this.unwrapData(await getInvoiceItems());
@@ -1177,6 +1195,12 @@ export default {
const saved = await this.saveDraft();
if (!saved) return;
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.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
v-if="hasPermission('invoice_application_view') && row.approvalStatus !== 'draft'"
v-if="
mkEnabled &&
hasPermission('invoice_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="openFlow(row)"
@click="handleMkAudit(row)"
>流程</el-link
>
<el-link
v-if="
hasPermission('invoice_application_approve') && row.approvalStatus === 'reviewing'
!mkEnabled &&
hasPermission('invoice_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="handleApprove(row)"
@@ -166,7 +172,9 @@
>
<el-link
v-if="
hasPermission('invoice_application_approve') && row.approvalStatus === 'reviewing'
!mkEnabled &&
hasPermission('invoice_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="danger"
@click="handleReturn(row)"
@@ -197,42 +205,6 @@
/>
</div>
</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>
</template>
@@ -244,6 +216,8 @@ import * as api from '@/api/payment/invoiceApplication';
import * as formalSettlementApi from '@/api/settlement/formalSettlement';
import { invoiceApplicationTableColumns } from '@/option/payment/invoiceApplication';
import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
const emptyQuery = () => ({
applicationNo: '',
@@ -271,7 +245,7 @@ export default {
selection: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
flowDialog: { visible: false, loading: false, row: {}, records: [] },
mkEnabled: false,
};
},
computed: {
@@ -280,6 +254,13 @@ export default {
mounted() {
this.loadOrganizationOptions();
this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
},
methods: {
hasPermission(code) {
@@ -356,19 +337,6 @@ export default {
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) {
await this.$confirm('确认删除该开票申请?', '提示', { type: 'warning' });
await api.remove(row.id);
@@ -377,9 +345,33 @@ export default {
},
async handleSubmit(row) {
await api.submit({ id: row.id });
await submitMkApprovalFlow({
bizType: 'invoice-application',
bizId: row.id,
subjectName: row.applicationNo || '',
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) {
await this.$confirm('确认审批通过该开票申请?', '提示', { type: 'warning' });
await api.approve({ id: row.id });
@@ -436,19 +428,6 @@ export default {
''
);
},
statusName(status) {
return (
{
draft: '草稿',
reviewing: '审批中',
approved: '审批通过',
returned: '已驳回',
voided: '已作废',
}[status] ||
status ||
'-'
);
},
displayValue(value) {
return value === null || value === undefined || value === '' ? '-' : value;
},
+26 -3
View File
@@ -134,7 +134,7 @@
</el-form-item>
</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 v-if="!readonly" type="primary" plain @click="syncReferenceData">同步</el-button>
<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 { getList as getCustomerList } from '@/api/vehicle/customer-archive';
import VehicleAttachmentTable from '@/components/vehicle-attachment-table/main.vue';
import { getMkPublicDetail } from '@/api/mk-process';
import { submitMkApprovalFlow } from '@/utils/mk-approval';
const mockInvoiceTypes = ['增值税专用发票', '增值税普通发票'];
const mockTaxRates = [3, 6, 9, 13];
@@ -401,7 +403,10 @@ export default {
return this.$route.query.id || '';
},
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() {
const code = this.recordId ? 'invoice_receipt_edit' : 'invoice_receipt_add';
@@ -444,6 +449,10 @@ export default {
.filter(Boolean);
},
async initialize() {
if (this.isPublicViewPage) {
await this.loadPublicDetail();
return;
}
const userInfo = this.$store.getters.userInfo || {};
const userEmail = userInfo.email || '';
this.departmentEmailOptions = userEmail ? [userEmail] : [];
@@ -452,6 +461,15 @@ export default {
return;
}
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 = {
...emptyForm(),
...data,
@@ -463,7 +481,6 @@ export default {
})),
attachments: this.parse(data.attachmentsJson),
};
if (this.settlementIds.length) await this.loadReferenceInformation();
},
validateInvoice(rule, value, callback) {
if (!value || !this.form.kingdeeInvoicePoolId) {
@@ -750,6 +767,12 @@ export default {
const saved = await this.saveDraft();
if (!saved) return;
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.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
v-if="hasPermission('invoice_receipt_view') && row.approvalStatus !== 'draft'"
v-if="
mkEnabled &&
hasPermission('invoice_receipt_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="openFlow(row)"
@click="handleMkAudit(row)"
>流程</el-link
>
<el-link
v-if="
hasPermission('invoice_receipt_approve') && row.approvalStatus === 'reviewing'
!mkEnabled &&
hasPermission('invoice_receipt_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="handleApprove(row)"
@@ -161,7 +167,9 @@
>
<el-link
v-if="
hasPermission('invoice_receipt_approve') && row.approvalStatus === 'reviewing'
!mkEnabled &&
hasPermission('invoice_receipt_approve') &&
row.approvalStatus === 'reviewing'
"
type="danger"
@click="handleReturn(row)"
@@ -190,42 +198,6 @@
/>
</div>
</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>
</template>
@@ -236,6 +208,8 @@ import * as XLSX from 'xlsx';
import * as api from '@/api/payment/invoiceReceipt';
import { invoiceReceiptTableColumns } from '@/option/payment/invoiceReceipt';
import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
const emptyQuery = () => ({
invoiceNo: '',
@@ -264,7 +238,7 @@ export default {
selection: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
flowDialog: { visible: false, loading: false, row: {}, records: [] },
mkEnabled: false,
};
},
computed: {
@@ -273,6 +247,13 @@ export default {
mounted() {
this.loadOrganizationOptions();
this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
},
methods: {
hasPermission(code) {
@@ -321,19 +302,6 @@ export default {
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) {
await this.$confirm('确认删除该收票登记?', '提示', { type: 'warning' });
await api.remove(row.id);
@@ -342,9 +310,33 @@ export default {
},
async handleSubmit(row) {
await api.submit({ id: row.id });
await submitMkApprovalFlow({
bizType: 'invoice-receipt',
bizId: row.id,
subjectName: row.invoiceNo || '',
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) {
await this.$confirm('确认审批通过该收票登记?', '提示', { type: 'warning' });
await api.approve({ id: row.id });
@@ -401,19 +393,6 @@ export default {
''
);
},
statusName(status) {
return (
{
draft: '草稿',
reviewing: '审批中',
approved: '审批通过',
returned: '已驳回',
voided: '已作废',
}[status] ||
status ||
'-'
);
},
displayValue(value) {
return value === null || value === undefined || value === '' ? '-' : value;
},
@@ -2635,7 +2635,7 @@ export default {
await api.submit({ id: this.form.id });
await submitMkApprovalFlow({
bizType: 'payment-application',
formInstanceId: this.form.id,
bizId: this.form.id,
subjectName: this.form.paymentNo || '',
approvalStatus: this.form.approvalStatus || '',
});
+49 -32
View File
@@ -151,14 +151,29 @@
>编辑</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"
@click="handleSubmit(row)"
>提交</el-link
>
<el-link
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"
@click="handleApprove(row)"
@@ -166,18 +181,14 @@
>
<el-link
v-if="
hasPermission('payment_application_approve') && row.approvalStatus === 'reviewing'
!mkEnabled &&
hasPermission('payment_application_approve') &&
row.approvalStatus === 'reviewing'
"
type="danger"
@click="handleReturn(row)"
>驳回</el-link
>
<el-link
v-if="hasPermission('payment_application_view') && row.approvalStatus !== 'draft'"
type="primary"
@click="openFlow(row)"
>流程</el-link
>
<el-link
v-if="
hasPermission('payment_application_void') && row.approvalStatus === 'approved'
@@ -208,22 +219,6 @@
/>
</div>
</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>
</template>
@@ -233,7 +228,8 @@ import { mapGetters } from 'vuex';
import * as api from '@/api/payment/paymentApplication';
import { paymentApplicationTableColumns } from '@/option/payment/paymentApplication';
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 = () => ({
paymentNo: '',
@@ -265,7 +261,7 @@ export default {
selection: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
flowDialog: { visible: false, row: {} },
mkEnabled: false,
};
},
computed: {
@@ -277,6 +273,13 @@ export default {
mounted() {
this.loadOrganizationOptions();
this.loadTable();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
},
methods: {
hasPermission(code) {
@@ -364,7 +367,7 @@ export default {
await api.submit({ id: row.id });
await submitMkApprovalFlow({
bizType: 'payment-application',
formInstanceId: row.id,
bizId: row.id,
subjectName: row.paymentNo || '',
approvalStatus: row.approvalStatus || '',
});
@@ -376,16 +379,30 @@ export default {
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 handleReturn(row) {
const { value } = await this.$prompt('请输入驳回原因', '审批驳回');
await api.returnBill({ id: row.id, reason: value });
this.$message.success('已驳回');
this.loadTable();
},
openFlow(row) {
this.flowDialog.row = row;
this.flowDialog.visible = true;
},
async handleVoid(row) {
const { value } = await this.$prompt('请输入作废原因', '作废付款申请');
await api.voidBill({ id: row.id, reason: value });
@@ -134,6 +134,7 @@ export default {
loading: { type: Boolean, default: false },
page: { type: Object, required: true },
hasPermission: { type: Function, required: true },
mkEnabled: { type: Boolean, default: false },
},
emits: [
'create',
@@ -193,7 +194,10 @@ export default {
actions.push({ type: 'delete', label: '删除', danger: true });
if (this.hasPermission('formal_settlement_submit') && this.isEditable(row))
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: 'return', label: '驳回', danger: true });
}
@@ -1604,7 +1604,7 @@ export default {
await submit({ id: this.form.id });
await submitMkApprovalFlow({
bizType: 'pre-settlement',
formInstanceId: this.form.id,
bizId: this.form.id,
subjectName: this.form.preSettlementNo || this.form.contractName || '',
approvalStatus: this.form.approvalStatus || '',
});
+32 -2
View File
@@ -64,6 +64,7 @@
:loading="loading"
:page="page"
:has-permission="hasPermissionFn"
:mk-enabled="mkEnabled"
@create="openCreate"
@payment="openPaymentDialog"
@sync="handleSync"
@@ -82,6 +83,7 @@
:loading="loading"
:page="page"
:has-permission="hasPermissionFn"
:mk-enabled="mkEnabled"
@create="openCreate"
@payment="openPaymentDialog"
@sync="handleSync"
@@ -182,7 +184,8 @@ import organizationSearch from '@/mixins/organization-search';
import { formalSettlementTableColumns } from '@/option/settlement/formalSettlementTable';
import FormalSettlementEditor from './components/formal-settlement-editor.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 = () => ({
formalSettlementNo: '',
@@ -224,6 +227,7 @@ export default {
rows: [],
form: { appliedAmount: 0, remark: '' },
},
mkEnabled: false,
};
},
computed: {
@@ -247,6 +251,13 @@ export default {
this.loadOrganizationOptions();
this.loadTable();
this.openRouteDetail();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
},
methods: {
hasPermission(code) {
@@ -290,6 +301,7 @@ export default {
edit: () => this.openEdit(row),
delete: () => this.handleDelete(row),
submit: () => this.handleSubmit(row),
mkAudit: () => this.handleMkAudit(row),
approve: () => this.handleApprove(row),
return: () => this.handleReturn(row),
void: () => this.handleVoid(row),
@@ -340,13 +352,31 @@ export default {
await api.submit({ id: row.id });
await submitMkApprovalFlow({
bizType: 'formal-settlement',
formInstanceId: row.id,
bizId: row.id,
subjectName: row.formalSettlementNo || '',
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) {
await this.$confirm(
'审核通过后正式结算生效,金额只能通过结算调整单处理,确认通过?',
+65 -28
View File
@@ -172,21 +172,43 @@
删除
</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"
@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
v-if="hasPermission('pre_settlement_approve') && row.approvalStatus === 'reviewing'"
v-if="
!mkEnabled &&
hasPermission('pre_settlement_approve') &&
row.approvalStatus === 'reviewing'
"
type="primary"
@click="handleApprove(row)"
>
通过
</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"
@click="handleReturn(row)"
>
@@ -259,23 +281,6 @@
</el-button>
</template>
</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>
</template>
@@ -290,6 +295,7 @@ import {
getPrintTemplates,
remove,
returnBill,
submit,
voidBill,
} from '@/api/settlement/preSettlement';
import { preSettlementSearchFields } from '@/option/settlement/preSettlementSearch';
@@ -297,6 +303,8 @@ import organizationSearch from '@/mixins/organization-search';
import { preSettlementTableColumns } from '@/option/settlement/preSettlementTable';
import { createSettlementTransfer } from '@/utils/settlement-transfer';
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';
const emptyQuery = () => ({
@@ -345,10 +353,7 @@ export default {
templates: [],
template: '',
},
flowDialog: {
visible: false,
row: {},
},
mkEnabled: false,
};
},
computed: {
@@ -372,6 +377,13 @@ export default {
this.loadOrganizationOptions();
this.loadTable();
this.openRouteDetail();
loadMkEnabled()
.then(enabled => {
this.mkEnabled = !!enabled;
})
.catch(() => {
this.mkEnabled = false;
});
},
methods: {
hasPermission(code) {
@@ -628,9 +640,34 @@ export default {
const { data } = await exportList(params);
downloadFile(data, `预结算单${this.$dayjs().format('YYYY-MM-DD HH-mm-ss')}.xlsx`);
},
openFlow(row) {
this.flowDialog.row = row;
this.flowDialog.visible = true;
async handleSubmit(row) {
await submit({ id: row.id });
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) {
await this.$confirm('确认审批通过该预结算单?', '提示', { type: 'warning' });
+1 -1
View File
@@ -4288,7 +4288,7 @@ export default {
submitCustomerApproval(id, fullName = '', approvalStatus = '') {
return submitMkApprovalFlow({
bizType: 'customer-archive',
formInstanceId: id,
bizId: id,
subjectName: fullName,
approvalStatus,
}).then(() => submitApproval(id));