Files
tms-erp-web/src/views/payment/bill-ledger.vue
T
gxwebsoft a8986690bb refactor(payment): 调整到期快捷筛选至账单台账页面独立展示
- 将快捷筛选标签及相关逻辑从搜索子组件提升至账单台账页面
- 标签置于搜索卡片下方、表格上方独立一行,满足用户需求
- 删除子组件中相关标签DOM及快捷筛选功能代码
- 统一选中态样式,采用 Element Plus 默认蓝底深字风格

fix(transportCapacity): 统一船舶管理弹窗表单控件宽度

- 删除异常的宽度强制规则,避免控件宽度不一致
- 采用固定宽度250px加最大宽度100%方案,实现多控件视觉宽度一致
- 清理无用label-width属性,解决label撑开布局异常问题
- 优化表单项label对齐与必填星号样式,确保多行label视觉协调

refactor(transportCapacity): 优化船舶证书分组布局及标签简化

- 证书有效期自标签统一更改为“有效期自”
- 证书上传区域由集中底部移至对应证书分组末尾,保持信息关联
- 清理无用样式,保留必需上传项间距样式,提升界面整洁度

fix(business): 修复项目申请表单级联选择器宽度问题

- 业务部门和承办部门el-cascader控件未设置宽度,导致收缩
- 补充级联选择器宽度规则,保证与其他控件宽度统一
- 支持热更新,无需重启开发环境
2026-09-02 14:36:42 +08:00

275 lines
9.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<basic-container class="bill-ledger-page">
<bill-ledger-search
:query="query"
:loading="loading"
@search="handleSearch"
@reset="resetSearch"
/>
<div class="bill-ledger-page__expiry-tags">
<el-check-tag
v-for="item in shortcutOptions"
:key="item.value"
:checked="query.expiryShortcut === item.value"
@change="handleShortcutChange(item.value)"
>
{{ item.label }}
</el-check-tag>
</div>
<bill-ledger-table
:rows="rows"
:loading="loading"
:page="page"
@add="openCreate"
@view="openView"
@edit="openEdit"
@delete="handleDelete"
@page-change="handlePageChange"
@size-change="handleSizeChange"
/>
<el-dialog
v-model="detailDialog.visible"
title="汇票台账详情"
width="86%"
append-to-body
destroy-on-close
>
<div v-loading="detailDialog.loading" class="bill-ledger-detail">
<section-card title="基本信息">
<el-descriptions :column="3" border>
<el-descriptions-item label="票据编号">{{
detailValue('billNo')
}}</el-descriptions-item>
<el-descriptions-item label="汇票类型">{{
detailValue('billTypeName', 'billType')
}}</el-descriptions-item>
<el-descriptions-item label="出票单位">{{
detailValue('issuerName')
}}</el-descriptions-item>
<el-descriptions-item label="收票单位">{{
detailValue('receiverName')
}}</el-descriptions-item>
<el-descriptions-item label="票面金额">{{
formatMoney(detailDialog.row.faceAmount)
}}</el-descriptions-item>
<el-descriptions-item label="可用余额">{{
formatMoney(detailDialog.row.availableBalance)
}}</el-descriptions-item>
<el-descriptions-item label="出票日期">{{
detailValue('issueDate')
}}</el-descriptions-item>
<el-descriptions-item label="到期日期">{{
detailValue('maturityDate')
}}</el-descriptions-item>
<el-descriptions-item label="出票行">{{
detailValue('issuingBank')
}}</el-descriptions-item>
<el-descriptions-item label="可用部门">{{
detailValue('availableDeptNames')
}}</el-descriptions-item>
<el-descriptions-item label="费用承担方">{{
detailValue('feeBearerName')
}}</el-descriptions-item>
<el-descriptions-item label="银行贴现参考率">
{{ formatRate(detailDialog.row.bankDiscountReferenceRate) }}
</el-descriptions-item>
<el-descriptions-item label="双方确认贴现率">
{{ formatRate(detailDialog.row.confirmedDiscountRate) }}
</el-descriptions-item>
<el-descriptions-item label="预计贴现费用">
{{ formatMoney(estimatedDiscountFee()) }}
</el-descriptions-item>
<el-descriptions-item label="备注" :span="3">
{{ detailValue('remark') }}
</el-descriptions-item>
</el-descriptions>
</section-card>
<section-card title="使用记录">
<el-table :data="detailDialog.usageRecords" border>
<el-table-column type="index" label="序号" width="64" align="center" />
<el-table-column prop="applicationNo" label="申请单号" min-width="180" align="center" />
<el-table-column label="使用金额" min-width="150" align="right">
<template #default="{ row }">{{ formatMoney(row.usedAmount) }}</template>
</el-table-column>
<el-table-column prop="useDeptName" label="使用部门" min-width="180" align="center" />
<el-table-column prop="statusName" label="状态" min-width="120" align="center" />
</el-table>
<el-empty v-if="!detailDialog.usageRecords.length" description="暂无使用记录" />
</section-card>
</div>
</el-dialog>
</basic-container>
</template>
<script>
import * as api from '@/api/payment/billLedger';
import * as billPaymentApi from '@/api/payment/billPayment';
import BillLedgerSearch from './components/bill-ledger-search.vue';
import BillLedgerTable from './components/bill-ledger-table.vue';
const emptyQuery = () => ({
billNo: '',
issueDateRange: [],
issuerName: '',
receiverName: '',
billType: '',
maturityStatus: '',
expiryShortcut: 'all',
});
export default {
name: 'BillLedger',
components: { BillLedgerSearch, BillLedgerTable },
data() {
return {
query: emptyQuery(),
counts: { all: 0, within30: 0, within90: 0, over90: 0 },
rows: [],
loading: false,
page: { current: 1, size: 10, total: 0 },
detailDialog: { visible: false, loading: false, row: {}, usageRecords: [] },
};
},
mounted() {
this.loadData();
},
computed: {
shortcutOptions() {
return [
{ label: `全部(${this.counts.all || 0}`, value: 'all' },
{ label: `30天内到期(${this.counts.within30 || 0}`, value: 'within30' },
{ label: `90天内到期(${this.counts.within90 || 0}`, value: 'within90' },
{ label: `90天以上(${this.counts.over90 || 0}`, value: 'over90' },
];
},
},
methods: {
handleShortcutChange(value) {
this.query.expiryShortcut = value;
this.handleSearch();
},
unwrapData(response) {
const body = response?.data || response || {};
return body?.data || body;
},
requestParams() {
const { issueDateRange, ...params } = this.query;
return {
...params,
issueStartDate: issueDateRange?.[0] || '',
issueEndDate: issueDateRange?.[1] || '',
};
},
async loadData() {
this.loading = true;
try {
const [listResponse, countResponse] = await Promise.all([
api.getList(this.page.current, this.page.size, this.requestParams()),
api.getExpiryCounts(),
]);
const data = this.unwrapData(listResponse);
this.rows = data.records || [];
this.page.total = Number(data.total || 0);
this.counts = { ...this.counts, ...(this.unwrapData(countResponse) || {}) };
} finally {
this.loading = false;
}
},
handleSearch() {
this.page.current = 1;
this.loadData();
},
resetSearch() {
this.query = emptyQuery();
this.handleSearch();
},
openCreate() {
this.$router.push({ path: '/payment/bill-ledger/form', query: { mode: 'add' } });
},
async openView(row) {
this.detailDialog = { visible: true, loading: true, row: { ...row }, usageRecords: [] };
try {
const [detailResponse, paymentResponse] = await Promise.all([
api.getDetail(row.id),
billPaymentApi.getList(1, 1000, { billLedgerId: row.id }),
]);
const detail = this.unwrapData(detailResponse) || {};
const paymentData = this.unwrapData(paymentResponse) || {};
const paymentRows = paymentData.records || (Array.isArray(paymentData) ? paymentData : []);
const sourceRecords = paymentRows.length ? paymentRows : detail.usageRecords || [];
this.detailDialog.row = { ...row, ...detail };
this.detailDialog.usageRecords = sourceRecords.map(item => ({
...item,
applicationNo: item.applicationNo || item.paymentNo || '-',
usedAmount: Number(item.usedAmount || 0),
useDeptName: item.useDeptName || item.deptName || '-',
statusName: item.statusName || item.approvalStatusName || '已审核',
}));
} catch (error) {
this.$message.error('票据详情加载失败,请稍后重试');
} finally {
this.detailDialog.loading = false;
}
},
openEdit(row) {
this.$router.push({
path: '/payment/bill-ledger/form',
query: { mode: 'edit', id: row.id },
});
},
async handleDelete(row) {
await this.$confirm('确认删除该汇票台账?', '提示', { type: 'warning' });
await api.remove(row.id);
this.$message.success('删除成功');
if (this.rows.length === 1 && this.page.current > 1) this.page.current -= 1;
this.loadData();
},
handlePageChange(current) {
this.page.current = current;
this.loadData();
},
handleSizeChange(size) {
this.page.current = 1;
this.page.size = size;
this.loadData();
},
detailValue(...fields) {
const value = fields
.map(field => this.detailDialog.row?.[field])
.find(item => item !== undefined && item !== null && item !== '');
return value === undefined ? '-' : value;
},
formatMoney(value) {
return Number(value || 0).toFixed(2);
},
formatRate(value) {
if (Number(value) === -1) return '';
return value === null || value === undefined || value === '' ? '-' : `${Number(value)}%`;
},
estimatedDiscountFee() {
return (
(Number(this.detailDialog.row.faceAmount || 0) *
Number(this.detailDialog.row.confirmedDiscountRate || 0)) /
100
);
},
},
};
</script>
<style scoped lang="scss">
.bill-ledger-page__expiry-tags {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-top: 16px;
margin-bottom: 6px;
:deep(.el-check-tag) {
margin: 0;
white-space: nowrap;
}
}
</style>