Files
YGChatCS/docs/superpowers/specs/2026-07-30-tickets-client-design.md

7.9 KiB
Raw Blame History

游客端票务页面迁移设计

背景与目标

/Users/gleen/OneFeel/xiaoqi-seji/需求交付物/前端原型.html 中的“游客端预览”迁移到 src/pages-service/tickets/,并以用户提供的截图作为首页视觉基准。

本次实现覆盖游客端完整链路:

  1. 景区票务首页
  2. 商品详情
  3. 预订选择与实名游客填写
  4. 常用出行人管理
  5. 模拟支付结果
  6. 我的订单与订单详情
  7. 退款申请与退款结果
  8. 我的凭证

后台管理端和员工核销端不在本次范围内。页面不接真实接口,使用结构化默认数据演示完整交互。刷新或重新进入页面后恢复默认数据。

技术方案

采用“单 uni-app 路由 + 同目录组件化状态流”。

  • src/pages-service/tickets/index.vue 是唯一页面入口,负责共享业务状态、页面状态切换、来源记录和返回规则。
  • 复杂视图拆为 src/pages-service/tickets/components/ 下的 Vue 组件。
  • 默认数据集中放在 src/pages-service/tickets/data.js
  • 价格、年龄、订单和退款等可独立验证的纯逻辑放在 src/pages-service/tickets/model.mjs
  • src/pages.jsonpages-service 分包注册 tickets/index,使用自定义导航。

页面内部不为每个步骤新增 uni-app 路由,以避免跨页传递预订草稿、游客和订单状态。首页左上角在没有内部历史时调用 uni.navigateBack;其余页面按进入来源返回。

组件边界

模块 职责
index.vue 页面状态编排、共享默认数据、返回策略、下单和退款命令
TicketHome.vue 景区头图、分类导航、商品分组、商品卡片与分类滚动联动
ProductDetail.vue 商品图片、价格、权益、使用说明、购买须知和预订入口
BookingFlow.vue 日期、场次、数量、游客、联系人、保险与提交订单
TravelerManager.vue 常用出行人列表、新增与选择
PaymentResult.vue 模拟支付成功信息以及订单、凭证入口
OrderList.vue 默认订单和本次新订单列表
OrderDetail.vue 状态、场次、游客、权益、费用、凭证与退款入口
RefundFlow.vue 退款权益选择、原因、预计金额和提交结果
CredentialsView.vue 第三方票务凭证与自营园内权益凭证

简单的商品卡片、状态标签和空状态可以继续拆为小组件,但不引入与当前需求无关的通用组件体系。

页面与交互

票务首页

  • 顶部使用景区实景占位图,展示返回、常用出行人、我的订单、景区名称、等级、地址、联系电话和导航入口。
  • 电话按钮调用 uni.makePhoneCall;导航按钮调用 uni.openLocation,若缺少平台能力则提示用户。
  • 头图下方是一个统一圆角内容壳:左侧为固定分类栏,右侧为独立滚动商品区。
  • 默认分类为景点门票包含景点门票、VIP 速通、直通车、门票+观光车、一日游和玩乐体验。
  • 点击左侧分类时将右侧对应分组标题滚动到内容区顶部;右侧滚动进入新分组时同步高亮左侧分类。
  • 点击商品图片或标题进入详情;点击“选购”直接进入预订选择。

商品详情与预订

  • 详情展示图片、短标题、价格、销量、标签、费用包含、费用不含、详情和购买须知。
  • 预订先选择日期和场次,再选择数量、游客、联系人和可选保险。
  • 实名商品要求游客数量不少于购买数量;年龄限制商品根据证件信息和使用日期校验年龄。
  • 常用出行人可以直接勾选,也可以手动新增。新增数据只保留在当前页面会话。
  • 提交前重新校验日期、场次、库存、游客、联系方式和年龄规则。

支付、订单、退款与凭证

  • “提交订单并模拟支付”不会调用支付接口;它会生成一条已支付订单并扣减当前会话内的展示库存。
  • 订单详情展示订单状态、使用场次、游客、联系手机、履约权益、费用、退款规则和支付时间。
  • 支持选择可退款权益、选择退款原因并提交模拟退款。提交后更新订单、权益和退款状态。
  • 第三方履约权益显示第三方票务凭证;自营权益显示园内权益凭证。二维码使用本地可渲染的视觉占位,不依赖远程二维码服务。

默认数据结构

景区

{
  id,
  name,
  level,
  heritage,
  address,
  phone,
  latitude,
  longitude,
  heroImage
}

商品分组

{
  id,
  name,
  subtitle,
  description,
  tag,
  productIds,
  sortOrder,
  enabled
}

商品

{
  id,
  name,
  shortTitle,
  category,
  description,
  salePrice,
  marketPrice,
  stock,
  sold,
  status,
  highlights,
  ageRule,
  included,
  excluded,
  detail,
  purchaseNotice,
  images,
  reservation: {
    requiresDate,
    advanceDays,
    requiresTimeSlot,
    timeSlots,
    realNameRequired,
    idTypes,
    maxQuantity,
    contactPhoneRequired
  },
  entitlements
}

出行人

{
  id,
  name,
  idType,
  idNumber,
  phone
}

订单

{
  id,
  orderNo,
  productId,
  productName,
  status,
  visitDate,
  timeSlot,
  quantity,
  travelers,
  contactName,
  phone,
  productAmount,
  insurance,
  paidAmount,
  paidAt,
  entitlements,
  gateCredential,
  selfCredential,
  refundStatus,
  logs
}

页面状态

页面状态使用固定枚举:

home
detail
booking
travelers
paid
orders
orderDetail
refundApply
refundResult
credentials

index.vue 同时记录当前商品、当前订单、预订草稿和页面来源,避免组件自行修改跨页面业务数据。子组件只通过 props 接收数据,并通过 emits 发出明确事件。

视觉与样式

  • 所有新增或调整的布局使用可静态扫描的 Tailwind CSS 完整类名。
  • 不新增 SCSS 布局类,不通过字符串拼接生成 Tailwind 类名。
  • 首页复刻截图中的大幅景区头图、深色渐变遮罩、白色景区信息、统一圆角票务内容壳、左侧绿色分类高亮、浅灰商品区域、白色商品卡片和橙色购买按钮。
  • 内页延续白色卡片、浅灰背景、蓝色信息标签和橙色主操作的视觉语言。
  • 景区头图和所有商品图片统一使用: https://one-feel-bucket.oss-cn-guangzhou.aliyuncs.com/oneFeel/2082673896938569729.jpg
  • 页面适配微信小程序常见手机宽度,并保留安全区底部间距。

校验、异常和空状态

  • 未选择日期或场次、购买数量无效、游客数量不足、实名信息不完整、年龄不符、联系人缺失、退款权益未选择时禁止提交,并用 uni.showToast 提供明确提示。
  • 日期或场次无库存时显示售罄并不可选。
  • 商品、订单、出行人均提供空状态,避免默认数组被清空时页面失去反馈。
  • 电话、地图等平台能力失败时不阻断主流程,只显示失败提示。
  • 默认数据不需要网络加载,因此不设计加载失败重试。

测试与验收

采用 Node 内置测试能力验证 model.mjs 中的纯逻辑,并遵循测试先行:

  • 商品总价与保险价格计算
  • 身份证年龄与适用年龄判断
  • 预订草稿必填项验证
  • 模拟订单生成及权益拆分
  • 退款金额计算与状态更新
  • 页面状态返回规则

实现后执行:

node --test src/pages-service/tickets/model.test.mjs
git diff --check
yarn build:mp-weixin

人工验收完整点击链路:首页分类联动、商品详情、直接选购、日期场次、游客选择/新增、模拟支付、订单列表、订单详情、凭证、退款申请和退款结果。

非目标

  • 不迁移后台管理端或员工核销端。
  • 不接入商品、库存、支付、出票、退款和地图等真实服务。
  • 不实现本地持久化、登录校验或跨设备订单同步。
  • 不修改 src/uni_modules/ 或现有票务以外业务页面。