Procházet zdrojové kódy

layout & first require token page

Michael Wang před 3 roky
rodič
revize
eca54a1d7d

+ 4 - 0
components.d.ts

@@ -11,7 +11,11 @@ declare module 'vue' {
     AInput: typeof import('ant-design-vue/es')['Input']
     AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
     AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
+    AMenu: typeof import('ant-design-vue/es')['Menu']
+    AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
     ASpin: typeof import('ant-design-vue/es')['Spin']
+    ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
+    Layout: typeof import('./src/components/Layout.vue')['default']
   }
 }
 

+ 3 - 1
src/api/loginPage.ts

@@ -1,4 +1,5 @@
 import { httpApp } from "@/plugins/axiosApp";
+import { useRouter } from "vue-router";
 
 /** 登录 */
 export function loginByUsername(loginInfo: {
@@ -13,5 +14,6 @@ export function loginByUsername(loginInfo: {
 
 /** 登出 */
 export function logout() {
-  // return httpApp.post("/api/ess/auth/logout");
+  const router = useRouter();
+  return httpApp.post("/api/ess/auth/logout").catch();
 }

+ 12 - 0
src/api/rootOrgPage.ts

@@ -0,0 +1,12 @@
+import { httpApp } from "@/plugins/axiosApp";
+
+/** 顶级机构分页查询 */
+export function getRootOrgList(params: {
+  code?: string;
+  name?: string;
+  enable?: boolean;
+  pageNo?: number;
+  pageSize?: number;
+}) {
+  return httpApp.post("/api/ess/root/org/page", params);
+}

+ 50 - 0
src/components/Layout.vue

@@ -0,0 +1,50 @@
+<template>
+  <div class="tw-h-screen tw-flex">
+    <div class="tw-bg-white">
+      <div class="tw-text-center tw-py-10">qm logo</div>
+      <a-menu style="width: 240px" mode="inline">
+        <a-sub-menu key="sub1">
+          <template #icon> icon </template>
+          <template #title>基础管理</template>
+          <a-menu-item key="1">顶级机构管理</a-menu-item>
+          <a-menu-item key="2">机构管理</a-menu-item>
+          <a-menu-item key="3">角色管理</a-menu-item>
+          <a-menu-item key="4">用户管理</a-menu-item>
+          <a-menu-item key="5">科目管理</a-menu-item>
+        </a-sub-menu>
+        <a-sub-menu key="sub2">
+          <template #icon> icon </template>
+          <template #title>项目管理</template>
+          <a-menu-item key="1">项目列表</a-menu-item>
+          <a-menu-item key="2">关联分析</a-menu-item>
+        </a-sub-menu>
+      </a-menu>
+    </div>
+    <div class="tw-h-screen" style="width: calc(100% - 240px)">
+      <div
+        class="tw-bg-white tw-flex tw-justify-between"
+        style="border-left: 1px solid var(--app-main-bg-color)"
+      >
+        <div>当前所在位置:<span class="location-teleport"></span></div>
+        <div class="tw-flex tw-cursor-pointer">
+          <div>{{ store.userInfo.displayName }}</div>
+
+          <div @click="doLogout">退出</div>
+        </div>
+      </div>
+      <router-view class="tw-m-8"></router-view>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { logout } from "@/api/loginPage";
+import { routeLogout } from "@/router";
+import { useMainStore } from "@/store";
+
+const store = useMainStore();
+
+async function doLogout() {
+  logout().then(() => routeLogout({ cause: "主动退出", redirectTo: "/" }));
+}
+</script>

+ 3 - 1
src/features/Login/Login.vue

@@ -43,10 +43,11 @@ const store = useMainStore();
 let accountValue = ref("");
 let password = ref("");
 const route = useRoute();
-const rootOrgId = route.query.rootOrgId as string;
+let rootOrgId = route.query.rootOrgId as string;
 const router = useRouter();
 if (!rootOrgId) {
   router.push("/?rootOrgId=1");
+  rootOrgId = "1";
 }
 
 let errorInfo = ref("");
@@ -60,6 +61,7 @@ async function login() {
     });
     console.log(res);
     store.setUserInfo(res.data);
+    router.push("/rootOrg");
   } catch (error) {
     console.log(error);
     errorInfo.value = (<any>error).response.data.desc;

+ 3 - 0
src/features/rootOrg/RootOrg.vue

@@ -0,0 +1,3 @@
+<template>
+  <div>org</div>
+</template>

+ 6 - 1
src/plugins/axiosNotice.ts

@@ -2,6 +2,8 @@ import Vue from "vue";
 import { throttle } from "lodash-es";
 import { message } from "ant-design-vue";
 import { logout } from "@/api/loginPage";
+import { routeLogout } from "@/router";
+import { useRoute } from "vue-router";
 
 export const notifyInvalidTokenThrottled = throttle(() => {
   message.error({
@@ -9,7 +11,10 @@ export const notifyInvalidTokenThrottled = throttle(() => {
     duration: 10,
   });
   setTimeout(() => {
-    logout();
+    const route = useRoute();
+    logout().then(() =>
+      routeLogout({ cause: "主动退出", redirectTo: route.fullPath })
+    );
   }, 3000);
   console.log("登录失效");
 }, 1000);

+ 29 - 3
src/router/index.ts

@@ -1,12 +1,15 @@
 import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
 import Login from "@/features/login/Login.vue";
 import Layout from "@/components/Layout.vue";
+import { getToken } from "@/auth/auth";
+import { isNil } from "lodash-es";
+import { useMainStore } from "@/store";
 
 const routes = [
-  { path: "/", component: Login },
-  { path: "/Login", component: Login, name: "Login" },
+  { path: "/", redirect: "/login" },
+  { path: "/login", component: Login, name: "Login" },
   {
-    path: "/admin/",
+    path: "/",
     children: [
       {
         path: "rootOrg",
@@ -31,4 +34,27 @@ const router = createRouter({
   routes, // short for `routes: routes`
 });
 
+export async function routeLogout(params: {
+  cause?: string;
+  redirectTo: string;
+}) {
+  const store = useMainStore();
+  return router.push(
+    `/login?rootOrgId=${
+      store.userInfo.rootOrgId === "-1" ? 1 : store.userInfo.rootOrgId
+    }&redirectTo=${encodeURI(params.redirectTo)}`
+  );
+}
+
+router.beforeEach((to, from, next) => {
+  const token = getToken();
+  if (isNil(token) && to.path.includes("/login") === false) {
+    routeLogout({ cause: "missingToken", redirectTo: to.fullPath }).then(() =>
+      next(false)
+    );
+  } else {
+    next();
+  }
+});
+
 export default router;

+ 14 - 1
src/store/index.ts

@@ -13,7 +13,7 @@ export const useMainStore = defineStore("main", {
         userId: -1,
         identity: "",
         displayName: "",
-        rootOrgId: "",
+        rootOrgId: "-1",
         rootOrgName: "",
         token: "",
         roleList: [] as Role[],
@@ -29,3 +29,16 @@ export const useMainStore = defineStore("main", {
     },
   },
 });
+
+setTimeout(() => {
+  const store = useMainStore();
+  store.$subscribe((_, state) =>
+    sessionStorage.setItem("appState", JSON.stringify(state))
+  );
+  const state = JSON.parse(
+    sessionStorage.getItem("appState") || "{}"
+  ) as ReturnType<typeof useMainStore>;
+  if (state.userInfo?.token) {
+    Object.assign(store, state);
+  }
+}, 0);

+ 1 - 1
src/styles/global.css

@@ -5,7 +5,7 @@
   --app-container-bg-color: white;
   --app-main-bg-color: #dee4f3;
   --app-main-text-color: #283e76;
-  --app-min-width: 1280px;
+  --app-min-width: 1024px;
   --app-bold-text-color: #435488;
   --app-small-header-text-color: #7584ac;
   --app-score-color: #5d65ff;