Complete main UI #37
2
src/ant-design.d.ts
vendored
2
src/ant-design.d.ts
vendored
@@ -3,6 +3,7 @@ import { CustomIconComponentProps } from '@ant-design/icons/es/components/Icon'
|
|||||||
import { TablePaginationConfig } from 'antd/lib'
|
import { TablePaginationConfig } from 'antd/lib'
|
||||||
import { ColumnsType, FilterValue, SorterResult, SortOrder } from 'antd/es/table/interface'
|
import { ColumnsType, FilterValue, SorterResult, SortOrder } from 'antd/es/table/interface'
|
||||||
import { CheckboxChangeEvent } from 'antd/es/checkbox'
|
import { CheckboxChangeEvent } from 'antd/es/checkbox'
|
||||||
|
import type { DataNode } from 'antd/es/tree'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
type IconComponent =
|
type IconComponent =
|
||||||
@@ -16,4 +17,5 @@ declare global {
|
|||||||
type _SorterResult<T> = SorterResult<T>
|
type _SorterResult<T> = SorterResult<T>
|
||||||
type _SortOrder = SortOrder
|
type _SortOrder = SortOrder
|
||||||
type _CheckboxChangeEvent = CheckboxChangeEvent
|
type _CheckboxChangeEvent = CheckboxChangeEvent
|
||||||
|
type _DataNode = DataNode
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ export const URL_API_LOGOUT = '/logout'
|
|||||||
export const URL_API_SYS_LOG = '/system/log'
|
export const URL_API_SYS_LOG = '/system/log'
|
||||||
export const URL_API_USER_INFO = '/system/user/info'
|
export const URL_API_USER_INFO = '/system/user/info'
|
||||||
export const URL_API_USER_LIST = '/system/user'
|
export const URL_API_USER_LIST = '/system/user'
|
||||||
|
export const URL_API_SYS_ROLE = '/system/role'
|
||||||
|
|||||||
31
src/global.d.ts
vendored
31
src/global.d.ts
vendored
@@ -111,6 +111,7 @@ interface MenuVo {
|
|||||||
url: string
|
url: string
|
||||||
powerId: number
|
powerId: number
|
||||||
parentId: number
|
parentId: number
|
||||||
|
moduleId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ElementVo {
|
interface ElementVo {
|
||||||
@@ -161,13 +162,6 @@ interface PageParam {
|
|||||||
sortOrder?: string
|
sortOrder?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetSysLogParams extends PageParam {
|
|
||||||
searchRequestUrl?: string
|
|
||||||
searchRegex?: boolean
|
|
||||||
searchStartTime?: string
|
|
||||||
searchEndTime?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TableParams {
|
interface TableParams {
|
||||||
pagination?: _TablePaginationConfig
|
pagination?: _TablePaginationConfig
|
||||||
sortField?: React.Key | readonly React.Key[]
|
sortField?: React.Key | readonly React.Key[]
|
||||||
@@ -175,6 +169,13 @@ interface TableParams {
|
|||||||
filters?: Record<string, _FilterValue | null>
|
filters?: Record<string, _FilterValue | null>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GetSysLogParams extends PageParam {
|
||||||
|
searchRequestUrl?: string
|
||||||
|
searchRegex?: boolean
|
||||||
|
searchStartTime?: string
|
||||||
|
searchEndTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
interface SysLogGetVo {
|
interface SysLogGetVo {
|
||||||
id: string
|
id: string
|
||||||
logType: string
|
logType: string
|
||||||
@@ -193,3 +194,19 @@ interface SysLogGetVo {
|
|||||||
userAgent: string
|
userAgent: string
|
||||||
operateUsername: string
|
operateUsername: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GetRoleParams extends PageParam {
|
||||||
|
searchName?: string
|
||||||
|
searchRegex?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RoleWithPowerGetVo {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
enable: string
|
||||||
|
modules: ModuleVo[]
|
||||||
|
menus: MenuVo[]
|
||||||
|
elements: ElementVo[]
|
||||||
|
operations: OperationVo[]
|
||||||
|
tree: _DataNode[]
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ import { COLOR_MAIN } from '@/constants/common.constants'
|
|||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<AntdConfigProvider theme={{ token: { colorPrimary: COLOR_MAIN } }} locale={zh_CN}>
|
<AntdConfigProvider
|
||||||
|
theme={{ token: { colorPrimary: COLOR_MAIN, colorBgContainer: 'transparent' } }}
|
||||||
|
locale={zh_CN}
|
||||||
|
>
|
||||||
<App />
|
<App />
|
||||||
</AntdConfigProvider>
|
</AntdConfigProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import FitFullScreen from '@/components/common/FitFullScreen.tsx'
|
import FitFullScreen from '@/components/common/FitFullScreen'
|
||||||
import Card from '@/components/common/Card'
|
import Card from '@/components/common/Card'
|
||||||
import { r_getSysLog } from '@/services/system.tsx'
|
import { r_getSysLog } from '@/services/system'
|
||||||
import {
|
import {
|
||||||
COLOR_ERROR_SECONDARY,
|
COLOR_ERROR_SECONDARY,
|
||||||
COLOR_FONT_SECONDARY,
|
COLOR_FONT_SECONDARY,
|
||||||
DATABASE_SELECT_SUCCESS
|
DATABASE_SELECT_SUCCESS
|
||||||
} from '@/constants/common.constants.ts'
|
} from '@/constants/common.constants'
|
||||||
import HideScrollbar from '@/components/common/HideScrollbar.tsx'
|
import HideScrollbar from '@/components/common/HideScrollbar'
|
||||||
import { getLocalTime } from '@/utils/common.ts'
|
import { getLocalTime } from '@/utils/common'
|
||||||
import FlexBox from '@/components/common/FlexBox'
|
import FlexBox from '@/components/common/FlexBox'
|
||||||
|
|
||||||
const Log: React.FC = () => {
|
const Log: React.FC = () => {
|
||||||
|
|||||||
@@ -1,7 +1,265 @@
|
|||||||
import React from 'react'
|
import React, { useState } from 'react'
|
||||||
|
import FitFullScreen from '@/components/common/FitFullScreen'
|
||||||
|
import HideScrollbar from '@/components/common/HideScrollbar'
|
||||||
|
import FlexBox from '@/components/common/FlexBox'
|
||||||
|
import Card from '@/components/common/Card'
|
||||||
|
import { r_getRole } from '@/services/system.tsx'
|
||||||
|
import { DATABASE_SELECT_SUCCESS } from '@/constants/common.constants.ts'
|
||||||
|
|
||||||
const Role: React.FC = () => {
|
const Role: React.FC = () => {
|
||||||
return <></>
|
const [roleData, setRoleData] = useState<RoleWithPowerGetVo[]>([])
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [tableParams, setTableParams] = useState<TableParams>({
|
||||||
|
pagination: {
|
||||||
|
current: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
position: ['bottomCenter']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const [searchName, setSearchName] = useState('')
|
||||||
|
const [useRegex, setUseRegex] = useState(false)
|
||||||
|
const [isRegexLegal, setIsRegexLegal] = useState(true)
|
||||||
|
|
||||||
|
const dataColumns: _ColumnsType<RoleWithPowerGetVo> = [
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
width: '20%'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '权限',
|
||||||
|
dataIndex: 'tree',
|
||||||
|
render: (value: _DataNode[]) => <AntdTree treeData={value} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'enable',
|
||||||
|
width: '0',
|
||||||
|
align: 'center',
|
||||||
|
render: (value) =>
|
||||||
|
value ? <AntdTag color={'success'}>启用</AntdTag> : <AntdTag>禁用</AntdTag>
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const handleOnTableChange = (
|
||||||
|
pagination: _TablePaginationConfig,
|
||||||
|
filters: Record<string, _FilterValue | null>,
|
||||||
|
sorter: _SorterResult<RoleWithPowerGetVo> | _SorterResult<RoleWithPowerGetVo>[]
|
||||||
|
) => {
|
||||||
|
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) {
|
||||||
|
setRoleData([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnSearchNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setSearchName(e.target.value)
|
||||||
|
|
||||||
|
if (useRegex) {
|
||||||
|
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') {
|
||||||
|
getRole()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnUseRegexChange = (e: _CheckboxChangeEvent) => {
|
||||||
|
setUseRegex(e.target.checked)
|
||||||
|
if (e.target.checked) {
|
||||||
|
try {
|
||||||
|
RegExp(searchName)
|
||||||
|
setIsRegexLegal(!(searchName.includes('{}') || searchName.includes('[]')))
|
||||||
|
} catch (e) {
|
||||||
|
setIsRegexLegal(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsRegexLegal(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOnQueryBtnClick = () => {
|
||||||
|
getRole()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRole = () => {
|
||||||
|
if (loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRegexLegal) {
|
||||||
|
void message.error({
|
||||||
|
content: '非法正则表达式'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true)
|
||||||
|
|
||||||
|
void r_getRole({
|
||||||
|
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: useRegex ? useRegex : undefined,
|
||||||
|
...tableParams.filters
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
const data = res.data
|
||||||
|
if (data.code === DATABASE_SELECT_SUCCESS) {
|
||||||
|
const records = data.data?.records
|
||||||
|
|
||||||
|
records?.map((value) => {
|
||||||
|
const menuMap = new Map<number, _DataNode[]>()
|
||||||
|
const elementMap = new Map<number, _DataNode[]>()
|
||||||
|
const operationMap = new Map<number, _DataNode[]>()
|
||||||
|
|
||||||
|
value.operations.forEach((operation) => {
|
||||||
|
if (
|
||||||
|
operationMap.has(operation.elementId) &&
|
||||||
|
operationMap.get(operation.elementId) !== null
|
||||||
|
) {
|
||||||
|
operationMap
|
||||||
|
.get(operation.elementId)
|
||||||
|
?.push({ title: operation.name, key: operation.powerId })
|
||||||
|
} else {
|
||||||
|
operationMap.set(operation.elementId, [
|
||||||
|
{ title: operation.name, key: operation.powerId }
|
||||||
|
])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
value.elements.forEach((element) => {
|
||||||
|
if (
|
||||||
|
elementMap.has(element.menuId) &&
|
||||||
|
elementMap.get(element.menuId) !== null
|
||||||
|
) {
|
||||||
|
elementMap.get(element.menuId)?.push({
|
||||||
|
title: element.name,
|
||||||
|
key: element.powerId,
|
||||||
|
children: operationMap.get(element.id)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
elementMap.set(element.menuId, [
|
||||||
|
{
|
||||||
|
title: element.name,
|
||||||
|
key: element.powerId,
|
||||||
|
children: operationMap.get(element.id)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
value.menus.forEach((menu) => {
|
||||||
|
if (menuMap.has(menu.moduleId) && menuMap.get(menu.moduleId) !== null) {
|
||||||
|
menuMap.get(menu.moduleId)?.push({
|
||||||
|
title: menu.name,
|
||||||
|
key: menu.powerId,
|
||||||
|
children: elementMap.get(menu.id)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
menuMap.set(menu.moduleId, [
|
||||||
|
{
|
||||||
|
title: menu.name,
|
||||||
|
key: menu.powerId,
|
||||||
|
children: elementMap.get(menu.id)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
value.tree = value.modules.map((module) => ({
|
||||||
|
title: module.name,
|
||||||
|
key: module.powerId,
|
||||||
|
children: menuMap.get(module.id)
|
||||||
|
}))
|
||||||
|
|
||||||
|
return value
|
||||||
|
})
|
||||||
|
|
||||||
|
records && setRoleData(records)
|
||||||
|
data.data &&
|
||||||
|
setTableParams({
|
||||||
|
...tableParams,
|
||||||
|
pagination: {
|
||||||
|
...tableParams.pagination,
|
||||||
|
total: data.data.total
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
void message.error({
|
||||||
|
content: '获取失败,请稍后重试'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getRole()
|
||||||
|
}, [
|
||||||
|
JSON.stringify(tableParams.filters),
|
||||||
|
JSON.stringify(tableParams.sortField),
|
||||||
|
JSON.stringify(tableParams.sortOrder),
|
||||||
|
JSON.stringify(tableParams.pagination?.pageSize),
|
||||||
|
JSON.stringify(tableParams.pagination?.current)
|
||||||
|
])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FitFullScreen>
|
||||||
|
<HideScrollbar
|
||||||
|
style={{ padding: 30 }}
|
||||||
|
isShowVerticalScrollbar
|
||||||
|
autoHideWaitingTime={500}
|
||||||
|
>
|
||||||
|
<FlexBox gap={20}>
|
||||||
|
<FlexBox direction={'horizontal'} gap={10}></FlexBox>
|
||||||
|
<Card>
|
||||||
|
<AntdTable
|
||||||
|
dataSource={roleData}
|
||||||
|
columns={dataColumns}
|
||||||
|
rowKey={(record) => record.id}
|
||||||
|
pagination={tableParams.pagination}
|
||||||
|
loading={loading}
|
||||||
|
onChange={handleOnTableChange}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</FlexBox>
|
||||||
|
</HideScrollbar>
|
||||||
|
</FitFullScreen>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Role
|
export default Role
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import request from '@/services/index'
|
import request from '@/services/index'
|
||||||
import { URL_API_SYS_LOG } from '@/constants/urls.constants'
|
import { URL_API_SYS_LOG, URL_API_SYS_ROLE } from '@/constants/urls.constants'
|
||||||
|
|
||||||
export const r_getSysLog = (param: GetSysLogParams) =>
|
export const r_getSysLog = (param: GetSysLogParams) =>
|
||||||
request.get<PageVo<SysLogGetVo>>(URL_API_SYS_LOG, { ...param })
|
request.get<PageVo<SysLogGetVo>>(URL_API_SYS_LOG, { ...param })
|
||||||
|
|
||||||
|
export const r_getRole = (parm: GetRoleParams) =>
|
||||||
|
request.get<PageVo<RoleWithPowerGetVo>>(URL_API_SYS_ROLE, { ...parm })
|
||||||
|
|||||||
@@ -144,3 +144,16 @@ export const getRedirectUrl = (path: string, redirectUrl: string): string => {
|
|||||||
export const getLocalTime = (utcTime: string, format: string = 'yyyy-MM-DD HH:mm:ssZ') => {
|
export const getLocalTime = (utcTime: string, format: string = 'yyyy-MM-DD HH:mm:ssZ') => {
|
||||||
return moment.utc(utcTime).local().format(format)
|
return moment.utc(utcTime).local().format(format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const floorNumber = (num: number, digits: number) => {
|
||||||
|
if (digits > 0) {
|
||||||
|
return Math.floor(num / Math.pow(10, digits - 1)) * Math.pow(10, digits - 1)
|
||||||
|
} else {
|
||||||
|
const regExpMatchArray = num.toString().match(new RegExp('^\\d\\.\\d{' + -digits + '}'))
|
||||||
|
if (regExpMatchArray !== null) {
|
||||||
|
return parseFloat(regExpMatchArray[0]).toFixed(-digits)
|
||||||
|
} else {
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user