198 lines
7.9 KiB
Vue
198 lines
7.9 KiB
Vue
<template>
|
||
<SettlementPageFrame>
|
||
<SettlementPageHeader
|
||
icon="el-icon-view"
|
||
title="结算单预览"
|
||
description="创建结算单前预览明细,检查指定账期是否已有结算单,并返回可结算账单明细。"
|
||
endpoint="GET /bill/finance_settlement_preview.dspy"
|
||
>
|
||
<template #actions>
|
||
<button type="button" class="settlement-btn settlement-btn--primary" :disabled="loading" @click="loadPreview">
|
||
<i class="el-icon-view" />{{ loading ? '预览中...' : '预览' }}
|
||
</button>
|
||
</template>
|
||
</SettlementPageHeader>
|
||
|
||
<section class="settlement-card settlement-card--padded" style="margin-bottom: 24px;">
|
||
<div class="settlement-card-heading" style="margin-bottom: 18px;">
|
||
<i class="el-icon-filter" />
|
||
<span>预览条件</span>
|
||
</div>
|
||
<div class="settlement-filter-grid">
|
||
<div class="settlement-field">
|
||
<label class="settlement-label">对手方类型</label>
|
||
<div class="settlement-choice-group">
|
||
<button type="button" class="settlement-choice" :class="{ 'is-active': form.counterparty_type === 'supplier' }" @click="form.counterparty_type = 'supplier'">供应商</button>
|
||
<button type="button" class="settlement-choice" :class="{ 'is-active': form.counterparty_type === 'reseller' }" @click="form.counterparty_type = 'reseller'">分销商</button>
|
||
</div>
|
||
</div>
|
||
<div class="settlement-field">
|
||
<label class="settlement-label">对手方</label>
|
||
<input v-model.trim="form.counterparty_orgid" class="settlement-input" type="text" placeholder="请输入供应商或分销商机构 ID">
|
||
</div>
|
||
<div class="settlement-field">
|
||
<label class="settlement-label">账期类型</label>
|
||
<div class="settlement-choice-group">
|
||
<button type="button" class="settlement-choice" :class="{ 'is-active': form.period_type === 'day' }" @click="form.period_type = 'day'">日结</button>
|
||
<button type="button" class="settlement-choice" :class="{ 'is-active': form.period_type === 'month' }" @click="form.period_type = 'month'">月结</button>
|
||
</div>
|
||
</div>
|
||
<div class="settlement-field">
|
||
<label class="settlement-label">账期开始</label>
|
||
<input v-model="form.period_start" class="settlement-input" type="date">
|
||
</div>
|
||
<div class="settlement-field">
|
||
<label class="settlement-label">账期结束</label>
|
||
<input v-model="form.period_end" class="settlement-input" type="date">
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section v-if="previewed && existingSettlement" class="settlement-alert settlement-alert--warning">
|
||
<span class="settlement-alert-icon"><i class="el-icon-warning-outline" /></span>
|
||
<div class="settlement-alert-content">
|
||
<b>该账期已存在结算单</b>
|
||
<p>结算单号:{{ existingSettlement.no }},当前状态:<SettlementStatusBadge :status="existingSettlement.status" /></p>
|
||
</div>
|
||
</section>
|
||
<section v-else-if="previewed" class="settlement-alert">
|
||
<span class="settlement-alert-icon"><i class="el-icon-circle-check" /></span>
|
||
<div class="settlement-alert-content">
|
||
<b>可创建结算单</b>
|
||
<p>当前账期未存在结算单,可以创建新的结算单。</p>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="settlement-metric-grid">
|
||
<SettlementMetricCard label="销售金额" :value="summary.sales" icon="el-icon-wallet" />
|
||
<SettlementMetricCard label="应结算金额" :value="summary.settlement" variant="emerald" icon="el-icon-s-order" />
|
||
<SettlementMetricCard label="平台收入" :value="summary.income" variant="amber" icon="el-icon-s-marketing" />
|
||
<SettlementMetricCard label="账单数量" :value="summary.billCount" suffix="笔" variant="violet" icon="el-icon-document" />
|
||
</div>
|
||
|
||
<section class="settlement-card">
|
||
<div class="settlement-card-head">
|
||
<div class="settlement-card-heading">
|
||
<i class="el-icon-document" />
|
||
<span>可结算账单明细</span>
|
||
<small class="settlement-card-subtitle">· {{ billRows.length }} 笔</small>
|
||
</div>
|
||
</div>
|
||
<div class="settlement-table-wrap">
|
||
<table class="settlement-table">
|
||
<thead>
|
||
<tr>
|
||
<th>账单 ID</th>
|
||
<th>订单 ID</th>
|
||
<th>账单日期</th>
|
||
<th>销售模式</th>
|
||
<th class="is-number">销售金额</th>
|
||
<th class="is-number">结算金额</th>
|
||
<th class="is-number">平台收入</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="row in billRows" :key="row.billId">
|
||
<td class="is-mono">{{ row.billId }}</td>
|
||
<td class="is-mono">{{ row.orderId }}</td>
|
||
<td><span class="is-mono"><i class="el-icon-date" style="margin-right: 4px; color: #94a3b8;" />{{ row.date }}</span></td>
|
||
<td><span class="settlement-pill">{{ row.mode }}</span></td>
|
||
<td class="is-number">{{ row.sales }}</td>
|
||
<td class="is-number is-emerald">{{ row.settlement }}</td>
|
||
<td class="is-number is-amber">{{ row.income }}</td>
|
||
</tr>
|
||
<tr v-if="previewed && !loading && !billRows.length">
|
||
<td colspan="7" style="padding: 42px; color: #94a3b8; text-align: center;">暂无可结算账单</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
</SettlementPageFrame>
|
||
</template>
|
||
|
||
<script>
|
||
import SettlementPageFrame from './SettlementPageFrame'
|
||
import SettlementPageHeader from './SettlementPageHeader'
|
||
import SettlementMetricCard from './SettlementMetricCard'
|
||
import SettlementStatusBadge from './SettlementStatusBadge'
|
||
import { settlementPreviewAPI } from '@/api/FinancialSettlementCenter'
|
||
import {
|
||
getAccountingOrgId,
|
||
getItems,
|
||
getPayload,
|
||
getSummary,
|
||
normalizeBill,
|
||
normalizeSettlement
|
||
} from './settlementHelpers'
|
||
|
||
export default {
|
||
name: 'SettlementStatementPreview',
|
||
components: {
|
||
SettlementPageFrame,
|
||
SettlementPageHeader,
|
||
SettlementMetricCard,
|
||
SettlementStatusBadge
|
||
},
|
||
data() {
|
||
return {
|
||
loading: false,
|
||
previewed: false,
|
||
existingSettlement: null,
|
||
billRows: [],
|
||
summary: {
|
||
sales: '¥0.00',
|
||
settlement: '¥0.00',
|
||
income: '¥0.00',
|
||
billCount: 0
|
||
},
|
||
form: {
|
||
counterparty_type: 'reseller',
|
||
counterparty_orgid: '',
|
||
period_type: 'month',
|
||
period_start: '2026-06-01',
|
||
period_end: '2026-06-30',
|
||
current_page: 1,
|
||
page_size: 50
|
||
}
|
||
}
|
||
},
|
||
methods: {
|
||
async loadPreview() {
|
||
const accountingOrgid = getAccountingOrgId(this.$route)
|
||
if (!accountingOrgid) {
|
||
this.$message.warning('未获取到核算机构 ID')
|
||
return
|
||
}
|
||
if (!this.form.counterparty_orgid) {
|
||
this.$message.warning('请输入对手方机构 ID')
|
||
return
|
||
}
|
||
|
||
this.loading = true
|
||
try {
|
||
const payload = getPayload(await settlementPreviewAPI({
|
||
accounting_orgid: accountingOrgid,
|
||
counterparty_type: this.form.counterparty_type,
|
||
counterparty_orgid: this.form.counterparty_orgid,
|
||
period_type: this.form.period_type,
|
||
period_start: this.form.period_start,
|
||
period_end: this.form.period_end,
|
||
current_page: this.form.current_page,
|
||
page_size: this.form.page_size
|
||
}))
|
||
this.summary = getSummary(payload)
|
||
this.billRows = getItems(payload).map(normalizeBill)
|
||
const existing = payload.existing_settlement || payload.existingSettlement
|
||
this.existingSettlement = existing ? normalizeSettlement(existing) : null
|
||
this.previewed = true
|
||
} catch (error) {
|
||
this.$message.error(error.message || '结算单预览失败')
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|