From 04c3369e6df608eaa1b8902dd0acb9477cd8aaaa Mon Sep 17 00:00:00 2001 From: yml2213 Date: Tue, 6 Oct 2026 20:40:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(admin):=20=E9=A1=B6=E6=A0=8F=E5=B8=B8?= =?UTF-8?q?=E9=A9=BB=E6=98=BE=E7=A4=BA=E5=BD=93=E5=89=8D=E5=95=86=E6=88=B7?= =?UTF-8?q?=E4=B8=8A=E4=B8=8B=E6=96=87=E5=B9=B6=E6=8F=90=E4=BE=9B=E9=80=80?= =?UTF-8?q?=E5=87=BA=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:管理员的商户上下文存在 localStorage,之前只会在「平台商户」页点「成员」时被 写入,界面上没有任何提示,而且只在登录/登出时清除。管理员点过一次商户后,订单/商品/ 钱包/成员等商户后台页面会一直停在该商户视角,而首页看板仍是平台口径——两个数字 看起来互相矛盾却无法解释。 - MainLayout 顶栏为管理员常驻显示「当前商户:xxx」,并用 Tooltip 说明哪些页面受它影响 - 提供「退出商户视角」按钮:清除 localStorage 后整页刷新,保证当前页已加载的数据 也按新上下文重新取一遍(只在上下文确实存在时出现) - README 管理端章节同步说明 未做静默回退的取舍:商户上下文解析失败时后端仍返回 403。因为商户后台存在写操作 (人工下单、取消、成员管理),若自动回退到默认商户,写入会落到错误的商户上—— 这是比"多点一下退出"严重得多的问题。 --- README.md | 1 + frontend/src/layouts/MainLayout.tsx | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/README.md b/README.md index 625b3da..5ca8e6e 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,7 @@ POST /api/open/v1/orders/ship-notify 实际上订单页只显示了自营商户这一家。 商户上下文的来源是前端 `localStorage.merchant_id`,只会在「平台商户」页点「成员」时被写入。 +顶栏会常驻显示「当前商户:xxx」,点旁边的「退出商户视角」即可回到默认商户(自营商户)。 需要看某个下游商户的订单时,用「下游订单」页的商户筛选即可,不必切换上下文。 ## 目录结构 diff --git a/frontend/src/layouts/MainLayout.tsx b/frontend/src/layouts/MainLayout.tsx index ea0c7d8..fd4a8db 100644 --- a/frontend/src/layouts/MainLayout.tsx +++ b/frontend/src/layouts/MainLayout.tsx @@ -229,6 +229,16 @@ export default function MainLayout() { return localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === 'true' }) const { user, logout, refreshProfile, isAdmin, merchant, merchantPermissions } = useAuth() + // 管理员的商户上下文来自 localStorage(即请求头 X-Merchant-ID 的来源), + // 之前只会在「平台商户」页点「成员」时被写入,界面上没有任何提示—— + // 管理员很容易以为自己看的是全平台数据,实际被静默框定在某个商户里。 + const [activeMerchantId] = useState(() => localStorage.getItem('merchant_id')) + const merchantContextLabel = merchant?.name || (activeMerchantId ? `商户 #${activeMerchantId}` : '默认商户') + const exitMerchantContext = () => { + localStorage.removeItem('merchant_id') + // 整页刷新:上下文变了,当前页已经加载的数据也必须按新上下文重新取一遍。 + window.location.reload() + } const [passwordOpen, setPasswordOpen] = useState(false) const [passwordSaving, setPasswordSaving] = useState(false) const [passwordForm] = Form.useForm() @@ -421,6 +431,22 @@ export default function MainLayout() {
{isAdmin && ( + + + 当前商户:{merchantContextLabel} + + + {activeMerchantId && ( + + + + )}