This commit is contained in:
2026-08-17 16:45:46 +08:00
parent 4a9438315c
commit d95c90bd1a
48 changed files with 1217 additions and 374 deletions
@@ -133,8 +133,8 @@ function formatDateTime(value: unknown) {
}
function displayOperator(value: unknown) {
const operator = String(value || '').trim()
if (!operator) return '系统'
return /^(?:operator-)?\d+$/i.test(operator) ? '操作人信息缺失' : operator
if (!operator) return '名称数据缺失'
return /^(?:operator-)?\d+$/i.test(operator) ? '名称数据缺失' : operator
}
const filteredRows = computed(() => {
const keyword = String(filters.value.keyword || '').trim().toLowerCase(); const direction = String(filters.value.direction || ''); const reviewStatus = String(filters.value.reviewStatus || '')
@@ -210,10 +210,16 @@ function statusLabel(status: string) { return financeStatusLabel(status) }
function money(value: unknown) { return Number(value || 0).toFixed(2) }
function onSelectionChange(rows: ArapRow[]) { selectedRows.value = rows }
function openGeneration(mode: 'BY_CUTOFF' | 'SELECTED') {
generationForm.mode = mode; generationForm.customerId = String(filters.value.customerId || ''); generationForm.period = Array.isArray(filters.value.businessRange) ? filters.value.businessRange.map(String) : []; generationForm.cutoffDate = generationForm.period[1] || ''; generationForm.remark = ''; generationError.value = null; generationOpen.value = true
generationForm.mode = mode
generationForm.customerId = ''
generationForm.period = Array.isArray(filters.value.businessRange) ? filters.value.businessRange.map(String) : []
generationForm.cutoffDate = generationForm.period[1] || ''
generationForm.remark = ''
generationError.value = null
generationOpen.value = true
}
async function submitGeneration() {
const eligible = selectedRows.value.filter((row) => row.feeSourceId && row.direction === 'RECEIVABLE' && row.reviewStatus === 'APPROVED' && row.settlementIncluded === true && row.statementGenerated === false)
const eligible = selectedRows.value.filter((row) => row.feeSourceId && row.direction === 'RECEIVABLE' && row.reviewStatus === 'APPROVED' && row.settlementIncluded === true && row.statementGenerated === false && row.customerId === generationForm.customerId)
const period = generationForm.period
if (!generationForm.customerId || !period[0] || !period[1]) { ElMessage.warning('请选择客户和业务期间'); return }
if (generationForm.mode === 'SELECTED' && !eligible.length) { ElMessage.warning('请选择审核通过、参与结算且未出账的应收费用'); return }
@@ -251,7 +257,7 @@ watch(() => [route.name, String(route.params.feeSourceId || '')], ([name, feeSou
<template v-if="stateError" #state><LoadErrorState title="客户应收应付加载失败" :message="stateError.message" :loading="customersLoading || loading" @retry="customersError ? loadCustomers() : load()"><template #details><ApiErrorMeta :details="stateError" /></template></LoadErrorState></template>
<section v-if="!customersError && !loadError" class="surface-panel table-panel">
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :loading="loading" :total="filteredRows.length" preference-key="finance-customer-arap-table" aria-label="客户应收应付列表" row-key="id" empty-text="暂无客户应收应付数据" @selection-change="onSelectionChange">
<template #toolbar-actions><div v-if="canCreateStatement" class="generation-actions"><el-button :disabled="!filters.customerId" @click="openGeneration('BY_CUTOFF')"><FilePlus2 :size="16" />按截止日期生成</el-button><el-button type="primary" :disabled="!selectedRows.length" @click="openGeneration('SELECTED')"><FilePlus2 :size="16" />按勾选生成</el-button></div></template>
<template #toolbar-actions><div v-if="canCreateStatement" class="generation-actions"><el-button @click="openGeneration('BY_CUTOFF')"><FilePlus2 :size="16" />按截止日期生成</el-button><el-button type="primary" :disabled="!selectedRows.length" @click="openGeneration('SELECTED')"><FilePlus2 :size="16" />按勾选生成</el-button></div></template>
<template #actions="{ row }"><div class="row-actions"><template v-if="row.feeSourceId"><el-button v-if="canViewSource" link type="primary" @click="openDetail(row)"><Eye :size="15" />详情</el-button><el-button v-if="canReviewSource" link type="primary" @click="openReview(row)"><FileCheck2 :size="15" />审核</el-button><el-button v-if="canSettleSource" link type="primary" @click="openInclusion(row)"><Link2 :size="15" />结算</el-button></template><span v-else class="muted-action">手工成本</span></div></template>
<template #customerName="{ row }">{{ customerName(row.customerId, row.customerName) }}</template><template #direction="{ row }"><el-tag :type="row.direction === 'RECEIVABLE' ? 'success' : row.direction === 'PAYABLE' ? 'warning' : 'info'">{{ financeDirectionLabel(row.direction) }}</el-tag></template>
<template #documentNo="{ row }">{{ feeDocumentLabel(row.direction, row.feeName) }}</template><template #sourceType="{ row }">{{ sourceTypeDisplay(row.sourceType) }}</template><template #sourceId="{ row }">{{ row.sourceId }}</template>
@@ -287,41 +293,246 @@ watch(() => [route.name, String(route.params.feeSourceId || '')], ([name, feeSou
</template>
<style scoped>
.finance-arap-page { min-width: 0; }
.finance-arap-detail { width: 100%; min-width: 0; }
.finance-arap-detail__surface { width: min(100%, 1600px); margin: 0 auto; overflow: hidden; }
.finance-arap-detail__layout { width: 100%; margin: 0 auto; }
.finance-arap-detail__layout :deep(.detail-page-layout) { gap: 0; }
.finance-arap-detail__layout :deep(.detail-page-layout__header) { min-height: 72px; align-items: center; padding: 16px 24px; border-bottom: 1px solid var(--cc-border, #e3e8ef); }
.finance-arap-detail__layout :deep(.detail-page-layout__summary) { padding: 16px 24px 0; }
.finance-arap-detail__layout :deep(.detail-page-layout__content) { padding: 0 24px 20px; }
.row-actions { display: flex; align-items: center; gap: 4px; white-space: nowrap; }
.row-actions .el-button { margin-left: 0; }
.generation-actions,.detail-heading,.detail-actions { display: flex; align-items: center; gap: 8px; }
.detail-heading { min-width: 0; align-items: flex-start; }
.detail-title { min-width: 0; }
.detail-heading h2 { margin: 0; font-size: 18px; }
.detail-heading p { overflow: hidden; margin: 4px 0 0; color: var(--cc-muted); text-overflow: ellipsis; white-space: nowrap; }
.detail-actions { margin-left: auto; }
.muted-action { color: var(--cc-muted); }
.arap-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; padding: 0 0 16px; border-bottom: 1px solid var(--cc-border, #e3e8ef); }
.arap-metric { min-width: 0; padding: 0 20px; }
.arap-metric:first-child { padding-left: 0; }
.arap-metric + .arap-metric { border-left: 1px solid var(--cc-border, #e3e8ef); }
.arap-metric span { display: block; color: var(--cc-muted); font-size: 12px; }
.arap-metric strong { display: inline-block; margin-top: 7px; color: var(--cc-text); font-size: 20px; line-height: 1.1; font-variant-numeric: tabular-nums; }
.arap-metric small { margin-left: 6px; color: var(--cc-muted); font-size: 11px; }
.arap-metric.is-amount strong { color: #4f46e5; }
.arap-detail-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(360px, .65fr); gap: 24px; border-bottom: 1px solid var(--cc-border, #e3e8ef); }
.arap-information,.arap-settlement,.operation-log { padding: 16px 0; }
.arap-settlement { padding-left: 24px; border-left: 1px solid var(--cc-border, #e3e8ef); }
.operation-log { min-height: 150px; }
:deep(.arap-detail .el-descriptions__content) { min-width: 0; overflow-wrap: anywhere; }
:deep(.arap-detail .el-descriptions__label) { width: 112px; color: var(--cc-muted); }
.operation-log :deep(.el-empty) { padding: 12px 0 4px; }
.operation-log :deep(.el-empty__image) { display: none; }
.operation-log small { display: block; margin-top: 4px; color: var(--cc-muted); }
@media (max-width: 1080px) { .finance-arap-detail__surface { width: 100%; } .arap-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); } .arap-metric:nth-child(3) { padding-left: 0; border-left: 0; } .arap-detail-grid { grid-template-columns: 1fr; gap: 0; } .arap-settlement { padding-left: 0; border-left: 0; border-top: 1px solid var(--cc-border, #e3e8ef); } }
@media (max-width: 720px) { .detail-heading { align-items: stretch; flex-direction: column; } .detail-actions { margin-left: 0; } .arap-metrics { grid-template-columns: 1fr; gap: 12px; } .arap-metric,.arap-metric:first-child,.arap-metric:nth-child(3) { padding-left: 0; } .arap-metric + .arap-metric { border-left: 0; } :deep(.arap-detail .el-descriptions__body .el-descriptions__table) { table-layout: fixed; } }
@media (max-width: 480px) { :deep(.arap-detail .el-descriptions__cell) { display: block; width: 100%; } }
.finance-arap-page {
min-width: 0;
}
.finance-arap-detail {
width: 100%;
min-width: 0;
}
.finance-arap-detail__surface {
width: min(100%, 1920px);
margin: 0 auto;
overflow: hidden;
}
.finance-arap-detail__layout {
width: 100%;
margin: 0 auto;
}
.finance-arap-detail__layout :deep(.detail-page-layout) {
gap: 0;
}
.finance-arap-detail__layout :deep(.detail-page-layout__header) {
min-height: 64px;
align-items: center;
padding: 12px 16px;
border-bottom: 1px solid var(--cc-border, #e3e8ef);
}
.finance-arap-detail__layout :deep(.detail-page-layout__summary) {
padding: 10px 16px 0;
}
.finance-arap-detail__layout :deep(.detail-page-layout__content) {
padding: 0 16px 12px;
}
.row-actions {
display: flex;
align-items: center;
gap: 4px;
white-space: nowrap;
}
.row-actions .el-button {
margin-left: 0;
}
.generation-actions,
.detail-heading,
.detail-actions {
display: flex;
align-items: center;
gap: 8px;
}
.detail-heading {
min-width: 0;
align-items: flex-start;
}
.detail-title {
min-width: 0;
}
.detail-heading h2 {
margin: 0;
font-size: 18px;
}
.detail-heading p {
overflow: hidden;
margin: 3px 0 0;
color: var(--cc-muted);
text-overflow: ellipsis;
white-space: nowrap;
}
.detail-actions {
margin-left: auto;
}
.muted-action {
color: var(--cc-muted);
}
.arap-metrics {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 0;
padding: 0 0 12px;
border-bottom: 1px solid var(--cc-border, #e3e8ef);
}
.arap-metric {
min-width: 0;
padding: 0 12px;
}
.arap-metric:first-child {
padding-left: 0;
}
.arap-metric + .arap-metric {
border-left: 1px solid var(--cc-border, #e3e8ef);
}
.arap-metric span {
display: block;
color: var(--cc-muted);
font-size: 12px;
}
.arap-metric strong {
display: inline-block;
margin-top: 6px;
color: var(--cc-text);
font-size: 20px;
line-height: 1.1;
font-variant-numeric: tabular-nums;
}
.arap-metric small {
margin-left: 6px;
color: var(--cc-muted);
font-size: 11px;
}
.arap-metric.is-amount strong {
color: #4f46e5;
}
.arap-detail-grid {
display: grid;
grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.65fr);
gap: 16px;
border-bottom: 1px solid var(--cc-border, #e3e8ef);
}
.arap-information,
.arap-settlement,
.operation-log {
padding: 10px 0;
}
.arap-settlement {
padding-left: 16px;
border-left: 1px solid var(--cc-border, #e3e8ef);
}
.operation-log {
min-height: 150px;
}
:deep(.arap-detail .el-descriptions__content) {
min-width: 0;
overflow-wrap: anywhere;
}
:deep(.arap-detail .el-descriptions__label) {
width: 112px;
color: var(--cc-muted);
}
.operation-log :deep(.el-empty) {
padding: 10px 0 2px;
}
.operation-log :deep(.el-empty__image) {
display: none;
}
.operation-log small {
display: block;
margin-top: 4px;
color: var(--cc-muted);
}
@media (max-width: 1080px) {
.finance-arap-detail__surface {
width: 100%;
}
.arap-metrics {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.arap-metric:nth-child(3) {
padding-left: 0;
border-left: 0;
}
.arap-detail-grid {
grid-template-columns: 1fr;
gap: 0;
}
.arap-settlement {
padding-left: 0;
border-left: 0;
border-top: 1px solid var(--cc-border, #e3e8ef);
}
}
@media (max-width: 720px) {
.detail-heading {
align-items: stretch;
flex-direction: column;
}
.detail-actions {
margin-left: 0;
}
.arap-metrics {
grid-template-columns: 1fr;
gap: 12px;
}
.arap-metric,
.arap-metric:first-child,
.arap-metric:nth-child(3) {
padding-left: 0;
}
.arap-metric + .arap-metric {
border-left: 0;
}
:deep(.arap-detail .el-descriptions__body .el-descriptions__table) {
table-layout: fixed;
}
}
@media (max-width: 480px) {
:deep(.arap-detail .el-descriptions__cell) {
display: block;
width: 100%;
}
}
</style>