This commit is contained in:
2026-10-20 23:34:11 +08:00
parent f155976f52
commit 13e4aa56ec
321 changed files with 6756 additions and 2110 deletions
@@ -1,4 +1,5 @@
<script setup lang="ts">
import '@/styles/adminWorkbench.css'
import '@/styles/adminDensity.css'
import '../financeDensity.css'
import { computed, onMounted, ref, watch } from 'vue'
@@ -453,7 +454,7 @@ async function submitPayment() {
async function performAction(row: SettlementRow, action: 'VOID' | 'REOPEN') {
const reason = await ElMessageBox.prompt('请输入操作原因', `${action === 'VOID' ? '作废' : '重开'}${title.value} · ${row.settlementNo || '—'}`, {
customClass: 'admin-density-confirm',
customClass: 'admin-density-confirm admin-workbench',
inputType: 'textarea', inputPattern: /\S+/, inputErrorMessage: '操作原因不能为空', confirmButtonText: '确认', cancelButtonText: '取消',
}).then((result) => result.value.trim()).catch(() => null)
if (reason === null) return
@@ -519,12 +520,12 @@ onMounted(() => {
</script>
<template>
<AdminPage as="div" class="finance-settlement-page admin-density" spacing="normal">
<AdminPage as="div" class="finance-settlement-page admin-density admin-workbench" spacing="normal">
<OperationErrorToast v-if="createOpen || paymentOpen" :details="error" />
<OperationErrorToast :message="receiptValidationError" />
<OperationErrorToast :details="receiptError" />
<el-result v-if="!canView" icon="warning" :title="`无权访问${title}`" sub-title="请联系管理员开通结算单查看权限" />
<DetailPageLayout v-else-if="detailMode" class="settlement-detail-page surface-panel finance-density-detail" :aria-label="`${title}详情`">
<DetailPageLayout v-else-if="detailMode" class="settlement-detail-page surface-panel finance-density-detail workbench-panel is-flush is-page-surface" :aria-label="`${title}详情`">
<template #header><div class="density-detail-header"><div class="density-detail-heading"><el-button link class="density-back" aria-label="返回列表" @click="backToList"><ArrowLeft :size="16" />返回列表</el-button><h1 class="density-detail-title">{{ detail?.settlementNo || '—' }}</h1><StatusBadge v-if="detail" :status="financeStatusLabel(detail.status)" /></div><div class="finance-detail-actions">
<el-button v-if="detail && canExport" :loading="exportSubmitting" :disabled="exportSubmitting" @click="exportDetail"><Download :size="15" />导出</el-button>
<el-button v-if="detail && canReceive && ['ISSUED','PARTIALLY_PAID'].includes(detail.status)" type="primary" :loading="receiptBusy" @click="openReceiptFromDetail"><HandCoins :size="15" />部分收款</el-button>
@@ -562,7 +563,7 @@ onMounted(() => {
</el-descriptions>
</FormSection>
<FormSection class="density-form-section" title="费用明细">
<div class="detail-table-scroll">
<div class="detail-table-scroll workbench-table">
<el-table :data="detail.lines" size="small" border stripe empty-text="暂无费用明细">
<el-table-column prop="feeItemName" label="费用类型" min-width="150" />
<el-table-column prop="sourceType" label="来源类型" min-width="140"><template #default="scope">{{ financeSourceTypeLabel(scope.row.sourceType) }}</template></el-table-column>
@@ -575,7 +576,7 @@ onMounted(() => {
</div>
</FormSection>
<FormSection class="density-form-section" :title="kind === 'receivable' ? '收款记录' : '付款记录'">
<div class="detail-table-scroll">
<div class="detail-table-scroll workbench-table">
<el-table :data="detail.transactions" size="small" border stripe :empty-text="kind === 'receivable' ? '暂无收款记录' : '暂无付款记录'">
<el-table-column prop="transactionDate" :label="kind === 'receivable' ? '收款日期' : '付款日期'" width="130" />
<el-table-column prop="amount" label="金额(CNY)" width="130" align="right"><template #default="scope">{{ money(scope.row.amount) }}</template></el-table-column>
@@ -589,7 +590,7 @@ onMounted(() => {
</div>
</FormSection>
<FormSection class="density-form-section" title="修订记录" :bordered="false">
<div class="detail-table-scroll">
<div class="detail-table-scroll workbench-table">
<el-table :data="detail.revisions" size="small" border stripe empty-text="暂无调整记录">
<el-table-column prop="action" label="动作" min-width="120"><template #default="scope">{{ settlementRevisionActionLabel(scope.row.action) || financeOperationActionLabel(scope.row.action) }}</template></el-table-column>
<el-table-column prop="beforeAmount" label="调整前(CNY)" width="140" align="right"><template #default="scope">{{ money(scope.row.beforeAmount) }}</template></el-table-column>
@@ -605,7 +606,7 @@ onMounted(() => {
<ListPageLayout v-else :aria-label="title">
<section><DataTable :preference-key="`finance-settlement-${kind}-table`" appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="!customerError && !error" v-model:page="page" v-model:page-size="pageSize" :data="paginatedRows" :columns="columns" :loading="loading" :total="filteredRows.length" :aria-label="`${title}列表`" row-key="id" empty-text="暂无符合条件的结算单">
<section class="workbench-table is-page-surface"><DataTable :preference-key="`finance-settlement-${kind}-table`" appearance="integrated" :stripe="false" column-settings-mode="show" :results-visible="!customerError && !error" v-model:page="page" v-model:page-size="pageSize" :data="paginatedRows" :columns="columns" :loading="loading" :total="filteredRows.length" :aria-label="`${title}列表`" row-key="id" empty-text="暂无符合条件的结算单">
<template #toolbar-start><h1>{{ title }}</h1></template>
<template #filters>
<QueryToolbar v-model="filters" :ariaLabel="`${title}筛选`" :fields="fields" :preference-key="`finance-settlement-${kind}-query`" :search-on-clear="false" @search="load" />
@@ -654,8 +655,8 @@ onMounted(() => {
</DataTable></section>
</ListPageLayout>
<AppDialog class="admin-density-dialog" v-model="createOpen" :title="`生成${title}`" width="min(600px, 94vw)" fullscreenable :confirm-loading="createBusy" @confirm="submitCreate">
<section class="density-dialog-section" data-tone="work" aria-label="结算单生成设置"><h3 class="density-dialog-section__title">生成设置</h3>
<AppDialog class="admin-density-dialog admin-workbench is-dialog" v-model="createOpen" :title="`生成${title}`" width="min(600px, 94vw)" fullscreenable :confirm-loading="createBusy" @confirm="submitCreate">
<section class="density-dialog-section workbench-evidence" data-tone="work" aria-label="结算单生成设置"><h3 class="density-dialog-section__title">生成设置</h3>
<el-form class="density-form" label-position="left" label-width="120px" :disabled="createBusy"><table class="density-table density-table--editable"><tbody>
<tr><td><el-form-item label="客户"><el-select v-model="createForm.customerId" filterable placeholder="请选择客户"><el-option v-for="item in activeCustomers" :key="String(item.id)" :label="item.tenantName" :value="String(item.id)" /></el-select></el-form-item></td></tr>
<tr><td><el-form-item label="币种"><span>CNY</span></el-form-item></td></tr>
@@ -669,16 +670,16 @@ onMounted(() => {
</section>
</AppDialog>
<AppDialog class="admin-density-dialog" v-model="paymentOpen" :title="`登记付款 · ${detail?.settlementNo || '—'}`" width="min(760px, 94vw)" fullscreenable :confirm-loading="paymentBusy" @confirm="submitPayment">
<AppDialog class="admin-density-dialog admin-workbench is-dialog" v-model="paymentOpen" :title="`登记付款 · ${detail?.settlementNo || '—'}`" width="min(760px, 94vw)" fullscreenable :confirm-loading="paymentBusy" @confirm="submitPayment">
<div class="density-dialog-sections">
<section v-if="detail" class="density-dialog-section partial-summary" data-tone="summary" aria-label="当前结算资料"><h3 class="density-dialog-section__title">当前结算(CNY)</h3>
<section v-if="detail" class="density-dialog-section partial-summary workbench-evidence" data-tone="summary" aria-label="当前结算资料"><h3 class="density-dialog-section__title">当前结算(CNY)</h3>
<table class="density-table settlement-dialog-facts"><tbody>
<tr><th scope="row">结算单号</th><td>{{ detail.settlementNo || '—' }}</td><th scope="row">供应商</th><td>{{ detailPartyName() }}</td></tr>
<tr><th scope="row">应付金额</th><td>{{ money(detail.amount) }}</td><th scope="row">已付金额</th><td class="is-success">{{ money(detail.paidAmount) }}</td></tr>
<tr><th scope="row">当前余额</th><td colspan="3" class="is-danger">{{ money(detail.outstandingAmount) }}</td></tr>
</tbody></table>
</section>
<section class="density-dialog-section" data-tone="work" aria-label="付款登记"><h3 class="density-dialog-section__title">付款登记</h3>
<section class="density-dialog-section workbench-evidence" data-tone="work" aria-label="付款登记"><h3 class="density-dialog-section__title">付款登记</h3>
<el-form class="settlement-operation-form density-form" label-position="left" label-width="140px" :disabled="paymentBusy"><table class="density-table density-table--editable settlement-operation-table"><tbody>
<tr><td><el-form-item label="付款日期"><el-date-picker v-model="paymentForm.transactionDate" type="date" value-format="YYYY-MM-DD" /></el-form-item></td><td><el-form-item label="本次付款金额(CNY)"><el-input-number v-model="paymentForm.amount" :min="0.01" :max="detail?.outstandingAmount || 0.01" :precision="2" placeholder="请输入付款金额" /></el-form-item></td></tr>
<tr><td><el-form-item label="付款方式"><el-select v-model="paymentForm.method"><el-option label="银行转账" value="BANK_TRANSFER" /><el-option label="现金" value="CASH" /><el-option label="其他" value="OTHER" /></el-select></el-form-item></td><td><el-form-item label="银行流水号/凭证号"><el-input v-model="paymentForm.referenceNo" placeholder="请输入付款流水号" /></el-form-item></td></tr>
@@ -690,16 +691,16 @@ onMounted(() => {
</div>
</AppDialog>
<AppDialog class="admin-density-dialog" v-model="receiptOpen" :title="`登记收款 · ${detail?.settlementNo || '—'}`" width="min(760px, 94vw)" fullscreenable :confirm-loading="receiptBusy" @confirm="submitReceipt">
<AppDialog class="admin-density-dialog admin-workbench is-dialog" v-model="receiptOpen" :title="`登记收款 · ${detail?.settlementNo || '—'}`" width="min(760px, 94vw)" fullscreenable :confirm-loading="receiptBusy" @confirm="submitReceipt">
<div class="density-dialog-sections">
<section v-if="detail" class="density-dialog-section partial-summary" data-tone="summary" aria-label="当前结算资料"><h3 class="density-dialog-section__title">当前结算(CNY)</h3>
<section v-if="detail" class="density-dialog-section partial-summary workbench-evidence" data-tone="summary" aria-label="当前结算资料"><h3 class="density-dialog-section__title">当前结算(CNY)</h3>
<table class="density-table settlement-dialog-facts"><tbody>
<tr><th scope="row">结算单号</th><td>{{ detail.settlementNo || '—' }}</td><th scope="row">客户公司</th><td>{{ detailPartyName() }}</td></tr>
<tr><th scope="row">应收金额</th><td>{{ money(detail.amount) }}</td><th scope="row">已收金额</th><td class="is-success">{{ money(detail.paidAmount) }}</td></tr>
<tr><th scope="row">当前余额</th><td colspan="3" class="is-danger">{{ money(detail.outstandingAmount) }}</td></tr>
</tbody></table>
</section>
<section class="density-dialog-section" data-tone="work" aria-label="收款登记"><h3 class="density-dialog-section__title">收款登记</h3>
<section class="density-dialog-section workbench-evidence" data-tone="work" aria-label="收款登记"><h3 class="density-dialog-section__title">收款登记</h3>
<el-form class="settlement-operation-form density-form" label-position="left" label-width="140px" :disabled="receiptBusy"><table class="density-table density-table--editable settlement-operation-table"><tbody>
<tr><td><el-form-item label="收款日期"><el-date-picker v-model="receiptForm.receivedDate" type="date" value-format="YYYY-MM-DD" /></el-form-item></td><td><el-form-item label="本次收款金额(CNY)"><el-input-number v-model="receiptForm.amount" :min="0.01" :max="detail?.outstandingAmount || 0.01" :precision="2" placeholder="请输入收款金额" /></el-form-item></td></tr>
<tr><td colspan="2"><el-form-item label="收款方式"><el-select v-model="receiptForm.paymentMethod"><el-option label="银行转账" value="BANK_TRANSFER" /><el-option label="现金" value="CASH" /><el-option label="其他" value="OTHER" /></el-select></el-form-item></td></tr>