2026-07-28 16:13:32 +08:00

234 lines
9.3 KiB
Vue

<template>
<SettlementPageFrame>
<SettlementPageHeader
icon="el-icon-s-operation"
title="流程总览"
description="财务结算全流程闭环:汇总查询、预览核对、创建结算单、提交审批和审批回调。"
endpoint="推荐调用流程"
>
<template #actions>
<button type="button" class="settlement-btn settlement-btn--primary" :disabled="loading" @click="loadData">
<i class="el-icon-refresh" />{{ loading ? '刷新中...' : '刷新数据' }}
</button>
</template>
</SettlementPageHeader>
<div class="settlement-metric-grid">
<SettlementMetricCard label="结算单总数" :value="settlementRows.length" suffix="个" icon="el-icon-tickets" />
<SettlementMetricCard label="销售金额合计" :value="money(totals.sales)" variant="emerald" icon="el-icon-wallet" />
<SettlementMetricCard label="结算金额合计" :value="money(totals.settlement)" variant="amber" icon="el-icon-s-order" />
<SettlementMetricCard label="平台收入合计" :value="money(totals.income)" variant="violet" icon="el-icon-s-marketing" />
</div>
<section class="settlement-card settlement-card--padded" style="margin-bottom: 24px;">
<div class="settlement-card-heading" style="margin-bottom: 22px;">
<i class="el-icon-s-operation" />
<span>结算流程闭环</span>
<small class="settlement-card-subtitle">· 点击任一节点进入对应功能</small>
</div>
<div class="settlement-flow-grid">
<div v-for="step in flowSteps" :key="step.index" class="settlement-flow-node" style="cursor: pointer;" @click="goStep(step.route)">
<div class="settlement-flow-icon">
<i :class="step.icon" />
<span class="settlement-flow-index">{{ step.index }}</span>
</div>
<div class="settlement-card settlement-card--hover settlement-flow-content">
<h3>{{ step.title }}</h3>
<strong>{{ step.subtitle }}</strong>
<p>{{ step.description }}</p>
<code class="settlement-flow-endpoint">{{ step.endpoint }}</code>
</div>
</div>
</div>
<div style="display: flex; flex-wrap: wrap; gap: 18px; margin-top: 21px; padding-top: 17px; color: #64748b; font-size: 12px; border-top: 1px solid #e2e8f0;">
<span><i class="el-icon-s-data" style="color: #0ea5e9;" /> 数据查询</span>
<span><i class="el-icon-document-add" style="color: #f59e0b;" /> 结算单操作</span>
<span><i class="el-icon-circle-check" style="color: #10b981;" /> 审批记账</span>
</div>
</section>
<div class="settlement-two-column">
<section class="settlement-card settlement-card--padded">
<div class="settlement-card-heading" style="margin-bottom: 9px;">
<i class="el-icon-data-analysis" />
<span>状态分布</span>
</div>
<div v-for="item in statusRows" :key="item.status" class="settlement-status-row">
<SettlementStatusBadge :status="item.status" />
<div class="settlement-progress-track">
<div class="settlement-progress-value" :class="item.color" :style="{ width: item.width }" />
</div>
<span class="settlement-progress-number">{{ item.value }}</span>
</div>
</section>
<section class="settlement-card settlement-card--padded">
<div class="settlement-card-heading">
<i class="el-icon-video-play" />
<span>快速操作</span>
</div>
<button v-for="item in quickActions" :key="item.title" type="button" class="settlement-quick-action" @click="goStep(item.route)">
<b><i :class="item.icon" style="margin-right: 6px; color: #0284c7;" />{{ item.title }}</b>
<span>{{ item.description }}</span>
</button>
</section>
</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">· {{ settlementRows.length }} </small>
</div>
<button type="button" class="settlement-btn settlement-btn--ghost" @click="goStep('FinancialSettlementStatementList')">
查看全部<i class="el-icon-arrow-right" style="margin: 0 0 0 5px;" />
</button>
</div>
<div class="settlement-table-wrap">
<table class="settlement-table">
<thead>
<tr>
<th>结算单号</th>
<th>对手方</th>
<th>账期</th>
<th>类型</th>
<th class="is-number">销售金额</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr v-for="row in recentSettlements" :key="row.id" style="cursor: pointer;" @click="goDetail(row)">
<td class="is-mono" style="font-weight: 700;">{{ row.no }}</td>
<td>{{ row.name }}</td>
<td class="is-mono is-muted">{{ row.start }} ~ {{ row.end }}</td>
<td><span class="settlement-pill">{{ row.periodType }}</span></td>
<td class="is-number">{{ row.sales }}</td>
<td><SettlementStatusBadge :status="row.status" /></td>
</tr>
<tr v-if="!loading && !recentSettlements.length">
<td colspan="6" 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 { settlementListAPI } from '@/api/FinancialSettlementCenter'
import {
getAccountingOrgId,
getItems,
getPayload,
money,
normalizeSettlement
} from './settlementHelpers'
import { flowSteps } from './settlementMockData'
export default {
name: 'ProcessOverview',
components: {
SettlementPageFrame,
SettlementPageHeader,
SettlementMetricCard,
SettlementStatusBadge
},
data() {
return {
loading: false,
flowSteps: flowSteps.map((step, index) => ({
...step,
route: [
'FinancialSettlementSummaryQuery',
'FinancialSettlementStatementPreview',
'FinancialCreateSettlementStatement',
'FinancialSubmitforApproval',
'FinancialApprovalCallback'
][index]
})),
settlementRows: [],
quickActions: [
{ icon: 'el-icon-view', title: '1. 预览结算单', description: '查看账期明细,检查重复', route: 'FinancialSettlementStatementPreview' },
{ icon: 'el-icon-circle-plus-outline', title: '2. 创建结算单', description: '生成草稿状态结算单', route: 'FinancialCreateSettlementStatement' },
{ icon: 'el-icon-s-promotion', title: '3. 提交审批', description: '送审并等待审批结果', route: 'FinancialSubmitforApproval' },
{ icon: 'el-icon-circle-check', title: '4. 审批回调', description: '处理审批结果并完成记账', route: 'FinancialApprovalCallback' }
]
}
},
computed: {
totals() {
return this.settlementRows.reduce((result, row) => ({
sales: result.sales + row.salesAmount,
settlement: result.settlement + row.settlementAmount,
income: result.income + row.incomeAmount
}), { sales: 0, settlement: 0, income: 0 })
},
recentSettlements() {
return this.settlementRows.slice(0, 5)
},
statusRows() {
const statusList = ['draft', 'approving', 'approved', 'settled', 'rejected', 'failed', 'cancelled']
const colorMap = {
approving: 'settlement-progress-value--amber',
approved: 'settlement-progress-value--emerald',
rejected: 'settlement-progress-value--rose',
failed: 'settlement-progress-value--rose'
}
const total = this.settlementRows.length
return statusList.map(status => {
const count = this.settlementRows.filter(row => row.status === status).length
const ratio = total ? (count / total) * 100 : 0
return {
status,
width: `${ratio}%`,
value: `${count} (${ratio.toFixed(0)}%)`,
color: colorMap[status] || ''
}
})
}
},
mounted() {
this.loadData()
},
methods: {
money,
async loadData() {
const accountingOrgid = getAccountingOrgId(this.$route)
if (!accountingOrgid) {
this.$message.warning('未获取到核算机构 ID')
return
}
this.loading = true
try {
const payload = getPayload(await settlementListAPI({
accounting_orgid: accountingOrgid,
current_page: 1,
page_size: 100
}))
this.settlementRows = getItems(payload).map(normalizeSettlement)
} catch (error) {
this.$message.error(error.message || '结算单概览加载失败')
} finally {
this.loading = false
}
},
goStep(route) {
if (route) this.$router.push({ name: route })
},
goDetail(row) {
this.$router.push({
name: 'FinancialSettlementStatementDetails',
query: { id: row.id }
})
}
}
}
</script>