Feat(Hint): Support dark mode
This commit is contained in:
@@ -4,6 +4,7 @@ import BaseStyles from '@/assets/css/base.style'
|
||||
import CommonStyles from '@/assets/css/common.style'
|
||||
import { COLOR_PRODUCTION } from '@/constants/common.constants'
|
||||
import { getRouter } from '@/router'
|
||||
import { init } from '@/util/common'
|
||||
import FullscreenLoadingMask from '@/components/common/FullscreenLoadingMask'
|
||||
|
||||
export const AppContext = createContext({
|
||||
@@ -12,10 +13,14 @@ export const AppContext = createContext({
|
||||
})
|
||||
|
||||
const App = () => {
|
||||
const [messageInstance, messageHolder] = message.useMessage()
|
||||
const [notificationInstance, notificationHolder] = notification.useNotification()
|
||||
const [modalInstance, modalHolder] = AntdModal.useModal()
|
||||
const [routerState, setRouterState] = useState(getRouter)
|
||||
const [isDarkMode, setIsDarkMode] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
init(messageInstance, notificationInstance, modalInstance)
|
||||
const darkThemeMq = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
setIsDarkMode(darkThemeMq.matches)
|
||||
const listener = (ev: MediaQueryListEvent) => {
|
||||
@@ -59,6 +64,9 @@ const App = () => {
|
||||
<RouterProvider router={routerState} />
|
||||
</Suspense>
|
||||
</AppContext.Provider>
|
||||
{messageHolder}
|
||||
{notificationHolder}
|
||||
{modalHolder}
|
||||
</AntdConfigProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export default createGlobalStyle(() => ({
|
||||
li: { listStyle: 'none' },
|
||||
img: { border: 0, verticalAlign: 'middle' },
|
||||
button: { cursor: 'pointer' },
|
||||
a: { color: '#666', textDecoration: 'none' },
|
||||
a: { color: '#666', textDecoration: 'none', whiteSpace: 'nowrap' },
|
||||
'button, input': {
|
||||
fontFamily:
|
||||
'Microsoft YaHei, Heiti SC, tahoma, arial, Hiragino Sans GB, "\\5B8B\\4F53", sans-serif',
|
||||
|
||||
@@ -4,9 +4,15 @@ import useStyles from '@/assets/css/components/common/card.style'
|
||||
type CardProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
||||
|
||||
const Card = forwardRef<HTMLDivElement, CardProps>(({ className, ...props }, ref) => {
|
||||
const { styles, cx } = useStyles()
|
||||
const { styles } = useStyles()
|
||||
|
||||
return <div className={cx(styles.cardBox, className)} {...props} ref={ref} />
|
||||
return (
|
||||
<div
|
||||
className={`${styles.cardBox}${className ? ` ${className}` : ''}`}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
export default Card
|
||||
|
||||
@@ -6,15 +6,11 @@ interface FitCenterProps extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement
|
||||
}
|
||||
|
||||
const FitCenter = ({ className, vertical, ...props }: FitCenterProps) => {
|
||||
const { styles, cx } = useStyles()
|
||||
const { styles } = useStyles()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
styles.fitCenter,
|
||||
className,
|
||||
vertical ? ' flex-vertical' : ' flex-horizontal'
|
||||
)}
|
||||
className={`${styles.fitCenter}${vertical ? ' flex-vertical' : ' flex-horizontal'}${className ? ` ${className}` : ''}`}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -9,11 +9,11 @@ interface FitFullscreenProps
|
||||
|
||||
const FitFullscreen = forwardRef<HTMLDivElement, FitFullscreenProps>(
|
||||
({ zIndex, backgroundColor, className, style, ...props }, ref) => {
|
||||
const { styles, cx } = useStyles()
|
||||
const { styles } = useStyles()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(styles.fitFullscreen, className)}
|
||||
className={`${styles.fitFullscreen}${className ? ` ${className}` : ''}`}
|
||||
style={{
|
||||
zIndex,
|
||||
backgroundColor,
|
||||
|
||||
@@ -8,15 +8,11 @@ interface FlexBoxProps extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement>,
|
||||
|
||||
const FlexBox = forwardRef<HTMLDivElement, FlexBoxProps>(
|
||||
({ className, direction, gap, style, ...props }, ref) => {
|
||||
const { styles, cx } = useStyles()
|
||||
const { styles } = useStyles()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
styles.flexBox,
|
||||
className,
|
||||
direction === 'horizontal' ? 'flex-horizontal' : 'flex-vertical'
|
||||
)}
|
||||
className={`${styles.flexBox}${direction === 'horizontal' ? ' flex-horizontal' : ' flex-vertical'}${className ? ` ${className}` : ''}`}
|
||||
style={{ gap, ...style }}
|
||||
{...props}
|
||||
ref={ref}
|
||||
|
||||
@@ -540,7 +540,7 @@ const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>(
|
||||
>
|
||||
<div
|
||||
ref={rootRef}
|
||||
className={cx(styles.hideScrollbarSelection, className)}
|
||||
className={`${styles.hideScrollbarSelection}${className ? ` ${className}` : ''}`}
|
||||
tabIndex={0}
|
||||
style={{
|
||||
width: `calc(${maskRef.current?.clientWidth}px + ${verticalScrollbarWidth}px)`,
|
||||
@@ -571,7 +571,7 @@ const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>(
|
||||
className={cx(
|
||||
styles.scrollbar,
|
||||
styles.verticalScrollbar,
|
||||
isVerticalScrollbarAutoHide ? ` ${styles.hide}` : ''
|
||||
isVerticalScrollbarAutoHide ? styles.hide : ''
|
||||
)}
|
||||
style={{
|
||||
height: maskRef.current
|
||||
@@ -619,7 +619,7 @@ const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>(
|
||||
className={cx(
|
||||
styles.scrollbar,
|
||||
styles.horizontalScrollbar,
|
||||
isHorizontalScrollbarAutoHide ? ` ${styles.hide}` : ''
|
||||
isHorizontalScrollbarAutoHide ? styles.hide : ''
|
||||
)}
|
||||
style={{
|
||||
width: maskRef.current
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Icon from '@ant-design/icons'
|
||||
import useStyles from '@/assets/css/components/common/sidebar/footer.style'
|
||||
import { SidebarContext } from '@/components/common/Sidebar/index'
|
||||
import { notification } from '@/util/common'
|
||||
import { getRedirectUrl } from '@/util/route'
|
||||
import { getAvatar, getLoginStatus, getNickname, removeToken } from '@/util/auth'
|
||||
import { navigateToLogin, navigateToUser } from '@/util/navigation'
|
||||
|
||||
@@ -3,7 +3,7 @@ import VanillaTilt, { TiltOptions } from 'vanilla-tilt'
|
||||
import protocolCheck from 'custom-protocol-check'
|
||||
import Icon from '@ant-design/icons'
|
||||
import useStyles from '@/assets/css/components/tools/store-card.style'
|
||||
import { checkDesktop, omitTextByByte } from '@/util/common'
|
||||
import { message, modal, checkDesktop, omitTextByByte } from '@/util/common'
|
||||
import { getLoginStatus, getUserId } from '@/util/auth'
|
||||
import {
|
||||
getAndroidUrl,
|
||||
@@ -56,7 +56,6 @@ const StoreCard = ({
|
||||
}: StoreCardProps) => {
|
||||
const { styles, theme } = useStyles()
|
||||
const navigate = useNavigate()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const cardRef = useRef<HTMLDivElement>(null)
|
||||
const [favorite_, setFavorite_] = useState<boolean>(favorite)
|
||||
const [userId, setUserId] = useState('')
|
||||
@@ -76,6 +75,7 @@ const StoreCard = ({
|
||||
if (platform === 'ANDROID') {
|
||||
void modal.confirm({
|
||||
centered: true,
|
||||
keyboard: false,
|
||||
icon: <Icon style={{ color: theme.colorPrimary }} component={IconOxygenInfo} />,
|
||||
title: 'Android 端',
|
||||
content: (
|
||||
@@ -144,6 +144,7 @@ const StoreCard = ({
|
||||
e.stopPropagation()
|
||||
void modal.confirm({
|
||||
centered: true,
|
||||
keyboard: false,
|
||||
icon: <Icon style={{ color: theme.colorPrimary }} component={IconOxygenInfo} />,
|
||||
title: 'Android 端',
|
||||
content: (
|
||||
@@ -190,114 +191,108 @@ const StoreCard = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Draggable
|
||||
id={`${author.username}:${toolId}:${ver}:${platform}`}
|
||||
data={{
|
||||
icon,
|
||||
toolName,
|
||||
toolId,
|
||||
authorUsername: author.username,
|
||||
ver: '',
|
||||
platform
|
||||
}}
|
||||
<Draggable
|
||||
id={`${author.username}:${toolId}:${ver}:${platform}`}
|
||||
data={{
|
||||
icon,
|
||||
toolName,
|
||||
toolId,
|
||||
authorUsername: author.username,
|
||||
ver: '',
|
||||
platform
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
style={{ overflow: 'visible', ...style }}
|
||||
ref={cardRef}
|
||||
{...props}
|
||||
onClick={handleCardOnClick}
|
||||
>
|
||||
<Card
|
||||
style={{ overflow: 'visible', ...style }}
|
||||
ref={cardRef}
|
||||
{...props}
|
||||
onClick={handleCardOnClick}
|
||||
>
|
||||
<FlexBox className={styles.root}>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.version}>
|
||||
<AntdTag>
|
||||
{platform.slice(0, 1)}-{ver}
|
||||
</AntdTag>
|
||||
</div>
|
||||
<div className={styles.operation}>
|
||||
{platform !== 'ANDROID' && supportPlatform.includes('ANDROID') && (
|
||||
<AntdTooltip title={'Android 端'}>
|
||||
<Icon
|
||||
component={IconOxygenMobile}
|
||||
onClick={handleOnAndroidBtnClick}
|
||||
/>
|
||||
</AntdTooltip>
|
||||
)}
|
||||
{platform === 'DESKTOP' && supportPlatform.includes('WEB') && (
|
||||
<AntdTooltip title={'Web 端'}>
|
||||
<Icon
|
||||
component={IconOxygenBrowser}
|
||||
onClick={handleOnWebBtnClick}
|
||||
/>
|
||||
</AntdTooltip>
|
||||
)}
|
||||
{platform === 'WEB' && supportPlatform.includes('DESKTOP') && (
|
||||
<AntdTooltip title={'桌面端'}>
|
||||
<Icon
|
||||
component={IconOxygenDesktop}
|
||||
onClick={handleOnDesktopBtnClick}
|
||||
/>
|
||||
</AntdTooltip>
|
||||
)}
|
||||
<AntdTooltip title={'源码'}>
|
||||
<FlexBox className={styles.root}>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.version}>
|
||||
<AntdTag>
|
||||
{platform.slice(0, 1)}-{ver}
|
||||
</AntdTag>
|
||||
</div>
|
||||
<div className={styles.operation}>
|
||||
{platform !== 'ANDROID' && supportPlatform.includes('ANDROID') && (
|
||||
<AntdTooltip title={'Android 端'}>
|
||||
<Icon
|
||||
component={IconOxygenCode}
|
||||
onClick={handleOnSourceBtnClick}
|
||||
component={IconOxygenMobile}
|
||||
onClick={handleOnAndroidBtnClick}
|
||||
/>
|
||||
</AntdTooltip>
|
||||
{author.id !== userId && (
|
||||
<AntdTooltip title={favorite_ ? '取消收藏' : '收藏'}>
|
||||
<Icon
|
||||
component={
|
||||
favorite_ ? IconOxygenStarFilled : IconOxygenStar
|
||||
}
|
||||
style={{
|
||||
color: favorite_ ? theme.colorPrimary : undefined
|
||||
}}
|
||||
onClick={handleOnStarBtnClick}
|
||||
/>
|
||||
</AntdTooltip>
|
||||
)}
|
||||
<DragHandle />
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.icon}>
|
||||
<img src={`data:image/svg+xml;base64,${icon}`} alt={'Icon'} />
|
||||
</div>
|
||||
<div className={styles.info}>
|
||||
<div className={styles.toolName} title={toolName}>
|
||||
{toolName}
|
||||
</div>
|
||||
<div>{`ID: ${toolId}`}</div>
|
||||
{toolDesc && (
|
||||
<div className={styles.toolDesc} title={toolDesc}>
|
||||
{omitTextByByte(toolDesc, 64)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{showAuthor && (
|
||||
<div className={styles.author} onClick={handleOnClickAuthor}>
|
||||
<div className={styles.avatar}>
|
||||
<AntdAvatar
|
||||
src={
|
||||
<AntdImage
|
||||
preview={false}
|
||||
src={`data:image/png;base64,${author.userInfo.avatar}`}
|
||||
alt={'Avatar'}
|
||||
/>
|
||||
}
|
||||
style={{ background: theme.colorBgLayout }}
|
||||
{platform === 'DESKTOP' && supportPlatform.includes('WEB') && (
|
||||
<AntdTooltip title={'Web 端'}>
|
||||
<Icon
|
||||
component={IconOxygenBrowser}
|
||||
onClick={handleOnWebBtnClick}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.authorName}>{author.userInfo.nickname}</div>
|
||||
</AntdTooltip>
|
||||
)}
|
||||
{platform === 'WEB' && supportPlatform.includes('DESKTOP') && (
|
||||
<AntdTooltip title={'桌面端'}>
|
||||
<Icon
|
||||
component={IconOxygenDesktop}
|
||||
onClick={handleOnDesktopBtnClick}
|
||||
/>
|
||||
</AntdTooltip>
|
||||
)}
|
||||
<AntdTooltip title={'源码'}>
|
||||
<Icon component={IconOxygenCode} onClick={handleOnSourceBtnClick} />
|
||||
</AntdTooltip>
|
||||
{author.id !== userId && (
|
||||
<AntdTooltip title={favorite_ ? '取消收藏' : '收藏'}>
|
||||
<Icon
|
||||
component={
|
||||
favorite_ ? IconOxygenStarFilled : IconOxygenStar
|
||||
}
|
||||
style={{
|
||||
color: favorite_ ? theme.colorPrimary : undefined
|
||||
}}
|
||||
onClick={handleOnStarBtnClick}
|
||||
/>
|
||||
</AntdTooltip>
|
||||
)}
|
||||
<DragHandle />
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.icon}>
|
||||
<img src={`data:image/svg+xml;base64,${icon}`} alt={'Icon'} />
|
||||
</div>
|
||||
<div className={styles.info}>
|
||||
<div className={styles.toolName} title={toolName}>
|
||||
{toolName}
|
||||
</div>
|
||||
<div>{`ID: ${toolId}`}</div>
|
||||
{toolDesc && (
|
||||
<div className={styles.toolDesc} title={toolDesc}>
|
||||
{omitTextByByte(toolDesc, 64)}
|
||||
</div>
|
||||
)}
|
||||
</FlexBox>
|
||||
</Card>
|
||||
</Draggable>
|
||||
{contextHolder}
|
||||
</>
|
||||
</div>
|
||||
{showAuthor && (
|
||||
<div className={styles.author} onClick={handleOnClickAuthor}>
|
||||
<div className={styles.avatar}>
|
||||
<AntdAvatar
|
||||
src={
|
||||
<AntdImage
|
||||
preview={false}
|
||||
src={`data:image/png;base64,${author.userInfo.avatar}`}
|
||||
alt={'Avatar'}
|
||||
/>
|
||||
}
|
||||
style={{ background: theme.colorBgLayout }}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.authorName}>{author.userInfo.nickname}</div>
|
||||
</div>
|
||||
)}
|
||||
</FlexBox>
|
||||
</Card>
|
||||
</Draggable>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
PERMISSION_USER_NOT_FOUND,
|
||||
SYSTEM_INVALID_CAPTCHA_CODE
|
||||
} from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { navigateToLogin } from '@/util/navigation'
|
||||
import { r_auth_forget, r_auth_retrieve } from '@/services/auth'
|
||||
import { AppContext } from '@/App'
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
PERMISSION_USERNAME_NOT_FOUND,
|
||||
SYSTEM_INVALID_CAPTCHA_CODE
|
||||
} from '@/constants/common.constants'
|
||||
import { message, notification, modal } from '@/util/common'
|
||||
import { getUserInfo, setToken } from '@/util/auth'
|
||||
import { utcToLocalTime } from '@/util/datetime'
|
||||
import {
|
||||
@@ -26,7 +27,6 @@ import FlexBox from '@/components/common/FlexBox'
|
||||
|
||||
const SignIn = () => {
|
||||
const { styles } = useStyles()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const { refreshRouter, isDarkMode } = useContext(AppContext)
|
||||
const navigate = useNavigate()
|
||||
const [searchParams] = useSearchParams()
|
||||
@@ -82,8 +82,7 @@ const SignIn = () => {
|
||||
switch (code) {
|
||||
case PERMISSION_LOGIN_SUCCESS:
|
||||
setToken(data?.token ?? '')
|
||||
void message.success('登录成功')
|
||||
setTimeout(() => {
|
||||
message.success('登录成功').then(() => {
|
||||
void getUserInfo().then((user) => {
|
||||
refreshRouter()
|
||||
navigateToRedirect(navigate, searchParams, '/repository')
|
||||
@@ -109,7 +108,7 @@ const SignIn = () => {
|
||||
placement: 'topRight'
|
||||
})
|
||||
})
|
||||
}, 1500)
|
||||
})
|
||||
break
|
||||
case PERMISSION_NEED_TWO_FACTOR:
|
||||
twoFactorForm.resetFields()
|
||||
@@ -299,7 +298,6 @@ const SignIn = () => {
|
||||
</div>
|
||||
</AntdForm>
|
||||
</FlexBox>
|
||||
{contextHolder}
|
||||
</FitCenter>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
SYSTEM_INVALID_CAPTCHA_CODE,
|
||||
SYSTEM_MATCH_SENSITIVE_WORD
|
||||
} from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { getLoginStatus, setToken } from '@/util/auth'
|
||||
import { navigateToLogin } from '@/util/navigation'
|
||||
import { r_auth_register, r_auth_resend } from '@/services/auth'
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
PERMISSION_VERIFY_SUCCESS,
|
||||
SYSTEM_MATCH_SENSITIVE_WORD
|
||||
} from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { getLoginStatus, getUserInfo, requestUserInfo } from '@/util/auth'
|
||||
import { navigateToLogin, navigateToRedirect, navigateToRepository } from '@/util/navigation'
|
||||
import { r_auth_resend, r_auth_verify } from '@/services/auth'
|
||||
@@ -125,13 +126,12 @@ const Verify = () => {
|
||||
const response = res.data
|
||||
switch (response.code) {
|
||||
case PERMISSION_VERIFY_SUCCESS:
|
||||
void message.success('恭喜你,完成了')
|
||||
setTimeout(() => {
|
||||
message.success('恭喜你,完成了').then(() => {
|
||||
void requestUserInfo().then(() => {
|
||||
refreshRouter()
|
||||
navigateToRedirect(navigate, searchParams, '/repository')
|
||||
})
|
||||
}, 1500)
|
||||
})
|
||||
break
|
||||
case SYSTEM_MATCH_SENSITIVE_WORD:
|
||||
void message.error('昵称包含敏感词,请重试')
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
DATABASE_SELECT_SUCCESS,
|
||||
DATABASE_UPDATE_SUCCESS
|
||||
} from '@/constants/common.constants'
|
||||
import { message, modal } from '@/util/common'
|
||||
import { hasPermission } from '@/util/auth'
|
||||
import { utcToLocalTime } from '@/util/datetime'
|
||||
import {
|
||||
@@ -27,7 +28,6 @@ import Card from '@/components/common/Card'
|
||||
|
||||
const Group = () => {
|
||||
const theme = useTheme()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [form] = AntdForm.useForm<GroupAddEditParam>()
|
||||
const formValues = AntdForm.useWatch([], form)
|
||||
const [newFormValues, setNewFormValues] = useState<GroupAddEditParam>()
|
||||
@@ -246,7 +246,7 @@ const Group = () => {
|
||||
centered: true,
|
||||
maskClosable: true,
|
||||
title: '确定删除',
|
||||
content: `确定删除角色 ${value.name} 吗?`
|
||||
content: `确定删除用户组 ${value.name} 吗?`
|
||||
})
|
||||
.then(
|
||||
(confirmed) => {
|
||||
@@ -300,7 +300,7 @@ const Group = () => {
|
||||
getGroup()
|
||||
break
|
||||
case DATABASE_DUPLICATE_KEY:
|
||||
void message.error('已存在相同名称的角色')
|
||||
void message.error('已存在相同名称的用户组')
|
||||
break
|
||||
default:
|
||||
void message.error('更新失败,请稍后重试')
|
||||
@@ -321,7 +321,7 @@ const Group = () => {
|
||||
getGroup()
|
||||
break
|
||||
case DATABASE_DUPLICATE_KEY:
|
||||
void message.error('已存在相同名称的角色')
|
||||
void message.error('已存在相同名称的用户组')
|
||||
break
|
||||
default:
|
||||
void message.error('添加失败,请稍后重试')
|
||||
@@ -563,6 +563,7 @@ const Group = () => {
|
||||
rowKey={(record) => record.id}
|
||||
pagination={tableParams.pagination}
|
||||
loading={isLoading}
|
||||
scroll={{ x: true }}
|
||||
onChange={handleOnTableChange}
|
||||
rowSelection={
|
||||
hasPermission('system:group:delete:multiple')
|
||||
@@ -657,7 +658,6 @@ const Group = () => {
|
||||
>
|
||||
{addAndEditForm}
|
||||
</AntdDrawer>
|
||||
{contextHolder}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ChangeEvent, KeyboardEvent } from 'react'
|
||||
import { useTheme } from 'antd-style'
|
||||
import dayjs from 'dayjs'
|
||||
import { DATABASE_SELECT_SUCCESS } from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { dayjsToUtc, utcToLocalTime } from '@/util/datetime'
|
||||
import { r_sys_log_get } from '@/services/system'
|
||||
import FitFullscreen from '@/components/common/FitFullscreen'
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
DATABASE_SELECT_SUCCESS,
|
||||
DATABASE_UPDATE_SUCCESS
|
||||
} from '@/constants/common.constants'
|
||||
import { message, modal } from '@/util/common'
|
||||
import { utcToLocalTime } from '@/util/datetime'
|
||||
import { hasPermission, powerListToPowerTree } from '@/util/auth'
|
||||
import {
|
||||
@@ -27,7 +28,6 @@ import Card from '@/components/common/Card'
|
||||
|
||||
const Role = () => {
|
||||
const theme = useTheme()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [form] = AntdForm.useForm<RoleAddEditParam>()
|
||||
const formValues = AntdForm.useWatch([], form)
|
||||
const [newFormValues, setNewFormValues] = useState<RoleAddEditParam>()
|
||||
@@ -572,6 +572,7 @@ const Role = () => {
|
||||
rowKey={(record) => record.id}
|
||||
pagination={tableParams.pagination}
|
||||
loading={isLoading}
|
||||
scroll={{ x: true }}
|
||||
onChange={handleOnTableChange}
|
||||
rowSelection={
|
||||
hasPermission('system:role:delete:multiple')
|
||||
@@ -664,7 +665,6 @@ const Role = () => {
|
||||
>
|
||||
{addAndEditForm}
|
||||
</AntdDrawer>
|
||||
{contextHolder}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { message } from '@/util/common'
|
||||
import { hasPermission } from '@/util/auth'
|
||||
import { r_sys_settings_base_get, r_sys_settings_base_update } from '@/services/system'
|
||||
import SettingsCard from '@/components/system/SettingCard'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Icon from '@ant-design/icons'
|
||||
import { message, modal } from '@/util/common'
|
||||
import { hasPermission } from '@/util/auth'
|
||||
import {
|
||||
r_sys_settings_mail_get,
|
||||
@@ -8,7 +9,6 @@ import {
|
||||
import SettingsCard from '@/components/system/SettingCard'
|
||||
|
||||
const Mail = () => {
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [mailForm] = AntdForm.useForm<MailSettingsParam>()
|
||||
const mailFormValues = AntdForm.useWatch([], mailForm)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
@@ -114,59 +114,56 @@ const Mail = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsCard
|
||||
icon={IconOxygenEmail}
|
||||
title={'邮件'}
|
||||
loading={isLoading}
|
||||
onReset={handleOnReset}
|
||||
onSave={handleOnSave}
|
||||
modifyOperationCode={['system:settings:modify:mail']}
|
||||
expand={
|
||||
<AntdButton onClick={handleOnTest} title={'测试'}>
|
||||
<Icon component={IconOxygenTest} />
|
||||
</AntdButton>
|
||||
}
|
||||
<SettingsCard
|
||||
icon={IconOxygenEmail}
|
||||
title={'邮件'}
|
||||
loading={isLoading}
|
||||
onReset={handleOnReset}
|
||||
onSave={handleOnSave}
|
||||
modifyOperationCode={['system:settings:modify:mail']}
|
||||
expand={
|
||||
<AntdButton onClick={handleOnTest} title={'测试'}>
|
||||
<Icon component={IconOxygenTest} />
|
||||
</AntdButton>
|
||||
}
|
||||
>
|
||||
<AntdForm
|
||||
form={mailForm}
|
||||
labelCol={{ flex: '8em' }}
|
||||
disabled={!hasPermission('system:settings:modify:mail')}
|
||||
>
|
||||
<AntdForm
|
||||
form={mailForm}
|
||||
labelCol={{ flex: '8em' }}
|
||||
disabled={!hasPermission('system:settings:modify:mail')}
|
||||
>
|
||||
<AntdForm.Item label={'SMTP 服务器'} name={'host'}>
|
||||
<AntdInput placeholder={'请输入 SMTP 服务器'} />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'端口号'} name={'port'}>
|
||||
<AntdInputNumber
|
||||
min={0}
|
||||
max={65535}
|
||||
style={{ width: '100%' }}
|
||||
placeholder={'请输入端口号'}
|
||||
/>
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'安全类型'} name={'securityType'}>
|
||||
<AntdSelect placeholder={'请选择安全类型'}>
|
||||
<AntdSelect.Option key={'None'}>None</AntdSelect.Option>
|
||||
<AntdSelect.Option key={'SSL/TLS'}>SSL/TLS</AntdSelect.Option>
|
||||
<AntdSelect.Option key={'StartTls'}>StartTls</AntdSelect.Option>
|
||||
</AntdSelect>
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'用户名'} name={'username'}>
|
||||
<AntdInput placeholder={'请输入用户名'} />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'密码'} name={'password'}>
|
||||
<AntdInput.Password placeholder={'请输入密码'} />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'发送者'} name={'from'}>
|
||||
<AntdInput placeholder={'请输入发送者'} />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'发送者名称'} name={'fromName'}>
|
||||
<AntdInput placeholder={'请输入发送者名称'} />
|
||||
</AntdForm.Item>
|
||||
</AntdForm>
|
||||
</SettingsCard>
|
||||
{contextHolder}
|
||||
</>
|
||||
<AntdForm.Item label={'SMTP 服务器'} name={'host'}>
|
||||
<AntdInput placeholder={'请输入 SMTP 服务器'} />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'端口号'} name={'port'}>
|
||||
<AntdInputNumber
|
||||
min={0}
|
||||
max={65535}
|
||||
style={{ width: '100%' }}
|
||||
placeholder={'请输入端口号'}
|
||||
/>
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'安全类型'} name={'securityType'}>
|
||||
<AntdSelect placeholder={'请选择安全类型'}>
|
||||
<AntdSelect.Option key={'None'}>None</AntdSelect.Option>
|
||||
<AntdSelect.Option key={'SSL/TLS'}>SSL/TLS</AntdSelect.Option>
|
||||
<AntdSelect.Option key={'StartTls'}>StartTls</AntdSelect.Option>
|
||||
</AntdSelect>
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'用户名'} name={'username'}>
|
||||
<AntdInput placeholder={'请输入用户名'} />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'密码'} name={'password'}>
|
||||
<AntdInput.Password placeholder={'请输入密码'} />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'发送者'} name={'from'}>
|
||||
<AntdInput placeholder={'请输入发送者'} />
|
||||
</AntdForm.Item>
|
||||
<AntdForm.Item label={'发送者名称'} name={'fromName'}>
|
||||
<AntdInput placeholder={'请输入发送者名称'} />
|
||||
</AntdForm.Item>
|
||||
</AntdForm>
|
||||
</SettingsCard>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChangeEvent } from 'react'
|
||||
import Icon from '@ant-design/icons'
|
||||
import { DATABASE_DUPLICATE_KEY, DATABASE_INSERT_SUCCESS } from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import {
|
||||
r_sys_settings_sensitive_add,
|
||||
r_sys_settings_sensitive_delete,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { message } from '@/util/common'
|
||||
import { hasPermission } from '@/util/auth'
|
||||
import { r_sys_settings_two_factor_get, r_sys_settings_two_factor_update } from '@/services/system'
|
||||
import SettingsCard from '@/components/system/SettingCard'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import useStyles from '@/assets/css/pages/system/statistics/common.style'
|
||||
import { message } from '@/util/common'
|
||||
import { r_sys_statistics_hardware } from '@/services/system'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
import StatisticsCard from '@/components/system/StatisticsCard'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import useStyles from '@/assets/css/pages/system/statistics/common.style'
|
||||
import { message } from '@/util/common'
|
||||
import { utcToLocalTime } from '@/util/datetime'
|
||||
import { r_sys_statistics_software } from '@/services/system'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
DATABASE_SELECT_SUCCESS,
|
||||
DATABASE_UPDATE_SUCCESS
|
||||
} from '@/constants/common.constants'
|
||||
import { message, modal } from '@/util/common'
|
||||
import { utcToLocalTime } from '@/util/datetime'
|
||||
import { hasPermission } from '@/util/auth'
|
||||
import editorExtraLibs from '@/util/editorExtraLibs'
|
||||
@@ -43,7 +44,6 @@ const Base = () => {
|
||||
({ currentLocation, nextLocation }) =>
|
||||
currentLocation.pathname !== nextLocation.pathname && Object.keys(hasEdited).length > 0
|
||||
)
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [tableParams, setTableParams] = useState<TableParam>({
|
||||
pagination: {
|
||||
current: 1,
|
||||
@@ -1093,6 +1093,7 @@ const Base = () => {
|
||||
expandedRowRender,
|
||||
onExpand: handleOnExpand
|
||||
}}
|
||||
scroll={{ x: true }}
|
||||
onChange={handleOnTableChange}
|
||||
/>
|
||||
</Card>
|
||||
@@ -1134,7 +1135,6 @@ const Base = () => {
|
||||
{addAndEditForm}
|
||||
</AntdDrawer>
|
||||
</FitFullscreen>
|
||||
{contextHolder}
|
||||
<AntdModal
|
||||
open={blocker.state === 'blocked'}
|
||||
title={'未保存'}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
DATABASE_SELECT_SUCCESS,
|
||||
DATABASE_UPDATE_SUCCESS
|
||||
} from '@/constants/common.constants'
|
||||
import { message, modal } from '@/util/common'
|
||||
import { utcToLocalTime } from '@/util/datetime'
|
||||
import {
|
||||
r_sys_tool_category_add,
|
||||
@@ -20,7 +21,6 @@ import HideScrollbar from '@/components/common/HideScrollbar'
|
||||
|
||||
const Category = () => {
|
||||
const theme = useTheme()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [form] = AntdForm.useForm<ToolCategoryAddEditParam>()
|
||||
const formValues = AntdForm.useWatch([], form)
|
||||
const [newFormValues, setNewFormValues] = useState<ToolCategoryAddEditParam>()
|
||||
@@ -298,6 +298,7 @@ const Category = () => {
|
||||
columns={categoryColumns}
|
||||
rowKey={(record) => record.id}
|
||||
loading={isLoading}
|
||||
scroll={{ x: true }}
|
||||
pagination={false}
|
||||
/>
|
||||
</Card>
|
||||
@@ -313,7 +314,6 @@ const Category = () => {
|
||||
>
|
||||
{addAndEditForm}
|
||||
</AntdDrawer>
|
||||
{contextHolder}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import Draggable from 'react-draggable'
|
||||
import Icon from '@ant-design/icons'
|
||||
import useStyles from '@/assets/css/pages/system/tools/code.style'
|
||||
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants'
|
||||
import { checkDesktop } from '@/util/common'
|
||||
import { message, modal, checkDesktop } from '@/util/common'
|
||||
import { navigateToExecute, navigateToRepository } from '@/util/navigation'
|
||||
import editorExtraLibs from '@/util/editorExtraLibs'
|
||||
import { r_sys_tool_get_one } from '@/services/system'
|
||||
@@ -17,7 +17,6 @@ const Code = () => {
|
||||
const { styles } = useStyles()
|
||||
const { isDarkMode } = useContext(AppContext)
|
||||
const navigate = useNavigate()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const { id } = useParams()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [files, setFiles] = useState<IFiles>({})
|
||||
@@ -106,7 +105,6 @@ const Code = () => {
|
||||
</div>
|
||||
</Draggable>
|
||||
</FitFullscreen>
|
||||
{contextHolder}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import useStyles from '@/assets/css/pages/system/tools/execute.style'
|
||||
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { navigateToTools } from '@/util/navigation'
|
||||
import { r_sys_tool_get_one } from '@/services/system'
|
||||
import FitFullscreen from '@/components/common/FitFullscreen'
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
DATABASE_SELECT_SUCCESS,
|
||||
DATABASE_UPDATE_SUCCESS
|
||||
} from '@/constants/common.constants'
|
||||
import { message, modal } from '@/util/common'
|
||||
import { utcToLocalTime } from '@/util/datetime'
|
||||
import { hasPermission } from '@/util/auth'
|
||||
import editorExtraLibs from '@/util/editorExtraLibs'
|
||||
@@ -41,7 +42,6 @@ const Template = () => {
|
||||
({ currentLocation, nextLocation }) =>
|
||||
currentLocation.pathname !== nextLocation.pathname && Object.keys(hasEdited).length > 0
|
||||
)
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [tableParams, setTableParams] = useState<TableParam>({
|
||||
pagination: {
|
||||
current: 1,
|
||||
@@ -1078,7 +1078,6 @@ const Template = () => {
|
||||
{addAndEditForm}
|
||||
</AntdDrawer>
|
||||
</FitFullscreen>
|
||||
{contextHolder}
|
||||
<AntdModal
|
||||
open={blocker.state === 'blocked'}
|
||||
title={'未保存'}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
DATABASE_UPDATE_SUCCESS,
|
||||
TOOL_NOT_UNDER_REVIEW
|
||||
} from '@/constants/common.constants'
|
||||
import { message, modal } from '@/util/common'
|
||||
import { navigateToCode } from '@/util/navigation'
|
||||
import {
|
||||
r_sys_tool_delete,
|
||||
@@ -28,7 +29,6 @@ import Permission from '@/components/common/Permission'
|
||||
const Tools = () => {
|
||||
const theme = useTheme()
|
||||
const navigate = useNavigate()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [tableParams, setTableParams] = useState<TableParam>({
|
||||
pagination: {
|
||||
current: 1,
|
||||
@@ -572,27 +572,25 @@ const Tools = () => {
|
||||
columns={dataColumns}
|
||||
pagination={tableParams.pagination}
|
||||
loading={isLoading}
|
||||
scroll={{ x: true }}
|
||||
onChange={handleOnTableChange}
|
||||
/>
|
||||
</Card>
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<FitFullscreen>
|
||||
<HideScrollbar
|
||||
style={{ padding: 20 }}
|
||||
isShowVerticalScrollbar
|
||||
autoHideWaitingTime={1000}
|
||||
>
|
||||
<FlexBox gap={20}>
|
||||
{toolbar}
|
||||
{table}
|
||||
</FlexBox>
|
||||
</HideScrollbar>
|
||||
</FitFullscreen>
|
||||
{contextHolder}
|
||||
</>
|
||||
<FitFullscreen>
|
||||
<HideScrollbar
|
||||
style={{ padding: 20 }}
|
||||
isShowVerticalScrollbar
|
||||
autoHideWaitingTime={1000}
|
||||
>
|
||||
<FlexBox gap={20}>
|
||||
{toolbar}
|
||||
{table}
|
||||
</FlexBox>
|
||||
</HideScrollbar>
|
||||
</FitFullscreen>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
DATABASE_SELECT_SUCCESS,
|
||||
DATABASE_UPDATE_SUCCESS
|
||||
} from '@/constants/common.constants'
|
||||
import { message, modal } from '@/util/common'
|
||||
import { hasPermission } from '@/util/auth'
|
||||
import { utcToLocalTime, isPastTime, localTimeToUtc, dayjsToUtc, getNowUtc } from '@/util/datetime'
|
||||
import {
|
||||
@@ -35,7 +36,6 @@ interface ChangePasswordFields extends UserUpdatePasswordParam {
|
||||
|
||||
const User = () => {
|
||||
const theme = useTheme()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
|
||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
||||
const [isDrawerEdit, setIsDrawerEdit] = useState(false)
|
||||
@@ -972,6 +972,7 @@ const User = () => {
|
||||
rowKey={(record) => record.id}
|
||||
pagination={tableParams.pagination}
|
||||
loading={isLoadingUserData}
|
||||
scroll={{ x: true }}
|
||||
onChange={handleOnTableChange}
|
||||
rowSelection={
|
||||
hasPermission('system:user:delete:multiple')
|
||||
@@ -1031,7 +1032,6 @@ const User = () => {
|
||||
>
|
||||
{addAndEditForm}
|
||||
</AntdDrawer>
|
||||
{contextHolder}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
DATABASE_INSERT_SUCCESS,
|
||||
DATABASE_SELECT_SUCCESS
|
||||
} from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { navigateToEdit } from '@/util/navigation'
|
||||
import {
|
||||
r_tool_category_get,
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
TOOL_HAS_BEEN_PUBLISHED,
|
||||
TOOL_UNDER_REVIEW
|
||||
} from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { navigateToRepository } from '@/util/navigation'
|
||||
import editorExtraLibs from '@/util/editorExtraLibs'
|
||||
import { r_tool_category_get, r_tool_detail, r_tool_update } from '@/services/tool'
|
||||
@@ -121,12 +122,14 @@ const Edit = () => {
|
||||
getTool()
|
||||
break
|
||||
case TOOL_UNDER_REVIEW:
|
||||
void message.error('保存失败:工具审核中')
|
||||
navigateToRepository(navigate)
|
||||
message.error('保存失败:工具审核中').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
break
|
||||
case TOOL_HAS_BEEN_PUBLISHED:
|
||||
void message.error('保存失败:工具已发布')
|
||||
navigateToRepository(navigate)
|
||||
message.error('保存失败:工具已发布').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
break
|
||||
default:
|
||||
void message.error('保存失败,请稍后重试')
|
||||
@@ -182,12 +185,14 @@ const Edit = () => {
|
||||
getTool()
|
||||
break
|
||||
case TOOL_UNDER_REVIEW:
|
||||
void message.error('保存失败:工具审核中')
|
||||
navigateToRepository(navigate)
|
||||
message.error('保存失败:工具审核中').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
break
|
||||
case TOOL_HAS_BEEN_PUBLISHED:
|
||||
void message.error('保存失败:工具已发布')
|
||||
navigateToRepository(navigate)
|
||||
message.error('保存失败:工具已发布').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
break
|
||||
default:
|
||||
void message.error('保存失败,请稍后重试')
|
||||
@@ -239,17 +244,20 @@ const Edit = () => {
|
||||
setHasEdited(false)
|
||||
break
|
||||
case 'PROCESSING':
|
||||
void message.warning('工具审核中,请勿修改')
|
||||
navigateToRepository(navigate)
|
||||
message.warning('工具审核中,请勿修改').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
break
|
||||
default:
|
||||
void message.warning('请先创建新版本后编辑工具')
|
||||
navigateToRepository(navigate)
|
||||
message.warning('请先创建新版本后编辑工具').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
}
|
||||
break
|
||||
case DATABASE_NO_RECORD_FOUND:
|
||||
void message.error('未找到指定工具')
|
||||
navigateToRepository(navigate)
|
||||
message.error('未找到指定工具').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
break
|
||||
default:
|
||||
void message.error('获取工具信息失败,请稍后重试')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import useStyles from '@/assets/css/pages/tools/source.style'
|
||||
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { getLoginStatus } from '@/util/auth'
|
||||
import { navigateToRepository, navigateToSource } from '@/util/navigation'
|
||||
import editorExtraLibs from '@/util/editorExtraLibs'
|
||||
@@ -52,8 +53,9 @@ const Source = () => {
|
||||
render(response.data!)
|
||||
break
|
||||
case DATABASE_NO_RECORD_FOUND:
|
||||
void message.error('未找到指定工具')
|
||||
navigateToRepository(navigate)
|
||||
void message.error('未找到指定工具').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
break
|
||||
default:
|
||||
void message.error('获取工具信息失败,请稍后重试')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { UIEvent } from 'react'
|
||||
import useStyles from '@/assets/css/pages/tools/store.style'
|
||||
import { DATABASE_SELECT_SUCCESS } from '@/constants/common.constants'
|
||||
import { checkDesktop } from '@/util/common'
|
||||
import { message, checkDesktop } from '@/util/common'
|
||||
import { r_tool_store_get } from '@/services/tool'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
import FitFullscreen from '@/components/common/FitFullscreen'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Icon from '@ant-design/icons'
|
||||
import useStyles from '@/assets/css/pages/tools/user.style'
|
||||
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants'
|
||||
import { checkDesktop } from '@/util/common'
|
||||
import { message, checkDesktop } from '@/util/common'
|
||||
import { navigateToRoot } from '@/util/navigation'
|
||||
import { r_sys_user_info_get_basic } from '@/services/system'
|
||||
import { r_tool_store_get_by_username } from '@/services/tool'
|
||||
@@ -40,7 +40,7 @@ const User = () => {
|
||||
return
|
||||
}
|
||||
setIsLoading(true)
|
||||
void message.loading({ content: '加载中', key: 'LOADING', duration: 0 })
|
||||
void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 })
|
||||
|
||||
void r_sys_user_info_get_basic(username!)
|
||||
.then((res) => {
|
||||
@@ -51,10 +51,9 @@ const User = () => {
|
||||
getTool(1)
|
||||
break
|
||||
case DATABASE_NO_RECORD_FOUND:
|
||||
void message.warning('用户不存在')
|
||||
setTimeout(() => {
|
||||
void message.warning('用户不存在').then(() => {
|
||||
navigateToRoot(navigate)
|
||||
}, 3000)
|
||||
})
|
||||
break
|
||||
default:
|
||||
void message.error('获取失败请稍后重试')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import useStyles from '@/assets/css/pages/tools/view.style'
|
||||
import { DATABASE_NO_RECORD_FOUND, DATABASE_SELECT_SUCCESS } from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { getLoginStatus } from '@/util/auth'
|
||||
import { navigateToRepository, navigateToRoot, navigateToView } from '@/util/navigation'
|
||||
import { r_tool_detail } from '@/services/tool'
|
||||
@@ -78,8 +79,9 @@ const View = () => {
|
||||
render(response.data!)
|
||||
break
|
||||
case DATABASE_NO_RECORD_FOUND:
|
||||
void message.error('未找到指定工具')
|
||||
navigateToRepository(navigate)
|
||||
void message.error('未找到指定工具').then(() => {
|
||||
navigateToRepository(navigate)
|
||||
})
|
||||
break
|
||||
default:
|
||||
void message.error('获取工具信息失败,请稍后重试')
|
||||
@@ -98,8 +100,9 @@ const View = () => {
|
||||
return
|
||||
}
|
||||
if (username === '!' && !getLoginStatus()) {
|
||||
void message.error('未登录')
|
||||
navigateToRoot(navigate)
|
||||
void message.error('未登录').then(() => {
|
||||
navigateToRoot(navigate)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (username !== '!' && ver) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
TOOL_SUBMIT_SUCCESS,
|
||||
TOOL_UNDER_REVIEW
|
||||
} from '@/constants/common.constants'
|
||||
import { checkDesktop } from '@/util/common'
|
||||
import { message, modal, checkDesktop } from '@/util/common'
|
||||
import { getLoginStatus } from '@/util/auth'
|
||||
import { navigateToEdit, navigateToSource, navigateToView } from '@/util/navigation'
|
||||
import {
|
||||
@@ -204,7 +204,6 @@ const ToolCard = ({ tools, onDelete, onUpgrade, onSubmit, onCancel }: ToolCardPr
|
||||
const Tools = () => {
|
||||
const { styles } = useStyles()
|
||||
const navigate = useNavigate()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [currentPage, setCurrentPage] = useState(0)
|
||||
const [hasNextPage, setHasNextPage] = useState(false)
|
||||
@@ -537,106 +536,97 @@ const Tools = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<FitFullscreen>
|
||||
<HideScrollbar isShowVerticalScrollbar autoHideWaitingTime={1000}>
|
||||
<FlexBox direction={'vertical'} className={styles.root}>
|
||||
<FlexBox direction={'horizontal'} className={styles.ownContent}>
|
||||
<UrlCard icon={IconOxygenNewProject} url={'/create'}>
|
||||
创建工具
|
||||
</UrlCard>
|
||||
{toolData &&
|
||||
Object.values(
|
||||
toolData.reduce((result: Record<string, ToolVo[]>, item) => {
|
||||
result[item.toolId] = result[item.toolId] || []
|
||||
result[item.toolId].push(item)
|
||||
return result
|
||||
}, {})
|
||||
).map((value) => (
|
||||
<ToolCard
|
||||
key={JSON.stringify(value)}
|
||||
tools={value}
|
||||
onDelete={handleOnDeleteTool}
|
||||
onUpgrade={handleOnUpgradeTool}
|
||||
onSubmit={handleOnSubmitTool}
|
||||
onCancel={handleOnCancelTool}
|
||||
/>
|
||||
))}
|
||||
{hasNextPage && <LoadMoreCard onClick={handleOnLoadMore} />}
|
||||
</FlexBox>
|
||||
{starToolData.length ? (
|
||||
<>
|
||||
<FlexBox
|
||||
direction={'horizontal'}
|
||||
className={styles.favoriteDivider}
|
||||
>
|
||||
<div />
|
||||
<div className={styles.dividerText}>收藏</div>
|
||||
<div />
|
||||
</FlexBox>
|
||||
<FlexBox direction={'horizontal'} className={styles.starContent}>
|
||||
{starToolData
|
||||
?.reduce((previousValue: ToolVo[], currentValue) => {
|
||||
if (
|
||||
!previousValue.some(
|
||||
(value) =>
|
||||
value.author.id ===
|
||||
currentValue.author.id &&
|
||||
value.toolId === currentValue.toolId
|
||||
)
|
||||
) {
|
||||
previousValue.push(currentValue)
|
||||
}
|
||||
return previousValue
|
||||
}, [])
|
||||
.map((item) => {
|
||||
const tools = starToolData.filter(
|
||||
(value) =>
|
||||
value.author.id === item.author.id &&
|
||||
value.toolId === item.toolId
|
||||
)
|
||||
const webTool = tools.find(
|
||||
(value) => value.platform === 'WEB'
|
||||
)
|
||||
const desktopTool = tools.find(
|
||||
(value) => value.platform === 'DESKTOP'
|
||||
)
|
||||
const androidTool = tools.find(
|
||||
(value) => value.platform === 'ANDROID'
|
||||
)
|
||||
const firstTool =
|
||||
(checkDesktop()
|
||||
? desktopTool || webTool
|
||||
: webTool || desktopTool) || androidTool
|
||||
|
||||
return (
|
||||
<StoreCard
|
||||
key={firstTool!.id}
|
||||
icon={firstTool!.icon}
|
||||
toolName={firstTool!.name}
|
||||
toolId={firstTool!.toolId}
|
||||
toolDesc={firstTool!.description}
|
||||
author={firstTool!.author}
|
||||
ver={firstTool!.ver}
|
||||
platform={firstTool!.platform}
|
||||
supportPlatform={tools.map(
|
||||
(value) => value.platform
|
||||
)}
|
||||
favorite={firstTool!.favorite}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{hasNextStarPage && (
|
||||
<LoadMoreCard onClick={handleOnLoadMoreStar} />
|
||||
)}
|
||||
</FlexBox>
|
||||
</>
|
||||
) : undefined}
|
||||
<FitFullscreen>
|
||||
<HideScrollbar isShowVerticalScrollbar autoHideWaitingTime={1000}>
|
||||
<FlexBox direction={'vertical'} className={styles.root}>
|
||||
<FlexBox direction={'horizontal'} className={styles.ownContent}>
|
||||
<UrlCard icon={IconOxygenNewProject} url={'/create'}>
|
||||
创建工具
|
||||
</UrlCard>
|
||||
{toolData &&
|
||||
Object.values(
|
||||
toolData.reduce((result: Record<string, ToolVo[]>, item) => {
|
||||
result[item.toolId] = result[item.toolId] || []
|
||||
result[item.toolId].push(item)
|
||||
return result
|
||||
}, {})
|
||||
).map((value) => (
|
||||
<ToolCard
|
||||
key={JSON.stringify(value)}
|
||||
tools={value}
|
||||
onDelete={handleOnDeleteTool}
|
||||
onUpgrade={handleOnUpgradeTool}
|
||||
onSubmit={handleOnSubmitTool}
|
||||
onCancel={handleOnCancelTool}
|
||||
/>
|
||||
))}
|
||||
{hasNextPage && <LoadMoreCard onClick={handleOnLoadMore} />}
|
||||
</FlexBox>
|
||||
</HideScrollbar>
|
||||
</FitFullscreen>
|
||||
{contextHolder}
|
||||
</>
|
||||
{starToolData.length ? (
|
||||
<>
|
||||
<FlexBox direction={'horizontal'} className={styles.favoriteDivider}>
|
||||
<div />
|
||||
<div className={styles.dividerText}>收藏</div>
|
||||
<div />
|
||||
</FlexBox>
|
||||
<FlexBox direction={'horizontal'} className={styles.starContent}>
|
||||
{starToolData
|
||||
?.reduce((previousValue: ToolVo[], currentValue) => {
|
||||
if (
|
||||
!previousValue.some(
|
||||
(value) =>
|
||||
value.author.id === currentValue.author.id &&
|
||||
value.toolId === currentValue.toolId
|
||||
)
|
||||
) {
|
||||
previousValue.push(currentValue)
|
||||
}
|
||||
return previousValue
|
||||
}, [])
|
||||
.map((item) => {
|
||||
const tools = starToolData.filter(
|
||||
(value) =>
|
||||
value.author.id === item.author.id &&
|
||||
value.toolId === item.toolId
|
||||
)
|
||||
const webTool = tools.find(
|
||||
(value) => value.platform === 'WEB'
|
||||
)
|
||||
const desktopTool = tools.find(
|
||||
(value) => value.platform === 'DESKTOP'
|
||||
)
|
||||
const androidTool = tools.find(
|
||||
(value) => value.platform === 'ANDROID'
|
||||
)
|
||||
const firstTool =
|
||||
(checkDesktop()
|
||||
? desktopTool || webTool
|
||||
: webTool || desktopTool) || androidTool
|
||||
|
||||
return (
|
||||
<StoreCard
|
||||
key={firstTool!.id}
|
||||
icon={firstTool!.icon}
|
||||
toolName={firstTool!.name}
|
||||
toolId={firstTool!.toolId}
|
||||
toolDesc={firstTool!.description}
|
||||
author={firstTool!.author}
|
||||
ver={firstTool!.ver}
|
||||
platform={firstTool!.platform}
|
||||
supportPlatform={tools.map(
|
||||
(value) => value.platform
|
||||
)}
|
||||
favorite={firstTool!.favorite}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{hasNextStarPage && <LoadMoreCard onClick={handleOnLoadMoreStar} />}
|
||||
</FlexBox>
|
||||
</>
|
||||
) : undefined}
|
||||
</FlexBox>
|
||||
</HideScrollbar>
|
||||
</FitFullscreen>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { arrayMove, SortableContext } from '@dnd-kit/sortable'
|
||||
import type { DragEndEvent } from '@dnd-kit/core/dist/types'
|
||||
import useStyles from '@/assets/css/pages/tools-framework.style'
|
||||
import { tools } from '@/router/tools'
|
||||
import { checkDesktop, getToolMenuItem, saveToolMenuItem } from '@/util/common'
|
||||
import { message, checkDesktop, getToolMenuItem, saveToolMenuItem } from '@/util/common'
|
||||
import { getViewPath } from '@/util/navigation'
|
||||
import FitFullscreen from '@/components/common/FitFullscreen'
|
||||
import Sidebar from '@/components/common/Sidebar'
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
PERMISSION_ACCESS_DENIED,
|
||||
PERMISSION_LOGIN_USERNAME_PASSWORD_ERROR
|
||||
} from '@/constants/common.constants'
|
||||
import { message, notification, modal } from '@/util/common'
|
||||
import { utcToLocalTime } from '@/util/datetime'
|
||||
import { getUserInfo, removeToken } from '@/util/auth'
|
||||
import { r_sys_user_info_change_password, r_sys_user_info_update } from '@/services/system'
|
||||
@@ -21,7 +22,6 @@ import HideScrollbar from '@/components/common/HideScrollbar'
|
||||
|
||||
const User = () => {
|
||||
const { styles, theme } = useStyles()
|
||||
const [modal, contextHolder] = AntdModal.useModal()
|
||||
const [form] = AntdForm.useForm<UserInfoUpdateParam>()
|
||||
const formValues = AntdForm.useWatch([], form)
|
||||
const [twoFactorForm] = AntdForm.useForm<{ twoFactorCode: string }>()
|
||||
@@ -180,7 +180,6 @@ const User = () => {
|
||||
const response = res.data
|
||||
switch (response.code) {
|
||||
case DATABASE_UPDATE_SUCCESS:
|
||||
void message.success('密码修改成功,请重新登录')
|
||||
removeToken()
|
||||
notification.info({
|
||||
message: '已退出登录',
|
||||
@@ -191,9 +190,9 @@ const User = () => {
|
||||
/>
|
||||
)
|
||||
})
|
||||
setTimeout(() => {
|
||||
message.success('密码修改成功,请重新登录').then(() => {
|
||||
window.location.reload()
|
||||
}, 1500)
|
||||
})
|
||||
resolve()
|
||||
break
|
||||
case PERMISSION_ACCESS_DENIED:
|
||||
@@ -312,7 +311,7 @@ const User = () => {
|
||||
return
|
||||
}
|
||||
setIsLoading(true)
|
||||
void message.loading({ content: '加载中', key: 'LOADING', duration: 0 })
|
||||
void message.loading({ content: '加载中……', key: 'LOADING', duration: 0 })
|
||||
void r_auth_two_factor_create()
|
||||
.then((res) => {
|
||||
message.destroy('LOADING')
|
||||
@@ -447,192 +446,180 @@ const User = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<FitFullscreen>
|
||||
<HideScrollbar
|
||||
isShowVerticalScrollbar
|
||||
autoHideWaitingTime={1000}
|
||||
className={styles.root}
|
||||
>
|
||||
<Card className={styles.content}>
|
||||
<FlexBox className={styles.info} direction={'horizontal'}>
|
||||
<AntdTooltip title={'点击获取新头像'}>
|
||||
<div className={styles.avatarBox}>
|
||||
<AntdAvatar
|
||||
src={
|
||||
<img
|
||||
src={`data:image/png;base64,${avatar}`}
|
||||
alt={'Avatar'}
|
||||
/>
|
||||
}
|
||||
size={144}
|
||||
style={{
|
||||
background: theme.colorBgLayout,
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
className={styles.avatar}
|
||||
onClick={handleOnChangeAvatar}
|
||||
/>
|
||||
</div>
|
||||
</AntdTooltip>
|
||||
<FlexBox className={styles.infoName}>
|
||||
<div className={styles.nickname}>
|
||||
{userWithPowerInfoVo?.userInfo.nickname}
|
||||
</div>
|
||||
<a
|
||||
className={styles.url}
|
||||
onClick={handleOnCopyToClipboard(userWithPowerInfoVo?.username)}
|
||||
>
|
||||
{userWithPowerInfoVo?.username &&
|
||||
new URL(
|
||||
`/store/${userWithPowerInfoVo.username}`,
|
||||
import.meta.env.VITE_UI_URL
|
||||
).href}
|
||||
<Icon component={IconOxygenCopy} />
|
||||
</a>
|
||||
</FlexBox>
|
||||
<FitFullscreen>
|
||||
<HideScrollbar
|
||||
isShowVerticalScrollbar
|
||||
autoHideWaitingTime={1000}
|
||||
className={styles.root}
|
||||
>
|
||||
<Card className={styles.content}>
|
||||
<FlexBox className={styles.info} direction={'horizontal'}>
|
||||
<AntdTooltip title={'点击获取新头像'}>
|
||||
<div className={styles.avatarBox}>
|
||||
<AntdAvatar
|
||||
src={
|
||||
<img
|
||||
src={`data:image/png;base64,${avatar}`}
|
||||
alt={'Avatar'}
|
||||
/>
|
||||
}
|
||||
size={144}
|
||||
style={{
|
||||
background: theme.colorBgLayout,
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
className={styles.avatar}
|
||||
onClick={handleOnChangeAvatar}
|
||||
/>
|
||||
</div>
|
||||
</AntdTooltip>
|
||||
<FlexBox className={styles.infoName}>
|
||||
<div className={styles.nickname}>
|
||||
{userWithPowerInfoVo?.userInfo.nickname}
|
||||
</div>
|
||||
<a
|
||||
className={styles.url}
|
||||
onClick={handleOnCopyToClipboard(userWithPowerInfoVo?.username)}
|
||||
>
|
||||
{userWithPowerInfoVo?.username &&
|
||||
new URL(
|
||||
`/store/${userWithPowerInfoVo.username}`,
|
||||
import.meta.env.VITE_UI_URL
|
||||
).href}
|
||||
<Icon component={IconOxygenCopy} />
|
||||
</a>
|
||||
</FlexBox>
|
||||
<FlexBox direction={'horizontal'} className={styles.header}>
|
||||
<div className={styles.title}>档案管理</div>
|
||||
<FlexBox className={styles.operation} direction={'horizontal'}>
|
||||
<AntdButton onClick={handleOnReset} loading={isLoading}>
|
||||
重置
|
||||
</AntdButton>
|
||||
<AntdButton
|
||||
onClick={handleOnSave}
|
||||
type={'primary'}
|
||||
disabled={isLoading || !isSubmittable}
|
||||
>
|
||||
保存
|
||||
</AntdButton>
|
||||
</FlexBox>
|
||||
</FlexBox>
|
||||
<FlexBox direction={'horizontal'} className={styles.header}>
|
||||
<div className={styles.title}>档案管理</div>
|
||||
<FlexBox className={styles.operation} direction={'horizontal'}>
|
||||
<AntdButton onClick={handleOnReset} loading={isLoading}>
|
||||
重置
|
||||
</AntdButton>
|
||||
<AntdButton
|
||||
onClick={handleOnSave}
|
||||
type={'primary'}
|
||||
disabled={isLoading || !isSubmittable}
|
||||
>
|
||||
保存
|
||||
</AntdButton>
|
||||
</FlexBox>
|
||||
<div className={styles.divider} />
|
||||
<FlexBox className={styles.list}>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>昵称</div>
|
||||
<div className={styles.input}>
|
||||
<AntdForm form={form}>
|
||||
<AntdForm.Item
|
||||
name={'nickname'}
|
||||
rules={[
|
||||
{ required: true, whitespace: true },
|
||||
{ min: 3, message: '昵称至少为3个字符' }
|
||||
]}
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<AntdInput
|
||||
maxLength={20}
|
||||
showCount
|
||||
disabled={isLoading}
|
||||
placeholder={'请输入昵称'}
|
||||
/>
|
||||
</AntdForm.Item>
|
||||
</AntdForm>
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>用户名</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput disabled value={userWithPowerInfoVo?.username} />
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>邮箱</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput
|
||||
disabled
|
||||
value={userWithPowerInfoVo?.userInfo.email}
|
||||
/>
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>注册时间</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput
|
||||
disabled
|
||||
value={utcToLocalTime(
|
||||
userWithPowerInfoVo?.createTime ?? ''
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</FlexBox>
|
||||
</FlexBox>
|
||||
<div className={styles.divider} />
|
||||
<FlexBox className={styles.list}>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>上次登录 IP</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput disabled value={userWithPowerInfoVo?.lastLoginIp} />
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>上次登录时间</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput
|
||||
disabled
|
||||
value={utcToLocalTime(
|
||||
userWithPowerInfoVo?.lastLoginTime ?? ''
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>密码</div>
|
||||
<div className={styles.input}>
|
||||
<AntdSpace.Compact>
|
||||
<AntdInput disabled value={'********'} />
|
||||
<AntdButton
|
||||
type={'primary'}
|
||||
title={'更改密码'}
|
||||
disabled={isLoading}
|
||||
onClick={handleOnChangePassword}
|
||||
>
|
||||
<Icon component={IconOxygenRefresh} />
|
||||
</AntdButton>
|
||||
</AntdSpace.Compact>
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>双因素</div>
|
||||
<div className={styles.input}>
|
||||
<AntdSpace.Compact>
|
||||
</FlexBox>
|
||||
<div className={styles.divider} />
|
||||
<FlexBox className={styles.list}>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>昵称</div>
|
||||
<div className={styles.input}>
|
||||
<AntdForm form={form}>
|
||||
<AntdForm.Item
|
||||
name={'nickname'}
|
||||
rules={[
|
||||
{ required: true, whitespace: true },
|
||||
{ min: 3, message: '昵称至少为3个字符' }
|
||||
]}
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<AntdInput
|
||||
disabled
|
||||
style={{
|
||||
color: userWithPowerInfoVo?.twoFactor
|
||||
? theme.colorPrimary
|
||||
: undefined
|
||||
}}
|
||||
value={
|
||||
userWithPowerInfoVo?.twoFactor ? '已设置' : '未设置'
|
||||
maxLength={20}
|
||||
showCount
|
||||
disabled={isLoading}
|
||||
placeholder={'请输入昵称'}
|
||||
/>
|
||||
</AntdForm.Item>
|
||||
</AntdForm>
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>用户名</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput disabled value={userWithPowerInfoVo?.username} />
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>邮箱</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput disabled value={userWithPowerInfoVo?.userInfo.email} />
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>注册时间</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput
|
||||
disabled
|
||||
value={utcToLocalTime(userWithPowerInfoVo?.createTime ?? '')}
|
||||
/>
|
||||
</div>
|
||||
</FlexBox>
|
||||
</FlexBox>
|
||||
<div className={styles.divider} />
|
||||
<FlexBox className={styles.list}>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>上次登录 IP</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput disabled value={userWithPowerInfoVo?.lastLoginIp} />
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>上次登录时间</div>
|
||||
<div className={styles.input}>
|
||||
<AntdInput
|
||||
disabled
|
||||
value={utcToLocalTime(userWithPowerInfoVo?.lastLoginTime ?? '')}
|
||||
/>
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>密码</div>
|
||||
<div className={styles.input}>
|
||||
<AntdSpace.Compact>
|
||||
<AntdInput disabled value={'********'} />
|
||||
<AntdButton
|
||||
type={'primary'}
|
||||
title={'更改密码'}
|
||||
disabled={isLoading}
|
||||
onClick={handleOnChangePassword}
|
||||
>
|
||||
<Icon component={IconOxygenRefresh} />
|
||||
</AntdButton>
|
||||
</AntdSpace.Compact>
|
||||
</div>
|
||||
</FlexBox>
|
||||
<FlexBox className={styles.row} direction={'horizontal'}>
|
||||
<div className={styles.label}>双因素</div>
|
||||
<div className={styles.input}>
|
||||
<AntdSpace.Compact>
|
||||
<AntdInput
|
||||
disabled
|
||||
style={{
|
||||
color: userWithPowerInfoVo?.twoFactor
|
||||
? theme.colorPrimary
|
||||
: undefined
|
||||
}}
|
||||
value={userWithPowerInfoVo?.twoFactor ? '已设置' : '未设置'}
|
||||
/>
|
||||
<AntdButton
|
||||
type={'primary'}
|
||||
title={userWithPowerInfoVo?.twoFactor ? '解绑' : '绑定'}
|
||||
disabled={isLoading}
|
||||
onClick={handleOnChangeTwoFactor(
|
||||
userWithPowerInfoVo?.twoFactor ?? false
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
component={
|
||||
userWithPowerInfoVo?.twoFactor
|
||||
? IconOxygenUnlock
|
||||
: IconOxygenLock
|
||||
}
|
||||
/>
|
||||
<AntdButton
|
||||
type={'primary'}
|
||||
title={userWithPowerInfoVo?.twoFactor ? '解绑' : '绑定'}
|
||||
disabled={isLoading}
|
||||
onClick={handleOnChangeTwoFactor(
|
||||
userWithPowerInfoVo?.twoFactor ?? false
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
component={
|
||||
userWithPowerInfoVo?.twoFactor
|
||||
? IconOxygenUnlock
|
||||
: IconOxygenLock
|
||||
}
|
||||
/>
|
||||
</AntdButton>
|
||||
</AntdSpace.Compact>
|
||||
</div>
|
||||
</FlexBox>
|
||||
</AntdButton>
|
||||
</AntdSpace.Compact>
|
||||
</div>
|
||||
</FlexBox>
|
||||
</Card>
|
||||
</HideScrollbar>
|
||||
</FitFullscreen>
|
||||
{contextHolder}
|
||||
</>
|
||||
</FlexBox>
|
||||
</Card>
|
||||
</HideScrollbar>
|
||||
</FitFullscreen>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
PERMISSION_UNAUTHORIZED,
|
||||
SYSTEM_REQUEST_TOO_FREQUENT
|
||||
} from '@/constants/common.constants'
|
||||
import { message } from '@/util/common'
|
||||
import { getRedirectUrl } from '@/util/route'
|
||||
import { getToken, setToken, removeToken } from '@/util/auth'
|
||||
|
||||
@@ -68,34 +69,36 @@ service.interceptors.response.use(
|
||||
switch (response.data.code) {
|
||||
case PERMISSION_UNAUTHORIZED:
|
||||
removeToken()
|
||||
void message.error({
|
||||
content: (
|
||||
<>
|
||||
<strong>未登录</strong>
|
||||
</>
|
||||
),
|
||||
key: 'NO_LOGIN'
|
||||
})
|
||||
setTimeout(() => {
|
||||
location.reload()
|
||||
}, 1500)
|
||||
message
|
||||
.error({
|
||||
content: (
|
||||
<>
|
||||
<strong>未登录</strong>
|
||||
</>
|
||||
),
|
||||
key: 'NO_LOGIN'
|
||||
})
|
||||
.then(() => {
|
||||
location.reload()
|
||||
})
|
||||
throw response?.data
|
||||
case PERMISSION_TOKEN_ILLEGAL:
|
||||
case PERMISSION_TOKEN_HAS_EXPIRED:
|
||||
removeToken()
|
||||
void message.error({
|
||||
content: (
|
||||
<>
|
||||
<strong>登录已过期</strong>
|
||||
</>
|
||||
),
|
||||
key: 'LOGIN_HAS_EXPIRED'
|
||||
})
|
||||
setTimeout(() => {
|
||||
location.replace(
|
||||
getRedirectUrl('/login', `${location.pathname}${location.search}`)
|
||||
)
|
||||
}, 1500)
|
||||
message
|
||||
.error({
|
||||
content: (
|
||||
<>
|
||||
<strong>登录已过期</strong>
|
||||
</>
|
||||
),
|
||||
key: 'LOGIN_HAS_EXPIRED'
|
||||
})
|
||||
.then(() => {
|
||||
location.replace(
|
||||
getRedirectUrl('/login', `${location.pathname}${location.search}`)
|
||||
)
|
||||
})
|
||||
throw response?.data
|
||||
case PERMISSION_ACCESS_DENIED:
|
||||
void message.error({
|
||||
|
||||
@@ -3,6 +3,25 @@ import { floor } from 'lodash'
|
||||
import { STORAGE_TOOL_MENU_ITEM_KEY } from '@/constants/common.constants'
|
||||
import { getLocalStorage, setLocalStorage } from '@/util/browser'
|
||||
import FullscreenLoadingMask from '@/components/common/FullscreenLoadingMask'
|
||||
import { MessageInstance } from 'antd/es/message/interface'
|
||||
import { NotificationInstance } from 'antd/es/notification/interface'
|
||||
import { HookAPI } from 'antd/es/modal/useModal'
|
||||
|
||||
let message: MessageInstance
|
||||
let notification: NotificationInstance
|
||||
let modal: HookAPI
|
||||
|
||||
export const init = (
|
||||
messageInstance: MessageInstance,
|
||||
notificationInstance: NotificationInstance,
|
||||
modalInstance: HookAPI
|
||||
) => {
|
||||
message = messageInstance
|
||||
notification = notificationInstance
|
||||
modal = modalInstance
|
||||
}
|
||||
|
||||
export { message, notification, modal }
|
||||
|
||||
export const randomInt = (start: number, end: number) => {
|
||||
if (start > end) {
|
||||
|
||||
Reference in New Issue
Block a user