Compare commits

...

17 Commits

Author SHA1 Message Date
刘泉佳 78bb38e955 🐛 收款流水认领额度改用收款金额并新增剩余可认领金额列
认领只登记本地,额度由本地累计认领控制,金蝶未匹配金额不再作为上限;批量认领校验复用剩余可认领金额口径。
2026-10-29 20:07:53 +08:00
刘泉佳 2cf966d6e3 feat: 开票申请查看展示每张发票金蝶开票状态与结果备注 2026-10-29 18:17:42 +08:00
刘泉佳 d23a9b00de refactor: 收款流水未匹配金额字段名统一为unmatchAmountRec 2026-10-29 16:13:23 +08:00
刘泉佳 d89fd9db97 feat: 收款流水列表展示匹配与结算金额字段 2026-10-29 16:06:03 +08:00
刘泉佳 94ee14b683 feat: 收款流水列表展示收款人公司与核算组织编码 2026-10-29 15:05:28 +08:00
刘泉佳 a725d3078f fix: 收款流水详情收款金额显示名称修正 2026-10-29 14:12:55 +08:00
刘泉佳 1957a78c00 fix: 收款流水同步接口超时时间延长到30秒 2026-10-29 12:55:03 +08:00
刘泉佳 acfe9bdd74 feat: 收款流水页面适配A301-1数据源并下线推送金蝶相关交互 2026-10-29 11:20:18 +08:00
刘泉佳 698f808f0b fix: 结算行付款金额联动回填申请付款金额并校验合计一致
结算信息行改动付款比例或付款金额时,自动把行金额合计回填到上方申请付款金额并重算比例;
保存/提交前校验行金额合计与申请付款金额一致,避免推送金蝶金额与预付建档分摊不一致。
回显加载走默认不同步,避免改写历史单据。
2026-10-29 02:19:23 +08:00
刘泉佳 ea6ec13ea4 fix: 付款申请拦截已调整结算单并过滤候选列表 2026-10-29 02:15:57 +08:00
刘泉佳 6119c44394 fix: 金蝶单据状态标签移除 status-text 类恢复颜色展示 2026-10-28 19:04:09 +08:00
刘泉佳 9dab7f7495 fix: 结算列表插槽列被兜底 formatter 覆盖导致状态无颜色与悬浮 2026-10-28 17:27:10 +08:00
刘泉佳 f5697e111a feat: 结算单与客商档案金蝶状态着色并悬浮展示失败原因 2026-10-28 17:00:34 +08:00
刘泉佳 775307f5c0 feat: 付款与开票申请金蝶单据状态着色并悬浮展示失败原因 2026-10-28 17:00:34 +08:00
刘泉佳 4502881063 feat: 付款申请审批通过前增加确认弹框 2026-10-28 16:11:29 +08:00
刘泉佳 358add743e fix: 合同变更审批接口超时统一使用APPROVE_TIMEOUT 2026-10-28 14:36:03 +08:00
刘泉佳 f67a4036ed fix: 项目变更与合同管理审批接口超时统一使用APPROVE_TIMEOUT 2026-10-28 14:16:42 +08:00
24 changed files with 179 additions and 187 deletions
+2 -2
View File
@@ -1,4 +1,5 @@
import { createCrudApi } from './common';
import { APPROVE_TIMEOUT } from '@/api/common';
import request from '@/axios';
const baseUrl = '/blade-transport/contract-change';
@@ -35,8 +36,7 @@ export const approve = id =>
url: `${baseUrl}/approve`,
method: 'post',
params: { id },
// 审批通过后同步推送合规(附件转传可达 20s+),覆盖全局 10s 超时
timeout: 120000,
timeout: APPROVE_TIMEOUT,
});
export const reject = id =>
+2 -2
View File
@@ -1,4 +1,5 @@
import { createCrudApi } from './common';
import { APPROVE_TIMEOUT } from '@/api/common';
import request from '@/axios';
const baseUrl = '/blade-transport/contract-manage';
@@ -36,8 +37,7 @@ export const approve = id =>
url: `${baseUrl}/approve`,
method: 'post',
params: { id },
// 审批通过后同步推送合规(附件转传可达 20s+),覆盖全局 10s 超时
timeout: 120000,
timeout: APPROVE_TIMEOUT,
});
export const reject = id =>
+2
View File
@@ -1,4 +1,5 @@
import { createCrudApi } from './common';
import { APPROVE_TIMEOUT } from '@/api/common';
import request from '@/axios';
const baseUrl = '/blade-transport/project-change';
@@ -35,6 +36,7 @@ export const approve = id =>
url: `${baseUrl}/approve`,
method: 'post',
params: { id },
timeout: APPROVE_TIMEOUT,
});
export const reject = id =>
-8
View File
@@ -8,20 +8,12 @@ export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get'
export const updateAttachments = data =>
request({ url: `${baseUrl}/attachments`, method: 'post', data });
export const voidClaim = id => request({ url: `${baseUrl}/void`, method: 'post', params: { id } });
export const queryKingdeeResult = () =>
request({ url: `${baseUrl}/query-kingdee-result`, method: 'post' });
export const claimStatusOptions = [
{ label: '已认领', value: 'claimed' },
{ label: '已作废', value: 'voided' },
];
export const pushStatusOptions = [
{ label: '未推送', value: 'none' },
{ label: '已推送', value: 'pushed' },
{ label: '推送失败', value: 'failed' },
];
export const kingdeeBillStatusOptions = [
{ label: '未生成', value: 'none' },
{ label: '已推送', value: 'pushed' },
+4 -9
View File
@@ -2,6 +2,9 @@ import request from '@/axios';
const baseUrl = '/blade-transport/receipt-flow';
/** 收款流水同步需远程拉取金蝶收款单并逐条落库,覆盖全局 10s 超时 */
export const SYNC_TIMEOUT = 30000;
export const getList = (current, size, params) =>
request({ url: `${baseUrl}/list`, method: 'get', params: { current, size, ...params } });
export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get', params: { id } });
@@ -12,9 +15,7 @@ export const getSettlementCandidates = (keyword, flowId) =>
params: { keyword, flowId },
});
export const claim = data => request({ url: `${baseUrl}/claim`, method: 'post', data });
export const sync = () => request({ url: `${baseUrl}/sync`, method: 'post' });
export const pushKingdee = flowId =>
request({ url: `${baseUrl}/push-kingdee`, method: 'post', params: { flowId } });
export const sync = () => request({ url: `${baseUrl}/sync`, method: 'post', timeout: SYNC_TIMEOUT });
export const claimStatusOptions = [
{ label: '未认领', value: 'unclaimed' },
@@ -22,12 +23,6 @@ export const claimStatusOptions = [
{ label: '认领完成', value: 'claimed' },
];
export const pushStatusOptions = [
{ label: '未推送', value: 'none' },
{ label: '已推送', value: 'pushed' },
{ label: '推送失败', value: 'failed' },
];
export const kingdeeBillStatusOptions = [
{ label: '已推送', value: 'pushed' },
{ label: '审核通过', value: 'approved' },
+1 -1
View File
@@ -169,7 +169,7 @@ export const paymentApplicationOption = ({
{ label: '当前节点', prop: 'currentNode', minWidth: 120, formatter: textFormatter },
{ label: '当前处理人', prop: 'currentProcessor', minWidth: 120, formatter: textFormatter },
{ label: '金蝶单据号', prop: 'kingdeeBillNo', minWidth: 130, formatter: textFormatter },
{ label: '金蝶单据状态', prop: 'kingdeeStatusName', minWidth: 130, formatter: textFormatter },
{ label: '金蝶单据状态', prop: 'kingdeeStatusName', slot: true, minWidth: 130 },
{ label: '金蝶锁状态', prop: 'kingdeeLockStatus', slot: true, minWidth: 150 },
{ label: '附件同步', prop: 'attachmentSyncStatusName', minWidth: 100, formatter: textFormatter },
],
+2 -2
View File
@@ -1,7 +1,7 @@
export const receiptClaimRecordTableColumns = [
{ prop: 'receiptNoticeNo', label: '认领通知单', minWidth: 150, link: true },
{ prop: 'receiptNoticeNo', label: '收款单号', minWidth: 150, link: true },
{ prop: 'payerName', label: '付款人', minWidth: 130 },
{ prop: 'receiptAmount', label: '付款金额', minWidth: 130, money: true },
{ prop: 'receiptAmount', label: '收款金额', minWidth: 130, money: true },
{ prop: 'counterpartyName', label: '对方户名', minWidth: 150 },
{ prop: 'counterpartyAccount', label: '对方账号', minWidth: 170 },
{ prop: 'counterpartyBank', label: '对方开户行', minWidth: 150 },
+12 -7
View File
@@ -1,18 +1,23 @@
export const receiptFlowTableColumns = [
{ prop: 'receiptNoticeNo', label: '认领通知单', minWidth: 150, link: true },
{ prop: 'receiptNoticeNo', label: '收款单号', minWidth: 150, link: true },
{ prop: 'payerName', label: '付款人', minWidth: 130 },
{ prop: 'receiptAmount', label: '付款金额', minWidth: 130, money: true },
{ prop: 'receiptAmount', label: '收款金额', minWidth: 130, money: true },
{ prop: 'counterpartyName', label: '对方户名', minWidth: 150 },
{ prop: 'counterpartyAccount', label: '对方账号', minWidth: 170 },
{ prop: 'counterpartyBank', label: '对方开户行', minWidth: 150 },
{ prop: 'payeeName', label: '收款人(公司)', minWidth: 150 },
//{ prop: 'orgNumber', label: '收款公司编码', minWidth: 130 },
//{ prop: 'openOrgNumber', label: '核算组织编码', minWidth: 130 },
{ prop: 'summary', label: '摘要', minWidth: 160 },
{ prop: 'transactionTime', label: '交易时间', minWidth: 170 },
{ prop: 'claimStatusName', label: '认领状态', minWidth: 110, status: true },
{ prop: 'kingdeeClaimStatusName', label: '公告状态', minWidth: 110 },
{ prop: 'claimedAmount', label: '已认领金额', minWidth: 130, money: true },
{ prop: 'unclaimedAmount', label: '金蝶未认领金额', minWidth: 140, money: true },
{ prop: 'pushStatusName', label: '推送状态', minWidth: 110, status: true },
{ prop: 'pushFailReason', label: '推送失败原因', minWidth: 160 },
{ prop: 'kingdeeBillNo', label: '金蝶收款单号', minWidth: 150 },
{ prop: 'remainingAmount', label: '剩余可认领金额', minWidth: 140, money: true },
{ prop: 'unmatchAmountRec', label: '未匹配金额', minWidth: 140, money: true },
//{ prop: 'matchAmountRec', label: '已匹配收款金额', minWidth: 140, money: true },
//{ prop: 'matchAmountPay', label: '已匹配付款金额', minWidth: 140, money: true },
//{ prop: 'unmatchAmountPay', label: '未匹配付款金额', minWidth: 140, money: true },
//{ prop: 'settleAmount', label: '已结算金额', minWidth: 130, money: true },
//{ prop: 'unsettleAmount', label: '未结算金额', minWidth: 130, money: true },
{ prop: 'kingdeeBillStatusName', label: '金蝶状态', minWidth: 110 },
];
+2 -1
View File
@@ -99,7 +99,8 @@ const buildTableColumns = () =>
}
// link / status 标记的列统一走单元格插槽
if (column.link || column.status) extra.slot = true;
if (!extra.formatter) extra.formatter = textFormatter;
// 插槽列不挂兜底 formatter:avue 中 formatter 会覆盖单元格插槽渲染
if (!extra.slot && !extra.formatter) extra.formatter = textFormatter;
return { ...column, ...extra };
});
+15
View File
@@ -0,0 +1,15 @@
/**
* 金蝶单据状态公共映射
*/
/** 金蝶单据状态 → el-tag 颜色类型(failed 状态列表页悬浮展示失败原因) */
export const KINGDEE_STATUS_TAG_TYPES = {
synced: 'success',
paid: 'success',
invoiced: 'success',
paying: 'warning',
failed: 'danger',
};
/** 金蝶单据状态 → el-tag 颜色类型,未映射状态返回 info */
export const kingdeeStatusType = status => KINGDEE_STATUS_TAG_TYPES[status] || 'info';
@@ -293,6 +293,12 @@
<el-input v-model="row.remark" :disabled="readonly" maxlength="200" />
</template>
</el-table-column>
<el-table-column v-if="readonly" label="开票状态" min-width="90" align="center">
<template #default="{ row }">{{ sheet.invoiceStatusName || '未开票' }}</template>
</el-table-column>
<el-table-column v-if="readonly" label="金蝶开票结果备注" min-width="200">
<template #default="{ row }">{{ sheet.kingdeeResultRemark }}</template>
</el-table-column>
<el-table-column v-if="!readonly" label="操作" width="110" fixed="right" align="center">
<template #default="{ $index }">
<div class="invoice-form-page__links">
+13
View File
@@ -125,6 +125,17 @@
{{ displayValue(row[column.prop]) }}
</el-tag>
<span v-else-if="column.money">{{ formatMoney(row[column.prop]) }}</span>
<template v-else-if="column.prop === 'kingdeeStatusName'">
<el-tooltip
:disabled="row.kingdeeStatus !== 'failed'"
:content="row.kingdeeFailReason || '推送金蝶失败,可点击「同步金蝶」重试'"
placement="top"
>
<el-tag :type="kingdeeStatusType(row.kingdeeStatus)">{{
row.kingdeeStatusName || '-'
}}</el-tag>
</el-tooltip>
</template>
<template v-else-if="column.prop === 'kingdeeLockStatus'">
<el-tooltip v-if="lockTag(row).show" :content="lockTag(row).tip" placement="top">
<el-tag :type="lockTag(row).type" class="status-text">{{ lockTag(row).label }}</el-tag>
@@ -238,6 +249,7 @@ import TableHeaderTools from '@/components/table-header-tools/main.vue';
import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
import { kingdeeStatusType } from '@/utils/kingdee';
const emptyQuery = () => ({
applicationNo: '',
@@ -500,6 +512,7 @@ export default {
''
);
},
kingdeeStatusType,
lockTag(row) {
if (row.kingdeeLockStatus === 'locked') {
return { show: true, type: 'danger', label: '金蝶锁定中', tip: '该单据已被金蝶锁定,不可编辑/作废' };
+34 -6
View File
@@ -2702,7 +2702,8 @@ export default {
this.referenceParams('formal')
);
const data = this.unwrapData(response) || {};
const records = data.records || [];
// 已调整的结算单为调整重推后的归档原单,金额已作废,不可再发起付款
const records = (data.records || []).filter(row => row.adjustStatus !== 'adjusted');
this.formalRows = await this.fillReferencePayableAmounts(records, 'settlement_payment');
this.formalPage.total = Number(data.total || 0);
} finally {
@@ -3124,18 +3125,21 @@ export default {
if (!target) return;
target.paymentRatio = value;
this.syncRowPayment(target, 'ratio');
this.syncHeaderSettlementTotalsFromRows();
this.syncHeaderSettlementTotalsFromRows(true);
},
handleRowAppliedAmountChange(row, value) {
const target = this.findReferenceRow(row);
if (!target) return;
target.appliedAmount = value;
this.syncRowPayment(target, 'amount');
this.syncHeaderSettlementTotalsFromRows();
this.syncHeaderSettlementTotalsFromRows(true);
},
/** 多结算单时仅同步结算金额/可付款金额合计,申请付款金额与比例由上方独立维护 */
syncHeaderSettlementTotalsFromRows() {
if (this.referenceRows.length <= 1) return;
/**
* 结算信息行合计回填付款基本信息。
* @param {boolean} syncApplied 行内编辑时同步申请付款金额与比例;回显加载时保持原值,避免改写历史单据
*/
syncHeaderSettlementTotalsFromRows(syncApplied = false) {
if (!this.referenceRows.length) return;
const settlementAmount = this.referenceRows.reduce(
(total, item) => total + Number(item.settlementAmount || 0),
0
@@ -3144,9 +3148,21 @@ export default {
(total, item) => total + Number(item.payableAmount || 0),
0
);
const appliedAmount = this.referenceRows.reduce(
(total, item) => total + Number(item.appliedAmount || 0),
0
);
this.amountSyncing = true;
this.form.settlementAmount = Number(settlementAmount.toFixed(2));
this.form.payableAmount = Number(payableAmount.toFixed(2));
if (syncApplied) {
this.form.appliedAmount = Number(appliedAmount.toFixed(2));
if (this.paymentAmountBase) {
this.form.paymentRatio = Number(
((appliedAmount / this.paymentAmountBase) * 100).toFixed(2)
);
}
}
this.$nextTick(() => {
this.amountSyncing = false;
this.$refs.formRef?.validateField?.(['settlementAmount', 'appliedAmount']);
@@ -3320,6 +3336,18 @@ export default {
ElMessage.warning(`${exceededRow.settlementNo || '结算单'}付款金额不能超过可付款金额`);
return false;
}
const rowAppliedTotal = this.referenceRows.reduce(
(total, item) => total + Number(item.appliedAmount || 0),
0
);
// 金蝶按付款基本信息申请金额推单,行合计不等时预付建档分摊会与金蝶金额不一致
if (Math.abs(rowAppliedTotal - appliedAmount) > 0.005) {
this.clearMessages();
ElMessage.warning(
`结算行付款金额合计${rowAppliedTotal.toFixed(2)}与申请付款金额${appliedAmount.toFixed(2)}不一致,请调整`
);
return false;
}
}
if (this.form.paymentType === 'project_advance' && !this.form.projectId) {
this.clearMessages();
+23 -7
View File
@@ -68,6 +68,18 @@
<span v-else>-</span>
</template>
<template #kingdeeStatusName="{ row }">
<el-tooltip
:disabled="row.kingdeeStatus !== 'failed'"
:content="row.kingdeeFailReason || '推送金蝶失败,可点击「同步金蝶」重试'"
placement="top"
>
<el-tag :type="kingdeeStatusType(row.kingdeeStatus)">{{
row.kingdeeStatusName || '-'
}}</el-tag>
</el-tooltip>
</template>
<template #menu="{ row }">
<el-link
v-if="hasPermission('payment_application_view')"
@@ -151,6 +163,7 @@ import { paymentApplicationOption } from '@/option/payment/paymentApplication';
import organizationSearch from '@/mixins/organization-search';
import { getMKApprovalUrl } from '@/api/system/business-process';
import { loadMkEnabled, submitMkApprovalFlow } from '@/utils/mk-approval';
import { kingdeeStatusType } from '@/utils/kingdee';
const paymentApplicationListRoute = '/payment/payment-application';
const paymentApplicationListRefreshKey = 'payment-application-list-refresh';
@@ -328,15 +341,17 @@ export default {
this.refreshChange();
},
async handleApprove(row) {
// 防止重复点击:请求进行中忽略后续点击
// 防止重复点击:请求进行中忽略后续点击,避免重复审批和重复提示
if (this.approveLoading) return;
this.approveLoading = true;
const loading = this.$loading({
lock: true,
text: '审批处理中,请稍候…',
background: 'rgba(255, 255, 255, 0.6)',
});
let loading = null;
try {
await this.$confirm('确认审批通过该付款申请?', '提示', { type: 'warning' });
loading = this.$loading({
lock: true,
text: '审批处理中,请稍候…',
background: 'rgba(255, 255, 255, 0.6)',
});
const res = await api.approve({ id: row.id });
// data=false 表示审批已通过但自动同步金蝶失败,msg 带具体原因
if (res.data.data === false) {
@@ -346,7 +361,7 @@ export default {
}
this.refreshChange();
} finally {
loading.close();
loading?.close();
this.approveLoading = false;
}
},
@@ -461,6 +476,7 @@ export default {
''
);
},
kingdeeStatusType,
lockTag(row) {
if (row.kingdeeLockStatus === 'locked') {
return { show: true, type: 'danger', label: '金蝶锁定中', tip: '该单据已被金蝶锁定,不可编辑/作废' };
@@ -4,7 +4,7 @@
<section-card title="收款信息">
<el-row :gutter="32">
<el-col :span="6">
<el-form-item label="认领通知单">
<el-form-item label="收款单号">
<el-input v-model="form.receiptNoticeNo" disabled />
</el-form-item>
</el-col>
+4 -34
View File
@@ -3,7 +3,7 @@
<section-card v-if="searchVisible" class="claim-record-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="claim-record-page__search-grid">
<el-form-item label="认领通知单">
<el-form-item label="收款单号">
<el-input v-model="query.receiptNoticeNo" clearable placeholder="请输入" />
</el-form-item>
<el-form-item label="对方户名">
@@ -56,16 +56,6 @@
<el-form-item v-show="searchExpanded" label="所属组织">
<el-input v-model="query.claimerDeptName" clearable placeholder="请输入" />
</el-form-item>
<el-form-item v-show="searchExpanded" label="推送状态">
<el-select v-model="query.pushStatus" clearable placeholder="请选择">
<el-option
v-for="item in pushStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-show="searchExpanded" label="金蝶单据状态">
<el-select v-model="query.kingdeeBillStatus" clearable placeholder="请选择">
<el-option
@@ -93,9 +83,6 @@
<section class="claim-record-page__table-panel">
<div class="claim-record-page__toolbar">
<el-button :loading="refreshing" @click="handleRefreshKingdeeResult">
查询金蝶认领结果
</el-button>
<table-header-tools
:columns="columns"
v-model:visible-column-keys="visibleColumnKeys"
@@ -131,11 +118,7 @@
<el-table-column label="操作" width="120" fixed="right" align="center">
<template #default="{ row }">
<el-link
v-if="
hasPermission('receipt_claim_record_void') &&
row.claimStatus === 'claimed' &&
row.pushStatus !== 'pushed'
"
v-if="hasPermission('receipt_claim_record_void') && row.claimStatus === 'claimed'"
type="danger"
@click="handleVoid(row)"
>作废</el-link
@@ -181,7 +164,6 @@ const emptyQuery = () => ({
claimDateRange: [],
claimerDeptName: '',
kingdeeBillStatus: '',
pushStatus: '',
});
export default {
@@ -195,17 +177,15 @@ export default {
searchExpanded: false,
// 与 avue-crud 一致:搜索项数量超过 searchIndex(默认一行 4 项)时才显示“展开/收起”
searchIndex: 4,
searchItemCount: 11,
searchItemCount: 10,
searchVisible: true,
tableSize: 'default',
claimStatusOptions: api.claimStatusOptions,
kingdeeBillStatusOptions: api.kingdeeBillStatusOptions,
pushStatusOptions: api.pushStatusOptions,
columns: receiptClaimRecordTableColumns,
visibleColumnKeys: receiptClaimRecordTableColumns.map(column => column.prop),
rows: [],
loading: false,
refreshing: false,
page: { current: 1, size: 10, total: 0 },
};
},
@@ -272,7 +252,7 @@ export default {
},
async handleVoid(row) {
await this.$confirm(
'作废后将回退本次认领金额,是否继续?',
'作废后将回退本次认领金额,并同步作废合同合规系统认领记录,是否继续?',
'作废认领记录',
{ type: 'warning', confirmButtonText: '确定', cancelButtonText: '取消' }
);
@@ -280,16 +260,6 @@ export default {
this.$message.success('作废成功');
await this.loadTable();
},
async handleRefreshKingdeeResult() {
this.refreshing = true;
try {
const updated = Number(this.unwrapData(await api.queryKingdeeResult()) || 0);
this.$message.success(`金蝶认领结果回写完成,更新${updated}条`);
await this.loadTable();
} finally {
this.refreshing = false;
}
},
hasPermission(code) {
return this.isAdmin || this.validData(this.permission?.[code], false);
},
+8 -14
View File
@@ -7,7 +7,7 @@
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column
prop="receiptNoticeNo"
label="认领通知单"
label="收款单号"
min-width="160"
show-overflow-tooltip
/>
@@ -43,8 +43,8 @@
<el-table-column label="已认领金额" min-width="130" align="right">
<template #default="{ row }">{{ formatMoney(row.claimedAmount) }}</template>
</el-table-column>
<el-table-column label="金蝶未认领金额" min-width="140" align="right">
<template #default="{ row }">{{ formatMoney(row.unclaimedAmount) }}</template>
<el-table-column label="未匹配金额" min-width="140" align="right">
<template #default="{ row }">{{ formatMoney(row.unmatchAmountRec) }}</template>
</el-table-column>
<el-table-column label="剩余可认领金额" min-width="140" align="right">
<template #default="{ row }">{{ formatMoney(flowRemaining(row)) }}</template>
@@ -96,7 +96,7 @@
formatMoney(row.settlement.claimedReceiptAmount)
}}</template>
</el-table-column>
<el-table-column label="认领通知单" min-width="180">
<el-table-column label="收款单号" min-width="180">
<template #default="{ row }">{{ row.flow.receiptNoticeNo || '-' }}</template>
</el-table-column>
<el-table-column label="收款金额" min-width="140" align="right">
@@ -302,10 +302,8 @@ export default {
);
},
flowRemaining(flow) {
const unclaimed = Number(flow.unclaimedAmount || 0);
const receipt = Number(flow.receiptAmount || 0);
const ceiling = unclaimed > 0 && receipt > 0 ? Math.min(unclaimed, receipt) : unclaimed || receipt;
return Math.max(ceiling - Number(flow.claimedAmount || 0), 0);
// 认领只登记本地:剩余可认领 = 收款金额 − 已认领金额
return Math.max(Number(flow.receiptAmount || 0) - Number(flow.claimedAmount || 0), 0);
},
maxAllocation(row) {
const current = Number(row.settlement.allocations?.[row.flow.id] || 0);
@@ -355,12 +353,8 @@ export default {
}
for (const flow of this.flows) {
const total = this.flowAllocatedTotal(flow.id);
const remaining = Math.max(
Number(flow.unclaimedAmount || 0) - Number(flow.claimedAmount || 0),
0
);
if (total > remaining + 0.001) {
this.$message.warning(`流水${flow.receiptNoticeNo}的累计认领金额不能超过公告未认领金额`);
if (total > this.flowRemaining(flow) + 0.001) {
this.$message.warning(`流水${flow.receiptNoticeNo}的累计认领金额不能超过剩余可认领金额`);
return;
}
}
+7 -8
View File
@@ -12,7 +12,7 @@
<section-card title="收款信息">
<el-row :gutter="32">
<el-col :span="6"
><el-form-item label="认领通知单"
><el-form-item label="收款单号"
><el-input v-model="form.receiptNoticeNo" disabled /></el-form-item
></el-col>
<el-col :span="6"
@@ -48,8 +48,8 @@
><el-input :model-value="formatMoney(form.claimedAmount)" disabled /></el-form-item
></el-col>
<el-col :span="6"
><el-form-item label="金蝶未认领金额"
><el-input :model-value="formatMoney(form.unclaimedAmount)" disabled /></el-form-item
><el-form-item label="未匹配金额"
><el-input :model-value="formatMoney(form.unmatchAmountRec)" disabled /></el-form-item
></el-col>
<el-col :span="6"
><el-form-item label="剩余可认领金额"
@@ -205,7 +205,7 @@ const emptyForm = () => ({
transactionTime: '',
detailSerialNo: '',
claimedAmount: 0,
unclaimedAmount: 0,
unmatchAmountRec: 0,
claimerName: '',
claimerDeptName: '',
claimDate: '',
@@ -252,11 +252,10 @@ export default {
);
},
claimableAmount() {
const unclaimed = Number(this.form.unclaimedAmount || 0);
// 认领只登记本地:剩余可认领 = 收款金额 − 已认领金额
const receipt = Number(this.form.receiptAmount || 0);
const ceiling =
unclaimed > 0 && receipt > 0 ? Math.min(unclaimed, receipt) : unclaimed || receipt;
return Math.max(ceiling - Number(this.form.claimedAmount || 0), 0);
const claimed = Number(this.form.claimedAmount || 0);
return Math.max(receipt - claimed, 0);
},
},
created() {
+10 -77
View File
@@ -3,7 +3,7 @@
<section v-if="searchVisible" class="receipt-flow-page__search">
<el-form :model="query" label-position="right" label-width="88px" @submit.prevent>
<div class="receipt-flow-page__search-grid">
<el-form-item label="认领通知单">
<el-form-item label="收款单号">
<el-input v-model="query.receiptNoticeNo" clearable placeholder="请输入" />
</el-form-item>
<el-form-item label="对方户名">
@@ -15,16 +15,6 @@
<el-form-item label="对方账号">
<el-input v-model="query.counterpartyAccount" clearable placeholder="请输入" />
</el-form-item>
<el-form-item label="推送状态">
<el-select v-model="query.pushStatus" clearable placeholder="请选择">
<el-option
v-for="item in pushStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="认领状态">
<el-select v-model="query.claimStatus" clearable placeholder="请选择">
<el-option
@@ -159,23 +149,10 @@
<span v-else>{{ displayValue(row[column.prop]) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="170" fixed="right" align="center">
<el-table-column label="操作" width="100" fixed="right" align="center">
<template #default="{ row }">
<el-link
v-if="canClaim(row)"
type="primary"
:disabled="pushingId === row.id"
@click="openClaim(row)"
>认领</el-link
>
<el-link
v-if="canPush(row)"
type="warning"
:disabled="pushingId === row.id"
@click="handlePush(row)"
>推送金蝶</el-link
>
<span v-if="!canClaim(row) && !canPush(row)">-</span>
<el-link v-if="canClaim(row)" type="primary" @click="openClaim(row)">认领</el-link>
<span v-else>-</span>
</template>
</el-table-column>
</el-table>
@@ -201,13 +178,13 @@
>
<div v-loading="detailDialog.loading">
<el-descriptions :column="3" border>
<el-descriptions-item label="认领通知单">
<el-descriptions-item label="收款单号">
{{ displayValue(detailDialog.data.receiptNoticeNo) }}
</el-descriptions-item>
<el-descriptions-item label="付款人">
{{ displayValue(detailDialog.data.payerName) }}
</el-descriptions-item>
<el-descriptions-item label="付款金额">
<el-descriptions-item label="收款金额">
{{ formatMoney(detailDialog.data.receiptAmount) }}
</el-descriptions-item>
<el-descriptions-item label="交易时间">
@@ -236,13 +213,8 @@
<el-descriptions-item label="剩余可认领金额">
{{ formatMoney(detailDialog.data.remainingAmount) }}
</el-descriptions-item>
<el-descriptions-item label="金蝶未认领金额">
{{ formatMoney(detailDialog.data.unclaimedAmount) }}
</el-descriptions-item>
<el-descriptions-item label="推送状态">
<el-tag :type="statusType(detailDialog.data, { prop: 'pushStatusName' })">
{{ displayValue(detailDialog.data.pushStatusName) }}
</el-tag>
<el-descriptions-item label="未匹配金额">
{{ formatMoney(detailDialog.data.unmatchAmountRec) }}
</el-descriptions-item>
<el-descriptions-item label="金蝶收款单号">
{{ displayValue(detailDialog.data.kingdeeBillNo) }}
@@ -250,9 +222,6 @@
<el-descriptions-item label="金蝶状态">
{{ displayValue(detailDialog.data.kingdeeBillStatusName) }}
</el-descriptions-item>
<el-descriptions-item label="推送失败原因">
{{ displayValue(detailDialog.data.pushFailReason) }}
</el-descriptions-item>
<el-descriptions-item label="摘要">
{{ displayValue(detailDialog.data.summary) }}
</el-descriptions-item>
@@ -267,9 +236,7 @@
</el-table-column>
<el-table-column prop="operatorName" label="认领人" min-width="120" align="center" />
<el-table-column label="状态变化" min-width="170" align="center">
<template #default="{ row }">
{{ row.actionType === 'push' ? row.actionName : claimStatusChange(row) }}
</template>
<template #default="{ row }">{{ claimStatusChange(row) }}</template>
</el-table-column>
<el-table-column prop="content" label="认领说明" min-width="220" />
</el-table>
@@ -297,7 +264,6 @@ const emptyQuery = () => ({
summary: '',
detailSerialNo: '',
claimStatus: '',
pushStatus: '',
kingdeeBillStatus: '',
receiptAmountStart: undefined,
receiptAmountEnd: undefined,
@@ -314,7 +280,6 @@ export default {
ArrowUp,
query: emptyQuery(),
claimStatusOptions: api.claimStatusOptions,
pushStatusOptions: api.pushStatusOptions,
kingdeeBillStatusOptions: api.kingdeeBillStatusOptions,
columns: receiptFlowTableColumns,
visibleColumnKeys: receiptFlowTableColumns.map(column => column.prop),
@@ -324,7 +289,6 @@ export default {
selectedRows: [],
loading: false,
syncing: false,
pushingId: null,
searchExpanded: false,
// 与 avue-crud 一致:搜索项数量超过 searchIndex(默认一行 4 项)时才显示“展开/收起”
searchIndex: 4,
@@ -389,7 +353,7 @@ export default {
this.syncing = true;
try {
const syncedCount = Number(this.unwrapData(await api.sync()) || 0);
this.$message.success(`流水同步完成,共同步${syncedCount}条认领公告`);
this.$message.success(`流水同步完成,共同步${syncedCount}条收款流水`);
await this.loadTable();
} finally {
this.syncing = false;
@@ -448,38 +412,7 @@ export default {
canClaim(row) {
return this.hasPermission('receipt_flow_claim') && Number(row.remainingAmount || 0) > 0;
},
canPush(row) {
return (
this.hasPermission('receipt_flow_push') &&
!!row.billId &&
row.claimStatus === 'claimed' &&
row.pushStatus !== 'pushed'
);
},
async handlePush(row) {
try {
await this.$confirm(
`确认将流水【${row.receiptNoticeNo || row.detailSerialNo || ''}】推送金蝶生成收款单?`,
'推送金蝶',
{ type: 'warning' }
);
} catch {
return;
}
this.pushingId = row.id;
try {
const data = this.unwrapData(await api.pushKingdee(row.id));
const billNo = data?.kingdeeBillNo;
this.$message.success(billNo ? `推送成功,金蝶收款单号:${billNo}` : '推送成功');
await this.loadTable();
} finally {
this.pushingId = null;
}
},
statusType(row, column) {
if (column?.prop === 'pushStatusName') {
return { pushed: 'success', failed: 'danger' }[row.pushStatus] || 'info';
}
return (
{ claimed: 'success', partial: 'warning', unclaimed: 'info' }[row.claimStatus] || ''
);
@@ -559,7 +559,7 @@
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column
prop="receiptNoticeNo"
label="认领通知单"
label="收款单号"
min-width="160"
align="center"
/>
@@ -60,7 +60,17 @@
}}</el-tag>
</template>
<template #kingdeeSyncStatus="{ row }">{{ kingdeeSyncName(row.kingdeeSyncStatus) }}</template>
<template #kingdeeSyncStatus="{ row }">
<el-tooltip
:disabled="row.kingdeeSyncStatus !== 'failed'"
:content="row.kingdeeFailReason || '推送金蝶失败,可点击「同步金蝶」重试'"
placement="top"
>
<el-tag :type="kingdeeStatusType(row.kingdeeSyncStatus)">{{
kingdeeSyncName(row.kingdeeSyncStatus)
}}</el-tag>
</el-tooltip>
</template>
<template #kingdeeLockStatus="{ row }">
<el-tooltip v-if="lockTag(row).show" :content="lockTag(row).tip" placement="top">
@@ -84,6 +94,7 @@
<script>
import { invoiceStatusName } from '@/option/settlement/formalSettlementSearch';
import { kingdeeSyncName, paymentStatusName } from '@/option/settlement/formalSettlement';
import { kingdeeStatusType } from '@/utils/kingdee';
export default {
name: 'FormalSettlementTablePanel',
@@ -186,6 +197,7 @@ export default {
''
);
},
kingdeeStatusType,
invoiceName(value, settlementType) {
return invoiceStatusName(value, settlementType);
},
@@ -486,6 +486,8 @@ export default {
const rows = this.selection;
if (rows.some(row => row.approvalStatus !== 'approved' || row.settlementType !== 'payable'))
return this.$message.warning('仅审批通过的付款结算单允许发起付款申请');
if (rows.some(row => row.adjustStatus === 'adjusted'))
return this.$message.warning('已调整的结算单不可再发起付款,请使用调整后的新单');
const contractIds = new Set(rows.map(row => String(row.contractId || '')));
if (contractIds.size !== 1 || contractIds.has(''))
return this.$message.warning('付款申请必须选择同一个合同的付款结算单');
@@ -93,11 +93,15 @@
><el-tag v-else-if="column.status" :type="statusType(row.approvalStatus)" class="status-text">{{
row[column.prop] || '-'
}}</el-tag
><el-tag
><el-tooltip
v-else-if="column.kingdee"
:disabled="row.kingdeeSyncStatus !== 'failed'"
:content="row.kingdeeFailReason || '推送金蝶失败,请重试'"
placement="top"
><el-tag
:type="kingdeeStatusType(row.kingdeeSyncStatus)"
class="status-text"
>{{ kingdeeSyncName(row.kingdeeSyncStatus) }}</el-tag
></el-tooltip
><span v-else-if="column.money">{{ formatMoney(row[column.prop]) }}</span
><span v-else>{{ displayValue(row[column.prop]) }}</span></template
></el-table-column
@@ -182,6 +186,7 @@ import { settlementAdjustmentSearchFields } from '@/option/settlement/settlement
import organizationSearch from '@/mixins/organization-search';
import { settlementAdjustmentTableColumns } from '@/option/settlement/settlementAdjustmentTable';
import { kingdeeSyncStatusOptions } from '@/option/settlement/formalSettlementSearch';
import { kingdeeStatusType } from '@/utils/kingdee';
import SettlementAdjustmentEditor from './components/settlement-adjustment-editor.vue';
import SettlementTableTools from './components/settlement-table-tools.vue';
import { isAdministrator } from '@/utils/auth';
@@ -365,9 +370,7 @@ export default {
'info'
);
},
kingdeeStatusType(status) {
return { synced: 'success', failed: 'danger' }[status] || 'info';
},
kingdeeStatusType,
kingdeeSyncName(value) {
return kingdeeSyncStatusOptions.find(item => item.value === value)?.label || value || '-';
},
+7 -1
View File
@@ -135,7 +135,13 @@
<template #kingdeeStatus="{ row }">
<el-tag v-if="row.kingdeeStatus === 'synced'" type="success">已推送</el-tag>
<el-tag v-else-if="row.kingdeeStatus === 'exist'" type="primary">金蝶已有</el-tag>
<el-tag v-else-if="row.kingdeeStatus === 'failed'" type="danger">推送失败</el-tag>
<el-tooltip
v-else-if="row.kingdeeStatus === 'failed'"
:content="row.kingdeeFailReason || '推送金蝶失败,请重试'"
placement="top"
>
<el-tag type="danger">推送失败</el-tag>
</el-tooltip>
<el-tag v-else type="info">未推送</el-tag>
</template>
<template #menu="{ row }">