import React from 'react' import Icon from '@ant-design/icons' import { COLOR_ERROR_SECONDARY, COLOR_FONT_SECONDARY, COLOR_PRODUCTION, DATABASE_DELETE_SUCCESS, DATABASE_DUPLICATE_KEY, DATABASE_INSERT_SUCCESS, DATABASE_SELECT_SUCCESS, DATABASE_UPDATE_SUCCESS } from '@/constants/common.constants' import { useUpdatedEffect } from '@/util/hooks' import { hasPermission } from '@/util/auth' import { utcToLocalTime } from '@/util/datetime' import { r_sys_group_add, r_sys_group_change_status, r_sys_group_delete, r_sys_group_delete_list, r_sys_group_get, r_sys_group_update, r_sys_role_get_list } from '@/services/system' import Permission from '@/components/common/Permission' import FitFullScreen from '@/components/common/FitFullScreen' import HideScrollbar from '@/components/common/HideScrollbar' import FlexBox from '@/components/common/FlexBox' import Card from '@/components/common/Card' const Group: React.FC = () => { const [modal, contextHolder] = AntdModal.useModal() const [form] = AntdForm.useForm() const formValues = AntdForm.useWatch([], form) const [newFormValues, setNewFormValues] = useState() const [groupData, setGroupData] = useState([]) const [isLoading, setIsLoading] = useState(false) const [tableParams, setTableParams] = useState({ pagination: { current: 1, pageSize: 20, position: ['bottomCenter'], showTotal: (total, range) => `第 ${ range[0] === range[1] ? `${range[0]}` : `${range[0]}~${range[1]}` } 项 共 ${total} 项` } }) const [searchName, setSearchName] = useState('') const [isUseRegex, setIsUseRegex] = useState(false) const [isRegexLegal, setIsRegexLegal] = useState(true) const [isDrawerOpen, setIsDrawerOpen] = useState(false) const [isDrawerEdit, setIsDrawerEdit] = useState(false) const [submittable, setSubmittable] = useState(false) const [roleData, setRoleData] = useState([]) const [isLoadingRole, setIsLoadingRole] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false) const [tableSelectedItem, setTableSelectedItem] = useState([]) const dataColumns: _ColumnsType = [ { title: '名称', dataIndex: 'name', width: '15%' }, { title: '角色', dataIndex: 'roles', render: (value: RoleVo[]) => value.length ? ( value.map((role) => ( {role.name} )) ) : ( ) }, { title: '创建时间', dataIndex: 'createTime', width: '10%', align: 'center', render: (value: string) => utcToLocalTime(value) }, { title: '修改时间', dataIndex: 'updateTime', width: '10%', align: 'center', render: (value: string) => utcToLocalTime(value) }, { title: '状态', dataIndex: 'enable', width: '5%', align: 'center', render: (value) => value ? 启用 : 禁用 }, { title: '操作', dataIndex: 'enable', width: '15em', align: 'center', render: (value, record) => ( <> {value ? ( 禁用 ) : ( 启用 )} 编辑 删除 ) } ] const handleOnTableChange = ( pagination: _TablePaginationConfig, filters: Record, sorter: _SorterResult | _SorterResult[] ) => { pagination = { ...tableParams.pagination, ...pagination } if (Array.isArray(sorter)) { setTableParams({ pagination, filters, sortField: sorter.map((value) => value.field).join(',') }) } else { setTableParams({ pagination, filters, sortField: sorter.field, sortOrder: sorter.order }) } if (pagination.pageSize !== tableParams.pagination?.pageSize) { setGroupData([]) } } const handleOnTableSelectChange = (selectedRowKeys: React.Key[]) => { setTableSelectedItem(selectedRowKeys) } const handleOnAddBtnClick = () => { setIsDrawerEdit(false) setIsDrawerOpen(true) form.setFieldValue('id', undefined) form.setFieldValue('name', newFormValues?.name) form.setFieldValue('roleIds', newFormValues?.roleIds) form.setFieldValue('enable', newFormValues?.enable ?? true) if (!roleData || !roleData.length) { getRoleData() } } const handleOnListDeleteBtnClick = () => { modal .confirm({ title: '确定删除', content: `确定删除选中的 ${tableSelectedItem.length} 个用户组吗?` }) .then( (confirmed) => { if (confirmed) { setIsLoading(true) void r_sys_group_delete_list(tableSelectedItem) .then((res) => { const data = res.data if (data.code === DATABASE_DELETE_SUCCESS) { void message.success('删除成功') setTimeout(() => { getGroup() }) } else { void message.error('删除失败,请稍后重试') } }) .finally(() => { setIsLoading(false) }) } }, () => {} ) } const handleOnEditBtnClick = (value: GroupWithRoleGetVo) => { return () => { setIsDrawerEdit(true) setIsDrawerOpen(true) form.setFieldValue('id', value.id) form.setFieldValue('name', value.name) form.setFieldValue( 'roleIds', value.roles.map((role) => role.id) ) form.setFieldValue('enable', value.enable) if (!roleData || !roleData.length) { getRoleData() } void form.validateFields() } } const handleOnDeleteBtnClick = (value: GroupWithRoleGetVo) => { return () => { modal .confirm({ title: '确定删除', content: `确定删除角色 ${value.name} 吗?` }) .then( (confirmed) => { if (confirmed) { setIsLoading(true) void r_sys_group_delete(value.id) .then((res) => { const data = res.data if (data.code === DATABASE_DELETE_SUCCESS) { void message.success('删除成功') setTimeout(() => { getGroup() }) } else { void message.error('删除失败,请稍后重试') } }) .finally(() => { setIsLoading(false) }) } }, () => {} ) } } const handleOnDrawerClose = () => { setIsDrawerOpen(false) } const filterOption = (input: string, option?: { label: string; value: string }) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase()) const handleOnSubmit = () => { if (isSubmitting) { return } setIsSubmitting(true) if (isDrawerEdit) { void r_sys_group_update(formValues) .then((res) => { const data = res.data switch (data.code) { case DATABASE_UPDATE_SUCCESS: setIsDrawerOpen(false) void message.success('更新成功') getGroup() break case DATABASE_DUPLICATE_KEY: void message.error('已存在相同名称的角色') break default: void message.error('更新失败,请稍后重试') } }) .finally(() => { setIsSubmitting(false) }) } else { void r_sys_group_add(formValues) .then((res) => { const data = res.data switch (data.code) { case DATABASE_INSERT_SUCCESS: setIsDrawerOpen(false) void message.success('添加成功') setNewFormValues(undefined) getGroup() break case DATABASE_DUPLICATE_KEY: void message.error('已存在相同名称的角色') break default: void message.error('添加失败,请稍后重试') } }) .finally(() => { setIsSubmitting(false) }) } } const handleOnSearchNameChange = (e: React.ChangeEvent) => { setSearchName(e.target.value) if (isUseRegex) { try { RegExp(e.target.value) setIsRegexLegal(!(e.target.value.includes('{}') || e.target.value.includes('[]'))) } catch (e) { setIsRegexLegal(false) } } else { setIsRegexLegal(true) } } const handleOnSearchNameKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { getGroup() } } const handleOnUseRegexChange = (e: _CheckboxChangeEvent) => { setIsUseRegex(e.target.checked) if (e.target.checked) { try { RegExp(searchName) setIsRegexLegal(!(searchName.includes('{}') || searchName.includes('[]'))) } catch (e) { setIsRegexLegal(false) } } else { setIsRegexLegal(true) } } const handleOnQueryBtnClick = () => { getGroup() } const handleOnChangStatusBtnClick = (id: string, newStatus: boolean) => { return () => { if (isLoading) { return } setIsLoading(true) void r_sys_group_change_status({ id, enable: newStatus }) .then((res) => { const data = res.data if (data.code === DATABASE_UPDATE_SUCCESS) { void message.success('更新成功') setTimeout(() => { getGroup() }) } else { void message.error('更新失败,请稍后重试') } }) .finally(() => { setIsLoading(false) }) } } const getGroup = () => { if (isLoading) { return } if (!isRegexLegal) { void message.error('非法正则表达式') return } setIsLoading(true) void r_sys_group_get({ currentPage: tableParams.pagination?.current, pageSize: tableParams.pagination?.pageSize, sortField: tableParams.sortField && tableParams.sortOrder ? (tableParams.sortField as string) : undefined, sortOrder: tableParams.sortField && tableParams.sortOrder ? tableParams.sortOrder : undefined, searchName: searchName.trim().length ? searchName : undefined, searchRegex: isUseRegex ? isUseRegex : undefined, ...tableParams.filters }) .then((res) => { const data = res.data if (data.code === DATABASE_SELECT_SUCCESS) { const records = data.data?.records records && setGroupData(records) data.data && setTableParams({ ...tableParams, pagination: { ...tableParams.pagination, total: data.data.total } }) } else { void message.error('获取失败,请稍后重试') } }) .finally(() => { setIsLoading(false) }) } const getRoleData = () => { if (isLoadingRole) { return } setIsLoadingRole(true) void r_sys_role_get_list() .then((res) => { const data = res.data if (data.code === DATABASE_SELECT_SUCCESS) { data.data && setRoleData(data.data) } else { void message.error('获取角色列表失败,请稍后重试') } }) .finally(() => { setIsLoadingRole(false) }) } useEffect(() => { form.validateFields({ validateOnly: true }).then( () => { setSubmittable(true) }, () => { setSubmittable(false) } ) if (!isDrawerEdit && formValues) { setNewFormValues({ name: formValues.name, roleIds: formValues.roleIds, enable: formValues.enable }) } }, [formValues]) useUpdatedEffect(() => { getGroup() }, [ JSON.stringify(tableParams.filters), JSON.stringify(tableParams.sortField), JSON.stringify(tableParams.sortOrder), JSON.stringify(tableParams.pagination?.pageSize), JSON.stringify(tableParams.pagination?.current) ]) const toolbar = ( 名称 } suffix={ <> {!isRegexLegal ? ( 非法表达式 ) : undefined} .* } allowClear value={searchName} onChange={handleOnSearchNameChange} onKeyDown={handleOnSearchNameKeyDown} status={isRegexLegal ? undefined : 'error'} /> 查询 ) const table = ( record.id} pagination={tableParams.pagination} loading={isLoading} onChange={handleOnTableChange} rowSelection={ hasPermission('system:group:delete:multiple') ? { type: 'checkbox', onChange: handleOnTableSelectChange } : undefined } /> ) const drawerToolbar = ( 取消 提交 ) const addAndEditForm = ( ({ value: value.id, label: `${value.name}${!value.enable ? '(已禁用)' : ''}` }))} /> ) return ( <> {toolbar} {table} {addAndEditForm} {contextHolder} ) } export default Group