customerPage.ts 10.2 KB
import { Page, Locator, expect } from '@playwright/test';
import { BasePage } from './basePage';

/**
 * 客户管理页面选择器
 */
const selectors = {
  // 导航
  customerMenu: 'text=客户管理',
  addCustomerButton: 'text=新增客户',
  
  // 表单字段
  customerNameInput: 'textbox', // 客户名称输入框
  phoneInput: 'spinbutton', // 手机号输入框
  idCardInput: 'textbox', // 身份证输入框
  
  // 客户分组
  customerGroupPicker: '.nut-input__mask',
  normalCustomerOption: 'uni-view:has-text("普通客户")',
  
  // 赊欠额度
  creditLimitSwitch: '.nut-form-item__body__slots > .nut-switch',
  creditLimitInput: 'uni-input:has-text("请输入赊欠额度/不输为不限额") input',
  
  // 车牌号
  // licensePlateInput: '.nut-input__mask',
  licensePlateInput:'uni-view:nth-child(11) > .nut-cell__value > .nut-form-item__body__slots > .input-wrapper > .flex-input > .nut-input > .nut-input__value > .nut-input__mask',
  confirmLicenceButton:'text=确定',
  // 省市区选择
  regionPicker: 'uni-view:nth-child(12) > .nut-cell__value > .nut-form-item__body__slots > .input-wrapper > .flex-input > .nut-input > .nut-input__value > .nut-input__mask',
  confirmRegionButton: 'text=确认选择',
  
  // 详细地址
  detailedAddressInput: 'uni-view:nth-child(13) > .nut-cell__value > .nut-form-item__body__slots > .nut-input > .nut-input__value > .nut-input__input > .uni-input-wrapper > .uni-input-input',
  
  // 操作按钮
  confirmButton: 'text=确定',
  saveButton: 'text=保存',
  
  // 验证
  customerInList: (customerName: string) => `uni-view:has-text("${customerName}")`,
};

/**
 * 客户管理页面类
 * 处理客户管理相关操作
 */
export class CustomerPage extends BasePage {
  // 导航定位器
  readonly customerMenu: Locator;
  readonly addCustomerButton: Locator;
  
  // 表单字段
  readonly customerNameInput: Locator;
  readonly phoneInput: Locator;
  readonly idCardInput: Locator;
  
  // 客户分组
  readonly customerGroupPicker: Locator;
  readonly normalCustomerOption: Locator;
  
  // 赊欠额度
  readonly creditLimitSwitch: Locator;
  readonly creditLimitInput: Locator;
  
  // 车牌号
  readonly licensePlateInput: Locator;
  
  // 省市区选择
  readonly regionPicker: Locator;
  readonly confirmRegionButton: Locator;
  
  // 详细地址
  readonly detailedAddressInput: Locator;
  
  // 操作按钮
  readonly confirmButton: Locator;
  readonly saveButton: Locator;

  constructor(page: Page) {
    super(page);
    
    this.customerMenu = page.getByText('客户管理');
    this.addCustomerButton = page.getByText('新增客户');
    this.customerNameInput = page.getByRole('textbox').nth(1);
    this.phoneInput = page.getByRole('spinbutton').first();
    this.idCardInput = page.getByRole('textbox').nth(2);
    this.customerGroupPicker = page.locator('.nut-input__mask').first();
    this.normalCustomerOption = page.locator('uni-view').filter({ hasText: /^普通客户$/ }).nth(3);
    this.creditLimitSwitch = page.locator('.nut-form-item__body__slots > .nut-switch');
    this.creditLimitInput = page.locator('uni-input').filter({ hasText: '请输入赊欠额度/不输为不限额' }).getByRole('spinbutton');
    this.licensePlateInput = page.locator('.nut-input__mask').first();
    this.regionPicker = page.locator('uni-view:nth-child(11) > .nut-cell__value > .nut-form-item__body__slots > .input-wrapper > .flex-input > .nut-input > .nut-input__value > .nut-input__mask');
    this.confirmRegionButton = page.getByText('确认选择');
    this.detailedAddressInput = page.locator('uni-view:nth-child(12) > .nut-cell__value > .nut-form-item__body__slots > .nut-input > .nut-input__value > .nut-input__input > .uni-input-wrapper > .uni-input-input');
    this.confirmButton = page.getByText('确定');
    this.saveButton = page.getByText('保存');
  }

  /**
   * 导航到首页并等待加载
   */
  async gotoHome(): Promise<void> {
    await this.navigate('/');
    await this.page.waitForLoadState('networkidle', { timeout: 30000 });
  }

  /**
   * 打开客户管理页面
   */
  async openCustomerManagement(): Promise<void> {
    await this.customerMenu.click();
    await this.page.waitForLoadState('networkidle', { timeout: 30000 });
  }

  /**
   * 点击新增客户按钮
   */
  async clickAddCustomer(): Promise<void> {
    await this.addCustomerButton.click();
    await this.page.waitForLoadState('networkidle', { timeout: 30000 });
  }

  /**
   * 填写客户名称
   * @param name 客户名称
   */
  async fillCustomerName(name: string): Promise<void> {
    await this.customerNameInput.click();
    await this.customerNameInput.fill(name);
  }

  /**
   * 填写手机号
   * @param phone 手机号
   */
  async fillPhone(phone: string): Promise<void> {
    await this.phoneInput.click();
    await this.phoneInput.fill(phone);
  }

  /**
   * 填写身份证号
   * @param idCard 身份证号
   */
  async fillIdCard(idCard: string): Promise<void> {
    await this.idCardInput.click();
    await this.idCardInput.fill(idCard);
  }

  /**
   * 选择客户分组(选择"普通客户")
   */
  async selectCustomerGroup(): Promise<void> {
    // 点击客户分组选择器
    await this.customerGroupPicker.click();
    
    // 等待弹窗出现
    await this.page.waitForTimeout(500);
    
    // 选择"普通客户"(使用 nth(4) 和 force: true 绕过遮罩层)
    await this.page.locator('uni-view').filter({ hasText: /^普通客户$/ }).nth(4).click({ force: true });
  }

  /**
   * 开启赊欠额度开关
   */
  async enableCreditLimit(): Promise<void> {
    await this.creditLimitSwitch.click();
  }

  /**
   * 填写赊欠额度
   * @param amount 赊欠额度金额
   */
  async fillCreditLimit(amount: string): Promise<void> {
    await this.creditLimitInput.click();
    await this.creditLimitInput.fill(amount);
  }

  /**
   * 填写车牌号
   * @param licensePlate 车牌号(如:渝ZY0706)
   */
  async fillLicensePlate(licensePlate: string): Promise<void> {
    // 点击车牌号输入框 - nth-child(11),开启赊欠额度后位置
    const licensePlateInput = this.page.locator('uni-view:nth-child(11) > .nut-cell__value > .nut-form-item__body__slots > .input-wrapper > .flex-input > .nut-input > .nut-input__value > .nut-input__mask');
    
    // 调用基类的通用方法
    await super.fillLicensePlate(licensePlate, licensePlateInput);
  }

  /**
   * 选择省市区
   * @param province 省份(如:山西省)
   * @param city 城市(如:长治市)
   * @param district 区县(如:潞城区)
   */
  async selectRegion(province: string, city: string, district: string): Promise<void> {
    // 点击省市区选择器 - nth-child(12),开启赊欠额度后位置
    await this.page.locator('uni-view:nth-child(12) > .nut-cell__value > .nut-form-item__body__slots > .input-wrapper > .flex-input > .nut-input > .nut-input__value > .nut-input__mask').click();
    
    // 等待弹窗出现
    await this.page.waitForTimeout(500);
    
    // 选择省份
    await this.page.getByText(province).click();
    
    // 选择城市
    await this.page.getByText(city).click();
    
    // 选择区县
    await this.page.getByText(district).click();
    
    // 确认选择
    await this.page.getByText('确认选择').click();
  }

  /**
   * 填写详细地址
   * @param address 详细地址
   */
  async fillDetailedAddress(address: string): Promise<void> {
    // 点击详细地址输入框 - nth-child(13),开启赊欠额度后位置
    await this.page.locator('uni-view:nth-child(13) > .nut-cell__value > .nut-form-item__body__slots > .nut-input > .nut-input__value > .nut-input__input > .uni-input-wrapper > .uni-input-input').click();
    // 填写详细地址
    await this.page.locator('uni-view:nth-child(13) > .nut-cell__value > .nut-form-item__body__slots > .nut-input > .nut-input__value > .nut-input__input > .uni-input-wrapper > .uni-input-input').fill(address);
  }

  /**
   * 上传客户图片
   * @param imagePath 图片文件路径(相对于项目根目录)
   */
  async uploadCustomerImage(imagePath: string): Promise<void> {
    // 调用基类的通用方法
    await super.uploadImage(imagePath);
  }

  /**
   * 创建新客户 - 完整流程
   * @param customerInfo 客户信息
   * @param options 可选配置
   */
  async createCustomer(
    customerInfo: {
      name: string;
      phone: string;
      idCard: string;
      detailedAddress?: string;
    },
    options?: {
      creditLimit?: string;
      licensePlate?: string;
      province?: string;
      city?: string;
      district?: string;
      imagePath?: string;
    }
  ): Promise<void> {
    // 打开客户管理
    await this.openCustomerManagement();
    
    // 点击新增客户
    await this.clickAddCustomer();
    
    // 填写客户名称
    await this.fillCustomerName(customerInfo.name);
    
    // 填写手机号
    await this.fillPhone(customerInfo.phone);
    
    // 填写身份证
    await this.fillIdCard(customerInfo.idCard);
    
    // 选择客户分组(默认第一个)
    await this.selectCustomerGroup();
    
    // 如果有赊欠额度配置
    if (options?.creditLimit) {
      await this.enableCreditLimit();
      await this.fillCreditLimit(options.creditLimit);
    }
    
    // 如果有车牌号配置
    if (options?.licensePlate) {
      await this.fillLicensePlate(options.licensePlate);
    }
    
    // 如果有省市区配置
    if (options?.province && options?.city && options?.district) {
      await this.selectRegion(options.province, options.city, options.district);
    }
    
    // 如果有详细地址
    if (customerInfo.detailedAddress) {
      await this.fillDetailedAddress(customerInfo.detailedAddress);
    }
    
    // 如果有图片上传
    if (options?.imagePath) {
      await this.uploadCustomerImage(options.imagePath);
    }
    
    // 保存客户
    await this.saveButton.click();
    
    // 等待保存完成
    await this.page.waitForLoadState('networkidle', { timeout: 30000 });
  }

  /**
   * 验证客户是否创建成功
   * @param customerName 客户名称
   */
  async verifyCustomerCreated(customerName: string): Promise<boolean> {
    try {
      await this.page.waitForSelector(selectors.customerInList(customerName), { timeout: 10000 });
      return true;
    } catch {
      return false;
    }
  }
}