Browse Source

路由权限

CzRger 7 months ago
parent
commit
ef5f945f1e

+ 22 - 9
src/api/interceptors.ts

@@ -1,5 +1,6 @@
 import axios from 'axios';
-// import {notify} from '@/utils/notify'
+import {ElMessage} from "element-plus";
+import {toLogin} from "@/utils/permissions";
 export class Interceptors {
   public instance: any
 
@@ -21,7 +22,7 @@ export class Interceptors {
     this.instance.interceptors.request.use(
       (config: any) => {
         if (!config.headers.Authorization) {
-          const token = localStorage.getItem('ax_token');
+          const token = localStorage.getItem('ss_token');
           if (token) {
             config.headers.Authorization = token;
           } else {
@@ -39,7 +40,22 @@ export class Interceptors {
     this.instance.interceptors.response.use(
       // 请求成功
       (res: any) => {
-        return Promise.resolve(res.data)
+        if (res.status === 200) {
+          if(res.data.code === 200){
+            return Promise.resolve(res.data);
+          } else if (res.data.code === 401) {
+            if(res.data.msg){
+              //@ts-ignore
+              ElMessage.warning(res.data.msg);
+            }
+            toLogin()
+          } else {
+            return Promise.resolve(res.data);
+          }
+        } else {
+          this.errorHandle(res);
+          return Promise.reject(res.data);
+        }
       },
       // 请求失败
       (error: { response: any; }) => {
@@ -49,8 +65,7 @@ export class Interceptors {
           this.errorHandle(response);
           return Promise.reject(response.data);
         } else {
-          //@ts-ignore
-          // notify.warning('网络连接异常,请稍后再试!');
+          ElMessage.warning('网络连接异常,请稍后再试!');
           // 抛出报错信息,在页面里需要接收
           return Promise.reject(error);
         }
@@ -66,12 +81,10 @@ export class Interceptors {
       case 403:
         break;
       case 404:
-        //@ts-ignore
-        // notify.warning('请求的资源不存在');
+        ElMessage.error('请求的资源不存在');
         break;
       default:
-        //@ts-ignore
-        // notify.warning('连接错误');
+        ElMessage.warning('连接错误');
     }
   }
 }

+ 9 - 0
src/api/modules/mock/global.ts

@@ -0,0 +1,9 @@
+import { handle } from '../../index'
+
+const suffix = 'mock-api'
+
+// 模拟接口
+export const mockGetUserInfo = () => handle({
+  url: `/${suffix}/getUserInfo`,
+  method: 'get',
+})

+ 0 - 1
src/api/request.ts

@@ -1,5 +1,4 @@
 import { Interceptors } from './interceptors';
-// import { ElMessage } from "element-plus";
 export class HttpRequest {
   public axios: any
   constructor() {

+ 1 - 1
src/main.ts

@@ -22,7 +22,7 @@ await initProperties(app)
 initComponent(app)
 app.use(initDirect)
 app.use(router)
-app.use(ElementPlus)
+app.use(ElementPlus as any)
 app.mount('#app')
 // 设置为 true 以在浏览器开发工具的 performance/timeline 面板中启用对组件初始化、编译、渲染和更新的性能追踪。
 app.config.performance = true

+ 47 - 8
src/router/index.ts

@@ -1,10 +1,19 @@
 import {createRouter, createWebHistory} from 'vue-router'
 import staticRouter from './modules/static'
+import webRouter from './modules/web'
+import manageRouter from './modules/manage'
 import Temp404 from '@/views/global/temp/404.vue'
+import {mockGetUserInfo} from "@/api/modules/mock/global";
+import {ElLoading, ElMessage} from "element-plus";
+import {useAppStore} from "@/stores";
+import {toLogin} from "@/utils/permissions";
+
 
 const routes = [
     ...staticRouter,
-    { path: '/:pathMatch(.*)*', name: 'NotFound', component: Temp404 }
+    { path: '/:pathMatch(.*)*', name: 'NotFound', component: Temp404 },
+    { path: '', redirect: '/web' },
+    webRouter,
 ]
 
 const router = createRouter({
@@ -13,15 +22,45 @@ const router = createRouter({
 });
 
 router.beforeEach((to, from , next) => {
-    if (to.query.routeTitle) {
-        to.meta.title = to.query.routeTitle
+    const AppStore = useAppStore()
+    if (userInfo) {
+        if (!AppStore.userInfo) {
+            AppStore.$patch((state) => {
+                state.userInfo = userInfo
+            })
+        }
+        if (to.query.routeTitle) {
+            to.meta.title = to.query.routeTitle
+        }
+        document.title = to.meta?.title || import.meta.env.VITE_TITLE
+        next()
+    } else if (to.path === '/login') {
+        next()
+    } else {
+        ElMessage.error('用户信息获取失败!')
+        toLogin()
     }
-    document.title = to.meta?.title || import.meta.env.VITE_TITLE
-    next()
 })
-
-
+let userInfo = null
 export const initMainRouter = async () => {
-
+    if (localStorage.getItem('ss_token')) {
+        const loading = ElLoading.service({
+            lock: true,
+            text: '加载中……',
+            background: 'rgba(0, 0, 0, 0.7)',
+        })
+        await Promise.all([
+            mockGetUserInfo()
+        ]).then(async ([user]) => {
+            userInfo = user.data
+            console.log('管理员:', userInfo?.isAdmin)
+            if (userInfo?.isAdmin) {
+                router.addRoute(manageRouter)
+            }
+            loading.close()
+        })
+    } else if (location.pathname !== '/login') {
+        toLogin()
+    }
 }
 export default router;

+ 18 - 0
src/router/modules/manage.ts

@@ -0,0 +1,18 @@
+// 后台系统
+export default {
+  path: '/manage',
+  name: '9d2974b6-5ae9-4e5d-b032-bc2f3f4b1aa4',
+  redirect: '/manage/home',
+  children: [
+    {
+      path: 'home',
+      name: '4786ca99-5235-4691-a0e8-078d0365046b',
+      component: () => import('@/views/manage/home/index.vue'),
+    },
+    {
+      path: 'system',
+      name: '1c1a19fd-ac7b-42ce-b4eb-0ac978a5dd3d',
+      component: () => import('@/views/manage/system/index.vue'),
+    }
+  ]
+}

+ 9 - 0
src/router/modules/static.ts

@@ -1,4 +1,13 @@
 // 不需要菜单管理配置的路由
 const staticRouter = [
+  {
+    path: '/login',
+    name: 'login',
+    component: () => import('@/views/global//login/index.vue'),
+    meta: {
+      title: '登录',
+      noToken: true
+    }
+  },
 ]
 export default staticRouter

+ 18 - 0
src/router/modules/web.ts

@@ -0,0 +1,18 @@
+// 前台系统
+export default {
+  path: '/web',
+  name: 'eea02f48-479f-48b1-a4a1-0430070e8bee',
+  redirect: '/web/home',
+  children: [
+    {
+      path: 'home',
+      name: '71305311-abcc-4d13-8531-f966b49839c5',
+      component: () => import('@/views/web/home/index.vue'),
+    },
+    {
+      path: 'list',
+      name: '4f6dd2ea-7c0a-4923-9a57-932ef42235f6',
+      component: () => import('@/views/web/list/index.vue'),
+    }
+  ]
+}

+ 4 - 1
src/stores/app.ts

@@ -1,8 +1,11 @@
 import {defineStore} from "pinia";
+import {mockGetUserInfo} from "@/api/modules/mock/global";
+import {ElLoading} from "element-plus";
 
 export const useAppStore = defineStore('app', {
   state: () => ({
-    token: ''
+    token: localStorage.getItem('ss_token'),
+    userInfo: null,
   }),
   getters: {
   },

+ 5 - 0
src/utils/permissions.ts

@@ -1,3 +1,8 @@
 export const has = (value: any) => {
 
 }
+
+export const toLogin = () => {
+  localStorage.clear();
+  window.location.replace("/login");
+};

+ 3 - 1
src/utils/util.ts

@@ -600,4 +600,6 @@ export const toPhone = (phone) => {
   a.href = 'tel:' + phone
   a.click()
   document.removeChild(a)
-}
+}
+
+export const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms))

+ 16 - 0
src/views/global/index.vue

@@ -0,0 +1,16 @@
+<template>
+  <div>
+    <el-button @click="$router.push('/web')">前台</el-button>
+    <el-button @click="$router.push('/manage')">后台</el-button>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 24 - 0
src/views/global/login/index.vue

@@ -0,0 +1,24 @@
+<template>
+  <div>
+    <h1>这里是登录页面</h1>
+    <el-button @click="onLogin">登录成功</el-button>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+import {ElMessage} from "element-plus";
+import {useRouter} from "vue-router";
+
+const {proxy} = getCurrentInstance()
+const router = useRouter()
+const state: any = reactive({})
+const onLogin = () => {
+  ElMessage.success('登录成功!')
+  localStorage.setItem('ss_token', 'tttoken')
+  location.replace('/')
+}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 1 - 0
src/views/global/temp/404.vue

@@ -1,4 +1,5 @@
 <template>
+  <div style="font-size: 200px">404</div>
 </template>
 
 <script lang="ts">

+ 15 - 0
src/views/manage/home/index.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    <h1>这是后台-首页</h1>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 15 - 0
src/views/manage/index.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    <h1>这是后台管理</h1>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 15 - 0
src/views/manage/system/index.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    <h1>这是后台-系统管理页面</h1>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 16 - 0
src/views/web/home/index.vue

@@ -0,0 +1,16 @@
+<template>
+  <div>
+    <h1>这是智搜首页</h1>
+    <el-button @click="$router.push({name: '4f6dd2ea-7c0a-4923-9a57-932ef42235f6'})">跳转到列表</el-button>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 15 - 0
src/views/web/list/index.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    <h1>这是智搜列表页</h1>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 26 - 26
vite.config.ts

@@ -52,38 +52,38 @@ export default defineConfig({
     open: true,
     strictPort: false,
     proxy: {
-      '/api': {
-        target: 'http://8.130.72.63:18085/',
+      '/mock-api': {
+        target: 'http://localhost:18061/',
         changeOrigin: true,
         rewrite: (path) => {
-          return path.replace(/^\/api/, '')
+          return path.replace(/^\/mock-api/, 'mock-api')
         }
       }
     }
   },
-  css: {
-    postcss: {
-      plugins: [
-        postcsspxtoviewport({
-          unitToConvert: 'px',
-          viewportWidth: 350,
-          unitPrecision: 5, // 单位转换后保留的精度
-          propList: ['*'], // 能转化为vw的属性列表
-          viewportUnit: 'vw', // 希望使用的视口单位
-          fontViewportUnit: 'vw', // 字体使用的视口单位
-          selectorBlackList: ['ignore-'], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。
-          minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
-          mediaQuery: true, // 媒体查询里的单位是否需要转换单位
-          replace: true, //  是否直接更换属性值,而不添加备用属性
-          exclude: [], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
-          include: [], // 如果设置了include,那将只有匹配到的文件才会被转换
-          landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
-          landscapeUnit: 'vw', // 横屏时使用的单位
-          landscapeWidth: 1628, // 横屏时使用的视口宽度
-        }),
-      ]
-    }
-  },
+  // css: {
+  //   postcss: {
+  //     plugins: [
+  //       postcsspxtoviewport({
+  //         unitToConvert: 'px',
+  //         viewportWidth: 1920,
+  //         unitPrecision: 5, // 单位转换后保留的精度
+  //         propList: ['*'], // 能转化为vw的属性列表
+  //         viewportUnit: 'vw', // 希望使用的视口单位
+  //         fontViewportUnit: 'vw', // 字体使用的视口单位
+  //         selectorBlackList: ['ignore-'], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。
+  //         minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
+  //         mediaQuery: true, // 媒体查询里的单位是否需要转换单位
+  //         replace: true, //  是否直接更换属性值,而不添加备用属性
+  //         exclude: [], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
+  //         include: [], // 如果设置了include,那将只有匹配到的文件才会被转换
+  //         landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
+  //         landscapeUnit: 'vw', // 横屏时使用的单位
+  //         landscapeWidth: 1628, // 横屏时使用的视口宽度
+  //       }),
+  //     ]
+  //   }
+  // },
   build: {
     outDir: "smart-search-web",
     rollupOptions: {//分包优化