|
|
@@ -1,5 +1,5 @@
|
|
|
import { Page, Locator } from '@playwright/test';
|
|
|
-import { selectRadixOption, selectRadixOptionAsync } from '@d8d/e2e-test-utils';
|
|
|
+import { selectRadixOption } from '@d8d/e2e-test-utils';
|
|
|
|
|
|
/**
|
|
|
* 订单状态常量
|
|
|
@@ -233,15 +233,19 @@ export class OrderManagementPage {
|
|
|
dateRange?: { start?: string; end?: string };
|
|
|
}) {
|
|
|
// 订单状态筛选
|
|
|
- if (filters.status || filters.workStatus) {
|
|
|
- const statusFilter = this.page.getByLabel(/订单状态|状态/);
|
|
|
+ if (filters.status) {
|
|
|
+ const statusFilter = this.page.getByLabel(/订单状态/);
|
|
|
await statusFilter.click();
|
|
|
- const statusLabel = filters.status
|
|
|
- ? ORDER_STATUS_LABELS[filters.status]
|
|
|
- : undefined;
|
|
|
- if (statusLabel) {
|
|
|
- await this.page.getByRole('option', { name: statusLabel }).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();
|
|
|
}
|
|
|
|
|
|
// 平台筛选
|
|
|
@@ -407,15 +411,17 @@ export class OrderManagementPage {
|
|
|
|
|
|
this.page.on('response', responseHandler);
|
|
|
|
|
|
- // 点击提交按钮(创建或更新)
|
|
|
- const submitButton = this.page.getByRole('button', { name: /^(创建|更新|保存)$/ });
|
|
|
- await submitButton.click();
|
|
|
-
|
|
|
- // 等待网络请求完成
|
|
|
- await this.page.waitForLoadState('networkidle', { timeout: 10000 });
|
|
|
+ try {
|
|
|
+ // 点击提交按钮(创建或更新)
|
|
|
+ const submitButton = this.page.getByRole('button', { name: /^(创建|更新|保存)$/ });
|
|
|
+ await submitButton.click();
|
|
|
|
|
|
- // 移除监听器
|
|
|
- this.page.off('response', responseHandler);
|
|
|
+ // 等待网络请求完成
|
|
|
+ await this.page.waitForLoadState('networkidle', { timeout: 10000 });
|
|
|
+ } finally {
|
|
|
+ // 确保监听器总是被移除,防止内存泄漏
|
|
|
+ this.page.off('response', responseHandler);
|
|
|
+ }
|
|
|
|
|
|
// 等待 Toast 消息显示
|
|
|
await this.page.waitForTimeout(2000);
|
|
|
@@ -461,7 +467,8 @@ export class OrderManagementPage {
|
|
|
*/
|
|
|
async waitForDialogClosed() {
|
|
|
const dialog = this.page.locator('[role="dialog"]');
|
|
|
- await dialog.waitFor({ state: 'hidden', timeout: 5000 }).catch(() => {});
|
|
|
+ await dialog.waitFor({ state: 'hidden', timeout: 5000 })
|
|
|
+ .catch(() => console.debug('对话框关闭超时,可能已经关闭'));
|
|
|
await this.page.waitForTimeout(500);
|
|
|
}
|
|
|
|
|
|
@@ -472,7 +479,8 @@ export class OrderManagementPage {
|
|
|
const confirmButton = this.page.getByRole('button', { name: /^确认删除$/ });
|
|
|
await confirmButton.click();
|
|
|
// 等待确认对话框关闭和网络请求完成
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 }).catch(() => {});
|
|
|
+ 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);
|
|
|
}
|
|
|
@@ -485,7 +493,8 @@ export class OrderManagementPage {
|
|
|
this.page.locator('[role="alertdialog"]')
|
|
|
);
|
|
|
await cancelButton.click();
|
|
|
- await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 }).catch(() => {});
|
|
|
+ await this.page.waitForSelector('[role="alertdialog"]', { state: 'hidden', timeout: 5000 })
|
|
|
+ .catch(() => console.debug('删除确认对话框关闭超时(取消操作)'));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -525,24 +534,63 @@ export class OrderManagementPage {
|
|
|
company?: string;
|
|
|
channel?: string;
|
|
|
}> {
|
|
|
- const result: Record<string, string> = {};
|
|
|
+ const dialog = this.page.locator('[role="dialog"]');
|
|
|
+ const result: Record<string, string | undefined> = {};
|
|
|
|
|
|
- // 订单名称
|
|
|
- const nameElement = this.page.locator('[role="dialog"]').getByText(/订单名称/);
|
|
|
+ // 订单名称 - 查找"订单名称"标签后的值
|
|
|
+ const nameElement = dialog.locator('.text-muted-foreground').filter({ hasText: '订单名称' })
|
|
|
+ .locator('..').locator('p,span,div').nth(1);
|
|
|
if (await nameElement.count() > 0) {
|
|
|
- result.name = await nameElement.textContent();
|
|
|
+ const text = await nameElement.textContent();
|
|
|
+ result.name = text || undefined;
|
|
|
}
|
|
|
|
|
|
// 订单状态
|
|
|
- const statusElement = this.page.locator('[role="dialog"]').getByText(/订单状态/);
|
|
|
+ const statusElement = dialog.locator('.text-muted-foreground').filter({ hasText: '订单状态' })
|
|
|
+ .locator('..').locator('p,span,div').nth(1);
|
|
|
if (await statusElement.count() > 0) {
|
|
|
- result.status = await statusElement.textContent();
|
|
|
+ const text = await statusElement.textContent();
|
|
|
+ result.status = text || undefined;
|
|
|
}
|
|
|
|
|
|
// 工作状态
|
|
|
- const workStatusElement = this.page.locator('[role="dialog"]').getByText(/工作状态/);
|
|
|
+ const workStatusElement = dialog.locator('.text-muted-foreground').filter({ hasText: '工作状态' })
|
|
|
+ .locator('..').locator('p,span,div').nth(1);
|
|
|
if (await workStatusElement.count() > 0) {
|
|
|
- result.workStatus = await workStatusElement.textContent();
|
|
|
+ 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;
|
|
|
@@ -552,7 +600,22 @@ export class OrderManagementPage {
|
|
|
|
|
|
/**
|
|
|
* 打开人员管理对话框
|
|
|
- * @param orderName 订单名称(如果在订单列表页)
|
|
|
+ *
|
|
|
+ * **使用场景:**
|
|
|
+ * - **从订单列表页打开**: 传入 `orderName` 参数,方法会先找到对应订单行,再点击人员管理按钮
|
|
|
+ * - **从订单详情页打开**: 不传参数,方法会直接点击页面中的人员管理按钮
|
|
|
+ *
|
|
|
+ * @param orderName 订单名称(可选)。从列表页打开时需要传入,从详情页打开时不传
|
|
|
+ *
|
|
|
+ * @example
|
|
|
+ * ```typescript
|
|
|
+ * // 从订单列表页打开
|
|
|
+ * await orderPage.openPersonManagementDialog('测试订单');
|
|
|
+ *
|
|
|
+ * // 从订单详情页打开
|
|
|
+ * await orderPage.openDetailDialog('测试订单');
|
|
|
+ * await orderPage.openPersonManagementDialog();
|
|
|
+ * ```
|
|
|
*/
|
|
|
async openPersonManagementDialog(orderName?: string) {
|
|
|
// 如果提供了订单名称,先找到对应的订单行
|