
@@ -55,13 +55,15 @@
diff --git a/src/pages/role/index.vue b/src/pages/role/index.vue
index fb51274..9455772 100644
--- a/src/pages/role/index.vue
+++ b/src/pages/role/index.vue
@@ -52,7 +52,23 @@ const table = useTable({
],
},
],
- common: {
+ search: {
+ items: [
+ {
+ extend: "name",
+ required: false,
+ },
+ ],
+ },
+ create: {
+ title: "新建角色",
+ modalProps: {
+ width: 580,
+ maskClosable: false,
+ },
+ formProps: {
+ layout: "vertical",
+ },
items: [
{
field: "name",
@@ -77,26 +93,7 @@ const table = useTable({
options: () => api.permission.getPermissions(),
},
],
- modalProps: {
- width: 580,
- maskClosable: false,
- },
- formProps: {
- layout: "vertical",
- },
- },
- search: {
- items: [
- {
- field: "name",
- label: "角色名称",
- type: "input",
- required: false,
- },
- ],
- },
- create: {
- title: "新建角色",
+
submit: ({ model }) => {
return api.role.addRole(model as any);
},
diff --git a/src/pages/user/index.vue b/src/pages/user/index.vue
index 06227e8..2fb33b7 100644
--- a/src/pages/user/index.vue
+++ b/src/pages/user/index.vue
@@ -10,142 +10,136 @@ import { Table, useTable } from "@/components";
import { dayjs } from "@/plugins";
import { Avatar, Button } from "@arco-design/web-vue";
-const table = useTable(() => {
- const nicknameRender = ({ record }: any) => {
- return (
-
-
-
-
-
- {record.nickname}
- 账号:{record.username}
-
-
- );
- };
- return {
- data: async (model, paging) => {
- return api.user.getUsers({ ...model, ...paging });
+const table = useTable({
+ data: async (model, paging) => {
+ return api.user.getUsers({ ...model, ...paging });
+ },
+ columns: [
+ {
+ type: "index",
},
- columns: [
- {
- type: "index",
+ {
+ title: "用户昵称",
+ dataIndex: "username",
+ width: 200,
+ render: ({ record }) => {
+ return (
+
+
+
+
+
+ {record.nickname}
+ 账号:{record.username}
+
+
+ );
},
- {
- title: "用户昵称",
- dataIndex: "username",
- width: 200,
- render: nicknameRender,
- },
- {
- title: "用户描述",
- dataIndex: "description",
- },
- {
- title: "用户邮箱",
- dataIndex: "email",
- },
- {
- title: "创建时间",
- dataIndex: "createdAt",
- width: 200,
- render: ({ record }) => dayjs(record.createdAt).format(),
- },
- {
- title: "操作",
- type: "button",
- width: 148,
- buttons: [
- {
- type: "modify",
- text: "修改",
+ },
+ {
+ title: "用户描述",
+ dataIndex: "description",
+ },
+ {
+ title: "用户邮箱",
+ dataIndex: "email",
+ },
+ {
+ title: "创建时间",
+ dataIndex: "createdAt",
+ width: 200,
+ render: ({ record }) => dayjs(record.createdAt).format(),
+ },
+ {
+ title: "操作",
+ type: "button",
+ width: 148,
+ buttons: [
+ {
+ type: "modify",
+ text: "修改",
+ },
+ {
+ type: "delete",
+ text: "删除",
+ onClick: async ({ record }) => {
+ return api.user.delUser(record.id);
},
- {
- type: "delete",
- text: "删除",
- onClick: async (data) => {
- return api.user.deleteUser(data.record.id);
- },
- },
- ],
+ },
+ ],
+ },
+ ],
+ search: {
+ items: [
+ {
+ extend: "username",
+ required: false,
},
],
- search: {
- items: [
- {
- extend: "username",
- required: false,
- },
- ],
+ },
+ create: {
+ title: "新建用户",
+ trigger: () => (
+
+ ),
+ modalProps: {
+ width: 772,
+ maskClosable: false,
},
- create: {
- title: "新建用户",
- trigger: () => (
-
- ),
- modalProps: {
- width: 772,
- maskClosable: false,
- },
- formProps: {
- layout: "vertical",
- class: "!grid grid-cols-2 gap-x-3",
- },
- model: {
- avatarUrl: "",
- },
- items: [
- {
- field: "username",
- label: "登录账号",
- type: "input",
- required: true,
- },
- {
- field: "nickname",
- label: "用户昵称",
- type: "input",
- },
- {
- field: "description",
- label: "个人描述",
- type: "input",
- },
- {
- field: "password",
- label: "密码",
- type: "password",
- },
- {
- label: "头像",
- field: "avatar?avatarUrl",
- type: "select",
- },
- {
- field: "startTime:endTime",
- label: "日期范围",
- type: "dateRange",
- nodeProps: {},
- },
- ],
- submit: ({ model }) => {
- console.log(model);
- },
+ formProps: {
+ layout: "vertical",
+ class: "!grid grid-cols-2 gap-x-3",
},
- modify: {
- extend: true,
- title: "修改用户",
- submit: ({ model }) => {
- return api.user.updateUser(model.id, model);
+ items: [
+ {
+ field: "username",
+ label: "登录账号",
+ type: "input",
+ required: true,
},
+ {
+ field: "nickname",
+ label: "用户昵称",
+ type: "input",
+ },
+ {
+ field: "description",
+ label: "个人描述",
+ type: "input",
+ },
+ {
+ field: "password",
+ label: "密码",
+ type: "password",
+ },
+ {
+ label: "头像",
+ field: "avatar",
+ type: "select",
+ },
+ {
+ field: "startTime:endTime",
+ label: "日期范围",
+ type: "dateRange",
+ nodeProps: {},
+ },
+ ],
+ submit: ({ model }) => {
+ console.log(model);
},
- };
+ },
+ modify: {
+ extend: true,
+ title: "修改用户",
+ submit: ({ model }) => {
+ return api.user.updateUser(model.id, model);
+ },
+ },
});
diff --git a/src/router/guards/guard-auth.ts b/src/router/guards/guard-auth.ts
new file mode 100644
index 0000000..452c255
--- /dev/null
+++ b/src/router/guards/guard-auth.ts
@@ -0,0 +1,34 @@
+import { NavigationGuardWithThis } from "vue-router";
+import { store, useUserStore } from "@/store";
+import { Message } from "@arco-design/web-vue";
+
+const userStore = useUserStore(store);
+
+/**
+ * 权限守卫
+ * @description 校验用户是否有路由的访问权限
+ */
+export function useAuthGuard() {
+ const whitelist = ["/404"];
+ const signoutlist = ["/login"];
+ const authGuard: NavigationGuardWithThis
= async function (to, from, next) {
+ if (to.meta.auth === false) {
+ return next();
+ }
+ if (whitelist.includes(to.fullPath)) {
+ return next();
+ }
+ if (signoutlist.includes(to.fullPath)) {
+ if (userStore.id) {
+ Message.warning(`提示:您已登陆,如需重新请退出后再操作!`);
+ return next(false);
+ }
+ return next();
+ }
+ if (!userStore.id) {
+ return next("/login");
+ }
+ next();
+ };
+ return authGuard;
+}
diff --git a/src/router/guards/guard-nprogress.ts b/src/router/guards/guard-nprogress.ts
new file mode 100644
index 0000000..9bff1c5
--- /dev/null
+++ b/src/router/guards/guard-nprogress.ts
@@ -0,0 +1,17 @@
+import { NavigationGuardWithThis } from "vue-router";
+import { NProgress } from "@/plugins";
+
+/**
+ * 进度条守卫
+ * @description 在路由跳转时显示进度条
+ */
+export const useNprogressGuard = () => {
+ const before: NavigationGuardWithThis = function (to, from, next) {
+ NProgress.start();
+ next();
+ };
+ const after: NavigationGuardWithThis = function (to, from, next) {
+ NProgress.done();
+ };
+ return { before, after };
+};
diff --git a/src/router/guards/guard-title.ts b/src/router/guards/guard-title.ts
new file mode 100644
index 0000000..326ad6a
--- /dev/null
+++ b/src/router/guards/guard-title.ts
@@ -0,0 +1,15 @@
+import { NavigationGuardWithThis } from "vue-router";
+
+/**
+ * 标题首位
+ * @description 路由跳转后更新页面标题
+ */
+export const useTitleGuard = () => {
+ const titleGuard: NavigationGuardWithThis = function (to, from, next) {
+ const title = to.meta.title || import.meta.env.VITE_APP_TITLE;
+ const subtitle = import.meta.env.VITE_APP_SUBTITLE;
+ document.title = `${title} | ${subtitle}`;
+ next();
+ };
+ return titleGuard;
+};
diff --git a/src/router/guards/index.ts b/src/router/guards/index.ts
deleted file mode 100644
index 4a8169b..0000000
--- a/src/router/guards/index.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { Router } from 'vue-router';
-import { NProgress } from '@/plugins';
-
-/**
- * 设置进度条
- * @param router 路由实例
- */
-export const useNprogress = (router: Router) => {
- router.beforeEach((to, from, next) => {
- NProgress.start();
- next();
- });
-
- router.afterEach(() => {
- NProgress.done();
- });
-};
-
-/**
- * 设置文档标题
- * @param router 路由实例
- */
-export const useTitle = (router: Router) => {
- router.beforeEach((to, from, next) => {
- const title = to.meta.title || import.meta.env.VITE_APP_TITLE;
- const subtitle = import.meta.env.VITE_APP_SUBTITLE;
- document.title = `${title} | ${subtitle}`;
- next();
- });
-};
-
-/**
- * 设置权限
- * @param router 路由实例
- */
-export const useAuth = (router: Router) => {
- router.beforeEach((to, from, next) => {
- if (to.meta.auth) {
- }
- next();
- });
-};
diff --git a/src/router/router/index.ts b/src/router/router/index.ts
index fcd0de6..9efdb2a 100644
--- a/src/router/router/index.ts
+++ b/src/router/router/index.ts
@@ -1,6 +1,12 @@
import { createRouter, createWebHashHistory } from "vue-router";
-import { useAuth, useNprogress, useTitle } from "../guards";
import { routes } from "../routes";
+import { useAuthGuard } from "../guards/guard-auth";
+import { useNprogressGuard } from "../guards/guard-nprogress";
+import { useTitleGuard } from "../guards/guard-title";
+
+const nprogressGuard = useNprogressGuard();
+const titleGuard = useTitleGuard();
+const authGuard = useAuthGuard();
const router = createRouter({
history: createWebHashHistory(),
@@ -13,8 +19,9 @@ const router = createRouter({
],
});
-useNprogress(router);
-useTitle(router);
-useAuth(router);
+router.beforeEach(nprogressGuard.before);
+router.beforeEach(nprogressGuard.after);
+router.beforeEach(titleGuard);
+router.beforeEach(authGuard);
export { router };
diff --git a/src/store/app/index.ts b/src/store/app/index.ts
index dc63f4a..e7b419a 100644
--- a/src/store/app/index.ts
+++ b/src/store/app/index.ts
@@ -1,38 +1,35 @@
-import { useDark } from "@vueuse/core";
import { defineStore } from "pinia";
export const useAppStore = defineStore({
id: "app",
- state: () => {
- const isDark = useDark({
- onChanged: (isDark) => {
- if (isDark) {
- document.body.setAttribute("arco-theme", "dark");
- document.body.classList.add("dark");
- return;
- }
- document.body.setAttribute("arco-theme", "light");
- document.body.classList.remove("dark");
- },
- });
- return {
- count: 0,
- isDark,
- title: import.meta.env.VITE_APP_TITLE,
- subtitle: import.meta.env.VITE_APP_SUBTITLE,
- };
- },
- getters: {
- doubleCount(state) {
- return state.count * 2;
- },
- },
+ state: () => ({
+ isDarkMode: false,
+ title: import.meta.env.VITE_TITLE,
+ subtitle: import.meta.env.VITE_SUBTITLE,
+ }),
actions: {
- increment() {
- this.count++;
- },
+ /**
+ * 切换暗/亮模式
+ */
toggleDark() {
- this.isDark = !this.isDark;
+ this.isDarkMode ? this.setLight() : this.setDark();
+ },
+ /**
+ * 切换为亮模式
+ */
+ setLight() {
+ document.body.setAttribute("arco-theme", "light");
+ document.body.classList.remove("dark");
+ this.isDarkMode = false;
+ },
+ /**
+ * 切换为暗模式
+ */
+ setDark() {
+ document.body.setAttribute("arco-theme", "dark");
+ document.body.classList.add("dark");
+ this.isDarkMode = true;
},
},
+ persist: true,
});
diff --git a/src/store/store/index.ts b/src/store/store/index.ts
index 9a62b28..35d468c 100644
--- a/src/store/store/index.ts
+++ b/src/store/store/index.ts
@@ -1,3 +1,5 @@
import { createPinia } from "pinia";
+import persistedstatePlugin from "pinia-plugin-persistedstate";
export const store = createPinia();
+store.use(persistedstatePlugin);
diff --git a/src/store/user/index.ts b/src/store/user/index.ts
index 25bfe1f..56891d0 100644
--- a/src/store/user/index.ts
+++ b/src/store/user/index.ts
@@ -1,14 +1,18 @@
-import { useStorage } from "@vueuse/core";
+import { LoginedUserVo } from "@/api";
import { defineStore } from "pinia";
export const useUserStore = defineStore({
id: "user",
state: () => {
- const user = useStorage("APP_USER", {
+ return {
+ /**
+ * 用户ID
+ */
+ id: 0,
/**
* 用户名称
*/
- name: "绝弹",
+ username: "绝弹",
/**
* 用户头像地址
*/
@@ -17,22 +21,35 @@ export const useUserStore = defineStore({
* JWT令牌
*/
accessToken: "",
- });
- return user;
+ /**
+ * 刷新令牌
+ */
+ refreshToken: "",
+ };
},
actions: {
+ /**
+ * 设置令牌
+ */
setToken(token: string) {
this.accessToken = token;
},
+ /**
+ * 清除用户信息
+ */
clearUser() {
- this.name = "";
+ this.username = "";
this.avatar = "";
this.accessToken = "";
},
- setUser(user: { name: string; avatar: string; accessToken: string }) {
- this.name = user.name;
+ /**
+ * 设置用户信息
+ */
+ setUser(user: LoginedUserVo) {
+ this.username = user.username;
this.avatar = user.avatar;
- this.accessToken = user.accessToken;
+ this.accessToken = user.token;
},
},
+ persist: true,
});
diff --git a/src/style/css-arco.less b/src/styles/css-arco.less
similarity index 100%
rename from src/style/css-arco.less
rename to src/styles/css-arco.less
diff --git a/src/style/css-base.less b/src/styles/css-base.less
similarity index 100%
rename from src/style/css-base.less
rename to src/styles/css-base.less
diff --git a/src/style/css-transition.less b/src/styles/css-transition.less
similarity index 100%
rename from src/style/css-transition.less
rename to src/styles/css-transition.less
diff --git a/src/style/css-unocss.less b/src/styles/css-unocss.less
similarity index 100%
rename from src/style/css-unocss.less
rename to src/styles/css-unocss.less
diff --git a/src/style/index.ts b/src/styles/index.ts
similarity index 100%
rename from src/style/index.ts
rename to src/styles/index.ts
diff --git a/src/types/auto-component.d.ts b/src/types/auto-component.d.ts
index 9098020..e98b15c 100644
--- a/src/types/auto-component.d.ts
+++ b/src/types/auto-component.d.ts
@@ -11,16 +11,23 @@ declare module '@vue/runtime-core' {
ABreadcrumb: typeof import('@arco-design/web-vue')['Breadcrumb']
ABreadcrumbItem: typeof import('@arco-design/web-vue')['BreadcrumbItem']
AButton: typeof import('@arco-design/web-vue')['Button']
+ ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider']
ADoption: typeof import('@arco-design/web-vue')['Doption']
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
ADropdown: typeof import('@arco-design/web-vue')['Dropdown']
+ AForm: typeof import('@arco-design/web-vue')['Form']
+ AFormItem: typeof import('@arco-design/web-vue')['FormItem']
+ AInput: typeof import('@arco-design/web-vue')['Input']
+ AInputPassword: typeof import('@arco-design/web-vue')['InputPassword']
ALayout: typeof import('@arco-design/web-vue')['Layout']
ALayoutContent: typeof import('@arco-design/web-vue')['LayoutContent']
ALayoutHeader: typeof import('@arco-design/web-vue')['LayoutHeader']
ALayoutSider: typeof import('@arco-design/web-vue')['LayoutSider']
+ ALink: typeof import('@arco-design/web-vue')['Link']
AMenu: typeof import('@arco-design/web-vue')['Menu']
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
+ ASpace: typeof import('@arco-design/web-vue')['Space']
ASubMenu: typeof import('@arco-design/web-vue')['SubMenu']
ATag: typeof import('@arco-design/web-vue')['Tag']
ATooltip: typeof import('@arco-design/web-vue')['Tooltip']
diff --git a/src/types/env.d.ts b/src/types/env.d.ts
index 42d43ee..ce450dc 100644
--- a/src/types/env.d.ts
+++ b/src/types/env.d.ts
@@ -4,15 +4,15 @@ interface ImportMetaEnv {
/**
* 网站标题
*/
- VITE_APP_TITLE: string;
+ VITE_TITLE: string;
/**
* 网站副标题
*/
- VITE_APP_SUBTITLE: string;
+ VITE_SUBTITLE: string;
/**
* 自定义的文件后缀
*/
- VITE_BUILD_EXTENSION: string;
+ VITE_EXTENSION: string;
/**
* API 地址
*/
@@ -20,11 +20,11 @@ interface ImportMetaEnv {
/**
* 开发服务器主机
*/
- VITE_DEV_HOST: string;
+ VITE_HOST: string;
/**
* 开发服务器端口
*/
- VITE_DEV_PORT: number;
+ VITE_PORT: number;
}
interface ImportMeta {
diff --git a/src/utils/message.ts b/src/utils/message.ts
new file mode 100644
index 0000000..9508226
--- /dev/null
+++ b/src/utils/message.ts
@@ -0,0 +1,7 @@
+import { Message } from "@arco-design/web-vue";
+
+export const message = {
+ warning() {
+ Message.warning(``)
+ }
+}
\ No newline at end of file
diff --git a/vite.config.ts b/vite.config.ts
index 120da36..68afe33 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -17,8 +17,8 @@ import plugin from "./scripts/vite/plugin";
export default defineConfig(({ mode }) => {
// 加载顺序,后者优先级高:.env .env.locale .env.[mode] .env.[mode].locale
const env = loadEnv(mode, process.cwd());
- const host = env.VITE_DEV_HOST || "0.0.0.0";
- const port = Number(env.VITE_DEV_PORT || 3020);
+ const host = env.VITE_HOST || "0.0.0.0";
+ const port = Number(env.VITE_PORT || 3020);
return {
base: "./",
@@ -39,7 +39,7 @@ export default defineConfig(({ mode }) => {
less: {
javascriptEnabled: true,
modifyVars: {
- hack: `true; @import (reference) "${resolve("src/style/css-arco.less")}";`,
+ hack: `true; @import (reference) "${resolve("src/styles/css-arco.less")}";`,
arcoblue: "#66f",
},
},