|
|
@@ -0,0 +1,332 @@
|
|
|
+# Story 5.9: 订单状态管理
|
|
|
+
|
|
|
+## Status
|
|
|
+Draft
|
|
|
+
|
|
|
+## Story
|
|
|
+**As a** 出行用户
|
|
|
+**I want** 能够查看和管理我的订单状态
|
|
|
+**so that** 了解出行安排进度
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+1. 查看订单列表(待支付、待出发、行程中、已完成、已取消)
|
|
|
+2. 查看订单详情信息
|
|
|
+3. 支持取消订单(在允许的时间范围内)
|
|
|
+4. 订单状态自动更新(待出发→行程中→已完成)
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+- [ ] 创建订单列表API端点 (AC: 1)
|
|
|
+ - [ ] 创建 `packages/server/src/api/orders/list.ts` - 订单列表API(支持按状态筛选)
|
|
|
+ - [ ] 实现订单列表查询逻辑(按用户ID和状态筛选)
|
|
|
+ - [ ] 实现订单列表分页和排序功能
|
|
|
+ - [ ] 添加订单列表验证和错误处理
|
|
|
+- [ ] 创建订单详情API端点 (AC: 2)
|
|
|
+ - [ ] 创建 `packages/server/src/api/orders/[id]/get.ts` - 订单详情API
|
|
|
+ - [ ] 实现订单详情查询逻辑(包含快照信息)
|
|
|
+ - [ ] 实现订单详情权限验证(只能查看自己的订单)
|
|
|
+ - [ ] 添加订单详情验证和错误处理
|
|
|
+- [ ] 创建订单取消API端点 (AC: 3)
|
|
|
+ - [ ] 创建 `packages/server/src/api/orders/[id]/cancel.ts` - 订单取消API(非通用CRUD路由)
|
|
|
+ - [ ] 实现订单取消业务逻辑(状态验证、时间范围检查)
|
|
|
+ - [ ] 实现订单取消后的状态更新和退款逻辑
|
|
|
+ - [ ] 添加订单取消验证和错误处理
|
|
|
+ - [ ] 遵循非通用CRUD路由规范(POST方法、路径格式、权限验证)
|
|
|
+- [ ] 编写订单相关API集成测试 (AC: 1, 2, 3)
|
|
|
+ - [ ] 编写订单列表API集成测试
|
|
|
+ - [ ] 编写订单详情API集成测试
|
|
|
+ - [ ] 编写订单取消API集成测试
|
|
|
+ - [ ] 测试订单状态流转逻辑
|
|
|
+ - [ ] 验证所有API测试通过
|
|
|
+- [ ] 从 mini-demo 迁移订单列表页面 (AC: 1)
|
|
|
+ - [ ] 分析 mini-demo 订单列表页面结构和功能
|
|
|
+ - [ ] 迁移 `mini-demo/pages/orders/` 到 `mini/src/pages/orders/`
|
|
|
+ - [ ] 转换文件格式:`.js/.wxml/.wxss` → `.tsx` (React + TypeScript)
|
|
|
+ - [ ] 转换样式系统:WXSS → Tailwind CSS
|
|
|
+ - [ ] 转换状态管理:小程序 Page data → React useState
|
|
|
+ - [ ] 转换事件处理:bindtap → onClick
|
|
|
+ - [ ] 集成真实后端 API 替换模拟数据
|
|
|
+ - [ ] 实现订单列表状态筛选功能
|
|
|
+ - [ ] 实现订单列表分页加载
|
|
|
+ - [ ] 实现订单列表空状态处理
|
|
|
+- [ ] 从 mini-demo 迁移订单详情页面 (AC: 2, 3)
|
|
|
+ - [ ] 分析 mini-demo 订单详情页面结构和功能
|
|
|
+ - [ ] 迁移 `mini-demo/pages/order-detail/` 到 `mini/src/pages/order-detail/`
|
|
|
+ - [ ] 转换文件格式:`.js/.wxml/.wxss` → `.tsx` (React + TypeScript)
|
|
|
+ - [ ] 转换样式系统:WXSS → Tailwind CSS
|
|
|
+ - [ ] 转换状态管理:小程序 Page data → React useState
|
|
|
+ - [ ] 转换事件处理:bindtap → onClick
|
|
|
+ - [ ] 集成真实后端 API 替换模拟数据
|
|
|
+ - [ ] 实现订单详情信息展示
|
|
|
+ - [ ] 实现订单取消功能
|
|
|
+ - [ ] 实现订单状态显示和更新
|
|
|
+- [ ] 编写小程序页面组件测试 (AC: 1, 2, 3)
|
|
|
+ - [ ] 编写订单列表页面组件测试
|
|
|
+ - [ ] 编写订单详情页面组件测试
|
|
|
+ - [ ] 测试订单状态管理流程
|
|
|
+ - [ ] 验证所有组件测试通过
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 数据模型设计
|
|
|
+基于 [docs/architecture/data-model-schema-changes.md#订单模型],订单实体已创建,包含以下关键属性:
|
|
|
+
|
|
|
+**订单实体关键属性** [Source: architecture/data-model-schema-changes.md#订单模型]:
|
|
|
+- `id`: number - 主键标识符
|
|
|
+- `userId`: number - 用户ID
|
|
|
+- `routeId`: number - 路线ID
|
|
|
+- `passengerCount`: number - 乘客数量
|
|
|
+- `totalAmount`: number - 订单总金额
|
|
|
+- `status`: string - 订单状态(待支付、待出发、行程中、已完成、已取消)
|
|
|
+- `paymentStatus`: string - 支付状态
|
|
|
+- `passengerSnapshots`: JSON - 乘客信息快照数组(下单时的多个乘客信息)
|
|
|
+- `routeSnapshot`: JSON - 路线信息快照(下单时的路线信息)
|
|
|
+- `createdAt`: Date - 创建时间
|
|
|
+
|
|
|
+**订单状态枚举定义** [Source: architecture/data-model-schema-changes.md#枚举定义]:
|
|
|
+```typescript
|
|
|
+export enum OrderStatus {
|
|
|
+ PENDING_PAYMENT = '待支付',
|
|
|
+ WAITING_DEPARTURE = '待出发',
|
|
|
+ IN_PROGRESS = '行程中',
|
|
|
+ COMPLETED = '已完成',
|
|
|
+ CANCELLED = '已取消'
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**支付状态枚举定义** [Source: architecture/data-model-schema-changes.md#枚举定义]:
|
|
|
+```typescript
|
|
|
+export enum PaymentStatus {
|
|
|
+ PENDING = '待支付',
|
|
|
+ PAID = '已支付',
|
|
|
+ FAILED = '支付失败',
|
|
|
+ REFUNDED = '已退款'
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### API端点设计
|
|
|
+基于 [docs/architecture/source-tree.md#实际项目结构],订单相关API端点必须遵循以下文件组织:
|
|
|
+
|
|
|
+**订单API文件位置** [Source: architecture/source-tree.md#实际项目结构]:
|
|
|
+- **订单列表API**: `packages/server/src/api/orders/list.ts`
|
|
|
+- **订单详情API**: `packages/server/src/api/orders/[id]/get.ts`
|
|
|
+- **订单取消API**: `packages/server/src/api/orders/[id]/cancel.ts`
|
|
|
+- **订单模块**: `packages/server/src/modules/orders/order.service.ts`
|
|
|
+- **订单实体**: `packages/server/src/modules/orders/order.entity.ts`
|
|
|
+- **Zod Schema**: `packages/server/src/modules/orders/order.schema.ts`
|
|
|
+
|
|
|
+### 订单状态管理逻辑
|
|
|
+基于 [docs/architecture/data-model-schema-changes.md#订单模型],订单状态管理必须遵循以下规则:
|
|
|
+
|
|
|
+**状态流转规则** [Source: architecture/data-model-schema-changes.md#订单模型]:
|
|
|
+- 待支付 → 待出发(支付成功后)
|
|
|
+- 待出发 → 行程中(出发时间到达)
|
|
|
+- 行程中 → 已完成(到达目的地)
|
|
|
+- 待出发 → 已取消(用户取消)
|
|
|
+
|
|
|
+**取消订单限制** [Source: architecture/data-model-schema-changes.md#订单模型]:
|
|
|
+- 仅允许取消状态为"待出发"的订单
|
|
|
+- 取消时间必须在出发时间前1小时以上
|
|
|
+- 取消后需要处理退款逻辑
|
|
|
+
|
|
|
+### 小程序页面迁移指导
|
|
|
+基于 [docs/architecture/mini-demo-migration-guide.md],订单相关页面迁移必须遵循以下规范:
|
|
|
+
|
|
|
+**迁移源文件** [Source: mini-demo/pages/]:
|
|
|
+- **订单列表页面**: `mini-demo/pages/orders/orders.js` + `orders.wxml` + `orders.wxss`
|
|
|
+- **订单详情页面**: `mini-demo/pages/order-detail/order-detail.js` + `order-detail.wxml` + `order-detail.wxss`
|
|
|
+
|
|
|
+**技术转换要求** [Source: architecture/mini-demo-migration-guide.md#技术栈转换]:
|
|
|
+- **文件格式**: `.js/.wxml/.wxss` → `.tsx` (React + TypeScript)
|
|
|
+- **样式系统**: WXSS → Tailwind CSS + shadcn/ui
|
|
|
+- **状态管理**: 小程序 Page data → React useState
|
|
|
+- **事件处理**: bindtap → onClick, bindinput → onInput
|
|
|
+- **数据集成**: 模拟数据 → 真实后端 API
|
|
|
+
|
|
|
+**订单列表页面功能** [Source: mini-demo/pages/orders/orders.js]:
|
|
|
+- 状态选项卡筛选(待出发、行程中、已完成、已取消)
|
|
|
+- 订单卡片展示(订单号、活动名称、行程信息、价格)
|
|
|
+- 司机信息展示(姓名、电话、车辆信息)
|
|
|
+- 订单操作(查看详情、联系司机、查看位置)
|
|
|
+
|
|
|
+**订单详情页面功能** [Source: mini-demo/pages/order-detail/order-detail.js]:
|
|
|
+- 订单详细信息展示
|
|
|
+- 乘客信息展示
|
|
|
+- 行程信息展示
|
|
|
+- 订单取消功能
|
|
|
+- 司机联系功能
|
|
|
+
|
|
|
+### 样式迁移规范
|
|
|
+基于 [docs/architecture/mini-demo-migration-guide.md#样式转换规范],订单页面样式必须遵循以下规范:
|
|
|
+
|
|
|
+**订单卡片样式** [Source: architecture/mini-demo-migration-guide.md#样式迁移对照表]:
|
|
|
+- 使用 `bg-card rounded-card shadow-medium p-card border border-border` 作为卡片基础样式
|
|
|
+- 包车订单使用特殊样式变体
|
|
|
+- 状态标签使用对应的颜色样式
|
|
|
+
|
|
|
+**状态颜色系统** [Source: architecture/mini-demo-migration-guide.md#颜色系统]:
|
|
|
+- 待出发:`text-warning`
|
|
|
+- 行程中:`text-info`
|
|
|
+- 已完成:`text-success`
|
|
|
+- 已取消:`text-error`
|
|
|
+
|
|
|
+### 技术栈要求
|
|
|
+基于 [docs/architecture/tech-stack.md#现有技术栈维护],必须使用项目标准技术栈:
|
|
|
+
|
|
|
+**后端框架** [Source: architecture/tech-stack.md#现有技术栈维护]:
|
|
|
+- **运行时**: Node.js 20.19.2
|
|
|
+- **框架**: Hono 4.8.5
|
|
|
+- **数据库**: PostgreSQL 17
|
|
|
+- **ORM**: TypeORM 0.3.25
|
|
|
+
|
|
|
+**小程序框架** [Source: architecture/tech-stack.md#现有技术栈维护]:
|
|
|
+- **前端框架**: Taro + React
|
|
|
+- **状态管理**: React Query
|
|
|
+- **样式系统**: Tailwind CSS + shadcn/ui
|
|
|
+
|
|
|
+### 开发规范要求
|
|
|
+基于 [docs/architecture/coding-standards.md#通用crud开发规范],必须遵循编码标准:
|
|
|
+
|
|
|
+**API设计规范** [Source: architecture/coding-standards.md#通用crud开发规范]:
|
|
|
+- 使用Zod Schema进行请求和响应验证
|
|
|
+- 包含完整的错误处理
|
|
|
+- 使用统一的响应格式
|
|
|
+- 包含权限验证中间件
|
|
|
+
|
|
|
+### 非通用CRUD路由规范
|
|
|
+基于 [docs/architecture/non-generic-crud-standards.md#业务操作路由],订单取消API必须遵循非通用CRUD路由规范:
|
|
|
+
|
|
|
+**业务操作路由规范** [Source: architecture/non-generic-crud-standards.md#业务操作路由]:
|
|
|
+- 订单取消使用 `POST` 方法表示动作执行
|
|
|
+- 路径格式为 `/:id/cancel`
|
|
|
+- 包含完整的权限验证
|
|
|
+- 返回操作结果
|
|
|
+
|
|
|
+**文件组织规范** [Source: architecture/non-generic-crud-standards.md#文件组织]:
|
|
|
+- 每个非通用路由功能创建独立文件
|
|
|
+- 文件名反映功能用途(如 `cancel.ts`)
|
|
|
+- 在模块的 `index.ts` 中统一导出
|
|
|
+
|
|
|
+**代码结构规范** [Source: architecture/non-generic-crud-standards.md#代码结构]:
|
|
|
+- 路由定义在前,处理函数在后
|
|
|
+- 使用 try-catch 包装所有业务逻辑
|
|
|
+- 保持错误处理的一致性
|
|
|
+
|
|
|
+**订单取消路由代码模板** [Source: architecture/non-generic-crud-standards.md#业务操作路由]:
|
|
|
+```typescript
|
|
|
+import { createRoute, OpenAPIHono } from '@hono/zod-openapi';
|
|
|
+import { authMiddleware } from '../../middleware/auth.middleware';
|
|
|
+import { OrderService } from '../../modules/orders/order.service';
|
|
|
+import { OrderCancelSchema, OrderResponseSchema } from '../../modules/orders/order.schema';
|
|
|
+
|
|
|
+// 订单取消路由定义
|
|
|
+const cancelOrderRoute = createRoute({
|
|
|
+ method: 'post',
|
|
|
+ path: '/{id}/cancel',
|
|
|
+ middleware: [authMiddleware],
|
|
|
+ request: {
|
|
|
+ params: z.object({
|
|
|
+ id: z.coerce.number<number>().openapi({
|
|
|
+ param: { name: 'id', in: 'path' },
|
|
|
+ example: 1,
|
|
|
+ description: '订单ID'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '订单取消成功',
|
|
|
+ content: { 'application/json': { schema: OrderResponseSchema } }
|
|
|
+ },
|
|
|
+ 400: { description: '参数错误' },
|
|
|
+ 401: { description: '未授权' },
|
|
|
+ 403: { description: '权限不足' },
|
|
|
+ 404: { description: '订单不存在' },
|
|
|
+ 500: { description: '服务器错误' }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const app = new OpenAPIHono()
|
|
|
+ .openapi(cancelOrderRoute, async (c) => {
|
|
|
+ try {
|
|
|
+ const user = c.get('user');
|
|
|
+ const { id } = c.req.valid('param');
|
|
|
+
|
|
|
+ const orderService = new OrderService();
|
|
|
+ const order = await orderService.cancelOrder(user.id, id);
|
|
|
+
|
|
|
+ return c.json(order, 200);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('订单取消失败:', error);
|
|
|
+ return c.json({
|
|
|
+ code: 500,
|
|
|
+ message: error instanceof Error ? error.message : '订单取消失败'
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+export default app;
|
|
|
+```
|
|
|
+
|
|
|
+**路由聚合链式规范** [Source: architecture/non-generic-crud-standards.md#路由聚合链式规范]:
|
|
|
+- 使用链式 `.openapi()` 方法注册路由
|
|
|
+- 业务操作路由优先于通用查询路由
|
|
|
+- 保持路由定义的顺序性
|
|
|
+
|
|
|
+**服务实例管理规范** [Source: architecture/non-generic-crud-standards.md#服务实例管理规范]:
|
|
|
+- 在路由处理函数中实例化服务类
|
|
|
+- 避免模块级别的单例,便于测试时 mock
|
|
|
+- 保持代码的可测试性和灵活性
|
|
|
+
|
|
|
+### Testing
|
|
|
+
|
|
|
+**测试要求** [Source: architecture/testing-strategy.md#主项目测试体系]:
|
|
|
+- **主项目测试位置**: `web/tests/unit/`, `web/tests/integration/`, `web/tests/e2e/` 目录
|
|
|
+- **主项目测试框架**: Vitest + Testing Library + hono/testing + Playwright
|
|
|
+- **小程序测试位置**: `mini/tests/` 目录
|
|
|
+- **覆盖率目标**: 核心业务逻辑 > 80%
|
|
|
+- **需要创建的测试文件**: 订单列表API集成测试、订单详情API集成测试、订单取消API集成测试、小程序页面组件测试
|
|
|
+
|
|
|
+**具体测试要求** [Source: architecture/testing-strategy.md#测试金字塔策略]:
|
|
|
+- **订单列表API集成测试** (P1优先级)
|
|
|
+ - 测试订单列表API端点
|
|
|
+ - 验证按状态筛选功能
|
|
|
+ - 测试分页和排序功能
|
|
|
+ - 验证权限控制(只能查看自己的订单)
|
|
|
+- **订单详情API集成测试** (P1优先级)
|
|
|
+ - 测试订单详情API端点
|
|
|
+ - 验证订单详情包含快照信息
|
|
|
+ - 测试权限验证逻辑
|
|
|
+ - 验证错误处理场景
|
|
|
+- **订单取消API集成测试** (P1优先级)
|
|
|
+ - 测试订单取消API端点
|
|
|
+ - 验证状态和时间限制检查
|
|
|
+ - 测试取消后的状态更新
|
|
|
+ - 验证退款逻辑(如有)
|
|
|
+- **小程序页面组件测试** (P1优先级)
|
|
|
+ - 测试订单列表页面组件渲染
|
|
|
+ - 测试订单详情页面组件
|
|
|
+ - 验证订单状态筛选功能
|
|
|
+ - 测试订单取消流程
|
|
|
+- **E2E订单管理流程测试** (P2优先级)
|
|
|
+ - 测试完整的订单管理流程
|
|
|
+ - 验证订单状态流转
|
|
|
+ - 测试订单取消功能
|
|
|
+
|
|
|
+## Change Log
|
|
|
+| Date | Version | Description | Author |
|
|
|
+|------|---------|-------------|--------|
|
|
|
+| 2025-10-24 | 1.0 | 初始故事创建,基于史诗005 US005-09需求 | Bob (Scrum Master) |
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+*此部分由开发代理在实施过程中填写*
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+### Completion Notes List
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+## QA Results
|
|
|
+*此部分由QA代理在审查完成后填写*
|