From 75bebcbb58de3ab0cf39923a8d31b07e21f1b518 Mon Sep 17 00:00:00 2001 From: gqt <3217233537@qq.com> Date: Mon, 8 Jun 2026 20:13:38 +0800 Subject: [PATCH] docs: add merged venue miniapp design --- .../2026-06-08-merged-venue-miniapp-design.md | 412 ++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-08-merged-venue-miniapp-design.md diff --git a/docs/superpowers/specs/2026-06-08-merged-venue-miniapp-design.md b/docs/superpowers/specs/2026-06-08-merged-venue-miniapp-design.md new file mode 100644 index 0000000..4f9d3a6 --- /dev/null +++ b/docs/superpowers/specs/2026-06-08-merged-venue-miniapp-design.md @@ -0,0 +1,412 @@ +# 合并版场馆小程序设计 + +## 背景 + +当前有两套独立系统: + +- 冰场馆小程序:前端为 uni-app 微信小程序,后端为 Django,部署在 `https://venue.test.chatgqt.top/`。 +- 综合场馆小程序:前端为 uni-app 微信小程序,后端为 Django,部署在 `https://venue2.test.chatgqt.top/`。 + +两个项目的后端、数据库、Django admin、CI/CD 都保持独立。本次只合并小程序端,在 `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序` 下新增合并版小程序项目。 + +两套旧小程序当前都配置同一个微信小程序 `appid`:`wx516b3e0d9940c788`。合并版继续沿用该 `appid`,不引入新的微信小程序身份。 + +## 目标 + +构建一个合并版 uni-app 微信小程序: + +- 用户首次进入时选择“冰场馆”或“综合场馆”。 +- 小程序内可以切换当前场馆。 +- 两个场馆的业务页面、登录态、API 请求和后端数据完全隔离。 +- 不合并、不改造两个 Django 后端、数据库、Django admin 和后端 CI/CD。 +- 新项目能独立安装依赖并构建微信小程序产物。 + +## 非目标 + +- 不统一两个后端接口协议。 +- 不迁移或合并会员数据、订单数据、课程数据、会员卡数据。 +- 不改造 Django admin。 +- 不新增统一后台或网关服务。 +- 不强制保留旧小程序的底部四个 Tab 结构。 +- 不重做业务页面视觉设计,只做必要的入口、切换和隔离改造。 + +## 推荐方案 + +采用“模块隔离合并”方案。 + +新项目保留两个业务模块: + +- `ice`:冰场馆模块。 +- `comprehensive`:综合场馆模块。 + +每个模块保留自己的页面、API、状态管理、业务工具和资源。公共层只负责场馆选择、当前场馆持久化、跨模块跳转和基础应用配置。 + +该方案的核心取舍是:牺牲一部分目录重复,换取后端隔离、登录态隔离、支付隔离和后续维护清晰度。 + +## 工程结构 + +新项目目录: + +```text +/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/ + miniprogram/ + package.json + vite.config.js + .env + .env.example + src/ + App.vue + main.js + manifest.json + pages.json + uni.scss + pages/ + venue-select/ + index.vue + ice/ + home/ + courses/ + bookings/ + profile/ + activities/ + comprehensive/ + home/ + courses/ + bookings/ + profile/ + activities/ + private/ + tickets/ + orders/ + pay/ + modules/ + ice/ + api/ + stores/ + utils/ + comprehensive/ + api/ + stores/ + utils/ + components/ + stores/ + venue.js + utils/ + venue.js + styles/ + variables.scss + static/ + ice/ + comprehensive/ +``` + +`pages` 放小程序实际路由页面,`modules` 放模块专属 API、状态和工具。页面通过模块专属路径导入业务能力,避免复用同名全局 API。 + +## 路由设计 + +`pages.json` 的第一个页面为: + +```text +pages/venue-select/index +``` + +旧页面迁移时统一加场馆前缀: + +```text +pages/ice/home/index +pages/ice/courses/index +pages/ice/courses/detail +pages/ice/bookings/index +pages/ice/bookings/detail +pages/ice/profile/index +pages/ice/profile/cards +pages/ice/profile/card-history +pages/ice/profile/detail +pages/ice/activities/detail + +pages/comprehensive/home/index +pages/comprehensive/courses/index +pages/comprehensive/courses/detail +pages/comprehensive/courses/confirm +pages/comprehensive/bookings/index +pages/comprehensive/bookings/course-detail +pages/comprehensive/bookings/private-detail +pages/comprehensive/profile/index +pages/comprehensive/profile/detail +pages/comprehensive/profile/orders +pages/comprehensive/profile/tickets +pages/comprehensive/profile/balance +pages/comprehensive/activities/index +pages/comprehensive/activities/detail +pages/comprehensive/private/index +pages/comprehensive/private/confirm +pages/comprehensive/tickets/index +pages/comprehensive/orders/detail +pages/comprehensive/pay/index +``` + +页面内所有 `uni.navigateTo`、`uni.redirectTo`、`uni.reLaunch`、`uni.switchTab` 目标都改为带模块前缀的路径。 + +由于用户没有要求保留旧 Tab,合并版可以先不配置全局 `tabBar`。模块内通过页面入口和按钮跳转完成导航。这样能避免一个小程序只能有一套全局 tabBar 带来的耦合。 + +## 场馆选择与切换 + +公共场馆状态使用 Pinia store 和本地存储: + +```text +CURRENT_VENUE_KEY = "CURRENT_VENUE" +``` + +可选值: + +```text +ice +comprehensive +``` + +流程: + +1. 用户首次进入 `pages/venue-select/index`。 +2. 如果本地已有 `CURRENT_VENUE`,页面可以展示当前场馆并提供继续进入或切换。 +3. 用户选择场馆后,写入 `CURRENT_VENUE`。 +4. 根据场馆跳转到对应首页: + - 冰场馆:`/pages/ice/home/index` + - 综合场馆:`/pages/comprehensive/home/index` +5. 小程序内的切换入口跳回 `pages/venue-select/index` 或直接调用公共切换方法。 +6. 切换当前场馆不清除另一套 token,用户切回原场馆后保持该后端的登录态。 + +建议在两个模块的“我的/会员中心”页面添加“切换场馆”入口,跳转到 `/pages/venue-select/index`。 + +## API 与环境变量 + +两个后端使用独立 baseURL: + +```text +VITE_ICE_API_BASE_URL=https://venue.test.chatgqt.top +VITE_COMPREHENSIVE_API_BASE_URL=https://venue2.test.chatgqt.top +``` + +冰场馆请求封装放在: + +```text +src/modules/ice/api/request.js +``` + +综合场馆请求封装放在: + +```text +src/modules/comprehensive/api/request.js +``` + +两个模块都可以继续使用后端现有响应协议 `{ code, data, message }`,但错误归一化逻辑不共用。这样可以保留冰场馆对 `40002` 资料完善、`40003` 绑定冲突等错误码的处理,也保留综合场馆上传、支付、订单相关的现有处理。 + +Vite H5 开发代理可配置两个前缀: + +```text +/ice-api -> VITE_ICE_API_BASE_URL +/comprehensive-api -> VITE_COMPREHENSIVE_API_BASE_URL +``` + +微信小程序构建时直接使用完整后端 URL。 + +## 登录态隔离 + +冰场馆保留: + +```text +ICE_MEMBER_TOKEN +ICE_MEMBER_TOKEN_EXPIRES_AT +``` + +综合场馆保留: + +```text +COMPREHENSIVE_VENUE_TOKEN +``` + +两个模块各自调用 `uni.login({ provider: "weixin" })`。登录得到的 code 只提交给当前模块对应后端: + +- 冰场馆:`https://venue.test.chatgqt.top/api/auth/wechat-login` +- 综合场馆:`https://venue2.test.chatgqt.top/api/auth/wechat-login` + +因为合并版沿用旧项目共同的 `appid`,不需要为新 `appid` 改两个后端微信登录配置。 + +## 支付隔离 + +综合场馆的 `pages/comprehensive/pay/index` 继续只使用综合场馆模块 API。微信支付参数由综合场馆后端生成,前端只调用 `uni.requestPayment`。 + +冰场馆模块不复用综合场馆订单和支付 API。任何支付相关跳转都必须保持在 `pages/comprehensive/*` 路由内。 + +## 样式与资源 + +全局 `styles/variables.scss` 采用两套项目共有变量,并以综合场馆版本为基础补齐冰场馆需要的变量和 mixin: + +- `$bg-color-main` +- `$bg-color-soft` +- `$bg-color-hover` +- `$bg-color-panel` +- `$text-color-*` +- `$color-primary` +- `$color-success` +- `$color-warning` +- `$color-danger` +- `$border-*` +- `$spacing-*` +- `minimal-card` +- `text-ellipsis` + +全局 `App.vue` 保留基础页面样式、按钮 reset、容器类、状态 badge、固定底部操作栏等公共规则。页面级样式随页面复制,减少重写成本。 + +静态资源按模块隔离: + +```text +src/static/ice/tab/* +src/static/comprehensive/tab/* +``` + +如果不配置全局 tabBar,旧 tab 图标只作为后续模块内导航备用资源。 + +## 文件迁移策略 + +复制时排除: + +- `node_modules` +- `dist` +- `.git` +- `.idea` +- `.DS_Store` +- 后端目录 +- 旧项目 `.env` 中的临时 frp 地址 + +优先以综合场馆小程序为工程基线,因为它已有 Pinia store、上传、支付、订单等更完整能力。冰场馆页面和 API 迁入独立模块。 + +所有旧的 `@/api/` 导入都改为模块路径: + +```text +@/modules/ice/api/ +@/modules/comprehensive/api/ +``` + +综合场馆 `defineStore("session")` 改为专属 ID: + +```text +defineStore("comprehensiveVenueSession") +``` + +如果冰场馆新增 store,也使用 `iceVenueSession`、`iceVenueProfile` 这类 `iceVenue` 前缀。 + +## 错误处理 + +场馆选择页: + +- 本地值不是 `ice` 或 `comprehensive` 时视为未选择。 +- 跳转失败时展示 toast,并停留在选择页。 + +API 请求: + +- 401 或后端登录过期错误只清理当前模块 token。 +- 网络错误只影响当前模块页面。 +- 切换场馆不触发任何后端请求,避免误清理另一模块登录态。 + +登录: + +- `uni.login` 未返回 code 时提示用户重试。 +- 后端返回绑定冲突、资料未完善等错误时沿用模块现有页面状态处理。 + +支付: + +- 支付失败或取消只影响综合场馆订单页面。 +- 不新增跨场馆支付状态。 + +## 测试与验收 + +基础验证: + +- 在 `场馆小程序/miniprogram` 执行 `npm install`。 +- 执行 `npm run build:mp-weixin`,确认能生成微信小程序产物。 + +路由验证: + +- 首次进入展示场馆选择页。 +- 选择冰场馆后进入 `/pages/ice/home/index`。 +- 选择综合场馆后进入 `/pages/comprehensive/home/index`。 +- 两个模块内主要页面跳转不再引用旧的 `/pages/home/index` 等无前缀路径。 + +API 验证: + +- 冰场馆页面请求使用 `VITE_ICE_API_BASE_URL`。 +- 综合场馆页面请求使用 `VITE_COMPREHENSIVE_API_BASE_URL`。 +- 冰场馆 token 不会出现在综合场馆请求头中。 +- 综合场馆 token 不会出现在冰场馆请求头中。 + +登录验证: + +- 冰场馆登录后写入 `ICE_MEMBER_TOKEN`。 +- 综合场馆登录后写入 `COMPREHENSIVE_VENUE_TOKEN`。 +- 切换场馆不会删除另一场馆 token。 + +支付验证: + +- 综合场馆支付页仍只调用综合场馆订单和支付 API。 +- 冰场馆页面没有误跳到综合支付页。 + +微信后台上线前检查: + +- 微信小程序 request 合法域名包含 `venue.test.chatgqt.top`。 +- 微信小程序 request 合法域名包含 `venue2.test.chatgqt.top`。 +- 如综合场馆支付上线,需要确认微信支付商户、回调和综合场馆后端配置保持现状。 + +## 难度 + +整体难度为中等偏上。 + +主要工作量不是新增业务,而是批量迁移: + +- 页面路径加模块前缀。 +- 页面内跳转路径同步修改。 +- API import 路径改为模块专属路径。 +- 两套样式和公共组件合并。 +- 验证两个模块的登录态、请求、支付不会串线。 + +## 风险与缓解 + +路由漏改: + +- 使用全文搜索检查旧路径:`/pages/home`、`/pages/courses`、`/pages/bookings`、`/pages/profile`、`/pages/pay`。 +- 构建后通过主要路径手动跳转验证。 + +API 串线: + +- 禁止使用全局 `src/api/request.js`。 +- 每个模块保留独立 `request.js` 和独立 env 变量。 +- 验证请求 URL 和 Authorization token。 + +登录态污染: + +- 保留并强化 token key 命名空间。 +- 401 只清理当前模块 token。 + +样式互相影响: + +- 公共样式只放基础 reset 和共用工具类。 +- 模块页面样式尽量保留在单文件组件内。 + +支付误接: + +- 支付页面只存在于 `pages/comprehensive/pay/index`。 +- 支付 API 只从 `src/modules/comprehensive/api/order.js` 导入。 + +微信后台配置遗漏: + +- 上线前将两个后端域名都加入合法域名。 +- 因沿用旧 `appid`,不新增后端微信登录配置变更。 + +## 交付结果 + +完成后应得到一个新的合并版小程序项目: + +```text +/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram +``` + +它可以独立构建微信小程序。用户首次进入选择场馆,后续可在小程序内切换;两个场馆后端、登录态、支付和业务数据仍完全隔离。