import React, { useEffect, useRef, useState } from 'react'; import { Tag, Button, Switch, Modal, Form, Input, message } from 'antd'; import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components'; import { useNavigate } from '@umijs/max'; import { FileTextOutlined } from '@ant-design/icons'; import { getAppUserList, updateIdCard, changeResumeStatus, resetPassword, } from '@/services/cms/appuser'; import { getDictValueEnum } from '@/services/system/dict'; import DictTag from '@/components/DictTag'; /** 身份证校验规则(18位) */ const ID_CARD_REGEX = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; function AppUserList() { const actionRef = useRef(); const navigate = useNavigate(); const [educationEnum, setEducationEnum] = useState>({}); const [sexEnum, setSexEnum] = useState>({}); const [areaEnum, setAreaEnum] = useState>({}); const [politicalEnum, setPoliticalEnum] = useState>({}); const [nationEnum, setNationEnum] = useState>({}); const [userTypeEnum, setUserTypeEnum] = useState>({}); const [workExperienceEnum, setWorkExperienceEnum] = useState>({}); /** 修改身份证 Modal 状态 */ const [idCardModalOpen, setIdCardModalOpen] = useState(false); const [idCardRecord, setIdCardRecord] = useState(null); const [idCardForm] = Form.useForm(); /** 修改密码 Modal 状态 */ const [passwordModalOpen, setPasswordModalOpen] = useState(false); const [passwordRecord, setPasswordRecord] = useState(null); const [passwordForm] = Form.useForm(); useEffect(() => { getDictValueEnum('education', true, true).then(setEducationEnum); getDictValueEnum('sys_user_sex', true).then(setSexEnum); getDictValueEnum('area', true, true).then(setAreaEnum); getDictValueEnum('political_affiliation', true, true).then(setPoliticalEnum); getDictValueEnum('nation', false, true).then(setNationEnum); getDictValueEnum('user_type', false, true).then(setUserTypeEnum); getDictValueEnum('experience', false, true).then(setWorkExperienceEnum); }, []); const columns: ProColumns[] = [ { title: '用户ID', dataIndex: 'userId', valueType: 'text', align: 'center', width: 80, hideInSearch: true, }, { title: '姓名', dataIndex: 'name', valueType: 'text', align: 'center', width: 120, }, { title: '手机号', dataIndex: 'phone', valueType: 'text', align: 'center', width: 140, }, { title: '性别', dataIndex: 'sex', valueType: 'select', align: 'center', width: 80, valueEnum: sexEnum, render: (_, record) => , }, { title: '年龄', dataIndex: 'age', valueType: 'text', align: 'center', width: 70, }, { title: '出生年月', dataIndex: 'birthDate', valueType: 'date', align: 'center', width: 120, fieldProps: { format: 'YYYY-MM-DD' }, }, { title: '学历', dataIndex: 'education', valueType: 'select', align: 'center', width: 90, valueEnum: educationEnum, render: (_, record) => , }, { title: '毕业院校', dataIndex: 'schoolName', valueType: 'text', align: 'center', width: 160, }, { title: '毕业时间', dataIndex: 'endTime', valueType: 'date', align: 'center', width: 120, fieldProps: { format: 'YYYY-MM-DD' }, }, { title: '地区', dataIndex: 'area', valueType: 'select', align: 'center', width: 100, valueEnum: areaEnum, render: (_, record) => , }, { title: '政治面貌', dataIndex: 'politicalAffiliation', valueType: 'select', align: 'center', width: 110, valueEnum: politicalEnum, render: (_, record) => , }, { title: '民族', dataIndex: 'nation', valueType: 'select', align: 'center', width: 90, valueEnum: nationEnum, render: (_, record) => , }, { title: '个人标签', dataIndex: 'userType', valueType: 'select', align: 'center', width: 110, valueEnum: userTypeEnum, render: (_, record) => , }, { title: '工作经验', dataIndex: 'workExperience', valueType: 'select', align: 'center', width: 110, valueEnum: workExperienceEnum, render: (_, record) => , }, { title: '期望薪资', dataIndex: 'salaryRange', hideInSearch: true, align: 'center', width: 140, render: (_, record) => { if (!record.salaryMin && !record.salaryMax) return '-'; return `${record.salaryMin ?? '-'} ~ ${record.salaryMax ?? '-'}`; }, }, { title: '身份证号', dataIndex: 'idCard', valueType: 'text', align: 'center', width: 170, render: (_, record) => { if (!record.idCard) return '-'; const idCard = record.idCard.toString(); if (idCard.length < 8) return idCard; return `${idCard.slice(0, 4)}${'*'.repeat(idCard.length - 8)}${idCard.slice(-4)}`; }, }, { title: '最后登录', dataIndex: 'loginDate', valueType: 'date', align: 'center', width: 110, hideInSearch: true, fieldProps: { format: 'YYYY-MM-DD' }, }, { title: '创建时间', dataIndex: 'createTime', valueType: 'dateTime', align: 'center', hideInSearch: true, width: 160, }, { title: '更新时间', dataIndex: 'updateTime', valueType: 'dateTime', align: 'center', hideInSearch: true, width: 160, }, { title: '简历状态', dataIndex: 'resumeStatus', align: 'center', width: 90, fixed: 'right', hideInSearch: true, render: (_, record) => ( { try { const newStatus = checked ? '1' : '2'; await changeResumeStatus({ userId: record.userId, resumeStatus: newStatus, }); message.success(checked ? '简历已设置成公开!' : '简历已设置成保密!'); actionRef.current?.reload(); } catch { message.error('操作失败'); } }} /> ), }, { title: '操作', valueType: 'option', align: 'center', width: 240, fixed: 'right', hideInSearch: true, render: (_, record) => [ , , , ], }, ]; return (
actionRef={actionRef} rowKey="userId" columns={columns} request={(params) => { const { current, pageSize, ...searchParams } = params; const filteredParams: Record = {}; Object.keys(searchParams).forEach((key) => { const val = searchParams[key]; if (val !== undefined && val !== null && val !== '') { filteredParams[key] = val; } }); return getAppUserList({ pageNum: current, pageSize, ...filteredParams, orderByColumn: 'createTime', isAsc: 'desc', }).then((res) => ({ data: res.rows || [], total: res.total, success: true, })); }} search={{ labelWidth: 'auto', defaultCollapsed: false }} scroll={{ x: 'max-content' }} pagination={{ defaultPageSize: 10, showSizeChanger: true }} headerTitle="个人用户管理" /> {/* 修改身份证 Modal */} setIdCardModalOpen(false)} onOk={() => idCardForm.submit()} destroyOnHidden >
{ try { await updateIdCard({ userId: idCardRecord!.userId, idCard: values.idCard, }); setIdCardModalOpen(false); actionRef.current?.reload(); } catch { message.error('修改失败'); } }} > {idCardRecord?.name || '-'}
{/* 修改密码 Modal */} setPasswordModalOpen(false)} onOk={() => passwordForm.submit()} destroyOnHidden >
{ try { await resetPassword({ userId: passwordRecord!.userId, password: values.password, }); message.success('密码修改成功'); setPasswordModalOpen(false); } catch { message.error('密码修改失败'); } }} > {passwordRecord?.name || '-'} { if (!value) return Promise.resolve(); const hasUpper = /[A-Z]/.test(value); const hasLower = /[a-z]/.test(value); const hasDigit = /\d/.test(value); const specialChars = value.replace(/[a-zA-Z0-9]/g, ''); const hasTwoSpecial = specialChars.length >= 2; if (!hasUpper) return Promise.reject(new Error('密码需包含大写字母')); if (!hasLower) return Promise.reject(new Error('密码需包含小写字母')); if (!hasDigit) return Promise.reject(new Error('密码需包含数字')); if (!hasTwoSpecial) return Promise.reject(new Error('密码需包含至少2个特殊字符')); return Promise.resolve(); }, }, ]} > ({ validator(_, value) { if (!value || getFieldValue('password') === value) { return Promise.resolve(); } return Promise.reject(new Error('两次输入的密码不一致')); }, }), ]} >
); } export default AppUserList;