From 446baf5939e010f9bd9c8d3261dfc357db9097c1 Mon Sep 17 00:00:00 2001 From: joey-home Date: Thu, 3 Sep 2026 21:40:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(web):=20=E5=BA=97=E9=93=BA=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=A1=B5=E4=B8=8E=E9=A1=B5=E5=A4=B4=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=99=A8=E6=8E=A5=E5=85=A5=E7=9C=9F=E5=AE=9E?= =?UTF-8?q?=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 页头平台选择器:PlatformProvider 加载平台目录与平台上下文 (X-Atlas-Platform-Id header),平台 id 仅作为非敏感 UI 偏好存 localStorage,默认取目录第一家(Ozon 优先) - 店铺管理页覆盖 docs/api/stores-and-platforms.md 已实现接口: 游标分页列表、创建(202+operation)、编辑(If-Match 乐观锁、 409 刷新提示)、设为默认、重新验证凭据、仓库同步(422 脱敏 错误展示)、软删除(DEFAULT_STORE_REPLACEMENT_REQUIRED 提示) - services/api.ts 新增 getList(保留 {data, meta} 分页信封)与 apiErrorCode;services/stores.ts 按契约生成 Idempotency-Key - @atlas/contracts 补充只读响应类型 Platform / PlatformContext / CursorPaginationMeta / StoreOperationResponse(无行为变更) - API Key 仅存在于提交瞬间的内存表单,不落任何存储 - 浏览器实测:注册→平台切换→创建/编辑/设默认/删除保护/同步 错误路径→刷新会话恢复全部通过;typecheck + production build 通过 --- apps/web/src/layouts/MainLayout.css | 19 + apps/web/src/layouts/MainLayout.tsx | 2 + apps/web/src/layouts/PlatformSelector.tsx | 46 ++ apps/web/src/pages/shops/ShopsPage.css | 11 + apps/web/src/pages/shops/ShopsPage.tsx | 626 +++++++++++++++++++++- apps/web/src/router/index.tsx | 6 +- apps/web/src/services/api.ts | 22 +- apps/web/src/services/platform.tsx | 145 +++++ apps/web/src/services/stores.ts | 74 +++ docs/project/HANDOFF.md | 15 +- packages/contracts/src/stores.ts | 34 ++ 11 files changed, 991 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/layouts/PlatformSelector.tsx create mode 100644 apps/web/src/pages/shops/ShopsPage.css create mode 100644 apps/web/src/services/platform.tsx create mode 100644 apps/web/src/services/stores.ts diff --git a/apps/web/src/layouts/MainLayout.css b/apps/web/src/layouts/MainLayout.css index 0657489..810437c 100644 --- a/apps/web/src/layouts/MainLayout.css +++ b/apps/web/src/layouts/MainLayout.css @@ -102,6 +102,25 @@ gap: 12px; } +/* 页头平台选择器:图标 + 无边框下拉,视觉与用户触发区一致 */ +.platform-selector { + display: flex; + align-items: center; + gap: 4px; + padding: 2px 8px; + border-radius: 6px; + transition: background 0.2s; +} + +.platform-selector:hover { + background: #f3f4f6; +} + +.platform-selector-icon { + color: var(--primary-color); + font-size: 15px; +} + /* 头像 + 用户名触发区:hover 有浅色背景反馈,暗示可下拉 */ .header-user-trigger { display: flex; diff --git a/apps/web/src/layouts/MainLayout.tsx b/apps/web/src/layouts/MainLayout.tsx index 56f8400..26683aa 100644 --- a/apps/web/src/layouts/MainLayout.tsx +++ b/apps/web/src/layouts/MainLayout.tsx @@ -10,6 +10,7 @@ import { UserOutlined, } from '@ant-design/icons'; import SidebarMenu from './SidebarMenu'; +import PlatformSelector from './PlatformSelector'; import { getBreadcrumbItems } from './menuConfig'; import { useSession } from '@/services/session'; import './MainLayout.css'; @@ -156,6 +157,7 @@ const MainLayout = () => { {session && (
+ { + const { + platforms, + currentPlatform, + selectPlatform, + context, + contextLoading, + } = usePlatform(); + + if (platforms.length === 0) return null; + + const tooltip = context?.default_store + ? `当前平台:${currentPlatform?.name},默认店铺:${context.default_store.name}` + : '选择当前平台'; + + return ( + +
+ + + + + + + + + + + + + +