diff --git a/build/resolvers/antd.ts b/build/resolvers/antd.ts
index 469af1b..3d18000 100644
--- a/build/resolvers/antd.ts
+++ b/build/resolvers/antd.ts
@@ -1,4 +1,4 @@
-export function kebabCase(key: string): string {
+export const kebabCase = (key: string) => {
const result: string = key.replace(/([A-Z])/g, ' $1').trim()
return result.split(' ').join('-').toLowerCase()
}
@@ -395,7 +395,7 @@ const isAntd = (compName: string): boolean => {
return antdNames.has(compName)
}
-export function AntDesignResolver(options: AntDesignResolverOptions = {}): ComponentResolver {
+export const AntDesignResolver = (options: AntDesignResolverOptions = {}): ComponentResolver => {
return {
type: 'component',
resolve: (name: string) => {
diff --git a/src/AuthRoute.tsx b/src/AuthRoute.tsx
index 7335e5e..35b6a77 100644
--- a/src/AuthRoute.tsx
+++ b/src/AuthRoute.tsx
@@ -1,5 +1,6 @@
import { getLoginStatus } from '@/utils/auth.ts'
import { PRODUCTION_NAME } from '@/constants/Common.constants.ts'
+import { getRedirectUrl } from '@/utils/common.ts'
const AuthRoute = () => {
const matches = useMatches()
@@ -16,9 +17,7 @@ const AuthRoute = () => {
if (matches.some(({ handle }) => (handle as RouteHandle)?.auth) && !isLogin) {
return (
)
}
diff --git a/src/assets/css/constants.scss b/src/assets/css/constants.scss
index 18e8338..3e6e1b5 100644
--- a/src/assets/css/constants.scss
+++ b/src/assets/css/constants.scss
@@ -1,6 +1,9 @@
$origin-color: white;
$main-color: #4E47BB;
$secondary-color: #BAB8E5;
+$error-color: #ff4d4f;
+$error-secondary-color: #ff7875;
+$blue-color: #1677ff;
$active-color: #EBECFFD;
$background-color: #F5F5F5;
$font-main-color: #4D4D4D;
diff --git a/src/assets/css/pages/tools-framework.scss b/src/assets/css/pages/tools-framework.scss
index b95691f..f9e08cf 100644
--- a/src/assets/css/pages/tools-framework.scss
+++ b/src/assets/css/pages/tools-framework.scss
@@ -13,7 +13,6 @@ body {
user-select: none;
transition: all .3s;
white-space: nowrap;
- overflow: hidden;
.title {
display: flex;
@@ -21,6 +20,7 @@ body {
font-weight: bold;
padding: 10px 14px;
color: constants.$main-color;
+ overflow: hidden;
.icon-box {
display: flex;
@@ -153,12 +153,10 @@ body {
animation: 0.3s ease;
@include mixins.unique-keyframes {
0% {
- display: block;
transform: translateX(-10px);
opacity: 0;
}
100% {
- display: block;
transform: translateX(0);
opacity: 1;
}
@@ -188,14 +186,14 @@ body {
padding: 8px 14px;
color: constants.$main-color;
- .icon-box {
+ .icon-user {
display: flex;
justify-content: center;
align-items: center;
margin-left: 4px;
padding: 10px;
- width: 32px;
- height: 32px;
+ width: 36px;
+ height: 36px;
font-size: constants.$SIZE_ICON_XS;
border: 2px constants.$font-secondary-color solid;
color: constants.$font-secondary-color;
@@ -205,10 +203,27 @@ body {
.text {
flex: 1;
- padding-left: 8px;
+ padding-left: 10px;
font-size: 1.4em;
color: constants.$font-main-color;
user-select: text;
+
+ a{
+ color: constants.$main-color;
+ text-decoration: underline;
+ }
+ }
+
+ .icon-exit {
+ font-size: constants.$SIZE_ICON_XS;
+ color: constants.$error-color;
+ padding: 6px 10px;
+ cursor: pointer;
+
+ &:hover {
+ border-radius: 8px;
+ background-color: constants.$background-color;
+ }
}
}
@@ -234,9 +249,50 @@ body {
}
.footer {
+ position: relative;
.text {
display: none;
}
+
+ .submenu-exit {
+ display: none;
+ position: absolute;
+ padding-left: 6px;
+ left: 100%;
+
+ .content {
+ padding: 8px;
+ border-radius: 8px;
+ background-color: constants.$origin-color;
+
+ .icon-exit {
+ padding: 4px 8px;
+ &:hover {
+ border-radius: 8px;
+ background-color: constants.$background-color;
+ }
+ }
+ }
+
+ &.hide {
+ display: none!important;
+ }
+ }
+
+ &:hover .submenu-exit {
+ display: block;
+ animation: 0.3s ease;
+ @include mixins.unique-keyframes {
+ 0% {
+ transform: translateX(-10px);
+ opacity: 0;
+ }
+ 100% {
+ transform: translateX(0);
+ opacity: 1;
+ }
+ }
+ }
}
}
}
diff --git a/src/assets/svg/exit.svg b/src/assets/svg/exit.svg
new file mode 100644
index 0000000..12a1804
--- /dev/null
+++ b/src/assets/svg/exit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/pages/ToolsFramework.tsx b/src/pages/ToolsFramework.tsx
index c29b28f..20f62a9 100644
--- a/src/pages/ToolsFramework.tsx
+++ b/src/pages/ToolsFramework.tsx
@@ -4,9 +4,15 @@ import '@/assets/css/pages/tools-framework.scss'
import Icon from '@ant-design/icons'
import { toolsJsonObjects } from '@/router/tools.tsx'
import HideScrollbar, { HideScrollbarElement } from '@/components/common/HideScrollbar.tsx'
-import { getLocalStorage, setLocalStorage } from '@/utils/common.ts'
+import { getLocalStorage, getRedirectUrl, setLocalStorage } from '@/utils/common.ts'
+import { getLoginStatus, logout } from '@/utils/auth.ts'
+import { NavLink, Outlet } from 'react-router-dom'
const ToolsFramework: React.FC = () => {
+ const matches = useMatches()
+ const lastMatch = matches.reduce((_, second) => second)
+ const location = useLocation()
+ const navigate = useNavigate()
const hideScrollbarRef = useRef(null)
const [submenuTop, setSubmenuTop] = useState(0)
const [submenuLeft, setSubmenuLeft] = useState(0)
@@ -37,6 +43,21 @@ const ToolsFramework: React.FC = () => {
}
}
+ const handleClickAvatar = () => {
+ if (getLoginStatus()) {
+ navigate(`${lastMatch.pathname}${location.search}`)
+ } else {
+ navigate(getRedirectUrl('/login', `${lastMatch.pathname}${location.search}`))
+ }
+ }
+
+ const handleLogout = () => {
+ logout()
+ setTimeout(() => {
+ window.location.reload()
+ }, 1500)
+ }
+
return (
<>
@@ -183,13 +204,42 @@ const ToolsFramework: React.FC = () => {
-
+
- 未登录
+
+ 未
+
+ 登录
+
+
+
+ 已登录
+
+
-
+
+
+
>
)
diff --git a/src/router/tools.tsx b/src/router/tools.tsx
index a3a4fcd..997809a 100644
--- a/src/router/tools.tsx
+++ b/src/router/tools.tsx
@@ -309,4 +309,9 @@ const tools: RouteObject[] = toolsJsonObjects.map((value) => ({
}))
}))
+tools.push({
+ path: '*',
+ element:
+})
+
export default tools
diff --git a/src/services/index.tsx b/src/services/index.tsx
index d89ba76..3d3a308 100644
--- a/src/services/index.tsx
+++ b/src/services/index.tsx
@@ -42,7 +42,7 @@ service.interceptors.request.use(
) {
await axios
.get(import.meta.env.VITE_API_TOKEN_URL, {
- headers: { token }
+ headers: { Authorization: `Bearer ${token}` }
})
.then((value: AxiosResponse<_Response>) => {
const response = value.data
@@ -53,7 +53,7 @@ service.interceptors.request.use(
}
token = getToken()
- config.headers.set('token', token)
+ config.headers.set('Authorization', `Bearer ${token}`)
}
return config
},
@@ -74,7 +74,7 @@ service.interceptors.response.use(
登录已过期
>
)
- setTimeout(function () {
+ setTimeout(() => {
location.reload()
}, 1500)
throw response?.data
diff --git a/src/utils/auth.ts b/src/utils/auth.ts
index 097e112..a923968 100644
--- a/src/utils/auth.ts
+++ b/src/utils/auth.ts
@@ -1,27 +1,28 @@
-import { clearLocalStorage, getCaptcha, getLocalStorage, setLocalStorage } from './common'
+import { getCaptcha, getLocalStorage, removeLocalStorage, setLocalStorage } from './common'
import { SYSTEM_OK, TOKEN_NAME } from '@/constants/Common.constants'
import request from '@/services'
let captcha: Captcha
-export async function login(username: string, password: string) {
+export const login = async (username: string, password: string) => {
return await request.post('/login', {
username,
password
})
}
-export function logout(): void {
- void request.get('/logout').finally(() => {
- clearLocalStorage()
+export const logout = () => {
+ void request.post('/logout').finally(() => {
+ removeLocalStorage('userInfo')
+ removeLocalStorage(TOKEN_NAME)
})
}
-export function getLoginStatus(): boolean {
+export const getLoginStatus = () => {
return getLocalStorage(TOKEN_NAME) !== null
}
-export async function getUser(): Promise {
+export const getUser = async (): Promise => {
if (getLocalStorage('userInfo') !== null) {
return new Promise((resolve) => {
resolve(JSON.parse(getLocalStorage('userInfo') as string) as User)
@@ -30,7 +31,7 @@ export async function getUser(): Promise {
return requestUser()
}
-export async function requestUser(): Promise {
+export const requestUser = async () => {
let user: User | null
await request.get('/user/info').then((value) => {
@@ -49,17 +50,17 @@ export async function requestUser(): Promise {
})
}
-export async function getUsername(): Promise {
+export const getUsername = async () => {
const user = await getUser()
return user.username
}
-export function getCaptchaSrc(): string {
+export const getCaptchaSrc = () => {
captcha = getCaptcha(300, 150, 4)
return captcha.base64Src
}
-export function verifyCaptcha(value: string): boolean {
+export const verifyCaptcha = (value: string) => {
return captcha.value.toLowerCase() === value.replace(/\s*/g, '').toLowerCase()
}
diff --git a/src/utils/common.ts b/src/utils/common.ts
index 7d0f9ce..04d1244 100644
--- a/src/utils/common.ts
+++ b/src/utils/common.ts
@@ -1,6 +1,6 @@
import { TOKEN_NAME } from '@/constants/Common.constants'
-export function getQueryVariable(variable: string): string | null {
+export const getQueryVariable = (variable: string) => {
const query = window.location.search.substring(1)
const vars = query.split('&')
for (const value of vars) {
@@ -12,12 +12,12 @@ export function getQueryVariable(variable: string): string | null {
return null
}
-export function setCookie(
+export const setCookie = (
name: string,
value: string,
daysToLive: number | null,
path: string | null
-): void {
+) => {
let cookie = `${name}=${encodeURIComponent(value)}`
if (typeof daysToLive === 'number') {
@@ -31,15 +31,15 @@ export function setCookie(
document.cookie = cookie
}
-export function setLocalStorage(name: string, value: string): void {
+export const setLocalStorage = (name: string, value: string) => {
localStorage.setItem(name, value)
}
-export function setToken(token: string): void {
+export const setToken = (token: string) => {
setLocalStorage(TOKEN_NAME, token)
}
-export function getCookie(name: string): string | null {
+export const getCookie = (name: string) => {
const cookieArr = document.cookie.split(';')
for (const cookie of cookieArr) {
@@ -52,31 +52,31 @@ export function getCookie(name: string): string | null {
return null
}
-export function getLocalStorage(name: string): string | null {
+export const getLocalStorage = (name: string) => {
return localStorage.getItem(name)
}
-export function getToken(): string | null {
+export const getToken = () => {
return getLocalStorage(TOKEN_NAME)
}
-export function removeCookie(name: string): void {
+export const removeCookie = (name: string) => {
document.cookie = `${name}=; max-age=0`
}
-export function removeLocalStorage(name: string): void {
+export const removeLocalStorage = (name: string) => {
localStorage.removeItem(name)
}
-export function removeToken(): void {
+export const removeToken = () => {
removeLocalStorage(TOKEN_NAME)
}
-export function clearLocalStorage(): void {
+export const clearLocalStorage = () => {
localStorage.clear()
}
-export function getCaptcha(width: number, high: number, num: number): Captcha {
+export const getCaptcha = (width: number, high: number, num: number) => {
const CHARTS = '23456789ABCDEFGHJKLMNPRSTUVWXYZabcdefghijklmnpqrstuvwxyz'.split('')
const canvas = document.createElement('canvas')
@@ -116,7 +116,7 @@ export function getCaptcha(width: number, high: number, num: number): Captcha {
}
}
-function randomInt(start: number, end: number): number {
+const randomInt = (start: number, end: number) => {
if (start > end) {
const t = start
start = end
@@ -127,10 +127,14 @@ function randomInt(start: number, end: number): number {
return start + Math.floor(Math.random() * (end - start))
}
-function randomFloat(start: number, end: number): number {
+const randomFloat = (start: number, end: number) => {
return start + Math.random() * (end - start)
}
-function randomColor(start: number, end: number): string {
+const randomColor = (start: number, end: number) => {
return `rgb(${randomInt(start, end)},${randomInt(start, end)},${randomInt(start, end)})`
}
+
+export const getRedirectUrl = (path: string, redirectUrl: string): string => {
+ return `${path}?redirect=${encodeURIComponent(redirectUrl)}`
+}