暂无可配置列
@@ -59,29 +37,23 @@
diff --git a/client/src/components/elderListDialog/index.vue b/client/src/components/elderListDialog/index.vue
index 172f22c..d5a8ee0 100644
--- a/client/src/components/elderListDialog/index.vue
+++ b/client/src/components/elderListDialog/index.vue
@@ -1,47 +1,26 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
- 选择
+ 选择
@@ -51,36 +30,27 @@
diff --git a/client/src/layout/components/NavBar/index.vue b/client/src/layout/components/NavBar/index.vue
index 4e8f846..fdccd75 100644
--- a/client/src/layout/components/NavBar/index.vue
+++ b/client/src/layout/components/NavBar/index.vue
@@ -1,50 +1,32 @@
-
diff --git a/client/src/layout/components/SideBar/components/MenuItem.vue b/client/src/layout/components/SideBar/components/MenuItem.vue
index e1a2de2..3b2b0d4 100644
--- a/client/src/layout/components/SideBar/components/MenuItem.vue
+++ b/client/src/layout/components/SideBar/components/MenuItem.vue
@@ -1,28 +1,15 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{
- menu.meta.title
- }}
+ menu.meta.title
+ }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{
- menu.meta.title
- }}
+ menu.meta.title
+ }}
@@ -84,35 +52,26 @@
diff --git a/client/src/layout/components/SideBar/index.vue b/client/src/layout/components/SideBar/index.vue
index 547e1aa..70cccae 100644
--- a/client/src/layout/components/SideBar/index.vue
+++ b/client/src/layout/components/SideBar/index.vue
@@ -1,25 +1,12 @@
-
diff --git a/client/src/layout/components/Tags/index.vue b/client/src/layout/components/Tags/index.vue
index 4ac0bb9..97c40c2 100644
--- a/client/src/layout/components/Tags/index.vue
+++ b/client/src/layout/components/Tags/index.vue
@@ -1,30 +1,17 @@
-
-
tags
diff --git a/client/src/layout/index.vue b/client/src/layout/index.vue
index b8f9bd5..6debadf 100644
--- a/client/src/layout/index.vue
+++ b/client/src/layout/index.vue
@@ -1,32 +1,19 @@
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
@@ -37,14 +24,10 @@
diff --git a/client/src/mock/getters.ts b/client/src/mock/getters.ts
index bbf9ef5..256c799 100644
--- a/client/src/mock/getters.ts
+++ b/client/src/mock/getters.ts
@@ -1,23 +1,15 @@
-// 从当前目录的 index 文件中导入 routes、users、IRoute 和 IUser
import { routes, users, IRoute, IUser } from './index'
-// 导入项目的 Vuex 存储实例
import store from '@/store'
-// 获取路由列表的函数,接受一个用户 ID(uid)作为参数
+// 获取路由列表
export const getRouterList = (uid: number) => {
- // 从 Vuex 存储中获取当前用户的权限 ID 列表
const authIdList: number[] = store.state.app.userPeofile.authIdList
- // 过滤出当前用户有权限访问的路由列表
const routeList: any[] = routes.filter(route => authIdList.includes(route.id))
-
- // 如果传入了用户 ID(uid)
if (uid) {
- // 查找具有指定 ID 的用户信息,userInfo 有可能是 undefined
+ // userInfo 有可能是 undefined
const userInfo: IUser | undefined = users.find(user => user.id === uid)
- // 如果找到了用户信息
if (userInfo) {
- // 以下是一段被注释掉的代码,功能可能是进一步筛选用户的授权路由列表
// const authRouteList: IRoute[] = []
// rid = router id
// userInfo.auth.map(rid => {
@@ -27,14 +19,12 @@ export const getRouterList = (uid: number) => {
// }
// })
// })
- // 返回成功响应,包含状态码、消息和筛选后的路由列表
return {
code: 0,
msg: 'ok',
data: routeList
}
} else {
- // 如果没有找到用户信息,返回错误响应
return {
code: 1001,
msg: 'No userInfo for this UID',
@@ -42,7 +32,6 @@ export const getRouterList = (uid: number) => {
}
}
} else {
- // 如果没有传入用户 ID,返回错误响应
return {
code: 1002,
msg: 'No UID received',
diff --git a/client/src/mock/index.ts b/client/src/mock/index.ts
index 4a645d7..8bed4b6 100644
--- a/client/src/mock/index.ts
+++ b/client/src/mock/index.ts
@@ -1,9 +1,5 @@
-// 从当前目录下的 routes 文件中导入 routes 变量和 IRoute 类型
import routes, { IRoute } from './routes'
-// 从当前目录下的 users 文件中导入 users 变量和 IUser 类型
import users, { IUser } from './users'
-// 导出 routes 变量,这样在其他文件中可以导入使用该变量
export { routes, users }
-// 导出 IRoute 和 IUser 类型,方便其他文件导入使用这些类型定义
export type { IRoute, IUser }
diff --git a/client/src/mock/routes.ts b/client/src/mock/routes.ts
index e547280..a46c70a 100644
--- a/client/src/mock/routes.ts
+++ b/client/src/mock/routes.ts
@@ -1,29 +1,17 @@
-// 定义一个接口 IRoute,用于描述路由的结构
export interface IRoute {
- // 路由的唯一标识 ID,类型为数字
id: number
- // 父路由的 ID,类型为数字
pid: number
- // 路由的名称,类型为字符串
name: string
- // 路由的路径,类型为字符串
path: string
- // 重定向的路径,是一个可选属性,类型为字符串
redirect?: string
- // 路由对应的组件路径,类型为字符串
component: string
- // 路由的元数据,是一个对象
meta: {
- // 路由的标题,类型为字符串
title: string
- // 路由的图标名称,是一个可选属性,类型为字符串
icon?: string
}
}
-// 定义一个名为 routes 的数组,元素类型为 IRoute,存储路由信息
const routes: IRoute[] = [
- // 第一个路由对象
{
id: 1,
pid: 0,
@@ -35,7 +23,6 @@ const routes: IRoute[] = [
icon: 'home'
}
},
- // 第二个路由对象
{
id: 2,
pid: 0,
@@ -48,43 +35,39 @@ const routes: IRoute[] = [
icon: 'sale'
}
},
- // 第三个路由对象
{
id: 3,
pid: 2,
path: 'counsel',
name: 'CounselSale',
- component:'sale/counsel/index.vue',
+ component: 'sale/counsel/index.vue',
meta: {
title: '咨询管理',
icon: ''
}
},
- // 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 4,
// pid: 2,
// path: 'intention',
// name: 'IntentionSale',
- // component:'sale/intention/index.vue',
+ // component: 'sale/intention/index.vue',
// meta: {
// title: '意向客户',
// icon: ''
// }
// },
- // 第五个路由对象
{
id: 5,
pid: 2,
path: 'book',
name: 'BookSale',
- component:'sale/book/index.vue',
+ component: 'sale/book/index.vue',
meta: {
title: '预定管理',
icon: ''
}
},
- // 第六个路由对象
{
id: 6,
pid: 0,
@@ -97,7 +80,6 @@ const routes: IRoute[] = [
icon: 'live'
}
},
- // 第七个路由对象
{
id: 7,
pid: 6,
@@ -109,7 +91,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第八个路由对象
{
id: 8,
pid: 6,
@@ -121,7 +102,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第九个路由对象
{
id: 9,
pid: 6,
@@ -133,7 +113,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第十个路由对象
{
id: 10,
pid: 6,
@@ -145,7 +124,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第十一个路由对象
{
id: 11,
pid: 6,
@@ -157,7 +135,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第十二个路由对象
{
id: 12,
pid: 6,
@@ -169,7 +146,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第十三个路由对象
{
id: 13,
pid: 0,
@@ -182,7 +158,6 @@ const routes: IRoute[] = [
icon: 'people'
}
},
- // 第十四个路由对象
{
id: 14,
pid: 13,
@@ -194,11 +169,10 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第十五个路由对象
{
id: 15,
pid: 13,
- path:'staff',
+ path: 'staff',
name: 'StaffPeople',
component: 'people/staff/index.vue',
meta: {
@@ -206,7 +180,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 16,
// pid: 13,
@@ -218,66 +191,61 @@ const routes: IRoute[] = [
// icon: ''
// }
// },
- // 第十七个路由对象
{
id: 17,
pid: 0,
path: '/serve',
name: 'Serve',
redirect: '/serve/project',
- component:'serve/index.vue',
+ component: 'serve/index.vue',
meta: {
title: '服务管理',
- icon:'serve'
+ icon: 'serve'
}
},
- // 第十八个路由对象
{
id: 18,
pid: 17,
path: 'project',
name: 'ProjectServe',
- component:'serve/project/index.vue',
+ component: 'serve/project/index.vue',
meta: {
title: '服务项目',
icon: ''
}
},
- // 第十九个路由对象
{
id: 19,
pid: 17,
path: 'level',
name: 'LevelServe',
- component:'serve/level/index.vue',
+ component: 'serve/level/index.vue',
meta: {
title: '护理等级',
icon: ''
}
},
- // 第二十个路由对象
{
id: 20,
pid: 17,
path: 'book',
name: 'BookServe',
- component:'serve/book/index.vue',
+ component: 'serve/book/index.vue',
meta: {
title: '服务预定',
icon: ''
}
},
- // 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 21,
// pid: 0,
// path: '/resource',
// name: 'Resource',
// redirect: '/resource/info',
- // component:'resource/index.vue',
+ // component: 'resource/index.vue',
// meta: {
// title: '物资管理',
- // icon:'resource'
+ // icon: 'resource'
// }
// },
// {
@@ -285,7 +253,7 @@ const routes: IRoute[] = [
// pid: 21,
// path: 'info',
// name: 'InfoResource',
- // component:'resource/info/index.vue',
+ // component: 'resource/info/index.vue',
// meta: {
// title: '物资信息',
// icon: ''
@@ -296,7 +264,7 @@ const routes: IRoute[] = [
// pid: 21,
// path: 'Storage',
// name: 'StorageResource',
- // component:'resource/storage/index.vue',
+ // component: 'resource/storage/index.vue',
// meta: {
// title: '仓库设置',
// icon: ''
@@ -307,7 +275,7 @@ const routes: IRoute[] = [
// pid: 21,
// path: 'enter',
// name: 'EnterResource',
- // component:'resource/enter/index.vue',
+ // component: 'resource/enter/index.vue',
// meta: {
// title: '入库管理',
// icon: ''
@@ -318,7 +286,7 @@ const routes: IRoute[] = [
// pid: 21,
// path: 'leave',
// name: 'LeaveResource',
- // component:'resource/leave/index.vue',
+ // component: 'resource/leave/index.vue',
// meta: {
// title: '出库管理',
// icon: ''
@@ -327,15 +295,14 @@ const routes: IRoute[] = [
// {
// id: 26,
// pid: 21,
- // path:'search',
+ // path: 'search',
// name: 'SearchResource',
- // component:'resource/search/index.vue',
+ // component: 'resource/search/index.vue',
// meta: {
// title: '库存查询',
// icon: ''
// }
// },
- // 第二十七个路由对象
{
id: 27,
pid: 0,
@@ -348,7 +315,6 @@ const routes: IRoute[] = [
icon: 'diet'
}
},
- // 第二十八个路由对象
{
id: 28,
pid: 27,
@@ -360,7 +326,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第二十九个路由对象
{
id: 29,
pid: 27,
@@ -372,7 +337,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第三十个路由对象
{
id: 30,
pid: 27,
@@ -384,7 +348,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第三十一个路由对象
{
id: 31,
pid: 0,
@@ -397,7 +360,6 @@ const routes: IRoute[] = [
icon: 'charge'
}
},
- // 第三十二个路由对象
{
id: 32,
pid: 31,
@@ -409,11 +371,10 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第三十三个路由对象
{
id: 33,
pid: 31,
- path:'record',
+ path: 'record',
name: 'RecordCharge',
component: 'charge/record/index.vue',
meta: {
@@ -421,7 +382,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第三十四个路由对象
{
id: 34,
pid: 31,
@@ -433,7 +393,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第三十五个路由对象
{
id: 35,
pid: 0,
@@ -446,11 +405,10 @@ const routes: IRoute[] = [
icon: 'base'
}
},
- // 第三十六个路由对象
{
id: 36,
pid: 35,
- path:'sale',
+ path: 'sale',
name: 'SaleBase',
redirect: '/base/sale/origin',
component: 'base/sale/index.vue',
@@ -459,7 +417,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第三十七个路由对象
{
id: 37,
pid: 36,
@@ -471,7 +428,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 38,
// pid: 36,
@@ -483,7 +439,6 @@ const routes: IRoute[] = [
// icon: ''
// }
// },
- // 第三十九个路由对象
{
id: 39,
pid: 35,
@@ -496,7 +451,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第四十个路由对象
{
id: 40,
pid: 39,
@@ -508,7 +462,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 第四十一个路由对象
{
id: 41,
pid: 39,
@@ -520,7 +473,6 @@ const routes: IRoute[] = [
icon: ''
}
},
- // 以下是一些被注释掉的路由对象,可根据需求启用
// {
// id: 42,
// pid: 35,
@@ -531,5 +483,4 @@ const routes: IRoute[] = [
// }
]
-// 导出 routes 数组,使其可以在其他模块中被导入和使用
export default routes
diff --git a/client/src/mock/users.ts b/client/src/mock/users.ts
index 3fb3645..db8e05e 100644
--- a/client/src/mock/users.ts
+++ b/client/src/mock/users.ts
@@ -1,20 +1,13 @@
-// 定义一个接口 IUser,用于描述用户对象的结构
export interface IUser {
- // 用户的唯一标识 ID,类型为数字
id: number
- // 用户的用户名,类型为字符串
username: string
- // 用户拥有的权限 ID 数组,数组中的元素类型为数字
auth: number[]
}
-// 导出一个默认的用户数组,类型为 IUser 数组
-// 数组中包含一个用户对象
export default [
{
id: 1,
username: 'zhangsan',
- // 该用户拥有的权限 ID 数组,包含多个权限 ID
auth: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
diff --git a/client/src/plugins/element-plus/index.ts b/client/src/plugins/element-plus/index.ts
index 9901b73..b28a690 100644
--- a/client/src/plugins/element-plus/index.ts
+++ b/client/src/plugins/element-plus/index.ts
@@ -1,17 +1,11 @@
-// 从 '@element-plus/icons-vue' 模块中导入所有的图标组件
import * as ElIcons from '@element-plus/icons-vue'
-// 从 'vue' 模块中导入 App 类型,用于表示 Vue 应用实例
import { App } from 'vue'
-// 定义一个名为 useElementPlus 的函数,该函数接受一个 App 类型的参数 app
const useElementPlus = (app: App) => {
- // 遍历 ElIcons 对象的所有属性
+ // 注册图标
for (const [key, component] of Object.entries(ElIcons)) {
- // 使用 app.component 方法将每个图标组件注册为全局组件
- // 组件的名称为属性名 key,组件本身为 component
app.component(key, component)
}
}
-// 导出 useElementPlus 函数,使其可以在其他模块中被导入和使用
export default useElementPlus
diff --git a/client/src/plugins/index.ts b/client/src/plugins/index.ts
index 09d5a2e..c6e49f2 100644
--- a/client/src/plugins/index.ts
+++ b/client/src/plugins/index.ts
@@ -1,6 +1,3 @@
-// 从当前目录下的 element-plus 文件中导入名为 useElementPlus 的函数
import useElementPlus from './element-plus'
-// 重新导出 useElementPlus 函数,这样其他模块在导入这个文件时
-// 可以通过解构赋值等方式获取到 useElementPlus 函数
export { useElementPlus }
diff --git a/client/src/router/index.ts b/client/src/router/index.ts
index 44cf2a0..a63c0cf 100644
--- a/client/src/router/index.ts
+++ b/client/src/router/index.ts
@@ -1,87 +1,62 @@
-// 从 vue-router 库中导入创建路由实例、路由记录类型和哈希路由历史模式的方法
import { createRouter, RouteRecordRaw, createWebHashHistory } from 'vue-router'
-// 导入布局组件
import Layout from '@/layout/index.vue'
-// 导入 Vuex 存储实例
import store from '@/store'
-// 导入初始化动态路由的工具函数
import { initRoutes } from './utils'
-// 定义静态路由数组,包含应用中固定的路由配置
+// 静态路由
const routes: Array = [
{
- // 根路径
path: '/',
- // 路由名称
name: 'Layout',
- // 路由对应的组件
component: Layout,
- // 重定向到 /home 路径
redirect: '/home',
- // 子路由数组,初始为空
children: []
},
{
- // 登录页面路径
path: '/login',
- // 路由名称
name: 'Login',
- // 路由元信息,包含页面标题
meta: {
title: '登录'
},
- // 使用动态导入方式加载登录页面组件
component: () =>
import(/* webpackChunkName: "Login" */ '@/views/login/index.vue')
},
{
- // 匹配所有未定义的路径
path: '/:pathMatch(.*)*',
- // 路由名称
name: 'NotFound',
- // 路由元信息,包含页面标题
meta: {
title: '404'
},
- // 使用动态导入方式加载 404 错误页面组件
component: () =>
import(/* webpackChunkName: "404" */ '@/views/error/404.vue')
}
]
-// 创建路由实例
const router = createRouter({
- // 使用哈希路由历史模式
history: createWebHashHistory(),
- // 路由配置
routes
})
-// 定义路由白名单,包含无需验证即可访问的路径
const ROUTER_WHITE_LIST = ['/login']
-// 全局前置守卫,在每次路由跳转前执行
router.beforeEach(async (to, from, next) => {
- // 设置页面标题,将目标路由的元信息中的标题与固定后缀拼接
- document.title = to.meta.title + ' | 敬老院管理系统'
+ // 设置页面标题
+ document["title"] = to.meta.title + " | 敬老院管理系统"
- // 判断访问的页面路径是否在路由白名单中,如果存在则直接放行
+ // .判断访问页面是否在路由白名单地址中,如果存在直接放行
if (ROUTER_WHITE_LIST.includes(to.path)) return next()
- // 判断是否有 Token,如果没有则重定向到登录页面
+ //.判断 是否有 Token,没有重定向到 login
if (!store.state.app.token) return next({ path: '/login', replace: true })
- // 如果没有初始化动态路由且存在 Token,则初始化动态路由
+ //如果没有初始化动态路由就初始化
if (!store.state.app.hasAuth && store.state.app.token) {
- // 调用初始化动态路由的工具函数
await initRoutes()
- // 重新跳转至目标路径
return next({ path: to.path })
}
- // 正常访问页面,放行路由跳转
+ // 7.正常访问页面
next()
})
-// 导出路由实例,供应用使用
export default router
diff --git a/client/src/router/types.ts b/client/src/router/types.ts
index 5c4a69f..d90861b 100644
--- a/client/src/router/types.ts
+++ b/client/src/router/types.ts
@@ -1,25 +1,14 @@
/** 路由 */
-// 定义一个接口 IRoute,用于规范路由对象的结构
export interface IRoute {
- // 路由的唯一标识 ID,类型为数字
id: number
- // 父路由的 ID,类型为数字,用于表示路由的层级关系
pid: number
- // 路由的名称,在路由配置和导航中使用,类型为字符串
name: string
- // 路由的路径,用于在浏览器地址栏中显示和导航,类型为字符串
path: string
- // 重定向的路径,是一个可选属性,当访问该路由时会自动重定向到指定路径,类型为字符串
redirect?: string
- // 路由对应的组件路径,指定该路由应渲染的 Vue 组件的路径,类型为字符串
component: string
- // 路由的元数据,是一个对象,包含与路由相关的额外信息
meta: {
- // 路由的标题,可用于页面标题、菜单显示等,类型为字符串
title: string
- // 路由的图标名称,是一个可选属性,可用于在菜单中显示图标,类型为字符串
icon?: string
}
- // 子路由数组,是一个可选属性,用于表示该路由下的子路由列表,元素类型为 IRoute
children?: IRoute[]
}
diff --git a/client/src/router/utils.ts b/client/src/router/utils.ts
index 4153b9a..ec5fc53 100644
--- a/client/src/router/utils.ts
+++ b/client/src/router/utils.ts
@@ -1,53 +1,31 @@
-// 从项目的路由类型文件中导入 IRoute 接口,用于描述路由的结构
import { IRoute } from "@/router/types";
-// 从 vue-router 库中导入 Router 和 RouteRecordRaw 类型
-// Router 是 Vue Router 的实例类型,RouteRecordRaw 用于定义路由记录
import { Router, RouteRecordRaw } from "vue-router";
-// 导入项目的路由实例
import router from "./index";
-// 导入项目的 Vuex 存储实例
import store from "@/store";
-// 从项目的工具函数文件中导入数组去重的工具函数
import { arrayDeduplicationByFiled } from "@/utils/commonUtil";
/** 将后端返回的路由转换成生成树形结构 */
function formatRouteTree(data: IRoute[]) {
- // 过滤出父路由,即 pid 为 0 的路由
const parents = data.filter(routeInfo => routeInfo.pid === 0);
- // 过滤出子路由,即 pid 不为 0 的路由
const children = data.filter(routeInfo => routeInfo.pid !== 0);
- // 调用递归函数将数据转换为树形结构
dataToTree(parents, children);
- // 返回转换后的父路由数组,此时父路由数组中包含了子路由信息
return parents;
- /**
- * 递归函数,将子路由挂载到对应的父路由上
- * @param parents 父路由数组
- * @param children 子路由数组
- */
function dataToTree(parents: IRoute[], children: IRoute[]) {
- // 遍历父路由数组
parents.map(parent => {
- // 遍历子路由数组
children.map((child, index) => {
- // 如果子路由的 pid 等于父路由的 id
if (child.pid === parent.id) {
- // 复制一份子路由数组,避免在原数组上进行操作
const _children: IRoute[] = JSON.parse(JSON.stringify(children));
- // 从复制的子路由数组中移除当前处理的子路由
_children.splice(index, 1);
- // 递归调用 dataToTree 函数,处理当前子路由的子路由
dataToTree([child], _children);
if (parent.children) {
- // 如果父路由已经有子路由数组,将当前子路由添加到该数组中
+ // 添加
parent.children.push(child);
- // 对父路由的子路由数组进行去重操作,根据 id 字段去重
+ // 菜单去重
parent.children = arrayDeduplicationByFiled(parent.children, "id");
} else {
- // 如果父路由还没有子路由数组,创建一个包含当前子路由的数组
parent.children = [child];
}
}
@@ -58,66 +36,46 @@ function formatRouteTree(data: IRoute[]) {
/** 将树形结构路由转化成真实的路由 */
function generateRouter(routeTree: IRoute[]) {
- // 遍历树形结构的路由数组
const newRoutes = routeTree.map(route => {
- // 创建一个新的路由记录对象
const _route: RouteRecordRaw = {
- // 路由的路径
path: route.path,
- // 路由的名称
name: route.name,
- // 路由的元信息
meta: route.meta,
- // 路由的重定向路径
redirect: route.redirect,
- // 使用动态导入的方式加载路由对应的组件,组件位于 @/views 目录下
- component: () => import("@/views/" + route.component),
- // 子路由数组,初始为空
+ component: () => import("@/views/" + route.component), // 注意:views目录下才能引入,否则ts不识别
children: []
};
- // 如果当前路由有子路由
if (route.children) {
- // 递归调用 generateRouter 函数,处理子路由
_route.children = generateRouter(route.children);
}
- // 返回新创建的路由记录对象
return _route;
});
- // 返回转换后的路由记录数组
return newRoutes;
}
-// 初始化动态路由的函数
+//初始化动态路由
export async function initRoutes() {
- // 调用 Vuex 的 action,获取路由树形结构数据
await store.dispatch("app/getRouterTree");
- // 将获取到的路由树形结构数据转换为真实的路由记录数组
const newRoutes = generateRouter(store.state.app.routeTree);
- // 遍历新的路由记录数组,将每个路由添加到名为 "Layout" 的父路由下
newRoutes.forEach(route => router.addRoute("Layout", route));
}
-// 清除路由的函数
+//清除路由
export function clearRoutes() {
- // 定义默认的路由名称数组
+ //删除之前注册的路由 默认状态下只有三个,如果超过三个删除多余的路由
const defaultRoutes = ["Layout", "Login", "NotFound"];
- // 获取当前路由实例中的所有路由记录
const currentRoutes = router.getRoutes();
- // 如果当前路由记录的数量不等于 3
if (currentRoutes.length != 3) {
- // 遍历当前的路由记录数组
+ //执行删除
currentRoutes.forEach(item => {
- // 如果当前路由的名称不在默认路由名称数组中
if (!defaultRoutes.includes(String(item.name))) {
- // 从路由实例中移除该路由
router.removeRoute(String(item.name));
}
});
}
}
-// 导出 formatRouteTree 和 generateRouter 函数,供其他模块使用
export { formatRouteTree, generateRouter };
diff --git a/client/src/store/index.ts b/client/src/store/index.ts
index 10041a7..79a8523 100644
--- a/client/src/store/index.ts
+++ b/client/src/store/index.ts
@@ -1,46 +1,29 @@
-// 从 vue 库中导入 InjectionKey 类型,用于在 Vue 3 中为 provide 和 inject 提供类型约束
import { InjectionKey } from 'vue'
-// 从 vuex 库中导入创建 store 的函数、基础的 useStore 函数和 Store 类型
import { createStore, useStore as baseUseStore, Store } from 'vuex'
-// 从项目的 store 类型文件中导入根状态类型
import { IRootState } from '@/store/types'
-// 从当前模块的 app 子模块中导入名为 store 的对象
import { store as app } from './modules/app'
-// 从当前模块的工具文件中导入自定义的 CommonStore 类型
import { CommonStore } from './utils'
-// 导入 vuex-persistedstate 插件,用于将 store 中的状态持久化到本地存储
import createPersistedState from 'vuex-persistedstate'
-// 定义一个包含所有模块的对象,这里目前只有 app 模块
export const modules = {
app
}
-// 定义一个注入键,用于在使用 useStore 时约束 state 的类型
-// 这里使用 Symbol 创建一个唯一的键,类型为 Store
+// injectionKey:约束state类型
export const key: InjectionKey> = Symbol()
-// 创建一个 Vuex store 实例,指定根状态类型为 IRootState
const store = createStore({
- // 注册模块
modules,
- // 应用插件
plugins: [
- // 使用 vuex-persistedstate 插件
createPersistedState({
- // 存储在本地存储中的键名
key: 'stateData',
- // 指定需要持久化的模块路径,这里只持久化 app 模块
paths: ['app']
})
]
}) as CommonStore
-// 定义一个自定义的 useStore 函数,返回类型为 CommonStore
-// 调用 baseUseStore 函数并传入注入键,确保类型安全
export function useStore(): CommonStore {
return baseUseStore(key)
}
-// 导出创建好的 store 实例,供应用使用
export default store
diff --git a/client/src/store/modules/app/index.ts b/client/src/store/modules/app/index.ts
index 31b30a1..7ebbf04 100644
--- a/client/src/store/modules/app/index.ts
+++ b/client/src/store/modules/app/index.ts
@@ -1,46 +1,26 @@
-// 从 vuex 中导入 ActionContext 类型,用于在 action 中获取上下文
import { ActionContext } from 'vuex'
-// 从项目的 store 类型文件中导入根状态类型
import { IRootState } from '@/store/types'
-// 从当前模块的类型文件中导入当前模块的状态类型
import { IAppState } from './types'
-// 从项目的路由类型文件中导入路由类型
import { IRoute } from '@/router/types'
-// 从项目的模拟数据获取器中导入获取路由列表的函数
import { getRouterList } from '@/mock/getters'
-// 从项目的路由工具文件中导入清除路由和格式化路由树的函数
import { clearRoutes, formatRouteTree } from '@/router/utils'
-// 从项目的 API 模块中导入获取用户路由列表的函数(当前注释掉未使用)
// import { getUserRouteList } from '@/apis'
-// 从项目的用户 API 模块中导入登录请求函数
import { getLogin } from '@/apis/user'
-// 导入项目的路由实例
import router from '@/router'
-// 定义默认状态对象
const defaultState = {
- // 用户 ID,初始为 1
uid: 1,
- // 用户令牌,初始为空字符串
token: '',
- // 是否有路由权限,初始为 false
hasAuth: false,
- // 路由树,初始为空数组
routeTree: [],
- // 侧边栏是否展开,初始为 true 表示展开
siderType: true,
- // 用户信息,初始为空对象
userPeofile: {},
- // 是否记住密码,初始为 false
rememberPWD: false
}
-// 导出当前模块的 store 配置
export const store = {
- // 开启命名空间,使模块的 action、mutation 和 getter 名称唯一
namespaced: true,
- // 模块的状态
state: {
uid: 1,
token: '',
@@ -50,53 +30,38 @@ export const store = {
userPeofile: {},
rememberPWD: false
},
- // 模块的 mutations,用于修改状态
mutations: {
- // 设置用户令牌的 mutation
setToken(state: IAppState, token: string) {
state.token = token
},
- // 设置路由树的 mutation
setRouteTree(state: IAppState, routeTree: IRoute[]) {
state.routeTree = routeTree
},
- // 设置是否有路由权限的 mutation
setAuth(state: IAppState, auth: boolean) {
state.hasAuth = auth
},
- // 切换侧边栏展开状态的 mutation
setSiderType(state: IAppState) {
state.siderType = !state.siderType
},
- // 设置用户信息的 mutation
setUserProfile(state: IAppState, userPeofile: any) {
state.userPeofile = userPeofile
},
- // 设置是否记住密码的 mutation
setRememberPWD(state: IAppState, rememberPWD: boolean) {
state.rememberPWD = rememberPWD
},
- // 清除 store 状态的 mutation,将状态重置为默认状态
clearStore(state: IAppState) {
Object.assign(state, defaultState)
}
},
- // 模块的 actions,用于处理异步操作和提交 mutations
actions: {
- // 登录 action
+ //登录
async actionLogin(
- // 从上下文获取 commit 和 state
{ commit, state }: ActionContext,
- // 登录数据
data: any
) {
- // 调用登录请求函数
const res: any = await getLogin(data)
- // 如果登录成功
if (res.code === 200) {
- // 提交设置令牌的 mutation
commit('setToken', res?.data?.token)
- // 提交设置用户信息的 mutation
commit('setUserProfile', {
username: res?.data.name,
userid: res?.data.id,
@@ -104,31 +69,22 @@ export const store = {
authIdList: res?.data.authIdList
})
}
- // 提交设置是否记住密码的 mutation
commit('setRememberPWD', data?.rememberPWD)
- // 返回登录请求的响应
return res
},
- // 获取权限菜单 action
+ //获取权限菜单
getRouterTree({ commit, state }: ActionContext) {
- // 模拟获取路由列表
+ // 模拟数据
const routeList = getRouterList(state.uid).data as unknown as IRoute[]
- // 格式化路由列表为路由树
const routeTree = formatRouteTree(routeList)
- // 提交设置路由树的 mutation
commit('setRouteTree', routeTree)
- // 提交设置有路由权限的 mutation
commit('setAuth', true)
},
- // 点击登出 action
+ // 点击登出
logout({ commit, state }: ActionContext) {
- // 提交清除 store 状态的 mutation
commit('clearStore')
- // 清除本地存储
localStorage.clear()
- // 清除动态添加的路由
clearRoutes()
- // 路由跳转到登录页
router.replace('/login')
}
}
diff --git a/client/src/store/modules/app/types.ts b/client/src/store/modules/app/types.ts
index 6ac80e7..b064c07 100644
--- a/client/src/store/modules/app/types.ts
+++ b/client/src/store/modules/app/types.ts
@@ -1,20 +1,11 @@
-// 从项目的路由类型文件中导入 IRoute 接口,用于描述路由的结构
import { IRoute } from '@/router/types'
-// 定义一个接口 IAppState,用于描述应用状态的结构
export interface IAppState {
- // 用户 ID,类型为数字
uid: number
- // 用户令牌,类型为字符串
token: string
- // 是否有路由权限,类型为布尔值
hasAuth: boolean
- // 路由树,是一个 IRoute 类型的数组,用于存储路由信息
routeTree: IRoute[]
- // 侧边栏是否展开,类型为布尔值
siderType: boolean
- // 用户信息,类型为 any,表示可以是任意类型的数据
userPeofile: any
- // 是否记住密码,类型为布尔值
rememberPWD: boolean
}
diff --git a/client/src/store/modules/soldManage/index.ts b/client/src/store/modules/soldManage/index.ts
index 5417709..fb5688c 100644
--- a/client/src/store/modules/soldManage/index.ts
+++ b/client/src/store/modules/soldManage/index.ts
@@ -1,16 +1,9 @@
-// 从 vuex 中导入 ActionContext 类型,它用于在 actions 里获取上下文,能访问 state、getters、mutations 等
import { ActionContext } from 'vuex'
-// 从项目的路由配置文件导入路由实例,后续可能会在 actions 里使用路由进行页面跳转
import router from '@/router'
-// 导出一个名为 store 的对象,这是一个 Vuex 模块
export const store = {
- // 设置为 true 表示开启命名空间,可避免不同模块间的 action、mutation 和 getter 名称冲突
namespaced: true,
- // state 是存储数据的地方,这里初始为空对象,后续可添加应用所需的状态数据
state: {},
- // mutations 用于修改 state 中的数据,是同步操作,这里初始为空对象,后续可添加具体的 mutation 函数
mutations: {},
- // actions 用于处理异步操作,如发起网络请求等,这里初始为空对象,后续可添加具体的 action 函数
actions: {}
}
diff --git a/client/src/store/types.ts b/client/src/store/types.ts
index 335ec26..28f5937 100644
--- a/client/src/store/types.ts
+++ b/client/src/store/types.ts
@@ -1,11 +1,5 @@
-// 从项目的 app 模块的类型文件中导入 IAppState 类型,该类型描述了 app 模块的状态结构
import { IAppState } from '@/store/modules/app/types'
-/**
- * 定义一个名为 IRootState 的类型,它表示整个 Vuex 存储的根状态结构。
- * 在 Vuex 中,根状态可以包含多个模块的状态,这里根状态只包含一个名为 app 的模块状态。
- */
export type IRootState = {
- // app 字段的类型为 IAppState,意味着根状态中的 app 模块状态遵循 IAppState 类型的定义
app: IAppState
}
diff --git a/client/src/store/utils.ts b/client/src/store/utils.ts
index 509eab0..f96b603 100644
--- a/client/src/store/utils.ts
+++ b/client/src/store/utils.ts
@@ -1,29 +1,25 @@
/** 智能提示 */
-// 从当前目录的 types 文件中导入 IRootState 类型,用于表示根状态
import { IRootState } from './types'
-// 从当前目录的 index 文件中导入 modules 对象,该对象包含了所有的 Vuex 模块
import { modules } from './index'
-// 从 vuex 库中导入 CommitOptions、DispatchOptions 和 Store 类型
import { CommitOptions, DispatchOptions, Store as VuexStore } from 'vuex'
-
-// 获取 modules 的类型
+// 获取modules的类型
type Modules = typeof modules
-// 获取所有模块下的 mutations
-type GetMutation = T extends { mutations: infer G }? G : never
+// 获取所有模块下的mutations
+type GetMutation = T extends { mutations: infer G } ? G : never
type GetMutations = {
[K in keyof T]: GetMutation
}
type mutationsObj = GetMutations
-// 获取所有模块下的 actions
-type GetAction = T extends { actions: infer G }? G : never
+// 获取所有模块下的actions
+type GetAction = T extends { actions: infer G } ? G : never
type GetActions = {
[K in keyof T]: GetAction
}
type actionsObj = GetActions
-// 获取所有模块下的 getters
-type GetGetter = T extends { getters: infer G }? G : never
+// 获取所有模块下的getters
+type GetGetter = T extends { getters: infer G } ? G : never
type GetGetters = {
[K in keyof T]: GetGetter
}
diff --git a/client/src/styles/element.scss b/client/src/styles/element.scss
index d1e83cf..81e2fba 100644
--- a/client/src/styles/element.scss
+++ b/client/src/styles/element.scss
@@ -1,27 +1,22 @@
-/* 为.el-breadcrumb__inner 和.el-breadcrumb__inner a 元素设置字体加粗为 400,!important 提高优先级 */
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
-/* 隐藏.el-upload 元素内的 input[type='file'] 元素,!important 提高优先级 */
.el-upload {
input[type='file'] {
display: none !important;
}
}
-/* 隐藏.el-upload__input 元素 */
.el-upload__input {
display: none;
}
-/* 为.upload-container 元素内的.el-upload 元素设置宽度为 100% */
.upload-container {
.el-upload {
width: 100%;
- /* 为.upload-container 元素内的.el-upload 元素的.el-upload-dragger 子元素设置宽度为 100%,高度为 200px */
.el-upload-dragger {
width: 100%;
height: 200px;
@@ -29,70 +24,62 @@
}
}
-/* 为.el-dropdown-menu 元素设置内边距为 0,!important 提高优先级 */
.el-dropdown-menu {
padding: 0 !important;
}
-/* 为.el-range-separator 元素设置盒模型为 content-box */
.el-range-separator {
box-sizing: content-box;
}
-/* 为.is-dark 元素设置 z-index 为 9999,!important 提高优先级 */
.is-dark {
z-index: 9999 !important;
}
-/* 重置带有 [class*='el-icon'] 类且后面跟着 span 元素的 margin-left 为 2px,!important 提高优先级 */
+/* 重置 el-button 中 icon 的 margin */
.reset-margin [class*='el-icon'] + span {
margin-left: 2px !important;
}
-/* 为.pure-popper 元素设置内边距为 0,!important 提高优先级 */
+/* 自定义 popover 的类名 */
.pure-popper {
padding: 0 !important;
}
-/* 为.pure-tooltip 元素设置 z-index 为 41000,!important 提高优先级,因为右侧操作面板 right-panel 类名的 z-index 为 40000,tooltip 需要大于它才能显示 */
+/* 自定义 tooltip 的类名 */
.pure-tooltip {
+ // 右侧操作面板right-panel类名的z-index为40000,tooltip需要大于它才能显示
z-index: 41000 !important;
}
-/* 为 #nprogress 元素及其子元素设置样式 */
+/* nprogress 适配 element-plus 的主题色 */
#nprogress {
- /* 为 #nprogress 元素的.bar 子元素设置背景颜色为 --el-color-primary 变量的值,!important 提高优先级 */
- &.bar {
+ & .bar {
background-color: var(--el-color-primary) !important;
}
- /* 为 #nprogress 元素的.peg 子元素设置 box-shadow,颜色为 --el-color-primary 变量的值,!important 提高优先级 */
- &.peg {
+ & .peg {
box-shadow: 0 0 10px var(--el-color-primary),
0 0 5px var(--el-color-primary) !important;
}
- /* 为 #nprogress 元素的.spinner-icon 子元素设置边框颜色为 --el-color-primary 变量的值 */
- &.spinner-icon {
+ & .spinner-icon {
border-top-color: var(--el-color-primary);
border-left-color: var(--el-color-primary);
}
}
-/* 为.el-dialog__headerbtn 和.el-message-box__headerbtn 元素的:hover 状态设置样式 */
+/* 全局覆盖element-plus的el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标的样式,表现更鲜明 */
.el-dialog__headerbtn,
.el-message-box__headerbtn {
&:hover {
- /* 为.el-dialog__headerbtn 和.el-message-box__headerbtn 元素在:hover 状态下的.el-dialog__close 子元素设置颜色为 --el-color-info 变量的值,!important 提高优先级 */
.el-dialog__close {
color: var(--el-color-info) !important;
}
}
}
-/* 为.el-icon 元素及其特定子元素设置样式 */
.el-icon {
- /* 为.el-icon 元素的.el-dialog__close、.el-drawer__close、.el-message-box__close 和.el-notification__closeBtn 子元素设置样式 */
&.el-dialog__close,
&.el-drawer__close,
&.el-message-box__close,
@@ -103,7 +90,6 @@
border-radius: 4px;
transition: background-color 0.2s, color 0.2s;
- /* 为这些子元素的:hover 状态设置样式 */
&:hover {
color: rgba(0, 0, 0, 0.88) !important;
background-color: rgba(0, 0, 0, 0.06);
@@ -112,7 +98,7 @@
}
}
-/* 克隆并自定义 ElMessage 样式,为.pure-message 元素设置样式 */
+/* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,暗黑模式在 src/style/dark.scss 文件进行了适配 */
.pure-message {
border-width: 0 !important;
background: #fff !important;
@@ -120,85 +106,69 @@
box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014,
0 9px 28px 8px #0000000d !important;
- /* 为.pure-message 元素的.is-closable 子元素的.el-message__content 子元素设置内边距 */
- &.el-message.is-closable.el-message__content {
+ &.el-message.is-closable .el-message__content {
padding-right: 17px !important;
}
- /* 为.pure-message 元素的.el-message__content 子元素设置颜色、指针事件和背景图像 */
- &.el-message__content {
+ & .el-message__content {
color: #000000d9 !important;
pointer-events: all !important;
background-image: initial !important;
}
- /* 为.pure-message 元素的.el-message__icon 子元素设置外边距 */
- &.el-message__icon {
+ & .el-message__icon {
margin-right: 8px !important;
}
- /* 为.pure-message 元素的.el-message__closeBtn 子元素设置样式 */
- &.el-message__closeBtn {
+ & .el-message__closeBtn {
outline: none;
border-radius: 4px;
right: 9px !important;
transition: background-color 0.2s, color 0.2s;
- /* 为.el-message__closeBtn 子元素的:hover 状态设置背景颜色 */
&:hover {
background-color: rgba(0, 0, 0, 0.06);
}
}
}
-/* 为.el-popconfirm 元素的.el-popconfirm__action 子元素内的不同类型的.el-button 元素设置样式 */
.el-popconfirm {
.el-popconfirm__action {
- /* 为.el-popconfirm__action 子元素内的.el-button--primary 类型的按钮设置背景颜色 */
.el-button--primary {
background-color: #409eff !important;
- /* 为.el-button--primary 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #79bbff !important;
}
}
- /* 为.el-popconfirm__action 子元素内的.el-button--success 类型的按钮设置背景颜色 */
.el-button--success {
background-color: #67C23A !important;
- /* 为.el-button--success 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #95d475 !important;
}
}
- /* 为.el-popconfirm__action 子元素内的.el-button--warning 类型的按钮设置背景颜色 */
.el-button--warning {
background-color: #E6A23C !important;
- /* 为.el-button--warning 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #eebe77 !important;
}
}
- /* 为.el-popconfirm__action 子元素内的.el-button--danger 类型的按钮设置背景颜色 */
.el-button--danger {
- background-color: #F56C6C !important;
+ background-color: #f56c6c !important;
- /* 为.el-button--danger 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #f89898 !important;
}
}
- /* 为.el-popconfirm__action 子元素内的.el-button--info 类型的按钮设置背景颜色 */
.el-button--info {
background-color: #909399 !important;
- /* 为.el-button--info 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #b1b3b8 !important;
}
@@ -206,56 +176,46 @@
}
}
-/* 为.el-button--primary 类型的按钮设置颜色和背景颜色 */
.el-button--primary {
color: white !important;
background-color: #409EFF !important;
- /* 为.el-button--primary 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #79bbff !important;
}
}
-/* 为.el-button--success 类型的按钮设置颜色和背景颜色 */
.el-button--success {
color: white !important;
background-color: #67C23A !important;
- /* 为.el-button--success 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #95d475 !important;
}
}
-/* 为.el-button--warning 类型的按钮设置颜色和背景颜色 */
.el-button--warning {
color: white !important;
background-color: #E6A23C !important;
- /* 为.el-button--warning 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #eebe77 !important;
}
}
-/* 为.el-button--danger 类型的按钮设置颜色和背景颜色 */
.el-button--danger {
color: white !important;
background-color: #F56C6C !important;
- /* 为.el-button--danger 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #f89898 !important;
}
}
-/* 为.el-button--info 类型的按钮设置颜色和背景颜色 */
.el-button--info {
color: white !important;
background-color: #909399 !important;
- /* 为.el-button--info 类型的按钮的:hover 状态设置背景颜色 */
&:hover {
background-color: #b1b3b8 !important;
}
diff --git a/client/src/styles/index.scss b/client/src/styles/index.scss
index eb00703..ca69fc8 100644
--- a/client/src/styles/index.scss
+++ b/client/src/styles/index.scss
@@ -1,26 +1,9 @@
-// 导入常用变量文件,该文件可能包含颜色、字体大小、间距等常用变量的定义
-@import './variables.module.scss';
-
-// 导入常用方法文件,该文件可能包含一些自定义的混合宏(mixin)或函数,用于简化样式编写
-@import './mixin.scss';
-
-// 导入基础样式文件,该文件可能包含一些全局的基础样式,如字体、文本对齐、行高等
-@import './base.scss';
-
-// 导入重置样式文件,该文件通常用于重置浏览器的默认样式,使不同浏览器的样式更加一致
-@import './reset.scss';
-
-// 导入登录页面的样式文件,该文件可能包含登录页面特有的样式
+@import './variables.module.scss'; // 常用变量
+@import './mixin.scss'; // 常用方法
+@import './base.scss'; // 基础样式
+@import './reset.scss'; // 重置样式
@import './login.scss';
-
-// 导入导航栏的样式文件,该文件可能包含导航栏的样式
@import './navbar.scss';
-
-// 导入侧边栏的样式文件,该文件可能包含侧边栏的样式
@import './sidebar.scss';
-
-// 导入 Element Plus 组件库的样式文件,该文件可能包含对 Element Plus 组件的样式覆盖或自定义
@import './element.scss';
-
-// 导入过渡效果的样式文件,该文件可能包含一些过渡动画的样式定义
@import './transition.scss';
diff --git a/client/src/styles/login.scss b/client/src/styles/login.scss
index 4bd7cca..83c9408 100644
--- a/client/src/styles/login.scss
+++ b/client/src/styles/login.scss
@@ -1,116 +1,70 @@
-// 定义一个名为.login-container 的类选择器,用于设置登录容器的样式
.login-container {
- // 设置定位为相对定位
position: relative;
- // 设置高度为视口高度的 100%
height: 100vh;
- // 设置宽度为视口宽度的 100%
width: 100vw;
- // 设置为弹性盒子布局
display: flex;
- // 使弹性盒子内的子元素在水平方向上两端对齐
justify-content: space-between;
- // 选择.login-container 内的.left-box 和.right-box 元素,设置它们在弹性布局中平均分配剩余空间
.left-box,
.right-box {
flex: 1;
}
- // 选择.login-container 内的.right-box 元素,设置其样式
.right-box {
- // 设置为弹性盒子布局
display: flex;
- // 使弹性盒子内的子元素在垂直方向上居中对齐
align-items: center;
- // 向上偏移 90 像素
margin-top: -90px;
- // 选择.right-box 内的.login-form 和.forget-pass-form 元素,设置它们的样式
- .login-form,
+ .login-form ,
.forget-pass-form {
- // 设置宽度为 360 像素
width: 360px;
- // 设置左边距为 50 像素
margin-left: 50px;
- // 选择.login-form 和.forget-pass-form 内的.title 元素,设置其样式
.title {
- // 设置为弹性盒子布局,子元素垂直排列
display: flex;
flex-direction: column;
- // 使弹性盒子内的子元素在水平方向上居中对齐
align-items: center;
- // 选择.title 内的 img 元素,设置其样式
img {
width: 80px;
height: 80px;
}
- // 选择.title 内的 h2 元素,设置其样式
h2 {
- // 设置文本颜色
color: #9193a3;
- // 设置外边距,上 10 像素,右 0 像素,下 15 像素,左 0 像素
margin: 10px 0 15px 0;
}
}
- // 选择.login-form 和.forget-pass-form 内的.password-set 元素,设置其样式
.password-set {
- // 设置为弹性盒子布局
display: flex;
- // 设置宽度为父元素的 100%
width: 100%;
- // 设置外边距,上 -10 像素,右 0 像素,下 10 像素,左 0 像素
margin: -10px 0 10px 0;
- // 使弹性盒子内的子元素在水平方向上向右对齐
justify-content: right;
}
}
}
- // 选择.login-container 内的.left-box 元素,设置其样式
.left-box {
- // 设置定位为相对定位
position: relative;
- // 设置宽度为父元素的 100%
width: 100%;
- // 为.left-box 元素添加一个伪元素,作为其背景图像容器
&::before {
content: '';
- // 设置定位为绝对定位
position: absolute;
- // 定位到元素的顶部
top: 0;
- // 定位到元素的左侧
left: 0;
- // 设置宽度为父元素的 100%
width: 100%;
- // 设置高度为父元素的 100%
height: 100%;
- // 设置背景图像,使用相对路径引用项目中的 bg.png 图片
background-image: url('~@/assets/imgs/bg.png');
- // 设置背景图像不重复
background-repeat: no-repeat;
- // 设置背景图像的大小,宽度自动,高度为父元素的 100%
background-size: auto 100%;
- // 设置 z 轴层级为 -1,使其在.left-box 内的其他元素下方
z-index: -1;
}
- // 选择.left-box 内的.img 元素,设置其样式
.img {
- // 设置宽度为父元素的 100%
width: 100%;
- // 设置高度为父元素的 100%
height: 100%;
- // 设置为弹性盒子布局
display: flex;
- // 使弹性盒子内的子元素在垂直方向上居中对齐
align-items: center;
- // 使弹性盒子内的子元素在水平方向上居中对齐
justify-content: center;
- // 选择.img 内的 img 元素,设置其样式
img {
width: 500px;
}
diff --git a/client/src/styles/mixin.scss b/client/src/styles/mixin.scss
index 68a03c8..3ca7168 100644
--- a/client/src/styles/mixin.scss
+++ b/client/src/styles/mixin.scss
@@ -1,34 +1,26 @@
-// 定义一个名为 clearfix 的混合宏(mixin)
@mixin clearfix {
- // 为使用该混合宏的元素添加一个伪元素:after
&:after {
content: '';
- // 设置伪元素的显示方式为表格,用于清除浮动
display: table;
clear: both;
}
}
-// 定义一个名为 scrollBar 的混合宏(mixin),用于设置滚动条样式
@mixin scrollBar {
- // 设置滚动条轨道的样式
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
- // 设置滚动条的宽度
&::-webkit-scrollbar {
width: 6px;
}
- // 设置滚动条滑块的样式
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
-// 定义一个名为 relative 的混合宏(mixin),用于设置元素的相对定位和尺寸
@mixin relative {
position: relative;
width: 100%;
diff --git a/client/src/styles/navbar.scss b/client/src/styles/navbar.scss
index b7f5985..a4af7eb 100644
--- a/client/src/styles/navbar.scss
+++ b/client/src/styles/navbar.scss
@@ -1,31 +1,19 @@
-/* 定义一个名为.navbar-bg-hover 的类选择器,用于设置导航栏背景悬停效果的样式 */
+// 导航划过阴影
.navbar-bg-hover {
- /* 设置为弹性盒子布局 */
display: flex;
- /* 使弹性盒子内的子元素在垂直方向上居中对齐 */
align-items: center;
- /* 使弹性盒子内的子元素在水平方向上居中对齐 */
justify-content: center;
- /* 设置高度为 48 像素 */
height: 48px;
- /* 设置内边距为 12 像素 */
padding: 12px;
- /* 设置所有属性的过渡效果,持续时间为 0.3 秒 */
transition: all 0.3s;
-}
-/* 当.navbar-bg-hover 元素被鼠标悬停时的样式 */
-&:hover {
- /* 设置背景颜色为 #f6f6f6 */
- background-color: #f6f6f6;
- /* 设置鼠标指针样式为指针 */
- cursor: pointer;
- /* 再次设置所有属性的过渡效果,持续时间为 0.3 秒 */
- transition: all 0.3s;
-}
+ &:hover {
+ background-color: #f6f6f6;
+ cursor: pointer;
+ transition: all 0.3s;
+ }
-/* 选择.navbar-bg-hover 元素内的.svg-icon 元素,设置其样式 */
-.svg-icon {
- /* 去除轮廓线 */
- outline: none;
+ .svg-icon {
+ outline: none;
+ }
}
diff --git a/client/src/styles/reset.scss b/client/src/styles/reset.scss
index 7d17a6d..9ccb917 100644
--- a/client/src/styles/reset.scss
+++ b/client/src/styles/reset.scss
@@ -1,97 +1,61 @@
-/* 对 html 和 body 元素设置样式 */
html,
body {
- /* 设置高度为视口高度的 100% */
height: 100%;
- /* 去除外边距 */
margin: 0;
- /* 去除内边距 */
padding: 0;
- /* 针对 Firefox 浏览器,设置字体抗锯齿为灰度模式,提高字体显示质量 */
-moz-osx-font-smoothing: grayscale;
- /* 针对 WebKit 内核的浏览器(如 Chrome、Safari),设置字体抗锯齿,提高字体显示质量 */
-webkit-font-smoothing: antialiased;
- /* 设置文本渲染方式为优化可读性 */
text-rendering: optimizeLegibility;
- // 这行代码被注释掉,原本是设置字体族,由于被注释,当前不生效。
// font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
// Microsoft YaHei, Arial, sans-serif;
}
-/* 对 id 为 app 的元素设置样式 */
#app {
- /* 设置高度为视口高度的 100% */
height: 100%;
}
-/* 对所有元素及其伪元素(:before 和 :after)设置样式 */
*,
*:before,
*:after {
- /* 使元素的 box-sizing 属性继承自父元素,通常用于统一盒模型的计算方式 */
box-sizing: inherit;
- /* 去除外边距 */
margin: 0;
- /* 去除内边距 */
padding: 0;
}
-/* 对处于激活(active)和获得焦点(focus)状态的 a 元素设置样式 */
a:focus,
a:active {
- /* 去除轮廓线 */
outline: none;
}
-/* 对 a 元素及其处于获得焦点(focus)和鼠标悬停(hover)状态时设置样式 */
a,
a:focus,
a:hover {
- /* 设置鼠标指针样式为指针 */
cursor: pointer;
- /* 使链接文本颜色继承自父元素 */
color: inherit;
- /* 去除链接的下划线 */
text-decoration: none;
}
-/* 对获得焦点的 div 元素设置样式 */
div:focus {
- /* 去除轮廓线 */
outline: none;
}
-/* 定义一个名为 clearfix 的类选择器,用于清除浮动,通过伪元素:after 实现 */
.clearfix {
&:after {
- /* 使伪元素不可见 */
visibility: hidden;
- /* 设置伪元素的显示方式为块级元素 */
display: block;
- /* 设置伪元素的字体大小为 0 */
font-size: 0;
- /* 设置伪元素的内容为空字符串 */
content: ' ';
- /* 清除浮动 */
clear: both;
- /* 设置伪元素的高度为 0 */
height: 0;
}
}
-/* 选择 id 为 driver-popover-item 的 div 元素内的.driver-popover-title 元素,设置其文本颜色 */
-div#driver-popover-item.driver-popover-title {
+div#driver-popover-item .driver-popover-title {
color: #1890ff;
}
-
-/* 选择 id 为 driver-popover-item 的 div 元素内的.driver-popover-footer 元素内的.driver-next-btn 元素,设置其样式 */
-div#driver-popover-item.driver-popover-footer.driver-next-btn {
- /* 设置背景颜色 */
+div#driver-popover-item .driver-popover-footer .driver-next-btn {
background-color: #1890ff;
- /* 设置文本颜色为白色 */
color: white;
- /* 去除文本阴影 */
text-shadow: none;
- /* 设置元素的边框圆角为 4 像素 */
border-radius: 4px;
}
diff --git a/client/src/styles/sidebar.scss b/client/src/styles/sidebar.scss
index d09e538..74840bd 100644
--- a/client/src/styles/sidebar.scss
+++ b/client/src/styles/sidebar.scss
@@ -1,221 +1,144 @@
-// 定义主要内容区域的样式
.main-container {
- // 宽度为视口宽度减去侧边栏宽度
width: calc(100% - $sideBarWidth);
- // 高度为视口高度
height: 100%;
- // 固定定位在视口右上角
position: fixed;
top: 0;
right: 0;
- // 设置 z-index 为 9,用于控制元素的层叠顺序
z-index: 9;
- // 所有属性的过渡效果,持续时间为 0.28 秒
transition: all 0.28s;
}
-// 重写菜单样式,定义侧边栏容器的样式
+// 重写菜单样式
.sidebar-container {
- // 所有属性的过渡效果,持续时间为 0.3 秒
transition: all 0.3s;
- // 宽度为侧边栏宽度变量的值,!important 提高优先级
width: $sideBarWidth !important;
- // 高度为视口高度
height: 100%;
- // 固定定位在视口左侧
position: fixed;
top: 0;
bottom: 0;
left: 0;
- // 设置 z-index 为 1001,确保侧边栏在其他元素之上
z-index: 1001;
- // 侧边栏的背景颜色,使用变量 $menuBg
background-color: $menuBg;
- // 侧边栏滚动条包裹元素的样式
.scrollbar-wrapper {
- // 隐藏水平滚动条,!important 提高优先级
overflow-x: hidden !important;
}
- // 垂直滚动条的样式
.el-scrollbar__bar.is-vertical {
- // 滚动条靠右显示
right: 0;
}
- // 滚动条组件的样式
.el-scrollbar {
- // 高度为视口高度减去 92px
height: calc(100% - 92px);
}
- // 侧边栏有 logo 时的样式
&.has-logo {
- // PC 端滚动条的样式
.el-scrollbar.pc {
/* logo: 48px、leftCollapse: 40px、leftCollapse-shadow: 4px */
- // 高度为视口高度减去 92px
height: calc(100% - 92px);
}
- // 移动端滚动条的样式
.el-scrollbar.mobile {
- // 高度为视口高度
height: 100%;
}
}
- // 水平菜单的样式
.is-horizontal {
- // 隐藏水平菜单
display: none;
}
- // 侧边栏链接的样式
a {
- // 先设置为内联块元素,再设置为弹性布局
display: inline-block;
display: flex;
- // 左侧内边距为 10px
padding-left: 10px;
- // 子元素换行显示
flex-wrap: wrap;
- // 宽度为 100%
width: 100%;
}
- // Element UI 菜单组件的样式
.el-menu {
- // 去除菜单边框
border: none;
- // 高度为视口高度
height: 100%;
- // 背景颜色为透明,!important 提高优先级
background-color: transparent !important;
}
- // 菜单项和子菜单标题的样式
.el-menu-item,
.el-sub-menu__title {
- // 高度为 50px
height: 50px;
- // 文字颜色,使用变量 $menuText
color: $menuText;
- // 背景颜色为透明,!important 提高优先级
background-color: transparent !important;
- // 左侧内边距为 18px,!important 提高优先级
padding-left: 18px !important;
- // 鼠标悬停时的样式
&:hover {
- // 文字颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
- // 图标样式
.svg-icon {
- // 图标颜色,使用变量 $menuActiveText
color: $menuActiveText;
- // 颜色过渡效果,持续时间为 0.3 秒
transition: color 0.3s;
}
}
- // 图标样式
.svg-icon {
- // 图标颜色,使用变量 $menuText
color: $menuText;
- // 颜色过渡效果,持续时间为 0.3 秒
transition: color 0.3s;
}
- // 菜单项内的 div 和 span 元素样式
div,
span {
- // 高度为 50px
height: 50px;
- // 行高为 50px
line-height: 50px;
- // 隐藏溢出内容
overflow: hidden;
- // 溢出内容显示省略号
text-overflow: ellipsis;
}
- // 图标样式
.svg-icon {
- // 最小宽度为 1em
min-width: 1em;
- // 右侧外边距为 5px
margin-right: 5px;
}
}
- // 无子菜单的标题和子菜单标题鼠标悬停时的样式
.submenu-title-noDropdown,
.el-sub-menu__title {
&:hover {
- // 背景颜色为透明
background-color: transparent;
}
}
- // 子级选中时,父级菜单高亮显示
+ // 子级选中父级也跟着亮
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
- // 文字颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
- // 图标样式
i {
- // 图标颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
}
}
- // 激活状态的菜单项样式
.is-active {
- // 颜色过渡效果,持续时间为 0.3 秒
transition: color 0.3s;
- // 文字颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
- // 图标样式
.svg-icon {
- // 图标颜色,使用变量 $menuActiveText
color: $menuActiveText;
- // 颜色过渡效果,持续时间为 0.3 秒
transition: color 0.3s;
}
}
// 子级菜单样式
.el-menu .el-sub-menu .el-menu-item {
- // 字体大小为 12px
font-size: 12px;
- // 最小宽度为 100px,!important 提高优先级
min-width: 100px !important;
- // 背景颜色,使用变量 $subMenuBg,!important 提高优先级
background-color: $subMenuBg !important;
- // 激活状态的子级菜单项样式
&.is-active {
- // 背景颜色,使用变量 $menuActiveBg,!important 提高优先级
background: $menuActiveBg !important;
- // 文字颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
}
}
- // 菜单项样式
.el-menu .el-menu-item {
- // 菜单项提示框触发器样式
.el-menu-tooltip__trigger {
- // 内边距为 18px
padding: 18px;
}
- // 激活状态的菜单项样式
&.is-active {
- // 背景颜色,使用变量 $menuActiveBg,!important 提高优先级
background: $menuActiveBg !important;
}
}
@@ -223,224 +146,153 @@
// 菜单栏折叠时的宽度
.el-menu--collapse {
- // 宽度为折叠后侧边栏宽度变量的值
width: $hideSideBarWidth;
}
// 折叠菜单时的样式
.hideSidebar {
- // 菜单栏容器样式
+ // 菜单栏容器
.sidebar-container {
- // 宽度过渡效果,持续时间为 0.3 秒
transition: width 0.3s;
- // 宽度为折叠后侧边栏宽度变量的值,!important 提高优先级
width: $hideSideBarWidth !important;
- // 子菜单样式
.el-sub-menu {
- // 激活状态的子菜单样式
&.is-active {
- // 所有属性过渡效果,持续时间为 0.28 秒
transition: all 0.28s;
- // 文字颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
- // 相对定位
position: relative;
- // 激活状态子菜单的伪元素样式
&::after {
- // 伪元素内容为空
content: '';
- // 高度为 50px
height: 50px;
- // 左侧距离为 2px
left: 2px;
- // 绝对定位
position: absolute;
- // 顶部距离为 0
top: 0;
- // 过渡延迟 0.28 秒,!important 提高优先级
transition-delay: 0.28s !important;
- // 宽度为 2px
width: 2px;
- // 背景颜色为主题色变量的值,!important 提高优先级
background-color: var(--el-color-primary) !important;
- // 不透明度为 1
opacity: 1;
}
- // 图标样式
.svg-icon {
- // 图标颜色,使用变量 $menuActiveText
color: $menuActiveText;
- // 颜色过渡效果,持续时间为 0.3 秒
transition: color 0.3s;
}
}
}
- // 可折叠菜单标题样式
+ // 可折叠菜单
.el-sub-menu__title {
- // 内边距为 18px
padding: 18px;
}
- // 不可折叠菜单项样式
+ // 不可折叠菜单
.el-menu-item {
- // 菜单项提示框触发器样式
.el-menu-tooltip__trigger {
- // 内边距为 18px
padding: 18px;
}
}
}
- // 菜单最外层样式
+ // 菜单的最外层
.el-menu--vertical {
- // 宽度为折叠后侧边栏宽度变量的值,!important 提高优先级
width: $hideSideBarWidth !important;
- // 宽度过渡效果,持续时间为 0.3 秒
transition: width 0.3s;
}
- // 主要内容区域样式
+ // 主要内容
.main-container {
- // 宽度为视口宽度减去折叠后侧边栏宽度
width: calc(100% - $hideSideBarWidth);
}
}
-// 展开时的菜单样式
+// 展开时的菜单
.el-menu--vertical {
- // 宽度为侧边栏宽度变量的值,!important 提高优先级
width: $sideBarWidth !important;
- // 宽度过渡效果,持续时间为 0.3 秒
transition: width 0.3s;
/* 子菜单中还有子菜单 */
- // 子菜单标题样式
.el-menu .el-sub-menu__title {
- // 字体大小为 12px
font-size: 12px;
- // 背景颜色,使用变量 $subMenuBg,!important 提高优先级
background-color: $subMenuBg !important;
}
}
-// 折叠时的菜单弹出框样式
+// 折叠时的菜单
.el-menu--popup-container {
- // 菜单样式
.el-menu {
- // 背景颜色,使用变量 $subMenuBg,!important 提高优先级
background-color: $subMenuBg !important;
}
- // 菜单项和子菜单标题样式
.el-menu-item,
.el-sub-menu__title {
- // 高度为 50px
height: 50px;
- // 文字颜色,使用变量 $menuText
color: $menuText;
- // 背景颜色为透明,!important 提高优先级
background-color: transparent !important;
- // 鼠标悬停时的样式
&:hover {
- // 文字颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
- // 图标样式
.svg-icon {
- // 图标颜色,使用变量 $menuActiveText
color: $menuActiveText;
- // 颜色过渡效果,持续时间为 0.3 秒
transition: color 0.3s;
}
}
- // 图标样式
.svg-icon {
- // 图标颜色,使用变量 $menuText
color: $menuText;
- // 颜色过渡效果,持续时间为 0.3 秒
transition: color 0.3s;
}
- // 菜单项内的 div 和 span 元素样式
div,
span {
- // 高度为 50px
height: 50px;
- // 行高为 50px
line-height: 50px;
- // 隐藏溢出内容
overflow: hidden;
- // 溢出内容显示省略号
text-overflow: ellipsis;
}
}
- // 无子菜单的标题和子菜单标题鼠标悬停时的样式
.submenu-title-noDropdown,
.el-sub-menu__title {
&:hover {
- // 背景颜色为透明
background-color: transparent;
}
}
- // 子级选中时,父级菜单高亮显示
.is-active > .el-sub-menu__title,
.is-active.submenu-title-noDropdown {
- // 文字颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
- // 图标样式
i {
- // 图标颜色,使用变量 $menuActiveText,!important 提高优先级
color: $menuActiveText !important;
}
}
- // 菜单项样式
.el-menu .el-menu-item {
- // 字体大小为 12px,!important 提高优先级
font-size: 12px !important;
- // 最小宽度为 100px,!important 提高优先级
min-width: 100px !important;
- // 背景颜色,使用变量 $subMenuBg,!important 提高优先级
background-color: $subMenuBg !important;
- // 激活状态的菜单项样式
&.is-active {
- // 背景颜色,使用变量 $menuHover,!important 提高优先级
background: $menuHover !important;
}
}
- // 激活状态的菜单项样式
.el-menu .el-menu-item {
&.is-active {
- // 背景颜色,使用变量 $menuHover,!important 提高优先级
background: $menuHover !important;
}
}
}
-// 修复折叠后闪烁的 bug
+// 修复折叠后闪烁的bug
.is-active {
- // 激活状态元素的伪元素样式
&::after {
- // 伪元素内容为空
content: '';
- // 不透明度为 1,!important 提高优先级
opacity: 1 !important;
}
- // 菜单图标样式
.menu-icon {
- // 无过渡效果,!important 提高优先级
transition: none !important;
- // 图标颜色为白色,!important 提高优先级
color: #fff !important;
}
}
diff --git a/client/src/styles/theme.scss b/client/src/styles/theme.scss
index 5599412..dbdc497 100644
--- a/client/src/styles/theme.scss
+++ b/client/src/styles/theme.scss
@@ -1,19 +1,15 @@
-/* 定义一个名为.large-card-font 的类选择器,用于设置卡片上数字的样式 */
+// 卡片数字
.large-card-font {
- /* 使用 @apply 指令,应用其他样式类的样式,这里应用了 font-semibold(半粗体字体)和 text-2xl(字体大小为 2 倍大)这两个样式类 */
@apply font-semibold text-2xl;
- /* 设置文本颜色为 RGB 值为 (41, 137, 255) 的颜色 */
color: rgb(41, 137, 255);
}
-/* 定义一个名为.text-main 的类选择器,用于设置文本的主要颜色 */
+// 字体颜色
.text-main {
- /* 设置文本颜色为十六进制颜色值 #cecece */
color: #cecece;
}
-/* 定义一个名为.border-main 的类选择器,用于设置默认的边框颜色和样式 */
+// 默认边框颜色
.border-main {
- /* 设置边框为 1 像素宽的实线,颜色为十六进制颜色值 #cfcfcf */
border: #cfcfcf solid 1px;
}
diff --git a/client/src/styles/transition.scss b/client/src/styles/transition.scss
index bc96ddd..2cc15ce 100644
--- a/client/src/styles/transition.scss
+++ b/client/src/styles/transition.scss
@@ -1,43 +1,31 @@
-/* 定义面包屑进入和离开时的活跃状态样式,设置过渡效果 */
+// 面包屑动画
.breadcrumb-enter-active,
.breadcrumb-leave-active {
- /* 所有属性的过渡效果,持续时间为 0.5 秒 */
transition: all 0.5s;
}
-/* 定义面包屑进入前的状态和离开时的活跃状态(这里似乎重复定义了离开活跃状态,可能存在错误)的样式 */
.breadcrumb-enter-from,
.breadcrumb-leave-active {
- /* 透明度设置为 0 */
opacity: 0;
- /* 水平方向平移 20 像素 */
transform: translateX(20px);
}
-/* 再次定义面包屑离开时的活跃状态样式,设置为绝对定位 */
.breadcrumb-leave-active {
position: absolute;
}
-/* 定义页面切换时的过渡动画相关类的样式,设置进入和离开时的活跃状态的过渡效果 */
+/* 页面切换过渡动画 */
.fade-transform-leave-active,
.fade-transform-enter-active {
- /* 所有属性的过渡效果,持续时间为 0.28 秒 */
transition: all 0.28s;
}
-/* 定义页面切换时进入前的状态样式 */
.fade-transform-enter-from {
- /* 透明度设置为 0 */
opacity: 0;
- /* 水平向左平移 30 像素 */
transform: translateX(-30px);
}
-/* 定义页面切换时离开到的状态样式 */
.fade-transform-leave-to {
- /* 透明度设置为 0 */
opacity: 0;
- /* 水平向右平移 30 像素 */
transform: translateX(30px);
}
diff --git a/client/src/styles/variables.module.scss b/client/src/styles/variables.module.scss
index 82562d4..9099d65 100644
--- a/client/src/styles/variables.module.scss
+++ b/client/src/styles/variables.module.scss
@@ -1,43 +1,24 @@
-// 定义侧边栏相关的样式变量
-
-// 侧边栏菜单文本的默认颜色,这里的颜色值 #fefefea6 表示带有一定透明度的白色
+// sidebar
$menuText: #fefefea6;
-// 侧边栏菜单激活时(选中时)文本的颜色,为纯白色
$menuActiveText: #fff;
-// 侧边栏菜单的背景颜色,设置为深色调 #031429
$menuBg: #031429;
-// 侧边栏菜单激活时(选中时)的背景颜色,为蓝色调 #558df6
$menuActiveBg: #558df6;
-// 侧边栏菜单项鼠标悬停时的背景颜色,同样为蓝色调 #558df6
$menuHover: #558df6;
-// 子菜单的背景颜色,设置为较深的颜色 #0e0303
$subMenuBg: #0e0303;
-// 隐藏的子菜单背景颜色,设置为更深的颜色 #00061a
$subHideMenuBg: #00061a;
-// 侧边栏展开时的宽度,设置为 210 像素
$sideBarWidth: 210px;
-// 侧边栏折叠时的宽度,设置为 54 像素
$hideSideBarWidth: 54px;
-// 使用 :export 指令将定义的变量导出,以便在其他地方(如 JavaScript 中)使用
:export {
- // 将 $menuText 变量导出为 menuText
menuText: $menuText;
- // 将 $menuActiveText 变量导出为 menuActiveText
menuActiveText: $menuActiveText;
- // 将 $menuBg 变量导出为 menuBg
menuBg: $menuBg;
- // 将 $menuHover 变量导出为 menuHover
menuHover: $menuHover;
- // 将 $subMenuBg 变量导出为 subMenuBg
subMenuBg: $subMenuBg;
- // 将 $subHideMenuBg 变量导出为 subHideMenuBg
subHideMenuBg: $subHideMenuBg;
- // 将 $sideBarWidth 变量导出为 sideBarWidth
sideBarWidth: $sideBarWidth;
- // 将 $hideSideBarWidth 变量导出为 hideSideBarWidth
hideSideBarWidth: $hideSideBarWidth;
}
diff --git a/client/src/styles/variables.module.scss.d.ts b/client/src/styles/variables.module.scss.d.ts
index 1576325..a4be38b 100644
--- a/client/src/styles/variables.module.scss.d.ts
+++ b/client/src/styles/variables.module.scss.d.ts
@@ -1,25 +1,12 @@
-// 定义一个接口 IVariables,用于描述包含侧边栏样式相关变量的对象结构
export interface IVariables {
- // 菜单文本的颜色,类型为字符串
menuText: string
- // 菜单激活时文本的颜色,类型为字符串
menuActiveText: string
- // 菜单的背景颜色,类型为字符串
menuBg: string
- // 菜单鼠标悬停时的背景颜色,类型为字符串
menuHover: string
- // 子菜单的背景颜色,类型为字符串
subMenuBg: string
- // 隐藏子菜单的背景颜色,类型为字符串
subHideMenuBg: string
- // 侧边栏展开时的宽度,类型为字符串
sideBarWidth: string
- // 侧边栏折叠时的宽度,类型为字符串
hideSideBarWidth: string
}
-
-// 声明一个名为 styles 的变量,其类型为 IVariables,但未初始化
export const styles: IVariables
-
-// 默认导出 styles 变量,但由于未初始化,可能在使用时需要注意
export default styles
diff --git a/client/src/types/global.d.ts b/client/src/types/global.d.ts
index 3fc7117..e0636d7 100644
--- a/client/src/types/global.d.ts
+++ b/client/src/types/global.d.ts
@@ -1,23 +1,11 @@
/** 文件类型 */
-// 声明一个模块,用于处理.svg 结尾的文件,这样在 TypeScript 中就可以导入.svg 文件而不会报错,
-// 但这里只是简单声明,没有定义具体的类型,意味着导入该类型文件时会被视为 any 类型
declare module '*.svg'
-// 声明用于处理.png 结尾的文件的模块
declare module '*.png'
-// 声明用于处理.jpg 结尾的文件的模块
declare module '*.jpg'
-// 声明用于处理.jpeg 结尾的文件的模块
declare module '*.jpeg'
-// 声明用于处理.gif 结尾的文件的模块
declare module '*.gif'
-// 声明用于处理.bmp 结尾的文件的模块
declare module '*.bmp'
-// 声明用于处理.tiff 结尾的文件的模块
declare module '*.tiff'
-// 声明用于处理.yaml 结尾的文件的模块
declare module '*.yaml'
-// 声明用于处理.json 结尾的文件的模块
declare module '*.json'
-// 声明用于处理 vue-count-to 模块,可能是为了在项目中使用 vue-count-to 这个 Vue 插件时,
-// 让 TypeScript 知道它的存在,即使没有具体的类型定义,也能正常导入和使用(类型为 any)
declare module 'vue-count-to'
diff --git a/client/src/types/vuex.d.ts b/client/src/types/vuex.d.ts
index 7b5e133..80d2f40 100644
--- a/client/src/types/vuex.d.ts
+++ b/client/src/types/vuex.d.ts
@@ -1,17 +1,12 @@
-// 从 'vuex' 库中导入 Store 和 Module 类型
+// vuex.d.ts
import { Store, Module } from 'vuex'
-// 从 './store/types' 文件中导入 IStoreType 类型,这个类型应该定义了 Vuex 存储的状态结构
import { type IStoreType } from './store/types'
-// 模块扩展,用于在 Vue 运行时核心模块中添加自定义类型声明
-// 这样做可以让 TypeScript 知道在 Vue 组件中 this.$store 的具体类型
+// 模块扩展
+// 模板内$store强类型支持
declare module '@vue/runtime-core' {
// 为 `this.$store` 提供类型声明
- // ComponentCustomProperties 是 Vue 中用于扩展组件自定义属性的接口
interface ComponentCustomProperties {
- // 声明 $store 属性,其类型为 Store
- // Store 是 Vuex 中的存储类,IStoreType 是之前导入的状态类型
- // 这意味着在 Vue 组件中使用 this.$store 时,TypeScript 会进行类型检查,确保操作符合 IStoreType 的定义
$store: Store
}
}
diff --git a/client/src/utils/commonUtil.ts b/client/src/utils/commonUtil.ts
index 191e548..8258bd6 100644
--- a/client/src/utils/commonUtil.ts
+++ b/client/src/utils/commonUtil.ts
@@ -1,47 +1,46 @@
-// 导出一个函数initArray,用于初始化数组
-// 如果传入的array存在则返回array,否则返回一个空数组
+// TODO 初始化Array
export const initArray = (array: any) => {
- return array? array : [];
+ return array ? array : [];
};
-// 导出一个函数arrayPushAllByFiled,用于将一个数组中某个字段的所有值添加到另一个数组
+// TODO 将一个Array的某个字段所有的值全部添加到了一个Array
export const arrayPushAllByFiled = (dataArray: any, pushArray: any, field: any) => {
- // 初始化dataArray和pushArray
+ // 初始化
dataArray = initArray(dataArray);
pushArray = initArray(pushArray);
- // 法一:使用for...of循环遍历dataArray,将每个元素的指定字段值添加到pushArray中
+ // 法一
// for (const item of dataArray) {
// pushArray.push(item[field]);
// }
// return pushArray;
- // 法二:使用map方法遍历dataArray,返回一个包含所有指定字段值的新数组
+ // 法二
return dataArray.map((item: any) => item[field]);
};
-// 导出一个函数arrayPushAllByObj,用于将一个数组的数据全部添加到另一个数组
+// TODO 将一个Array的数据全部添加到了一个Array
export const arrayPushAllByObj = (dataArray: any, pushArray: any) => {
- // 初始化dataArray和pushArray
+ // 初始化
dataArray = initArray(dataArray);
pushArray = initArray(pushArray);
- // 使用展开运算符将dataArray的所有元素添加到pushArray中
+ // push
pushArray.push(...dataArray);
return pushArray;
};
-// 导出一个函数arrayDeduplicationByFiled,用于根据指定字段对数组进行去重
+// TODO Array根据字段去重
export const arrayDeduplicationByFiled = (array: any, field: string) => {
- // 初始化array
+ // 初始化
array = initArray(array);
- // 去重 法一:使用Set和map方法对指定字段进行去重,返回一个包含去重后字段值的新数组
+ // 去重 法一:该方法对编号进行去重返回的是[1,3,5]的编号数组
// const idArray = [...new Set(array.map((item: any) => item[field]))];
// 再使用for循环依次取出id对应数据即可
- // 去重 法二:使用reduce方法遍历数组,检查当前对象的指定字段是否已存在于新数组中,不存在则添加
+ // 去重 法二
return array.reduce((newArray: any, thisObj: any) => {
// 检查当前对象的属性是否已经存在于新数组中
const exists = newArray.some((item: any) => thisObj[field] === item[field]);
@@ -53,16 +52,16 @@ export const arrayDeduplicationByFiled = (array: any, field: string) => {
}, []);
};
-// 导出一个函数arrayDeduplicationByObj,用于根据对象对数组进行去重(适用于非对象数组)
+// TODO Array根据对象去重(适用于非对象数组)
export const arrayDeduplicationByObj = (array: any) => {
- // 初始化array
+ // 初始化
array = initArray(array);
- // 去重 法一:使用Set和map方法对数组元素进行去重,返回一个包含去重后元素的新数组
+ // 去重 法一:该方法对编号进行去重返回的是[1,3,5]的编号数组
// const idArray = [...new Set(array.map((item: any) => item))];
// 再使用for循环依次取出id对应数据即可
- // 去重 法二:使用reduce方法遍历数组,检查当前对象是否已存在于新数组中,不存在则添加
+ // 去重 法二
return array.reduce((newArray: any, thisObj: any) => {
// 检查当前对象的属性是否已经存在于新数组中
const exists = newArray.some((item: any) => thisObj === item);
diff --git a/client/src/utils/formRules.ts b/client/src/utils/formRules.ts
index 1b6ac04..9953f35 100644
--- a/client/src/utils/formRules.ts
+++ b/client/src/utils/formRules.ts
@@ -1,4 +1,4 @@
-// 从 @/utils/is 模块中导入多个用于验证的函数
+// 电话规则
import {
isNotEmail,
isNotIdNum,
@@ -7,58 +7,43 @@ import {
isNotNumber
} from "@/utils/is";
-// 电话规则验证函数
+// 电话规则
export function phoneRule(rule: any, value: any, callback: any, field: string) {
- // 去除输入值的首尾空格
const trim = value?.trim();
- // 如果输入值为空
if (!trim) {
- // 调用回调函数并传递错误信息,提示电话不能为空
callback(new Error(field + "电话不能为空"));
} else if (isNotPhone(trim)) {
- // 如果输入值不是有效的电话号码格式
callback(new Error(field + "电话格式有误"));
} else {
- // 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
-// 邮箱规则验证函数
+// 邮箱规则
export function emailRule(rule: any, value: any, callback: any, field: string) {
- // 去除输入值的首尾空格
const trim = value?.trim();
- // 如果输入值为空
if (!trim) {
- // 调用回调函数并传递错误信息,提示邮箱不能为空
callback(new Error(field + "邮箱不能为空"));
} else if (isNotEmail(trim)) {
- // 如果输入值不是有效的邮箱格式
callback(new Error(field + "邮箱格式有误"));
} else {
- // 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
-// 身份证号规则验证函数
+// 身份证号规则
export function idNumRule(rule: any, value: any, callback: any, field: string) {
- // 去除输入值的首尾空格
const trim = value?.trim();
- // 如果输入值为空
if (!trim) {
- // 调用回调函数并传递错误信息,提示身份证号不能为空
callback(new Error(field + "身份证号不能为空"));
} else if (isNotIdNum(trim)) {
- // 如果输入值不是有效的身份证号格式
callback(new Error(field + "身份证号格式有误"));
} else {
- // 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
-// 字符串规则验证函数
+// 字符串规则
export function stringRule(
rule: any,
value: any,
@@ -67,22 +52,17 @@ export function stringRule(
mixLen: number,
maxLen: number
) {
- // 去除输入值的首尾空格
const trim = value?.trim();
- // 如果输入值为空
if (!trim) {
- // 调用回调函数并传递错误信息,提示该字段不能为空
callback(new Error(field + "不能为空"));
} else if (trim.length < mixLen || trim.length > maxLen) {
- // 如果输入值的长度不在指定范围内
callback(new Error(field + "长度应为" + mixLen + "~" + maxLen));
} else {
- // 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
-// 数字(整数/小数)规则验证函数
+// 数字(整数/小数)规则
export function numberRule(
rule: any,
value: any,
@@ -91,27 +71,21 @@ export function numberRule(
mix: number,
max: number
) {
- // 如果输入值为空
if (!value) {
- // 调用回调函数并传递错误信息,提示该字段不能为空
callback(new Error(field + "不能为空"));
} else {
- // 将输入值转换为字符串并去除首尾空格
const trim = value.toString()?.trim();
- // 如果输入值不是有效的数字格式
if (isNotNumber(trim)) {
callback(new Error(field + "格式有误"));
} else if (trim < mix || trim > max) {
- // 如果输入值不在指定的数字范围内
callback(new Error(field + "应该在" + mix + "~" + max + "之间"));
} else {
- // 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
}
-// 整数规则验证函数
+// 整数规则
export function integerRule(
rule: any,
value: any,
@@ -120,32 +94,24 @@ export function integerRule(
mix: number,
max: number
) {
- // 如果输入值为空
if (!value) {
- // 调用回调函数并传递错误信息,提示该字段不能为空
callback(new Error(field + "不能为空"));
} else {
- // 将输入值转换为字符串并去除首尾空格
const trim = value.toString()?.trim();
- // 如果输入值不是有效的整数格式
if (isNotInteger(trim)) {
callback(new Error(field + "格式有误"));
} else if (trim < mix || trim > max) {
- // 如果输入值不在指定的整数范围内
callback(new Error(field + "应该在" + mix + "~" + max + "之间"));
} else {
- // 如果输入值有效,调用回调函数且不传递错误信息
callback();
}
}
}
-// 日期规则验证函数,禁用当前时间之前的日期
+// 日期规则
export const disabledNowBeforeDate = (time: Date) => {
return time.getTime() < Date.now();
};
-
-// 日期规则验证函数,禁用当前时间之后的日期
export const disabledNowAfterDate = (time: Date) => {
return time.getTime() > Date.now();
};
diff --git a/client/src/utils/http/index.ts b/client/src/utils/http/index.ts
index f2af8ec..7aad11f 100644
--- a/client/src/utils/http/index.ts
+++ b/client/src/utils/http/index.ts
@@ -1,52 +1,35 @@
-// 从 '@/store' 导入 Vuex 的 store 实例
import store from "@/store";
-// 导入 axios 库,并解构出 AxiosRequestConfig 和 AxiosResponse 类型
import baseAxios, { AxiosRequestConfig, AxiosResponse } from "axios";
-// 从 'element-plus' 导入 ElMessage 用于显示消息提示
import { ElMessage } from "element-plus";
-// 定义基础 URL
export const baseUrl = "http://127.0.0.1:9001/";
-// 创建一个 axios 实例,设置基础 URL、超时时间和默认 headers
const axios = baseAxios.create({
- baseURL: "", // 这里可以根据实际情况设置基础 URL,如果为空则使用全局的 baseUrl
- timeout: 5000, // 设置请求超时时间为 5000 毫秒
- headers: {} // 可以在这里设置默认的请求头
+ baseURL: "",
+ timeout: 5000,
+ headers: {}
});
-// 请求拦截器,在请求发送前会被调用
+// 请求拦截器
axios.interceptors.request.use((config: any) => {
- // 从 localStorage 中获取名为 "stateData" 的数据,并解析为 JSON 对象
- // 然后尝试获取其中的 app.token 作为令牌
const token = JSON.parse(localStorage.getItem("stateData")!)?.app?.token;
- // 将令牌设置到请求头的 "token" 字段中
config.headers.token = token;
- // 返回配置好的请求对象
return config;
});
-// 响应拦截器,在接收到响应后会被调用
+// 响应拦截器
axios.interceptors.response.use(
(res: AxiosResponse) => {
- // 如果响应数据中的 code 为 500 且 msg 为 "令牌无效"
if (res.data.code === 500 && res.data.msg === "令牌无效") {
- // 调用 store 的 app/logout 方法进行登出操作
store.dispatch("app/logout");
- // 显示错误消息提示 "登录过期,请重新登录"
ElMessage.error({ message: "登录过期,请重新登录" });
}
- // 如果响应数据中的 err 为 1
if (res.data.err === 1) {
- // 则返回一个被拒绝的 Promise,携带响应数据
return Promise.reject(res.data);
}
- // 返回响应数据
return res.data;
},
- // 如果响应出现错误,返回一个被拒绝的 Promise,携带错误信息
- err => Promise.reject(err)
+ err => Promise.reject(err) // 响应出问题
);
-// 默认导出创建好的 axios 实例
export default axios;
diff --git a/client/src/utils/index.ts b/client/src/utils/index.ts
index bf6a3d8..0135629 100644
--- a/client/src/utils/index.ts
+++ b/client/src/utils/index.ts
@@ -1,7 +1,3 @@
-// 从 './http' 文件中导入名为 http 的模块
-// 这里假设 './http' 文件中导出了一个名为 http 的对象,这个对象可能是封装好的 HTTP 请求工具,例如使用 axios 封装的请求实例
import http from './http'
-// 导出导入的 http 对象
-// 这样其他文件就可以通过导入这个文件来使用 http 对象进行 HTTP 请求操作
export { http }
diff --git a/client/src/utils/is/index.ts b/client/src/utils/is/index.ts
index 77c8660..3f4c3ff 100644
--- a/client/src/utils/is/index.ts
+++ b/client/src/utils/is/index.ts
@@ -1,277 +1,174 @@
-// 获取 Object.prototype.toString 方法的引用,用于后续类型判断
-const toString = Object.prototype.toString;
-// 定义一个正则表达式,用于校验保留两位小数的实数
-// 支持正负号,整数部分可以是 0 或者以 1 - 9 开头的数字串,小数部分可以有 1 到 2 位
-const REGEXP_NUMBER = /^[+-]?(0|([1-9]\d*))(\.\d{1,2})?$/;
-// 定义一个正则表达式,用于校验邮箱格式
-// 要求邮箱由字母、数字组成,中间有 @ 符号,并且有正确的域名和顶级域名
-const REGEXP_EMAIL = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/;
-// 定义一个正则表达式,用于校验手机号格式
-// 要求手机号以 1 开头,第二位是 3 - 9 中的一个数字,后面跟着 9 位数字
-const REGEXP_PHONE = /^1[3456789]\d{9}$/;
-// 定义一个正则表达式,用于校验身份证号格式
-// 符合中国 18 位身份证号码的格式规则
+const toString = Object.prototype.toString
+// 保留两位小数的实数校验规则
+const REGEXP_NUMBER = /^[+-]?(0|([1-9]\d*))(\.\d{1,2})?$/
+// 密码校验规则
+const REGEXP_EMAIL = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+$/
+// 手机号校验规则
+const REGEXP_PHONE = /^1[3456789]\d{9}$/
+// 身份证号校验规则
const REGEXP_ID_NUM =
- /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
+ /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
/**
* @description: 判断值是否为账号(手机号/邮箱)
- * @param {string} account - 待判断的账号字符串
- * @returns {boolean} - 如果既不是手机号也不是邮箱,返回 true;否则返回 false
*/
export function isNotAccount(account: string) {
- // 使用正则表达式检查账号是否既不是手机号也不是邮箱
- return !REGEXP_PHONE.test(account) && !REGEXP_EMAIL.test(account);
+ return !REGEXP_PHONE.test(account) && !REGEXP_EMAIL.test(account)
}
/**
* @description: 判断值是否为手机号
- * @param {string} phone - 待判断的手机号字符串
- * @returns {boolean} - 如果不是手机号,返回 true;否则返回 false
*/
export function isNotPhone(phone: string) {
- // 使用正则表达式检查是否不是手机号
- return !REGEXP_PHONE.test(phone);
+ return !REGEXP_PHONE.test(phone)
}
/**
* @description: 判断值是否为邮箱
- * @param {string} email - 待判断的邮箱字符串
- * @returns {boolean} - 如果不是邮箱,返回 true;否则返回 false
*/
export function isNotEmail(email: string) {
- // 使用正则表达式检查是否不是邮箱
- return !REGEXP_EMAIL.test(email);
+ return !REGEXP_EMAIL.test(email)
}
/**
* @description: 判断值是否为身份证号
- * @param {string} idNum - 待判断的身份证号字符串
- * @returns {boolean} - 如果不是身份证号,返回 true;否则返回 false
*/
export function isNotIdNum(idNum: string) {
- // 使用正则表达式检查是否不是身份证号
- return !REGEXP_ID_NUM.test(idNum);
+ return !REGEXP_ID_NUM.test(idNum)
}
/**
* @description: 判断值是否为数字
- * @param {string} num - 待判断的数字字符串
- * @returns {boolean} - 如果不是符合规则的数字,返回 true;否则返回 false
*/
export function isNotNumber(num: string) {
- // 使用正则表达式检查是否不是符合规则的数字
- return !REGEXP_NUMBER.test(num);
+ return !REGEXP_NUMBER.test(num)
}
/**
* @description: 判断值是否为整数
- * @param {number} num - 待判断的数字
- * @returns {boolean} - 如果不是整数,返回 true;否则返回 false
*/
export function isNotInteger(num: number) {
- // 使用 Number.isInteger 方法检查是否不是整数
- return !Number.isInteger(Number(num));
+ return !Number.isInteger(Number(num))
}
/**
- * @description: 判断值是否为某个类型
- * @param {unknown} val - 待判断的值
- * @param {string} type - 要判断的类型名称
- * @returns {boolean} - 如果值是指定类型,返回 true;否则返回 false
+ * @description: 判断值是否未某个类型
*/
export function is(val: unknown, type: string) {
- // 使用 toString 方法获取值的类型字符串,并与指定类型比较
- return toString.call(val) === `[object ${type}]`;
+ return toString.call(val) === `[object ${type}]`
}
/**
- * @description: 是否为函数
- * @param {unknown} val - 待判断的值
- * @returns {val is T} - 如果是函数,返回 true;否则返回 false
+ * @description: 是否为函数
*/
export function isFunction void>(val: unknown): val is T {
- // 调用 is 函数判断是否为 Function 类型
- return is(val, 'Function');
+ return is(val, 'Function')
}
/**
* @description: 是否已定义
- * @param {T} val - 待判断的值
- * @returns {val is T} - 如果值已定义(不是 undefined),返回 true;否则返回 false
*/
export const isDef = (val?: T): val is T => {
- // 使用 typeof 检查值是否不是 undefined
- return typeof val !== 'undefined';
+ return typeof val !== 'undefined'
}
-/**
- * @description: 是否未定义
- * @param {T} val - 待判断的值
- * @returns {val is T} - 如果值未定义(是 undefined),返回 true;否则返回 false
- */
export const isUnDef = (val?: T): val is T => {
- // 调用 isDef 函数取反判断是否未定义
- return !isDef(val);
+ return !isDef(val)
}
-
/**
* @description: 是否为对象
- * @param {any} val - 待判断的值
- * @returns {val is Record} - 如果是对象且不为 null,返回 true;否则返回 false
*/
export const isObject = (val: any): val is Record => {
- // 检查值不为 null 且是 Object 类型
- return val !== null && is(val, 'Object');
+ return val !== null && is(val, 'Object')
}
/**
- * @description: 是否为时间
- * @param {unknown} val - 待判断的值
- * @returns {val is Date} - 如果是 Date 类型,返回 true;否则返回 false
+ * @description: 是否为时间
*/
export function isDate(val: unknown): val is Date {
- // 调用 is 函数判断是否为 Date 类型
- return is(val, 'Date');
+ return is(val, 'Date')
}
/**
- * @description: 是否为数值
- * @param {unknown} val - 待判断的值
- * @returns {val is number} - 如果是 Number 类型,返回 true;否则返回 false
+ * @description: 是否为数值
*/
export function isNumber(val: unknown): val is number {
- // 调用 is 函数判断是否为 Number 类型
- return is(val, 'Number');
+ return is(val, 'Number')
}
/**
- * @description: 是否为 AsyncFunction
- * @param {unknown} val - 待判断的值
- * @returns {val is Promise} - 如果是 AsyncFunction 类型,返回 true;否则返回 false
- * 注:这里类型标注有误,实际应是检查是否为异步函数类型
+ * @description: 是否为AsyncFunction
*/
export function isAsyncFunction(val: unknown): val is Promise {
- // 调用 is 函数判断是否为 AsyncFunction 类型
- return is(val, 'AsyncFunction');
+ return is(val, 'AsyncFunction')
}
/**
- * @description: 是否为 promise
- * @param {unknown} val - 待判断的值
- * @returns {val is Promise} - 如果是 Promise 对象,返回 true;否则返回 false
+ * @description: 是否为promise
*/
export function isPromise(val: unknown): val is Promise {
- // 检查值是 Promise 类型,是对象,且有 then 和 catch 方法
return (
is(val, 'Promise') &&
isObject(val) &&
isFunction(val.then) &&
isFunction(val.catch)
- );
+ )
}
/**
- * @description: 是否为字符串
- * @param {unknown} val - 待判断的值
- * @returns {val is string} - 如果是 String 类型,返回 true;否则返回 false
+ * @description: 是否为字符串
*/
export function isString(val: unknown): val is string {
- // 调用 is 函数判断是否为 String 类型
- return is(val, 'String');
+ return is(val, 'String')
}
/**
- * @description: 是否为 boolean 类型
- * @param {unknown} val - 待判断的值
- * @returns {val is boolean} - 如果是 Boolean 类型,返回 true;否则返回 false
+ * @description: 是否为boolean类型
*/
export function isBoolean(val: unknown): val is boolean {
- // 调用 is 函数判断是否为 Boolean 类型
- return is(val, 'Boolean');
+ return is(val, 'Boolean')
}
/**
- * @description: 是否为数组
- * @param {any} val - 待判断的值
- * @returns {val is Array} - 如果是数组,返回 true;否则返回 false
+ * @description: 是否为数组
*/
export function isArray(val: any): val is Array {
- // 检查值存在且是数组
- return val && Array.isArray(val);
+ return val && Array.isArray(val)
}
/**
* @description: 是否客户端
- * @returns {boolean} - 如果在客户端环境(window 对象存在),返回 true;否则返回 false
*/
export const isClient = () => {
- // 检查 window 对象是否已定义
- return typeof window !== 'undefined';
+ return typeof window !== 'undefined'
}
/**
* @description: 是否为浏览器
- * @param {any} val - 待判断的值
- * @returns {val is Window} - 如果是 window 对象,返回 true;否则返回 false
*/
export const isWindow = (val: any): val is Window => {
- // 检查 window 对象已定义且值是 Window 类型
- return typeof window !== 'undefined' && is(val, 'Window');
+ return typeof window !== 'undefined' && is(val, 'Window')
}
-/**
- * @description: 是否为元素
- * @param {unknown} val - 待判断的值
- * @returns {val is Element} - 如果是 DOM 元素,返回 true;否则返回 false
- */
export const isElement = (val: unknown): val is Element => {
- // 检查值是对象且有 tagName 属性
- return isObject(val) && !!val.tagName;
+ return isObject(val) && !!val.tagName
}
-/**
- * @description: 是否为服务器端
- * @type {boolean} - 如果在服务器端环境(window 对象不存在),值为 true;否则为 false
- */
-export const isServer = typeof window === 'undefined';
+export const isServer = typeof window === 'undefined'
-/**
- * @description: 是否为图片节点
- * @param {Element} o - 待判断的 DOM 元素
- * @returns {boolean} - 如果是图片元素,返回 true;否则返回 false
- */
+// 是否为图片节点
export function isImageDom(o: Element) {
- // 检查元素存在且标签名是 IMAGE 或 IMG
- return o && ['IMAGE', 'IMG'].includes(o.tagName);
+ return o && ['IMAGE', 'IMG'].includes(o.tagName)
}
-/**
- * @description: 是否为 null
- * @param {unknown} val - 待判断的值
- * @returns {val is null} - 如果值为 null,返回 true;否则返回 false
- */
export function isNull(val: unknown): val is null {
- // 检查值是否等于 null
- return val === null;
+ return val === null
}
-/**
- * @description: 是否同时为 null 和 undefined(此逻辑有误,实际不可能同时成立)
- * @param {unknown} val - 待判断的值
- * @returns {val is null | undefined} - 如果值同时为 null 和 undefined,返回 true;否则返回 false
- */
export function isNullAndUnDef(val: unknown): val is null | undefined {
- // 调用 isUnDef 和 isNull 函数判断
- return isUnDef(val) && isNull(val);
+ return isUnDef(val) && isNull(val)
}
-/**
- * @description: 是否为 null 或 undefined
- * @param {unknown} val - 待判断的值
- * @returns {val is null | undefined} - 如果值为 null 或 undefined,返回 true;否则返回 false
- */
export function isNullOrUnDef(val: unknown): val is null | undefined {
- // 调用 isUnDef 和 isNull 函数取或判断
- return isUnDef(val) || isNull(val);
+ return isUnDef(val) || isNull(val)
}
diff --git a/client/src/utils/util.ts b/client/src/utils/util.ts
index 5a739fb..3714383 100644
--- a/client/src/utils/util.ts
+++ b/client/src/utils/util.ts
@@ -1,55 +1,37 @@
-// 从 './is' 文件中导入 isArray 函数,用于判断一个值是否为数组
import { isArray } from './is'
-// 定义一个函数 formatValue,用于格式化传入的值
export function formatValue(callValue: any) {
- // 如果传入的值是数组,使用 '/' 拼接数组元素(如果数组有元素),否则返回 '--'
- if (isArray(callValue)) return callValue.length? callValue.join(' / ') : '--'
- // 如果传入的值不是数组,直接返回该值,如果值为 null 或 undefined,则返回 '--'
- return callValue?? '--'
+ // 如果当前值为数组,使用 / 拼接(根据需求自定义)
+ if (isArray(callValue)) return callValue.length ? callValue.join(' / ') : '--'
+ return callValue ?? '--'
}
-// 定义一个函数 handleRowAccordingToProp,根据属性路径处理行数据
export function handleRowAccordingToProp(
- row: { [key: string]: any }, // 表示一个对象,键为字符串类型,值为任意类型
- prop: string // 表示属性路径字符串
+ row: { [key: string]: any },
+ prop: string
) {
- // 如果属性路径中不包含 '.',直接返回行数据中该属性的值,如果值为 null 或 undefined,则返回 '--'
- if (!prop.includes('.')) return row[prop]?? '--'
- // 如果属性路径中包含 '.',按 '.' 分割属性路径,依次获取嵌套对象的属性值
- prop.split('.').forEach(item => (row = row[item]?? '--'))
- // 返回最终获取到的值
+ if (!prop.includes('.')) return row[prop] ?? '--'
+ prop.split('.').forEach(item => (row = row[item] ?? '--'))
return row
}
-// 定义一个函数 handleProp,处理属性路径字符串
export function handleProp(prop: string) {
- // 按 '.' 分割属性路径字符串,得到一个数组
const propArr = prop.split('.')
- // 如果分割后的数组长度为 1,说明属性路径没有嵌套,直接返回原属性路径字符串
if (propArr.length == 1) return prop
- // 如果数组长度大于 1,返回属性路径字符串中最后一个部分
return propArr[propArr.length - 1]
}
-// 定义一个函数 filterEnum,根据枚举数据过滤并格式化值
export function filterEnum(
- callValue: any, // 要过滤的值
- enumData: any[] | undefined, // 枚举数据数组或 undefined
- fieldNames?: { label: string; value: string }, // 可选的字段名称配置对象,默认为 { label: 'label', value: 'value' }
- type?: 'tag' // 可选的类型,默认为 undefined
+ callValue: any,
+ enumData: any[] | undefined,
+ fieldNames?: { label: string; value: string },
+ type?: 'tag'
): string {
- // 获取字段名称配置中的 'value' 字段名,如果未提供则默认为 'value'
- const value = fieldNames?.value?? 'value'
- // 获取字段名称配置中的 'label' 字段名,如果未提供则默认为 'label'
- const label = fieldNames?.label?? 'label'
- // 定义一个空对象,用于存储过滤后的数据
+ const value = fieldNames?.value ?? 'value'
+ const label = fieldNames?.label ?? 'label'
let filterData: { [key: string]: any } = {}
- // 如果枚举数据是一个数组,查找与传入值匹配的枚举项
if (Array.isArray(enumData))
filterData = enumData.find((item: any) => item[value] === callValue)
- // 如果类型为 'tag',返回过滤数据中的 'tagType' 字段值,如果不存在则返回空字符串
- if (type == 'tag') return filterData?.tagType? filterData.tagType : ''
- // 返回过滤数据中的 'label' 字段值,如果过滤数据不存在则返回 '--'
- return filterData? filterData[label] : '--'
+ if (type == 'tag') return filterData?.tagType ? filterData.tagType : ''
+ return filterData ? filterData[label] : '--'
}
diff --git a/client/src/views/base/activity/index.vue b/client/src/views/base/activity/index.vue
index d7f7279..37386f2 100644
--- a/client/src/views/base/activity/index.vue
+++ b/client/src/views/base/activity/index.vue
@@ -1,18 +1,9 @@
-
-
activity
-
+
-
+
diff --git a/client/src/views/base/index.vue b/client/src/views/base/index.vue
index ad13d94..cf9ed48 100644
--- a/client/src/views/base/index.vue
+++ b/client/src/views/base/index.vue
@@ -1,22 +1,7 @@
-
-
+
-
+
diff --git a/client/src/views/base/live/flat/dialog/bed.vue b/client/src/views/base/live/flat/dialog/bed.vue
index d3f10e0..f1736ed 100644
--- a/client/src/views/base/live/flat/dialog/bed.vue
+++ b/client/src/views/base/live/flat/dialog/bed.vue
@@ -1,88 +1,66 @@
-
- v-model="dialogVisible"
-
- :title="drawerProps.title"
-
- destroy-on-close
+ style="width: 70%"
+ v-model="dialogVisible"
+ :title="drawerProps.title"
+ destroy-on-close
>
-
-
-
- :model="formData"
- class="login-form"
-
- ref="ruleFormRef"
-
- :rules="rules"
- label-width="120px"
- >
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
diff --git a/client/src/views/base/live/index.vue b/client/src/views/base/live/index.vue
index 52d2b92..cf9ed48 100644
--- a/client/src/views/base/live/index.vue
+++ b/client/src/views/base/live/index.vue
@@ -1,17 +1,7 @@
-
-
+
-
+
diff --git a/client/src/views/base/live/room/index.vue b/client/src/views/base/live/room/index.vue
index b89fae0..3386654 100644
--- a/client/src/views/base/live/room/index.vue
+++ b/client/src/views/base/live/room/index.vue
@@ -1,137 +1,118 @@
-
-
- title="用户列表"
- :columns="columns"
- :requestApi="getTableList"
- :initParam="initParam"
- :dataCallback="dataCallback"
+ ref="proTable"
+ title="用户列表"
+ :columns="columns"
+ :requestApi="getTableList"
+ :initParam="initParam"
+ :dataCallback="dataCallback"
>
-
-
-
-
-
-
- 新增
-
-
+
+
+
+
+ 新增
+
-
-
-
-
- 查看
-
-
-
- 编辑
-
-
-
- @confirm="deleteData(scope)"
- confirm-button-type="danger"
- >
-
-
- 删除
+
+
+
+ 查看
+
+
+ 编辑
+
+
+
+ 删除
+
+
-
-
-
diff --git a/client/src/views/base/live/room/roomDialog/index.vue b/client/src/views/base/live/room/roomDialog/index.vue
index b5d73b0..e4772ff 100644
--- a/client/src/views/base/live/room/roomDialog/index.vue
+++ b/client/src/views/base/live/room/roomDialog/index.vue
@@ -1,136 +1,107 @@
-
-
- v-model="dialogVisible"
- :title="drawerProps.title"
- destroy-on-close
+ style="width: 70%"
+ v-model="dialogVisible"
+ :title="drawerProps.title"
+ destroy-on-close
>
-
-
-
-
- class="login-form"
- ref="ruleFormRef"
- :rules="rules"
- label-width="120px"
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/client/src/views/base/sale/origin/index.vue b/client/src/views/base/sale/origin/index.vue
index 31d830f..fae4f59 100644
--- a/client/src/views/base/sale/origin/index.vue
+++ b/client/src/views/base/sale/origin/index.vue
@@ -1,9 +1,5 @@
-
-
-
+
-
-
- 新增
-
+ 新增
-
+
-
查看
-
编辑
-
-
删除
-
-
+
diff --git a/client/src/views/base/sale/origin/originDialog/index.vue b/client/src/views/base/sale/origin/originDialog/index.vue
index d97022a..97998e8 100644
--- a/client/src/views/base/sale/origin/originDialog/index.vue
+++ b/client/src/views/base/sale/origin/originDialog/index.vue
@@ -1,172 +1,138 @@
-
- :title="drawerProps.title"
- destroy-on-close
+ v-model="dialogVisible"
+ :title="drawerProps.title"
+ destroy-on-close
>
-
-
-
- class="login-form"
- ref="ruleFormRef"
- :rules="rules"
- label-width="120px"
- >
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
+
diff --git a/client/src/views/charge/audit/auditDialog/index.vue b/client/src/views/charge/audit/auditDialog/index.vue
index 8c97ac7..f382ae5 100644
--- a/client/src/views/charge/audit/auditDialog/index.vue
+++ b/client/src/views/charge/audit/auditDialog/index.vue
@@ -1,194 +1,152 @@
-
- :title="drawerProps.title"
- destroy-on-close
+ v-model="dialogVisible"
+ :title="drawerProps.title"
+ destroy-on-close
>
-
-
-
- class="login-form"
- ref="ruleFormRef"
- :rules="rules"
- label-width="120px"
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
diff --git a/client/src/views/charge/index.vue b/client/src/views/charge/index.vue
index b6740fe..cf9ed48 100644
--- a/client/src/views/charge/index.vue
+++ b/client/src/views/charge/index.vue
@@ -1,27 +1,7 @@
-
-
+
-
+
diff --git a/client/src/views/charge/prestore/index.vue b/client/src/views/charge/prestore/index.vue
index 808d3fd..07f5d10 100644
--- a/client/src/views/charge/prestore/index.vue
+++ b/client/src/views/charge/prestore/index.vue
@@ -1,93 +1,83 @@
-
-
- title="用户列表"
- :columns="columns"
- :requestApi="getTableList"
- :initParam="initParam"
- :dataCallback="dataCallback"
+ ref="proTable"
+ title="用户列表"
+ :columns="columns"
+ :requestApi="getTableList"
+ :initParam="initParam"
+ :dataCallback="dataCallback"
>
-
-
-
-
- link
- :icon="CreditCard"
- @click="openDrawer('账户充值',scope)"
- >
- 账户充值
-
-
+
+
+
+
+
+ 账户充值
+
+
-
-
+
diff --git a/client/src/views/charge/prestore/prestoreDialog/index.vue b/client/src/views/charge/prestore/prestoreDialog/index.vue
index 7ba812b..03f28ba 100644
--- a/client/src/views/charge/prestore/prestoreDialog/index.vue
+++ b/client/src/views/charge/prestore/prestoreDialog/index.vue
@@ -1,166 +1,133 @@
-
- v-model="dialogVisible"
- :title="drawerProps.title"
- destroy-on-close
+ style="width: 70%"
+ v-model="dialogVisible"
+ :title="drawerProps.title"
+ destroy-on-close
>
-
-
-
- class="login-form"
- ref="ruleFormRef"
- :rules="rules"
- label-width="120px"
- >
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
+
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/exception/BusinessRuntimeException.java b/server/src/main/java/com/ew/gerocomium/common/config/exception/BusinessRuntimeException.java
index 979cee1..1d25322 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/exception/BusinessRuntimeException.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/exception/BusinessRuntimeException.java
@@ -1,36 +1,22 @@
-// 声明该类所在的包路径,通常用于组织和管理代码结构
package com.ew.gerocomium.common.config.exception;
-// 导入自定义的异常枚举类,该类可能定义了各种异常类型的代码和消息
import com.ew.gerocomium.common.constant.ExceptionEnum;
-// 导入 Lombok 库的 @Getter 注解,用于自动生成类中属性的 getter 方法
import lombok.Getter;
-// 使用 @Getter 注解,让 Lombok 自动为类中的属性生成 getter 方法
@Getter
-// 定义一个自定义的运行时异常类,继承自 RuntimeException,用于处理业务逻辑中的异常情况
public class BusinessRuntimeException extends RuntimeException {
- // 定义一个静态常量 serialVersionUID,用于序列化版本控制,确保在反序列化时版本的一致性
private static final long serialVersionUID = -7382189364622337034L;
- // 定义一个私有成员变量 code,用于存储异常的错误码
private final Integer code;
- // 定义一个私有成员变量 msg,用于存储异常的错误消息
private final String msg;
- // 定义一个构造函数,接收错误码和错误消息作为参数
public BusinessRuntimeException(Integer code, String msg) {
- // 调用父类 RuntimeException 的构造函数,将错误消息传递给父类
super(msg);
- // 将传入的错误码赋值给当前类的 code 成员变量
this.code = code;
- // 将传入的错误消息赋值给当前类的 msg 成员变量
this.msg = msg;
}
- // 定义另一个构造函数,接收一个 ExceptionEnum 类型的参数
public BusinessRuntimeException(ExceptionEnum type) {
- // 调用上面定义的构造函数,将 ExceptionEnum 类型参数的 code 和 msg 传递进去
this(type.getCode(), type.getMsg());
}
-}
\ No newline at end of file
+}
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/exception/BusinessRuntimeExceptionAdvice.java b/server/src/main/java/com/ew/gerocomium/common/config/exception/BusinessRuntimeExceptionAdvice.java
index 9f31319..27995d0 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/exception/BusinessRuntimeExceptionAdvice.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/exception/BusinessRuntimeExceptionAdvice.java
@@ -1,143 +1,80 @@
-// 声明该类所在的包,用于组织和管理代码结构
package com.ew.gerocomium.common.config.exception;
-// 导入自定义的代码枚举类,可能包含各种业务状态码
import com.ew.gerocomium.common.constant.CodeEnum;
-// 导入自定义的异常枚举类,包含不同类型异常的信息
import com.ew.gerocomium.common.constant.ExceptionEnum;
-// 导入自定义的响应工具类,用于构建响应结果
import com.ew.gerocomium.common.util.ResponseUtil;
-// 导入自定义的基础结果类,用于封装接口返回数据
import com.ew.gerocomium.dao.base.Result;
-// 导入 Lombok 提供的日志注解,可自动为类添加日志记录功能
import lombok.extern.slf4j.Slf4j;
-// 导入 Spring Security 框架中权限访问被拒绝的异常类
import org.springframework.security.access.AccessDeniedException;
-// 导入 Spring Security 框架中凭证错误的异常类
import org.springframework.security.authentication.BadCredentialsException;
-// 导入 Spring Security 框架中内部认证服务异常类
import org.springframework.security.authentication.InternalAuthenticationServiceException;
-// 导入 Spring Web 模块中 HTTP 请求方法不支持的异常类
import org.springframework.web.HttpRequestMethodNotSupportedException;
-// 导入 Spring Web 模块中缺少请求参数的异常类
import org.springframework.web.bind.MissingServletRequestParameterException;
-// 导入 Spring 框架的异常处理注解,用于捕获和处理控制器层抛出的异常
import org.springframework.web.bind.annotation.ExceptionHandler;
-// 导入 Spring 框架的全局异常处理注解,结合 @ExceptionHandler 捕获全局异常
import org.springframework.web.bind.annotation.RestControllerAdvice;
-// 导入 Spring Web 模块中方法参数类型不匹配的异常类
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
-// 导入 Spring MVC 模块中未找到处理器的异常类
import org.springframework.web.servlet.NoHandlerFoundException;
-// 导入 JavaMail 中的消息传递异常类
+
import javax.mail.MessagingException;
-// 导入 JavaMail 中邮件发送失败的异常类
import javax.mail.SendFailedException;
-// 导入 Servlet 规范中的 HttpServletRequest 类,用于获取 HTTP 请求信息
import javax.servlet.http.HttpServletRequest;
-// 导入 Servlet 规范中的 HttpServletResponse 类,用于发送 HTTP 响应信息
import javax.servlet.http.HttpServletResponse;
-// 导入 Java 中的 Objects 工具类,提供一些对象操作方法
import java.util.Objects;
-// 使用 Lombok 的 Slf4j 注解,自动为该类添加日志记录功能
-
-// 标记为日志记录类,使用Slf4j日志框架
@Slf4j
-// 表示这是一个全局的异常处理类,用于处理控制器层抛出的异常
@RestControllerAdvice
public class BusinessRuntimeExceptionAdvice {
- /**
- * 异常处理方法,处理所有类型的异常
- *
- * @param ex 捕获到的异常对象
- * @param response HTTP响应对象,用于返回结果
- * @param request HTTP请求对象
- */
@ExceptionHandler({Exception.class})
public void exceptionHandler(Exception ex, HttpServletResponse response, HttpServletRequest request) {
- // 异常类型描述
String errorType;
- // 异常对应的错误码
Integer errorCode;
- // 异常对应的错误消息
String errorMsg;
- // 判断是否为自定义的业务异常
if (ex instanceof BusinessRuntimeException) {
errorType = "业务异常";
- // 获取自定义业务异常的错误码
+ // AssertUtils断言抛出的自定义业务异常
errorCode = ((BusinessRuntimeException) ex).getCode();
- // 获取自定义业务异常的错误消息
errorMsg = ((BusinessRuntimeException) ex).getMsg();
- }
- // 判断是否为请求的资源不存在的异常
- else if (ex instanceof NoHandlerFoundException) {
+ } else if (ex instanceof NoHandlerFoundException) {
errorType = "无访问资源";
- // 获取资源不存在对应的错误码
errorCode = ExceptionEnum.NOT_EXIST.getCode();
- // 获取资源不存在对应的错误消息
errorMsg = ExceptionEnum.NOT_EXIST.getMsg();
- }
- // 判断是否为请求方式不支持的异常
- else if (ex instanceof HttpRequestMethodNotSupportedException) {
+ } else if (ex instanceof HttpRequestMethodNotSupportedException) {
errorType = "请求方式错误";
- // 获取请求方式错误对应的错误码
errorCode = ExceptionEnum.METHOD_ERROR.getCode();
- // 获取请求方式错误对应的错误消息
errorMsg = ExceptionEnum.METHOD_ERROR.getMsg();
- }
- // 判断是否为请求参数缺失或参数类型不匹配的异常
- else if (ex instanceof MissingServletRequestParameterException || ex instanceof MethodArgumentTypeMismatchException) {
+ // MissingServletRequestParameterException -> 未传必传参数
+ // MethodArgumentTypeMismatchException -> 参数类型错误
+ } else if (ex instanceof MissingServletRequestParameterException || ex instanceof MethodArgumentTypeMismatchException) {
errorType = "请求参数异常";
- // 获取请求参数异常对应的错误码
errorCode = ExceptionEnum.PARAM_ERROR.getCode();
- // 获取请求参数异常对应的错误消息
errorMsg = ExceptionEnum.PARAM_ERROR.getMsg();
- }
- // 判断是否为认证失败的异常(账号未注册或密码错误)
- else if (ex instanceof InternalAuthenticationServiceException || ex instanceof BadCredentialsException) {
+ // InternalAuthenticationServiceException -> 账号未注册
+ // BadCredentialsException -> 密码错误
+ } else if (ex instanceof InternalAuthenticationServiceException || ex instanceof BadCredentialsException) {
errorType = "认证失败";
- // 获取认证失败对应的错误码
errorCode = ExceptionEnum.CERTIFICATION_ERROR.getCode();
- // 获取认证失败对应的错误消息
errorMsg = ExceptionEnum.CERTIFICATION_ERROR.getMsg();
- }
- // 判断是否为权限不足的异常
- else if (ex instanceof AccessDeniedException) {
+ } else if (ex instanceof AccessDeniedException) {
errorType = "权限不足";
- // 获取权限不足对应的错误码
errorCode = ExceptionEnum.AUTH_ERROR.getCode();
- // 获取权限不足对应的错误消息
errorMsg = ExceptionEnum.AUTH_ERROR.getMsg();
- }
- // 其他类型的异常
- else {
+ } else {
errorType = "其他异常";
- // 获取通用错误码
errorCode = CodeEnum.ERROR.getCode();
- // 获取异常的消息
String message = ex.getMessage();
- // 标记是否匹配到自定义的异常消息
boolean checkMsg = false;
- // 遍历所有自定义异常枚举
for (ExceptionEnum exceptionEnum : ExceptionEnum.values()) {
- // 判断异常消息是否与自定义异常枚举中的消息匹配
if (Objects.equals(exceptionEnum.getMsg(), message)) {
checkMsg = true;
break;
}
}
- // 如果匹配到自定义异常消息,则使用该消息,否则使用系统错误消息
errorMsg = checkMsg ? message : ExceptionEnum.SYS_ERROR.getMsg();
}
- // 判断日志级别是否为INFO
if (log.isInfoEnabled()) {
- // 记录异常类型
log.info(errorType);
- // 打印异常堆栈信息
ex.printStackTrace();
}
- // 使用工具类将错误结果输出到响应中
ResponseUtil.resultOut(response, Result.error(errorCode, errorMsg));
}
-}
\ No newline at end of file
+}
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/file/FileTempPath.java b/server/src/main/java/com/ew/gerocomium/common/config/file/FileTempPath.java
index e54630e..3ed73b8 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/file/FileTempPath.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/file/FileTempPath.java
@@ -1,35 +1,19 @@
-// 声明该类所在的包,通常用于组织和管理代码结构
package com.ew.gerocomium.common.config.file;
-// 导入 Hutool 工具包中的日期格式常量类
import cn.hutool.core.date.DatePattern;
-// 导入 Hutool 工具包中的日期工具类
import cn.hutool.core.date.DateUtil;
-// 导入 Hutool 工具包中的文件操作工具类
import cn.hutool.core.io.FileUtil;
-// 导入 Hutool 工具包中的字符常量类
import cn.hutool.core.text.CharPool;
-// 导入 Hutool 工具包中的字符串常量类
import cn.hutool.core.text.StrPool;
-// 导入 Hutool 工具包中的 ID 生成工具类
import cn.hutool.core.util.IdUtil;
-// 导入 Hutool 工具包中的字符串操作工具类
import cn.hutool.core.util.StrUtil;
-// 导入 Hutool 工具包中的操作系统信息类
import cn.hutool.system.OsInfo;
-// 导入自定义的常量类
import com.ew.gerocomium.common.constant.Constant;
-// 导入自定义的异常枚举类
import com.ew.gerocomium.common.constant.ExceptionEnum;
-// 导入自定义的断言工具类
import com.ew.gerocomium.common.util.AssertUtil;
-// 导入 Lombok 提供的全参构造函数注解
import lombok.AllArgsConstructor;
-// 导入 Lombok 提供的自动处理异常注解
import lombok.SneakyThrows;
-// 导入 Spring 框架的配置类注解
import org.springframework.context.annotation.Configuration;
-// 导入 Spring 框架处理文件上传的类
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
@@ -38,22 +22,18 @@ import java.time.LocalDateTime;
/**
* 文件信息
*/
-// 表明这是一个 Spring 配置类
@Configuration
-// 让 Lombok 自动生成全参构造函数
@AllArgsConstructor
public class FileTempPath {
- // 注入文件上传配置属性类的实例
private final FileUploadConfigPropertity fileUploadConfigPropertity;
/**
- * 获取 module 存储路径
+ * 获取module存储路径
*
* @param module 模块名称
* @return 根路径/module/当天日期/
*/
public String uploadPath(String module) {
- // 拼接上传路径,格式为根路径 + 模块名 + 当天日期
return getRootPath() + File.separator
+ module + File.separator
+ DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN)
@@ -66,7 +46,6 @@ public class FileTempPath {
* @return 根路径/download/
*/
public String downloadPath() {
- // 拼接下载路径,格式为根路径 + /download/
return getRootPath() + File.separator + Constant.STR_DOWNLOAD + File.separator;
}
@@ -76,7 +55,6 @@ public class FileTempPath {
* @return 根路径/upload/img/
*/
public String imgSrcPath() {
- // 拼接图片存储路径,格式为根路径 + /upload/img/
return getRootPath() + File.separator + Constant.STR_UPLOAD_IMG + File.separator;
}
@@ -86,7 +64,6 @@ public class FileTempPath {
* @return 根路径/upload/video/
*/
public String videoSrcPath() {
- // 拼接视频存储路径,格式为根路径 + /upload/video/
return getRootPath() + File.separator + Constant.STR_UPLOAD_VIDEO + File.separator;
}
@@ -96,7 +73,6 @@ public class FileTempPath {
* @return 根路径/upload/file/
*/
public String filePath() {
- // 拼接附件存储路径,格式为根路径 + /upload/file/
return getRootPath() + File.separator + Constant.STR_UPLOAD_FILE + File.separator;
}
@@ -106,21 +82,12 @@ public class FileTempPath {
* @return 根路径
*/
public String getRootPath() {
- // 创建操作系统信息对象
OsInfo osInfo = new OsInfo();
- // 判断操作系统是否为 Windows
if (osInfo.isWindows()) {
- // 如果是 Windows 系统,返回 Windows 对应的根路径
return fileUploadConfigPropertity.getWindows();
- }
- // 判断操作系统是否为 Mac OS X
- else if (osInfo.isMacOsX()) {
- // 如果是 Mac OS X 系统,返回 Mac OS X 对应的根路径
+ } else if (osInfo.isMacOsX()) {
return fileUploadConfigPropertity.getMacos();
- }
- // 其他操作系统,默认为 Linux
- else {
- // 返回 Linux 对应的根路径
+ } else {
return fileUploadConfigPropertity.getLinux();
}
}
@@ -128,70 +95,63 @@ public class FileTempPath {
/**
* 文件上传 保存
*
- * @param file 上传的文件
- * @param module 模块名称
- * @param suff 允许的文件后缀数组
- * @return 保存后的文件对象
+ * @param file
+ * @param module
+ * @param suff
+ * @return
*/
@SneakyThrows
public File saveFile(MultipartFile file, String module, String[] suff) {
- // 检查文件是否为空或文件名是否为空
if (file == null || StrUtil.isBlank(file.getOriginalFilename())) {
return null;
}
- // 获取文件后缀,格式为 .xxx
String suffix = StrPool.DOT + FileUtil.getSuffix(file.getOriginalFilename());
- // 校验文件后缀是否不在允许的后缀数组中,如果不在则抛出异常
+ // 文件后缀校验
AssertUtil.isTrue(!StrUtil.equalsAnyIgnoreCase(suffix, suff), ExceptionEnum.UPLOAD_SUFFIX_ERROR);
- // 生成新的文件名,格式为雪花算法 ID + _ + 原文件名
+ // 文件转存
+ // 模块路径/雪花算法ID_上传文件名称
String fileName = IdUtil.getSnowflakeNextIdStr() + "_" + file.getOriginalFilename();
- // 创建文件对象,路径为模块上传路径 + 新文件名
File files = FileUtil.file(uploadPath(module) + fileName);
- // 创建文件的父目录
FileUtil.mkParentDirs(files);
- // 将上传的文件转存到指定位置
+
file.transferTo(files);
return files;
}
+
/**
* 文件上传 备查信息
*
* @param file http MultipartFile 文件流
* @param suff 后缀 包含此类型的后缀不允许上传 如:.exe .sh
- * @return 保存后的文件对象
+ * @return
*/
@SneakyThrows
public File saveInformationFile(MultipartFile file, String[] suff) {
- // 调用 saveFile 方法,指定模块名为 "information"
return saveFile(file, "information", suff);
}
@SneakyThrows
public File saveCommFile(MultipartFile file, String module) {
- // 调用 saveFile 方法,不限制文件后缀
return saveFile(file, module, null);
}
/**
- * 下载路径处理 前提是放开 uri
+ * 下载路径处理 前提是放开uri
*
- * @param file 要下载的文件
- * @return 处理后的下载 URL
+ * @param file
+ * @return
*/
public String downloadUrl(File file) {
- // 获取文件的绝对路径
String filePath = file.getAbsolutePath();
- // 替换根路径为空字符串,并将反斜杠替换为正斜杠
String downloadUrl = filePath
.replace(getRootPath(), "")
.replace(StrPool.BACKSLASH, StrPool.SLASH);
- // 在路径前添加斜杠
return CharPool.SLASH + downloadUrl;
}
public String downloadUrl(String path) {
- // 调用 downloadUrl 方法,将文件路径转换为文件对象
return downloadUrl(FileUtil.file(path));
}
+
}
\ No newline at end of file
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/file/FileUploadConfigPropertity.java b/server/src/main/java/com/ew/gerocomium/common/config/file/FileUploadConfigPropertity.java
index 9eb680d..61c9568 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/file/FileUploadConfigPropertity.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/file/FileUploadConfigPropertity.java
@@ -1,32 +1,19 @@
-// 声明该类所在的包,用于组织和管理代码结构
package com.ew.gerocomium.common.config.file;
-// 导入 Lombok 库的 @Data 注解,该注解会自动生成 getter、setter、toString、equals 和 hashCode 等方法
import lombok.Data;
-// 导入 Spring Boot 提供的 @ConfigurationProperties 注解,用于将配置文件中的属性映射到 Java 类中
import org.springframework.boot.context.properties.ConfigurationProperties;
-// 导入 Spring 框架的 @Configuration 注解,表明这是一个配置类,会被 Spring 容器管理
import org.springframework.context.annotation.Configuration;
/**
* 文件上传路径配置
*/
-// 使用 Lombok 的 @Data 注解,自动生成类的 getter、setter、toString 等方法
@Data
-// 使用 Spring 的 @Configuration 注解,将该类标记为配置类
@Configuration
-// 使用 @ConfigurationProperties 注解,指定从配置文件中读取以 "filesave" 为前缀的属性
@ConfigurationProperties(prefix = "filesave")
-// 定义一个配置属性类,用于存储文件上传路径的相关配置
public class FileUploadConfigPropertity {
- // 定义一个字符串类型的属性,用于存储 Windows 系统下的文件上传路径
private String windows;
- // 定义一个字符串类型的属性,用于存储 Mac OS 系统下的文件上传路径
private String macos;
- // 定义一个字符串类型的属性,用于存储 Linux 系统下的文件上传路径
private String linux;
- // 定义一个字符串类型的属性,用于存储上传文件的头部路径配置
private String uploadHead;
- // 定义一个字符串类型的属性,用于存储本地文件的头部路径配置
private String localHead;
-}
\ No newline at end of file
+}
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/mybatisplus/MetaObjectHandlerImpl.java b/server/src/main/java/com/ew/gerocomium/common/config/mybatisplus/MetaObjectHandlerImpl.java
index 95e2bbf..f211a64 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/mybatisplus/MetaObjectHandlerImpl.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/mybatisplus/MetaObjectHandlerImpl.java
@@ -1,119 +1,86 @@
-// 声明该类所在的包,用于组织和管理代码结构
package com.ew.gerocomium.common.config.mybatisplus;
-// 导入 MyBatis-Plus 核心的元对象处理器接口
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
-// 导入自定义的权限验证处理类
import com.ew.gerocomium.common.config.security.handler.AuthorityAssert;
-// 导入自定义的登录用户信息视图对象类
import com.ew.gerocomium.dao.vo.LoginUserVo;
-// 导入 Lombok 提供的日志注解,可自动为类添加日志记录功能
import lombok.extern.slf4j.Slf4j;
-// 导入 MyBatis 的元对象类,用于操作对象属性
import org.apache.ibatis.reflection.MetaObject;
-// 导入 Spring 框架的组件注解,将该类标记为 Spring 组件,以便 Spring 自动扫描和管理
import org.springframework.stereotype.Component;
-// 导入 Java 的资源注入注解
import javax.annotation.Resource;
-// 导入 Java 的日期类,用于表示时间
-import java.util.Date;
-// 导入 Java 的数组工具类,用于处理数组操作
import java.util.Arrays;
-// 导入 Java 的列表接口,用于存储元素
+import java.util.Date;
import java.util.List;
-// 导入 Java 的流处理工具类,用于集合元素的转换和处理
import java.util.stream.Collectors;
/**
* mybatis对象处理器
**/
-// 使用 Lombok 的 Slf4j 注解,自动为该类添加日志记录功能
@Slf4j
-// 使用 Spring 的 Component 注解,将该类标记为组件,让 Spring 框架管理
@Component
-// 定义一个元对象处理器实现类,实现 MyBatis-Plus 的 MetaObjectHandler 接口
public class MetaObjectHandlerImpl implements MetaObjectHandler {
-
- // 使用 Spring 的 Resource 注解注入 AuthorityAssert 类的实例
@Resource
private AuthorityAssert authorityAssert;
- // 定义常量,表示创建记录的用户 ID 字段名
private static final String CREATEID = "createId";
- // 定义常量,表示创建记录的时间字段名
private static final String CREATETIME = "createTime";
- // 定义常量,表示更新记录的用户 ID 字段名
private static final String UPDATEID = "updateId";
- // 定义常量,表示更新记录的时间字段名
private static final String UPDATETIME = "updateTime";
/**
* 自动填充创建时间修改时间
*
- * @param metaObject 元对象,包含要操作的对象信息
+ * @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
- // 调用 authorityAssert 的方法获取当前登录用户的信息
+ // 获取登录信息
LoginUserVo loginUserInfo = authorityAssert.getLoginUserInfo();
- // 获取元对象中所有可获取的字段名称,并存储在列表中
+ //获取所有的字段名称
List list = Arrays.stream(metaObject.getGetterNames()).collect(Collectors.toList());
- // 判断列表中是否包含创建用户 ID 字段
if (list.contains(CREATEID)) {
- // 如果登录用户信息不为空
+ // 有登录信息
if (loginUserInfo != null) {
- // 设置创建用户 ID 字段的值为当前登录用户的 ID
this.setFieldValByName(CREATEID, loginUserInfo.getId(), metaObject);
+ // 无登录信息
} else {
- // 若登录用户信息为空,设置创建用户 ID 字段的值为默认值 1L
this.setFieldValByName(CREATEID, 1L, metaObject);
}
}
- // 判断列表中是否包含创建时间字段
if (list.contains(CREATETIME)) {
- // 设置创建时间字段的值为当前时间
this.setFieldValByName(CREATETIME, new Date(), metaObject);
}
- // 判断列表中是否包含更新用户 ID 字段
if (list.contains(UPDATEID)) {
- // 如果登录用户信息不为空
+ // 有登录信息
if (loginUserInfo != null) {
- // 设置更新用户 ID 字段的值为当前登录用户的 ID
this.setFieldValByName(UPDATEID, loginUserInfo.getId(), metaObject);
+ // 无登录信息
} else {
- // 若登录用户信息为空,设置更新用户 ID 字段的值为默认值 1L
this.setFieldValByName(UPDATEID, 1L, metaObject);
}
}
- // 判断列表中是否包含更新时间字段
if (list.contains(UPDATETIME)) {
- // 设置更新时间字段的值为当前时间
this.setFieldValByName(UPDATETIME, new Date(), metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
- // 调用 authorityAssert 的方法获取当前登录用户的信息
+ // 获取登录信息
LoginUserVo loginUserInfo = authorityAssert.getLoginUserInfo();
- // 获取元对象中所有可获取的字段名称,并存储在列表中
+ //获取所有的字段名称
List list = Arrays.stream(metaObject.getGetterNames()).collect(Collectors.toList());
- // 判断列表中是否包含更新用户 ID 字段
if (list.contains(UPDATEID)) {
- // 如果登录用户信息不为空
+ // 有登录信息
if (loginUserInfo != null) {
- // 设置更新用户 ID 字段的值为当前登录用户的 ID
this.setFieldValByName(UPDATEID, loginUserInfo.getId(), metaObject);
+ // 无登录信息
} else {
- // 若登录用户信息为空,设置更新用户 ID 字段的值为默认值 1L
this.setFieldValByName(UPDATEID, 1L, metaObject);
}
}
- // 判断列表中是否包含更新时间字段
if (list.contains(UPDATETIME)) {
- // 设置更新时间字段的值为当前时间
this.setFieldValByName(UPDATETIME, new Date(), metaObject);
}
}
-}
\ No newline at end of file
+}
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/quartz/QuartzConfig.java b/server/src/main/java/com/ew/gerocomium/common/config/quartz/QuartzConfig.java
index b2191f9..eb9dc75 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/quartz/QuartzConfig.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/quartz/QuartzConfig.java
@@ -1,57 +1,33 @@
-// 声明该类所在的包,用于组织和管理代码结构
package com.ew.gerocomium.common.config.quartz;
-// 导入 Quartz 框架的 JobDetail 接口,用于定义作业的详细信息
-import org.quartz.JobDetail;
-// 导入 Quartz 框架的 Trigger 接口,用于定义作业的触发条件
-import org.quartz.Trigger;
-// 导入 Quartz 框架的 JobBuilder 类,用于构建 JobDetail 对象
-import org.quartz.JobBuilder;
-// 导入 Quartz 框架的 TriggerBuilder 类,用于构建 Trigger 对象
-import org.quartz.TriggerBuilder;
-// 导入 Quartz 框架的 CronScheduleBuilder 类,用于构建基于 Cron 表达式的调度器
-import org.quartz.CronScheduleBuilder;
-// 导入 Quartz 框架的 JobDataMap 类,用于存储作业的数据
-import org.quartz.JobDataMap;
-// 导入 Spring 框架的配置类注解,表明这是一个配置类
+import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-// 导入 Spring 框架中 Quartz 作业的基类
import org.springframework.scheduling.quartz.QuartzJobBean;
-// 使用 Spring 的 Configuration 注解,将该类标记为配置类
@Configuration
- public class QuartzConfig {
-
- // 定义一个名为 reserveExpireJobDetail 的 Bean,用于配置预定过期的作业详情
- @Bean
- public JobDetail reserveExpireJobDetail() {
- // 调用自定义的 newJobDetail 方法创建并返回一个 JobDetail 对象
- return newJobDetail(QuartzJob.ReserveExpireJob.class, "reserveExpireJobDetail");
- }
-
- // 定义一个名为 reserveExpireTrigger 的 Bean,用于配置预定过期作业的触发器
- @Bean
- public Trigger reserveExpireTrigger() {
- // 调用自定义的 newTrigger 方法创建并返回一个 Trigger 对象,关联到 reserveExpireJobDetail 作业详情
- return newTrigger(reserveExpireJobDetail(), "reserveExpireJobTrigger", "0 0 0 ? * *");
- }
+public class QuartzConfig {
+ // 预定过期
+ @Bean
+ public JobDetail reserveExpireJobDetail() {
+ return newJobDetail(QuartzJob.ReserveExpireJob.class, "reserveExpireJobDetail");
+ }
- // 定义一个名为 contractExpireJobDetail 的 Bean,用于配置合同到期的作业详情
- @Bean
- public JobDetail contractExpireJobDetail() {
- // 调用自定义的 newJobDetail 方法创建并返回一个 JobDetail 对象
- return newJobDetail(QuartzJob.ContractExpireJob.class, "contractExpireJobDetail");
- }
+ @Bean
+ public Trigger reserveExpireTrigger() {
+ return newTrigger(reserveExpireJobDetail(), "reserveExpireJobTrigger", "0 0 0 ? * *");
+ }
- // 定义一个名为 contractExpireTrigger 的 Bean,用于配置合同到期作业的触发器
- @Bean
- public Trigger contractExpireTrigger() {
- // 调用自定义的 newTrigger 方法创建并返回一个 Trigger 对象,关联到 contractExpireJobDetail 作业详情
- return newTrigger(contractExpireJobDetail(), "contractExpireJobTrigger", "0 0 8 ? * *");
- }
+ // 合同到期
+ @Bean
+ public JobDetail contractExpireJobDetail() {
+ return newJobDetail(QuartzJob.ContractExpireJob.class, "contractExpireJobDetail");
+ }
- // 通用的作业详情构建方法,参数为作业类和作业详情名称
+ @Bean
+ public Trigger contractExpireTrigger() {
+ return newTrigger(contractExpireJobDetail(), "contractExpireJobTrigger", "0 0 8 ? * *");
+ }
// 任务封装
private JobDetail newJobDetail(Class extends QuartzJobBean> jobDetailClass, String jobDetailName) {
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/quartz/QuartzJob.java b/server/src/main/java/com/ew/gerocomium/common/config/quartz/QuartzJob.java
index aa1308c..8435b7c 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/quartz/QuartzJob.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/quartz/QuartzJob.java
@@ -1,54 +1,37 @@
-// 声明该类所在的包,用于组织和管理代码结构
package com.ew.gerocomium.common.config.quartz;
-// 导入自定义的合同服务接口
import com.ew.gerocomium.service.ContractService;
-// 导入自定义的预定服务接口
import com.ew.gerocomium.service.ReserveService;
-// 导入 Lombok 提供的注解,用于简化异常处理,自动抛出异常
import lombok.SneakyThrows;
-// 导入 Quartz 框架中作业的基类,Spring 整合 Quartz 时使用的作业类需要继承该类
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
-// 导入 Spring 框架的服务注解,将该类标记为服务层组件
import org.springframework.stereotype.Service;
-// 导入 Spring 的资源注入注解
import javax.annotation.Resource;
-// 使用 Spring 的 Service 注解,将该类标记为服务层组件,让 Spring 框架管理
@Service
public class QuartzJob {
-
- // 使用 Spring 的 Resource 注解注入 ReserveService 接口的实现类实例
@Resource
private ReserveService reserveService;
- // 使用 Spring 的 Resource 注解注入 ContractService 接口的实现类实例
@Resource
private ContractService contractService;
- // 定义一个内部类,表示床位预定过期任务,继承自 QuartzJobBean
+ // 床位预定过期任务
public class ReserveExpireJob extends QuartzJobBean {
- // 使用 Lombok 的 @SneakyThrows 注解,自动处理方法内可能抛出的异常
@SneakyThrows
@Override
- // 重写 QuartzJobBean 的 executeInternal 方法,该方法在作业执行时被调用
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
- // 调用 ReserveService 中的 reserveExpireJob 方法,执行床位预定过期的业务逻辑
reserveService.reserveExpireJob();
}
}
- // 定义一个内部类,表示老人合同到期任务,继承自 QuartzJobBean
+ // 老人合同到期任务
public class ContractExpireJob extends QuartzJobBean {
- // 使用 Lombok 的 @SneakyThrows 注解,自动处理方法内可能抛出的异常
@SneakyThrows
@Override
- // 重写 QuartzJobBean 的 executeInternal 方法,该方法在作业执行时被调用
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
- // 调用 ContractService 中的 contractExpireJob 方法,执行老人合同到期的业务逻辑
contractService.contractExpireJob();
}
}
-}
\ No newline at end of file
+}
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/redis/FastJsonRedisSerializer.java b/server/src/main/java/com/ew/gerocomium/common/config/redis/FastJsonRedisSerializer.java
index 0f2718a..5b83078 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/redis/FastJsonRedisSerializer.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/redis/FastJsonRedisSerializer.java
@@ -1,93 +1,53 @@
-// 声明该类所在的包,用于组织和管理代码结构
package com.ew.gerocomium.common.config.redis;
-// 导入阿里巴巴的 FastJSON 库,用于 JSON 处理
import com.alibaba.fastjson.JSON;
-// 导入 FastJSON 库中用于设置序列化特性的类
import com.alibaba.fastjson.serializer.SerializerFeature;
-// 导入 Jackson 库中用于处理 Java 类型的类,在反序列化等操作中会用到
import com.fasterxml.jackson.databind.JavaType;
-// 导入 Jackson 库中用于创建类型工厂的类,通过该工厂创建 JavaType 等类型对象
import com.fasterxml.jackson.databind.type.TypeFactory;
-// 导入 Spring Data Redis 中用于定义 Redis 序列化器的接口
import org.springframework.data.redis.serializer.RedisSerializer;
-// 导入 Spring Data Redis 中序列化异常类,用于处理序列化过程中可能出现的异常情况
import org.springframework.data.redis.serializer.SerializationException;
-// 导入 FastJSON 库中用于解析配置的类
import com.alibaba.fastjson.parser.ParserConfig;
-// 导入 Java 标准库中用于处理字符集的类
import java.nio.charset.Charset;
/**
* Redis使用FastJson序列化
- * 该类实现了RedisSerializer接口,用于将Java对象序列化为字节数组,以及将字节数组反序列化为Java对象
*/
public class FastJsonRedisSerializer implements RedisSerializer {
- // 默认字符集,使用UTF-8编码
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
- // 泛型T对应的具体类的Class对象
private Class clazz;
- // 静态代码块,在类加载时执行
- // 开启FastJson的自动类型支持,这样在序列化和反序列化时可以保留对象的类型信息
static {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
}
- /**
- * 构造函数,用于初始化泛型T对应的具体类的Class对象
- * @param clazz 泛型T对应的具体类的Class对象
- */
public FastJsonRedisSerializer(Class clazz) {
super();
this.clazz = clazz;
}
- /**
- * 序列化方法,将Java对象序列化为字节数组
- * @param t 要序列化的Java对象
- * @return 序列化后的字节数组
- * @throws SerializationException 如果序列化过程中出现异常
- */
@Override
public byte[] serialize(T t) throws SerializationException {
- // 如果要序列化的对象为null,则返回一个空的字节数组
if (t == null) {
return new byte[0];
}
- // 使用FastJson将对象转换为JSON字符串,并写入类名信息
- // 然后将JSON字符串按照默认字符集编码为字节数组
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
- /**
- * 反序列化方法,将字节数组反序列化为Java对象
- * @param bytes 要反序列化的字节数组
- * @return 反序列化后的Java对象
- * @throws SerializationException 如果反序列化过程中出现异常
- */
@Override
public T deserialize(byte[] bytes) throws SerializationException {
- // 如果字节数组为null或者长度为0,则返回null
if (bytes == null || bytes.length <= 0) {
return null;
}
- // 将字节数组按照默认字符集解码为字符串
String str = new String(bytes, DEFAULT_CHARSET);
- // 使用FastJson将JSON字符串反序列化为指定类型的对象
+
return JSON.parseObject(str, clazz);
}
- /**
- * 获取指定类的JavaType对象
- * @param clazz 要获取JavaType的类
- * @return 对应的JavaType对象
- */
+
protected JavaType getJavaType(Class> clazz) {
- // 使用Jackson的TypeFactory构建指定类的JavaType对象
return TypeFactory.defaultInstance().constructType(clazz);
}
}
\ No newline at end of file
diff --git a/server/src/main/java/com/ew/gerocomium/common/config/redis/RedisConfig.java b/server/src/main/java/com/ew/gerocomium/common/config/redis/RedisConfig.java
index 38d8b7a..78ff5c3 100644
--- a/server/src/main/java/com/ew/gerocomium/common/config/redis/RedisConfig.java
+++ b/server/src/main/java/com/ew/gerocomium/common/config/redis/RedisConfig.java
@@ -1,53 +1,30 @@
-// 声明该类所在的包,包名为 com.ew.gerocomium.common.config.redis
package com.ew.gerocomium.common.config.redis;
-// 导入 Spring 框架中用于声明 Bean 的注解
import org.springframework.context.annotation.Bean;
-// 导入 Spring 框架中用于声明配置类的注解
import org.springframework.context.annotation.Configuration;
-// 导入 Spring Data Redis 中用于表示 Redis 连接工厂的类
import org.springframework.data.redis.connection.RedisConnectionFactory;
-// 导入 Spring Data Redis 中用于操作 Redis 的核心类
import org.springframework.data.redis.core.RedisTemplate;
-// 导入 Spring Data Redis 中用于将字符串进行序列化的类
import org.springframework.data.redis.serializer.StringRedisSerializer;
-// 使用 @Configuration 注解将该类标记为 Spring 的配置类,用于定义 Bean
-
-// 此注解表明该类是一个配置类,Spring会对其进行扫描并处理其中的配置信息
@Configuration
public class RedisConfig {
- /**
- * 创建一个RedisTemplate的Bean,用于与Redis进行交互
- * @param connectionFactory Redis连接工厂,用于创建Redis连接
- * @return 配置好的RedisTemplate实例
- */
@Bean
- // 抑制未经检查的类型转换和原始类型使用的警告
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate