qiuxiang a0c99c3e8d 新增店铺收款京喜账单页签并从京东账单切分
在京东账单右侧新增京喜账单页签,复用京东日账单的取数、列定义、筛选、排序、分页与导出,只增加平台维度过滤:京东账单排除京喜店铺,京喜账单只取京喜店铺。平台口径集中在 config/jd_bill_platform.php 与 JdBillPlatform(含口径切换起始日期参数,默认全量历史),仓库通过 forPlatform() 收窄,两个口径互补、总额守恒,底层镜像数据不修改不删除。真实镜像实测:京喜 488,464 笔 + 京东 210,983 笔 = 拆分前 699,447 笔,收入/支出/差额逐项误差为 0。
2026-09-28 19:25:53 +08:00

169 lines
6.3 KiB
JavaScript
Vendored
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 业务工作台(账单流水数据 › 各子功能)统一前端入口。
* 对应 Blade:resources/views/business/pages/show.blade.php
* 路由:/{company_id}/workspace/{section}/{page}/{tab}
*
* 店铺收款账户账单(store-receiving-bills)下各 tab:
* - taobao-alipay → 独立实现 TaobaoAlipayBills(经营分析副本共享镜像)
* - taobao-wechat / pinduoduo / jd-wallet / jd-transactions / jingxi / dewu / vipshop / vipshop-jx
* → 通用实现 AccountBills(表 ec_account_bills,按 bill_type 区分)
* - douyin → AccountBills 展示共享原始账单镜像中的头条放心购渠道
*/
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', 'jingxi', 'douyin', 'dewu', 'vipshop', 'vipshop-jx'];
const STORE_RECEIVING_TABS = ['taobao-alipay', 'taobao-wechat', 'pinduoduo', 'jd-wallet', 'jd-transactions', 'jingxi', 'douyin', 'dewu', 'vipshop', 'vipshop-jx'];
function pageContext(pathname = window.location.pathname) {
const parts = (pathname || '').split('/').filter(Boolean);
const idx = parts.indexOf('workspace');
if (idx === -1) {
return { companyId: '', section: '', page: '', tab: '' };
}
return {
companyId: idx > 0 ? parts[idx - 1] : '',
section: parts[idx + 1] || '',
page: parts[idx + 2] || '',
tab: parts[idx + 3] || '',
};
}
function resolveComponent(context) {
const alipayBase = context.companyId
? `/${context.companyId}/ecommerce-finance/alipay-bills`
: '/ecommerce-finance/alipay-bills';
const accountBase = context.companyId
? `/${context.companyId}/ecommerce-finance/account-bills/type/${encodeURIComponent(context.tab)}`
: `/ecommerce-finance/account-bills/type/${encodeURIComponent(context.tab)}`;
// 店铺收款账户账单 › 淘系支付宝账户(独立实现)
if (context.page === 'store-receiving-bills' && context.tab === 'taobao-alipay') {
const exportBase = context.companyId
? `/${context.companyId}/ecommerce-finance/alipay-bills/export`
: '/ecommerce-finance/alipay-bills/export';
return { Component: TaobaoAlipayBills, props: { apiBase: alipayBase, exportBase } };
}
// 店铺收款账户账单 › 其它账户类型(通用实现)
if (context.page === 'store-receiving-bills' && GENERIC_TABS.indexOf(context.tab) !== -1) {
return { Component: AccountBills, props: { apiBase: accountBase, billType: context.tab } };
}
return null;
}
const mount = document.querySelector('.business-blank-page');
if (mount) {
const initialContext = pageContext();
// Vue replaces the original mount node; keep the identity across local tab switches.
const preferencesUser = mount.dataset.tablePreferencesUser || 'anonymous';
const titleSuffix = document.title.includes(' - ') ? document.title.slice(document.title.lastIndexOf(' - ')) : '';
function isStoreReceivingContext(context) {
return context.page === 'store-receiving-bills'
&& STORE_RECEIVING_TABS.indexOf(context.tab) !== -1;
}
function updateActiveTab(tab) {
document.querySelectorAll('.business-tab-link').forEach((link) => {
const linkContext = pageContext(new URL(link.href, window.location.origin).pathname);
const isActive = linkContext.tab === tab;
link.classList.toggle('is-active', isActive);
if (isActive) {
link.setAttribute('aria-current', 'page');
} else {
link.removeAttribute('aria-current');
}
});
const label = document.querySelector('.business-tab-link[aria-current="page"] span:last-child')?.textContent.trim();
const title = document.querySelector('h1 [data-title-truncate]');
if (label && title) {
title.textContent = label;
document.title = label + titleSuffix;
}
}
/* eslint-disable no-new */
const workspace = new Vue({
el: mount,
data: {
context: initialContext,
},
render(h) {
const resolved = resolveComponent(this.context);
if (resolved) {
return h(resolved.Component, {
key: this.context.tab,
props: { ...resolved.props, userKey: preferencesUser },
});
}
return h('div', { class: 'business-page-empty' }, '该页面尚未实现');
},
});
function navigate(url, pushState = true) {
const target = new URL(url, window.location.origin);
const nextContext = pageContext(target.pathname);
if (target.origin !== window.location.origin || !isStoreReceivingContext(nextContext)) {
return false;
}
if (pushState && target.pathname !== window.location.pathname) {
window.history.pushState({}, '', `${target.pathname}${target.search}${target.hash}`);
}
workspace.context = nextContext;
updateActiveTab(nextContext.tab);
return true;
}
const tabBar = document.querySelector('.business-tab-bar');
if (tabBar) {
tabBar.addEventListener('click', (event) => {
const link = event.target.closest('.business-tab-link');
if (!link
|| event.button !== 0
|| event.metaKey
|| event.ctrlKey
|| event.shiftKey
|| event.altKey
) {
return;
}
const nextContext = pageContext(new URL(link.href, window.location.origin).pathname);
if (!isStoreReceivingContext(nextContext)) {
return;
}
// 在标签栏捕获阶段阻止原始链接和全局导航监听器,避免整页刷新。
event.preventDefault();
event.stopPropagation();
navigate(link.href);
}, true);
}
window.addEventListener('popstate', () => {
navigate(window.location.href, false);
});
updateActiveTab(initialContext.tab);
}