| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825 |
- import { Page, Locator } from '@playwright/test';
- import { selectRadixOption } from '@d8d/e2e-test-utils';
- /**
- * 订单状态常量
- */
- export const ORDER_STATUS = {
- DRAFT: 'draft',
- CONFIRMED: 'confirmed',
- IN_PROGRESS: 'in_progress',
- COMPLETED: 'completed',
- } as const;
- /**
- * 订单状态类型
- */
- export type OrderStatus = typeof ORDER_STATUS[keyof typeof ORDER_STATUS];
- /**
- * 订单状态显示名称映射
- */
- export const ORDER_STATUS_LABELS: Record<OrderStatus, string> = {
- draft: '草稿',
- confirmed: '已确认',
- in_progress: '进行中',
- completed: '已完成',
- } as const;
- /**
- * 工作状态常量
- */
- export const WORK_STATUS = {
- NOT_EMPLOYED: 'not_employed',
- PENDING: 'pending',
- EMPLOYED: 'employed',
- RESIGNED: 'resigned',
- } as const;
- /**
- * 工作状态类型
- */
- export type WorkStatus = typeof WORK_STATUS[keyof typeof WORK_STATUS];
- /**
- * 工作状态显示名称映射
- */
- export const WORK_STATUS_LABELS: Record<WorkStatus, string> = {
- not_employed: '未就业',
- pending: '待就业',
- employed: '已就业',
- resigned: '已离职',
- } as const;
- /**
- * 订单数据接口
- */
- export interface OrderData {
- /** 订单名称 */
- name: string;
- /** 预计开始日期 */
- expectedStartDate?: string;
- /** 平台ID */
- platformId?: number;
- /** 平台名称 */
- platformName?: string;
- /** 公司ID */
- companyId?: number;
- /** 公司名称 */
- companyName?: string;
- /** 渠道ID */
- channelId?: number;
- /** 渠道名称 */
- channelName?: string;
- /** 订单状态 */
- status?: OrderStatus;
- /** 工作状态 */
- workStatus?: WorkStatus;
- }
- /**
- * 订单人员数据接口
- */
- export interface OrderPersonData {
- /** 残疾人ID */
- disabledPersonId: number;
- /** 残疾人姓名 */
- disabledPersonName?: string;
- /** 入职日期 */
- hireDate?: string;
- /** 薪资 */
- salary?: number;
- /** 工作状态 */
- workStatus?: WorkStatus;
- /** 实际入职日期 */
- actualHireDate?: string;
- /** 离职日期 */
- resignDate?: string;
- }
- /**
- * 网络响应数据接口
- */
- export interface NetworkResponse {
- /** 请求URL */
- url: string;
- /** 请求方法 */
- method: string;
- /** 响应状态码 */
- status: number;
- /** 是否成功 */
- ok: boolean;
- /** 响应头 */
- responseHeaders: Record<string, string>;
- /** 响应体 */
- responseBody: unknown;
- }
- /**
- * 表单提交结果接口
- */
- export interface FormSubmitResult {
- /** 提交是否成功 */
- success: boolean;
- /** 是否有错误 */
- hasError: boolean;
- /** 是否有成功消息 */
- hasSuccess: boolean;
- /** 错误消息 */
- errorMessage?: string;
- /** 成功消息 */
- successMessage?: string;
- /** 网络响应列表 */
- responses?: NetworkResponse[];
- }
- /**
- * 订单管理 Page Object
- *
- * 用于订单管理功能的 E2E 测试
- * 页面路径: /admin/orders(待确认)
- *
- * @example
- * ```typescript
- * const orderPage = new OrderManagementPage(page);
- * await orderPage.goto();
- * await orderPage.createOrder({ name: '测试订单' });
- * ```
- */
- export class OrderManagementPage {
- readonly page: Page;
- // ===== 页面级选择器 =====
- /** 页面标题 */
- readonly pageTitle: Locator;
- /** 新增订单按钮 */
- readonly addOrderButton: Locator;
- /** 订单列表表格 */
- readonly orderTable: Locator;
- /** 搜索输入框 */
- readonly searchInput: Locator;
- /** 搜索按钮 */
- readonly searchButton: Locator;
- constructor(page: Page) {
- this.page = page;
- // 初始化页面级选择器
- // 使用更精确的选择器来定位页面标题(避免与侧边栏按钮冲突)
- this.pageTitle = page.locator('[data-slot="card-title"]').getByText('订单管理', { exact: true });
- // 使用 data-testid 定位创建订单按钮(按钮文本是"创建订单"不是"新增订单")
- this.addOrderButton = page.getByTestId('create-order-button');
- this.orderTable = page.locator('table');
- // 使用 data-testid 定位搜索输入框
- this.searchInput = page.getByTestId('search-order-name-input');
- // 使用 data-testid 定位搜索按钮
- this.searchButton = page.getByTestId('search-button');
- }
- // ===== 导航和基础验证 =====
- /**
- * 导航到订单管理页面
- */
- async goto() {
- await this.page.goto('/admin/orders');
- await this.page.waitForLoadState('domcontentloaded');
- // 等待页面标题出现
- await this.pageTitle.waitFor({ state: 'visible', timeout: 15000 });
- // 等待表格数据加载
- await this.page.waitForSelector('table tbody tr', { state: 'visible', timeout: 20000 });
- await this.expectToBeVisible();
- }
- /**
- * 验证页面关键元素可见
- */
- async expectToBeVisible() {
- await this.pageTitle.waitFor({ state: 'visible', timeout: 15000 });
- await this.addOrderButton.waitFor({ state: 'visible', timeout: 10000 });
- }
- // ===== 搜索和筛选功能 =====
- /**
- * 按订单名称搜索
- * @param name 订单名称
- */
- async searchByName(name: string) {
- await this.searchInput.fill(name);
- await this.searchButton.click();
- await this.page.waitForLoadState('networkidle');
- await this.page.waitForTimeout(1000);
- }
- /**
- * 打开高级筛选对话框
- */
- async openFilterDialog() {
- const filterButton = this.page.getByRole('button', { name: /筛选|高级筛选/ });
- await filterButton.click();
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
- }
- /**
- * 设置筛选条件
- * @param filters 筛选条件
- */
- async setFilters(filters: {
- status?: OrderStatus;
- workStatus?: WorkStatus;
- platformId?: number;
- platformName?: string;
- companyId?: number;
- companyName?: string;
- channelId?: number;
- channelName?: string;
- dateRange?: { start?: string; end?: string };
- }) {
- // 订单状态筛选
- if (filters.status) {
- const statusFilter = this.page.getByLabel(/订单状态/);
- await statusFilter.click();
- const statusLabel = ORDER_STATUS_LABELS[filters.status];
- await this.page.getByRole('option', { name: statusLabel }).click();
- }
- // 工作状态筛选
- if (filters.workStatus) {
- const workStatusFilter = this.page.getByLabel(/工作状态/);
- await workStatusFilter.click();
- const workStatusLabel = WORK_STATUS_LABELS[filters.workStatus];
- await this.page.getByRole('option', { name: workStatusLabel }).click();
- }
- // 平台筛选
- if (filters.platformName) {
- await selectRadixOption(this.page, '平台', filters.platformName);
- }
- // 公司筛选
- if (filters.companyName) {
- await selectRadixOption(this.page, '公司', filters.companyName);
- }
- // 渠道筛选
- if (filters.channelName) {
- await selectRadixOption(this.page, '渠道', filters.channelName);
- }
- // 日期范围筛选
- if (filters.dateRange) {
- if (filters.dateRange.start) {
- const startDateInput = this.page.getByLabel(/开始日期|起始日期/);
- await startDateInput.fill(filters.dateRange.start);
- }
- if (filters.dateRange.end) {
- const endDateInput = this.page.getByLabel(/结束日期|截止日期/);
- await endDateInput.fill(filters.dateRange.end);
- }
- }
- }
- /**
- * 应用筛选条件
- */
- async applyFilters() {
- const applyButton = this.page.getByRole('button', { name: /应用|确定|筛选/ });
- await applyButton.click();
- await this.page.waitForLoadState('networkidle');
- await this.page.waitForTimeout(1000);
- }
- /**
- * 清空筛选条件
- */
- async clearFilters() {
- const clearButton = this.page.getByRole('button', { name: /重置|清空/ });
- await clearButton.click();
- await this.page.waitForTimeout(500);
- }
- // ===== 订单 CRUD 操作 =====
- /**
- * 打开创建订单对话框
- */
- async openCreateDialog() {
- await this.addOrderButton.click();
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
- }
- /**
- * 打开编辑订单对话框
- * @param orderName 订单名称
- */
- async openEditDialog(orderName: string) {
- // 找到订单行并点击"打开菜单"按钮
- const orderRow = this.orderTable.locator('tbody tr').filter({ hasText: orderName });
- const menuButton = orderRow.getByRole('button', { name: '打开菜单' });
- await menuButton.click();
- // 等待菜单出现并点击"编辑"选项
- // 使用 data-testid 或 role 定位编辑选项
- const editOption = this.page.getByRole('menuitem', { name: '编辑' });
- await editOption.waitFor({ state: 'visible', timeout: 3000 });
- await editOption.click();
- // 等待编辑对话框出现
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
- }
- /**
- * 打开删除确认对话框
- * @param orderName 订单名称
- */
- async openDeleteDialog(orderName: string) {
- // 找到订单行并点击"打开菜单"按钮(与编辑操作相同的模式)
- const orderRow = this.orderTable.locator('tbody tr').filter({ hasText: orderName });
- const menuButton = orderRow.getByRole('button', { name: '打开菜单' });
- await menuButton.click();
- // 等待菜单出现并点击"删除"选项
- const deleteOption = this.page.getByRole('menuitem', { name: '删除' });
- await deleteOption.waitFor({ state: 'visible', timeout: 3000 });
- await deleteOption.click();
- // 等待删除确认对话框出现
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'visible', timeout: 5000 });
- }
- /**
- * 填写订单表单
- * @param data 订单数据
- */
- async fillOrderForm(data: OrderData) {
- // 等待表单出现
- await this.page.waitForSelector('form', { state: 'visible', timeout: 5000 });
- // 填写订单名称
- if (data.name) {
- await this.page.getByLabel(/订单名称|名称/).fill(data.name);
- }
- // 填写预计开始日期
- if (data.expectedStartDate) {
- const dateInput = this.page.getByLabel(/预计开始日期|开始日期/);
- await dateInput.fill(data.expectedStartDate);
- }
- // 选择平台
- if (data.platformName) {
- await selectRadixOption(this.page, '平台', data.platformName);
- }
- // 选择公司
- if (data.companyName) {
- await selectRadixOption(this.page, '公司', data.companyName);
- }
- // 选择渠道
- if (data.channelName) {
- await selectRadixOption(this.page, '渠道', data.channelName);
- }
- // 选择订单状态(如果是编辑模式)
- if (data.status) {
- const statusLabel = ORDER_STATUS_LABELS[data.status];
- await selectRadixOption(this.page, '订单状态', statusLabel);
- }
- // 选择工作状态(如果是编辑模式)
- if (data.workStatus) {
- const workStatusLabel = WORK_STATUS_LABELS[data.workStatus];
- await selectRadixOption(this.page, '工作状态', workStatusLabel);
- }
- }
- /**
- * 提交表单
- * @returns 表单提交结果
- */
- async submitForm(): Promise<FormSubmitResult> {
- // 收集网络响应
- const responses: NetworkResponse[] = [];
- // 监听所有网络请求
- const responseHandler = async (response: Response) => {
- const url = response.url();
- // 监听订单管理相关的 API 请求
- if (url.includes('/orders') || url.includes('order')) {
- const requestBody = response.request()?.postData();
- const responseBody = await response.text().catch(() => '');
- let jsonBody = null;
- try {
- jsonBody = JSON.parse(responseBody);
- } catch {
- // 不是 JSON 响应
- }
- responses.push({
- url,
- method: response.request()?.method() ?? 'UNKNOWN',
- status: response.status(),
- ok: response.ok(),
- responseHeaders: await response.allHeaders().catch(() => ({})),
- responseBody: jsonBody || responseBody,
- });
- }
- };
- this.page.on('response', responseHandler);
- try {
- // 点击提交按钮(创建或更新)
- const submitButton = this.page.getByRole('button', { name: /^(创建|更新|保存)$/ });
- await submitButton.click();
- // 等待网络请求完成(使用较宽松的超时,因为有些操作可能不触发网络请求)
- try {
- await this.page.waitForLoadState('networkidle', { timeout: 5000 });
- } catch {
- // networkidle 超时不是致命错误,继续检查 Toast 消息
- console.debug('networkidle 超时,继续检查 Toast 消息');
- }
- } finally {
- // 确保监听器总是被移除,防止内存泄漏
- this.page.off('response', responseHandler);
- }
- // 等待 Toast 消息显示
- await this.page.waitForTimeout(2000);
- // 检查 Toast 消息
- const errorToast = this.page.locator('[data-sonner-toast][data-type="error"]');
- const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
- const hasError = await errorToast.count() > 0;
- const hasSuccess = await successToast.count() > 0;
- let errorMessage: string | null = null;
- let successMessage: string | null = null;
- if (hasError) {
- errorMessage = await errorToast.first().textContent();
- }
- if (hasSuccess) {
- successMessage = await successToast.first().textContent();
- }
- return {
- success: hasSuccess || (!hasError && !hasSuccess),
- hasError,
- hasSuccess,
- errorMessage: errorMessage ?? undefined,
- successMessage: successMessage ?? undefined,
- responses,
- };
- }
- /**
- * 取消对话框
- */
- async cancelDialog() {
- const cancelButton = this.page.getByRole('button', { name: '取消' });
- await cancelButton.click();
- await this.waitForDialogClosed();
- }
- /**
- * 等待对话框关闭
- */
- async waitForDialogClosed() {
- const dialog = this.page.locator('[role="dialog"]');
- await dialog.waitFor({ state: 'hidden', timeout: 5000 })
- .catch(() => console.debug('对话框关闭超时,可能已经关闭'));
- await this.page.waitForTimeout(500);
- }
- /**
- * 确认删除操作
- */
- async confirmDelete() {
- // 尝试多种可能的按钮名称
- const confirmButton = this.page.locator('[role="alertdialog"]').getByRole('button', {
- name: /^(确认删除|删除|确定|确认)$/
- });
- await confirmButton.click();
- // 等待确认对话框关闭和网络请求完成
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
- .catch(() => console.debug('删除确认对话框关闭超时'));
- await this.page.waitForLoadState('networkidle', { timeout: 10000 });
- await this.page.waitForTimeout(1000);
- }
- /**
- * 取消删除操作
- */
- async cancelDelete() {
- const cancelButton = this.page.getByRole('button', { name: '取消' }).and(
- this.page.locator('[role="alertdialog"]')
- );
- await cancelButton.click();
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
- .catch(() => console.debug('删除确认对话框关闭超时(取消操作)'));
- }
- /**
- * 验证订单是否存在
- * @param orderName 订单名称
- * @returns 订单是否存在
- */
- async orderExists(orderName: string): Promise<boolean> {
- const orderRow = this.orderTable.locator('tbody tr').filter({ hasText: orderName });
- return (await orderRow.count()) > 0;
- }
- // ===== 订单详情 =====
- /**
- * 打开订单详情对话框
- * @param orderName 订单名称
- */
- async openDetailDialog(orderName: string) {
- // 找到订单行并点击查看详情按钮
- const orderRow = this.orderTable.locator('tbody tr').filter({ hasText: orderName });
- const detailButton = orderRow.getByRole('button', { name: /详情|查看/ });
- await detailButton.click();
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
- }
- /**
- * 获取订单详情中的基本信息
- * @returns 订单基本信息
- */
- async getOrderDetailInfo(): Promise<{
- name?: string;
- status?: string;
- workStatus?: string;
- expectedStartDate?: string;
- platform?: string;
- company?: string;
- channel?: string;
- }> {
- const dialog = this.page.locator('[role="dialog"]');
- const result: Record<string, string | undefined> = {};
- // 订单名称 - 查找"订单名称"标签后的值
- const nameElement = dialog.locator('.text-muted-foreground').filter({ hasText: '订单名称' })
- .locator('..').locator('p,span,div').nth(1);
- if (await nameElement.count() > 0) {
- const text = await nameElement.textContent();
- result.name = text || undefined;
- }
- // 订单状态
- const statusElement = dialog.locator('.text-muted-foreground').filter({ hasText: '订单状态' })
- .locator('..').locator('p,span,div').nth(1);
- if (await statusElement.count() > 0) {
- const text = await statusElement.textContent();
- result.status = text || undefined;
- }
- // 工作状态
- const workStatusElement = dialog.locator('.text-muted-foreground').filter({ hasText: '工作状态' })
- .locator('..').locator('p,span,div').nth(1);
- if (await workStatusElement.count() > 0) {
- const text = await workStatusElement.textContent();
- result.workStatus = text || undefined;
- }
- // 预计开始日期
- const startDateElement = dialog.locator('.text-muted-foreground').filter({ hasText: /预计开始日期|开始日期/ })
- .locator('..').locator('p,span,div').nth(1);
- if (await startDateElement.count() > 0) {
- const text = await startDateElement.textContent();
- result.expectedStartDate = text || undefined;
- }
- // 平台
- const platformElement = dialog.locator('.text-muted-foreground').filter({ hasText: '平台' })
- .locator('..').locator('p,span,div').nth(1);
- if (await platformElement.count() > 0) {
- const text = await platformElement.textContent();
- result.platform = text || undefined;
- }
- // 公司
- const companyElement = dialog.locator('.text-muted-foreground').filter({ hasText: '公司' })
- .locator('..').locator('p,span,div').nth(1);
- if (await companyElement.count() > 0) {
- const text = await companyElement.textContent();
- result.company = text || undefined;
- }
- // 渠道
- const channelElement = dialog.locator('.text-muted-foreground').filter({ hasText: '渠道' })
- .locator('..').locator('p,span,div').nth(1);
- if (await channelElement.count() > 0) {
- const text = await channelElement.textContent();
- result.channel = text || undefined;
- }
- return result;
- }
- // ===== 人员关联管理 =====
- /**
- * 打开人员管理对话框
- *
- * **使用场景:**
- * - **从订单列表页打开**: 传入 `orderName` 参数,方法会先找到对应订单行,再点击人员管理按钮
- * - **从订单详情页打开**: 不传参数,方法会直接点击页面中的人员管理按钮
- *
- * @param orderName 订单名称(可选)。从列表页打开时需要传入,从详情页打开时不传
- *
- * @example
- * ```typescript
- * // 从订单列表页打开
- * await orderPage.openPersonManagementDialog('测试订单');
- *
- * // 从订单详情页打开
- * await orderPage.openDetailDialog('测试订单');
- * await orderPage.openPersonManagementDialog();
- * ```
- */
- async openPersonManagementDialog(orderName?: string) {
- // 如果提供了订单名称,先找到对应的订单行
- if (orderName) {
- const orderRow = this.orderTable.locator('tbody tr').filter({ hasText: orderName });
- const personButton = orderRow.getByRole('button', { name: /人员|员工/ });
- await personButton.click();
- } else {
- // 如果在详情页,直接点击人员管理按钮
- const personButton = this.page.getByRole('button', { name: /人员管理|添加人员/ });
- await personButton.click();
- }
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
- }
- /**
- * 添加人员到订单
- * @param personData 人员数据
- */
- async addPersonToOrder(personData: OrderPersonData) {
- // 点击添加人员按钮
- const addButton = this.page.getByRole('button', { name: /添加人员|新增人员/ });
- await addButton.click();
- await this.page.waitForTimeout(300);
- // 选择残疾人(支持通过名称选择)
- if (personData.disabledPersonName) {
- await selectRadixOption(this.page, '残疾人|选择残疾人', personData.disabledPersonName);
- } else if (personData.disabledPersonId) {
- // 如果只提供了 ID,尝试在对话框中选择第一个残疾人
- const firstCheckbox = this.page.locator('[role="dialog"]').locator('table tbody tr').first().locator('input[type="checkbox"]').first();
- try {
- await firstCheckbox.waitFor({ state: 'visible', timeout: 3000 });
- await firstCheckbox.check();
- } catch {
- console.debug('没有可用的残疾人数据');
- }
- }
- // 填写入职日期
- if (personData.hireDate) {
- const hireDateInput = this.page.getByLabel(/入职日期/);
- await hireDateInput.fill(personData.hireDate);
- }
- // 填写薪资
- if (personData.salary !== undefined) {
- const salaryInput = this.page.getByLabel(/薪资|工资/);
- await salaryInput.fill(String(personData.salary));
- }
- // 选择工作状态
- if (personData.workStatus) {
- const workStatusLabel = WORK_STATUS_LABELS[personData.workStatus];
- await selectRadixOption(this.page, '工作状态', workStatusLabel);
- }
- // 提交
- const submitButton = this.page.getByRole('button', { name: /^(添加|确定|保存)$/ });
- await submitButton.click();
- await this.page.waitForLoadState('networkidle');
- await this.page.waitForTimeout(1000);
- }
- /**
- * 修改人员工作状态
- * @param personName 人员姓名
- * @param newStatus 新的工作状态
- */
- async updatePersonWorkStatus(personName: string, newStatus: WorkStatus) {
- // 找到人员行
- const personRow = this.page.locator('[role="dialog"]').locator('table tbody tr').filter({ hasText: personName });
- // 点击编辑工作状态按钮
- const editButton = personRow.getByRole('button', { name: /编辑|修改/ });
- await editButton.click();
- await this.page.waitForTimeout(300);
- // 选择新的工作状态
- const workStatusLabel = WORK_STATUS_LABELS[newStatus];
- await selectRadixOption(this.page, '工作状态', workStatusLabel);
- // 提交
- const submitButton = this.page.getByRole('button', { name: /^(更新|保存|确定)$/ });
- await submitButton.click();
- await this.page.waitForLoadState('networkidle');
- await this.page.waitForTimeout(1000);
- }
- // ===== 附件管理 =====
- /**
- * 打开添加附件对话框
- */
- async openAddAttachmentDialog() {
- const attachmentButton = this.page.getByRole('button', { name: /添加附件|上传附件/ });
- await attachmentButton.click();
- await this.page.waitForSelector('[role="dialog"]', { state: 'visible', timeout: 5000 });
- }
- /**
- * 上传附件
- * @param personName 人员姓名
- * @param fileName 文件名
- * @param mimeType 文件类型(默认为 image/jpeg)
- */
- async uploadAttachment(personName: string, fileName: string, mimeType: string = 'image/jpeg') {
- // 选择订单人员
- const personSelect = this.page.getByLabel(/选择人员|订单人员/);
- await personSelect.click();
- await this.page.getByRole('option', { name: personName }).click();
- // 查找文件上传输入框
- const fileInput = this.page.locator('input[type="file"]');
- await fileInput.setInputFiles({
- name: fileName,
- mimeType,
- buffer: Buffer.from(`fake ${fileName} content`),
- });
- // 等待上传处理
- await this.page.waitForTimeout(500);
- // 提交
- const submitButton = this.page.getByRole('button', { name: /^(上传|确定|保存)$/ });
- await submitButton.click();
- await this.page.waitForLoadState('networkidle');
- await this.page.waitForTimeout(1000);
- }
- // ===== 高级操作 =====
- /**
- * 创建订单(完整流程)
- * @param data 订单数据
- * @returns 表单提交结果
- */
- async createOrder(data: OrderData): Promise<FormSubmitResult> {
- await this.openCreateDialog();
- await this.fillOrderForm(data);
- const result = await this.submitForm();
- await this.waitForDialogClosed();
- return result;
- }
- /**
- * 编辑订单(完整流程)
- * @param orderName 订单名称
- * @param data 更新的订单数据
- * @returns 表单提交结果
- */
- async editOrder(orderName: string, data: OrderData): Promise<FormSubmitResult> {
- await this.openEditDialog(orderName);
- await this.fillOrderForm(data);
- const result = await this.submitForm();
- await this.waitForDialogClosed();
- return result;
- }
- /**
- * 删除订单(完整流程)
- * @param orderName 订单名称
- * @returns 是否成功删除
- */
- async deleteOrder(orderName: string): Promise<boolean> {
- await this.openDeleteDialog(orderName);
- await this.confirmDelete();
- // 等待并检查 Toast 消息
- await this.page.waitForTimeout(1000);
- const successToast = this.page.locator('[data-sonner-toast][data-type="success"]');
- const hasSuccess = await successToast.count() > 0;
- return hasSuccess;
- }
- }
|