| | |
| | | import { useCallback, useEffect, useState } from 'react'; |
| | | import { useCallback, useEffect, useMemo, useState } from 'react'; |
| | | import { |
| | | App as AntdApp, |
| | | Button, |
| | | Cascader, |
| | | Drawer, |
| | | Form, |
| | | Input, |
| | |
| | | Spin, |
| | | } from 'antd'; |
| | | import { createEmployee, getEmployeeDetail, updateEmployee } from '../server'; |
| | | import type { EmployeeFormValues, EmployeeVO, SelectOption } from '../types'; |
| | | import type { |
| | | EmployeeFormValues, |
| | | EmployeeVO, |
| | | OrgTreeNode, |
| | | SelectOption, |
| | | } from '../types'; |
| | | |
| | | interface OrgCascaderOption { |
| | | value: number; |
| | | label: string; |
| | | children?: OrgCascaderOption[]; |
| | | } |
| | | |
| | | /** 组织树转为级联选择选项,按层级展示。 */ |
| | | const toCascaderOptions = (nodes: OrgTreeNode[]): OrgCascaderOption[] => |
| | | nodes.map((node) => ({ |
| | | value: node.id, |
| | | label: node.orgName, |
| | | children: node.children?.length ? toCascaderOptions(node.children) : undefined, |
| | | })); |
| | | |
| | | /** 在组织树中查找某个组织 ID 的完整路径,用于编辑 / 详情时回填级联值。 */ |
| | | const findOrgPath = (nodes: OrgTreeNode[], targetId: number): number[] | null => { |
| | | for (const node of nodes) { |
| | | if (node.id === targetId) return [node.id]; |
| | | |
| | | const childPath = node.children ? findOrgPath(node.children, targetId) : null; |
| | | if (childPath) return [node.id, ...childPath]; |
| | | } |
| | | |
| | | return null; |
| | | }; |
| | | |
| | | export type UserFormMode = 'create' | 'edit' | 'detail'; |
| | | |
| | |
| | | mode: UserFormMode; |
| | | /** 编辑 / 详情对象;新增时为空。 */ |
| | | record: EmployeeVO | null; |
| | | orgOptions: SelectOption[]; |
| | | /** 组织树,用于所属组织的二级联动选择。 */ |
| | | orgTree: OrgTreeNode[]; |
| | | roleOptions: SelectOption[]; |
| | | onClose: () => void; |
| | | onSuccess: () => void; |
| | | } |
| | | |
| | | const toFormValues = (employee: EmployeeVO): EmployeeFormValues => ({ |
| | | const toFormValues = ( |
| | | employee: EmployeeVO, |
| | | orgTree: OrgTreeNode[], |
| | | ): EmployeeFormValues => ({ |
| | | name: employee.name, |
| | | phone: employee.phone, |
| | | orgId: employee.orgId, |
| | | orgPath: findOrgPath(orgTree, employee.orgId) ?? [], |
| | | roleId: employee.roleId, |
| | | position: employee.position, |
| | | email: employee.email, |
| | |
| | | open, |
| | | mode, |
| | | record, |
| | | orgOptions, |
| | | orgTree, |
| | | roleOptions, |
| | | onClose, |
| | | onSuccess, |
| | |
| | | const [loading, setLoading] = useState(false); |
| | | const { message } = AntdApp.useApp(); |
| | | const isDetail = mode === 'detail'; |
| | | const orgCascaderOptions = useMemo(() => toCascaderOptions(orgTree), [orgTree]); |
| | | |
| | | useEffect(() => { |
| | | if (!open) return; |
| | |
| | | setLoading(true); |
| | | try { |
| | | const data = await getEmployeeDetail({ id: record.id }); |
| | | if (active) form.setFieldsValue(toFormValues(data)); |
| | | if (active) form.setFieldsValue(toFormValues(data, orgTree)); |
| | | } catch { |
| | | // 错误已由 request 统一提示 |
| | | if (active) onClose(); |
| | |
| | | } |
| | | |
| | | if (mode === 'edit' && record) { |
| | | form.setFieldsValue(toFormValues(record)); |
| | | form.setFieldsValue(toFormValues(record, orgTree)); |
| | | } |
| | | }; |
| | | |
| | |
| | | return () => { |
| | | active = false; |
| | | }; |
| | | }, [form, mode, onClose, open, record]); |
| | | }, [form, mode, onClose, open, orgTree, record]); |
| | | |
| | | const handleSubmit = useCallback(async () => { |
| | | if (isDetail) return; |
| | |
| | | } |
| | | |
| | | setSubmitting(true); |
| | | |
| | | const { orgPath, ...rest } = values; |
| | | const orgId = orgPath[orgPath.length - 1]; |
| | | |
| | | try { |
| | | if (mode === 'edit' && record) { |
| | | await updateEmployee({ id: record.id, ...values }); |
| | | await updateEmployee({ id: record.id, ...rest, orgId }); |
| | | message.success('员工信息已更新'); |
| | | } else { |
| | | await createEmployee(values); |
| | | await createEmployee({ ...rest, orgId }); |
| | | message.success('员工创建成功'); |
| | | } |
| | | |
| | |
| | | <Input placeholder="请输入手机号" maxLength={11} disabled={isDetail} /> |
| | | </Form.Item> |
| | | <Form.Item |
| | | name="orgId" |
| | | name="orgPath" |
| | | label="所属组织" |
| | | rules={[{ required: true, message: '请选择所属组织' }]} |
| | | > |
| | | <Select |
| | | <Cascader |
| | | options={orgCascaderOptions} |
| | | changeOnSelect |
| | | showSearch |
| | | optionFilterProp="label" |
| | | options={orgOptions} |
| | | placeholder="请选择所属组织" |
| | | disabled={isDetail} |
| | | style={{ width: '100%' }} |
| | | /> |
| | | </Form.Item> |
| | | <Form.Item |