|
|
@@ -3,7 +3,7 @@ import { reactive, ref, computed, onMounted } from 'vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
import { View, Money, Switch, Close, Upload, Plus, Delete, Download, ZoomIn, Document } from '@element-plus/icons-vue'
|
|
|
import { paymentApi, attachmentApi, reimburseApi } from '../../api'
|
|
|
-import { statusLabel, statusTone, formatSumMoney } from '../../utils/format'
|
|
|
+import { statusLabel, statusTone, formatSumMoney, formatMoney, formatMoneyYuan, moneyTableFormatter } from '../../utils/format'
|
|
|
import { useServerPaged } from '../../hooks/useServerPaged'
|
|
|
import { useApplicantOptions } from '../../hooks/useApplicantOptions'
|
|
|
import ListPageScaffold from '../../components/template/ListPageScaffold.vue'
|
|
|
@@ -57,7 +57,7 @@ async function loadPaymentFinanceStats() {
|
|
|
{ name: '待处理单据', value: String(d.pendingCount ?? 0) },
|
|
|
{ name: '已打款', value: String(d.paidCount ?? 0) },
|
|
|
{ name: '冲抵备用金', value: String(d.offsetCount ?? 0) },
|
|
|
- { name: '本月处理金额(元)', value: Number(d.monthProcessedAmount ?? 0).toLocaleString('zh-CN') }
|
|
|
+ { name: '本月处理金额(元)', value: formatMoney(d.monthProcessedAmount ?? 0) }
|
|
|
]
|
|
|
} catch {
|
|
|
/* interceptor */
|
|
|
@@ -313,6 +313,23 @@ function openOffsetDialog(row: any) {
|
|
|
fetchOffsetAdvances()
|
|
|
}
|
|
|
|
|
|
+function buildOffsetItems(totalOffset: number) {
|
|
|
+ const items: Array<{ advanceId: number; offsetAmount: number; applyCode: string }> = []
|
|
|
+ let remaining = totalOffset
|
|
|
+ for (const adv of offsetSelectedAdvances.value) {
|
|
|
+ if (remaining <= 0) break
|
|
|
+ const available = Number(adv.actualAmount || adv.amount || 0) - Number(adv.offsetAmount || 0)
|
|
|
+ const toOffset = Math.min(remaining, available)
|
|
|
+ items.push({
|
|
|
+ advanceId: adv.id,
|
|
|
+ offsetAmount: toOffset,
|
|
|
+ applyCode: adv.applyCode || String(adv.id)
|
|
|
+ })
|
|
|
+ remaining -= toOffset
|
|
|
+ }
|
|
|
+ return items
|
|
|
+}
|
|
|
+
|
|
|
async function submitOffset() {
|
|
|
if (offsetSelectedAdvances.value.length === 0) {
|
|
|
ElMessage.warning('请选择要冲抵的备用金申请单')
|
|
|
@@ -323,23 +340,42 @@ async function submitOffset() {
|
|
|
ElMessage.warning('请填写冲抵金额')
|
|
|
return
|
|
|
}
|
|
|
+ if (uploadedFiles.value.length === 0) {
|
|
|
+ ElMessage.warning('请至少上传 1 个冲抵附件')
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- // Calculate overflow distribution
|
|
|
- const items: Array<{ advanceId: number; offsetAmount: number }> = []
|
|
|
- let remaining = totalOffset
|
|
|
- for (const adv of offsetSelectedAdvances.value) {
|
|
|
- if (remaining <= 0) break
|
|
|
- const available = Number(adv.actualAmount || adv.amount || 0) - Number(adv.offsetAmount || 0)
|
|
|
- const toOffset = Math.min(remaining, available)
|
|
|
- items.push({ advanceId: adv.id, offsetAmount: toOffset })
|
|
|
- remaining -= toOffset
|
|
|
+ const items = buildOffsetItems(totalOffset)
|
|
|
+ const payAmount = Number(offsetPayAmount.value) || 0
|
|
|
+ const advanceLines = items
|
|
|
+ .map((it) => `${it.applyCode}(冲抵 ${formatMoneyYuan(it.offsetAmount)})`)
|
|
|
+ .join('\n')
|
|
|
+ const confirmMsg = [
|
|
|
+ '请确认冲抵信息:',
|
|
|
+ '',
|
|
|
+ `冲抵金额:${formatMoneyYuan(totalOffset)}`,
|
|
|
+ `冲抵备用金:`,
|
|
|
+ advanceLines,
|
|
|
+ `发放金额:${formatMoneyYuan(payAmount)}`,
|
|
|
+ '',
|
|
|
+ '确定提交冲抵吗?'
|
|
|
+ ].join('\n')
|
|
|
+
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm(confirmMsg, '确认冲抵', {
|
|
|
+ confirmButtonText: '确定冲抵',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ } catch {
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
loadingMap.offsetSubmit = true
|
|
|
try {
|
|
|
await paymentApi.batchOffset(currentRow.value.id, {
|
|
|
- items,
|
|
|
- payAmount: Number(offsetPayAmount.value) || 0,
|
|
|
+ items: items.map(({ advanceId, offsetAmount }) => ({ advanceId, offsetAmount })),
|
|
|
+ payAmount,
|
|
|
remark: offsetRemark.value,
|
|
|
})
|
|
|
ElMessage.success('冲抵成功')
|
|
|
@@ -578,17 +614,17 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<template #table-columns>
|
|
|
<el-table-column type="selection" width="48" />
|
|
|
<el-table-column type="index" label="序号" width="90" />
|
|
|
+ <el-table-column prop="applyTime" label="申请时间" min-width="160" />
|
|
|
<el-table-column prop="applyCode" label="单号" min-width="140" />
|
|
|
<el-table-column prop="applicantName" label="申请人" min-width="100" />
|
|
|
<el-table-column prop="title" label="报销标题" min-width="180" />
|
|
|
- <el-table-column prop="applyTime" label="审批完成时间" min-width="160" />
|
|
|
- <el-table-column prop="amount" label="报销金额(元)" class-name="col-money" min-width="120" />
|
|
|
- <el-table-column label="冲抵金额(元)" class-name="col-money" min-width="120">
|
|
|
+ <el-table-column prop="amount" label="报销金额(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="120" />
|
|
|
+ <el-table-column label="冲抵金额(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="120">
|
|
|
<template #default="{ row }">
|
|
|
{{ formatSumMoney(Number(row.offsetAmount || 0)) }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="发放金额(元)" class-name="col-money" min-width="120">
|
|
|
+ <el-table-column label="发放金额(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="120">
|
|
|
<template #default="{ row }">
|
|
|
{{
|
|
|
row.actualAmount != null && row.actualAmount !== ''
|
|
|
@@ -668,16 +704,17 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
|
|
|
<template #table-columns>
|
|
|
<el-table-column type="index" label="序号" width="90" />
|
|
|
+ <el-table-column prop="applyTime" label="申请时间" min-width="160" />
|
|
|
<el-table-column prop="applyCode" label="单号" min-width="140" />
|
|
|
<el-table-column prop="applicantName" label="申请人" min-width="100" />
|
|
|
<el-table-column prop="title" label="标题" min-width="180" show-overflow-tooltip />
|
|
|
- <el-table-column prop="amount" label="报销金额(元)" class-name="col-money" min-width="120" />
|
|
|
- <el-table-column label="冲抵金额(元)" class-name="col-money" min-width="120">
|
|
|
+ <el-table-column prop="amount" label="报销金额(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="120" />
|
|
|
+ <el-table-column label="冲抵金额(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="120">
|
|
|
<template #default="{ row }">
|
|
|
{{ formatSumMoney(Number(row.offsetAmount || 0)) }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="发放金额(元)" class-name="col-money" min-width="120">
|
|
|
+ <el-table-column label="发放金额(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="120">
|
|
|
<template #default="{ row }">
|
|
|
{{
|
|
|
row.actualAmount != null && row.actualAmount !== ''
|
|
|
@@ -715,7 +752,7 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<BaseTag :tone="statusTone(viewData.status)">{{ statusLabel(viewData.status) }}</BaseTag>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <p class="dlg-view-meta">金额(元):<b class="money-em">¥{{ Number(viewData.amount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}</b></p>
|
|
|
+ <p class="dlg-view-meta">金额(元):<b class="money-em">{{ formatMoneyYuan(viewData.amount || 0) }}</b></p>
|
|
|
</div>
|
|
|
<div class="dlg-view-section">
|
|
|
<div class="dlg-kv dlg-kv--triple">
|
|
|
@@ -728,7 +765,7 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<div class="k">审批完成时间</div>
|
|
|
<div class="v">{{ viewData.applyTime || '-' }}</div>
|
|
|
<div class="k">金额(元)</div>
|
|
|
- <div class="v">¥{{ Number(viewData.amount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}</div>
|
|
|
+ <div class="v">{{ formatMoneyYuan(viewData.amount || 0) }}</div>
|
|
|
<div class="k">状态</div>
|
|
|
<div class="v">{{ statusLabel(viewData.status) }}</div>
|
|
|
</div>
|
|
|
@@ -760,7 +797,7 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<label>发放金额(元)</label>
|
|
|
<BaseInput :model-value="String(currentRow.amount || '')" disabled placeholder="发放金额" />
|
|
|
</div>
|
|
|
- <div class="field">
|
|
|
+ <div class="field field-amount-danger">
|
|
|
<label>实际发放金额(元)</label>
|
|
|
<BaseInput v-model="actualAmount" placeholder="请输入实际发放金额" />
|
|
|
</div>
|
|
|
@@ -822,7 +859,7 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<label>报销金额(元)</label>
|
|
|
<BaseInput :model-value="String(currentRow.amount || '')" disabled />
|
|
|
</div>
|
|
|
- <div class="field">
|
|
|
+ <div class="field field-amount-danger">
|
|
|
<label>冲抵金额(元)</label>
|
|
|
<BaseInput v-model="offsetAmount" placeholder="请输入冲抵金额" />
|
|
|
</div>
|
|
|
@@ -842,30 +879,30 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<BaseButton size="small" @click="offsetAdvanceFilter.keyword = ''; offsetAdvancePage = 1; fetchOffsetAdvances()">重置</BaseButton>
|
|
|
</div>
|
|
|
<el-table
|
|
|
+ class="bx-table"
|
|
|
:data="offsetAdvances"
|
|
|
:loading="offsetAdvanceLoading"
|
|
|
max-height="300"
|
|
|
@selection-change="(rows) => offsetSelectedAdvances = rows"
|
|
|
border
|
|
|
- size="small"
|
|
|
>
|
|
|
- <el-table-column type="selection" width="40" />
|
|
|
+ <el-table-column type="selection" width="48" align="center" />
|
|
|
<el-table-column prop="applyCode" label="申请单号" min-width="130" />
|
|
|
<el-table-column prop="applicantName" label="申请人" min-width="80" />
|
|
|
<el-table-column prop="reason" label="申请原因" min-width="120" show-overflow-tooltip />
|
|
|
- <el-table-column label="已发放金额(元)" class-name="col-money" min-width="100">
|
|
|
+ <el-table-column label="已发放金额(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="100">
|
|
|
<template #default="{ row }">
|
|
|
- {{ Number(row.actualAmount || row.amount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}
|
|
|
+ {{ formatMoney(row.actualAmount || row.amount || 0) }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="已冲抵金额(元)" class-name="col-money" min-width="100">
|
|
|
+ <el-table-column label="已冲抵金额(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="100">
|
|
|
<template #default="{ row }">
|
|
|
- {{ Number(row.offsetAmount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}
|
|
|
+ {{ formatMoney(row.offsetAmount || 0) }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="剩余可冲抵(元)" class-name="col-money" min-width="100">
|
|
|
+ <el-table-column label="剩余可冲抵(元)" :formatter="moneyTableFormatter" class-name="col-money" min-width="100">
|
|
|
<template #default="{ row }">
|
|
|
- {{ (Number(row.actualAmount || row.amount || 0) - Number(row.offsetAmount || 0)).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}
|
|
|
+ {{ formatMoney(Number(row.actualAmount || row.amount || 0) - Number(row.offsetAmount || 0)) }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
@@ -892,7 +929,7 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
|
|
|
<!-- 附件 -->
|
|
|
<div class="form-section form-section-last">
|
|
|
- <h4>冲抵附件</h4>
|
|
|
+ <h4>冲抵附件(必填)</h4>
|
|
|
<div class="attachment-upload-area">
|
|
|
<el-upload :http-request="handleUpload" :show-file-list="false" multiple :disabled="uploadLoading">
|
|
|
<div class="upload-trigger">
|
|
|
@@ -934,7 +971,7 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
</div>
|
|
|
</div>
|
|
|
<p class="dlg-view-meta">
|
|
|
- 金额(元):<b class="money-em">¥{{ Number(processedViewData.amount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}</b>
|
|
|
+ 金额(元):<b class="money-em">{{ formatMoneyYuan(processedViewData.amount || 0) }}</b>
|
|
|
</p>
|
|
|
</div>
|
|
|
|
|
|
@@ -949,7 +986,7 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<div class="k">标题</div>
|
|
|
<div class="v"><BaseClampText :text="processedViewData.title || processedViewData.reason" /></div>
|
|
|
<div class="k">金额(元)</div>
|
|
|
- <div class="v">¥{{ Number(processedViewData.amount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}</div>
|
|
|
+ <div class="v">{{ formatMoneyYuan(processedViewData.amount || 0) }}</div>
|
|
|
</div>
|
|
|
<template v-if="processedAttachments['申请附件']?.length">
|
|
|
<div class="section-attachment-title section-gap-tight">附件</div>
|
|
|
@@ -983,14 +1020,12 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<h4>发放信息</h4>
|
|
|
<div class="dlg-kv dlg-kv--triple">
|
|
|
<div class="k">发放金额(元)</div>
|
|
|
- <div class="v">¥{{ Number((processedViewData.amount || 0) - (processedViewData.offsetAmount || 0)).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}</div>
|
|
|
+ <div class="v">{{ formatMoneyYuan((processedViewData.amount || 0) - (processedViewData.offsetAmount || 0)) }}</div>
|
|
|
<div class="k">实际发放金额(元)</div>
|
|
|
<div class="v">
|
|
|
- ¥{{
|
|
|
- Number(
|
|
|
- processedViewData.actualAmount ?? ((processedViewData.amount || 0) - (processedViewData.offsetAmount || 0))
|
|
|
- ).toLocaleString('zh-CN', { minimumFractionDigits: 2 })
|
|
|
- }}
|
|
|
+ {{ formatMoneyYuan(
|
|
|
+ processedViewData.actualAmount ?? ((processedViewData.amount || 0) - (processedViewData.offsetAmount || 0))
|
|
|
+ ) }}
|
|
|
</div>
|
|
|
<template v-if="processedViewData.payTime">
|
|
|
<div class="k">发放时间</div>
|
|
|
@@ -1025,7 +1060,7 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<h4>冲抵信息</h4>
|
|
|
<div class="dlg-kv dlg-kv--triple">
|
|
|
<div class="k">冲抵金额(元)</div>
|
|
|
- <div class="v">¥{{ Number(processedViewData.offsetAmount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}</div>
|
|
|
+ <div class="v">{{ formatMoneyYuan(processedViewData.offsetAmount || 0) }}</div>
|
|
|
<template v-if="processedViewData.payTime">
|
|
|
<div class="k">处理时间</div>
|
|
|
<div class="v">{{ processedViewData.payTime }}</div>
|
|
|
@@ -1064,9 +1099,9 @@ function processedSummaryMethod(params: { data: any[] }) {
|
|
|
<el-table-column prop="advanceApplyCode" label="备用金单号" min-width="130" />
|
|
|
<el-table-column prop="advanceApplicantName" label="备用金申请人" min-width="110" />
|
|
|
<el-table-column prop="advanceReason" label="申请原因" min-width="160" show-overflow-tooltip />
|
|
|
- <el-table-column label="冲抵金额(元)" min-width="120" class-name="col-money">
|
|
|
+ <el-table-column label="冲抵金额(元)" min-width="120" :formatter="moneyTableFormatter" class-name="col-money">
|
|
|
<template #default="{ row: offsetRow }">
|
|
|
- ¥{{ Number(offsetRow.offsetAmount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2 }) }}
|
|
|
+ {{ formatMoneyYuan(offsetRow.offsetAmount || 0) }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="createTime" label="冲抵时间" min-width="160" />
|