docs: add tickets client migration design
This commit is contained in:
245
docs/superpowers/specs/2026-07-30-tickets-client-design.md
Normal file
245
docs/superpowers/specs/2026-07-30-tickets-client-design.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# 游客端票务页面迁移设计
|
||||
|
||||
## 背景与目标
|
||||
|
||||
将 `/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.json` 的 `pages-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 速通、直通车、门票+观光车、一日游和玩乐体验。
|
||||
- 点击左侧分类时将右侧对应分组标题滚动到内容区顶部;右侧滚动进入新分组时同步高亮左侧分类。
|
||||
- 点击商品图片或标题进入详情;点击“选购”直接进入预订选择。
|
||||
|
||||
### 商品详情与预订
|
||||
|
||||
- 详情展示图片、短标题、价格、销量、标签、费用包含、费用不含、详情和购买须知。
|
||||
- 预订先选择日期和场次,再选择数量、游客、联系人和可选保险。
|
||||
- 实名商品要求游客数量不少于购买数量;年龄限制商品根据证件信息和使用日期校验年龄。
|
||||
- 常用出行人可以直接勾选,也可以手动新增。新增数据只保留在当前页面会话。
|
||||
- 提交前重新校验日期、场次、库存、游客、联系方式和年龄规则。
|
||||
|
||||
### 支付、订单、退款与凭证
|
||||
|
||||
- “提交订单并模拟支付”不会调用支付接口;它会生成一条已支付订单并扣减当前会话内的展示库存。
|
||||
- 订单详情展示订单状态、使用场次、游客、联系手机、履约权益、费用、退款规则和支付时间。
|
||||
- 支持选择可退款权益、选择退款原因并提交模拟退款。提交后更新订单、权益和退款状态。
|
||||
- 第三方履约权益显示第三方票务凭证;自营权益显示园内权益凭证。二维码使用本地可渲染的视觉占位,不依赖远程二维码服务。
|
||||
|
||||
## 默认数据结构
|
||||
|
||||
### 景区
|
||||
|
||||
```js
|
||||
{
|
||||
id,
|
||||
name,
|
||||
level,
|
||||
heritage,
|
||||
address,
|
||||
phone,
|
||||
latitude,
|
||||
longitude,
|
||||
heroImage
|
||||
}
|
||||
```
|
||||
|
||||
### 商品分组
|
||||
|
||||
```js
|
||||
{
|
||||
id,
|
||||
name,
|
||||
subtitle,
|
||||
description,
|
||||
tag,
|
||||
productIds,
|
||||
sortOrder,
|
||||
enabled
|
||||
}
|
||||
```
|
||||
|
||||
### 商品
|
||||
|
||||
```js
|
||||
{
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
### 出行人
|
||||
|
||||
```js
|
||||
{
|
||||
id,
|
||||
name,
|
||||
idType,
|
||||
idNumber,
|
||||
phone
|
||||
}
|
||||
```
|
||||
|
||||
### 订单
|
||||
|
||||
```js
|
||||
{
|
||||
id,
|
||||
orderNo,
|
||||
productId,
|
||||
productName,
|
||||
status,
|
||||
visitDate,
|
||||
timeSlot,
|
||||
quantity,
|
||||
travelers,
|
||||
contactName,
|
||||
phone,
|
||||
productAmount,
|
||||
insurance,
|
||||
paidAmount,
|
||||
paidAt,
|
||||
entitlements,
|
||||
gateCredential,
|
||||
selfCredential,
|
||||
refundStatus,
|
||||
logs
|
||||
}
|
||||
```
|
||||
|
||||
### 页面状态
|
||||
|
||||
页面状态使用固定枚举:
|
||||
|
||||
```js
|
||||
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` 中的纯逻辑,并遵循测试先行:
|
||||
|
||||
- 商品总价与保险价格计算
|
||||
- 身份证年龄与适用年龄判断
|
||||
- 预订草稿必填项验证
|
||||
- 模拟订单生成及权益拆分
|
||||
- 退款金额计算与状态更新
|
||||
- 页面状态返回规则
|
||||
|
||||
实现后执行:
|
||||
|
||||
```bash
|
||||
node --test src/pages-service/tickets/model.test.mjs
|
||||
git diff --check
|
||||
yarn build:mp-weixin
|
||||
```
|
||||
|
||||
人工验收完整点击链路:首页分类联动、商品详情、直接选购、日期场次、游客选择/新增、模拟支付、订单列表、订单详情、凭证、退款申请和退款结果。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不迁移后台管理端或员工核销端。
|
||||
- 不接入商品、库存、支付、出票、退款和地图等真实服务。
|
||||
- 不实现本地持久化、登录校验或跨设备订单同步。
|
||||
- 不修改 `src/uni_modules/` 或现有票务以外业务页面。
|
||||
Reference in New Issue
Block a user