UserDetail.tsx 9.64 KB
import { useEffect, useMemo, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { message } from 'antd'
import { createUser, listUsers, updateUser } from '@/api/usr'
import { BizError } from '@/api/request'
import { useAppDispatch } from '@/store'
import { closeTab } from '@/store/tabs'
import type { UserListItem } from '@/api/types'
import { IconCancel, IconDelete, IconEdit, IconGrid, IconPlus, IconSave } from '@/components/icons'

interface Props {
  mode: 'new' | 'edit'
}

const PERMS = [
  '默认显示(必选)', '禁止查看价格', '客服跟单', '报价组员工', '物控部员工', '供应链PMC', '允许查看订单价格',
  '储运部员工', '外部供应商', '品质部员工', '技术中心员工', '机修组员工', '生产部计划员工', '外发组员工',
  '模烫车间', '装订车间', '后加工车间', '品质部管理', '精品车间', '人事组', '统计组', '机修主管',
  '样品开发部员工', '设计开发', '总经办', '审核组', '结算组', '打样车间', '制版组', '文控组', '行政组',
  '成本组', '采购组', 'OA管理员', '开发组', 'API对接', 'MES管理员', '报表组',
]

const TABS = ['权限组', '客户查看权限', '供应商查看权限', '人员查看权限', '工序查看权限', '司机查看权限']

const USER_TYPES = ['超级管理员', '普通用户']
const LANGS = [{ v: 'zh', t: '中文' }, { v: 'en', t: '英文' }]

interface FormState {
  sUserNo: string
  sUserName: string
  sUserType: string
  sLanguage: string
  bCanModifyDocs: boolean
  perms: Set<number>
  tCreateDate: string
  sCreatedBy: string
  sStaffName: string
}

const empty: FormState = {
  sUserNo: '',
  sUserName: '',
  sUserType: '超级管理员',
  sLanguage: 'zh',
  bCanModifyDocs: false,
  perms: new Set([0]),
  tCreateDate: '',
  sCreatedBy: '',
  sStaffName: '',
}

export default function UserDetail({ mode }: Props) {
  const navigate = useNavigate()
  const dispatch = useAppDispatch()
  const params = useParams()
  const userId = mode === 'edit' ? Number(params.id) : null

  const [form, setForm] = useState<FormState>(empty)
  const [tab, setTab] = useState(0)
  const [submitting, setSubmitting] = useState(false)
  const [editing, setEditing] = useState(mode === 'new')
  const [loaded, setLoaded] = useState(mode === 'new')

  useEffect(() => {
    if (mode !== 'edit' || !userId) return
    let cancelled = false
    ;(async () => {
      try {
        const res = await listUsers({ pageNum: 1, pageSize: 100, queryField: 'username', matchType: 'contains', queryValue: '' })
        if (cancelled) return
        const found = res.list.find((u: UserListItem) => u.iIncrement === userId)
        if (!found) {
          message.warning('用户不存在或已删除')
          return
        }
        setForm({
          sUserNo: found.sUserNo,
          sUserName: found.sUserName,
          sUserType: found.sUserType,
          sLanguage: found.sLanguage,
          bCanModifyDocs: false,
          perms: new Set([0]),
          tCreateDate: found.tCreateDate ?? '',
          sCreatedBy: found.sCreatedBy ?? '',
          sStaffName: found.sStaffName ?? '',
        })
        setLoaded(true)
      } catch (err) {
        const msg = err instanceof BizError ? err.message : '加载用户信息失败'
        message.error(msg)
      }
    })()
    return () => { cancelled = true }
  }, [mode, userId])

  const togglePerm = (i: number) => {
    if (!editing) return
    setForm(f => {
      const next = new Set(f.perms)
      if (next.has(i)) next.delete(i); else next.add(i)
      next.add(0)
      return { ...f, perms: next }
    })
  }

  const handleSave = async () => {
    if (!form.sUserNo.trim() || !form.sUserName.trim()) {
      message.warning('请填写必填字段:用户号、用户名')
      return
    }
    setSubmitting(true)
    try {
      const permIds = [...form.perms].map(i => i + 1)
      if (mode === 'new') {
        await createUser({
          sUserNo: form.sUserNo.trim(),
          sUserName: form.sUserName.trim(),
          sUserType: form.sUserType,
          sLanguage: form.sLanguage,
          bCanModifyDocs: form.bCanModifyDocs,
          permissionCategoryIds: permIds,
        })
        message.success('用户创建成功,初始密码 666666')
        closeAndBack()
      } else if (userId) {
        await updateUser(userId, {
          sUserType: form.sUserType,
          sLanguage: form.sLanguage,
          bCanModifyDocs: form.bCanModifyDocs,
          permissionCategoryIds: permIds,
        })
        message.success('保存成功')
        setEditing(false)
      }
    } catch (err) {
      const msg = err instanceof BizError ? err.message : '保存失败'
      message.error(msg)
    } finally {
      setSubmitting(false)
    }
  }

  const closeAndBack = () => {
    dispatch(closeTab('userdetail'))
    navigate('/users')
  }

  const isNew = mode === 'new'
  const langText = useMemo(
    () => LANGS.find(l => l.v === form.sLanguage)?.t ?? form.sLanguage,
    [form.sLanguage],
  )

  return (
    <div className="userdetail-screen">
      <div className="toolbar">
        <span className={`tb-btn ${editing && !isNew ? 'disabled' : ''}`} onClick={() => !editing && navigate('/users/new')}>
          <IconPlus />新增
        </span>
        <span className={`tb-btn ${editing || isNew ? 'disabled' : ''}`} onClick={() => !isNew && setEditing(true)}>
          <IconEdit />修改
        </span>
        <span className="tb-btn disabled"><IconDelete />删除</span>
        <span className={`tb-btn ${editing && !submitting ? '' : 'disabled'}`} onClick={editing ? handleSave : undefined}>
          <IconSave />保存
        </span>
        <span className={`tb-btn ${editing && !isNew ? '' : 'disabled'}`} onClick={() => editing && !isNew && setEditing(false)}>
          <IconCancel />取消
        </span>
        <span className="tb-btn disabled"><IconGrid />功能</span>
        <span className="tb-btn disabled">作废</span>
        <span className="tb-btn disabled">重置密码</span>
        <span className="tb-btn disabled">取消作废</span>
        <span className="spacer" />
        <span className="gear">⚙</span>
      </div>

      <div className="form-grid">
        <div className="form-cell">
          <span className="lbl">创建时间:</span>
          <div className="field readonly">{isNew ? '' : form.tCreateDate}</div>
        </div>
        <div className="form-cell">
          <span className="lbl">制单人:</span>
          <div className="field readonly">{isNew ? '保存后自动生成' : form.sCreatedBy}</div>
        </div>
        <div className="form-cell">
          <span className="lbl req">员工名:</span>
          <input
            type="text"
            value={form.sStaffName}
            onChange={e => setForm(f => ({ ...f, sStaffName: e.target.value }))}
            disabled={!editing}
            placeholder="(暂不绑定员工档案)"
          />
        </div>

        <div className="form-cell">
          <span className="lbl req">用户名:</span>
          <input
            type="text"
            value={form.sUserName}
            onChange={e => setForm(f => ({ ...f, sUserName: e.target.value }))}
            disabled={!editing || !isNew}
          />
        </div>
        <div className="form-cell">
          <span className="lbl req">类型:</span>
          {editing ? (
            <select className="field" value={form.sUserType} onChange={e => setForm(f => ({ ...f, sUserType: e.target.value }))}>
              {USER_TYPES.map(t => <option key={t} value={t}>{t}</option>)}
            </select>
          ) : (
            <div className="field readonly">{form.sUserType}</div>
          )}
        </div>
        <div className="form-cell">
          <span className="lbl req">语言:</span>
          {editing ? (
            <select className="field" value={form.sLanguage} onChange={e => setForm(f => ({ ...f, sLanguage: e.target.value }))}>
              {LANGS.map(l => <option key={l.v} value={l.v}>{l.t}</option>)}
            </select>
          ) : (
            <div className="field readonly">{langText}</div>
          )}
        </div>

        <div className="form-cell">
          <span className="lbl req">用户号:</span>
          <input
            type="text"
            value={form.sUserNo}
            onChange={e => setForm(f => ({ ...f, sUserNo: e.target.value }))}
            disabled={!editing || !isNew}
          />
        </div>
        <div className="form-cell"></div>
        <div className="form-cell">
          <span className="lbl">单据修改权限:</span>
          <span
            className={`cb ${form.bCanModifyDocs ? 'checked' : ''}`}
            onClick={() => editing && setForm(f => ({ ...f, bCanModifyDocs: !f.bCanModifyDocs }))}
          />
        </div>
      </div>

      <div className="tabs-row">
        {TABS.map((t, i) => (
          <div key={t} className={`tb ${tab === i ? 'active' : ''}`} onClick={() => setTab(i)}>
            {t}
          </div>
        ))}
      </div>

      <div className="perm-list">
        <div className="perm-row head">
          <span className="cb"></span>
          <span>权限分类</span>
          <span className="ic" style={{ marginLeft: 'auto', color: '#aaa' }}>⇅</span>
        </div>
        {tab === 0 ? (
          loaded && PERMS.map((p, i) => (
            <div key={p} className="perm-row" onClick={() => togglePerm(i)}>
              <span className={`cb ${form.perms.has(i) ? 'checked' : ''}`} />
              <span>{p}</span>
            </div>
          ))
        ) : (
          <div style={{ padding: '40px 14px', color: '#888', textAlign: 'center' }}>该 tab 后端暂未实现</div>
        )}
      </div>
    </div>
  )
}