+
{{ lastName }}
@@ -18,14 +18,15 @@
diff --git a/src/modules/base/pages/layout/components/topbar.vue b/src/modules/base/pages/layout/components/topbar.vue
new file mode 100644
index 0000000..a85adf8
--- /dev/null
+++ b/src/modules/base/pages/layout/components/topbar.vue
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ user.info.nickName }}
+
+
+
+
+
+
+
+ 个人中心
+
+
+
+ 退出
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/base/pages/layout/components/views.vue b/src/modules/base/pages/layout/components/views.vue
new file mode 100644
index 0000000..0f95b68
--- /dev/null
+++ b/src/modules/base/pages/layout/components/views.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/base/pages/layout/index.vue b/src/modules/base/pages/layout/index.vue
new file mode 100644
index 0000000..a3cf360
--- /dev/null
+++ b/src/modules/base/pages/layout/index.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
diff --git a/src/cool/modules/base/pages/login/components/captcha.vue b/src/modules/base/pages/login/components/captcha.vue
similarity index 64%
rename from src/cool/modules/base/pages/login/components/captcha.vue
rename to src/modules/base/pages/login/components/captcha.vue
index 17328b9..c70667e 100644
--- a/src/cool/modules/base/pages/login/components/captcha.vue
+++ b/src/modules/base/pages/login/components/captcha.vue
@@ -1,12 +1,12 @@
-
-
+
+
diff --git a/src/cool/modules/base/static/css/index.scss b/src/modules/base/static/css/index.scss
similarity index 100%
rename from src/cool/modules/base/static/css/index.scss
rename to src/modules/base/static/css/index.scss
diff --git a/src/cool/modules/base/static/css/theme.scss b/src/modules/base/static/css/theme.scss
similarity index 94%
rename from src/cool/modules/base/static/css/theme.scss
rename to src/modules/base/static/css/theme.scss
index 10a3e13..0846d0b 100644
--- a/src/cool/modules/base/static/css/theme.scss
+++ b/src/modules/base/static/css/theme.scss
@@ -1,6 +1,6 @@
// customize style
.scroller1 {
- overflow: hidden auto;
+ overflow: auto;
position: relative;
z-index: 9;
@@ -19,7 +19,7 @@
}
}
-// Element-ui theme
+// Element-plus theme
.el-input-number {
.el-input-number__decrease,
.el-input-number__increase {
diff --git a/src/modules/base/store/app.ts b/src/modules/base/store/app.ts
new file mode 100644
index 0000000..283aefa
--- /dev/null
+++ b/src/modules/base/store/app.ts
@@ -0,0 +1,62 @@
+import { defineStore } from "pinia";
+import { ref } from "vue";
+import { app } from "/@/cool/config";
+import { deepMerge, getBrowser, storage } from "/@/cool/utils";
+
+export const useAppStore = defineStore("app", function () {
+ // 基本信息
+ const info = ref
({
+ ...app
+ });
+
+ // 浏览器信息
+ const browser = ref(getBrowser());
+
+ // 加载
+ const loading = ref(false);
+
+ // 是否折叠
+ const isFold = ref(browser.value.isMini || false);
+
+ // 折叠
+ function fold(v?: boolean) {
+ if (v === undefined) {
+ v = !isFold.value;
+ }
+
+ isFold.value = v;
+ }
+
+ // 设置基本信息
+ function set(data: any) {
+ deepMerge(info.value, data);
+ storage.set("__app__", info.value);
+ }
+
+ // 设置浏览器信息
+ function setBrowser() {
+ browser.value = getBrowser();
+ }
+
+ // 加载
+ function showLoading() {
+ loading.value = true;
+ }
+
+ // 关闭
+ function hideLoading() {
+ loading.value = false;
+ }
+
+ return {
+ info,
+ browser,
+ loading,
+ isFold,
+ fold,
+ set,
+ setBrowser,
+ showLoading,
+ hideLoading
+ };
+});
diff --git a/src/modules/base/store/index.ts b/src/modules/base/store/index.ts
new file mode 100644
index 0000000..5385acc
--- /dev/null
+++ b/src/modules/base/store/index.ts
@@ -0,0 +1,18 @@
+import { useAppStore } from "./app";
+import { useMenuStore } from "./menu";
+import { useProcessStore } from "./process";
+import { useUserStore } from "./user";
+
+export function useBaseStore() {
+ const app = useAppStore();
+ const menu = useMenuStore();
+ const process = useProcessStore();
+ const user = useUserStore();
+
+ return {
+ app,
+ menu,
+ process,
+ user
+ };
+}
diff --git a/src/modules/base/store/menu.ts b/src/modules/base/store/menu.ts
new file mode 100644
index 0000000..a4860e1
--- /dev/null
+++ b/src/modules/base/store/menu.ts
@@ -0,0 +1,188 @@
+import { ElMessage } from "element-plus";
+import { defineStore } from "pinia";
+import { ref } from "vue";
+import { deepTree, isArray, isEmpty, isObject, revDeepTree, storage } from "/@/cool/utils";
+import { app } from "/@/cool/config";
+import { addViews, service } from "/@/cool";
+import { revisePath } from "../utils";
+
+declare enum Type {
+ "目录" = 0,
+ "菜单" = 1,
+ "权限" = 2
+}
+
+declare interface Item {
+ id: number;
+ parentId: number;
+ path: string;
+ router?: string;
+ viewPath?: string;
+ type: Type;
+ name: string;
+ icon: string;
+ orderNum: number;
+ isShow: number;
+ keepAlive?: number;
+ meta?: {
+ label: string;
+ keepAlive: number;
+ };
+ children?: Item[];
+}
+
+// 本地缓存
+const data = storage.info();
+
+export const useMenuStore = defineStore("menu", function () {
+ // 视图路由
+ const routes = ref- (data["menu.routes"] || []);
+
+ // 菜单组
+ const group = ref
- (data["menu.group"] || []);
+
+ // 顶部菜单序号
+ const index = ref(0);
+
+ // 左侧菜单列表
+ const list = ref
- ([]);
+
+ // 权限列表
+ const perms = ref(data["menu.perms"] || []);
+
+ // 设置左侧菜单
+ function setMenu(i: number) {
+ if (isEmpty(index)) {
+ i = index.value;
+ }
+
+ if (app.showAMenu) {
+ const { children = [] } = group.value[i] || {};
+
+ index.value = i;
+ list.value = children;
+ } else {
+ list.value = group.value;
+ }
+ }
+
+ // 设置权限
+ function setPerms(list: Item[]) {
+ function deep(d: any) {
+ if (isObject(d)) {
+ if (d.permission) {
+ d._permission = {};
+ for (const i in d.permission) {
+ d._permission[i] =
+ list.findIndex((e: any) =>
+ e.replace(/:/g, "/").includes(`${d.namespace}/${i}`)
+ ) >= 0;
+ }
+ } else {
+ for (const i in d) {
+ deep(d[i]);
+ }
+ }
+ }
+ }
+
+ perms.value = list;
+ storage.set("menu.perms", list);
+
+ deep(service);
+ }
+
+ // 设置视图
+ function setRoutes(list: Item[]) {
+ addViews(list);
+
+ routes.value = list;
+ storage.set("menu.routes", list);
+ }
+
+ // 设置菜单组
+ function setGroup(list: Item[]) {
+ group.value = list;
+ storage.set("menu.group", list);
+ }
+
+ // 获取菜单,权限信息
+ function get(): Promise {
+ return new Promise((resolve, reject) => {
+ function next(res: any) {
+ if (!isArray(res.menus)) {
+ res.menus = [];
+ }
+
+ if (!isArray(res.perms)) {
+ res.perms = [];
+ }
+
+ const list = res.menus
+ .filter((e: Item) => e.type != 2)
+ .map((e: Item) => {
+ return {
+ id: e.id,
+ parentId: e.parentId,
+ path: revisePath(e.router || String(e.id)),
+ viewPath: e.viewPath,
+ type: e.type,
+ name: e.name,
+ icon: e.icon,
+ orderNum: e.orderNum,
+ isShow: isEmpty(e.isShow) ? true : e.isShow,
+ meta: {
+ label: e.name,
+ keepAlive: e.keepAlive
+ },
+ children: []
+ };
+ });
+
+ // 设置权限
+ setPerms(res.perms);
+
+ // 设置菜单组
+ setGroup(deepTree(list));
+
+ // 设置视图路由
+ setRoutes(list.filter((e: Item) => e.type == 1));
+
+ // 设置菜单
+ setMenu(index.value);
+
+ resolve(group.value);
+ }
+
+ // 自定义菜单
+ if (isEmpty(app.menuList)) {
+ service.base.comm
+ .permmenu()
+ .then((res) => {
+ next(res);
+ })
+ .catch((err) => {
+ ElMessage.error("菜单加载异常!");
+ reject(err);
+ });
+ } else {
+ next({
+ menus: revDeepTree([])
+ });
+ }
+ });
+ }
+
+ return {
+ routes,
+ group,
+ index,
+ list,
+ perms,
+ get,
+ setPerms,
+ setMenu,
+ setRoutes,
+ setGroup
+ };
+});
diff --git a/src/modules/base/store/process.ts b/src/modules/base/store/process.ts
new file mode 100644
index 0000000..e44718e
--- /dev/null
+++ b/src/modules/base/store/process.ts
@@ -0,0 +1,72 @@
+import { defineStore } from "pinia";
+import { ref } from "vue";
+
+interface Item {
+ label: string;
+ value: string;
+ active?: boolean;
+ keepAlive?: boolean;
+}
+
+export const useProcessStore = defineStore("process", function () {
+ const menu1: Item = {
+ label: "首页",
+ value: "/",
+ active: true
+ };
+
+ const list = ref
- ([menu1]);
+
+ // 添加
+ function add(item: Item) {
+ const index = list.value.findIndex(
+ (e: Item) => e.value.split("?")[0] === item.value.split("?")[0]
+ );
+
+ list.value.map((e: Item) => {
+ e.active = e.value == item.value;
+ });
+
+ if (index < 0) {
+ if (item.value == "/") {
+ item.label = menu1.label;
+ }
+
+ if (item.label) {
+ list.value.push({
+ ...item,
+ active: true
+ });
+ }
+ } else {
+ list.value[index].active = true;
+ list.value[index].label = item.label;
+ list.value[index].value = item.value;
+ }
+ }
+
+ // 移除
+ function remove(index: number) {
+ if (index != 0) {
+ list.value.splice(index, 1);
+ }
+ }
+
+ // 设置
+ function set(data: Item[]) {
+ list.value = data;
+ }
+
+ // 重置
+ function reset() {
+ list.value = [menu1];
+ }
+
+ return {
+ list,
+ add,
+ remove,
+ set,
+ reset
+ };
+});
diff --git a/src/modules/base/store/user.ts b/src/modules/base/store/user.ts
new file mode 100644
index 0000000..28845f7
--- /dev/null
+++ b/src/modules/base/store/user.ts
@@ -0,0 +1,103 @@
+import { defineStore } from "pinia";
+import { ref } from "vue";
+import { href, storage } from "/@/cool/utils";
+import { test } from "/@/cool/config";
+import { service } from "/@/cool";
+
+interface User {
+ id: number;
+ name: string;
+ username: string;
+ nickName: string;
+ phone: string;
+ headImg: string;
+ email: string;
+ status: 0 | 1;
+ departmentId: string;
+ createTime: Date;
+ [key: string]: any;
+}
+
+// 本地缓存
+const data = storage.info();
+
+export const useUserStore = defineStore("user", function () {
+ // 标识
+ const token = ref(test.token || data.token);
+
+ // 设置标识
+ function setToken(data: {
+ token: string;
+ expire: string;
+ refreshToken: string;
+ refreshExpire: string;
+ }) {
+ // 请求的唯一标识
+ token.value = data.token;
+ storage.set("token", data.token, data.expire);
+
+ // 刷新 token 的唯一标识
+ storage.set("refreshToken", data.refreshToken, data.refreshExpire);
+ }
+
+ // 刷新标识
+ async function refreshToken(): Promise {
+ return new Promise((resolve, reject) => {
+ service.base.open
+ .refreshToken({
+ refreshToken: storage.get("refreshToken")
+ })
+ .then((res) => {
+ setToken(res);
+ resolve(res.token);
+ })
+ .catch((err) => {
+ logout();
+ reject(err);
+ });
+ });
+ }
+
+ // 用户信息
+ const info = ref(data.userInfo);
+
+ // 设置用户信息
+ function set(value: any) {
+ info.value = value;
+ storage.set("userInfo", value);
+ }
+
+ // 清除用户
+ function clear() {
+ storage.remove("userInfo");
+ storage.remove("token");
+ token.value = "";
+ info.value = null;
+ }
+
+ // 退出
+ async function logout() {
+ await service.base.comm.logout();
+ clear();
+ href("/login");
+ }
+
+ // 获取用户信息
+ async function get() {
+ return service.base.comm.person().then((res) => {
+ set(res);
+ return res;
+ });
+ }
+
+ return {
+ token,
+ info,
+ get,
+ set,
+ logout,
+ clear,
+ setToken,
+ refreshToken
+ };
+});
diff --git a/src/cool/modules/base/utils/index.ts b/src/modules/base/utils/index.ts
similarity index 100%
rename from src/cool/modules/base/utils/index.ts
rename to src/modules/base/utils/index.ts
diff --git a/src/modules/base/views/components/dept-check.vue b/src/modules/base/views/components/dept-check.vue
new file mode 100644
index 0000000..464c76a
--- /dev/null
+++ b/src/modules/base/views/components/dept-check.vue
@@ -0,0 +1,145 @@
+