diff --git a/.claude/skills/page-naming/SKILL.md b/.claude/skills/page-naming/SKILL.md new file mode 100644 index 0000000..fe06a62 --- /dev/null +++ b/.claude/skills/page-naming/SKILL.md @@ -0,0 +1,50 @@ +--- +name: shz-admin-page-naming +description: Naming convention for new page directories in shz-admin. Use when creating a new page folder under src/pages/. +--- + +# shz-admin 页面目录命名规范 + +新建页面时,文件夹命名遵循:**首单词首字母大写,其余字母全部小写**。 + +## 规则 + +``` +src/pages/{PageName}/ +``` + +- 第一个单词的首字母 **大写** +- 其余所有字母(包括后续单词)**小写** +- 不允许多个大写字母(驼峰) +- 多个单词直接连写,不用分隔符 + +## 示例 + +``` +✅ Talentcollect ❌ TalentCollect +✅ Mobileusers ❌ MobileUsers +✅ Management ❌ ManagementList +✅ Jobfair ❌ JobFair +✅ Livemgmt ❌ LiveMgmt +✅ Usermgmt ❌ UserMgmt +``` + +## 目录结构 + +新建页面时的标准文件结构: + +``` +src/pages/{PageName}/ +└── List/ + └── index.tsx +``` + +如果页面有弹窗子组件,放在同级的 `components/` 下: + +``` +src/pages/{PageName}/ +├── List/ +│ └── index.tsx +└── components/ + └── SomeModal.tsx +``` diff --git a/src/pages/Talentcollect/List/index.tsx b/src/pages/Talentcollect/List/index.tsx index 9bcc735..10a3ca0 100644 --- a/src/pages/Talentcollect/List/index.tsx +++ b/src/pages/Talentcollect/List/index.tsx @@ -18,8 +18,8 @@ function TalentCollectList() { const [sexEnum, setSexEnum] = useState({}); useEffect(() => { - getDictValueEnum('education', true, true).then((data) => setEducationEnum(data)); - getDictValueEnum('area', true, true).then((data) => setAreaEnum(data)); + getDictValueEnum('education', false, true).then((data) => setEducationEnum(data)); + getDictValueEnum('area', false, true).then((data) => setAreaEnum(data)); getDictValueEnum('sys_user_sex', false).then((data) => setSexEnum(data)); }, []); diff --git a/src/pages/Usermgmt/Appuser/List/index.tsx b/src/pages/Usermgmt/Appuser/List/index.tsx new file mode 100644 index 0000000..61e15fe --- /dev/null +++ b/src/pages/Usermgmt/Appuser/List/index.tsx @@ -0,0 +1,174 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Tag } from 'antd'; +import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components'; +import { getAppUserList } from '@/services/cms/appuser'; +import { getDictValueEnum } from '@/services/system/dict'; +import DictTag from '@/components/DictTag'; + +function AppUserList() { + const actionRef = useRef(); + const [educationEnum, setEducationEnum] = useState>({}); + const [sexEnum, setSexEnum] = useState>({}); + const [areaEnum, setAreaEnum] = useState>({}); + const [politicalEnum, setPoliticalEnum] = useState>({}); + + 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); + }, []); + + 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, + hideInSearch: true, + }, + { + title: '学历', + dataIndex: 'education', + valueType: 'select', + align: 'center', + width: 90, + valueEnum: educationEnum, + render: (_, record) => , + }, + { + 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: '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, + }, + ]; + + 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, + }).then((res) => ({ + data: res.rows || [], + total: res.total, + success: true, + })); + }} + search={{ labelWidth: 'auto' }} + scroll={{ x: 'max-content' }} + pagination={{ defaultPageSize: 10, showSizeChanger: true }} + headerTitle="个人用户管理" + /> +
+ ); +} + +export default AppUserList; diff --git a/src/services/cms/appuser.ts b/src/services/cms/appuser.ts new file mode 100644 index 0000000..4d20bf6 --- /dev/null +++ b/src/services/cms/appuser.ts @@ -0,0 +1,17 @@ +import { request } from '@umijs/max'; + +/** + * 分页查询个人用户管理列表 + * GET /cms/appUser/list + */ +export async function getAppUserList( + params?: API.CmsAppUser.ListParams & { + pageNum?: number; + pageSize?: number; + }, +) { + return request('/api/cms/appUser/list', { + method: 'GET', + params, + }); +} diff --git a/src/types/cms/appuser.d.ts b/src/types/cms/appuser.d.ts new file mode 100644 index 0000000..7b9fa3c --- /dev/null +++ b/src/types/cms/appuser.d.ts @@ -0,0 +1,68 @@ +declare namespace API.CmsAppUser { + export interface AppUserResult { + total: number; + rows: AppUserRow[]; + code: number; + msg: string; + data?: any; + } + + export interface AppUserRow { + createTime: string | null; + updateTime: string | null; + userId: number; + name: string | null; + age: string | null; + sex: string; + birthDate: string | null; + education: string | null; + politicalAffiliation: string | null; + phone: string; + avatar: string; + salaryMin: string | null; + salaryMax: string | null; + area: string | null; + status: string; + loginIp: string; + loginDate: string | null; + jobTitleId: string | null; + experience: string | null; + isRecommend: number; + email: string | null; + jobTitle: string | null; + jobName: string | null; + idCard: string | null; + isCompanyUser: string; + password: string | null; + openid: string | null; + unionid: string | null; + nation: string | null; + workExperience: string | null; + company: string | null; + experiencesList: any; + appSkillsList: any; + fileList: any; + myChart: any; + ytjPassword: string | null; + address: string | null; + domicileAddress: string | null; + lcUserid: string | null; + userType: string | null; + resumeStatus: string | null; + matchLevelDesc: string | null; + applyId: string | null; + } + + export interface ListParams { + pageNum?: number; + pageSize?: number; + name?: string; + phone?: string; + sex?: string; + education?: string; + area?: string; + status?: string; + politicalAffiliation?: string; + idCard?: string; + } +}