跳到主要内容

BBC 8.0 前端架构

本文档描述 BBC 8.0 PC UI 的三个 Web 应用与共享包边界、运行时启动、登录会话、请求链路、动态权限路由、配置系统和构建产物。

本文只覆盖 PC UI workspace,不描述移动端工程、后端服务内部实现、数据库或中间件架构。具体编码步骤见新增页面开发指引,环境变量见配置文件,构建命令见运行发布,正式部署见部署 PC 前端

页面存在不等于功能可见

BBC 8.0 平台端和商家端的菜单、层级、排序及角色权限以后端 current 菜单接口为准;部分页面还受功能开关控制。不能只根据源码中存在某个页面就判断当前环境已开放该功能。

1. 架构定位

BBC 8.0 PC UI 是一个基于 Vue 3、TypeScript、Vite 和 pnpm workspace 的多应用单仓库。仓库同时包含三个可独立构建的 Web 应用和多个共享包:

  • apps/pc:买家 PC 端。
  • apps/seller:商家后台。
  • apps/admin:平台管理后台。
  • packages/*:跨端运行时、接口类型、通用组件、配置、装修和客服等共享能力。

架构的核心目标是:

  1. 三端共享基础设施,但保留端内业务边界。
  2. 登录、接口和菜单等端侧差异通过注入接入共享运行时。
  3. 后台菜单结构和权限以后端返回为准,前端只维护页面能力。
  4. 环境与部署差异通过配置与构建链路表达,不散落在页面代码中。

2. 系统上下文

shop-tnt 系统上下文

前端仓库不定义后端服务、数据库或中间件架构。前端只依赖部署环境提供的 Base、Buyer、Seller、Admin API 地址,以及上传和实时消息所需的外部能力。

3. 代码组织与职责

3.1 顶层目录

.
├── apps/
│ ├── pc/
│ ├── seller/
│ └── admin/
├── packages/
│ ├── api/
│ ├── chat/
│ ├── components/
│ ├── config/
│ ├── core/
│ ├── decor/
│ ├── locales/
│ └── utils/
├── config/ # 仓库默认配置
├── scripts/ # 质量检查和辅助脚本
├── types/ # 全局类型声明
├── package.json
└── pnpm-workspace.yaml

3.2 应用层

应用主要职责关键入口
apps/pc买家页面、购物车、结算、会员中心和前台客服入口src/main.tssrc/router/index.tssrc/storesrc/api
apps/seller商家商品、订单、促销、店铺、财务和客服后台src/main.tssrc/router/*src/viewssrc/api
apps/admin平台商品、订单、会员、店铺、财务、运营、系统与权限后台src/main.tssrc/router/*src/viewssrc/api

应用拥有自己的页面、端内路由、端内 API 和业务状态。应用之间不得互相导入内部文件;确实需要跨端复用的能力应提升到合适的 packages/*

3.3 共享包

职责关键入口
@shop-tnt/core应用启动、路由守卫、登录会话、权限菜单、主题、全局上下文和 push-channelpackages/core/index.ts
@shop-tnt/api请求辅助、Base 公共接口、上传能力和后端生成类型packages/api/index.ts
@shop-tnt/components跨端公共组件、反馈服务和后台布局组件packages/components/index.ts
@shop-tnt/configAPI、域名、部署路径、资源前缀、功能开关和 Vite 配置工厂packages/config/index.ts
@shop-tnt/utilsHTTP 客户端、存储、HTML 安全、导航、国际化辅助和指令packages/utils/index.ts
@shop-tnt/locales语言资源、语言类型和路由标题映射packages/locales/index.ts
@shop-tnt/chat客服页面、聊天状态、未读消息和 push 消费packages/chat/index.ts
@shop-tnt/decor页面装修类型、编辑器、预览渲染和数据转换packages/decor/index.ts

decor 的根入口刻意保持轻量:买家预览使用 @shop-tnt/decor/pc-preview,后台装修编辑器使用 @shop-tnt/decor/editor,避免前台构建意外引入完整编辑器运行时。

3.4 依赖方向

Workspace 依赖方向

必须保持以下依赖约束:

  • packages/* 不得引用 apps/*
  • 一个 app 不得直接引用另一个 app。
  • utils 不持有页面、路由、Pinia 或具体业务端依赖。
  • core 只编排公共运行时;端侧接口通过参数注入,不在 core 中硬编码业务 URL。
  • 共享包之间出现循环依赖时,应重新检查职责,而不是通过路径技巧绕过。

4. 应用启动架构

三个应用都从各自的 src/main.ts 调用 @shop-tnt/corebootstrapApp

  • PC 注入买家刷新 token 接口和 PC store。
  • Seller 注入商家认证服务、权限路由安装器和 Seller store。
  • Admin 注入平台认证服务、权限路由安装器和 Admin store。

4.1 启动时序

应用启动时序

启动阶段先使用本地缓存的站点信息和主题完成首屏,再异步请求最新数据。站点信息或主题请求失败时保留已知缓存,不阻断应用挂载。

4.2 shopApp 运行时上下文

bootstrapApp 创建并注入 shopApp 上下文,主要包含:

  • 当前 appName、应用配置和 API scope。
  • 当前端隔离的存储 key。
  • 站点信息和主题状态。
  • 登录会话操作。
  • i18n 翻译函数和语言切换能力。
  • 后台明暗主题状态。
  • 公共 app store。
  • push-channel 客户端。

页面和共享组件通过注入读取这些能力,不应自行创建第二套全局运行时。

5. 状态分层

状态按生命周期分为三层:

层级典型内容位置
应用运行时上下文配置、站点、主题、认证服务、push-channelpackages/core/shop-app.ts
跨端全局状态页面 Loading、站点信息packages/core/app-store.ts
端内业务状态PC 用户、购物车;各端业务页面状态apps/*/src/store 或页面内 composable

Admin 和 Seller 当前只安装公共 app store,并把客服运行时接入 shopApp;PC 另外维护用户与购物车 store。页面私有、生命周期短的状态优先留在页面或 composable,不应全部提升到 Pinia。

6. 路由与权限架构

6.1 PC 静态路由

PC 路由主要维护在 apps/pc/src/router/index.ts,页面组件和路由层级由前端静态声明。常用 meta 包括:

  • title / i18nKey:页面标题。
  • requiresAuth:是否要求本地登录会话。
  • loginMode:需要登录时使用页面跳转还是弹窗。
  • layout:页面布局类型。
  • backName / backPath:二级页直达时的返回兜底。

PC 还可以在端内守卫中处理分销等业务访问条件;这些条件不进入后台动态菜单模型。

6.2 Admin/Seller 动态权限路由

Admin 和 Seller 使用“本地页面能力 + 后端菜单结构”的组合:

文件职责
router/index.ts登录页、根布局、首页、兜底页等基础静态路由
router/page-routes.ts扁平页面注册:name、绝对 path、meta、隐藏页关系
router/route-components.tsroute name 到实际 Vue 页面组件的映射
router/menu-icon-fallbacks.ts后端 icon 为空时的扁平兜底,不表达菜单层级
router/permission-routes.ts组合页面注册、组件、功能开关并创建权限安装器

后端 current 菜单树决定:

  • 用户可见哪些菜单。
  • 菜单父子层级和同级顺序。
  • 菜单标题。
  • 非空菜单图标。

前端决定:

  • identifier 对应哪个本地 route name。
  • 页面真实 URL 和 Vue 组件。
  • 隐藏详情页、编辑页和登录后流程页。
  • 后端 icon 缺失时的兼容图标。

6.3 权限路由生成时序

后台权限路由生成时序

children 的后端节点由 RouterView 承载,不需要创建前端占位页面。后端 identifier 找不到本地页面时,开发环境输出权限诊断;不应静默生成一个功能不明的兼容页面。

6.4 隐藏页与返回链路

详情、编辑和审核页通常不出现在菜单中。它们通过 hiddenbackName / backNames 跟随入口页面授权;authFlow 用于店铺认证、支付进件等登录后可访问但不属于菜单的系统流程。

二级页返回由 usePageBack() 统一解析:

  1. 优先使用入口通过 withReturnTo() 写入的安全 returnTo
  2. 其次使用路由 meta 的 backName
  3. 再使用安全的 backPath
  4. 最后回到端内默认兜底页面。

7. 登录会话与请求架构

7.1 会话所有权

packages/core/auth.ts 负责会话数据的标准化、读写、清理和跨标签通知;具体登录、登出、刷新 token、用户信息和菜单接口由各 app 的 authService 实现。

不同 app 通过 getStorageKeys(appName) 使用隔离的 user、access token、refresh token 等 key。登录态广播只携带 app 名和变化类型,不广播 token 内容。

7.2 请求分层

层级路径职责
HTTP 运行时packages/utils/request.tsAxios 实例、token、序列化、请求取消、刷新重试、Loading 和错误回调
API 辅助packages/api/request.tsapiGetapiPostapiPutapiDel、响应解包
公共基础接口packages/api/base.ts站点、主题、验证码、地区等跨端基础接口
后端生成类型packages/api/models/*.tsJava VO/DTO/DO 对应的 TypeScript 类型,不承载运行时请求函数
端内业务接口apps/*/src/api当前应用使用的商品、订单、会员、店铺等接口函数

packages/api/index.tsmodels 使用 type-only 导出。真正需要跨端复用的运行时接口应拥有明确模块和导出入口,不能依靠向生成类型文件加入函数来隐式暴露。

7.3 受保护请求时序

受保护请求生命周期

请求默认策略:

  • GET 请求默认登记为 route scope,路由切换时取消。
  • 提交、上传等请求默认不随路由切换取消。
  • 同一取消 scope 可通过 cancelKey 让新请求替换旧请求。
  • 并发请求刷新 token 时复用同一个 Promise,避免刷新风暴。
  • 命中会话过期条件的请求最多自动重试一次。
  • 页面只有在明确接管反馈时才关闭统一错误消息。

8. UI 与业务能力分层

组件按复用范围放置:

  • 只服务单个应用:apps/<app>/src/components
  • 跨端通用交互:packages/components
  • 页面装修:packages/decor
  • 客服聊天:packages/chat

packages/components 既包含基础交互,也包含跨后台复用的业务组件。高影响公共模式包括:

  • AppShell:后台整体布局和菜单宿主。
  • PageActionBar:二级页返回与主操作。
  • TableLayout:后台列表表格、分页、工具栏和抽屉。
  • BackendTabs:Admin/Seller 统一页签外观。
  • MoneyInput / UnitNumberInput:金额和单位数值输入契约。
  • 各类 Picker、导入导出、上传和验证码组件。

业务页面应从公共入口复用这些模式,不应通过复制组件或覆盖 TDesign 内部样式形成第二套交互规范。

9. 配置架构

配置分为“仓库默认值”和“环境覆盖值”:

配置读取架构

配置默认值读取封装
API 地址config/api.tspackages/config/api.ts
页面域名config/domain.tspackages/config/domain.ts
部署虚拟路径config/alias.tspackages/config/alias.ts
静态资源前缀config/assets.tspackages/config/assets.ts
功能开关config/features.tspackages/config/features.ts
应用名称与标题无独立根配置packages/config/apps.ts

API、域名、虚拟路径、CDN 和功能开关不应硬编码在页面。VITE_* 会进入浏览器产物,不能存放密钥、数据库密码或服务端令牌。

10. 构建架构

三端 vite.config.ts 都调用 packages/config/build/vite.tscreateViteConfig。共享工厂统一负责:

  • 注入 VITE_APP_NAME、应用标题和构建版本标识。
  • workspace 包别名。
  • rpx 到 px 转换。
  • @shop-tnt/components 直接导入处理。
  • Vue 和 TDesign 组件自动导入。
  • Vite base、CDN 资源前缀和 SCSS 配置。
  • 生产构建分包和压缩。
  • 生成固定路径的 version 文件,用于覆盖部署后的版本提示。

三端共享构建架构

构建模式只决定读取的环境和优化行为,不改变源码职责边界。测试、生产部署地址必须由对应 .env.* 明确提供。

11. 核心架构决策

决策原因影响
三端共用 bootstrapApp避免登录、请求、主题和路由守卫分叉端侧差异必须通过 service/setup hook 注入
后台菜单以后端 current 树为准权限、层级和展示保持同一事实来源前端页面 name 必须与 identifier 对齐
API 运行时与生成类型分离防止生成覆盖业务逻辑,保持契约可追踪models 只放生成类型,接口函数使用明确模块
共享包按真实复用提升避免三个 app 复制公共能力,也避免过度抽象单端业务默认留在 app,第二个真实使用方出现后再提升
decor 拆分 editor/preview 入口防止前台加载沉重编辑器依赖调用方必须选择正确子路径

12. 扩展点判断

新增能力前,按以下顺序判断归属:

新增能力归属判断

几个常见边界:

  • 新增 PC 页面:页面和静态路由都在 apps/pc
  • 新增 Admin/Seller 菜单页:页面注册、组件映射和后端菜单 identifier 必须共同成立。
  • 新增业务接口:当前端专用接口放端内 src/api;公共类型复用生成模型;真正跨端运行时接口使用明确共享模块。
  • 新增选择器、上传、表格等交互:先检查公共组件,确认多端真实复用后再新增共享组件。
  • 修改请求、会话、路由或构建:优先改共享入口并检查全部调用端。

13. 验证边界

架构层改动往往影响多个端。按当前项目规则使用以下最小验证:

改动范围最小验证
单个 apppnpm build:dev:<端>
packages/*config/*、根构建配置或多个 apppnpm build:dev
API、共享类型pnpm typecheck,并执行受影响构建
语言包pnpm locale:check
Markdown 文档pnpm exec prettier --check <文件>

构建通过只证明代码可以产出静态文件,不等于登录、菜单权限、接口契约或产品部署已经完成业务验收。

14. 文档事实来源

为避免架构文档变成过时描述,发生冲突时优先检查以下代码来源:

事实代码来源
workspace 应用和包pnpm-workspace.yaml、各目录 package.json
启动顺序和全局上下文packages/core/app.tsapps/*/src/main.ts
登录会话packages/core/auth.ts、各端 session/passport API
HTTP 行为packages/utils/request.tspackages/api/request.ts
后台权限路由packages/core/permission.tsapps/{admin,seller}/src/router
组件公开入口packages/components/index.ts
配置变量和优先级config/*packages/config/*
构建命令根和各 app 的 package.json

修改这些架构入口时,应在同一个变更中检查并更新本文档;具体实现始终优先于已经过时的描述。