李金
7 months ago
10 changed files with 444 additions and 356 deletions
-
50src/components/avatar/index.tsx
-
111src/components/breadcrumb/index.tsx
-
84src/components/icon/index.tsx
-
51src/components/icon/picker/IconRender.tsx
-
24src/components/icon/types.ts
-
49src/layout/RootLayout.tsx
-
34src/layout/style.ts
-
294src/pages/system/menus/index.tsx
-
36src/service/system.ts
-
67src/store/user.ts
@ -0,0 +1,50 @@ |
|||
import Icon from '@/components/icon' |
|||
import { useTranslation } from '@/i18n.ts' |
|||
import { currentUserAtom } from '@/store/user.ts' |
|||
import { Avatar as AntAvatar, Dropdown, Spin } from 'antd' |
|||
import { useAtomValue } from 'jotai' |
|||
|
|||
const Avatar = () => { |
|||
|
|||
const { t } = useTranslation() |
|||
const { data, isLoading } = useAtomValue(currentUserAtom) |
|||
|
|||
return ( |
|||
<div> |
|||
<Dropdown |
|||
key={'user'} |
|||
placement="bottomRight" |
|||
menu={{ |
|||
items: [ |
|||
{ |
|||
key: 'logout', |
|||
icon: <Icon type={'park:Logout'}/>, |
|||
label: <span style={{ |
|||
marginInlineStart: 8, |
|||
userSelect: 'none' |
|||
}}>{t('app.header.logout')}</span>, |
|||
}, |
|||
], |
|||
}} |
|||
> |
|||
<Spin spinning={isLoading}> |
|||
<AntAvatar |
|||
key="avatar" |
|||
size={'small'} |
|||
src={data?.avatar || data?.nickname?.substring(0, 1)}> |
|||
{!data?.avatar && data?.nickname?.substring(0, 1)} |
|||
</AntAvatar> |
|||
<span key="name" |
|||
style={{ |
|||
marginInlineStart: 8, |
|||
userSelect: 'none' |
|||
}}> |
|||
{data?.nickname} |
|||
</span> |
|||
</Spin> |
|||
</Dropdown> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
export default Avatar |
@ -1,25 +1,25 @@ |
|||
export interface ReactIcon { |
|||
type: 'antd' | 'park'; |
|||
componentName: string; |
|||
props?: object; |
|||
type: 'antd' | 'park'; |
|||
componentName: string; |
|||
props?: object; |
|||
} |
|||
|
|||
export interface IconfontIcon { |
|||
type: 'iconfont'; |
|||
componentName: string; |
|||
props: { |
|||
type: string; |
|||
}; |
|||
scriptUrl?: string; |
|||
type: 'iconfont'; |
|||
componentName: string; |
|||
props: { |
|||
type: string; |
|||
}; |
|||
scriptUrl?: string; |
|||
} |
|||
|
|||
export interface IconComponentProps { |
|||
type: string; |
|||
type: string; |
|||
|
|||
[key: string]: any; |
|||
[key: string]: any; |
|||
} |
|||
|
|||
/** |
|||
* 最基础的图标信息单元 |
|||
*/ |
|||
export type IconUnit = ReactIcon | IconfontIcon | IconComponentProps |
|||
export type IconUnit = IconComponentProps | ReactIcon | IconfontIcon |
@ -1,21 +1,31 @@ |
|||
import { createStyles } from '@/theme' |
|||
|
|||
export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => { |
|||
const prefix = `${prefixCls}-${token?.proPrefix}-layout` |
|||
const prefix = `${prefixCls}-${token?.proPrefix}-layout` |
|||
|
|||
const container = { |
|||
[prefix]: css`
|
|||
const container = { |
|||
[prefix]: css`
|
|||
.ant-pro-global-header-logo, |
|||
.ant-pro-layout-bg-list { |
|||
user-select: none; |
|||
} |
|||
`,
|
|||
} |
|||
|
|||
`,
|
|||
} |
|||
|
|||
const pageContext = css`
|
|||
box-shadow: ${token.boxShadowSecondary}; |
|||
`
|
|||
const pageContext = css`
|
|||
box-shadow: ${token.boxShadowSecondary}; |
|||
`
|
|||
|
|||
return { |
|||
container: cx(container[prefix], props?.className), |
|||
pageContext, |
|||
const sideMenu = css`
|
|||
.ant-pro-base-menu-inline-group .ant-menu-item-group-title .anticon { |
|||
margin-inline-end: 0; |
|||
} |
|||
`
|
|||
|
|||
return { |
|||
container: cx(container[prefix], props?.className), |
|||
pageContext, |
|||
sideMenu, |
|||
} |
|||
|
|||
}) |
@ -1,49 +1,62 @@ |
|||
import { appAtom } from '@/store/system.ts' |
|||
import { IUserInfo } from '@/types/user' |
|||
import { AxiosResponse } from 'axios' |
|||
import { atom } from 'jotai/index' |
|||
import { IAuth, MenuItem } from '@/types' |
|||
import { IApiResult, IAuth, MenuItem } from '@/types' |
|||
import { LoginRequest } from '@/types/login' |
|||
import { atomWithMutation, atomWithQuery, queryClientAtom } from 'jotai-tanstack-query' |
|||
import systemServ from '@/service/system.ts' |
|||
import { formatMenuData, isDev } from '@/utils' |
|||
|
|||
export const authAtom = atom<IAuth>({ |
|||
isLogin: false, |
|||
authKey: [] |
|||
isLogin: false, |
|||
authKey: [] |
|||
}) |
|||
|
|||
const devLogin = { |
|||
username: 'SupperAdmin', |
|||
password: 'kk123456', |
|||
code: '123456' |
|||
username: 'SupperAdmin', |
|||
password: 'kk123456', |
|||
code: '123456' |
|||
} |
|||
export const loginFormAtom = atom<LoginRequest>({ |
|||
...(isDev ? devLogin : {}) |
|||
...(isDev ? devLogin : {}) |
|||
} as LoginRequest) |
|||
|
|||
export const loginAtom = atomWithMutation<any, LoginRequest>(() => ({ |
|||
mutationKey: [ 'login' ], |
|||
mutationFn: async (params) => { |
|||
return await systemServ.login(params) |
|||
}, |
|||
onSuccess: () => { |
|||
// console.log('login success', data)
|
|||
}, |
|||
retry: false, |
|||
mutationKey: [ 'login' ], |
|||
mutationFn: async (params) => { |
|||
return await systemServ.login(params) |
|||
}, |
|||
onSuccess: () => { |
|||
// console.log('login success', data)
|
|||
}, |
|||
retry: false, |
|||
})) |
|||
|
|||
export const userMenuDataAtom = atomWithQuery<any, MenuItem[]>((get) => ({ |
|||
enabled: false, |
|||
queryKey: [ 'user_menus', get(appAtom).token ], |
|||
export const currentUserAtom = atomWithQuery<IApiResult<IUserInfo>, any, IUserInfo>((get) => { |
|||
return { |
|||
queryKey: [ 'user_info', get(appAtom).token ], |
|||
queryFn: async () => { |
|||
return await systemServ.user.menus() |
|||
}, |
|||
select: (data: AxiosResponse) => { |
|||
return formatMenuData(data.data.rows as any ?? []) |
|||
return await systemServ.user.current() |
|||
}, |
|||
initialData: () => { |
|||
const queryClient = get(queryClientAtom) |
|||
return queryClient.getQueryData([ 'user_menus', get(appAtom).token ]) |
|||
}, |
|||
retry: false, |
|||
select: (data) => { |
|||
return data.data |
|||
} |
|||
} |
|||
}) |
|||
|
|||
export const userMenuDataAtom = atomWithQuery<any, MenuItem[]>((get) => ({ |
|||
enabled: false, |
|||
queryKey: [ 'user_menus', get(appAtom).token ], |
|||
queryFn: async () => { |
|||
return await systemServ.user.menus() |
|||
}, |
|||
select: (data: AxiosResponse) => { |
|||
return formatMenuData(data.data.rows as any ?? []) |
|||
}, |
|||
initialData: () => { |
|||
const queryClient = get(queryClientAtom) |
|||
return queryClient.getQueryData([ 'user_menus', get(appAtom).token ]) |
|||
}, |
|||
retry: false, |
|||
})) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue