LoginForm.tsx 2.76 KB
import { useEffect } from 'react';
import { Form, Input, Select, Button, Alert } from 'antd';
import type { LoginReq } from '../../api/auth';
import { COMPANY_OPTIONS } from './loginConstants';

export interface LoginFormFieldErrors {
  username?: string;
  password?: string;
  companyCode?: string;
}

interface Props {
  onSubmit: (req: LoginReq) => Promise<void>;
  loading: boolean;
  errorMessage: string | null;
  fieldErrors: LoginFormFieldErrors;
  /** 锁定状态下 submit 强制 disabled(无视 loading) */
  submitDisabled?: boolean;
}

export default function LoginForm({
  onSubmit,
  loading,
  errorMessage,
  fieldErrors,
  submitDisabled = false,
}: Props) {
  const [form] = Form.useForm<LoginReq>();

  useEffect(() => {
    // 字段级错误同步到 AntD Form 实例
    const errs: Array<{ name: keyof LoginFormFieldErrors; errors: string[] }> = [];
    (['username', 'password', 'companyCode'] as const).forEach((k) => {
      if (fieldErrors[k]) errs.push({ name: k, errors: [fieldErrors[k]!] });
    });
    if (errs.length > 0) {
      form.setFields(errs as any);
    }
  }, [fieldErrors, form]);

  const handleFinish = async (values: LoginReq) => {
    await onSubmit(values);
  };

  return (
    <Form
      form={form}
      layout="vertical"
      onFinish={handleFinish}
      initialValues={{ companyCode: 'HQ' }}
      data-testid="login-form"
    >
      {errorMessage && (
        <Alert
          type="error"
          message={errorMessage}
          showIcon
          style={{ marginBottom: 16 }}
          data-testid="login-error-alert"
        />
      )}

      <Form.Item
        label="用户名"
        name="username"
        rules={[{ required: true, message: '请输入用户名' }]}
      >
        <Input
          placeholder="请输入你的用户名"
          disabled={loading}
          autoComplete="username"
        />
      </Form.Item>

      <Form.Item
        label="密码"
        name="password"
        rules={[{ required: true, message: '请输入密码' }]}
      >
        <Input.Password
          placeholder="请输入你的密码"
          disabled={loading}
          autoComplete="current-password"
        />
      </Form.Item>

      <Form.Item
        label="公司"
        name="companyCode"
        rules={[{ required: true, message: '请选择公司' }]}
      >
        <Select
          options={COMPANY_OPTIONS}
          disabled={loading}
          data-testid="company-select"
        />
      </Form.Item>

      <Form.Item>
        <Button
          type="primary"
          htmlType="submit"
          block
          loading={loading}
          disabled={submitDisabled}
          data-testid="login-submit"
        >
          {loading ? '登录中...' : '登 录'}
        </Button>
      </Form.Item>
    </Form>
  );
}