// REQ-USR-001 / REQ-USR-002: 用户单据页面容器(判 mode、装配 4 子组件、提交反馈与导航回流) import { useEffect } from 'react'; import { Form, Spin, Button, Modal, App as AntdApp } from 'antd'; import { useNavigate, useParams, useLocation } from 'react-router-dom'; import type { UserVO } from '../../../api/types'; import UserDetailToolbar from './UserDetailToolbar'; import UserBasicForm from './UserBasicForm'; import PermissionTabs from './PermissionTabs'; import PermissionGroupList from './PermissionGroupList'; import { useUserDetail } from './useUserDetail'; import { MODE_CREATE, MODE_EDIT, MSG_CREATE_SUCCESS, MSG_EDIT_SUCCESS, MSG_ERR_USER_NOT_FOUND, MSG_LOAD_DETAIL_FAIL, MSG_CANCEL_CONFIRM, PATH_USER_LIST, PATH_USER_NEW, TEXT_BACK_TO_LIST, TEXT_RETRY, type UserFormValues, } from './constants'; import styles from './UserDetail.module.css'; /** Checkbox 受控值为 boolean,提交映射需 0/1(BR8) */ function normalizeFormValues(raw: UserFormValues): UserFormValues { return { ...raw, iCanModifyBill: (raw.iCanModifyBill ? 1 : 0) as 0 | 1, }; } export default function UserDetailPage() { const navigate = useNavigate(); const params = useParams<{ id?: string }>(); const location = useLocation(); const { message } = AntdApp.useApp(); const [form] = Form.useForm(); const mode = params.id ? MODE_EDIT : MODE_CREATE; const userId = params.id ? Number(params.id) : undefined; const presetUser = (location.state as { user?: UserVO } | null)?.user ?? null; const detail = useUserDetail({ mode, userId, presetUser }); const { formValues, employees, permissions, checkedPermissionIds, readonlyCreator, readonlyCreateTime, loading, submitting, loadFailed, notFound, selectEmployee, togglePermission, toggleAll, submit, reload, } = detail; // hook 持有的受控值回写到 AntD Form(create 默认 / edit 回填,BR1/BR2/BR6/BR17) useEffect(() => { form.setFieldsValue({ ...formValues, iCanModifyBill: (formValues.iCanModifyBill ? 1 : 0) as 0 | 1, }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [formValues]); const handleSave = async () => { try { const values = await form.validateFields(); const ret = await submit(normalizeFormValues({ ...formValues, ...values })); if (ret.ok) { message.success(mode === MODE_CREATE ? MSG_CREATE_SUCCESS : MSG_EDIT_SUCCESS); navigate(PATH_USER_LIST); } else if (ret.fieldError) { form.setFields([ { name: ret.fieldError.field, errors: [ret.fieldError.message] }, ]); } } catch { // validateFields 失败:就近字段已展示错误,不发请求(BR12) } }; const handleCancel = () => { if (form.isFieldsTouched()) { Modal.confirm({ title: MSG_CANCEL_CONFIRM, onOk: () => navigate(PATH_USER_LIST), }); } else { navigate(PATH_USER_LIST); } }; const handleNew = () => { navigate(PATH_USER_NEW); }; const handleSelectEmployee = (value: number | null) => { selectEmployee(value); }; // edit 详情不存在(40401):返回列表入口(spec § 4) if (notFound) { return (
{MSG_ERR_USER_NOT_FOUND}
); } // 预取/详情取数失败:重试入口(spec § 4 loadError) if (loadFailed) { return (
{MSG_LOAD_DETAIL_FAIL}
); } return (
void handleSave()} onCancel={handleCancel} onNew={handleNew} />
); }