feat(web-admin): rename transfer pay statuses to 付款 wording

Use 已付款/付款确认中/付款完成 for payStatus; keep period money
labels 应缴费/已缴费/欠缴费 unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-10-12 18:10:13 +08:00
1 parent c71bb5a11c
commit a6f56f3453
13 files changed
+245 -333

No files matched your search

@@ -354,7 +354,7 @@
}
try {
await ElMessageBox.confirm(
'确认提交缴费确认?提交后状态变为「缴费确认中」。',
'确认提交缴费确认?提交后状态变为「付款确认中」。',
'提交缴费确认',
{
confirmButtonText: '确定',
@@ -98,7 +98,7 @@ export function evaluateFqParamsChange(
if (rows.some((d) => BLOCKING_STATUSES.has(String(d.payStatus || '')))) {
return {
action: 'blocked',
reason: '存在缴费确认中或退费处理中的明细,请先完成相关流程后再修改分期参数。'
reason: '存在付款确认中或退费处理中的明细,请先完成相关流程后再修改分期参数。'
}
}
@@ -150,7 +150,7 @@ export function evaluatePayModeSwitch(
if (hasBlockingStatus(rows)) {
return {
action: 'blocked',
reason: '存在缴费确认中或退费处理中的明细,请先完成相关流程后再切换缴费模式。'
reason: '存在付款确认中或退费处理中的明细,请先完成相关流程后再切换缴费模式。'
}
}
+5 -5
View File
@@ -138,9 +138,9 @@ export const handleDoneFlagLabel = createLabelGetter(handleDoneFlag)
export const handleDoneFlagTagType = createTagTypeGetter(handleDoneFlag)
export const payStatus: StatusRegistry = {
dfj: { label: '已缴费', tagType: 'primary' },
jfqrz: { label: '缴费确认中', tagType: 'warning' },
yjf: { label: '缴费成功', tagType: 'success' },
dfj: { label: '已付款', tagType: 'primary' },
jfqrz: { label: '付款确认中', tagType: 'warning' },
yjf: { label: '付款完成', tagType: 'success' },
tfqrz: { label: '退费确认中', tagType: 'warning' },
ytf: { label: '已退费', tagType: 'danger' }
}
@@ -179,10 +179,10 @@ export const periodFinanceAudit: StatusRegistry = {
export const periodFinanceAuditLabel = createLabelGetter(periodFinanceAudit)
export const periodFinanceAuditTagType = createTagTypeGetter(periodFinanceAudit)
/** 按样本列表整体进度(勿与转账笔 payStatus 混用:payStatus.dfj=已缴费) */
/** 按样本列表整体进度(勿与转账笔 payStatus 混用:payStatus.dfj=已付款) */
export const samplePaymentProgress: StatusRegistry = {
dfj: { label: '待缴费', tagType: 'info' },
jfqrz: { label: '缴费确认中', tagType: 'warning' },
jfqrz: { label: '付款确认中', tagType: 'warning' },
bfyj: { label: '部分已缴', tagType: 'primary' },
yjq: { label: '已缴清', tagType: 'success' }
}
@@ -650,7 +650,7 @@
async function submitReject() {
if (!currentDetailId.value) return
try {
await ElMessageBox.confirm('确定退回?退回后状态将变为「缴费成功」。', '退回确认', {
await ElMessageBox.confirm('确定退回?退回后状态将变为「付款完成」。', '退回确认', {
type: 'warning'
})
} catch {
@@ -1,4 +1,4 @@
<!-- 缴费财务确认及开票(按转账笔;退费确认 Tab 已下线) -->
<!-- 缴费财务确认(按转账笔;退费确认 / 开票申请 Tab 已下线) -->
<!-- eslint-disable vue/no-v-model-argument -->
<template>
<div class="page-container">
@@ -31,20 +31,7 @@
formatTabBadgeCount(formalPendingBadge)
}}</span>
</button>
<!-- TODO(P1): 开票改挂 transfer;当前仍走旧 payment_detail 开票 API -->
<button
type="button"
role="tab"
class="panel-pill-tabs__btn"
:class="{ 'is-active': mainTab === 'invoice' }"
:aria-selected="mainTab === 'invoice'"
@click="mainTab = 'invoice'"
>
开票申请
<span v-if="invoicePendingBadge > 0" class="panel-pill-tabs__badge">{{
formatTabBadgeCount(invoicePendingBadge)
}}</span>
</button>
<!-- 开票申请 Tab 已下线;组件保留 InvoiceRequestTab.vue 待后续改挂 transfer -->
</div>
</div>
@@ -100,90 +87,214 @@
</el-form>
</div>
<div v-loading="pendingLoading" class="pending-card-section">
<div v-if="pendingData.length" class="pending-card-grid">
<article v-for="row in pendingData" :key="String(row.id)" class="pending-card">
<div class="pending-card__head">
<div class="pending-card__identity">
<div class="pending-card__name">{{ row.motherName || '-' }}</div>
<div v-if="cardSubtitle(row)" class="pending-card__sub">{{ cardSubtitle(row) }}</div>
</div>
<div class="pending-card__amount">
<div class="pending-card__amount-val">
{{ formatPaymentAmount(row.transferAmount) }}
</div>
<div class="pending-card__amount-label">
{{ isPresignRow(row) ? '待确认意向金' : '待确认转账' }}
</div>
</div>
</div>
<div class="pending-card__transfer">
<span class="pending-card__transfer-way">{{
transferTypeLabel(String(row.transferType || '')) || '-'
}}</span>
<span class="pending-card__transfer-time">{{
formatDisplayOrDash(row.transferTime)
}}</span>
</div>
<div v-if="row.remark" class="pending-card__remark">备注:{{ row.remark }}</div>
<div class="pending-card__facts">
<template v-if="isPresignRow(row)">
<div class="pending-card__field">
<label>业务日期</label>
<span>{{ formatPaymentDueDate(row.orderDate) }}</span>
</div>
<div class="pending-card__field">
<label>预产期</label>
<span>{{ formatPaymentDueDate(row.expectedDeliveryDate) }}</span>
</div>
<div class="pending-card__field">
<label>合同金额</label>
<span>{{ formatPaymentAmount(row.contractAmount) }}</span>
<em v-if="row.contractPayMode">{{
payModeLabel(String(row.contractPayMode || ''))
}}</em>
</div>
<div class="pending-card__field">
<label>采集专员</label>
<span>{{ row.collectorUserName || '-' }}</span>
</div>
</template>
<template v-else>
<div class="pending-card__field">
<label>期次</label>
<span>第 {{ row.installmentNo ?? '-' }} 期</span>
</div>
<div class="pending-card__field">
<label>应缴费时间</label>
<span>{{ formatPaymentDueDate(row.installmentDueDate) }}</span>
</div>
<div class="pending-card__field">
<label>批次应缴</label>
<span>{{ formatPaymentAmount(row.dueAmount) }}</span>
</div>
<div class="pending-card__field">
<label>缴费方式</label>
<span>{{ payModeLabel(String(row.payMode || '')) }}</span>
</div>
</template>
</div>
<div v-if="isPresignRow(row) && row.sampleTypeNames" class="pending-card__samples">
<label>样本类型</label>
<p>{{ row.sampleTypeNames }}</p>
</div>
<div class="pending-card__foot">
<div class="pending-card__meta">
<el-tag type="warning" size="small">缴费确认中</el-tag>
<span>提交 {{ formatDisplayOrDash(row.createTime) }}</span>
</div>
<div class="list-body list-wrap payment-confirm-table-wrap">
<el-table
class="list-table"
:data="pendingData"
v-loading="pendingLoading"
stripe
row-key="id"
:key="'pending-' + mainTab"
@row-dblclick="openConfirm"
>
<el-table-column
type="index"
label="序号"
min-width="68"
align="center"
header-align="center"
:index="
(index) => (pendingPagination.page - 1) * pendingPagination.pageSize + index + 1
"
/>
<el-table-column
prop="protocolNo"
label="协议号"
min-width="140"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.protocolNo || '-' }}</template>
</el-table-column>
<el-table-column
prop="sampleCode"
:label="isPresignTab ? '样本类型' : '样本编码'"
min-width="140"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">
{{ isPresignTab ? row.sampleTypeNames || '-' : row.sampleCode || '-' }}
</template>
</el-table-column>
<el-table-column
prop="motherName"
label="客户姓名"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.motherName || '-' }}</template>
</el-table-column>
<el-table-column
v-if="!isPresignTab"
prop="motherIdCard"
label="身份证号"
min-width="170"
align="center"
header-align="center"
>
<template #default="{ row }">{{ maskIdCard(row.motherIdCard) }}</template>
</el-table-column>
<el-table-column
:prop="isPresignTab ? 'orderStatus' : 'protocolStatus'"
:label="isPresignTab ? '订单状态' : '协议状态'"
min-width="120"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-tag
v-if="isPresignTab"
:type="presignOrderStatusTagType(String(row.orderStatus || ''))"
size="small"
>
{{ presignOrderStatusLabel(String(row.orderStatus || '')) }}
</el-tag>
<el-tag
v-else
:type="protocolStatusTagType(String(row.protocolStatus || ''))"
size="small"
>{{
protocolStatusDisplayLabel(
String(row.protocolStatus || ''),
String(row.voidType || '')
)
}}</el-tag
>
</template>
</el-table-column>
<el-table-column
v-if="!isPresignTab"
prop="payMode"
label="缴费方式"
min-width="110"
align="center"
header-align="center"
>
<template #default="{ row }">{{ payModeLabel(String(row.payMode || '')) }}</template>
</el-table-column>
<el-table-column
v-if="!isPresignTab"
prop="installmentNo"
label="期数"
min-width="80"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.installmentNo ?? '-' }}</template>
</el-table-column>
<el-table-column
:prop="isPresignTab ? 'orderDate' : 'installmentDueDate'"
:label="isPresignTab ? '业务日期' : '应缴费时间'"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">{{
isPresignTab
? formatPaymentDueDate(row.orderDate)
: formatPaymentDueDate(row.installmentDueDate)
}}</template>
</el-table-column>
<el-table-column
:prop="isPresignTab ? 'contractAmount' : 'dueAmount'"
:label="isPresignTab ? '合同金额(元)' : '应缴金额(元)'"
min-width="140"
align="center"
header-align="center"
>
<template #default="{ row }">{{
isPresignTab
? formatPaymentAmount(row.contractAmount)
: formatPaymentAmount(row.dueAmount)
}}</template>
</el-table-column>
<el-table-column
prop="transferAmount"
:label="isPresignTab ? '意向金(元)' : '实缴金额(元)'"
min-width="130"
align="center"
header-align="center"
>
<template #default="{ row }">{{ formatPaymentAmount(row.transferAmount) }}</template>
</el-table-column>
<el-table-column
prop="transferType"
label="转账方式"
min-width="110"
align="center"
header-align="center"
>
<template #default="{ row }">{{
transferTypeLabel(String(row.transferType || ''))
}}</template>
</el-table-column>
<el-table-column
prop="transferTime"
label="转账时间"
min-width="170"
align="center"
header-align="center"
>
<template #default="{ row }">{{ formatDisplayOrDash(row.transferTime) }}</template>
</el-table-column>
<el-table-column
prop="remark"
label="备注"
min-width="120"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.remark || '—' }}</template>
</el-table-column>
<el-table-column
prop="payStatus"
label="状态"
min-width="110"
align="center"
header-align="center"
>
<template #default>
<el-tag type="warning" size="small">付款确认中</el-tag>
</template>
</el-table-column>
<el-table-column
prop="createTime"
label="提交时间"
min-width="170"
align="center"
header-align="center"
>
<template #default="{ row }">{{ formatDisplayOrDash(row.createTime) }}</template>
</el-table-column>
<el-table-column
label="操作"
min-width="140"
fixed="right"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-button class="btn-op-item primary" @click="openConfirm(row)">
<el-icon><Check /></el-icon>确认收款
</el-button>
</div>
</article>
</div>
<div v-else-if="!pendingLoading" class="finance-empty">暂无待确认记录</div>
<div v-if="pendingPagination.total > 0" class="pagination list-pager-bar pending-pager">
</template>
</el-table-column>
</el-table>
<div class="pagination list-pager-bar">
<el-pagination
:current-page="pendingPagination.page"
:page-size="pendingPagination.pageSize"
@@ -436,7 +547,7 @@
header-align="center"
>
<template #default>
<el-tag type="success" size="small">缴费成功</el-tag>
<el-tag type="success" size="small">付款完成</el-tag>
</template>
</el-table-column>
<el-table-column
@@ -572,7 +683,6 @@
</el-dialog>
</div>
<InvoiceRequestTab v-if="mainTab === 'invoice'" @action-done="loadTabPendingCounts" />
</section>
</div>
</template>
@@ -582,7 +692,6 @@
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Close, Check, RefreshLeft, Search, View } from '@element-plus/icons-vue'
import { fetchProtocolInvoicePendingCount } from '@/api/collection-protocol'
import {
fetchPaymentTransferReceiptConfirmList,
fetchPaymentTransferReceiptConfirmedList,
@@ -616,23 +725,19 @@
presignOrderStatusTagType
} from '@/utils/status-tag-registry'
import { formatMoneyDisplay } from '@/utils/money-format'
import InvoiceRequestTab from './InvoiceRequestTab.vue'
defineOptions({ name: 'CellStoragePaymentConfirm' })
const route = useRoute()
const mainTab = ref<'presign' | 'formal' | 'invoice'>(
String(route.query.tab || '') === 'invoice'
? 'invoice'
: String(route.query.tab || '') === 'formal' || String(route.query.tab || '') === 'payment'
? 'formal'
: 'presign'
const mainTab = ref<'presign' | 'formal'>(
String(route.query.tab || '') === 'formal' || String(route.query.tab || '') === 'payment'
? 'formal'
: 'presign'
)
const isPaymentTab = computed(() => mainTab.value === 'presign' || mainTab.value === 'formal')
const isPresignTab = computed(() => mainTab.value === 'presign')
const presignPendingBadge = ref(0)
const formalPendingBadge = ref(0)
const invoicePendingBadge = ref(0)
function formatTabBadgeCount(count: number): string {
return count > 99 ? '99+' : String(count)
@@ -647,19 +752,6 @@
return String(row?.source || '') === 'presign'
}
function cardSubtitle(row: Record<string, unknown>) {
const parts: string[] = []
const protocolNo = String(row.protocolNo || '').trim()
if (protocolNo) parts.push(protocolNo)
if (!isPresignRow(row)) {
const sampleCode = String(row.sampleCode || '').trim()
if (sampleCode) parts.push(sampleCode)
const idCard = String(row.motherIdCard || '').trim()
if (idCard) parts.push(maskIdCard(idCard))
}
return parts.join(' · ')
}
const pendingSearchForm = reactive({ keyword: '' })
const confirmedSearchForm = reactive({ keyword: '' })
const pendingInstallmentDueDateRange = ref<[string, string] | null>(null)
@@ -716,14 +808,12 @@
async function loadTabPendingCounts() {
try {
const [paymentRes, presignRes, invRes] = await Promise.all([
const [paymentRes, presignRes] = await Promise.all([
fetchPaymentTransferReceiptConfirmList({ page: 1, pageSize: 1 }),
fetchPresignTransferReceiptConfirmList({ page: 1, pageSize: 1 }),
fetchProtocolInvoicePendingCount()
fetchPresignTransferReceiptConfirmList({ page: 1, pageSize: 1 })
])
formalPendingBadge.value = paymentRes.total ?? 0
presignPendingBadge.value = presignRes.total ?? 0
invoicePendingBadge.value = Number(invRes?.count ?? 0)
} catch {
// 角标加载失败时保留上次数值,避免干扰主流程
}
@@ -840,7 +930,7 @@
async function submitReject() {
if (!currentDetailId.value) return
try {
await ElMessageBox.confirm('确定退回?退回后状态将变为「已缴费」。', '退回确认', {
await ElMessageBox.confirm('确定退回?退回后状态将变为「已付款」。', '退回确认', {
type: 'warning'
})
} catch {
@@ -887,9 +977,8 @@
}
})
watch(mainTab, (tab) => {
watch(mainTab, () => {
loadTabPendingCounts()
if (tab === 'invoice') return
pendingPagination.page = 1
confirmedPagination.page = 1
loadAll()
@@ -921,182 +1010,6 @@
padding-right: 12px;
}
.pending-card-section {
min-height: 80px;
padding: 0 0 4px;
}
.pending-card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
gap: 16px;
padding: 16px 24px 8px;
}
.pending-card {
display: flex;
flex-direction: column;
gap: 14px;
border: 1px solid var(--mint-border, #e2e8f0);
border-radius: 12px;
background: #fff;
padding: 20px 22px 16px;
transition:
border-color 0.15s,
box-shadow 0.15s;
&:hover {
border-color: #a7f3d0;
box-shadow: 0 4px 14px rgb(15 23 42 / 6%);
}
}
.pending-card__head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
}
.pending-card__name {
font-size: 18px;
font-weight: 600;
color: var(--text, #1e293b);
line-height: 1.3;
}
.pending-card__sub {
margin-top: 4px;
font-size: 12px;
color: var(--mint-text-muted, #64748b);
line-height: 1.4;
}
.pending-card__amount {
flex-shrink: 0;
text-align: right;
}
.pending-card__amount-val {
font-size: 22px;
font-weight: 700;
color: var(--primary-dark, #059669);
font-variant-numeric: tabular-nums;
line-height: 1.2;
}
.pending-card__amount-label {
margin-top: 4px;
font-size: 12px;
color: var(--mint-text-muted, #64748b);
}
.pending-card__transfer {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 8px 16px;
padding: 10px 12px;
background: var(--primary-bg, #ecfdf5);
border-radius: 8px;
}
.pending-card__transfer-way {
font-size: 13px;
font-weight: 600;
color: var(--primary-dark, #059669);
}
.pending-card__transfer-time {
font-size: 13px;
color: var(--mint-text, #334155);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.pending-card__remark {
font-size: 12px;
color: var(--mint-text-muted, #64748b);
word-break: break-all;
}
.pending-card__facts {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px 24px;
}
.pending-card__field label {
display: block;
margin-bottom: 4px;
font-size: 12px;
color: var(--mint-text-muted, #64748b);
}
.pending-card__field span {
font-size: 14px;
color: var(--text, #1e293b);
line-height: 1.4;
word-break: break-word;
}
.pending-card__field em {
display: inline-block;
margin-left: 6px;
font-size: 12px;
font-style: normal;
color: var(--mint-text-muted, #64748b);
}
.pending-card__samples {
padding-top: 2px;
label {
display: block;
margin-bottom: 4px;
font-size: 12px;
color: var(--mint-text-muted, #64748b);
}
p {
margin: 0;
font-size: 13px;
color: var(--mint-text, #334155);
line-height: 1.55;
}
}
.pending-card__foot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 2px;
padding-top: 12px;
border-top: 1px solid #f1f5f9;
}
.pending-card__meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--mint-text-muted, #64748b);
}
.pending-pager {
padding: 0 24px;
}
.finance-empty {
padding: 32px 24px;
text-align: center;
font-size: 13px;
color: var(--mint-text-muted, #64748b);
}
.payment-confirm-table-wrap {
overflow-x: auto;
}
@@ -1137,13 +1050,4 @@
}
}
@media (max-width: 900px) {
.pending-card-grid {
grid-template-columns: 1fr;
}
.pending-card__facts {
grid-template-columns: 1fr;
}
}
</style>
@@ -447,7 +447,7 @@
const progressStatusOptions = [
{ value: 'dfj', label: '待缴费' },
{ value: 'jfqrz', label: '缴费确认中' },
{ value: 'jfqrz', label: '付款确认中' },
{ value: 'bfyj', label: '部分已缴' },
{ value: 'yjq', label: '已缴清' }
]
@@ -1,4 +1,4 @@
<!-- 缴费信息 · 按转账笔状态列表(已缴费 / 确认中 / 成功) -->
<!-- 缴费信息 · 按转账笔状态列表(已付款 / 付款确认中 / 付款完成) -->
<template>
<div class="payment-info-tab">
<div class="filter-block">
@@ -175,10 +175,14 @@
</div>
</div>
<div
v-if="row.freight?.id || row.freight?.transportMode"
v-if="
row.freight?.id ||
row.freight?.transportMode ||
row.transport?.etaTime
"
class="sample-card__section sample-card__section--transport"
>
<div class="sample-card__section-label">运费信息</div>
<div class="sample-card__section-label">运输与运费</div>
<div class="data-grid data-grid--4">
<div class="data-item">
<div class="data-label">运输方式</div>
@@ -198,6 +202,10 @@
}}</div
>
</div>
<div class="data-item">
<div class="data-label">预计到达</div>
<div class="data-value">{{ dash(row.transport?.etaTime) }}</div>
</div>
</div>
</div>
<div class="sample-card__section sample-card__section--reception">
@@ -1756,7 +1764,7 @@
return {
key: `ov-${i}`,
label: name,
subLabel: '缴费成功',
subLabel: '付款完成',
dotClass: 'done',
dotIcon: '✓',
labelClass: 'done',
@@ -1777,7 +1785,7 @@
return {
key: `ov-${i}`,
label: name,
subLabel: '已缴费',
subLabel: '已付款',
dotClass: 'pending',
dotIcon: '○',
labelClass: ''
@@ -442,7 +442,7 @@
return '¥' + formatMoneyDisplay(v)
}
/** 仅财务已确认(yjf)锁定;缴费确认中仍可改,直至财务确认 */
/** 仅财务已确认(yjf)锁定;付款确认中仍可改,直至财务确认 */
function isTransferLocked(tr: Record<string, any>) {
return tr.payStatus === 'yjf'
}
@@ -833,7 +833,7 @@
async function submitReject() {
if (!currentDetailId.value) return
try {
await ElMessageBox.confirm('确定退回?退回后状态将变为「已缴费」。', '退回确认', {
await ElMessageBox.confirm('确定退回?退回后状态将变为「付款完成」。', '退回确认', {
type: 'warning'
})
} catch {
@@ -114,7 +114,7 @@
</div>
<div class="pending-card__foot">
<div class="pending-card__meta">
<el-tag type="warning" size="small">缴费确认中</el-tag>
<el-tag type="warning" size="small">付款确认中</el-tag>
<span>提交 {{ formatDisplayOrDash(row.createTime) }}</span>
</div>
<el-button class="btn-op-item primary" @click="openConfirm(row)">
@@ -286,7 +286,7 @@
header-align="center"
>
<template #default>
<el-tag type="success" size="small">已缴费</el-tag>
<el-tag type="success" size="small">付款完成</el-tag>
</template>
</el-table-column>
<el-table-column
@@ -569,8 +569,8 @@
const kanbanColumns: KanbanColumnDef[] = [
{ key: 'dfj', label: '待缴费' },
{ key: 'jfqrz', label: '缴费确认中' },
{ key: 'yjf', label: '已缴费' },
{ key: 'jfqrz', label: '付款确认中' },
{ key: 'yjf', label: '付款完成' },
{ key: 'tfqrz', label: '退费确认中' },
{ key: 'ytf', label: '已退费' }
]