Files
venue-miniapp/miniprogram/docs/superpowers/plans/2026-07-12-comprehensive-venue-frontend-integration.md
T

22 KiB
Raw Blame History

综合场馆新增业务前端对接 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: 完成综合场馆排课接口迁移、商城储蓄卡与次卡购买、已有次卡可约排课、个人中心入口和支付规则,并移除两个场馆首页的近期课程区块。

Architecture: 延续现有 uni-app Vue 3 的 pages/comprehensive 页面层与 modules/comprehensive/api 接口映射层。会员端课程统一使用排课 session,商城复用现有订单支付页,普通课程预约与次卡预约保持独立数据模型;不新增依赖、不改后端、不重构冰场馆其他业务。

Tech Stack: uni-app、Vue 3 <script setup>、Pinia、JavaScript、Node.js 静态验证脚本、npm

Global Constraints

  • 有效前端目录仅为 场馆小程序/miniprogram,不得修改两个已废弃的 冰场馆小程序/miniprogram综合场馆小程序/miniprogram
  • 产品界面使用“储蓄卡”称谓;代码、接口和后端模型沿用 storedValuestored_value 和“储值卡”。
  • 排课详情和预约使用 session.idcourse_id 仅表示课程模板,不能用于预约。
  • 储蓄卡订单仅允许微信支付;次卡套餐订单允许余额支付和微信支付。
  • 次卡预约不创建支付订单,预约时不扣次数,后台核销时才扣减。
  • 普通预约和次卡预约的嵌套 session 不保证包含 courts,相关页面不得依赖该字段。
  • 综合场馆与冰场馆首页均不再展示近期课程,但课程列表和详情入口必须保留。
  • 不修改场地页面视觉、不实现后台锁场、不修改冰场馆其他业务。
  • 不新增 npm 依赖;继续使用现有请求封装、登录 store、样式变量和分页约定。

文件结构与职责

新建文件

文件 职责
src/modules/comprehensive/api/membership.js 次卡套餐、持卡、流水、可约排课和次卡预约的请求与映射
src/modules/comprehensive/api/storedValue.js 储蓄卡商品和购买订单的请求与映射
src/pages/comprehensive/mall/index.vue 商城分区展示次卡套餐和储蓄卡,创建订单并跳转支付
src/pages/comprehensive/membership/cards.vue 我的次卡分页列表
src/pages/comprehensive/membership/card-detail.vue 次卡信息、适用课程和使用流水
src/pages/comprehensive/membership/available-sessions.vue 当前已有次卡能够预约的排课列表与选卡预约
src/pages/comprehensive/membership/booking-detail.vue 次卡预约详情
scripts/verify-comprehensive-session-contract.mjs 验证排课 URL、session_idbooking.session 和首页移除课程
scripts/verify-comprehensive-commerce.mjs 验证商城、次卡页面、支付限制、个人中心入口和路由注册

修改文件

文件 修改职责
src/modules/comprehensive/api/course.js /api/sessions{ session_id }
src/modules/comprehensive/api/content.js 首页不再映射近期排课
src/modules/comprehensive/api/booking.js 普通预约改读 session_idsession
src/pages/comprehensive/courses/*.vue 页面变量和提交语义改为排课
src/pages/comprehensive/bookings/index.vue 普通预约/次卡预约切换展示
src/pages/comprehensive/bookings/course-detail.vue 普通预约详情读取 booking.session,不依赖场地字段
src/pages/comprehensive/profile/index.vue 余额、充值、我的次卡、流水和消费记录入口
src/pages/comprehensive/profile/orders.vue 新增会员卡、储值卡订单筛选
src/pages/comprehensive/pay/index.vue 储值卡订单强制微信支付并复查订单状态
src/pages/comprehensive/home/index.vue 移除近期课程区块和相关状态
src/pages/ice/home/index.vue 移除近期课程区块和相关状态
src/modules/ice/api/home.js 首页请求不再传课程参数、不再映射近期课程
src/pages.json 注册商城和次卡页面
package.json 注册两条新的验证命令

Task 1: 排课接口与普通课程预约迁移

Files:

  • Create: scripts/verify-comprehensive-session-contract.mjs
  • Modify: src/modules/comprehensive/api/course.js
  • Modify: src/modules/comprehensive/api/booking.js
  • Modify: src/pages/comprehensive/courses/index.vue
  • Modify: src/pages/comprehensive/courses/detail.vue
  • Modify: src/pages/comprehensive/courses/confirm.vue
  • Modify: src/pages/comprehensive/bookings/index.vue
  • Modify: src/pages/comprehensive/bookings/course-detail.vue
  • Modify: package.json

Interfaces:

  • Produces: toSession(backendSession): SessionViewModel

  • Produces: courseApi.getSessions(params)courseApi.getSessionDetail(sessionId)courseApi.createCourseBooking(sessionId)

  • Produces: toCourseBooking() 返回 { session_id, session, order, ...statusFields }

  • Consumes: 现有 request()toPagination()toPageQuery()、日期和金额工具

  • Step 1: 先建立会失败的排课契约验证

新增验证脚本,至少断言:

expectIncludes(courseApi, "url: '/api/sessions'", 'session list endpoint')
expectIncludes(courseApi, 'url: `/api/sessions/${id}`', 'session detail endpoint')
expectIncludes(courseApi, 'data: { session_id: sessionId }', 'booking payload')
expectExcludes(courseApi, "url: '/api/courses'", 'legacy course endpoint')
expectIncludes(bookingApi, 'session_id: backendBooking.session_id', 'booking session id')
expectIncludes(bookingApi, 'session: toBookingSession(backendBooking.session)', 'booking session mapper')
expectExcludes(bookingApi, 'course: toBookingCourse(backendBooking.course)', 'legacy booking course')

package.json 增加:

"verify:comprehensive-session": "node scripts/verify-comprehensive-session-contract.mjs"

运行 npm run verify:comprehensive-session,预期因旧 /api/coursescourse_idbooking.course 而失败。

  • Step 2: 完成 API 映射与页面迁移

course.js 的核心接口固定为:

export const toSession = (backendSession = {}) => ({
  id: backendSession.id ?? null,
  course_id: backendSession.course_id ?? null,
  title: backendSession.title || '',
  cover_image: backendSession.cover_image || '',
  coach_id: backendSession.coach_id ?? null,
  coach_name: backendSession.coach_name || '',
  start_at: backendSession.start_at || '',
  end_at: backendSession.end_at || '',
  capacity: toNumber(backendSession.capacity),
  booked_count: toNumber(backendSession.booked_count),
  remaining_count: toNumber(backendSession.remaining_count),
  price: backendSession.price || '0.00',
  status: backendSession.status || '',
  status_label: backendSession.status_label || backendSession.status || '',
  courts: toArray(backendSession.courts).map(toCourseCourt),
  detail_html: backendSession.detail_html || '',
  created_at: backendSession.created_at || '',
  updated_at: backendSession.updated_at || ''
})

export const courseApi = {
  getSessions(params = {}) {
    return request({ url: '/api/sessions', data: toSessionQuery(params) })
      .then((data) => toPagination(data, toSession))
  },
  getSessionDetail(id) {
    return request({ url: `/api/sessions/${id}` }).then(toSession)
  },
  createCourseBooking(sessionId) {
    return request({
      url: '/api/bookings/course',
      method: 'POST',
      data: { session_id: sessionId }
    })
  }
}

普通预约映射改读 backendBooking.session;嵌套 session 映射允许 courts 缺失并返回空数组。课程列表、详情、确认页内部变量改为 session/sessions,确认页提交 session.id。预约列表和详情改读 item.sessionbooking.session,并删除对预约嵌套对象 courts.map(...) 的强依赖。

  • Step 3: 验证并提交这一条完整链路

运行:

npm run verify:comprehensive-session
npm run build:mp-weixin

预期:验证脚本打印 Comprehensive session contract verification passed.;微信小程序构建退出码为 0。随后提交:

git add package.json scripts/verify-comprehensive-session-contract.mjs src/modules/comprehensive/api/course.js src/modules/comprehensive/api/booking.js src/pages/comprehensive/courses src/pages/comprehensive/bookings
git commit -m "feat: migrate comprehensive courses to sessions"

Task 2: 商城、次卡套餐与储蓄卡购买

Files:

  • Create: src/modules/comprehensive/api/membership.js
  • Create: src/modules/comprehensive/api/storedValue.js
  • Create: src/pages/comprehensive/mall/index.vue
  • Create: scripts/verify-comprehensive-commerce.mjs
  • Modify: src/pages.json
  • Modify: package.json

Interfaces:

  • Produces: membershipApi.getPlans()membershipApi.createMembershipOrder(planId)

  • Produces: storedValueApi.getCards()storedValueApi.createOrder(cardId)

  • Produces: 商城购买成功统一跳转 /pages/comprehensive/pay/index?order_id={id}

  • Consumes: request()authStorage、综合场馆 session store、现有支付页

  • Step 1: 扩展静态验证,先覆盖商城路由和接口契约

验证脚本检查以下精确契约:

expectIncludes(membershipApi, "url: '/api/membership/plans'", 'membership plans')
expectIncludes(membershipApi, "url: '/api/membership/orders'", 'membership order')
expectIncludes(membershipApi, 'data: { plan_id: planId }', 'membership payload')
expectIncludes(storedValueApi, "url: '/api/stored-value/cards'", 'stored value cards')
expectIncludes(storedValueApi, "url: '/api/stored-value/orders'", 'stored value order')
expectIncludes(storedValueApi, 'data: { card_id: cardId }', 'stored value payload')
expectIncludes(pagesJson, 'pages/comprehensive/mall/index', 'mall route')
expectIncludes(mallPage, '储蓄卡', 'stored value UI copy')
expectIncludes(mallPage, 'face_value', 'face value display')

增加命令:

"verify:comprehensive-commerce": "node scripts/verify-comprehensive-commerce.mjs"

运行 npm run verify:comprehensive-commerce,预期因文件和路由尚不存在而失败。

  • Step 2: 实现两个 API 模块和商城页面

membership.js 的套餐和订单接口返回稳定视图模型:

const toPlan = (item = {}) => ({
  id: item.id ?? null,
  name: item.name || '',
  price: item.price || '0.00',
  total_count: toNumber(item.total_count),
  is_active: item.is_active === true,
  courses: toArray(item.courses).map((course) => ({
    id: course.id ?? null,
    title: course.title || ''
  })),
  created_at: item.created_at || ''
})

storedValue.js 映射 id/name/price/face_value/is_active/created_at。商城并行加载套餐和储蓄卡,分区展示;储蓄卡卡片必须同时显示“支付 ¥price”和“到账 ¥face_value”。购买前检查登录,创建请求期间禁用对应按钮,成功后只使用后端返回的 order.id 跳转支付页。

pages.json 注册商城路由,标题使用“商城”。

  • Step 3: 验证商城并提交

运行:

npm run verify:comprehensive-commerce
npm run build:mp-weixin

预期两条命令退出码均为 0。提交:

git add package.json scripts/verify-comprehensive-commerce.mjs src/modules/comprehensive/api/membership.js src/modules/comprehensive/api/storedValue.js src/pages/comprehensive/mall/index.vue src/pages.json
git commit -m "feat: add comprehensive membership and stored value mall"

Task 3: 我的次卡、可约排课和次卡预约

Files:

  • Create: src/pages/comprehensive/membership/cards.vue
  • Create: src/pages/comprehensive/membership/card-detail.vue
  • Create: src/pages/comprehensive/membership/available-sessions.vue
  • Create: src/pages/comprehensive/membership/booking-detail.vue
  • Modify: src/modules/comprehensive/api/membership.js
  • Modify: src/pages/comprehensive/bookings/index.vue
  • Modify: src/pages.json
  • Modify: scripts/verify-comprehensive-commerce.mjs

Interfaces:

  • Produces: getCards(params)getUsageRecords(cardId, params)getAvailableSessions(params)

  • Produces: createCardBooking({ cardId, sessionId })getCardBookings(params)getCardBookingDetail(bookingId)

  • Produces: AvailableSession.available_card_ids: number[]

  • Consumes: Task 2 的 getPlans(),用于按 plan_id 在次卡详情补充适用课程;不得调用不存在的单卡详情接口

  • Step 1: 先把持卡和预约契约加入验证脚本

加入以下断言后运行验证,预期失败:

expectIncludes(membershipApi, "url: '/api/membership/cards'", 'member cards')
expectIncludes(membershipApi, 'cards/${cardId}/usage-records', 'card usage records')
expectIncludes(membershipApi, "url: '/api/membership/available-courses'", 'available sessions')
expectIncludes(membershipApi, "url: '/api/membership/bookings'", 'card bookings')
expectIncludes(membershipApi, 'data: { card_id: cardId, session_id: sessionId }', 'card booking payload')
expectIncludes(availablePage, 'available_card_ids', 'available card selection')
expectExcludes(bookingDetail, 'booking.order', 'card booking has no order')
  • Step 2: 实现次卡 API 与四个页面

membership.js 统一输出:

createCardBooking({ cardId, sessionId }) {
  return request({
    url: '/api/membership/bookings',
    method: 'POST',
    data: { card_id: cardId, session_id: sessionId }
  }).then(toCardBooking)
}

页面规则:

  • cards.vue 分页显示 plan_name/total_count/remaining_count/status_label
  • card-detail.vue 并行请求 getPlans() 和该卡使用流水,以 plan_id 匹配套餐并展示适用课程;找不到套餐时仍展示卡和流水。
  • available-sessions.vue 只展示 /available-courses 返回的数据。从卡详情带 card_id 进入时过滤不含该 ID 的排课;未指定卡时,单个 available_card_ids 自动选中,多个 ID 让用户选择。
  • 创建次卡预约后直接跳 membership/booking-detail?id={booking.id},不进入支付页。
  • booking-detail.vue 展示 booking.sessionbooking.card 和状态时间,不展示订单与自行取消按钮,也不依赖 session.courts
  • bookings/index.vue 在课程业务下增加“普通预约/次卡预约”切换,分别请求 /bookings/courses/membership/bookings;次卡预约金额区域显示“次卡预约”。

pages.json 注册四个页面及明确的导航标题。

  • Step 3: 验证持卡预约全链路并提交

运行:

npm run verify:comprehensive-commerce
npm run verify:comprehensive-session
npm run build:mp-weixin

预期全部退出码为 0。提交:

git add scripts/verify-comprehensive-commerce.mjs src/modules/comprehensive/api/membership.js src/pages/comprehensive/membership src/pages/comprehensive/bookings/index.vue src/pages.json
git commit -m "feat: add membership card course booking flow"

Task 4: 个人中心、消费记录与储蓄卡支付规则

Files:

  • Modify: src/pages/comprehensive/profile/index.vue
  • Modify: src/pages/comprehensive/profile/orders.vue
  • Modify: src/pages/comprehensive/pay/index.vue
  • Modify: scripts/verify-comprehensive-commerce.mjs

Interfaces:

  • Consumes: memberApi.getBalance()、商城路由、我的次卡路由、现有订单 API

  • Produces: 储值卡订单 business_type === 'stored_value' 时只能调用 payOrderByWechat()

  • Produces: 订单筛选增加 membershipstored_value

  • Step 1: 先增加个人中心和支付限制验证

expectIncludes(profilePage, '/pages/comprehensive/mall/index', 'mall entry')
expectIncludes(profilePage, '/pages/comprehensive/membership/cards', 'my cards entry')
expectIncludes(profilePage, '/pages/comprehensive/profile/balance', 'balance records entry')
expectIncludes(profilePage, '/pages/comprehensive/profile/orders', 'consumption records entry')
expectIncludes(orderPage, "value: 'membership'", 'membership filter')
expectIncludes(orderPage, "value: 'stored_value'", 'stored value filter')
expectIncludes(payPage, "order.value?.business_type === 'stored_value'", 'stored value payment guard')

运行 npm run verify:comprehensive-commerce,预期新断言失败。

  • Step 2: 扩展个人中心、订单和支付页

个人中心登录后请求余额并展示,菜单增加:

{ title: '充值', url: '/pages/comprehensive/mall/index' }
{ title: '我的次卡', url: '/pages/comprehensive/membership/cards' }
{ title: '余额流水', url: '/pages/comprehensive/profile/balance' }
{ title: '消费记录', url: '/pages/comprehensive/profile/orders' }

订单筛选增加“会员卡”和“储值卡”。支付页定义:

const isStoredValueOrder = computed(() => order.value?.business_type === 'stored_value')
const canUseBalance = computed(() => {
  if (isStoredValueOrder.value) return false
  return toAmountNumber(balance.value.balance) >= toAmountNumber(order.value?.amount)
})

储值卡订单隐藏余额支付项、默认 wechatselectMethod('balance')pay() 都必须有储值卡保护。微信 uni.requestPayment 成功后重新调用 loadPage() 获取后端订单状态;不在前端直接增加余额。

  • Step 3: 验证并提交个人中心与支付改造

运行:

npm run verify:comprehensive-commerce
npm run build:mp-weixin

预期全部通过。提交:

git add scripts/verify-comprehensive-commerce.mjs src/pages/comprehensive/profile/index.vue src/pages/comprehensive/profile/orders.vue src/pages/comprehensive/pay/index.vue
git commit -m "feat: connect comprehensive profile and stored value payment"

Task 5: 移除首页近期课程并完成整体回归

Files:

  • Modify: src/pages/comprehensive/home/index.vue
  • Modify: src/modules/comprehensive/api/content.js
  • Modify: src/pages/ice/home/index.vue
  • Modify: src/modules/ice/api/home.js
  • Modify: scripts/verify-comprehensive-session-contract.mjs
  • Modify: scripts/verify-home-venue-switch.mjs(仅在原断言受页面结构变化影响时调整,保留场馆切换验证)

Interfaces:

  • 综合场馆首页继续消费 banners/articles/venue,忽略后端 upcoming_sessions

  • 冰场馆首页继续消费 banners/activities/venue,不请求或映射 upcoming_courses

  • 两个场馆课程 Tab 与课程页面不变

  • Step 1: 先加入首页移除课程的失败验证

expectExcludes(comprehensiveHome, '近期课程', 'comprehensive recent courses section')
expectExcludes(comprehensiveHome, 'upcomingCourses', 'comprehensive recent course state')
expectExcludes(comprehensiveContentApi, 'upcoming_courses', 'legacy comprehensive home mapping')
expectExcludes(comprehensiveContentApi, 'upcoming_sessions', 'unused comprehensive home mapping')
expectExcludes(iceHome, '近期课程', 'ice recent courses section')
expectExcludes(iceHome, 'upcomingCourses', 'ice recent course state')
expectExcludes(iceHomeApi, 'course_limit', 'ice recent course request')
expectExcludes(iceHomeApi, 'upcoming_courses', 'ice recent course mapping')

运行 npm run verify:comprehensive-session,预期因两个首页仍包含近期课程而失败。

  • Step 2: 删除两个首页的近期课程展示和无用数据流

综合场馆首页删除近期课程模板、upcomingCourses 状态、formatTimeRange 导入和课程相关样式;content.js 的首页模型只返回:

{
  banners: toArray(backendData.banners).map(toBanner),
  articles: toArray(backendData.articles).map(toArticle),
  venue: { name: backendData.venue?.name || '' }
}

冰场馆首页删除近期课程模板、状态、格式化函数和相关样式;home.js 不再导入课程映射、不再发送 course_limit/course_date,首页模型只保留 banners/activities/venue。不要删除 VenueTabBar 的课程 Tab,也不要修改两个场馆的课程列表和详情页面。

  • Step 3: 执行完整验证、人工联调清单并提交

自动验证:

npm run verify:tabbar
npm run verify:startup
npm run verify:home-switch
npm run verify:comprehensive-auth
npm run verify:auth-agreements
npm run verify:comprehensive-session
npm run verify:comprehensive-commerce
npm run build:mp-weixin
npm run build:h5

预期所有命令退出码为 0。随后在微信开发者工具连接综合场馆后端,人工验证:

  1. 排课列表、详情、普通预约和支付使用同一 session.id
  2. 商城同时展示次卡套餐和储蓄卡,储蓄卡明确显示售价与到账面值。
  3. 次卡支付后出现在我的次卡;“去预约”只展示当前已有次卡能约的排课。
  4. 次卡预约成功不进入支付页,后台核销/取消后刷新状态正确。
  5. 储蓄卡订单只能微信支付,成功后余额和充值流水刷新正确。
  6. 个人中心可进入充值、我的次卡、余额流水和消费记录。
  7. 两个场馆首页均无近期课程,课程 Tab 仍可正常进入。
  8. 包场、门票、订单详情、登录和场馆切换无回归。

最后提交:

git add src/pages/comprehensive/home/index.vue src/modules/comprehensive/api/content.js src/pages/ice/home/index.vue src/modules/ice/api/home.js scripts/verify-comprehensive-session-contract.mjs scripts/verify-home-venue-switch.mjs
git commit -m "feat: finalize comprehensive frontend integration"

完成定义

  • 五个 Task 均有独立提交且验证通过。
  • npm run build:mp-weixinnpm run build:h5 均成功。
  • 新增 API 没有旧 /api/courses 或预约 { course_id } 残留。
  • 商城、持卡、可约排课、次卡预约、储蓄卡充值和个人中心形成完整可操作链路。
  • 综合场馆与冰场馆首页均不展示近期课程。
  • 工作区中用户原有的无关改动未被提交或覆盖。