瀏覽代碼

添加登录退出功能,集成到界面和路由当中

Kevin Jiang 3 年之前
父節點
當前提交
4ee86f981f

+ 17 - 2
src/components/NavMenu.vue

@@ -1,13 +1,17 @@
 <script setup lang="ts">
-import { FilePptOutlined, FileSearchOutlined, NodeIndexOutlined } from '@ant-design/icons-vue';
+import { FilePptOutlined, FileSearchOutlined, NodeIndexOutlined, LogoutOutlined } from '@ant-design/icons-vue';
 import { onMounted, ref, watch } from 'vue';
 import { useRoute, RouterLink } from "vue-router";
 import _ from "lodash";
+import { useAuthStore } from '@/stores/auth.store';
+import { routeToLogin } from "@/router";
 
 const selectedKeys = ref<string[]>(['/']);
 const openKeys = ref<string[]>(['/']);
-
+// 当前路由
 const route = useRoute();
+// 授权store
+const authStore = useAuthStore();
 
 onMounted(() => {
   openKeys.value = getOpenKeys(route.path);
@@ -37,6 +41,11 @@ function getOpenKeys(path: string): string[] {
   return openKeys;
 }
 
+function logout(e: MouseEvent) {
+  authStore.logout();
+  routeToLogin();
+  e.stopPropagation();
+}
 </script>
 
 <template>
@@ -78,5 +87,11 @@ function getOpenKeys(path: string): string[] {
         <RouterLink to="/knowledge-graph/search">建筑工程科技导航</RouterLink>
       </a-menu-item>
     </a-sub-menu>
+    <a-menu-item key="/logout" @click="logout">
+      <template #icon>
+        <logout-outlined />
+      </template>
+      退出系统
+    </a-menu-item>
   </a-menu>
 </template>

+ 1 - 1
src/main.ts

@@ -3,7 +3,7 @@ import { createPinia } from "pinia";
 import Antd from "ant-design-vue";
 
 import App from "./App.vue";
-import router from "./router";
+import { router } from "./router";
 
 import "ant-design-vue/dist/antd.less";
 

+ 29 - 2
src/router/index.ts

@@ -1,12 +1,15 @@
+import { useAuthStore } from "@/stores/auth.store";
+import type { SearchRouteParam } from "@/types/route.type";
 import { createRouter, createWebHistory } from "vue-router";
 import ReportView from "../views/report/ReportView.vue";
 import RouteView from "../views/RouteView.vue";
 
-const router = createRouter({
+export const router = createRouter({
   history: createWebHistory(import.meta.env.BASE_URL),
   routes: [
     {
       path: "/",
+      name: "Home",
       redirect: "/report/index"
     },
     {
@@ -88,4 +91,28 @@ const router = createRouter({
   ],
 });
 
-export default router;
+router.beforeResolve(async to => {
+  const authStore = useAuthStore();
+
+  if (to.name != 'Login' && !authStore.isLoginIn()) {
+    return { name: "Login" };
+  }
+});
+
+export function routeToHome() {
+  router.push({ name: "Home" })
+}
+
+export function routeToLogin() {
+  router.push({ name: "Login" });
+}
+
+/**
+ * 路由到搜索结果页面,把查询表达式传入到搜索结果页面
+ * @param param queryString参数
+ */
+export function routeToSearch(param: SearchRouteParam, extras: {[index: string]: any} = {}) {
+  const queryStrParam: {[index: string]: any} = { ...param, ...extras };
+
+  router.push({ name: 'SearchResult', query: queryStrParam });
+}

+ 28 - 0
src/stores/auth.store.ts

@@ -0,0 +1,28 @@
+import { ref } from "vue";
+import { defineStore } from "pinia";
+
+const tokenKey = "token";
+
+export const useAuthStore = defineStore('auth', () => {
+  const token = ref(localStorage.getItem(tokenKey));
+
+  function setToken(_token: string) {
+    token.value = _token;
+    localStorage.setItem(tokenKey, _token);
+  }
+
+  function isLoginIn() {
+    return token.value && token.value.trim() != "";
+  }
+
+  function logout() {
+    setToken("");
+  }
+
+  return {
+    token,
+    setToken,
+    isLoginIn,
+    logout,
+  }
+});

+ 13 - 0
src/types/route.type.ts

@@ -0,0 +1,13 @@
+import type { SearchType, Sort } from "./search.types";
+
+export interface SearchRouteParam {
+  type: SearchType;
+  query?: string;
+  field?: string;
+  kw?: string;
+  yearSelected?: string[];
+  authorSelected?: string[];
+  sort?: Sort;
+  page?: number;
+  size?: number;
+}

+ 11 - 0
src/types/search.types.ts

@@ -19,3 +19,14 @@ export interface AggItem {
   key: string;
   count: number;
 }
+
+export type SearchType = 'simple' | 'advanced';
+
+export interface Pagination {
+  page: number;
+  size: number;
+}
+
+export type Sort = 'Relevance' | 'DateDesc' | 'DateAsc';
+
+export type ResultMode = 'brief' | 'detail';

+ 9 - 9
src/views/LoginView.vue

@@ -1,6 +1,8 @@
-<script setup lang="ts">import { reactive } from 'vue';
-import { useRoute, useRouter } from "vue-router";
+<script setup lang="ts">
+import { reactive } from 'vue';
 import user from "@/services/user.service";
+import { useAuthStore } from '@/stores/auth.store';
+import { routeToHome } from '@/router';
 
 interface FormState {
   username: string;
@@ -8,26 +10,24 @@ interface FormState {
   remember: boolean;
 }
 
-// 路由管理器
-const router = useRouter();
-// 当前路由对象
-const route = useRoute();
+// 授权store
+const authStore = useAuthStore();
 
 const formState = reactive<FormState>({
   username: '',
   password: '',
   remember: true,
 });
+
 const onFinish = (values: any) => {
-  console.log(values);
   let param = {
     mobilePhone: values.username,
     password: values.password,
     type: 1
   }
   user.login(param).then((resp) => {
-    localStorage.setItem('token', resp.data.data.token);
-    router.push({ name: "SearchIndex" });
+    authStore.setToken(resp.data.data.token);
+    routeToHome();
   }).catch((err) => {
     console.log(err);
   })

+ 1 - 1
src/views/search/AdvancedSearchView.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { message } from "ant-design-vue";
 import { ref } from "vue";
-import { routeToSearch } from "./search.helper";
+import { routeToSearch } from "@/router";
 
 const query = ref('');
 

+ 4 - 3
src/views/search/SearchResultView.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import { onUnmounted, ref, computed, type Ref, onMounted, reactive, provide } from "vue";
+import { onUnmounted, ref, computed, type Ref, onMounted, reactive } from "vue";
 import { useRoute } from "vue-router";
 import { useSideBarStore } from "@/stores/side-bar";
 import SearchBox from "./components/SearchBox.vue";
@@ -7,9 +7,10 @@ import SearchResultToolbar from "./components/SearchResultToolbar.vue";
 import SearchResultList from "./components/SearchResultList.vue";
 import type { SearchRequest } from "@/types/request.types";
 import { useSearchStore } from "@/stores/search.store";
-import { routeToSearch, type SearchRouteParam } from "./search.helper";
-import type { ResultMode, Sort } from "./search-component.type";
+import { routeToSearch } from "@/router";
 import AdvancedSearchBox from "./components/AdvancedSearchBox.vue";
+import type { SearchRouteParam } from "@/types/route.type";
+import type { ResultMode, Sort } from "@/types/search.types";
 
 const sideBarStore = useSideBarStore();
 

+ 1 - 1
src/views/search/SearchView.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { message, type SelectProps } from "ant-design-vue";
 import { ref } from "vue";
-import { routeToSearch } from "./search.helper";
+import { routeToSearch } from "@/router";
 
 const keyword = ref("");
 

+ 1 - 1
src/views/search/components/SearchResultItem.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { PropType } from "vue";
 import type { SearchResultDoc } from "@/types/search.types";
-import type { ResultMode } from "../search-component.type";
+import type { ResultMode } from "@/types/search.types";
 
 defineProps({
   data: {

+ 1 - 1
src/views/search/components/SearchResultList.vue

@@ -2,7 +2,7 @@
 import { computed, type PropType } from "vue";
 import SearchResultItem from "./SearchResultItem.vue";
 import type { SearchResult } from "@/types/search.types";
-import type { ResultMode } from "../search-component.type";
+import type { ResultMode } from "@/types/search.types";
 
 const props = defineProps({
   data: {

+ 1 - 1
src/views/search/components/SearchResultToolbar.vue

@@ -3,7 +3,7 @@ import type { SelectProps } from "ant-design-vue";
 import { ref } from "vue";
 import type { PropType } from "vue";
 import type { SearchResult } from "@/types/search.types";
-import type { Pagination, ResultMode } from "../search-component.type";
+import type { Pagination, ResultMode } from "@/types/search.types";
 
 // 排序选择项列表
 const sortOptions = ref<SelectProps["options"]>([

+ 0 - 9
src/views/search/search-component.type.ts

@@ -1,9 +0,0 @@
-
-export interface Pagination {
-  page: number;
-  size: number;
-}
-
-export type Sort = 'Relevance' | 'DateDesc' | 'DateAsc';
-
-export type ResultMode = 'brief' | 'detail';

+ 0 - 105
src/views/search/search.helper.ts

@@ -1,105 +0,0 @@
-import router from "@/router/index";
-import type { LocationQuery } from "vue-router";
-import type { Sort } from "./search-component.type";
-
-export type SearchType = 'simple' | 'advanced';
-
-export interface SearchRouteParam {
-  type: SearchType;
-  query?: string;
-  field?: string;
-  kw?: string;
-  yearSelected?: string[];
-  authorSelected?: string[];
-  sort?: Sort;
-  page?: number;
-  size?: number;
-}
-
-/**
- * 路由到搜索结果页面,把查询表达式传入到搜索结果页面
- * @param param queryString参数
- */
-export function routeToSearch(param: SearchRouteParam, extras: {[index: string]: any} = {}) {
-  const queryStrParam: {[index: string]: any} = { ...param, ...extras };
-
-  router.push({ name: 'SearchResult', query: queryStrParam });
-}
-
-/**
- * 解析url query string为SearchRouteParam对象
- * @param queryParam parsed url query string
- * @returns SearchRouteParam
- */
-export function parseUrlQuery(queryParam: LocationQuery): SearchRouteParam {
-  let type: SearchType;
-  let query: string = '';
-  let field: string = '';
-  let kw: string = '';
-  if (queryParam.type == 'advanced') {
-    type = 'advanced';
-    query = queryParam.query as string;
-  } else {
-    type = 'simple';
-    // 初始化关键词
-    if (queryParam.kw) {
-      kw = (queryParam.kw as string).trim();
-    }
-    if (queryParam.field) {
-      field = (queryParam.field as string).trim();
-    }
-    query = `${field}=(${kw})`
-  }
-
-  let yearSelected: string[] = [];
-  if (queryParam.yearSelected) {
-    if (Array.isArray(queryParam.yearSelected)) {
-      yearSelected = queryParam.yearSelected as string[];
-    } else {
-      yearSelected = [queryParam.yearSelected];
-    }
-  }
-
-  let authorSelected: string[] = [];
-  if (queryParam.authorSelected) {
-    if (Array.isArray(queryParam.authorSelected)) {
-      authorSelected = queryParam.authorSelected as string[];
-    } else {
-      authorSelected = [queryParam.authorSelected];
-    }
-  }
-
-  let sort: Sort = 'Relevance';
-  if (queryParam.sort) {
-    sort = queryParam.sort as Sort;
-  }
-
-  let page: number | null = null;
-  if (queryParam.page) {
-    page = parseInt(queryParam.page as string);
-  }
-
-  let size: number | null = null;
-  if (queryParam.size) {
-    size = parseInt(queryParam.size as string);
-  }
-
-  const result: SearchRouteParam = {
-    type,
-    query,
-    field,
-    kw,
-    yearSelected,
-    authorSelected,
-    sort,
-  };
-
-  if (page) {
-    result['page'] = page;
-  }
-  if (size) {
-    result['size'] = size;
-  }
-
-  return result;
-}