12 changed files with 337 additions and 124 deletions
			
			
		- 
					95src/locales/lang/en-US.ts
 - 
					3src/locales/lang/pages/system/menus/en-US.ts
 - 
					24src/locales/lang/pages/system/menus/zh-CN.ts
 - 
					94src/locales/lang/zh-CN.ts
 - 
					45src/pages/system/menus/index.tsx
 - 
					13src/pages/system/menus/store.ts
 - 
					102src/pages/system/roles/index.tsx
 - 
					25src/pages/system/roles/store.ts
 - 
					22src/pages/system/roles/style.ts
 - 
					4src/service/base.ts
 - 
					32src/service/system.ts
 - 
					2vite.config.ts
 
@ -1,50 +1,63 @@ | 
			
		|||||
import antdEN from 'antd/locale/en_US' | 
				import antdEN from 'antd/locale/en_US' | 
			
		||||
 | 
				import menus from './pages/system/menus/en-US' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				
 | 
			
		||||
export default { | 
				export default { | 
			
		||||
  ...antdEN, | 
				 | 
			
		||||
 | 
				    ...antdEN, | 
			
		||||
 | 
				
 | 
			
		||||
  error: { | 
				 | 
			
		||||
    '404': { | 
				 | 
			
		||||
      title: 'not fund', | 
				 | 
			
		||||
      message: 'Sorry, not found this page.' | 
				 | 
			
		||||
 | 
				    error: { | 
			
		||||
 | 
				        '404': { | 
			
		||||
 | 
				            title: 'not fund', | 
			
		||||
 | 
				            message: 'Sorry, not found this page.' | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				        '403': { | 
			
		||||
 | 
				            title: 'not authorized', | 
			
		||||
 | 
				            message: 'Sorry, you are not authorized to access this page.' | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				        'error': { | 
			
		||||
 | 
				            title: 'error info', | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				    route: { | 
			
		||||
 | 
				        goBack: 'Go Back', | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				    app: { | 
			
		||||
 | 
				        header: { | 
			
		||||
 | 
				            logout: 'logout', | 
			
		||||
 | 
				        } | 
			
		||||
    }, | 
				    }, | 
			
		||||
    '403': { | 
				 | 
			
		||||
      title: 'not authorized', | 
				 | 
			
		||||
      message: 'Sorry, you are not authorized to access this page.' | 
				 | 
			
		||||
 | 
				    login: { | 
			
		||||
 | 
				        title: 'Account Password Login', | 
			
		||||
 | 
				        username: 'Username', | 
			
		||||
 | 
				        usernameMsg: 'Please enter your username', | 
			
		||||
 | 
				        password: 'Password', | 
			
		||||
 | 
				        passwordMsg: 'Please enter your password', | 
			
		||||
 | 
				        code: 'Verification Code', | 
			
		||||
 | 
				        codeMsg: 'Please enter the verification code', | 
			
		||||
 | 
				        submit: 'Login', | 
			
		||||
 | 
				        success: 'Login success' | 
			
		||||
    }, | 
				    }, | 
			
		||||
    'error': { | 
				 | 
			
		||||
      title: 'error info', | 
				 | 
			
		||||
 | 
				    home: { | 
			
		||||
 | 
				        welcome: 'Welcome to' | 
			
		||||
    }, | 
				    }, | 
			
		||||
  }, | 
				 | 
			
		||||
  route: { | 
				 | 
			
		||||
    goBack: 'Go Back', | 
				 | 
			
		||||
  }, | 
				 | 
			
		||||
  app: { | 
				 | 
			
		||||
    header: { | 
				 | 
			
		||||
      logout: 'logout', | 
				 | 
			
		||||
 | 
				    system: { | 
			
		||||
 | 
				        menus, | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    errorTitle: 'Error', | 
			
		||||
 | 
				    successTitle: 'Success', | 
			
		||||
 | 
				    success: 'Submit Success', | 
			
		||||
 | 
				    fail: 'Submit Fail', | 
			
		||||
 | 
				    saveSuccess: 'Save Success', | 
			
		||||
 | 
				    saveFail: 'Save Fail', | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    tabs: { | 
			
		||||
 | 
				        refresh: 'Refresh', | 
			
		||||
 | 
				        maximize: 'Maximize', | 
			
		||||
 | 
				        closeCurrent: 'Close current', | 
			
		||||
 | 
				        closeLeft: 'Close Left', | 
			
		||||
 | 
				        closeRight: 'Close Right', | 
			
		||||
 | 
				        closeOther: 'Close other', | 
			
		||||
 | 
				        closeAll: 'Close All' | 
			
		||||
    } | 
				    } | 
			
		||||
  }, | 
				 | 
			
		||||
  login:{ | 
				 | 
			
		||||
    title: 'Account Password Login', | 
				 | 
			
		||||
    username: 'Username', | 
				 | 
			
		||||
    usernameMsg: 'Please enter your username', | 
				 | 
			
		||||
    password: 'Password', | 
				 | 
			
		||||
    passwordMsg: 'Please enter your password', | 
				 | 
			
		||||
    code: 'Verification Code', | 
				 | 
			
		||||
    codeMsg: 'Please enter the verification code', | 
				 | 
			
		||||
    submit: 'Login', | 
				 | 
			
		||||
    success: 'Login success' | 
				 | 
			
		||||
  }, | 
				 | 
			
		||||
  home: { | 
				 | 
			
		||||
    welcome: 'Welcome to' | 
				 | 
			
		||||
  }, | 
				 | 
			
		||||
  tabs: { | 
				 | 
			
		||||
    refresh: 'Refresh', | 
				 | 
			
		||||
    maximize: 'Maximize', | 
				 | 
			
		||||
    closeCurrent: 'Close current', | 
				 | 
			
		||||
    closeLeft: 'Close Left', | 
				 | 
			
		||||
    closeRight: 'Close Right', | 
				 | 
			
		||||
    closeOther: 'Close other', | 
				 | 
			
		||||
    closeAll: 'Close All' | 
				 | 
			
		||||
  } | 
				 | 
			
		||||
} | 
				} | 
			
		||||
@ -0,0 +1,3 @@ | 
			
		|||||
 | 
				export default { | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				} | 
			
		||||
@ -0,0 +1,24 @@ | 
			
		|||||
 | 
				export default { | 
			
		||||
 | 
				    title: '菜单', | 
			
		||||
 | 
				    setting: '配置', | 
			
		||||
 | 
				    saveSuccess: '保存成功', | 
			
		||||
 | 
				    form:{ | 
			
		||||
 | 
				        title: '菜单名称', | 
			
		||||
 | 
				        parent: '上级菜单', | 
			
		||||
 | 
				        type:'类型', | 
			
		||||
 | 
				        typeOptions: { | 
			
		||||
 | 
				            menu: '菜单', | 
			
		||||
 | 
				            iframe: 'iframe', | 
			
		||||
 | 
				            link: '外链', | 
			
		||||
 | 
				            button: '按钮', | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				        name: '别名', | 
			
		||||
 | 
				        icon: '图标', | 
			
		||||
 | 
				        sort: '排序', | 
			
		||||
 | 
				        path: '路由', | 
			
		||||
 | 
				        component: '视图', | 
			
		||||
 | 
				        componentHelp: '视图路径,相对于src/pages,菜单组可以不填', | 
			
		||||
 | 
				        save: '保存', | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				    button: '按钮' | 
			
		||||
 | 
				} | 
			
		||||
@ -1,49 +1,61 @@ | 
			
		|||||
import antdZh from 'antd/locale/zh_CN' | 
				import antdZh from 'antd/locale/zh_CN' | 
			
		||||
 | 
				import menus from './pages/system/menus/zh-CN.ts' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				
 | 
			
		||||
export default { | 
				export default { | 
			
		||||
  ...antdZh, | 
				 | 
			
		||||
  error: { | 
				 | 
			
		||||
    '404': { | 
				 | 
			
		||||
      title: '无法找到', | 
				 | 
			
		||||
      message: '找不到此页面' | 
				 | 
			
		||||
 | 
				    ...antdZh, | 
			
		||||
 | 
				    error: { | 
			
		||||
 | 
				        '404': { | 
			
		||||
 | 
				            title: '无法找到', | 
			
		||||
 | 
				            message: '找不到此页面' | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				        '403': { | 
			
		||||
 | 
				            title: '没有权限', | 
			
		||||
 | 
				            message: '对不起,您没有权限查看此页面。' | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				        'error': { | 
			
		||||
 | 
				            title: '错误信息', | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				    route: { | 
			
		||||
 | 
				        goBack: '返回', | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				    app: { | 
			
		||||
 | 
				        header: { | 
			
		||||
 | 
				            logout: '退出登录', | 
			
		||||
 | 
				        } | 
			
		||||
    }, | 
				    }, | 
			
		||||
    '403': { | 
				 | 
			
		||||
      title: '没有权限', | 
				 | 
			
		||||
      message: '对不起,您没有权限查看此页面。' | 
				 | 
			
		||||
 | 
				    login: { | 
			
		||||
 | 
				        title: '账户密码登录', | 
			
		||||
 | 
				        username: '用户名', | 
			
		||||
 | 
				        usernameMsg: '请输入用户名', | 
			
		||||
 | 
				        password: '密码', | 
			
		||||
 | 
				        passwordMsg: '请输入密码', | 
			
		||||
 | 
				        code: '验证码', | 
			
		||||
 | 
				        codeMsg: '请输入验证码', | 
			
		||||
 | 
				        submit: '登录', | 
			
		||||
 | 
				        success: '登录成功' | 
			
		||||
    }, | 
				    }, | 
			
		||||
    'error': { | 
				 | 
			
		||||
      title: '错误信息', | 
				 | 
			
		||||
 | 
				    home: { | 
			
		||||
 | 
				        welcome: '欢迎使用' | 
			
		||||
 | 
				    }, | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    system: { | 
			
		||||
 | 
				        menus, | 
			
		||||
    }, | 
				    }, | 
			
		||||
  }, | 
				 | 
			
		||||
  route: { | 
				 | 
			
		||||
    goBack: '返回', | 
				 | 
			
		||||
  }, | 
				 | 
			
		||||
  app: { | 
				 | 
			
		||||
    header: { | 
				 | 
			
		||||
      logout: '退出登录', | 
				 | 
			
		||||
 | 
				    errorTitle: '错误', | 
			
		||||
 | 
				    successTitle: '成功', | 
			
		||||
 | 
				    success: '提交成功', | 
			
		||||
 | 
				    fail: '提交失败', | 
			
		||||
 | 
				    saveSuccess: '保存成功', | 
			
		||||
 | 
				    saveFail: '保存失败', | 
			
		||||
 | 
				    tabs: { | 
			
		||||
 | 
				        refresh: '刷新', | 
			
		||||
 | 
				        maximize: '最大化', | 
			
		||||
 | 
				        closeCurrent: '关闭当前', | 
			
		||||
 | 
				        closeLeft: '关闭左侧', | 
			
		||||
 | 
				        closeRight: '关闭右侧', | 
			
		||||
 | 
				        closeOther: '关闭其它', | 
			
		||||
 | 
				        closeAll: '关闭所有' | 
			
		||||
    } | 
				    } | 
			
		||||
  }, | 
				 | 
			
		||||
  login:{ | 
				 | 
			
		||||
    title: '账户密码登录', | 
				 | 
			
		||||
    username: '用户名', | 
				 | 
			
		||||
    usernameMsg: '请输入用户名', | 
				 | 
			
		||||
    password: '密码', | 
				 | 
			
		||||
    passwordMsg: '请输入密码', | 
				 | 
			
		||||
    code: '验证码', | 
				 | 
			
		||||
    codeMsg: '请输入验证码', | 
				 | 
			
		||||
    submit: '登录', | 
				 | 
			
		||||
    success: '登录成功' | 
				 | 
			
		||||
  }, | 
				 | 
			
		||||
  home: { | 
				 | 
			
		||||
    welcome: '欢迎使用' | 
				 | 
			
		||||
  }, | 
				 | 
			
		||||
  tabs: { | 
				 | 
			
		||||
    refresh: '刷新', | 
				 | 
			
		||||
    maximize: '最大化', | 
				 | 
			
		||||
    closeCurrent: '关闭当前', | 
				 | 
			
		||||
    closeLeft: '关闭左侧', | 
				 | 
			
		||||
    closeRight: '关闭右侧', | 
				 | 
			
		||||
    closeOther: '关闭其它', | 
				 | 
			
		||||
    closeAll: '关闭所有' | 
				 | 
			
		||||
  } | 
				 | 
			
		||||
} | 
				} | 
			
		||||
@ -1,15 +1,109 @@ | 
			
		|||||
import { PageContainer } from '@ant-design/pro-components' | 
				 | 
			
		||||
import {   createLazyFileRoute } from '@tanstack/react-router' | 
				 | 
			
		||||
 | 
				import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components' | 
			
		||||
 | 
				import { createLazyFileRoute } from '@tanstack/react-router' | 
			
		||||
 | 
				import { useStyle } from './style.ts' | 
			
		||||
 | 
				import { useMemo, useRef } from 'react' | 
			
		||||
 | 
				import { useAtomValue } from 'jotai' | 
			
		||||
 | 
				import { rolesAtom } from './store.ts' | 
			
		||||
 | 
				import { useTranslation } from '@/i18n.ts' | 
			
		||||
 | 
				import { Button, Space, Table } from 'antd' | 
			
		||||
 | 
				import { PlusOutlined } from '@ant-design/icons' | 
			
		||||
 | 
				
 | 
			
		||||
const Roles = () => { | 
				const Roles = () => { | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    const { t } = useTranslation() | 
			
		||||
 | 
				    const { styles } = useStyle() | 
			
		||||
 | 
				    const actionRef = useRef<ActionType>() | 
			
		||||
 | 
				    const { data, isLoading } = useAtomValue(rolesAtom) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    const columns = useMemo(() => { | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				        return [ | 
			
		||||
 | 
				            { title: 'id', dataIndex: 'id', hideInTable: true, hideInSearch: true, }, | 
			
		||||
 | 
				            { title: '名称', dataIndex: 'name' }, | 
			
		||||
 | 
				            { title: '别名', dataIndex: 'code' }, | 
			
		||||
 | 
				            { title: '状态', dataIndex: 'status' }, | 
			
		||||
 | 
				            { title: '排序', dataIndex: 'sort', valueType: 'indexBorder', }, | 
			
		||||
 | 
				            { title: '备注', dataIndex: 'remark' }, | 
			
		||||
 | 
				            { | 
			
		||||
 | 
				                title: '操作', valueType: 'option', | 
			
		||||
 | 
				                key: 'option', | 
			
		||||
 | 
				                render: (text, record, _, action) => [ | 
			
		||||
 | 
				                    <a | 
			
		||||
 | 
				                            key="editable" | 
			
		||||
 | 
				                            onClick={() => { | 
			
		||||
 | 
				                                action?.startEditable?.(record.id) | 
			
		||||
 | 
				                            }} | 
			
		||||
 | 
				                    > | 
			
		||||
 | 
				                        编辑 | 
			
		||||
 | 
				                    </a>, | 
			
		||||
 | 
				                    <a href={record.url} target="_blank" rel="noopener noreferrer" key="view"> | 
			
		||||
 | 
				                        查看 | 
			
		||||
 | 
				                    </a>, | 
			
		||||
 | 
				                    <a href={record.url} target="_blank" rel="noopener noreferrer" key="del"> | 
			
		||||
 | 
				                        删除 | 
			
		||||
 | 
				                    </a>, | 
			
		||||
 | 
				                ], | 
			
		||||
 | 
				            }, | 
			
		||||
 | 
				        ] as ProColumns[] | 
			
		||||
 | 
				    }, []) | 
			
		||||
 | 
				
 | 
			
		||||
    return ( | 
				    return ( | 
			
		||||
            <PageContainer breadcrumbRender={false}> | 
				 | 
			
		||||
 | 
				            <PageContainer breadcrumbRender={false} title={false} className={styles.container}> | 
			
		||||
 | 
				                <ProTable | 
			
		||||
 | 
				                        rowKey={'id'} | 
			
		||||
 | 
				                        actionRef={actionRef} | 
			
		||||
 | 
				                        headerTitle={t('system.roles.title', '角色管理')} | 
			
		||||
 | 
				                        columns={columns} | 
			
		||||
 | 
				                        loading={isLoading} | 
			
		||||
 | 
				                        dataSource={data?.rows} | 
			
		||||
 | 
				                        search={false} | 
			
		||||
 | 
				                        rowSelection={{ | 
			
		||||
 | 
				                            selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT], | 
			
		||||
 | 
				                        }} | 
			
		||||
 | 
				                        tableAlertOptionRender={() => { | 
			
		||||
 | 
				                            return ( | 
			
		||||
 | 
				                                    <Space size={16}> | 
			
		||||
 | 
				                                        <a>批量删除</a> | 
			
		||||
 | 
				                                    </Space> | 
			
		||||
 | 
				                            ); | 
			
		||||
 | 
				                        }} | 
			
		||||
 | 
				                        toolbar={{ | 
			
		||||
 | 
				                            search: { | 
			
		||||
 | 
				                                onSearch: (value: string) => { | 
			
		||||
 | 
				                                    alert(value) | 
			
		||||
 | 
				                                }, | 
			
		||||
 | 
				                            }, | 
			
		||||
 | 
				                            onSearch: (value) => { | 
			
		||||
 | 
				                                console.log('value', value) | 
			
		||||
 | 
				                            }, | 
			
		||||
 | 
				                            actions: [ | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				                                <Button | 
			
		||||
 | 
				                                        key="button" | 
			
		||||
 | 
				                                        icon={<PlusOutlined/>} | 
			
		||||
 | 
				                                        onClick={() => { | 
			
		||||
 | 
				                                            actionRef.current?.reload() | 
			
		||||
 | 
				                                        }} | 
			
		||||
 | 
				                                        type="primary" | 
			
		||||
 | 
				                                > | 
			
		||||
 | 
				                                    新建 | 
			
		||||
 | 
				                                </Button>, | 
			
		||||
 | 
				                            ] | 
			
		||||
 | 
				                        }} | 
			
		||||
 | 
				                        pagination={{ | 
			
		||||
 | 
				                            total: data?.total, | 
			
		||||
 | 
				                            current: data?.page, | 
			
		||||
 | 
				                            pageSize: data?.pageSize, | 
			
		||||
 | 
				                            onChange: (page) => { | 
			
		||||
 | 
				                                console.log('page', page) | 
			
		||||
 | 
				                            } | 
			
		||||
 | 
				                        }} | 
			
		||||
 | 
				                /> | 
			
		||||
            </PageContainer> | 
				            </PageContainer> | 
			
		||||
    ) | 
				    ) | 
			
		||||
} | 
				} | 
			
		||||
 | 
				
 | 
			
		||||
export const Route = createLazyFileRoute("/system/roles")({ | 
				 | 
			
		||||
 | 
				export const Route = createLazyFileRoute('/system/roles')({ | 
			
		||||
    component: Roles | 
				    component: Roles | 
			
		||||
}) | 
				}) | 
			
		||||
 | 
				
 | 
			
		||||
@ -0,0 +1,25 @@ | 
			
		|||||
 | 
				import { atom } from 'jotai/index' | 
			
		||||
 | 
				import { IRole } from '@/types/roles' | 
			
		||||
 | 
				import { atomWithQuery } from 'jotai-tanstack-query' | 
			
		||||
 | 
				import { IPage, IPageResult } from '@/types' | 
			
		||||
 | 
				import systemServ from '@/service/system.ts' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				type SearchParams = IPage & IRole | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const idAtom = atom(0) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const IdsAtom = atom([]) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const roleAtom = atom<IRole>(undefined as unknown as IRole) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const searchAtom = atom<SearchParams>({} as SearchParams) | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const rolesAtom = atomWithQuery<any, IPageResult<IRole>>((get) => { | 
			
		||||
 | 
				    return { | 
			
		||||
 | 
				        queryKey: [ 'roles', get(searchAtom) ], | 
			
		||||
 | 
				        queryFn: async ({ queryKey: [ , params ] }) => { | 
			
		||||
 | 
				            return await systemServ.role.list(params as SearchParams) | 
			
		||||
 | 
				        }, | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				}) | 
			
		||||
@ -0,0 +1,22 @@ | 
			
		|||||
 | 
				import { createStyles } from '@/theme' | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				export const useStyle = createStyles(({ token, css, cx, prefixCls }) => { | 
			
		||||
 | 
				    const prefix = `${prefixCls}-${token?.proPrefix}-role-page`; | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    const box = css`
 | 
			
		||||
 | 
				        flex: 1; | 
			
		||||
 | 
				        background: ${token.colorBgContainer}; | 
			
		||||
 | 
				    `
 | 
			
		||||
 | 
				    const form = css`
 | 
			
		||||
 | 
				        display: flex; | 
			
		||||
 | 
				        flex-wrap: wrap; | 
			
		||||
 | 
				        min-width: 500px; | 
			
		||||
 | 
				    `
 | 
			
		||||
 | 
				
 | 
			
		||||
 | 
				    return { | 
			
		||||
 | 
				        container: cx(prefix), | 
			
		||||
 | 
				        box, | 
			
		||||
 | 
				        form, | 
			
		||||
 | 
				    } | 
			
		||||
 | 
				}) | 
			
		||||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue