From d17b646ae05899c9961ebae39f8e6b92647656ed Mon Sep 17 00:00:00 2001
From: gqt <3217233537@qq.com>
Date: Sun, 12 Jul 2026 19:57:37 +0800
Subject: [PATCH] docs: relocate docs into miniprogram/docs
---
docs/merged-miniapp-verification.md | 77 -
.../plans/2026-06-08-merged-venue-miniapp.md | 1683 -----------------
.../2026-06-08-merged-venue-miniapp-design.md | 412 ----
3 files changed, 2172 deletions(-)
delete mode 100644 docs/merged-miniapp-verification.md
delete mode 100644 docs/superpowers/plans/2026-06-08-merged-venue-miniapp.md
delete mode 100644 docs/superpowers/specs/2026-06-08-merged-venue-miniapp-design.md
diff --git a/docs/merged-miniapp-verification.md b/docs/merged-miniapp-verification.md
deleted file mode 100644
index 4f9aa25..0000000
--- a/docs/merged-miniapp-verification.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# 合并版场馆小程序验证记录
-
-## 构建
-
-- 命令:`npm run build:mp-weixin`
-- 结果:通过,命令退出码为 0
-- 产物:`miniprogram/dist/build/mp-weixin`
-- 备注:构建日志包含 uni-app 版本提示和 uview-plus/Sass 弃用警告,未出现编译错误。
-
-## 路由隔离
-
-- 检查旧的无前缀页面路径:通过
-- 冰场馆页面前缀:`pages/ice`
-- 综合场馆页面前缀:`pages/comprehensive`
-- `pages.json` 首个页面:`pages/venue-select/index`
-- `pages.json` 页面数量:30
-- 综合场馆页面数量:19
-- 冰场馆页面数量:10
-- 全局 `tabBar`:未配置
-
-## API 隔离
-
-- 冰场馆 baseURL:`VITE_ICE_API_BASE_URL`
-- 综合场馆 baseURL:`VITE_COMPREHENSIVE_API_BASE_URL`
-- 旧 `VITE_API_BASE_URL`:未使用
-- 旧全局 API import:未发现
-
-## 登录态隔离
-
-- 冰场馆 token:`ICE_MEMBER_TOKEN`
-- 冰场馆 token 过期时间:`ICE_MEMBER_TOKEN_EXPIRES_AT`
-- 综合场馆 token:`COMPREHENSIVE_VENUE_TOKEN`
-
-## 支付隔离
-
-- `uni.requestPayment` 仅出现在 `pages/comprehensive/pay/index.vue`
-- 综合场馆支付接口仅出现在 `modules/comprehensive/api/order.js`
-- 冰场馆模块未引用综合场馆支付页或支付 API
-
-## 自动化检查命令
-
-```bash
-cd /Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram
-npm run build:mp-weixin
-```
-
-```bash
-cd /Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序
-rg -n "@/api|@/stores/session|@/utils/(date|money|status)|@/components/StatePanel.vue" miniprogram/src/pages miniprogram/src/modules
-rg -n '\x27/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)|"/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)|`/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)' miniprogram/src/pages
-rg -n "VITE_API_BASE_URL" miniprogram/src/modules miniprogram/.env miniprogram/.env.example miniprogram/vite.config.js
-node -e "const fs=require('fs'); const p=JSON.parse(fs.readFileSync('miniprogram/src/pages.json','utf8')); const paths=p.pages.map(x=>x.path); console.log(JSON.stringify({first: paths[0], total: paths.length, comprehensive: paths.filter(x=>x.startsWith('pages/comprehensive/')).length, ice: paths.filter(x=>x.startsWith('pages/ice/')).length, hasTabBar: Boolean(p.tabBar)}, null, 2));"
-```
-
-## 微信开发者工具烟测
-
-当前终端环境未直接打开微信开发者工具执行人工烟测。上线或提审前需要在微信开发者工具中打开:
-
-```text
-/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/dist/build/mp-weixin
-```
-
-人工检查项:
-
-- 首次进入展示“选择场馆”。
-- 选择“冰场馆”进入 `pages/ice/home/index`。
-- 选择“综合场馆”进入 `pages/comprehensive/home/index`。
-- 两个模块的“会员中心/我的”可返回 `pages/venue-select/index` 切换场馆。
-- 冰场馆页面请求域名为 `https://venue.test.chatgqt.top`。
-- 综合场馆页面请求域名为 `https://venue2.test.chatgqt.top`。
-- 综合场馆支付页仍由综合场馆后端生成支付参数。
-
-## 上线前人工检查
-
-- 微信 request 合法域名包含 `venue.test.chatgqt.top`。
-- 微信 request 合法域名包含 `venue2.test.chatgqt.top`。
-- 综合场馆支付商户、回调和综合场馆后端配置保持现状。
diff --git a/docs/superpowers/plans/2026-06-08-merged-venue-miniapp.md b/docs/superpowers/plans/2026-06-08-merged-venue-miniapp.md
deleted file mode 100644
index 33850ac..0000000
--- a/docs/superpowers/plans/2026-06-08-merged-venue-miniapp.md
+++ /dev/null
@@ -1,1683 +0,0 @@
-# Merged Venue Miniapp Implementation Plan
-
-> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
-
-**Goal:** Build a new merged uni-app WeChat mini program under `场馆小程序/miniprogram` that lets users choose and switch between ice venue and comprehensive venue while keeping both Django backends, auth tokens, APIs, and business pages isolated.
-
-**Architecture:** The app uses one public venue selection shell and two isolated modules: `src/modules/ice` and `src/modules/comprehensive`. Route pages live under `src/pages/ice/*` and `src/pages/comprehensive/*`, while each module imports only its own API client and state. No backend code is changed.
-
-**Tech Stack:** uni-app, Vue 3, Vite 5, Pinia, uview-plus, dayjs, WeChat mini program target.
-
----
-
-## File Structure Map
-
-- Create `miniprogram/package.json`: merged project dependency and script manifest copied from the existing miniapp projects.
-- Create `miniprogram/package-lock.json`: copied from the comprehensive project first, then refreshed by `npm install` if needed.
-- Create `miniprogram/vite.config.js`: Vite + uni plugin config with two API env variables and two H5 proxy prefixes.
-- Create `miniprogram/.env`: production-like default backend URLs for both venues.
-- Create `miniprogram/.env.example`: local development URL examples for both venues.
-- Create `miniprogram/src/main.js`: Vue app bootstrap with Pinia and uview-plus.
-- Create `miniprogram/src/App.vue`: merged global styles and app lifecycle logging.
-- Create `miniprogram/src/manifest.json`: WeChat app manifest using `wx516b3e0d9940c788`.
-- Create `miniprogram/src/uni.scss`: shared SCSS imports.
-- Create `miniprogram/src/styles/variables.scss`: shared design variables and mixins.
-- Create `miniprogram/src/pages.json`: merged page registry, no global `tabBar` in first version.
-- Create `miniprogram/src/stores/venue.js`: public Pinia store for current venue selection.
-- Create `miniprogram/src/utils/venue.js`: venue constants, storage helpers, target home paths, and navigation helpers.
-- Create `miniprogram/src/pages/venue-select/index.vue`: first-entry venue selector and switch page.
-- Create `miniprogram/src/modules/comprehensive/api/*`: comprehensive backend API modules.
-- Create `miniprogram/src/modules/comprehensive/stores/session.js`: comprehensive session store with dedicated store id.
-- Create `miniprogram/src/modules/comprehensive/utils/*`: comprehensive business utility modules.
-- Create `miniprogram/src/pages/comprehensive/*`: comprehensive venue route pages.
-- Create `miniprogram/src/modules/ice/api/*`: ice backend API modules.
-- Create `miniprogram/src/components/ice/StatePanel.vue`: ice module state panel component.
-- Create `miniprogram/src/pages/ice/*`: ice venue route pages.
-- Create `miniprogram/src/static/comprehensive/tab/*`: comprehensive tab image assets for future module navigation.
-- Create `miniprogram/src/static/ice/tab/*`: ice tab image assets for future module navigation.
-
-## Source Roots
-
-- Existing comprehensive miniapp: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/综合场馆小程序/miniprogram`
-- Existing ice miniapp: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/冰场馆小程序/miniprogram`
-- New merged miniapp: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram`
-
-## Implementation Tasks
-
-### Task 1: Scaffold the Merged Miniapp Shell
-
-**Files:**
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/package.json`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/package-lock.json`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/vite.config.js`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/.env`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/.env.example`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/main.js`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/App.vue`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/manifest.json`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/uni.scss`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/styles/variables.scss`
-
-- [ ] **Step 1: Copy baseline project metadata**
-
-Run:
-
-```bash
-cp '/Volumes/ExternalStorageA/project/2026.5/体育场馆/综合场馆小程序/miniprogram/package.json' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/package.json'
-cp '/Volumes/ExternalStorageA/project/2026.5/体育场馆/综合场馆小程序/miniprogram/package-lock.json' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/package-lock.json'
-```
-
-Expected: both files exist in `场馆小程序/miniprogram`.
-
-- [ ] **Step 2: Update merged package metadata**
-
-Edit `miniprogram/package.json` to:
-
-```json
-{
- "name": "merged-venue-miniapp",
- "version": "0.1.0",
- "description": "冰场馆与综合场馆合并版微信小程序端",
- "type": "module",
- "scripts": {
- "dev:mp-weixin": "uni -p mp-weixin",
- "build:mp-weixin": "uni build -p mp-weixin",
- "dev:h5": "uni",
- "build:h5": "uni build"
- },
- "dependencies": {
- "@dcloudio/uni-app": "3.0.0-alpha-5000120260211001",
- "@dcloudio/uni-components": "3.0.0-alpha-5000120260211001",
- "@dcloudio/uni-h5": "3.0.0-alpha-5000120260211001",
- "@dcloudio/uni-mp-weixin": "3.0.0-alpha-5000120260211001",
- "dayjs": "^1.11.21",
- "pinia": "^2.3.1",
- "uview-plus": "^3.8.37",
- "vue": "^3.4.0"
- },
- "devDependencies": {
- "@dcloudio/uni-automator": "3.0.0-alpha-5000120260211001",
- "@dcloudio/uni-cli-shared": "3.0.0-alpha-5000120260211001",
- "@dcloudio/uni-stacktracey": "3.0.0-alpha-5000120260211001",
- "@dcloudio/vite-plugin-uni": "3.0.0-alpha-5000120260211001",
- "sass": "^1.83.0",
- "vite": "^5.2.0"
- }
-}
-```
-
-Expected: package name and description identify the merged app; dependencies remain identical to the two existing miniapps.
-
-- [ ] **Step 3: Create environment files**
-
-Create `miniprogram/.env`:
-
-```dotenv
-VITE_ICE_API_BASE_URL=https://venue.test.chatgqt.top
-VITE_COMPREHENSIVE_API_BASE_URL=https://venue2.test.chatgqt.top
-```
-
-Create `miniprogram/.env.example`:
-
-```dotenv
-VITE_ICE_API_BASE_URL=http://127.0.0.1:8000
-VITE_COMPREHENSIVE_API_BASE_URL=http://127.0.0.1:8001
-```
-
-Expected: no old single `VITE_API_BASE_URL` remains in these files.
-
-- [ ] **Step 4: Create Vite config**
-
-Create `miniprogram/vite.config.js`:
-
-```js
-import { fileURLToPath, URL } from 'node:url'
-import { defineConfig, loadEnv } from 'vite'
-import uniPlugin from '@dcloudio/vite-plugin-uni'
-
-const uni = typeof uniPlugin === 'function' ? uniPlugin : uniPlugin.default
-
-export default defineConfig(({ mode }) => {
- const env = loadEnv(mode, process.cwd(), '')
- const iceApiBase = env.VITE_ICE_API_BASE_URL || 'http://127.0.0.1:8000'
- const comprehensiveApiBase = env.VITE_COMPREHENSIVE_API_BASE_URL || 'http://127.0.0.1:8001'
-
- return {
- plugins: [uni()],
- optimizeDeps: {
- include: ['uview-plus'],
- },
- resolve: {
- alias: {
- '@': fileURLToPath(new URL('./src', import.meta.url)),
- },
- },
- css: {
- preprocessorOptions: {
- scss: {
- api: 'modern-compiler',
- },
- },
- },
- server: {
- proxy: {
- '/ice-api': {
- target: iceApiBase,
- changeOrigin: true,
- secure: false,
- rewrite: (path) => path.replace(/^\/ice-api/, ''),
- },
- '/comprehensive-api': {
- target: comprehensiveApiBase,
- changeOrigin: true,
- secure: false,
- rewrite: (path) => path.replace(/^\/comprehensive-api/, ''),
- },
- },
- },
- }
-})
-```
-
-Expected: H5 development can proxy both backends; WeChat builds still use env URLs directly.
-
-- [ ] **Step 5: Create app bootstrap**
-
-Create `miniprogram/src/main.js`:
-
-```js
-import { createSSRApp } from 'vue'
-import App from './App.vue'
-import * as Pinia from 'pinia'
-import uviewPlus from 'uview-plus'
-import 'uview-plus/index.scss'
-
-export function createApp() {
- const app = createSSRApp(App)
- app.use(Pinia.createPinia())
- app.use(uviewPlus)
- return {
- app,
- Pinia
- }
-}
-```
-
-Expected: Pinia and uview-plus are globally registered.
-
-- [ ] **Step 6: Create manifest**
-
-Create `miniprogram/src/manifest.json`:
-
-```json
-{
- "name": "场馆服务",
- "appid": "",
- "description": "冰场馆与综合场馆合并版会员服务小程序",
- "versionName": "0.1.0",
- "versionCode": "100",
- "transformPx": false,
- "mp-weixin": {
- "appid": "wx516b3e0d9940c788",
- "setting": {
- "urlCheck": false,
- "es6": true,
- "postcss": true,
- "minified": true
- },
- "usingComponents": true
- },
- "vueVersion": "3"
-}
-```
-
-Expected: WeChat appid is `wx516b3e0d9940c788`.
-
-- [ ] **Step 7: Create global SCSS files**
-
-Create `miniprogram/src/uni.scss`:
-
-```scss
-@use "@/styles/variables.scss" as *;
-@import "uview-plus/theme.scss";
-```
-
-Create `miniprogram/src/styles/variables.scss`:
-
-```scss
-$bg-color-main: #FFFFFF;
-$bg-color-soft: #F8FAFC;
-$bg-color-hover: #F1F5F9;
-$bg-color-panel: #EFF6FF;
-
-$text-color-main: #0F172A;
-$text-color-regular: #334155;
-$text-color-muted: #64748B;
-$text-color-light: #94A3B8;
-
-$color-primary: #0EA5E9;
-$color-primary-light: #E0F2FE;
-$color-success: #10B981;
-$color-success-light: #D1FAE5;
-$color-warning: #F59E0B;
-$color-warning-light: #FEF3C7;
-$color-danger: #EF4444;
-$color-danger-light: #FEE2E2;
-
-$border-color: #E2E8F0;
-$border-radius-sm: 6rpx;
-$border-radius-base: 12rpx;
-$border-radius-lg: 20rpx;
-
-$spacing-xs: 8rpx;
-$spacing-sm: 16rpx;
-$spacing-md: 24rpx;
-$spacing-lg: 32rpx;
-$spacing-xl: 48rpx;
-
-@mixin minimal-card {
- background: $bg-color-main;
- border: 1rpx solid $border-color;
- border-radius: $border-radius-base;
- padding: $spacing-md;
- box-shadow: 0 2rpx 8rpx rgba(15, 23, 42, 0.03);
-}
-
-@mixin text-ellipsis {
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-```
-
-Expected: SCSS variables used by both old projects are available.
-
-- [ ] **Step 8: Create global App component**
-
-Create `miniprogram/src/App.vue`:
-
-```vue
-
-
-
-```
-
-Expected: common global classes used by the comprehensive project remain available, and ice pages still get the shared variables.
-
-- [ ] **Step 9: Commit shell**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序'
-git add miniprogram/package.json miniprogram/package-lock.json miniprogram/vite.config.js miniprogram/.env miniprogram/.env.example miniprogram/src/main.js miniprogram/src/App.vue miniprogram/src/manifest.json miniprogram/src/uni.scss miniprogram/src/styles/variables.scss
-git commit -m "feat: scaffold merged miniapp shell"
-```
-
-Expected: commit succeeds with only shell files staged.
-
-### Task 2: Add Public Venue Selection State and Page
-
-**Files:**
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/utils/venue.js`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/stores/venue.js`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages/venue-select/index.vue`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages.json`
-
-- [ ] **Step 1: Create venue utility module**
-
-Create `miniprogram/src/utils/venue.js`:
-
-```js
-export const CURRENT_VENUE_KEY = 'CURRENT_VENUE'
-
-export const VENUE_KEYS = Object.freeze({
- ICE: 'ice',
- COMPREHENSIVE: 'comprehensive'
-})
-
-export const VENUE_OPTIONS = Object.freeze([
- {
- key: VENUE_KEYS.ICE,
- name: '冰场馆',
- description: '课程预约、会员卡与滑冰服务',
- homePath: '/pages/ice/home/index'
- },
- {
- key: VENUE_KEYS.COMPREHENSIVE,
- name: '综合场馆',
- description: '课程、包场、门票、订单与余额',
- homePath: '/pages/comprehensive/home/index'
- }
-])
-
-export const isVenueKey = (value) => {
- return value === VENUE_KEYS.ICE || value === VENUE_KEYS.COMPREHENSIVE
-}
-
-export const getVenueOption = (venueKey) => {
- return VENUE_OPTIONS.find((item) => item.key === venueKey) || null
-}
-
-export const getStoredVenue = () => {
- const venue = uni.getStorageSync(CURRENT_VENUE_KEY)
- return isVenueKey(venue) ? venue : ''
-}
-
-export const setStoredVenue = (venueKey) => {
- if (!isVenueKey(venueKey)) {
- uni.removeStorageSync(CURRENT_VENUE_KEY)
- return ''
- }
-
- uni.setStorageSync(CURRENT_VENUE_KEY, venueKey)
- return venueKey
-}
-
-export const navigateToVenueHome = (venueKey, options = {}) => {
- const venue = getVenueOption(venueKey)
- if (!venue) {
- uni.reLaunch({ url: '/pages/venue-select/index' })
- return
- }
-
- const navigate = options.redirect === true ? uni.redirectTo : uni.reLaunch
- navigate({ url: venue.homePath })
-}
-```
-
-Expected: utility has a single source of truth for venue keys and home paths.
-
-- [ ] **Step 2: Create venue Pinia store**
-
-Create `miniprogram/src/stores/venue.js`:
-
-```js
-import { defineStore } from 'pinia'
-import { getStoredVenue, getVenueOption, navigateToVenueHome, setStoredVenue } from '@/utils/venue'
-
-export const useVenueStore = defineStore('currentVenue', {
- state: () => ({
- currentVenue: ''
- }),
- getters: {
- currentVenueOption: (state) => getVenueOption(state.currentVenue),
- hasSelectedVenue: (state) => Boolean(getVenueOption(state.currentVenue))
- },
- actions: {
- init() {
- this.currentVenue = getStoredVenue()
- return this.currentVenue
- },
- selectVenue(venueKey) {
- this.currentVenue = setStoredVenue(venueKey)
- return this.currentVenue
- },
- enterVenue(venueKey) {
- const selectedVenue = this.selectVenue(venueKey)
- navigateToVenueHome(selectedVenue)
- }
- }
-})
-```
-
-Expected: selection persists and can navigate to module home.
-
-- [ ] **Step 3: Create venue selection page**
-
-Create `miniprogram/src/pages/venue-select/index.vue`:
-
-```vue
-
-
-
-
-
-
-
- {{ venue.name }}
- {{ venue.description }}
-
-
- {{ venue.key === currentVenue ? '当前' : '进入' }}
-
-
-
-
-
-
-
-
-
-```
-
-Expected: first page gives two concrete choices and persists selection before navigation.
-
-- [ ] **Step 4: Create initial pages registry**
-
-Create `miniprogram/src/pages.json`:
-
-```json
-{
- "easycom": {
- "autoscan": true,
- "custom": {
- "^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
- "^up-(.*)": "uview-plus/components/u-$1/u-$1.vue",
- "^u-([^-].*)": "uview-plus/components/u-$1/u-$1.vue"
- }
- },
- "pages": [
- {
- "path": "pages/venue-select/index",
- "style": {
- "navigationBarTitleText": "选择场馆",
- "navigationBarBackgroundColor": "#FFFFFF",
- "navigationBarTextStyle": "black"
- }
- }
- ],
- "globalStyle": {
- "navigationBarTextStyle": "black",
- "navigationBarBackgroundColor": "#FFFFFF",
- "backgroundColor": "#F8FAFC",
- "backgroundColorBottom": "#F8FAFC",
- "backgroundColorTop": "#FFFFFF"
- }
-}
-```
-
-Expected: app has a valid first page before business modules are migrated.
-
-- [ ] **Step 5: Verify selection shell builds**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-npm install
-npm run build:mp-weixin
-```
-
-Expected: build succeeds or fails only because `/pages/ice/home/index` and `/pages/comprehensive/home/index` do not exist yet after tapping; compile-time should not require those target files until pages are registered. If compile fails for missing dependencies, fix dependency installation before continuing.
-
-- [ ] **Step 6: Commit selection shell**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序'
-git add miniprogram/src/utils/venue.js miniprogram/src/stores/venue.js miniprogram/src/pages/venue-select/index.vue miniprogram/src/pages.json miniprogram/package-lock.json
-git commit -m "feat: add venue selection shell"
-```
-
-Expected: commit succeeds with public shell files and any refreshed lockfile.
-
-### Task 3: Migrate Comprehensive Venue Module
-
-**Files:**
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/comprehensive/api/*.js`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/comprehensive/stores/session.js`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/comprehensive/utils/*.js`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages/comprehensive/**`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/static/comprehensive/tab/*.png`
-- Modify: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages.json`
-
-- [ ] **Step 1: Copy comprehensive source files into namespaced locations**
-
-Run:
-
-```bash
-mkdir -p '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/comprehensive'
-mkdir -p '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages/comprehensive'
-mkdir -p '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/static/comprehensive'
-cp -R '/Volumes/ExternalStorageA/project/2026.5/体育场馆/综合场馆小程序/miniprogram/src/api' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/comprehensive/api'
-cp -R '/Volumes/ExternalStorageA/project/2026.5/体育场馆/综合场馆小程序/miniprogram/src/stores' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/comprehensive/stores'
-cp -R '/Volumes/ExternalStorageA/project/2026.5/体育场馆/综合场馆小程序/miniprogram/src/utils' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/comprehensive/utils'
-cp -R '/Volumes/ExternalStorageA/project/2026.5/体育场馆/综合场馆小程序/miniprogram/src/pages/.' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages/comprehensive/'
-cp -R '/Volumes/ExternalStorageA/project/2026.5/体育场馆/综合场馆小程序/miniprogram/src/static/tab' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/static/comprehensive/tab'
-```
-
-Expected: comprehensive pages exist under `src/pages/comprehensive`, and API/store/utils exist under `src/modules/comprehensive`.
-
-- [ ] **Step 2: Update comprehensive request base URL**
-
-Edit `miniprogram/src/modules/comprehensive/api/request.js` so the top constants are:
-
-```js
-const KEY_TOKEN = 'COMPREHENSIVE_VENUE_TOKEN'
-
-const API_BASE_URL = import.meta.env.VITE_COMPREHENSIVE_API_BASE_URL || 'http://127.0.0.1:8001'
-```
-
-Expected: `VITE_API_BASE_URL` is not used in this module.
-
-- [ ] **Step 3: Rename comprehensive session store id and imports**
-
-Edit `miniprogram/src/modules/comprehensive/stores/session.js`:
-
-```js
-import { defineStore } from 'pinia'
-import { authApi, authStorage } from '@/modules/comprehensive/api/auth'
-import { memberApi } from '@/modules/comprehensive/api/member'
-
-export const useComprehensiveSessionStore = defineStore('comprehensiveVenueSession', {
- state: () => ({
- isReady: false,
- isLoggedIn: false,
- member: null
- }),
- actions: {
- async init() {
- this.isLoggedIn = authStorage.isLoggedIn()
- if (this.isLoggedIn) {
- try {
- this.member = await memberApi.getMemberMe()
- } catch (error) {
- if ([40001, 40002, 401, 403].includes(error.code) || [401, 403].includes(error.statusCode)) {
- authStorage.clear()
- this.member = null
- this.isLoggedIn = false
- }
- }
- }
- this.isReady = true
- },
- async login() {
- const loginResult = await loginByWechat()
- const data = await authApi.wechatLogin({ code: loginResult.code })
- this.member = data.member
- this.isLoggedIn = true
- },
- logout() {
- authApi.logout()
- this.member = null
- this.isLoggedIn = false
- },
- async refreshMember() {
- if (!authStorage.isLoggedIn()) return
- this.member = await memberApi.getMemberMe()
- this.isLoggedIn = true
- }
- }
-})
-
-const loginByWechat = () => new Promise((resolve, reject) => {
- uni.login({
- provider: 'weixin',
- success: (res) => {
- if (!res.code) {
- reject(new Error('微信登录未返回 code'))
- return
- }
- resolve(res)
- },
- fail: reject
- })
-})
-```
-
-Expected: no `@/api` imports and no `defineStore('session')` remain in this file.
-
-- [ ] **Step 4: Rewrite comprehensive page imports**
-
-Run these replacements from `miniprogram`:
-
-```bash
-perl -pi -e "s#@/api/#@/modules/comprehensive/api/#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#@/stores/session#@/modules/comprehensive/stores/session#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#@/utils/#@/modules/comprehensive/utils/#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#useSessionStore#useComprehensiveSessionStore#g" src/pages/comprehensive/**/*.vue
-```
-
-Expected: comprehensive pages import from `@/modules/comprehensive/*`.
-
-- [ ] **Step 5: Rewrite comprehensive route strings**
-
-Run these replacements from `miniprogram`:
-
-```bash
-perl -pi -e "s#/pages/home#/pages/comprehensive/home#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#/pages/courses#/pages/comprehensive/courses#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#/pages/bookings#/pages/comprehensive/bookings#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#/pages/profile#/pages/comprehensive/profile#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#/pages/activities#/pages/comprehensive/activities#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#/pages/private#/pages/comprehensive/private#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#/pages/tickets#/pages/comprehensive/tickets#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#/pages/orders#/pages/comprehensive/orders#g" src/pages/comprehensive/**/*.vue
-perl -pi -e "s#/pages/pay#/pages/comprehensive/pay#g" src/pages/comprehensive/**/*.vue
-```
-
-Expected: comprehensive pages no longer navigate to unprefixed old routes.
-
-- [ ] **Step 6: Add comprehensive switch entry to profile menu**
-
-Edit `miniprogram/src/pages/comprehensive/profile/index.vue`.
-
-Add one item to `menuItems` after the personal info item:
-
-```js
-{ title: '切换场馆', url: '/pages/venue-select/index', theme: 'profile-theme', icon: 'profile' }
-```
-
-Expected: logged-in comprehensive users can navigate to the venue selection page. If the page shows no menu when logged out, the venue selector remains available by manually opening the first page; Task 7 will also validate direct switching.
-
-- [ ] **Step 7: Register comprehensive pages**
-
-Modify `miniprogram/src/pages.json` by appending these page entries after `pages/venue-select/index`:
-
-```json
-{
- "path": "pages/comprehensive/home/index",
- "style": {
- "navigationBarTitleText": "首页",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/comprehensive/courses/index",
- "style": {
- "navigationBarTitleText": "课程",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/comprehensive/bookings/index",
- "style": {
- "navigationBarTitleText": "我的预约",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/comprehensive/profile/index",
- "style": {
- "navigationBarTitleText": "会员中心"
- }
-},
-{
- "path": "pages/comprehensive/activities/index",
- "style": {
- "navigationBarTitleText": "活动公告",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/comprehensive/activities/detail",
- "style": {
- "navigationBarTitleText": "活动详情"
- }
-},
-{
- "path": "pages/comprehensive/courses/detail",
- "style": {
- "navigationBarTitleText": "课程详情"
- }
-},
-{
- "path": "pages/comprehensive/courses/confirm",
- "style": {
- "navigationBarTitleText": "确认课程预约"
- }
-},
-{
- "path": "pages/comprehensive/private/index",
- "style": {
- "navigationBarTitleText": "包场预约"
- }
-},
-{
- "path": "pages/comprehensive/private/confirm",
- "style": {
- "navigationBarTitleText": "确认包场"
- }
-},
-{
- "path": "pages/comprehensive/tickets/index",
- "style": {
- "navigationBarTitleText": "篮球门票"
- }
-},
-{
- "path": "pages/comprehensive/pay/index",
- "style": {
- "navigationBarTitleText": "订单支付"
- }
-},
-{
- "path": "pages/comprehensive/orders/detail",
- "style": {
- "navigationBarTitleText": "订单详情"
- }
-},
-{
- "path": "pages/comprehensive/bookings/course-detail",
- "style": {
- "navigationBarTitleText": "课程预约详情"
- }
-},
-{
- "path": "pages/comprehensive/bookings/private-detail",
- "style": {
- "navigationBarTitleText": "包场预约详情"
- }
-},
-{
- "path": "pages/comprehensive/profile/balance",
- "style": {
- "navigationBarTitleText": "余额流水",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/comprehensive/profile/tickets",
- "style": {
- "navigationBarTitleText": "我的门票",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/comprehensive/profile/orders",
- "style": {
- "navigationBarTitleText": "我的订单",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/comprehensive/profile/detail",
- "style": {
- "navigationBarTitleText": "个人信息"
- }
-}
-```
-
-Expected: all comprehensive pages from the old `pages.json` are registered with the `pages/comprehensive` prefix.
-
-- [ ] **Step 8: Verify comprehensive module references**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-rg -n "@/api|@/stores/session|@/utils/" src/pages/comprehensive src/modules/comprehensive
-rg -n "'/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)|\"/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)" src/pages/comprehensive
-rg -n "VITE_API_BASE_URL" src/modules/comprehensive
-```
-
-Expected: all three commands return no matches.
-
-- [ ] **Step 9: Build after comprehensive migration**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-npm run build:mp-weixin
-```
-
-Expected: build succeeds, or fails only because ice pages have not been registered yet. If the failure references comprehensive imports, fix those references before continuing.
-
-- [ ] **Step 10: Commit comprehensive module**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序'
-git add miniprogram/src/modules/comprehensive miniprogram/src/pages/comprehensive miniprogram/src/static/comprehensive miniprogram/src/pages.json
-git commit -m "feat: migrate comprehensive venue module"
-```
-
-Expected: commit succeeds with comprehensive module files.
-
-### Task 4: Migrate Ice Venue Module
-
-**Files:**
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/ice/api/*.js`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/components/ice/StatePanel.vue`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages/ice/**`
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/static/ice/tab/*.png`
-- Modify: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages.json`
-
-- [ ] **Step 1: Copy ice source files into namespaced locations**
-
-Run:
-
-```bash
-mkdir -p '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/ice'
-mkdir -p '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages/ice'
-mkdir -p '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/components/ice'
-mkdir -p '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/static/ice'
-cp -R '/Volumes/ExternalStorageA/project/2026.5/体育场馆/冰场馆小程序/miniprogram/src/api' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/modules/ice/api'
-cp '/Volumes/ExternalStorageA/project/2026.5/体育场馆/冰场馆小程序/miniprogram/src/components/StatePanel.vue' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/components/ice/StatePanel.vue'
-cp -R '/Volumes/ExternalStorageA/project/2026.5/体育场馆/冰场馆小程序/miniprogram/src/pages/.' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages/ice/'
-cp -R '/Volumes/ExternalStorageA/project/2026.5/体育场馆/冰场馆小程序/miniprogram/src/static/tab' '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/static/ice/tab'
-```
-
-Expected: ice pages exist under `src/pages/ice`, API under `src/modules/ice/api`, and state panel under `src/components/ice`.
-
-- [ ] **Step 2: Update ice request base URL**
-
-Edit `miniprogram/src/modules/ice/api/request.js` so the base URL constant is:
-
-```js
-const API_BASE_URL = import.meta.env.VITE_ICE_API_BASE_URL || 'http://127.0.0.1:8000'
-```
-
-Expected: `VITE_API_BASE_URL` is not used in this module.
-
-- [ ] **Step 3: Rewrite ice page imports**
-
-Run these replacements from `miniprogram`:
-
-```bash
-perl -pi -e "s#@/api/#@/modules/ice/api/#g" src/pages/ice/**/*.vue
-perl -pi -e "s#@/components/StatePanel.vue#@/components/ice/StatePanel.vue#g" src/pages/ice/**/*.vue
-```
-
-Expected: ice pages import from `@/modules/ice/api/*` and `@/components/ice/StatePanel.vue`.
-
-- [ ] **Step 4: Rewrite ice route strings**
-
-Run these replacements from `miniprogram`:
-
-```bash
-perl -pi -e "s#/pages/home#/pages/ice/home#g" src/pages/ice/**/*.vue
-perl -pi -e "s#/pages/courses#/pages/ice/courses#g" src/pages/ice/**/*.vue
-perl -pi -e "s#/pages/bookings#/pages/ice/bookings#g" src/pages/ice/**/*.vue
-perl -pi -e "s#/pages/profile#/pages/ice/profile#g" src/pages/ice/**/*.vue
-perl -pi -e "s#/pages/activities#/pages/ice/activities#g" src/pages/ice/**/*.vue
-```
-
-Expected: ice pages no longer navigate to unprefixed old routes.
-
-- [ ] **Step 5: Add ice switch entry to profile page**
-
-Edit `miniprogram/src/pages/ice/profile/index.vue`.
-
-Add a menu item in the logged-in menu group before the logout item:
-
-```vue
-
-```
-
-If the page does not define `.profile-theme` or `.svg-profile-minimal`, use the existing `card-theme` icon container classes instead:
-
-```vue
-
-
-
-
-
-```
-
-Expected: logged-in ice users can navigate to the venue selection page.
-
-- [ ] **Step 6: Register ice pages**
-
-Modify `miniprogram/src/pages.json` by appending these page entries after the comprehensive entries:
-
-```json
-{
- "path": "pages/ice/home/index",
- "style": {
- "navigationBarTitleText": "首页",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/ice/courses/index",
- "style": {
- "navigationBarTitleText": "近期课程",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/ice/bookings/index",
- "style": {
- "navigationBarTitleText": "我的预约",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/ice/profile/index",
- "style": {
- "navigationBarTitleText": "会员中心"
- }
-},
-{
- "path": "pages/ice/bookings/detail",
- "style": {
- "navigationBarTitleText": "预约详情"
- }
-},
-{
- "path": "pages/ice/courses/detail",
- "style": {
- "navigationBarTitleText": "课程详情"
- }
-},
-{
- "path": "pages/ice/profile/cards",
- "style": {
- "navigationBarTitleText": "我的会员卡",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/ice/profile/card-history",
- "style": {
- "navigationBarTitleText": "会员卡使用流水",
- "enablePullDownRefresh": true
- }
-},
-{
- "path": "pages/ice/profile/detail",
- "style": {
- "navigationBarTitleText": "个人信息"
- }
-},
-{
- "path": "pages/ice/activities/detail",
- "style": {
- "navigationBarTitleText": "活动详情"
- }
-}
-```
-
-Expected: all ice pages from the old `pages.json` are registered with the `pages/ice` prefix.
-
-- [ ] **Step 7: Verify ice module references**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-rg -n "@/api|@/components/StatePanel.vue" src/pages/ice src/modules/ice
-rg -n "'/pages/(home|courses|bookings|profile|activities)|\"/pages/(home|courses|bookings|profile|activities)" src/pages/ice
-rg -n "VITE_API_BASE_URL" src/modules/ice
-```
-
-Expected: all three commands return no matches.
-
-- [ ] **Step 8: Build after ice migration**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-npm run build:mp-weixin
-```
-
-Expected: build succeeds. If build fails, fix the reported import, route registration, or SCSS variable error before continuing.
-
-- [ ] **Step 9: Commit ice module**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序'
-git add miniprogram/src/modules/ice miniprogram/src/pages/ice miniprogram/src/components/ice miniprogram/src/static/ice miniprogram/src/pages.json
-git commit -m "feat: migrate ice venue module"
-```
-
-Expected: commit succeeds with ice module files.
-
-### Task 5: Finalize Cross-Module Navigation and Safety Checks
-
-**Files:**
-- Modify: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/pages/venue-select/index.vue`
-- Modify: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/src/utils/venue.js`
-- Modify: module pages only if checks reveal stale routes or stale imports.
-
-- [ ] **Step 1: Ensure venue selector can return to stored current venue**
-
-Update `miniprogram/src/pages/venue-select/index.vue` to keep the existing card UI and add a continue action when a venue is already selected:
-
-```vue
-
-
-
-
-
- 当前场馆
- {{ selectedVenue.name }}
-
-
-
-
-
-
- {{ venue.name }}
- {{ venue.description }}
-
-
- {{ venue.key === currentVenue ? '切换进入' : '进入' }}
-
-
-
-
-
-```
-
-Add script code:
-
-```js
-const selectedVenue = computed(() => venueStore.currentVenueOption)
-
-const continueCurrentVenue = () => {
- if (!venueStore.currentVenue) return
- venueStore.enterVenue(venueStore.currentVenue)
-}
-```
-
-Add styles:
-
-```scss
-.current-card {
- display: flex;
- flex-direction: column;
- gap: 12rpx;
- margin-bottom: 32rpx;
- padding: 28rpx;
- border-radius: $border-radius-lg;
- background: $bg-color-main;
- border: 1rpx solid $border-color;
-}
-
-.current-label {
- color: $text-color-muted;
- font-size: 22rpx;
- font-weight: 700;
-}
-
-.current-name {
- color: $text-color-main;
- font-size: 32rpx;
- font-weight: 900;
-}
-
-.continue-btn {
- margin-top: 12rpx;
-}
-```
-
-Expected: users who return to the selector can continue into the stored venue without changing it.
-
-- [ ] **Step 2: Run stale import checks**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-rg -n "@/api|@/stores/session|@/utils/(date|money|status)|@/components/StatePanel.vue" src/pages src/modules
-```
-
-Expected: no matches. If matches appear, rewrite them to module-specific imports:
-
-```text
-@/modules/ice/api/
-@/modules/comprehensive/api/
-@/modules/comprehensive/utils/
-@/components/ice/StatePanel.vue
-```
-
-- [ ] **Step 3: Run stale route checks**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-rg -n "'/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)|\"/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)|`/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)" src/pages
-```
-
-Expected: no matches. If matches appear, prefix with `ice` or `comprehensive` based on the file path.
-
-- [ ] **Step 4: Run API base URL checks**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-rg -n "VITE_API_BASE_URL|const API_BASE_URL" src/modules
-```
-
-Expected output includes only:
-
-```text
-src/modules/ice/api/request.js:const API_BASE_URL = import.meta.env.VITE_ICE_API_BASE_URL || 'http://127.0.0.1:8000'
-src/modules/comprehensive/api/request.js:const API_BASE_URL = import.meta.env.VITE_COMPREHENSIVE_API_BASE_URL || 'http://127.0.0.1:8001'
-```
-
-- [ ] **Step 5: Run token isolation checks**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-rg -n "ICE_MEMBER_TOKEN|ICE_MEMBER_TOKEN_EXPIRES_AT|COMPREHENSIVE_VENUE_TOKEN" src/modules
-```
-
-Expected output includes:
-
-```text
-src/modules/ice/api/request.js:const KEY_TOKEN = 'ICE_MEMBER_TOKEN'
-src/modules/ice/api/request.js:const KEY_TOKEN_EXPIRES_AT = 'ICE_MEMBER_TOKEN_EXPIRES_AT'
-src/modules/comprehensive/api/request.js:const KEY_TOKEN = 'COMPREHENSIVE_VENUE_TOKEN'
-```
-
-- [ ] **Step 6: Build final merged app**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-npm run build:mp-weixin
-```
-
-Expected: build succeeds and outputs `dist/build/mp-weixin`.
-
-- [ ] **Step 7: Commit safety pass**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序'
-git add miniprogram
-git commit -m "fix: finalize merged venue navigation"
-```
-
-Expected: commit succeeds if files changed. If no files changed after checks, skip this commit and record that no safety-pass commit was needed.
-
-### Task 6: Manual WeChat Mini Program Smoke Test
-
-**Files:**
-- No source files should be modified unless the smoke test finds a defect.
-
-- [ ] **Step 1: Open generated mini program in WeChat DevTools**
-
-Open this directory in WeChat DevTools:
-
-```text
-/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram/dist/build/mp-weixin
-```
-
-Expected: project opens with appid `wx516b3e0d9940c788`.
-
-- [ ] **Step 2: Smoke test venue selector**
-
-In the simulator:
-
-```text
-1. Open first page.
-2. Confirm "选择场馆" appears.
-3. Tap "冰场馆".
-4. Confirm URL is pages/ice/home/index.
-5. Navigate back to pages/venue-select/index.
-6. Tap "综合场馆".
-7. Confirm URL is pages/comprehensive/home/index.
-```
-
-Expected: both venue cards navigate to the correct module home page.
-
-- [ ] **Step 3: Smoke test ice module navigation**
-
-Open these paths in WeChat DevTools page path input:
-
-```text
-pages/ice/home/index
-pages/ice/courses/index
-pages/ice/bookings/index
-pages/ice/profile/index
-pages/ice/profile/cards
-```
-
-Expected: each page loads without a JavaScript import error. Network errors from unavailable backend are acceptable during local smoke testing if request URLs point to `https://venue.test.chatgqt.top`.
-
-- [ ] **Step 4: Smoke test comprehensive module navigation**
-
-Open these paths in WeChat DevTools page path input:
-
-```text
-pages/comprehensive/home/index
-pages/comprehensive/courses/index
-pages/comprehensive/bookings/index
-pages/comprehensive/profile/index
-pages/comprehensive/private/index
-pages/comprehensive/tickets/index
-pages/comprehensive/pay/index?order_id=1
-```
-
-Expected: each page loads without a JavaScript import error. The pay page may show an order loading error for `order_id=1`; it must not call the ice backend.
-
-- [ ] **Step 5: Inspect request domains**
-
-Use WeChat DevTools network panel:
-
-```text
-1. Open pages/ice/home/index.
-2. Confirm requests go to https://venue.test.chatgqt.top.
-3. Open pages/comprehensive/home/index.
-4. Confirm requests go to https://venue2.test.chatgqt.top.
-```
-
-Expected: requests never cross backend domains.
-
-- [ ] **Step 6: Commit smoke-test fixes**
-
-If source fixes were required, run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序'
-git add miniprogram
-git commit -m "fix: address merged miniapp smoke test issues"
-```
-
-Expected: commit succeeds only if smoke testing found and fixed defects.
-
-### Task 7: Final Verification and Delivery Notes
-
-**Files:**
-- Create: `/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/docs/merged-miniapp-verification.md`
-
-- [ ] **Step 1: Run final command verification**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序/miniprogram'
-npm run build:mp-weixin
-rg -n "@/api|@/stores/session|@/utils/(date|money|status)|@/components/StatePanel.vue" src/pages src/modules
-rg -n "'/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)|\"/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)|`/pages/(home|courses|bookings|profile|activities|private|tickets|orders|pay)" src/pages
-rg -n "VITE_API_BASE_URL" src/modules .env .env.example vite.config.js
-```
-
-Expected:
-
-```text
-npm run build:mp-weixin exits 0
-stale import rg exits 1 with no matches
-stale route rg exits 1 with no matches
-VITE_API_BASE_URL rg exits 1 with no matches
-```
-
-- [ ] **Step 2: Write verification note**
-
-Create `docs/merged-miniapp-verification.md`:
-
-```markdown
-# 合并版场馆小程序验证记录
-
-## 构建
-
-- 命令:`npm run build:mp-weixin`
-- 结果:通过
-- 产物:`miniprogram/dist/build/mp-weixin`
-
-## 路由隔离
-
-- 检查旧的无前缀页面路径:通过
-- 冰场馆页面前缀:`pages/ice`
-- 综合场馆页面前缀:`pages/comprehensive`
-
-## API 隔离
-
-- 冰场馆 baseURL:`VITE_ICE_API_BASE_URL`
-- 综合场馆 baseURL:`VITE_COMPREHENSIVE_API_BASE_URL`
-- 旧 `VITE_API_BASE_URL`:未使用
-
-## 登录态隔离
-
-- 冰场馆 token:`ICE_MEMBER_TOKEN`
-- 冰场馆 token 过期时间:`ICE_MEMBER_TOKEN_EXPIRES_AT`
-- 综合场馆 token:`COMPREHENSIVE_VENUE_TOKEN`
-
-## 上线前人工检查
-
-- 微信 request 合法域名包含 `venue.test.chatgqt.top`
-- 微信 request 合法域名包含 `venue2.test.chatgqt.top`
-- 综合场馆支付仍由综合场馆后端生成支付参数
-```
-
-If any command fails, replace `结果:通过` with the exact failing command and actual status, then fix the issue before final delivery.
-
-- [ ] **Step 3: Commit verification note**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序'
-git add docs/merged-miniapp-verification.md
-git commit -m "docs: record merged miniapp verification"
-```
-
-Expected: commit succeeds with the verification record.
-
-- [ ] **Step 4: Final git status check**
-
-Run:
-
-```bash
-cd '/Volumes/ExternalStorageA/project/2026.5/体育场馆/场馆小程序'
-git status --short
-```
-
-Expected: no uncommitted files except intentionally ignored build output if `.gitignore` is added later. If build output appears and should not be committed, add a project `.gitignore` that ignores:
-
-```gitignore
-miniprogram/node_modules/
-miniprogram/dist/
-.DS_Store
-```
-
-Commit `.gitignore` with:
-
-```bash
-git add .gitignore
-git commit -m "chore: ignore generated miniapp files"
-```
-
-Expected: working tree is clean or only contains intentionally untracked files reported to the user.
-
-## Plan Self-Review
-
-Spec coverage:
-
-- New project under `场馆小程序/miniprogram`: Task 1.
-- First-entry venue choice and in-app switching: Tasks 2, 5, and 6.
-- Isolated Django backends and API clients: Tasks 1, 3, 4, and 5.
-- Token isolation: Tasks 3, 4, 5, and 7.
-- Route prefixing: Tasks 3, 4, and 5.
-- No backend/admin/CI merge: all tasks operate only under `场馆小程序`.
-- Build and smoke verification: Tasks 5, 6, and 7.
-
-Placeholder scan: the plan intentionally avoids unspecified implementation slots. Each migration step includes exact copy commands, rewrite commands, file paths, expected checks, and commit commands.
-
-Type consistency:
-
-- Venue key values are `ice` and `comprehensive` across `VENUE_KEYS`, storage, routes, and page prefixes.
-- Store exports are `useVenueStore` and `useComprehensiveSessionStore`.
-- Environment variables are `VITE_ICE_API_BASE_URL` and `VITE_COMPREHENSIVE_API_BASE_URL`.
-- Token keys are `ICE_MEMBER_TOKEN`, `ICE_MEMBER_TOKEN_EXPIRES_AT`, and `COMPREHENSIVE_VENUE_TOKEN`.
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
deleted file mode 100644
index 4f9d3a6..0000000
--- a/docs/superpowers/specs/2026-06-08-merged-venue-miniapp-design.md
+++ /dev/null
@@ -1,412 +0,0 @@
-# 合并版场馆小程序设计
-
-## 背景
-
-当前有两套独立系统:
-
-- 冰场馆小程序:前端为 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
-```
-
-它可以独立构建微信小程序。用户首次进入选择场馆,后续可在小程序内切换;两个场馆后端、登录态、支付和业务数据仍完全隔离。