Login.tsx 4.2 KB
import { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { login } from '@/api/usr'
import { BizError } from '@/api/request'
import { useAppDispatch, useAppSelector } from '@/store'
import { loginSucceeded } from '@/store/auth'
import { IconAntler, IconAvatar, IconLock } from '@/components/icons'
import type { ErrorPayload } from '@/api/types'

export default function Login() {
  const navigate = useNavigate()
  const dispatch = useAppDispatch()
  const existingToken = useAppSelector(s => s.auth.token)
  const [userName, setUserName] = useState('')
  const [password, setPassword] = useState('')
  const [version] = useState<'standard'>('standard')
  const [submitting, setSubmitting] = useState(false)
  const [error, setError] = useState('')

  useEffect(() => {
    if (existingToken) navigate('/', { replace: true })
  }, [existingToken, navigate])

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    if (!userName.trim() || !password) {
      setError('请输入用户名和密码')
      return
    }
    setError('')
    setSubmitting(true)
    try {
      const res = await login({ sUserName: userName.trim(), sPassword: password, sVersion: version })
      dispatch(loginSucceeded({ token: res.accessToken, user: res.user }))
      navigate('/', { replace: true })
    } catch (err) {
      if (err instanceof BizError) {
        if (err.code === 40101) setError('用户名或密码错误')
        else if (err.code === 40301) {
          const payload = err.payload as ErrorPayload | undefined
          const sec = payload?.cooldownSeconds
          setError(`账户已锁定,请 ${sec ? Math.ceil(sec / 60) + ' 分钟' : '稍后'}后重试`)
        } else if (err.code === 40010) setError(err.message || '请求参数无效')
        else setError(err.message || '登录失败')
      } else {
        setError('网络错误,请检查后端服务')
      }
    } finally {
      setSubmitting(false)
    }
  }

  return (
    <div className="login-wrap">
      <div className="login-head">
        <span className="lg" style={{ color: '#0e1216' }}>
          <IconAntler width={42} height={42} />
        </span>
        <span className="name">Antler ERP</span>
        <span className="sub">欢迎登录EBC平台</span>
      </div>
      <form className="login-hero" onSubmit={handleSubmit}>
        <div className="login-text">
          <div className="en">Enterprise Business Capability</div>
          <div className="zh">企业业务能力平台</div>
          <div className="erp">ERP</div>
        </div>
        <div className="login-card">
          <h3>用户登录</h3>
          <div className="lf">
            <span className="ic"><IconAvatar /></span>
            <span className="div"></span>
            <input
              type="text"
              placeholder="请输入你的用户名"
              value={userName}
              onChange={e => setUserName(e.target.value)}
              autoFocus
            />
          </div>
          <div className="lf">
            <span className="ic"><IconLock /></span>
            <span className="div"></span>
            <input
              type="password"
              placeholder="请输入你的密码"
              value={password}
              onChange={e => setPassword(e.target.value)}
            />
          </div>
          <div className="lf dropdown">
            <input type="text" value="标准版" readOnly style={{ cursor: 'pointer' }} />
          </div>
          <div className="err">{error}</div>
          <button className="submit" type="submit" disabled={submitting}>
            {submitting ? '登 录 中…' : '登 录'}
          </button>
        </div>
      </form>
      <div className="login-foot">
        🛠 ©Copyright Antler Software | 印刷智慧工厂 | 印刷MES | 印刷ERP | 印刷电商平台 | 文件智能处理 | 印前自动化 | 400-880-6237
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, marginLeft: 6 }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="#3a6cb6">
            <path d="M12 2l9 4v6c0 5-4 9-9 10-5-1-9-5-9-10V6z" />
          </svg>
          沪ICP备14034791号-1
        </span>
      </div>
    </div>
  )
}