fix: 修复淘系微信账单加载和表头

This commit is contained in:
wangshu 2026-07-22 09:57:53 +08:00
parent c6945fd188
commit db0063f78b
7 changed files with 56 additions and 19 deletions

View File

@ -8,6 +8,7 @@ namespace Modules\EcommerceFinance;
* 列定义来自「账单抬头.xlsx」的各子表(sheet 名 = 账户类型)。
* sheet 名 ↔ tab slug ↔ 列 三者在此一一对应,避免错乱。
*
* 账户可选配置分组表头 groups,字段列统一由 columns 定义。
* 每列: [label, field, kind]
* field: 真实列名(如 record_code / income / occurred_at / updated_at),
* 或 'payload.xxx' 表示存在 payload JSON 中。
@ -18,13 +19,20 @@ namespace Modules\EcommerceFinance;
class AccountBillColumns
{
/**
* @return array<string,array{title:string,columns:array<int,array{0:string,1:string,2:string}>}>
* @return array<string,array{title:string,groups?:array<int,array{0:string,1:int}>,columns:array<int,array{0:string,1:string,2:string}>}>
*/
public static function map(): array
{
return [
'taobao-wechat' => [
'title' => '淘系微信账户',
'groups' => [
['基础信息', 7],
['账户与交易', 5],
['金额', 2],
['业务关联', 2],
['维护信息', 2],
],
'columns' => [
['记录编码', 'record_code', 'num'],
['店铺', 'store_name', 'text'],
@ -214,7 +222,7 @@ class AccountBillColumns
}
/**
* @return array{title:string,columns:array<int,array{label:string,field:string,kind:string}>}
* @return array{title:string,groups:array<int,array{label:string,span:int}>,columns:array<int,array{label:string,field:string,kind:string}>}
*/
public static function for(string $type): ?array
{
@ -228,8 +236,13 @@ class AccountBillColumns
return ['label' => $c[0], 'field' => $c[1], 'kind' => $c[2]];
}, $map[$type]['columns']);
$groups = array_map(function ($group) {
return ['label' => $group[0], 'span' => $group[1]];
}, $map[$type]['groups'] ?? []);
return [
'title' => $map[$type]['title'],
'groups' => $groups,
'columns' => $columns,
];
}

View File

@ -2,8 +2,8 @@
namespace Modules\EcommerceFinance\Http\Controllers;
use App\Abstracts\Http\Controller;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\EcommerceFinance\AccountBillColumns;
use Modules\EcommerceFinance\Models\AccountBill;
@ -14,9 +14,9 @@ class AccountBills extends Controller
* 经 admin 路由组(web 会话)暴露,前端带 CSRF 调用。
* 按 bill_type 过滤,返回分页数据 + 汇总 + 该类型的列配置。
*/
public function index(Request $request)
public function index(Request $request, string $bill_type)
{
$billType = (string) $request->get('bill_type', '');
$billType = $bill_type;
if (! AccountBillColumns::has($billType)) {
abort(404, '未知的账户类型。');

View File

@ -9,7 +9,4 @@ Route::admin('ecommerce-finance', function () {
Route::get('alipay-bills', 'AlipayBills@index')->name('alipay-bills.index');
Route::get('alipay-bills/{bill}', 'AlipayBills@show')->name('alipay-bills.show');
// 店铺收款账户账单 › 其它账户类型(通用表 ec_account_bills,按 bill_type 区分)
Route::get('account-bills', 'AccountBills@index')->name('account-bills.index');
Route::get('account-bills/{bill}', 'AccountBills@show')->name('account-bills.show');
});

View File

@ -54,15 +54,20 @@
<!-- 数据表(列由后端配置动态渲染) -->
<div class="ab-panel">
<div class="ab-phead">
<div class="ab-title">{{ columnsTitle }}</div>
<div class="ab-title">{{ columnGroups.length ? '账单明细' : columnsTitle }}</div>
<div class="ab-count" v-if="!loading">{{ total }} 条</div>
</div>
<div class="ab-scroll">
<table class="ab-table" v-if="!loading && columns.length">
<table class="ab-table" :class="{ 'ab-table-grouped': columnGroups.length }" v-if="!loading && !loadError && columns.length">
<thead>
<tr>
<th v-for="(c, i) in columns" :key="i" :class="{ 'ab-num': isNumKind(c.kind) }"
<tr class="ab-group" v-if="columnGroups.length">
<th v-for="(group, i) in columnGroups" :key="i" :colspan="group.span" scope="colgroup">
{{ group.label }}
</th>
</tr>
<tr class="ab-col">
<th v-for="(c, i) in columns" :key="i" :class="{ 'ab-num': isNumKind(c.kind) }" scope="col"
@click="maybeSort(c)">
{{ c.label }}
<span class="ab-sort" v-if="sortableField(c.field)">⇅</span>
@ -82,7 +87,12 @@
</tbody>
</table>
<div v-else class="ab-empty">加载中…</div>
<div v-else-if="loading" class="ab-empty">加载中…</div>
<div v-else-if="loadError" class="ab-empty ab-error">
<div>账单加载失败,请重试</div>
<button class="ab-btn" @click="fetch">重新加载</button>
</div>
<div v-else class="ab-empty">暂无账单字段</div>
</div>
<!-- 分页 -->
@ -120,9 +130,11 @@ export default {
data() {
return {
loading: false,
loadError: false,
rows: [],
columns: [],
columnsTitle: '',
columnGroups: [],
summary: { income: 0, expense: 0, balance: 0, count: 0 },
total: 0,
currentPage: 1,
@ -149,8 +161,8 @@ export default {
methods: {
async fetch() {
this.loading = true;
this.loadError = false;
const params = {
bill_type: this.billType,
...this.filters,
sort: this.sort.key,
dir: this.sort.dir,
@ -170,12 +182,17 @@ export default {
if (body.columns) {
this.columns = body.columns.columns || body.columns || [];
this.columnsTitle = body.columns.title || '';
this.columnGroups = body.columns.groups || [];
}
} catch (e) {
console.error('加载账单失败', e);
this.rows = [];
this.columns = [];
this.columnsTitle = '';
this.columnGroups = [];
this.total = 0;
this.summary = { income: 0, expense: 0, balance: 0, count: 0 };
this.loadError = true;
} finally {
this.loading = false;
}
@ -297,8 +314,10 @@ export default {
.ab-scroll { overflow-x: auto; }
.ab-table { border-collapse: collapse; width: 100%; font-size: 0.78125rem; }
.ab-table thead th { background: #fafbfd; color: #1f2937; font-weight: 600; text-align: left; border-bottom: 1px solid #e6e9f0; padding: 0.5625rem 0.625rem; white-space: nowrap; }
.ab-table thead th.ab-num { text-align: right; }
.ab-table-grouped { min-width: 2200px; }
.ab-table thead .ab-group th { background: #f0f3f9; color: #6b7280; font-size: 0.75rem; font-weight: 600; text-align: center; border-bottom: 1px solid #dfe4ec; padding: 0.625rem; white-space: nowrap; }
.ab-table thead .ab-col th { background: #fafbfd; color: #1f2937; font-weight: 600; text-align: left; border-bottom: 1px solid #e6e9f0; padding: 0.5625rem 0.625rem; white-space: nowrap; }
.ab-table thead .ab-col th.ab-num { text-align: right; }
.ab-sort { color: #9aa3b2; margin-left: 0.1875rem; }
.ab-table tbody td { padding: 0.5625rem 0.625rem; border-bottom: 1px solid #f1f3f7; white-space: nowrap; color: #1f2937; }
.ab-table tbody tr:hover { background: #f7f9ff; }
@ -309,6 +328,8 @@ export default {
.ab-tag { display: inline-block; padding: 0.0625rem 0.5rem; border-radius: 1rem; font-size: 0.71875rem; font-weight: 500; background: #eef2ff; color: #4f46e5; }
.ab-empty { padding: 3rem; text-align: center; color: #9aa3b2; }
.ab-error { color: #dc2626; }
.ab-error .ab-btn { margin-top: 0.75rem; color: #1f2937; }
.ab-pager { display: flex; align-items: center; gap: 0.625rem; padding: 0.875rem 1rem; border-top: 1px solid #e6e9f0; flex-wrap: wrap; }
.ab-page-info { color: #6b7280; font-size: 0.78125rem; }

View File

@ -40,8 +40,8 @@ const alipayBase = companyId
: '/ecommerce-finance/alipay-bills';
const accountBase = companyId
? `/${companyId}/ecommerce-finance/account-bills`
: '/ecommerce-finance/account-bills';
? `/${companyId}/ecommerce-finance/account-bills/type/${encodeURIComponent(tab)}`
: `/ecommerce-finance/account-bills/type/${encodeURIComponent(tab)}`;
function resolveComponent() {
// 店铺收款账户账单 › 淘系支付宝账户(独立实现)

View File

@ -100,7 +100,7 @@
</div>
@if (($page['slug'] ?? null) === 'store-receiving-bills')
<script src="{{ asset('js/business/pages.min.js') }}"></script>
<script src="{{ asset('js/business/pages.min.js') }}?v={{ filemtime(public_path('js/business/pages.min.js')) }}"></script>
@endif
</x-slot>
</x-layouts.admin>

View File

@ -1,6 +1,12 @@
<?php
use Illuminate\Support\Facades\Route;
use Modules\EcommerceFinance\Http\Controllers\AccountBills;
Route::get('ecommerce-finance/account-bills/type/{bill_type}', [AccountBills::class, 'index'])
->name('ecommerce-finance.account-bills.index');
Route::get('ecommerce-finance/account-bills/{bill}', [AccountBills::class, 'show'])
->name('ecommerce-finance.account-bills.show');
/**
* 'admin' middleware applied to all routes