Files
junhong_cmp_fiber/docs/前端建设/前端选型与代码组织.md
break 5ba227eff5
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 1m8s
111
2026-07-29 14:58:28 +08:00

7.6 KiB
Raw Blame History

前端选型与代码组织

状态:推荐方案,尚未创建脚手架或安装依赖。

一、推荐结论

推荐使用 Vue 3 + TypeScript + Vite并采用 pnpm workspace 单仓库、三个独立应用:

frontend/
├── apps/
│   ├── admin-web/       # 管理 Web
│   ├── admin-h5/        # 管理 H5
│   └── client-h5/       # 独立 C 端 H5
└── packages/
    └── api/             # OpenAPI 生成类型和请求客户端

推荐组合:

领域 选择 理由
框架 Vue 3 + TypeScript 管理后台和 H5 生态成熟,单文件组件适合页面型业务
构建 Vite 配置少,三应用可独立构建和发布
工作区 pnpm workspace 只解决多应用依赖和共享 API 包,不引入额外编排平台
管理 Web UI Element Plus 表格、表单、树、分页、弹窗等后台能力完整
管理 H5/C 端 UI Vant 移动表单、列表、弹层、支付结果页等 H5 交互成熟
路由 Vue Router 三个应用分别维护静态路由表
客户端状态 Pinia 只保存登录态、当前用户、菜单和按钮权限
接口类型 openapi-typescript 从现有 OpenAPI 生成 TypeScript 类型
请求客户端 openapi-fetch + 原生 fetch 类型直接复用,减少手写接口和额外封装

不在首期引入Nx、Turborepo、大型后台模板、服务端状态缓存库、自研组件库、微前端。

二、为什么建议三个应用

管理 Web 和管理 H5 使用同一套后端业务与权限,但它们是两个真实的交互界面:

  • Web 以高密度表格、批量操作、复杂配置为主。
  • 管理 H5 以资产查询、现场操作、审批、资金和通知为主。
  • 两端登录分别传 device=webdevice=h5,后端会返回不同菜单。
  • Element Plus 和 Vant 的布局与交互模型不同,强行在一个应用混用会增加条件渲染和包体积。
  • C 端 H5 使用完全不同的个人客户认证、微信 OAuth、支付回跳和资产绑定流程必须独立。

三个应用放在同一仓库,可以统一 TypeScript、Lint、构建和 OpenAPI 类型,又不会把三种页面体验绑在一个发布包中。

三、何时可以改成两个应用

如果管理 H5 最终只保留以下少量页面,可以使用“自适应管理端 + C 端 H5”两应用方案

  • 登录和个人中心。
  • 通知。
  • 统一资产搜索和只读详情。
  • 少量订单、退款、换货审批。

一旦管理 H5 需要独立导航、设备控制、企业授权、资金、上传或大量移动表单,就应使用独立 admin-h5。当前页面矩阵已经超过纯只读壳层,因此默认采用三个应用。

四、共享边界

首期只共享 packages/api

Go 路由和 DTO
      ↓
docs/admin-openapi.yaml
      ↓
openapi-typescript
      ↓
packages/api 类型与客户端
      ↓
admin-web / admin-h5 / client-h5

暂不共享:

  • 页面组件。
  • 登录页面。
  • 业务状态管理。
  • Web/H5 表单组件。
  • 业务流程组合函数。

等两个应用出现真实、稳定、完全相同的重复后再提取。不要先创建 shared-businessshared-components 等空泛包。

五、推荐仓库结构

frontend/
├── apps/
│   ├── admin-web/
│   │   └── src/
│   │       ├── app/
│   │       ├── pages/
│   │       ├── routes/
│   │       └── stores/
│   ├── admin-h5/
│   │   └── src/
│   │       ├── app/
│   │       ├── pages/
│   │       ├── routes/
│   │       └── stores/
│   └── client-h5/
│       └── src/
│           ├── app/
│           ├── pages/
│           ├── routes/
│           └── stores/
├── packages/
│   └── api/
│       ├── generated/
│       ├── client.ts
│       └── index.ts
├── package.json
├── pnpm-workspace.yaml
└── tsconfig.base.json

目录保持扁平。页面内部先就近放置组件,不按 api/service/model/controller 重建一套前端分层。

六、请求模块的唯一职责

packages/api 只负责:

  1. OpenAPI 生成类型。
  2. Base URL。
  3. Bearer Token 注入。
  4. 管理端 Refresh Token 单次刷新队列。
  5. {code,msg,data,timestamp} 解包。
  6. 401、403、429、5xx 统一错误事件。
  7. Request ID 提取。

它不负责:

  • 页面跳转。
  • Toast 文案拼接。
  • 将订单状态改成本地状态机。
  • 缓存所有列表和详情。
  • 替页面吞掉错误。

这使请求模块保持为一个小接口、深实现的公共模块,三应用只需要学习同一套调用方式。

七、动态菜单实现

后端菜单只决定“哪些本地路由可见和可进入”,不能直接决定加载哪个源代码文件。

正确方式:

  1. 每个管理应用维护静态路由表:routeKey/url → 页面组件
  2. 登录后读取 menus
  3. 将后端菜单与本地静态路由表求交集。
  4. 生成导航和路由白名单。
  5. 未匹配到本地页面时记录告警并隐藏,不允许字符串动态 import 任意组件。
  6. 使用 buttons 控制操作按钮。

八、状态管理边界

Pinia 首期只保存:

  • Access Token、Refresh Token。
  • 当前用户。
  • 菜单、按钮和权限码。
  • 当前终端类型。
  • 少量跨页面 UI 状态。

订单列表、资产详情、套餐列表等服务端数据由页面直接请求并局部刷新。等出现跨页面共享缓存、复杂失效和后台自动刷新需求后,再评估服务端状态库。

九、OpenAPI 工作流

建议建立固定流水线:

go run ./cmd/gendocs
        ↓
更新 docs/admin-openapi.yaml
        ↓
生成 packages/api/generated
        ↓
TypeScript 类型检查
        ↓
构建三个应用

生成文件不手改。字段不正确时修改 Go DTO、RouteSpec 或文档生成器,然后重新生成。

当前 admin-openapi.yaml 同时包含管理端、C 端、开放接口和回调,文件名虽然偏旧,但首期无需为前端拆分多份 OpenAPI。

十、方案对比

方案 优点 风险 结论
Vue 三应用单仓库 Web/H5 体验清晰;共享接口类型;独立发布 有少量工程重复 推荐
Vue 自适应管理端 + C端H5 少一个应用,首期代码更少 Web/H5 组件混用、条件页面和包体增长 仅管理 H5 很小时使用
React 三应用 也能满足需求,团队成熟时可选 当前没有团队技术偏好,初始约定和库选择更多 团队明显更熟 React 时替换推荐方案

如果实施团队已有稳定 React 经验,应优先服从团队能力,使用 React + TypeScript + Vite、Ant Design、Ant Design Mobile仍保持“三应用单仓库只共享 OpenAPI 包”的结构,不必为追求 Vue 统一而增加学习成本。

十一、创建脚手架前需要确认

  1. 前端团队更熟 Vue 还是 React。
  2. 管理 H5 是否作为独立正式产品发布。
  3. 三个应用的域名、Base URL 和环境配置。
  4. 微信公众号 OAuth 回调域名和支付回跳地址。
  5. 首期页面范围及权限种子数据。
  6. 后端企业数据范围和逐接口权限门禁是否完成验证。

十二、参考资料