# Story 10.1: 创建订单管理 Page Object Status: done ## Story 作为测试开发者, 我想要创建订单管理的 Page Object, 以便组织订单管理相关的页面元素和操作。 ## Acceptance Criteria **Given** Epic 9 的 Page Object 模式已验证 **When** 创建 `web/tests/e2e/pages/admin/order-management.page.ts` **Then** 定义订单列表页面的选择器和操作方法 **And** 定义创建订单表单的选择器和操作方法 **And** 定义编辑订单表单的选择器和操作方法 **And** 定义订单详情对话框的选择器和操作方法 **And** 定义人员关联相关的选择器和操作方法 **And** 定义附件上传相关的选择器和操作方法 **And** 遵循现有 Page Object 设计模式 **And** 所有方法有完整的 TypeScript 类型定义 **参考:** - `web/tests/e2e/pages/admin/disability-person.page.ts` 作为参考 - `web/tests/e2e/pages/admin/region-management.page.ts` 作为参考 - 遵循项目的 Page Object 设计模式 ## Tasks / Subtasks - [x] 创建订单管理 Page Object 基础结构 (AC: Given, When, And) - [x] 定义订单列表页面选择器(标题、新增按钮、搜索框、表格等) - [x] 实现 goto() 方法导航到订单管理页面 - [x] 实现 expectToBeVisible() 方法验证关键元素可见 - [x] 定义订单列表相关方法和选择器 (AC: When) - [x] 定义订单名称搜索输入框和搜索按钮 - [x] 定义订单筛选器(状态、平台、公司、渠道、日期范围) - [x] 定义订单列表表格选择器 - [x] 实现搜索功能方法 searchByName() - [x] 实现筛选功能方法 - [x] 定义订单 CRUD 相关方法和选择器 (AC: When) - [x] 实现打开创建订单对话框方法 openCreateDialog() - [x] 实现填写订单表单方法 fillOrderForm() - [x] 实现提交表单方法 submitForm() - [x] 实现打开编辑订单对话框方法 openEditDialog() - [x] 实现打开删除确认对话框方法 openDeleteDialog() - [x] 实现订单是否存在验证方法 orderExists() - [x] 定义订单详情相关方法和选择器 (AC: When) - [x] 实现打开订单详情对话框方法 openDetailDialog() - [x] 定义详情对话框内的选择器(订单信息、人员列表、附件列表) - [x] 定义人员关联相关方法和选择器 (AC: When) - [x] 实现打开人员管理对话框方法 openPersonManagementDialog() - [x] 实现添加人员方法 addPersonToOrder() - [x] 实现修改工作状态方法 updatePersonWorkStatus() - [x] 定义附件管理相关方法和选择器 (AC: When) - [x] 实现打开添加附件对话框方法 openAddAttachmentDialog() - [x] 实现上传附件方法 uploadAttachment() - [x] 添加 TypeScript 类型定义和 JSDoc 注释 (AC: And) - [x] 定义 OrderData 接口 - [x] 定义 OrderPersonData 接口 - [x] 定义 FormSubmitResult 接口 - [x] 为所有公共方法添加 JSDoc 注释 ## Dev Notes ### Epic Context **Epic 10: 订单管理 E2E 测试 (Epic C - 业务测试 Epic)** - **目标**: 为订单管理功能编写完整的 E2E 测试,验证订单的 CRUD、状态流转、人员关联和附件管理功能 - **业务分组**: Epic C(业务测试 Epic) - **背景**: 订单管理是招聘系统的核心业务功能,涉及复杂表单(多选择器联动)、状态流转、人员关联等场景 - **模式**: 业务测试为主,工具包支持为辅(遵循 Epic A 成功模式) **依赖:** - Epic 1: ✅ 已完成(Select 工具基础框架) - Epic 2: ✅ 已完成(Select 工具在真实 E2E 测试中验证) - Epic 9: 🔄 进行中(残疾人管理完整 E2E 测试覆盖) ### 订单管理功能概述 根据 epics.md,订单管理涉及以下核心功能: 1. **订单列表**: 查看、搜索、筛选、分页 2. **订单 CRUD**: 创建、编辑、删除订单 3. **订单状态流转**: 草稿 → 已确认 → 进行中 → 已完成 4. **订单详情**: 查看订单完整信息、人员列表、附件列表 5. **人员关联**: 添加残疾人到订单、管理工作状态(未就业、待就业、已就业、已离职) 6. **附件管理**: 为订单人员添加附件 ### Page Object 设计模式参考 本项目已建立成熟的 Page Object 设计模式,参考以下文件: **1. disability-person.page.ts** (残疾人管理 - 复杂表单示例) - 位置: `web/tests/e2e/pages/admin/disability-person.page.ts` - 特点: 多步骤表单、照片上传、动态列表(银行卡、备注、回访记录) - 关键模式: - 使用 `@d8d/e2e-test-utils` 的 `selectRadixOption` 和 `selectProvinceCity` - 网络响应监听和 Toast 消息验证 - 表单调试使用 `console.debug` **2. region-management.page.ts** (区域管理 - 业务模块示例) - 位置: `web/tests/e2e/pages/admin/region-management.page.ts` - 特点: 树形结构、CRUD 操作、状态切换 - 关键模式: - 导出的类型定义(RegionData, RegionLevel, FormSubmitResult 等) - 完整的 JSDoc 注释 - 网络响应监听(NetworkResponse 接口) - Toast 消息验证(data-sonner-toast) ### 技术要求 **导入依赖:** ```typescript import { Page, Locator } from '@playwright/test'; import { selectRadixOption, selectRadixOptionAsync } from '@d8d/e2e-test-utils'; ``` **选择器策略:** - 优先使用 `data-testid` 属性 - 其次使用 `role + name` 组合(如 `getByRole('button', { name: '新增订单' })`) - 避免使用 CSS 类名(不稳定) - 文本匹配使用 `exact: true` 避免误匹配 **网络响应监听模式:** ```typescript // 收集网络响应 const responses: NetworkResponse[] = []; // 监听所有网络请求 this.page.on('response', async (response: Response) => { const url = response.url(); if (url.includes('/orders') || url.includes('order')) { // 收集响应数据 } }); // 执行操作后等待网络空闲 await this.page.waitForLoadState('networkidle', { timeout: 10000 }); ``` **Toast 消息验证:** ```typescript const errorToast = this.page.locator('[data-sonner-toast][data-type="error"]'); const successToast = this.page.locator('[data-sonner-toast][data-type="success"]'); ``` ### Project Structure Notes **文件位置:** - Page Object 文件: `web/tests/e2e/pages/admin/order-management.page.ts` - 测试文件目录: `web/tests/e2e/specs/admin/` - Fixtures 目录: `web/tests/e2e/fixtures/` **对齐统一项目结构:** - 遵循 `project-context.md` 中的 TypeScript 严格模式规则 - 函数参数、返回值必须有明确类型注解 - 禁止使用 `any` 类型 - 公共 API 必须包含完整 JSDoc 注释 ### 测试标准参考 遵循以下测试标准文档(来自 epics.md): - `docs/standards/testing-standards.md` - 测试规范 - `docs/standards/web-ui-testing-standards.md` - Web UI 测试规范 - `docs/standards/e2e-radix-testing.md` - Radix UI E2E 测试标准(核心) **选择器优先级(来自 e2e-radix-testing.md):** 1. `data-testid` - 最高优先级 2. `aria-label + role` 3. `text content + role` - 兜底 **错误消息格式标准:** ``` Error: 操作失败 上下文信息 💡 修复建议 ``` ### 类型定义参考 基于 `region-management.page.ts` 的类型定义模式: ```typescript /** * 订单状态常量 */ export const ORDER_STATUS = { DRAFT: 'draft', CONFIRMED: 'confirmed', IN_PROGRESS: 'in_progress', COMPLETED: 'completed', } as const; /** * 工作状态常量 */ export const WORK_STATUS = { NOT_EMPLOYED: 'not_employed', PENDING: 'pending', EMPLOYED: 'employed', RESIGNED: 'resigned', } as const; /** * 订单数据接口 */ export interface OrderData { /** 订单名称 */ name: string; /** 预计开始日期 */ expectedStartDate?: string; /** 平台ID */ platformId?: number; /** 公司ID */ companyId?: number; /** 渠道ID */ channelId?: number; /** 订单状态 */ status?: typeof ORDER_STATUS[keyof typeof ORDER_STATUS]; /** 工作状态 */ workStatus?: typeof WORK_STATUS[keyof typeof WORK_STATUS]; } /** * 订单人员数据接口 */ export interface OrderPersonData { /** 残疾人ID */ disabledPersonId: number; /** 入职日期 */ hireDate?: string; /** 薪资 */ salary?: number; /** 工作状态 */ workStatus?: typeof WORK_STATUS[keyof typeof WORK_STATUS]; /** 实际入职日期 */ actualHireDate?: string; /** 离职日期 */ resignDate?: string; } /** * 网络响应数据 */ export interface NetworkResponse { url: string; method: string; status: number; ok: boolean; responseHeaders: Record; responseBody: unknown; } /** * 表单提交结果 */ export interface FormSubmitResult { /** 提交是否成功 */ success: boolean; /** 是否有错误 */ hasError: boolean; /** 是否有成功消息 */ hasSuccess: boolean; /** 错误消息 */ errorMessage?: string; /** 成功消息 */ successMessage?: string; /** 网络响应列表 */ responses?: NetworkResponse[]; } ``` ### 订单管理页面元素(待验证) **注意**: 以下元素基于 PRD 描述,实际实现时需要通过浏览器开发工具验证 DOM 结构。 **订单列表页面:** - 页面路径: `/admin/orders`(待确认) - 页面标题: "订单管理" - 新增订单按钮: "新增订单" - 搜索输入框: placeholder="搜索订单名称" - 搜索按钮: "搜索" - 筛选器: 订单状态、工作状态、平台、公司、渠道、日期范围 - 订单列表表格: 显示订单名称、平台、公司、渠道、订单状态、工作状态等 **订单表单:** - 订单名称: 必填 - 预计开始日期: 必填,日期选择器 - 平台: 可选,下拉选择器 - 公司: 可选,下拉选择器 - 渠道: 可选,下拉选择器 **订单详情对话框:** - 显示订单基本信息 - 显示关联人员列表 - 显示附件列表 **人员管理对话框:** - 选择残疾人: 下拉选择器 - 入职日期: 日期选择器 - 薪资: 数字输入 - 工作状态: 下拉选择器 **附件上传对话框:** - 选择订单人员: 下拉选择器 - 上传附件: 文件上传组件 ### 调试技巧 **表单调试:** ```typescript // 在 form.handleSubmit 的第二个参数中添加 console.debug form.handleSubmit(handleSubmit, (errors) => console.debug('表单验证错误:', errors)) ``` **E2E 测试失败调试:** - 查看 `test-results/**/error-context.md` - 使用 `timeout` 命令限制运行时间 - `timeout 60 pnpm test:e2e:chromium <测试文件名>` ### References - [Source: _bmad-output/planning-artifacts/epics.md#Epic 10](../planning-artifacts/epics.md) - [Source: _bmad-output/project-context.md](../project-context.md) - [Source: web/tests/e2e/pages/admin/region-management.page.ts](../../web/tests/e2e/pages/admin/region-management.page.ts) - [Source: web/tests/e2e/pages/admin/disability-person.page.ts](../../web/tests/e2e/pages/admin/disability-person.page.ts) ## Dev Agent Record ### Agent Model Used claude-opus-4-5-20251101 ### Debug Log References ### Completion Notes List ✅ **Story 10.1 完成实现** 创建了订单管理 Page Object (`web/tests/e2e/pages/admin/order-management.page.ts`),包含以下功能: 1. **类型定义和常量**: - `ORDER_STATUS` - 订单状态常量(草稿、已确认、进行中、已完成) - `WORK_STATUS` - 工作状态常量(未就业、待就业、已就业、已离职) - `ORDER_STATUS_LABELS` / `WORK_STATUS_LABELS` - 状态显示名称映射 - `OrderData` 接口 - 订单数据类型 - `OrderPersonData` 接口 - 订单人员数据类型 - `NetworkResponse` 接口 - 网络响应类型 - `FormSubmitResult` 接口 - 表单提交结果类型 2. **页面基础功能**: - `goto()` - 导航到订单管理页面 - `expectToBeVisible()` - 验证关键元素可见 - 页面选择器:标题、新增按钮、表格、搜索框等 3. **搜索和筛选**: - `searchByName()` - 按订单名称搜索 - `openFilterDialog()` - 打开高级筛选对话框 - `setFilters()` - 设置筛选条件(状态、平台、公司、渠道、日期范围) - `applyFilters()` - 应用筛选 - `clearFilters()` - 清空筛选 4. **订单 CRUD**: - `openCreateDialog()` - 打开创建订单对话框 - `openEditDialog()` - 打开编辑订单对话框 - `openDeleteDialog()` - 打开删除确认对话框 - `fillOrderForm()` - 填写订单表单 - `submitForm()` - 提交表单(包含网络响应监听和 Toast 消息验证) - `cancelDialog()` - 取消对话框 - `confirmDelete()` - 确认删除 - `cancelDelete()` - 取消删除 - `orderExists()` - 验证订单是否存在 5. **高级操作(完整流程)**: - `createOrder()` - 创建订单(完整流程) - `editOrder()` - 编辑订单(完整流程) - `deleteOrder()` - 删除订单(完整流程) 6. **订单详情**: - `openDetailDialog()` - 打开订单详情对话框 - `getOrderDetailInfo()` - 获取订单详情中的基本信息 7. **人员关联管理**: - `openPersonManagementDialog()` - 打开人员管理对话框 - `addPersonToOrder()` - 添加人员到订单 - `updatePersonWorkStatus()` - 修改人员工作状态 8. **附件管理**: - `openAddAttachmentDialog()` - 打开添加附件对话框 - `uploadAttachment()` - 上传附件 **实现要点**: - 遵循项目 Page Object 设计模式(参考 region-management.page.ts 和 disability-person.page.ts) - 使用 `@d8d/e2e-test-utils` 的 `selectRadixOption` 和 `selectRadixOptionAsync` 处理 Radix UI 组件 - 使用 `role + name` 组合选择器,符合项目无障碍测试标准 - 所有公共方法都包含完整的 JSDoc 注释 - 网络响应监听模式用于验证 API 调用 - Toast 消息验证(使用 `data-sonner-toast` 属性) **注意**: 实际 DOM 结构和选择器可能需要根据实际页面实现进行调整,建议在编写测试时通过浏览器开发工具验证。 ### File List - web/tests/e2e/pages/admin/order-management.page.ts ## Change Log ### 2026-01-11 - ✅ 创建订单管理 Page Object (`web/tests/e2e/pages/admin/order-management.page.ts`) - ✅ 定义订单状态和工作状态常量及类型 - ✅ 实现页面基础功能(导航、可见性验证) - ✅ 实现搜索和筛选功能 - ✅ 实现订单 CRUD 操作方法 - ✅ 实现订单详情相关方法 - ✅ 实现人员关联管理方法 - ✅ 实现附件管理方法 - ✅ 添加完整 TypeScript 类型定义和 JSDoc 注释 - ✅ 类型检查通过