配套 README.md,给出一个「运营后台」的完整拆分演练。
一个运营后台,含:
src/
app.js # 装配:provide 全局 service + 路由 + 根壳
components/ # 通用 UI(无业务耦合)
app-shell.js # 布局壳(菜单 + 标签 + 内容区)
side-menu.js # 侧边菜单(接收菜单数据,不自己拉接口)
tabs-bar.js # 多标签栏
tabs-container.js # KeepAlive 容器
base-table.js # 通用表格(列配置驱动)
base-modal.js # 通用弹窗(slot 内容)
modules/
auth/
page-login.js
auth-service.js # 登录态 + token + 权限码
user/
page-user-list.js
page-user-detail.js
user-service.js # 用户 CRUD
user-model.js # 用户数据结构 + 转换
order/
page-order-list.js
page-order-detail.js
order-service.js
services/ # 跨模块共享
dict-service.js # 数据字典(权限/订单模块都用)
menu-service.js # 菜单树(app-shell 用)
utils/
http.js
storage.js
format.js
router.js
| 代码 | 归属 | 理由 |
|---|---|---|
| 登录态、token、权限码 | modules/auth/auth-service.js |
认证是独立功能域 |
| 用户 CRUD | modules/user/user-service.js |
仅用户模块用 |
| 订单 CRUD | modules/order/order-service.js |
仅订单模块用 |
| 数据字典 | services/dict-service.js |
跨模块(用户、订单都拉下拉项)→ 上提 |
| 菜单树 | services/menu-service.js |
app-shell 用,且依赖权限 → 跨模块 |
| 表格 / 弹窗 | components/base-table.js 等 |
无业务耦合,可复用/可抽库 |
| http / storage | utils/ |
纯能力 |
page-user-list(视图)
├─ 读 dictService.roles(signal)→ 渲染筛选项
├─ 调 userService.fetchList(query) → 拿到数据
└─ 渲染 base-table(传入列配置 + 数据)
└─ 行点击 → dispatchEvent('row-click')
└─ page-user-list 收到 → router.navigate('/users/:id')
└─ tabsService.open(...) + toggle 激活 → KeepAlive
原则回顾:
services/,模块内的在模块目录。page-user-list → base-table、user-service、dictService ✅(上层依赖下层/共享)user-service → utils/http ✅utils/http → auth-service(取 token)⚠️ —— 这是「工具反向依赖服务」。
auth-service 注入 token getter 给 http,或 http 通过参数接收 token。configureHttp({ getToken: () => authService.getToken() }) 在 app.js 装配时调用。这样 utils 不 import services。user-service / dict-service 可在 Node 直接 import,mock http 后单测。format.js / storage.js 纯函数,直接断言。base-table 组件逻辑(列排序/选择)用 DOM 测试或抽纯函数到 utils 测。components/base-table.js。fmode-ui-table(ESM,无构建)。