feat(ecommerce): 店铺收款账户账单·其余6个账户类型页(通用配置驱动)
按「账单抬头.xlsx」各子表(微信/拼多多/京东网银钱包/京东流水/抖音/得物)设计对应 tab 页: - 新增通用表 ec_account_bills(bill_type + 通用列 + payload JSON) - AccountBill 模型 + AccountBillColumns 配置类(6类型列定义,单一数据源,sheet名↔tab↔列不乱) - AccountBills 控制器(admin 路由组,按 bill_type 筛选/排序/分页+汇总+下发列配置) - admin 路由登记 account-bills - 通用前端组件 AccountBills.vue(按后端下发 columns 动态渲染表头/单元格,含筛选/汇总/分页) - pages.js:store-receiving-bills 页按 tab 路由(taobao-alipay→独立组件;其余6个→AccountBills) - 修正 pages.js/Blade 的 section/page/tab 解析(按真实URL billing-transactions/store-receiving-bills/<tab>) - 种子:6类型各6行演示数据 淘系支付宝账户保持独立实现不变。
This commit is contained in:
parent
c934f5f12c
commit
74ddc6c88e
236
modules/EcommerceFinance/AccountBillColumns.php
Normal file
236
modules/EcommerceFinance/AccountBillColumns.php
Normal file
@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\EcommerceFinance;
|
||||
|
||||
/**
|
||||
* 店铺收款账户账单 - 各账户类型的列配置(单一数据源)。
|
||||
*
|
||||
* 列定义来自「账单抬头.xlsx」的各子表(sheet 名 = 账户类型)。
|
||||
* sheet 名 ↔ tab slug ↔ 列 三者在此一一对应,避免错乱。
|
||||
*
|
||||
* 每列: [label, field, kind]
|
||||
* field: 真实列名(如 record_code / income / occurred_at / updated_at),
|
||||
* 或 'payload.xxx' 表示存在 payload JSON 中。
|
||||
* kind: text | num | money | money_in | money_out | balance | date | tag
|
||||
*
|
||||
* 淘系支付宝账户(taobao-alipay)已有独立实现,不在此处定义。
|
||||
*/
|
||||
class AccountBillColumns
|
||||
{
|
||||
/**
|
||||
* @return array<string,array{title:string,columns:array<int,array{0:string,1:string,2:string}>}>
|
||||
*/
|
||||
public static function map(): array
|
||||
{
|
||||
return [
|
||||
'taobao-wechat' => [
|
||||
'title' => '淘系微信账户',
|
||||
'columns' => [
|
||||
['记录编码', 'record_code', 'num'],
|
||||
['店铺', 'store_name', 'text'],
|
||||
['财务备注', 'finance_remark', 'text'],
|
||||
['订单号', 'order_no', 'num'],
|
||||
['金额', 'amount', 'money'],
|
||||
['自定义备注', 'custom_remark', 'text'],
|
||||
['账单项目', 'bill_item', 'tag'],
|
||||
['线上单号', 'payload.online_order_no', 'num'],
|
||||
['淘宝订单编号', 'payload.taobao_order_no', 'num'],
|
||||
['支付流水号', 'payload.pay_serial_no', 'num'],
|
||||
['入账时间', 'occurred_at', 'date'],
|
||||
['入账类型', 'payload.entry_type', 'text'],
|
||||
['收入金额', 'income', 'money_in'],
|
||||
['支出金额', 'expense', 'money_out'],
|
||||
['业务描述', 'payload.business_desc', 'text'],
|
||||
['备注', 'remark', 'text'],
|
||||
['JST拉取时间', 'payload.jst_pulled_at', 'date'],
|
||||
['修改人', 'modifier', 'text'],
|
||||
],
|
||||
],
|
||||
|
||||
'pinduoduo' => [
|
||||
'title' => '拼多多账户',
|
||||
'columns' => [
|
||||
['记录编码', 'record_code', 'num'],
|
||||
['店铺', 'store_name', 'text'],
|
||||
['财务备注', 'finance_remark', 'text'],
|
||||
['订单', 'order_no', 'num'],
|
||||
['金额', 'amount', 'money'],
|
||||
['自定义备注', 'custom_remark', 'text'],
|
||||
['账单项目', 'bill_item', 'tag'],
|
||||
['商户订单号', 'payload.merchant_order_no', 'num'],
|
||||
['线上单号', 'payload.online_order_no', 'num'],
|
||||
['财务类型', 'payload.finance_type', 'text'],
|
||||
['类型', 'payload.type', 'text'],
|
||||
['发生时间', 'occurred_at', 'date'],
|
||||
['收入金额', 'income', 'money_in'],
|
||||
['支出金额', 'expense', 'money_out'],
|
||||
['备注', 'remark', 'text'],
|
||||
['修改时间', 'updated_at', 'date'],
|
||||
['修改人', 'modifier', 'text'],
|
||||
],
|
||||
],
|
||||
|
||||
'jd-wallet' => [
|
||||
'title' => '京东网银钱包账户',
|
||||
'columns' => [
|
||||
['记录编码', 'record_code', 'num'],
|
||||
['店铺', 'store_name', 'text'],
|
||||
['财务备注', 'finance_remark', 'text'],
|
||||
['订单', 'order_no', 'num'],
|
||||
['金额', 'amount', 'money'],
|
||||
['自定义备注', 'custom_remark', 'text'],
|
||||
['账单项目', 'bill_item', 'tag'],
|
||||
['线上单号', 'payload.online_order_no', 'num'],
|
||||
['单据编号', 'payload.doc_no', 'num'],
|
||||
['订单编号', 'payload.order_no_2', 'num'],
|
||||
['商户订单号', 'payload.merchant_order_no', 'num'],
|
||||
['单据类型', 'payload.doc_type', 'text'],
|
||||
['商品编码', 'payload.goods_code', 'num'],
|
||||
['商品名称', 'payload.goods_name', 'text'],
|
||||
['费用结算时间', 'occurred_at', 'date'],
|
||||
['费用发生时间', 'payload.fee_occurred_at', 'date'],
|
||||
['费用项', 'payload.fee_item', 'text'],
|
||||
['收入金额', 'income', 'money_in'],
|
||||
['支出金额', 'expense', 'money_out'],
|
||||
['币种', 'payload.currency', 'text'],
|
||||
['钱包结算备注', 'payload.wallet_remark', 'text'],
|
||||
['备注', 'remark', 'text'],
|
||||
['店铺号', 'payload.store_no', 'num'],
|
||||
['京东门店编码', 'payload.jd_store_code', 'num'],
|
||||
['品牌门店编号', 'payload.brand_store_no', 'num'],
|
||||
['门店名称', 'payload.store_name_2', 'text'],
|
||||
['账户代码', 'payload.account_code', 'num'],
|
||||
['修改时间', 'updated_at', 'date'],
|
||||
['修改人', 'modifier', 'text'],
|
||||
],
|
||||
],
|
||||
|
||||
'jd-transactions' => [
|
||||
'title' => '京东流水',
|
||||
'columns' => [
|
||||
['记录编码', 'record_code', 'num'],
|
||||
['店铺', 'store_name', 'text'],
|
||||
['财务备注', 'finance_remark', 'text'],
|
||||
['订单', 'order_no', 'num'],
|
||||
['金额', 'amount', 'money'],
|
||||
['自定义备注', 'custom_remark', 'text'],
|
||||
['账单项目', 'bill_item', 'tag'],
|
||||
['线上单号', 'payload.online_order_no', 'num'],
|
||||
['流水号', 'payload.serial_no', 'num'],
|
||||
['交易订单号', 'payload.tx_order_no', 'num'],
|
||||
['账户名称', 'payload.account_name', 'text'],
|
||||
['费用结算时间', 'occurred_at', 'date'],
|
||||
['账单日期', 'payload.bill_date', 'date'],
|
||||
['商户订单号', 'payload.merchant_order_no', 'num'],
|
||||
['交易备注', 'payload.tx_remark', 'text'],
|
||||
['交易类型', 'payload.tx_type', 'text'],
|
||||
['收入金额', 'income', 'money_in'],
|
||||
['支出金额', 'expense', 'money_out'],
|
||||
['账户余额', 'balance', 'balance'],
|
||||
['币种', 'payload.currency', 'text'],
|
||||
['记账请求号', 'payload.book_request_no', 'num'],
|
||||
['业务订单号', 'payload.business_order_no', 'num'],
|
||||
['修改时间', 'updated_at', 'date'],
|
||||
['修改人', 'modifier', 'text'],
|
||||
],
|
||||
],
|
||||
|
||||
'douyin' => [
|
||||
'title' => '抖音账户',
|
||||
'columns' => [
|
||||
['记录编码', 'record_code', 'num'],
|
||||
['店铺', 'store_name', 'text'],
|
||||
['财务备注', 'finance_remark', 'text'],
|
||||
['订单', 'order_no', 'num'],
|
||||
['金额', 'amount', 'money'],
|
||||
['自定义备注', 'custom_remark', 'text'],
|
||||
['商户主体名称', 'payload.merchant_name', 'text'],
|
||||
['账单项目', 'bill_item', 'tag'],
|
||||
['动账流水号', 'payload.move_serial_no', 'num'],
|
||||
['订单号', 'payload.order_no_2', 'num'],
|
||||
['线上单号', 'payload.online_order_no', 'num'],
|
||||
['子订单号', 'payload.sub_order_no', 'num'],
|
||||
['商品ID', 'payload.goods_id', 'num'],
|
||||
['账务类型', 'payload.account_type', 'text'],
|
||||
['结算时间', 'occurred_at', 'date'],
|
||||
['动账摘要', 'payload.move_summary', 'text'],
|
||||
['下单时间', 'payload.order_placed_at', 'date'],
|
||||
['业务类型', 'payload.business_type', 'text'],
|
||||
['结算账户', 'payload.settle_account', 'text'],
|
||||
['动账场景', 'payload.move_scene', 'text'],
|
||||
['达人ID', 'payload.talent_id', 'num'],
|
||||
['达人名称', 'payload.talent_name', 'text'],
|
||||
['备注', 'remark', 'text'],
|
||||
['收入', 'income', 'money_in'],
|
||||
['支出', 'expense', 'money_out'],
|
||||
['创建时间', 'created_at', 'date'],
|
||||
['修改时间', 'updated_at', 'date'],
|
||||
['修改人', 'modifier', 'text'],
|
||||
],
|
||||
],
|
||||
|
||||
'dewu' => [
|
||||
'title' => '得物账户',
|
||||
'columns' => [
|
||||
['记录编码', 'record_code', 'num'],
|
||||
['店铺', 'store_name', 'text'],
|
||||
['财务备注', 'finance_remark', 'text'],
|
||||
['金额', 'amount', 'money'],
|
||||
['订单号', 'order_no', 'num'],
|
||||
['线上单号', 'payload.online_order_no', 'num'],
|
||||
['自定义备注', 'custom_remark', 'text'],
|
||||
['账单项目', 'bill_item', 'tag'],
|
||||
['店铺', 'payload.store_2', 'text'],
|
||||
['订单类型', 'payload.order_type', 'text'],
|
||||
['商品名称', 'payload.goods_name', 'text'],
|
||||
['商品货号', 'payload.goods_no', 'num'],
|
||||
['数量', 'payload.quantity', 'num'],
|
||||
['渠道', 'payload.channel', 'text'],
|
||||
['业务类型', 'payload.business_type', 'text'],
|
||||
['收入金额', 'income', 'money_in'],
|
||||
['支出金额', 'expense', 'money_out'],
|
||||
['线上单号对应实际店铺', 'payload.online_real_store', 'text'],
|
||||
['订单创建时间', 'payload.order_created_at', 'date'],
|
||||
['支付/退款时间', 'occurred_at', 'date'],
|
||||
['发货/退货时间', 'payload.ship_return_at', 'date'],
|
||||
['结算状态', 'payload.settle_status', 'text'],
|
||||
['收款账期', 'payload.pay_period', 'text'],
|
||||
['拉取时间', 'payload.pulled_at', 'date'],
|
||||
['修改时间', 'updated_at', 'date'],
|
||||
['修改人', 'modifier', 'text'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function types(): array
|
||||
{
|
||||
return array_keys(self::map());
|
||||
}
|
||||
|
||||
public static function has(string $type): bool
|
||||
{
|
||||
return isset(self::map()[$type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{title:string,columns:array<int,array{label:string,field:string,kind:string}>}
|
||||
*/
|
||||
public static function for(string $type): ?array
|
||||
{
|
||||
$map = self::map();
|
||||
|
||||
if (! isset($map[$type])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$columns = array_map(function ($c) {
|
||||
return ['label' => $c[0], 'field' => $c[1], 'kind' => $c[2]];
|
||||
}, $map[$type]['columns']);
|
||||
|
||||
return [
|
||||
'title' => $map[$type]['title'],
|
||||
'columns' => $columns,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* 店铺收款账户账单 - 通用账单表(覆盖淘系微信/拼多多/京东网银钱包/京东流水/抖音/得物)。
|
||||
* 淘系支付宝账户(taobao-alipay)使用独立的 ec_alipay_bills 表,不在此表。
|
||||
* 各类型特有的列存于 payload JSON;列定义见 Modules\EcommerceFinance\AccountBillColumns。
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('ec_account_bills', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('company_id');
|
||||
$table->string('bill_type', 32); // taobao-wechat/pinduoduo/jd-wallet/jd-transactions/douyin/dewu
|
||||
|
||||
// 通用列(各类型共有 / 用于筛选汇总)
|
||||
$table->string('record_code', 64);
|
||||
$table->string('store_name', 255);
|
||||
$table->string('finance_remark', 255)->nullable(); // 财务备注
|
||||
$table->string('order_no', 64)->nullable(); // 订单 / 订单号
|
||||
$table->decimal('amount', 20, 6)->nullable(); // 金额
|
||||
$table->string('custom_remark', 255)->nullable(); // 自定义备注
|
||||
$table->string('bill_item', 64)->nullable(); // 账单项目
|
||||
$table->dateTime('occurred_at')->nullable(); // 主时间(入账/发生/结算...)
|
||||
$table->decimal('income', 20, 6)->default(0); // 收入(金额)
|
||||
$table->decimal('expense', 20, 6)->default(0); // 支出(金额)
|
||||
$table->decimal('balance', 20, 6)->default(0); // 余额/账户余额
|
||||
$table->string('remark', 512)->nullable(); // 备注
|
||||
$table->string('modifier', 64)->nullable(); // 修改人
|
||||
$table->json('payload')->nullable(); // 各类型特有列
|
||||
|
||||
$table->unsignedInteger('created_by')->nullable();
|
||||
$table->string('created_from', 100)->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['company_id', 'bill_type']);
|
||||
$table->index(['company_id', 'bill_type', 'store_name']);
|
||||
$table->index(['company_id', 'bill_type', 'occurred_at']);
|
||||
$table->index(['company_id', 'bill_type', 'bill_item']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('ec_account_bills');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\EcommerceFinance\Database\Seeds;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Modules\EcommerceFinance\AccountBillColumns;
|
||||
|
||||
class AccountBillsTableSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* 为 6 种账户类型生成演示行(淘系支付宝不在内,它有独立表/种子)。
|
||||
* 运行:php artisan db:seed --class=Modules\\EcommerceFinance\\Database\\Seeds\\AccountBillsTableSeeder
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$companyId = (int) (DB::table('companies')->value('id') ?? 1);
|
||||
|
||||
$shops = [
|
||||
'淘宝-亿家达家居鞋柜电脑桌',
|
||||
'天猫-亿家达旗舰店',
|
||||
'天猫-卓禾家具旗舰店',
|
||||
'拼多多-亿家达家居旗舰店',
|
||||
'京东-亿家达旗舰店',
|
||||
'抖音-亿家达旗舰店',
|
||||
'得物-亿家达旗舰店',
|
||||
];
|
||||
|
||||
$items = ['交易收款', '退款', '提现到银行卡', '服务费', '红包补贴', '佣金扣款', '平台补贴', '以旧换新自补平台过桥'];
|
||||
|
||||
$now = now();
|
||||
$seq = 3000000000000000000;
|
||||
|
||||
foreach (AccountBillColumns::types() as $billType) {
|
||||
$config = AccountBillColumns::for($billType);
|
||||
DB::table('ec_account_bills')
|
||||
->where('company_id', $companyId)
|
||||
->where('bill_type', $billType)
|
||||
->delete();
|
||||
|
||||
$balance = 50000.00;
|
||||
|
||||
for ($i = 0; $i < 6; $i++) {
|
||||
$real = [
|
||||
'company_id' => $companyId,
|
||||
'bill_type' => $billType,
|
||||
'modifier' => 'api',
|
||||
'created_by' => null,
|
||||
'created_from' => 'ecommerce-finance',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
$payload = [];
|
||||
|
||||
$income = $i % 2 === 0 ? round(60 + ($i * 37 % 600), 2) : 0.00;
|
||||
$expense = $i % 2 === 1 ? round(8 + ($i * 13 % 120), 2) : 0.00;
|
||||
$balance += $income - $expense;
|
||||
|
||||
$day = str_pad((string) (1 + ($i % 15)), 2, '0', STR_PAD_LEFT);
|
||||
$hh = str_pad((string) (8 + ($i % 12)), 2, '0', STR_PAD_LEFT);
|
||||
$mm = str_pad((string) (($i * 7) % 60), 2, '0', STR_PAD_LEFT);
|
||||
$occurred = '2026-07-' . $day . ' ' . $hh . ':' . $mm . ':11';
|
||||
|
||||
foreach ($config['columns'] as $col) {
|
||||
[$label, $field, $kind] = [$col['label'], $col['field'], $col['kind']];
|
||||
$value = $this->valueFor($field, $kind, $label, [
|
||||
'i' => $i,
|
||||
'shop' => $shops[($i + crc32($billType)) % count($shops)],
|
||||
'item' => $items[$i % count($items)],
|
||||
'income' => $income,
|
||||
'expense' => $expense,
|
||||
'balance' => round($balance, 2),
|
||||
'occurred' => $occurred,
|
||||
'seq' => $seq,
|
||||
]);
|
||||
|
||||
if (strpos($field, 'payload.') === 0) {
|
||||
$payload[substr($field, 8)] = $value;
|
||||
} else {
|
||||
$real[$field] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$real['payload'] = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||||
$seq++;
|
||||
|
||||
DB::table('ec_account_bills')->insert($this->normalizeRow($real));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function valueFor($field, $kind, $label, array $c)
|
||||
{
|
||||
// 真实列优先按字段定值
|
||||
switch ($field) {
|
||||
case 'record_code':
|
||||
return (string) ($c['seq']);
|
||||
case 'store_name':
|
||||
return $c['shop'];
|
||||
case 'bill_item':
|
||||
return $c['item'];
|
||||
case 'occurred_at':
|
||||
return $c['occurred'];
|
||||
case 'income':
|
||||
return $c['income'];
|
||||
case 'expense':
|
||||
return $c['expense'];
|
||||
case 'balance':
|
||||
return $c['balance'];
|
||||
case 'amount':
|
||||
return $c['income'] + $c['expense'];
|
||||
case 'order_no':
|
||||
return (string) (1570700000000000000 + $c['i']);
|
||||
case 'finance_remark':
|
||||
case 'custom_remark':
|
||||
return $c['i'] % 3 === 0 ? '财务备注-' . $c['i'] : null;
|
||||
case 'remark':
|
||||
return $c['item'] . ' 演示备注';
|
||||
case 'modifier':
|
||||
return 'api';
|
||||
case 'created_at':
|
||||
case 'updated_at':
|
||||
return now();
|
||||
}
|
||||
|
||||
// payload 列按 kind 推断
|
||||
switch ($kind) {
|
||||
case 'date':
|
||||
return $c['occurred'];
|
||||
case 'num':
|
||||
return (string) (3300000000000000 + $c['i'] + crc32($field));
|
||||
case 'money':
|
||||
case 'balance':
|
||||
return $c['amount'] ?? 0;
|
||||
case 'money_in':
|
||||
return $c['income'];
|
||||
case 'money_out':
|
||||
return $c['expense'];
|
||||
case 'tag':
|
||||
return $c['item'];
|
||||
default:
|
||||
return $label . '-' . $c['i'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保证插入行类型与表结构一致(decimal/null)。
|
||||
*/
|
||||
private function normalizeRow(array $real): array
|
||||
{
|
||||
$decimals = ['amount', 'income', 'expense', 'balance'];
|
||||
|
||||
foreach ($decimals as $k) {
|
||||
if (isset($real[$k])) {
|
||||
$real[$k] = (float) $real[$k];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($real['finance_remark'])) {
|
||||
$real['finance_remark'] = null;
|
||||
}
|
||||
if (empty($real['custom_remark'])) {
|
||||
$real['custom_remark'] = null;
|
||||
}
|
||||
|
||||
return $real;
|
||||
}
|
||||
}
|
||||
91
modules/EcommerceFinance/Http/Controllers/AccountBills.php
Normal file
91
modules/EcommerceFinance/Http/Controllers/AccountBills.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\EcommerceFinance\Http\Controllers;
|
||||
|
||||
use App\Abstracts\Http\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\EcommerceFinance\AccountBillColumns;
|
||||
use Modules\EcommerceFinance\Models\AccountBill;
|
||||
|
||||
class AccountBills extends Controller
|
||||
{
|
||||
/**
|
||||
* 通用账单列表(店铺收款账户账单 › 各账户类型 tab)。
|
||||
* 经 admin 路由组(web 会话)暴露,前端带 CSRF 调用。
|
||||
* 按 bill_type 过滤,返回分页数据 + 汇总 + 该类型的列配置。
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$billType = (string) $request->get('bill_type', '');
|
||||
|
||||
if (! AccountBillColumns::has($billType)) {
|
||||
abort(404, '未知的账户类型。');
|
||||
}
|
||||
|
||||
$query = AccountBill::query()
|
||||
->where('company_id', company_id())
|
||||
->where('bill_type', $billType);
|
||||
|
||||
if ($store = $request->get('store_name')) {
|
||||
$query->where('store_name', $store);
|
||||
}
|
||||
|
||||
if ($item = $request->get('bill_item')) {
|
||||
$query->where('bill_item', $item);
|
||||
}
|
||||
|
||||
if ($start = $request->get('start')) {
|
||||
$query->where('occurred_at', '>=', $start);
|
||||
}
|
||||
|
||||
if ($end = $request->get('end')) {
|
||||
$query->where('occurred_at', '<=', $end . ' 23:59:59');
|
||||
}
|
||||
|
||||
if ($keyword = $request->get('keyword')) {
|
||||
$query->where(function ($q) use ($keyword) {
|
||||
$like = '%' . $keyword . '%';
|
||||
$q->where('record_code', 'like', $like)
|
||||
->orWhere('order_no', 'like', $like)
|
||||
->orWhere('remark', 'like', $like)
|
||||
->orWhere('bill_item', 'like', $like);
|
||||
});
|
||||
}
|
||||
|
||||
$sortable = ['occurred_at', 'income', 'expense', 'balance', 'record_code'];
|
||||
$sort = in_array($request->get('sort'), $sortable, true) ? $request->get('sort') : 'occurred_at';
|
||||
$dir = $request->get('dir') === 'asc' ? 'asc' : 'desc';
|
||||
$query->orderBy($sort, $dir);
|
||||
|
||||
$perPage = min(max((int) $request->get('limit', 10), 1), 100);
|
||||
$rows = $query->paginate($perPage);
|
||||
|
||||
// 汇总(分页前)
|
||||
$summaryRow = (clone $query)->selectRaw(
|
||||
'COALESCE(SUM(income), 0) as income, ' .
|
||||
'COALESCE(SUM(expense), 0) as expense, ' .
|
||||
'COUNT(*) as count'
|
||||
)->first();
|
||||
|
||||
$latestBalance = (clone $query)
|
||||
->orderByDesc('occurred_at')
|
||||
->orderByDesc('id')
|
||||
->value('balance');
|
||||
|
||||
$data = $rows->toArray();
|
||||
$data['summary'] = [
|
||||
'income' => (float) ($summaryRow->income ?? 0),
|
||||
'expense' => (float) ($summaryRow->expense ?? 0),
|
||||
'count' => (int) ($summaryRow->count ?? 0),
|
||||
'balance' => $latestBalance !== null ? (float) $latestBalance : 0,
|
||||
];
|
||||
$data['columns'] = AccountBillColumns::for($billType);
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
public function show(AccountBill $bill)
|
||||
{
|
||||
return response()->json($bill);
|
||||
}
|
||||
}
|
||||
42
modules/EcommerceFinance/Models/AccountBill.php
Normal file
42
modules/EcommerceFinance/Models/AccountBill.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\EcommerceFinance\Models;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
|
||||
class AccountBill extends Model
|
||||
{
|
||||
use \Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
protected $table = 'ec_account_bills';
|
||||
|
||||
protected $fillable = [
|
||||
'company_id',
|
||||
'bill_type',
|
||||
'record_code',
|
||||
'store_name',
|
||||
'finance_remark',
|
||||
'order_no',
|
||||
'amount',
|
||||
'custom_remark',
|
||||
'bill_item',
|
||||
'occurred_at',
|
||||
'income',
|
||||
'expense',
|
||||
'balance',
|
||||
'remark',
|
||||
'modifier',
|
||||
'payload',
|
||||
'created_by',
|
||||
'created_from',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'occurred_at' => 'datetime',
|
||||
'amount' => 'decimal:6',
|
||||
'income' => 'decimal:6',
|
||||
'expense' => 'decimal:6',
|
||||
'balance' => 'decimal:6',
|
||||
'payload' => 'array',
|
||||
];
|
||||
}
|
||||
@ -5,7 +5,11 @@ use Illuminate\Support\Facades\Route;
|
||||
Route::admin('ecommerce-finance', function () {
|
||||
Route::view('/', 'ecommerce-finance::index')->name('index');
|
||||
|
||||
// 店铺收款账户账单 › 淘系支付宝账户
|
||||
// 店铺收款账户账单 › 淘系支付宝账户(独立表 ec_alipay_bills)
|
||||
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');
|
||||
});
|
||||
|
||||
319
resources/assets/js/components/business/AccountBills.vue
Normal file
319
resources/assets/js/components/business/AccountBills.vue
Normal file
@ -0,0 +1,319 @@
|
||||
<template>
|
||||
<div class="account-page">
|
||||
<!-- 汇总卡片 -->
|
||||
<div class="ab-stats">
|
||||
<div class="ab-stat">
|
||||
<div class="ab-stat-k">收入合计</div>
|
||||
<div class="ab-stat-v income">{{ money(summary.income) }}</div>
|
||||
<div class="ab-stat-s">{{ summary.count }} 笔交易</div>
|
||||
</div>
|
||||
<div class="ab-stat">
|
||||
<div class="ab-stat-k">支出合计</div>
|
||||
<div class="ab-stat-v expense">{{ money(summary.expense) }}</div>
|
||||
<div class="ab-stat-s">按当前筛选</div>
|
||||
</div>
|
||||
<div class="ab-stat">
|
||||
<div class="ab-stat-k">期末余额(最新)</div>
|
||||
<div class="ab-stat-v">{{ money(summary.balance) }}</div>
|
||||
<div class="ab-stat-s">最新一条记录</div>
|
||||
</div>
|
||||
<div class="ab-stat">
|
||||
<div class="ab-stat-k">交易笔数</div>
|
||||
<div class="ab-stat-v">{{ summary.count }}</div>
|
||||
<div class="ab-stat-s">当前筛选结果</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选栏 -->
|
||||
<div class="ab-filter">
|
||||
<div class="ab-field">
|
||||
<label>店铺</label>
|
||||
<input v-model.trim="filters.store_name" placeholder="店铺名称" />
|
||||
</div>
|
||||
<div class="ab-field">
|
||||
<label>账单项目</label>
|
||||
<input v-model.trim="filters.bill_item" placeholder="账单项目" />
|
||||
</div>
|
||||
<div class="ab-field ab-field-date">
|
||||
<label>时间</label>
|
||||
<div class="ab-date">
|
||||
<input type="date" v-model="filters.start" /> <span>~</span>
|
||||
<input type="date" v-model="filters.end" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ab-field ab-field-kw">
|
||||
<label>关键词(记录编码 / 订单 / 备注)</label>
|
||||
<input v-model.trim="filters.keyword" placeholder="输入关键词" />
|
||||
</div>
|
||||
<div class="ab-actions">
|
||||
<button class="ab-btn ab-btn-primary" @click="applyFilters">查询</button>
|
||||
<button class="ab-btn" @click="resetFilters">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表(列由后端配置动态渲染) -->
|
||||
<div class="ab-panel">
|
||||
<div class="ab-phead">
|
||||
<div class="ab-title">{{ columnsTitle }}</div>
|
||||
<div class="ab-count" v-if="!loading">{{ total }} 条</div>
|
||||
</div>
|
||||
|
||||
<div class="ab-scroll">
|
||||
<table class="ab-table" v-if="rows.length && columns.length">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(c, i) in columns" :key="i" :class="{ 'ab-num': isNumKind(c.kind) }"
|
||||
@click="maybeSort(c)">
|
||||
{{ c.label }}
|
||||
<span class="ab-sort" v-if="sortableField(c.field)">⇅</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="r in rows" :key="r.id">
|
||||
<td v-for="(c, i) in columns" :key="i" :class="cellClass(c)">
|
||||
<span v-if="c.kind === 'tag'" class="ab-tag">{{ cellText(r, c) || '—' }}</span>
|
||||
<template v-else>{{ cellDisplay(r, c) }}</template>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="ab-empty" v-else-if="!loading">没有符合条件的账单记录</div>
|
||||
<div class="ab-empty" v-else>加载中…</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="ab-pager" v-if="rows.length">
|
||||
<div class="ab-page-info">第 {{ rangeStart }} - {{ rangeEnd }} 条 / 共 {{ total }} 条</div>
|
||||
<div class="ab-page-right">
|
||||
<span>每页</span>
|
||||
<select v-model.number="perPage" @change="changePage(1)">
|
||||
<option :value="10">10</option>
|
||||
<option :value="20">20</option>
|
||||
<option :value="50">50</option>
|
||||
</select>
|
||||
<button class="ab-page-btn" :disabled="currentPage <= 1" @click="changePage(1)">«</button>
|
||||
<button class="ab-page-btn" :disabled="currentPage <= 1" @click="changePage(currentPage - 1)">‹</button>
|
||||
<span class="ab-page-no">{{ currentPage }} / {{ lastPage }}</span>
|
||||
<button class="ab-page-btn" :disabled="currentPage >= lastPage" @click="changePage(currentPage + 1)">›</button>
|
||||
<button class="ab-page-btn" :disabled="currentPage >= lastPage" @click="changePage(lastPage)">»</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const SORTABLE = ['occurred_at', 'income', 'expense', 'balance', 'record_code'];
|
||||
|
||||
export default {
|
||||
name: 'AccountBills',
|
||||
|
||||
props: {
|
||||
apiBase: { type: String, required: true },
|
||||
billType: { type: String, required: true },
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
rows: [],
|
||||
columns: [],
|
||||
columnsTitle: '',
|
||||
summary: { income: 0, expense: 0, balance: 0, count: 0 },
|
||||
total: 0,
|
||||
currentPage: 1,
|
||||
lastPage: 1,
|
||||
perPage: 10,
|
||||
filters: { store_name: '', bill_item: '', start: '', end: '', keyword: '' },
|
||||
sort: { key: 'occurred_at', dir: 'desc' },
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
rangeStart() {
|
||||
return this.total === 0 ? 0 : (this.currentPage - 1) * this.perPage + 1;
|
||||
},
|
||||
rangeEnd() {
|
||||
return Math.min(this.currentPage * this.perPage, this.total);
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetch() {
|
||||
this.loading = true;
|
||||
const params = {
|
||||
bill_type: this.billType,
|
||||
...this.filters,
|
||||
sort: this.sort.key,
|
||||
dir: this.sort.dir,
|
||||
limit: this.perPage,
|
||||
page: this.currentPage,
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await window.axios.get(this.apiBase, { params });
|
||||
const body = res.data || {};
|
||||
this.rows = body.data || [];
|
||||
this.total = body.total || 0;
|
||||
this.currentPage = body.current_page || 1;
|
||||
this.lastPage = body.last_page || 1;
|
||||
this.perPage = body.per_page || this.perPage;
|
||||
this.summary = body.summary || { income: 0, expense: 0, balance: 0, count: 0 };
|
||||
if (body.columns) {
|
||||
this.columns = body.columns.columns || body.columns || [];
|
||||
this.columnsTitle = body.columns.title || '';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载账单失败', e);
|
||||
this.rows = [];
|
||||
this.total = 0;
|
||||
this.summary = { income: 0, expense: 0, balance: 0, count: 0 };
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
applyFilters() {
|
||||
this.currentPage = 1;
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
resetFilters() {
|
||||
this.filters = { store_name: '', bill_item: '', start: '', end: '', keyword: '' };
|
||||
this.currentPage = 1;
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
changePage(p) {
|
||||
this.currentPage = p;
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
maybeSort(c) {
|
||||
if (!this.sortableField(c.field)) return;
|
||||
if (this.sort.key === c.field) {
|
||||
this.sort.dir = this.sort.dir === 'asc' ? 'desc' : 'asc';
|
||||
} else {
|
||||
this.sort.key = c.field;
|
||||
this.sort.dir = 'desc';
|
||||
}
|
||||
this.currentPage = 1;
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
sortableField(field) {
|
||||
return SORTABLE.indexOf(field) !== -1;
|
||||
},
|
||||
|
||||
getValue(row, field) {
|
||||
if (!field) return '';
|
||||
if (field.indexOf('payload.') === 0) {
|
||||
const key = field.slice(8);
|
||||
const p = row.payload || {};
|
||||
return p[key] === null || p[key] === undefined ? '' : p[key];
|
||||
}
|
||||
return row[field] === null || row[field] === undefined ? '' : row[field];
|
||||
},
|
||||
|
||||
cellText(row, c) {
|
||||
return this.getValue(row, c.field);
|
||||
},
|
||||
|
||||
cellDisplay(row, c) {
|
||||
const v = this.getValue(row, c.field);
|
||||
if (v === '' || v === null || v === undefined) return '—';
|
||||
|
||||
switch (c.kind) {
|
||||
case 'money_in':
|
||||
return '+' + this.money(v);
|
||||
case 'money_out':
|
||||
return '−' + this.money(v);
|
||||
case 'balance':
|
||||
case 'money':
|
||||
return this.money(v);
|
||||
default:
|
||||
return v;
|
||||
}
|
||||
},
|
||||
|
||||
cellClass(c) {
|
||||
const cls = { 'ab-num': this.isNumKind(c.kind) };
|
||||
if (c.kind === 'money_in') cls['ab-in'] = true;
|
||||
if (c.kind === 'money_out') cls['ab-out'] = true;
|
||||
if (c.kind === 'num') cls['ab-mono'] = true;
|
||||
return cls;
|
||||
},
|
||||
|
||||
isNumKind(kind) {
|
||||
return kind === 'money' || kind === 'money_in' || kind === 'money_out' || kind === 'balance' || kind === 'num';
|
||||
},
|
||||
|
||||
money(n) {
|
||||
const v = Number(n || 0);
|
||||
return '¥' + v.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.account-page { padding: 1.25rem 1.5rem 1.5rem; }
|
||||
|
||||
.ab-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.875rem; margin-bottom: 0.875rem; }
|
||||
.ab-stat { background: #fff; border: 1px solid #e6e9f0; border-radius: 0.75rem; padding: 1rem 1.125rem; box-shadow: 0 1px 2px rgba(16,24,40,.04), 0 1px 3px rgba(16,24,40,.06); }
|
||||
.ab-stat-k { font-size: 0.75rem; color: #6b7280; }
|
||||
.ab-stat-v { font-size: 1.375rem; font-weight: 700; margin-top: 0.5rem; letter-spacing: .3px; }
|
||||
.ab-stat-s { font-size: 0.75rem; color: #9aa3b2; margin-top: 0.25rem; }
|
||||
.ab-stat-v.income { color: #f5222d; }
|
||||
.ab-stat-v.expense { color: #16a34a; }
|
||||
|
||||
.ab-filter { display: flex; flex-wrap: wrap; gap: 0.875rem; background: #fff; border: 1px solid #e6e9f0; border-radius: 0.75rem; padding: 1rem 1.125rem; margin-bottom: 0.875rem; }
|
||||
.ab-field { display: flex; flex-direction: column; gap: 0.3125rem; }
|
||||
.ab-field label { font-size: 0.75rem; color: #6b7280; font-weight: 500; }
|
||||
.ab-field input { height: 2.125rem; min-width: 11.25rem; padding: 0 0.625rem; border: 1px solid #e6e9f0; border-radius: 0.5rem; background: #fff; font-size: 0.8125rem; color: #1f2937; outline: none; }
|
||||
.ab-field input:focus { border-color: #4f46e5; box-shadow: 0 0 0 3px rgba(79,70,229,.12); }
|
||||
.ab-field-kw { flex: 1; min-width: 12.5rem; }
|
||||
.ab-field-kw input { width: 100%; }
|
||||
.ab-date { display: flex; align-items: center; gap: 0.375rem; }
|
||||
.ab-date input { min-width: 8.75rem; }
|
||||
.ab-actions { display: flex; gap: 0.625rem; align-items: flex-end; margin-left: auto; }
|
||||
.ab-btn { height: 2.125rem; padding: 0 0.875rem; border-radius: 0.5rem; border: 1px solid #e6e9f0; background: #fff; color: #1f2937; cursor: pointer; font-size: 0.8125rem; font-weight: 500; }
|
||||
.ab-btn:hover { border-color: #c7cdda; }
|
||||
.ab-btn-primary { background: #4f46e5; border-color: #4f46e5; color: #fff; }
|
||||
.ab-btn-primary:hover { background: #4338ca; }
|
||||
|
||||
.ab-panel { background: #fff; border: 1px solid #e6e9f0; border-radius: 0.75rem; box-shadow: 0 1px 2px rgba(16,24,40,.04), 0 1px 3px rgba(16,24,40,.06); overflow: hidden; }
|
||||
.ab-phead { display: flex; align-items: center; gap: 0.625rem; padding: 0.875rem 1rem; border-bottom: 1px solid #e6e9f0; }
|
||||
.ab-title { font-weight: 600; font-size: 0.875rem; }
|
||||
.ab-count { color: #9aa3b2; font-size: 0.75rem; }
|
||||
|
||||
.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-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; }
|
||||
.ab-num { text-align: right; font-variant-numeric: tabular-nums; }
|
||||
.ab-mono { font-family: ui-monospace, Menlo, Consolas, monospace; color: #6b7280; font-size: 0.71875rem; }
|
||||
.ab-in { color: #f5222d; font-weight: 600; }
|
||||
.ab-out { color: #16a34a; font-weight: 600; }
|
||||
.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-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; }
|
||||
.ab-page-right { margin-left: auto; display: flex; align-items: center; gap: 0.375rem; font-size: 0.78125rem; }
|
||||
.ab-page-right select { height: 1.875rem; border: 1px solid #e6e9f0; border-radius: 0.4375rem; padding: 0 0.375rem; }
|
||||
.ab-page-btn { height: 1.875rem; min-width: 1.875rem; padding: 0 0.5rem; border: 1px solid #e6e9f0; background: #fff; border-radius: 0.4375rem; cursor: pointer; font-size: 0.78125rem; color: #1f2937; }
|
||||
.ab-page-btn:hover:not(:disabled) { border-color: #4f46e5; color: #4f46e5; }
|
||||
.ab-page-btn:disabled { opacity: .45; cursor: not-allowed; }
|
||||
.ab-page-no { padding: 0 0.375rem; }
|
||||
</style>
|
||||
54
resources/assets/js/views/business/pages.js
vendored
54
resources/assets/js/views/business/pages.js
vendored
@ -1,48 +1,74 @@
|
||||
/**
|
||||
* 业务工作台(店铺管理 › 各子功能)统一前端入口。
|
||||
* 业务工作台(账单流水数据 › 各子功能)统一前端入口。
|
||||
* 对应 Blade:resources/views/business/pages/show.blade.php
|
||||
* 从当前 URL(/{company_id}/workspace/{section}/{page}/{tab})取出
|
||||
* company_id 与 page slug,挂载 Vue 并按 slug 渲染对应组件。
|
||||
* 路由:/{company_id}/workspace/{section}/{page}/{tab}
|
||||
*
|
||||
* 淘系支付宝账户(store-receiving-bill › taobao-alipay)在此实现;
|
||||
* 京东流水(jd-transactions)等后续页面复用同一框架,按 slug 增加分支即可。
|
||||
* 店铺收款账户账单(store-receiving-bills)下各 tab:
|
||||
* - taobao-alipay → 独立实现 TaobaoAlipayBills(表 ec_alipay_bills)
|
||||
* - taobao-wechat / pinduoduo / jd-wallet / jd-transactions / douyin / dewu
|
||||
* → 通用实现 AccountBills(表 ec_account_bills,按 bill_type 区分,列配置由后端下发)
|
||||
*/
|
||||
|
||||
require('./../../bootstrap');
|
||||
|
||||
import Vue from 'vue';
|
||||
import TaobaoAlipayBills from './../../components/business/TaobaoAlipayBills.vue';
|
||||
import AccountBills from './../../components/business/AccountBills.vue';
|
||||
|
||||
const GENERIC_TABS = ['taobao-wechat', 'pinduoduo', 'jd-wallet', 'jd-transactions', 'douyin', 'dewu'];
|
||||
|
||||
function pageContext() {
|
||||
const parts = (window.location.pathname || '').split('/').filter(Boolean);
|
||||
const idx = parts.indexOf('workspace');
|
||||
|
||||
if (idx === -1) {
|
||||
return { companyId: '', page: '' };
|
||||
return { companyId: '', section: '', page: '', tab: '' };
|
||||
}
|
||||
|
||||
const companyId = idx > 0 ? parts[idx - 1] : '';
|
||||
const page = parts[idx + 1] || '';
|
||||
|
||||
return { companyId, page };
|
||||
return {
|
||||
companyId: idx > 0 ? parts[idx - 1] : '',
|
||||
section: parts[idx + 1] || '',
|
||||
page: parts[idx + 2] || '',
|
||||
tab: parts[idx + 3] || '',
|
||||
};
|
||||
}
|
||||
|
||||
const { companyId, page } = pageContext();
|
||||
const { companyId, page, tab } = pageContext();
|
||||
|
||||
const apiBase = companyId
|
||||
const alipayBase = companyId
|
||||
? `/${companyId}/ecommerce-finance/alipay-bills`
|
||||
: '/ecommerce-finance/alipay-bills';
|
||||
|
||||
const accountBase = companyId
|
||||
? `/${companyId}/ecommerce-finance/account-bills`
|
||||
: '/ecommerce-finance/account-bills';
|
||||
|
||||
function resolveComponent() {
|
||||
// 店铺收款账户账单 › 淘系支付宝账户(独立实现)
|
||||
if (page === 'store-receiving-bills' && tab === 'taobao-alipay') {
|
||||
return { Component: TaobaoAlipayBills, props: { apiBase: alipayBase } };
|
||||
}
|
||||
|
||||
// 店铺收款账户账单 › 其它账户类型(通用实现)
|
||||
if (page === 'store-receiving-bills' && GENERIC_TABS.indexOf(tab) !== -1) {
|
||||
return { Component: AccountBills, props: { apiBase: accountBase, billType: tab } };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const mount = document.querySelector('.business-blank-page');
|
||||
|
||||
if (mount) {
|
||||
const resolved = resolveComponent();
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
el: mount,
|
||||
|
||||
render(h) {
|
||||
if (page === 'taobao-alipay') {
|
||||
return h(TaobaoAlipayBills, { props: { apiBase } });
|
||||
if (resolved) {
|
||||
return h(resolved.Component, { props: resolved.props });
|
||||
}
|
||||
|
||||
return h('div', { class: 'business-page-empty' }, '该页面尚未实现');
|
||||
|
||||
@ -99,7 +99,7 @@
|
||||
<section class="business-blank-page" aria-label="{{ $activeTab['title'] ?? ($page['title'] ?? $section['title']) }}"></section>
|
||||
</div>
|
||||
|
||||
@if (in_array($page['slug'] ?? null, ['taobao-alipay', 'taobao-wechat', 'jd-wallet', 'jd-transactions']))
|
||||
@if (($page['slug'] ?? null) === 'store-receiving-bills')
|
||||
<script src="{{ asset('js/business/pages.min.js') }}"></script>
|
||||
@endif
|
||||
</x-slot>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user