UserBasicForm.tsx 4.19 KB
// REQ-USR-001 / REQ-USR-002: 用户单据表单网格(3 列布局,8 字段 + 员工联动 + 前置校验,BR1-BR9)
import { Form, Input, Select, Checkbox, type FormInstance } from 'antd';
import type { EmployeeOption } from '../../../api/types';
import {
  USER_TYPE_OPTIONS,
  LANGUAGE_OPTIONS,
  USERNAME_PATTERN,
  LABEL_CREATE_TIME,
  LABEL_CREATOR,
  LABEL_EMPLOYEE,
  LABEL_USERNAME,
  LABEL_USER_TYPE,
  LABEL_LANGUAGE,
  LABEL_USER_NO,
  LABEL_CAN_MODIFY_BILL,
  TEXT_CREATOR_PLACEHOLDER,
  MSG_USERNAME_FORMAT,
  MSG_USERNAME_REQUIRED,
  MSG_USERNO_REQUIRED,
  MSG_USERTYPE_REQUIRED,
  MSG_LANGUAGE_REQUIRED,
  type UserFormValues,
} from './constants';
import styles from './UserDetail.module.css';

export interface UserBasicFormProps {
  form: FormInstance<UserFormValues>;
  mode: 'create' | 'edit';
  employees: EmployeeOption[];
  readonlyCreateTime?: string;
  readonlyCreator?: string;
  onSelectEmployee(value: number | null): void;
}

const toEnumOptions = (arr: readonly string[]) => arr.map((v) => ({ value: v, label: v }));

export default function UserBasicForm({
  form,
  mode,
  employees,
  readonlyCreateTime,
  readonlyCreator,
  onSelectEmployee,
}: UserBasicFormProps) {
  void form; // 表单由父级 Form 实例驱动(受控 initialValues / validate / submit)

  const creatorText =
    mode === 'edit' ? readonlyCreator || '' : TEXT_CREATOR_PLACEHOLDER;
  const createTimeText = mode === 'edit' ? readonlyCreateTime || '' : '';

  return (
    <div className={styles.formGrid}>
      {/* 创建时间(只读,BR1) */}
      <Form.Item label={LABEL_CREATE_TIME}>
        <div className={styles.readonlyField} data-testid="field-createtime">
          {createTimeText}
        </div>
      </Form.Item>

      {/* 制单人(只读,BR2) */}
      <Form.Item label={LABEL_CREATOR}>
        <div className={styles.readonlyField} data-testid="field-creator">
          {creatorText}
        </div>
      </Form.Item>

      {/* 员工名(Select,选中联动带出用户名/用户号,BR5) */}
      <Form.Item label={LABEL_EMPLOYEE} name="iEmployeeId">
        <Select
          allowClear
          placeholder="请选择员工"
          options={employees.map((e) => ({ value: e.value, label: e.label }))}
          onChange={(v) => onSelectEmployee((v as number | undefined) ?? null)}
          virtual={false}
          data-testid="select-employee"
        />
      </Form.Item>

      {/* 用户名(create 可编辑必填 + 格式校验;edit 只读,BR3) */}
      <Form.Item
        label={LABEL_USERNAME}
        name="sUserName"
        rules={
          mode === 'create'
            ? [
                { required: true, message: MSG_USERNAME_REQUIRED },
                { pattern: USERNAME_PATTERN, message: MSG_USERNAME_FORMAT },
              ]
            : []
        }
      >
        <Input disabled={mode === 'edit'} data-testid="field-username" />
      </Form.Item>

      {/* 类型(Select 枚举,create 默认普通用户,BR6) */}
      <Form.Item
        label={LABEL_USER_TYPE}
        name="sUserType"
        rules={[{ required: true, message: MSG_USERTYPE_REQUIRED }]}
      >
        <Select
          options={toEnumOptions(USER_TYPE_OPTIONS)}
          virtual={false}
          data-testid="select-usertype"
        />
      </Form.Item>

      {/* 语言(Select 枚举,必填,BR7) */}
      <Form.Item
        label={LABEL_LANGUAGE}
        name="sLanguage"
        rules={[{ required: true, message: MSG_LANGUAGE_REQUIRED }]}
      >
        <Select
          options={toEnumOptions(LANGUAGE_OPTIONS)}
          placeholder="请选择语言"
          virtual={false}
          data-testid="select-language"
        />
      </Form.Item>

      {/* 用户号(必填,BR4,可由员工名联动带出,BR5) */}
      <Form.Item
        label={LABEL_USER_NO}
        name="sUserNo"
        rules={[{ required: true, message: MSG_USERNO_REQUIRED }]}
      >
        <Input data-testid="field-userno" />
      </Form.Item>

      {/* 单据修改权限(Checkbox,默认否,BR8) */}
      <Form.Item label={LABEL_CAN_MODIFY_BILL} name="iCanModifyBill" valuePropName="checked">
        <Checkbox data-testid="field-canmodify" />
      </Form.Item>
    </div>
  );
}