a8986690bb
- 将快捷筛选标签及相关逻辑从搜索子组件提升至账单台账页面 - 标签置于搜索卡片下方、表格上方独立一行,满足用户需求 - 删除子组件中相关标签DOM及快捷筛选功能代码 - 统一选中态样式,采用 Element Plus 默认蓝底深字风格 fix(transportCapacity): 统一船舶管理弹窗表单控件宽度 - 删除异常的宽度强制规则,避免控件宽度不一致 - 采用固定宽度250px加最大宽度100%方案,实现多控件视觉宽度一致 - 清理无用label-width属性,解决label撑开布局异常问题 - 优化表单项label对齐与必填星号样式,确保多行label视觉协调 refactor(transportCapacity): 优化船舶证书分组布局及标签简化 - 证书有效期自标签统一更改为“有效期自” - 证书上传区域由集中底部移至对应证书分组末尾,保持信息关联 - 清理无用样式,保留必需上传项间距样式,提升界面整洁度 fix(business): 修复项目申请表单级联选择器宽度问题 - 业务部门和承办部门el-cascader控件未设置宽度,导致收缩 - 补充级联选择器宽度规则,保证与其他控件宽度统一 - 支持热更新,无需重启开发环境
275 lines
9.4 KiB
Vue
275 lines
9.4 KiB
Vue
<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>
|