rui.jiang 1 рік тому
батько
коміт
8567a61849

Різницю між файлами не показано, бо вона завелика
+ 14176 - 1
package-lock.json


+ 2 - 1
package.json

@@ -15,7 +15,8 @@
     "svg-sprite-loader": "^6.0.11",
     "vue": "^2.6.14",
     "vue-router": "^3.5.1",
-    "vuex": "^3.6.2"
+    "vuex": "^3.6.2",
+    "vuex-persistedstate": "^4.1.0"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "~5.0.0",

+ 45 - 16
src/App.vue

@@ -1,37 +1,61 @@
 <template>
-  <div id="app">
+  <div id="app" :style="{ '--color': defaultTheme }" v-loading="defaultLoading">
+    <theme-picker v-show="false" />
+
     <router-view />
   </div>
 </template>
 <script>
-import { login } from '@/api/login'
-import { testApi } from '@/api/test'
+import ThemePicker from "@/components/ThemePicker";
+import { login } from "@/api/login";
+import { testApi } from "@/api/test";
+import "@/assets/style/index.css";
 export default {
   created() {
     // this.test('2122')
   },
-
+  components: { ThemePicker },
+  metaInfo() {
+    return {
+      title:
+        this.$store.state.settings.dynamicTitle &&
+        this.$store.state.settings.title,
+      titleTemplate: (title) => {
+        return title
+          ? `${title} - ${process.env.VUE_APP_TITLE}`
+          : process.env.VUE_APP_TITLE;
+      },
+    };
+  },
+  computed: {
+    defaultTheme() {
+      return this.$store.state.settings.theme;
+    },
+    defaultLoading() {
+      return this.$store.state.settings.loading;
+    },
+  },
   methods: {
     // 调取后端api方法
     addLog() {
       const data = {
-        userName: '测试1',
-        password: '1111'
-      }
-      login(data).then((res) => {})
+        userName: "测试1",
+        password: "1111",
+      };
+      login(data).then((res) => {});
     },
     // 调取后端api方法
     test(id) {
       const data = {
-        userName: '测试2',
-        password: '1111'
-      }
+        userName: "测试2",
+        password: "1111",
+      };
       testApi(data, id).then((res) => {
-        console.log(res)
-      })
-    }
-  }
-}
+        console.log(res);
+      });
+    },
+  },
+};
 </script>
 <style lang="scss">
 body {
@@ -39,3 +63,8 @@ body {
   height: 100%;
 }
 </style>
+<style scoped>
+#app .theme-picker {
+  display: none;
+}
+</style>

+ 7 - 7
src/api/login.js

@@ -1,9 +1,9 @@
-import request from '@/utils/request'
+import request from "@/utils/request";
 
-export function login (data) {
+export function login(data) {
   return request({
-    url: '/login',
-    method: 'post',
-    data
-  })
-}
+    url: "/energy-manage-service/sysuserinfo/open/userLogin",
+    method: "post",
+    data,
+  });
+}

+ 31 - 0
src/assets/style/element-variables.module.scss

@@ -0,0 +1,31 @@
+/**
+* I think element-ui's default theme color is too light for long-term use.
+* So I modified the default color and you can modify it to your liking.
+**/
+
+/* theme color */
+$--color-primary: #00baad;
+$--color-success: #13ce66;
+$--color-warning: #ffba00;
+$--color-danger: #ff4949;
+// $--color-info: #1E1E1E;
+
+$--button-font-weight: 400;
+
+// $--color-text-regular: #1f2d3d;
+
+$--border-color-light: #dfe4ed;
+$--border-color-lighter: #e6ebf5;
+
+$--table-border: 1px solid #dfe6ec;
+
+/* icon font path, required */
+$--font-path: "~element-ui/lib/theme-chalk/fonts";
+
+@import "~element-ui/packages/theme-chalk/src/index";
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+  theme: $--color-primary;
+}

+ 4 - 0
src/assets/style/index.css

@@ -0,0 +1,4 @@
+.el-table th.el-table__cell {
+  background-color: var(--color) !important;
+  color: aliceblue !important;
+}

+ 35 - 16
src/components/HeaderCom.vue

@@ -6,7 +6,12 @@
     </div>
     <div class="personalCenter">
       <p class="current-time">{{ currentDate }}</p>
-      <el-popover placement="bottom" width="220" trigger="click" style="cursor: pointer">
+      <el-popover
+        placement="bottom"
+        width="220"
+        trigger="click"
+        style="cursor: pointer"
+      >
         <img src="@/assets/portrait.png" slot="reference" />
         <div>
           <div class="cursor-pointer boxmini">
@@ -21,6 +26,14 @@
             <p>角色:超级管理员</p>
           </div>
           <el-divider></el-divider>
+          <div class="cursor-pointer boxmini">
+            <p>主题切换:</p>
+            <theme-picker
+              style="float: right; height: 26px; margin: -3px 8px 0 0"
+              @change="themeChange"
+            />
+          </div>
+          <el-divider></el-divider>
           <div class="cursor-pointer boxmini" @click="skip(1)">
             <p class="logout">退出登录</p>
           </div>
@@ -31,33 +44,43 @@
 </template>
 
 <script>
+import ThemePicker from "@/components/ThemePicker";
 export default {
   data() {
     return {
       currentDate: "",
-    }
+    };
+  },
+  components: {
+    ThemePicker,
   },
-
   mounted() {
     this.updateCurrentDateTime();
     setInterval(this.updateCurrentDateTime, 1000);
   },
 
   methods: {
+    themeChange(val) {
+      this.$store.dispatch("settings/changeSetting", {
+        key: "theme",
+        value: val,
+      });
+      this.theme = val;
+    },
     updateCurrentDateTime() {
       const now = new Date();
       const year = now.getFullYear();
-      const month = (now.getMonth() + 1).toString().padStart(2, '0');
-      const day = now.getDate().toString().padStart(2, '0');
-      const hours = now.getHours().toString().padStart(2, '0');
-      const minutes = now.getMinutes().toString().padStart(2, '0');
-      const seconds = now.getSeconds().toString().padStart(2, '0');
+      const month = (now.getMonth() + 1).toString().padStart(2, "0");
+      const day = now.getDate().toString().padStart(2, "0");
+      const hours = now.getHours().toString().padStart(2, "0");
+      const minutes = now.getMinutes().toString().padStart(2, "0");
+      const seconds = now.getSeconds().toString().padStart(2, "0");
 
       // 设置当前时间数据
       this.currentDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
-    }
-  }
-}
+    },
+  },
+};
 </script>
 
 <style lang="scss" scoped>
@@ -66,7 +89,7 @@ export default {
   justify-content: space-between;
   align-items: center;
   height: 60px;
-  background: #FFF;
+  background: #fff;
   padding: 0 20px;
 
   .header-logo {
@@ -111,12 +134,9 @@ export default {
 .boxmini {
   display: flex;
 
-
   p {
-
     font-size: 14px;
     font-weight: 600;
-
   }
 
   .logout {
@@ -124,7 +144,6 @@ export default {
     text-align: center;
     width: 100%;
   }
-
 }
 
 .el-divider--horizontal {

+ 16 - 0
src/components/ThemePicker/chalk.js

@@ -0,0 +1,16 @@
+/*
+ * @Author: your name
+ * @Date: 2024-05-19 21:10:47
+ * @LastEditTime: 2024-05-19 21:10:55
+ * @LastEditors: bogon
+ * @Description: In User Settings Edit
+ * @FilePath: /performance-test/src/components/ThemePicker/chalk.js
+ */
+// chalk.js
+const chalkCss = `
+body {
+  background-color: #f0f0f0;
+}
+`;
+
+export { chalkCss };

+ 220 - 0
src/components/ThemePicker/index.vue

@@ -0,0 +1,220 @@
+<template>
+  <el-color-picker
+    v-model="theme"
+    :predefine="[
+      '#409EFF',
+      '#1890ff',
+      '#304156',
+      '#212121',
+      '#11a983',
+      '#13c2c2',
+      '#6959CD',
+      '#f5222d',
+    ]"
+    class="theme-picker"
+    popper-class="theme-picker-dropdown"
+    @change="change"
+  />
+</template>
+<script>
+// import chalkCss from "./chalk";
+const version = require("element-ui/package.json").version; // element-ui version from node_modules
+const ORIGINAL_THEME = "#409EFF"; // default color
+
+export default {
+  data() {
+    return {
+      chalk: "", // content of theme-chalk css
+      theme: "",
+    };
+  },
+  computed: {
+    defaultTheme() {
+      return this.$store.state.settings.theme;
+    },
+  },
+  watch: {
+    defaultTheme: {
+      handler: function (val, oldVal) {
+        this.theme = val;
+      },
+      immediate: true,
+    },
+    async theme(val) {
+      await this.setTheme(val);
+    },
+  },
+  created() {
+    if (this.defaultTheme !== ORIGINAL_THEME) {
+      this.setTheme(this.defaultTheme);
+    }
+  },
+
+  methods: {
+    async setTheme(val) {
+      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME;
+      if (typeof val !== "string") return;
+      const themeCluster = this.getThemeCluster(val.replace("#", ""));
+      const originalCluster = this.getThemeCluster(oldVal.replace("#", ""));
+
+      const getHandler = (variable, id) => {
+        return () => {
+          const originalCluster = this.getThemeCluster(
+            ORIGINAL_THEME.replace("#", "")
+          );
+          const newStyle = this.updateStyle(
+            this[variable],
+            originalCluster,
+            themeCluster
+          );
+
+          let styleTag = document.getElementById(id);
+          if (!styleTag) {
+            styleTag = document.createElement("style");
+            styleTag.setAttribute("id", id);
+            document.head.appendChild(styleTag);
+          }
+          styleTag.innerText = newStyle;
+        };
+      };
+
+      if (!this.chalk) {
+        console.log(version, "version");
+        this.$store.commit("settings/changeLoading", {
+          key: "loading",
+          value: true,
+        });
+        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
+        // // const url = require("@/assets/style/theme-chalk.css");
+        const res = await this.getCSSString(url, "chalk");
+        console.log(res, "res");
+        this.$store.commit("settings/changeLoading", {
+          key: "loading",
+          value: false,
+        });
+        //  this.chalk = chalkCss.replace(/@font-face{[^}]+}/, '') // 本地缓存,如果需要获取线上的就用上面那种方式,优点:切换无延迟,缺点:需要手动维护 css string
+      }
+
+      const chalkHandler = getHandler("chalk", "chalk-style");
+
+      chalkHandler();
+
+      const styles = [].slice
+        .call(document.querySelectorAll("style"))
+        .filter((style) => {
+          const text = style.innerText;
+          return (
+            new RegExp(oldVal, "i").test(text) && !/Chalk Variables/.test(text)
+          );
+        });
+      styles.forEach((style) => {
+        const { innerText } = style;
+        if (typeof innerText !== "string") return;
+        style.innerText = this.updateStyle(
+          innerText,
+          originalCluster,
+          themeCluster
+        );
+      });
+      // 主题更新完成后,设置 loading 状态为 false
+
+      this.$emit("change", val);
+      const that = this;
+      // setTimeout(() => {
+
+      // }, 2000);
+    },
+
+    updateStyle(style, oldCluster, newCluster) {
+      let newStyle = style;
+
+      // 执行完成时调用 resolve 表示异步操作完成
+      oldCluster.forEach((color, index) => {
+        newStyle = newStyle.replace(new RegExp(color, "ig"), newCluster[index]);
+      });
+      return newStyle;
+    },
+
+    getCSSString(url, variable) {
+      return new Promise((resolve) => {
+        const xhr = new XMLHttpRequest();
+        xhr.onreadystatechange = () => {
+          if (xhr.readyState === 4 && xhr.status === 200) {
+            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, "");
+            resolve();
+          }
+        };
+        xhr.open("GET", url);
+        xhr.send();
+      });
+    },
+
+    getThemeCluster(theme) {
+      const tintColor = (color, tint) => {
+        let red = parseInt(color.slice(0, 2), 16);
+        let green = parseInt(color.slice(2, 4), 16);
+        let blue = parseInt(color.slice(4, 6), 16);
+
+        if (tint === 0) {
+          // when primary color is in its rgb space
+          return [red, green, blue].join(",");
+        } else {
+          red += Math.round(tint * (255 - red));
+          green += Math.round(tint * (255 - green));
+          blue += Math.round(tint * (255 - blue));
+
+          red = red.toString(16);
+          green = green.toString(16);
+          blue = blue.toString(16);
+
+          return `#${red}${green}${blue}`;
+        }
+      };
+
+      const shadeColor = (color, shade) => {
+        let red = parseInt(color.slice(0, 2), 16);
+        let green = parseInt(color.slice(2, 4), 16);
+        let blue = parseInt(color.slice(4, 6), 16);
+
+        red = Math.round((1 - shade) * red);
+        green = Math.round((1 - shade) * green);
+        blue = Math.round((1 - shade) * blue);
+
+        red = red.toString(16);
+        green = green.toString(16);
+        blue = blue.toString(16);
+
+        return `#${red}${green}${blue}`;
+      };
+
+      const clusters = [theme];
+      for (let i = 0; i <= 9; i++) {
+        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))));
+      }
+      clusters.push(shadeColor(theme, 0.1));
+      return clusters;
+    },
+    change() {
+      const that = this;
+      console.log("dianji quding ");
+    },
+  },
+};
+</script>
+
+<style>
+.theme-message,
+.theme-picker-dropdown {
+  z-index: 99999 !important;
+}
+
+.theme-picker .el-color-picker__trigger {
+  height: 26px !important;
+  width: 26px !important;
+  padding: 2px;
+}
+
+.theme-picker-dropdown .el-color-dropdown__link-btn {
+  display: none;
+}
+</style>

+ 24 - 19
src/main.js

@@ -1,30 +1,35 @@
-import Vue from 'vue'
-import App from './App.vue'
-import router from './router'
-import { store } from './store/index.js'
-
+import Vue from "vue";
+import App from "./App.vue";
+import router from "./router";
+import { store } from "./store/index.js";
+import "./assets/style/element-variables.module.scss";
 // 引入element ui
-import ElementUI from 'element-ui'
-import 'element-ui/lib/theme-chalk/index.css'
-Vue.use(ElementUI)
-
+import ElementUI from "element-ui";
+import "element-ui/lib/theme-chalk/index.css";
+Vue.use(ElementUI);
 // 引入css
-import './styles/index.scss'
+import "./styles/index.scss";
 // 注册svg组件
-import SvgIcon from '@/components/SvgIcons/index.vue'
-Vue.component('SvgIcon', SvgIcon)
+import SvgIcon from "@/components/SvgIcons/index.vue";
+Vue.component("SvgIcon", SvgIcon);
 // 序列化post方法
-import qs from 'qs'
-Vue.prototype.$qs = qs
+import qs from "qs";
+Vue.prototype.$qs = qs;
 
 // 引入tailwind
 // https://www.tailwindcss.cn/docs/installation
 
-Vue.prototype.$BASE_URL = window?._BASE_CONFIG?.API
-Vue.config.productionTip = false
-
+Vue.prototype.$BASE_URL = window?._BASE_CONFIG?.API;
+Vue.config.productionTip = false;
+if (store.state.auth.userInfo.permission !== undefined) {
+  store.dispatch("auth/setAddRouter", {
+    resultRouter:
+      (store.state.auth.userInfo && store.state.auth.userInfo.permission) || [],
+    router,
+  });
+}
 new Vue({
   router,
   store,
-  render: (h) => h(App)
-}).$mount('#app')
+  render: (h) => h(App),
+}).$mount("#app");

+ 36 - 36
src/router/index.js

@@ -1,25 +1,35 @@
-import Vue from 'vue'
-import VueRouter from 'vue-router'
-import Home from '../views/home/Index.vue'
+// router/index.js
+import Vue from "vue";
+import VueRouter from "vue-router";
+import Home from "../views/home/Index.vue";
 
-Vue.use(VueRouter)
+Vue.use(VueRouter);
 
 const routes = [
   {
-    path: '/',
-    redirect: '/login'
+    path: "/",
+    redirect: "/login",
   },
   {
-    path: '/home',
-    redirect: '/home/cockpitManage',
-    name: 'home',
+    path: "/home",
+    redirect: "/home/cockpitManage",
+    name: "home",
     component: Home,
     children: [
       // 驾驶舱
       {
-        path: 'cockpitManage',
-        name: 'cockpitManage',
-        component: () => import('../views/admin/cockpitManage/Index.vue')
+        path: "cockpitManage",
+        name: "cockpitManage",
+        component: () => import("../views/admin/cockpitManage/Index.vue"),
+        children: [
+          // 电子地图
+          {
+            path: "electronic-map",
+            name: "electronicMap",
+            component: () =>
+              import("../views/admin/cockpitManage/electronicMap.vue"),
+          },
+        ],
       },
       // 电子地图
       {
@@ -73,32 +83,22 @@ const routes = [
     ]
   },
   {
-    path: '/login',
-    name: 'login',
-    component: () => import('../views/login/Index.vue')
+    path: "/login",
+    name: "login",
+    component: () => import("../views/login/Index.vue"),
   },
-
-  {
-    path: '/:pathMatch(.*)*',
-    component: () => import('@/views/error/404.vue'),
-    meta: { hidden: true }
-  }
-  // {
-  //   path: '*',
-  //   redirect: '/'
-  // }
-]
+];
 
 const router = new VueRouter({
-  mode: 'history',
+  mode: "history",
   base: process.env.BASE_URL,
-  scrollBehavior: () => ({
-    y: 0
-  }),
-  routes
-})
-const originalPush = VueRouter.prototype.push
+  scrollBehavior: () => ({ y: 0 }),
+  routes,
+});
+
+const originalPush = VueRouter.prototype.push;
 VueRouter.prototype.push = function push(location) {
-  return originalPush.call(this, location).catch((err) => err)
-}
-export default router
+  return originalPush.call(this, location).catch((err) => err);
+};
+
+export default router;

+ 66 - 0
src/store/auth.js

@@ -0,0 +1,66 @@
+import { login } from "../api/login";
+import { getAuthRouterFn } from "@/utils/getAuth";
+
+export default {
+  namespaced: true, // 子模块一定要开启命名空间
+  state: {
+    userInfo: {},
+    // routes: [],
+  },
+  getters: {},
+  mutations: {
+    SET_USERINFO(state, payload) {
+      state.userInfo = payload;
+    },
+    // SET_ROUTES(state, routes) {
+    //   state.routes = routes;
+    // },
+  },
+  actions: {
+    async goLogin({ commit, dispatch }, { loginForm, router }) {
+      try {
+        const result = await login(loginForm);
+        commit("SET_USERINFO", result.data);
+        dispatch("setAddRouter", {
+          resultRouter: result.data.permission,
+          router,
+        });
+      } catch (error) {
+        console.error("Login error:", error);
+      }
+    },
+    setAddRouter({ commit }, { resultRouter, router }) {
+      console.log("1111");
+      const { authRouterList } = getAuthRouterFn(resultRouter);
+      // 获取home路由
+      const homeRoute = router.options.routes.find(
+        (route) => route.name === "home"
+      );
+      // 确保home路由存在
+      if (homeRoute) {
+        if (!homeRoute.children) {
+          homeRoute.children = [];
+        }
+        authRouterList.forEach((item) => {
+          // 动态路由的父路径设置为home
+          homeRoute.children.push(item);
+        });
+        // 重新添加home路由
+        router.addRoute(homeRoute);
+      }
+      // 添加404页面路由
+      router.addRoute({
+        path: "/:pathMatch(.*)*",
+        name: "NotFound",
+        component: () => import("@/views/error/404.vue"),
+        meta: { hidden: true },
+      });
+      console.log("router", router.getRoutes());
+      // 持久化存储动态路由
+      // commit("SET_ROUTES", homeRoute.children);
+      // localStorage.setItem("authRoutes", JSON.stringify(homeRoute.children));
+      // 确保导航到动态添加的路由
+      router.push("/home/system/userMag");
+    },
+  },
+};

+ 19 - 9
src/store/index.js

@@ -1,7 +1,10 @@
-import Vuex from 'vuex'
-import Vue from 'vue'
-import breadStore from './breadStore.js' //引入子模块
-Vue.use(Vuex)
+import Vuex from "vuex";
+import Vue from "vue";
+import breadStore from "./breadStore.js"; //引入子模块
+import auth from "./auth.js";
+import createPersistedState from "vuex-persistedstate";
+import settings from "./settings.js";
+Vue.use(Vuex);
 export const store = new Vuex.Store({
   state: {
     // 存放共有store下子模块数据
@@ -11,8 +14,8 @@ export const store = new Vuex.Store({
     // state的计算属性,监听state的变化时对state里的数据进行加工
     //如果其他组件都需要相同的函数,就可以把函数写到这里面
     getterPrice(state) {
-      return (state.price += 100)
-    }
+      return (state.price += 100);
+    },
     //调用this.$store.getters.getterPrice
   },
   mutations: {
@@ -25,6 +28,13 @@ export const store = new Vuex.Store({
   //然后在每一个module中写state, getters, mutations, actions等(注意在子模块中需要开启命名空间)。
   modules: {
     //面包屑模块
-    breadStore
-  }
-})
+    breadStore,
+    auth,
+    settings,
+  },
+  plugins: [
+    createPersistedState({
+      storage: window.sessionStorage, // 或者 localStorage
+    }),
+  ],
+});

+ 35 - 0
src/store/settings.js

@@ -0,0 +1,35 @@
+const storageSetting = JSON.parse(localStorage.getItem("layout-setting")) || "";
+const state = {
+  title: "",
+  theme: storageSetting.theme || "#409EFF",
+  loading: false,
+};
+const mutations = {
+  CHANGE_SETTING: (state, { key, value }) => {
+    if (state.hasOwnProperty(key)) {
+      state[key] = value;
+    }
+  },
+  changeLoading(state, { key, value }) {
+    state.loading = value;
+  },
+};
+
+const actions = {
+  // 修改布局设置
+  changeSetting({ commit }, data) {
+    commit("CHANGE_SETTING", data);
+  },
+
+  // 设置网页标题
+  setTitle({ commit }, title) {
+    state.title = title;
+  },
+};
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 58 - 0
src/utils/getAuth.js

@@ -0,0 +1,58 @@
+/*
+ * @Author: your name
+ * @Date: 2024-05-17 16:09:03
+ * @LastEditTime: 2024-05-18 18:40:13
+ * @LastEditors: bogon
+ * @Description: In User Settings Edit
+ * @FilePath: /performance-test/src/utils/getAuth.js
+ */
+import { orgList } from "@/views/home/components/mockData";
+//返回可动态添加的路由
+export const getAuthRouterFn = (list) => {
+  // 将list 转成一维数组,按钮级别权限拿到 返回为[]格式
+  const { result, anthBtnList } = flattenTree(list);
+  const arr = filterTreeByPermissions(result, orgList);
+  return { authRouterList: arr, anthBtnList };
+};
+
+const flattenTree = (tree) => {
+  let result = [];
+  let anthBtnList = [];
+  const flattenRecursive = (nodes) => {
+    nodes.forEach((node) => {
+      result.push(node);
+      if (node.children && node.children.length > 0) {
+        flattenRecursive(node.children);
+      }
+      if (node.permissionDepth === 2) {
+        anthBtnList.push(node);
+      }
+    });
+  };
+
+  flattenRecursive(tree);
+  return { result, anthBtnList };
+};
+const filterTreeByPermissions = (permissions, tree) => {
+  const permissionSet = new Set(permissions.map((item) => item.permissionName));
+
+  const filterTreeRecursive = (nodes) => {
+    return nodes.reduce((filteredNodes, node) => {
+      const newNode = { ...node };
+
+      if (newNode.children && newNode.children.length > 0) {
+        newNode.children = filterTreeRecursive(newNode.children);
+      }
+      if (
+        permissionSet.has(newNode.name) ||
+        (newNode.children && newNode.children.length > 0)
+      ) {
+        filteredNodes.push(newNode);
+      }
+
+      return filteredNodes;
+    }, []);
+  };
+
+  return filterTreeRecursive(tree);
+};

+ 45 - 44
src/utils/request.js

@@ -1,10 +1,10 @@
-import axios from 'axios'
-import { Message } from 'element-ui'
-console.log(window)
+import axios from "axios";
+import { Message } from "element-ui";
+console.log(window?._BASE_CONFIG?.API, "window?._BASE_CONFIG?.API");
 const service = axios.create({
-  baseURL: window?._BASE_CONFIG?.API || '/api',
-  withCredentials: true
-})
+  baseURL: window?._BASE_CONFIG?.API || "/api",
+  withCredentials: true,
+});
 
 /**
  * 请求拦截器
@@ -12,12 +12,12 @@ const service = axios.create({
  */
 service.interceptors.request.use(
   (config) => {
-    return config
+    return config;
   },
   (error) => {
-    return Promise.reject(error)
+    return Promise.reject(error);
   }
-)
+);
 
 /**
  * 响应拦截器
@@ -26,61 +26,62 @@ service.interceptors.request.use(
  */
 service.interceptors.response.use(
   async (response) => {
-    const { data } = response
+    const { data } = response;
     if (data?.code) {
-      if (data.code !== '0000') {
+      console.log(data?.code, "data?.code");
+      if (data.code !== 200) {
         Message({
-          message: data.msg || 'Error',
-          type: 'error',
-          duration: 5 * 1000
-        })
-        return Promise.reject(new Error(data.msg || 'Error'))
+          message: data.msg || "Error",
+          type: "error",
+          duration: 5 * 1000,
+        });
+        return Promise.reject(new Error(data.msg || "Error"));
       } else {
-        return data
+        return data;
       }
-    } else if (data.type === 'application/octet-stream') {
-      return response
-    } else if (data.type === 'application/json') {
-      const resData = JSON.parse(await data.text())
-      console.log(resData)
+    } else if (data.type === "application/octet-stream") {
+      return response;
+    } else if (data.type === "application/json") {
+      const resData = JSON.parse(await data.text());
+      console.log(resData);
       // 根据后端返回code码进行处理
-      if (resData.code !== '0000') {
+      if (resData.code !== 200) {
         Message({
-          message: resData.msg || 'Error',
-          type: 'error',
-          duration: 5 * 1000
-        })
-        return Promise.reject(new Error(resData.msg || 'Error'))
+          message: resData.msg || "Error",
+          type: "error",
+          duration: 5 * 1000,
+        });
+        return Promise.reject(new Error(resData.msg || "Error"));
       } else {
-        return resData
+        return resData;
       }
     }
   },
   (error) => {
-    const { response } = error
+    const { response } = error;
     if (response?.status === 401) {
-      window.location = response.data
-      return
+      window.location = response.data;
+      return;
     }
     Message({
       message: error.message,
-      type: 'error',
-      duration: 5 * 1000
-    })
-    return Promise.reject(error)
+      type: "error",
+      duration: 5 * 1000,
+    });
+    return Promise.reject(error);
   }
-)
+);
 
 const request = (requestObj) => {
-  const { url, method, data = {}, timeout, params, responseType } = requestObj
+  const { url, method, data = {}, timeout, params, responseType } = requestObj;
   return service({
     url,
-    method: method || 'post',
+    method: method || "post",
     data,
     timeout: timeout || 300000,
-    params: params || (method && method.toLowerCase() === 'get' ? data : {}),
-    responseType: responseType || 'json'
-  })
-}
+    params: params || (method && method.toLowerCase() === "get" ? data : {}),
+    responseType: responseType || "json",
+  });
+};
 
-export default request
+export default request;

+ 0 - 2
src/views/dataAdministration/index.vue

@@ -162,7 +162,5 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.condition {}
 
-.list-page {}
 </style>

+ 140 - 77
src/views/home/components/Menu.vue

@@ -2,61 +2,125 @@
   <el-aside :width="!isCollapse ? '300px' : '100px'" class="asideBox">
     <div class="homeBox">
       <div class="logoItem" :class="{ 'flexCenter ': isCollapse }">
-        <div class="logoImg" v-show="isCollapse" @click="
-          handleChangeMenuUrl(
-            { name: '驾驶舱', id: 1, path: 'cockpitManage', iconName: 'gps' },
-            `/home/cockpitManage?name=驾驶舱`
-          )
-          ">
-          <SvgIcon name="dnao" class="dnao" width="40px" height="40px" color="#222"></SvgIcon>
+        <div
+          class="logoImg"
+          v-show="isCollapse"
+          @click="
+            handleChangeMenuUrl(
+              { name: '驾驶舱', id: 1, path: 'cockpitManage', iconName: 'gps' },
+              `/home/cockpitManage?name=驾驶舱`
+            )
+          "
+        >
+          <SvgIcon
+            name="dnao"
+            class="dnao"
+            width="40px"
+            height="40px"
+            color="#222"
+          ></SvgIcon>
         </div>
-        <span v-if="!isCollapse" @click="
-          handleChangeMenuUrl(
-            { name: '驾驶舱', id: 1, path: 'cockpitManage', iconName: 'gps' },
-            `/home/cockpitManage?name=驾驶舱`
-          )
-          " :class="isCollapse ? 'stop-animation' : 'active-animation'">风机运行管理平台</span>
+        <span
+          v-if="!isCollapse"
+          @click="
+            handleChangeMenuUrl(
+              { name: '驾驶舱', id: 1, path: 'cockpitManage', iconName: 'gps' },
+              `/home/cockpitManage?name=驾驶舱`
+            )
+          "
+          :class="isCollapse ? 'stop-animation' : 'active-animation'"
+          >风机运行管理平台</span
+        >
       </div>
     </div>
-    <el-menu ref="menu" class="mt-3 el-menu-vertical-demo" @open="handleOpen" @select="handleOpen" @close="handleClose"
-      background-color="#eff1f3" text-color="#000" active-text-color="#0754a1" :router="false"
-      :default-active="defaultActive" :unique-opened="true" :collapse="isCollapse">
-      <el-submenu v-for="(item, index) in orgList" :key="index" :index="item.id">
+    <el-menu
+      ref="menu"
+      class="mt-3 el-menu-vertical-demo"
+      @open="handleOpen"
+      @select="handleOpen"
+      @close="handleClose"
+      background-color="#eff1f3"
+      text-color="#000"
+      active-text-color="#0754a1"
+      :router="false"
+      :default-active="defaultActive"
+      :unique-opened="true"
+      :collapse="isCollapse"
+    >
+      <el-submenu
+        v-for="(item, index) in orgList"
+        :key="index"
+        :index="item.id"
+      >
         <template slot="title">
           <div class="flex items-center justify-start">
-            <i class="flex items-center justify-center mr-2" style="margin-left: 3px">
-              <SvgIcon :name="item.iconName" class="dnao" width="20px" height="22px" color="#222"></SvgIcon>
+            <i
+              class="flex items-center justify-center mr-2"
+              style="margin-left: 3px"
+            >
+              <SvgIcon
+                :name="item.iconName"
+                class="dnao"
+                width="20px"
+                height="22px"
+                color="#222"
+              ></SvgIcon>
             </i>
-            <span slot="title" style="display: inline-block" :class="{
-              'active-menu':
-                defaultActive === `/windField?id=${item.id}&name=${item.name}`
-            }">{{ item.name }}</span>
+            <span
+              slot="title"
+              style="display: inline-block"
+              :class="{
+                'active-menu':
+                  defaultActive ===
+                  `/windField?id=${item.id}&name=${item.name}`,
+              }"
+              >{{ item.name }}</span
+            >
           </div>
         </template>
-        <el-menu-item v-for="(child, childIndex) in item.children" :key="childIndex"
-          :index="`/home/${child.path}?id=${child.id}&name=${child.name}`">
+        <el-menu-item
+          v-for="(child, childIndex) in item.children"
+          :key="childIndex"
+          :index="`/home/${item.path}/${child.path}?id=${child.id}&name=${child.name}`"
+        >
           <template slot="title">
-            <span slot="title" style="padding-left: 22px; width: 100%; display: inline-block" :class="{
-              'active-menu':
-                defaultActive === `/dynamo?id=${item.id}&name=${item.name}`
-            }" @click="
+            <span
+              slot="title"
+              style="padding-left: 22px; width: 100%; display: inline-block"
+              :class="{
+                'active-menu':
+                  defaultActive === `/dynamo?id=${item.id}&name=${item.name}`,
+              }"
+              @click="
                 handleChangeMenuUrl(
                   item,
-                  `/home/${child.path}?id=${item.id}&name=${item.name}`
+                  `/home/${item.path}/${child.path}?id=${item.id}&name=${item.name}`
                 )
-                ">{{ child.name }}</span>
+              "
+              >{{ child.name }}</span
+            >
           </template>
         </el-menu-item>
       </el-submenu>
     </el-menu>
     <div class="foldBox flexCenter">
-      <span v-show="isCollapse" class="el-icon-s-unfold icon" @click="isCollapse = false">展开</span>
-      <span v-show="!isCollapse" class="el-icon-s-fold icon" @click="isCollapse = true">收起</span>
+      <span
+        v-show="isCollapse"
+        class="el-icon-s-unfold icon"
+        @click="isCollapse = false"
+        >展开</span
+      >
+      <span
+        v-show="!isCollapse"
+        class="el-icon-s-fold icon"
+        @click="isCollapse = true"
+        >收起</span
+      >
     </div>
   </el-aside>
 </template>
 <script>
-import { orgList } from './mockData'
+import { orgList } from "./mockData";
 
 export default {
   data() {
@@ -66,17 +130,17 @@ export default {
       // 三级菜单数组
       orgList: orgList,
       // 搜索值
-      searchInputValue: '',
-      defaultActive: '',
+      searchInputValue: "",
+      defaultActive: "",
       activeIndex: false,
-      keyObject: {}
-    }
+      keyObject: {},
+    };
   },
 
   computed: {
     currentMenuIndex() {
-      return this.$store.state.breadStore?.currentUrl?.routeUrl
-    }
+      return this.$store.state.breadStore?.currentUrl?.routeUrl;
+    },
   },
 
   watch: {
@@ -84,76 +148,76 @@ export default {
       deep: true,
       handler(newVale, oldVal) {
         if (newVale) {
-          this.$refs.menu.close(newVale)
+          this.$refs.menu.close(newVale);
         }
-      }
+      },
     },
     keyObject: {
       deep: true,
       handler(newVale) {
         if (newVale && newVale.key === this.defaultActive) {
-          this.getBreadcrumbList(newVale.keyPath)
+          this.getBreadcrumbList(newVale.keyPath);
         }
-      }
-    }
+      },
+    },
   },
-  created() { },
+  created() {},
   methods: {
     getBreadcrumbList(keyPath) {
-      const urls = keyPath
+      const urls = keyPath;
       const result = urls.map((url, index) => {
-        const params = new URLSearchParams(url.split('?')[1]) // 解析 URL 参数
-        const id = params.get('id')
-        const name = params.get('name')
-        const routeUrl = url
+        const params = new URLSearchParams(url.split("?")[1]); // 解析 URL 参数
+        const id = params.get("id");
+        const name = params.get("name");
+        const routeUrl = url;
         // 如果是最后一个路由,则添加额外属性
         if (index === urls.length - 1) {
-          return { id, name, routeUrl, currentPage: true }
+          return { id, name, routeUrl, currentPage: true };
         }
-        return { id, name, routeUrl }
-      })
+        return { id, name, routeUrl };
+      });
       // console.log(result)
-      this.$store.commit('breadStore/ADD_BREAD', result)
-      return result
+      this.$store.commit("breadStore/ADD_BREAD", result);
+      return result;
     },
     handleOpen(key, keyPath) {
       // console.log(key, keyPath)
-      this.activeIndex = false
+      this.activeIndex = false;
       this.keyObject = {
         key,
-        keyPath
-      }
+        keyPath,
+      };
     },
     handleClose(key, keyPath) {
       // console.log(key, keyPath)
-      this.activeIndex = false
+      this.activeIndex = false;
       this.keyObject = {
         key,
-        keyPath
-      }
+        keyPath,
+      };
     },
 
     shrinkTree() {
-      this.$refs.menu.close(`/orgsPage?id=${orgList.id}&name=${orgList.name}`)
+      this.$refs.menu.close(`/orgsPage?id=${orgList.id}&name=${orgList.name}`);
     },
     handleChangeRouter() {
-      this.activeIndex = true
-      this.defaultActive = ''
-      this.$store.commit('breadStore/ADD_BREAD', [])
-      this.$refs.menu.close(`/orgsPage?id=${orgList.id}&name=${orgList.name}`)
-      this.$router.push('/')
+      this.activeIndex = true;
+      this.defaultActive = "";
+      this.$store.commit("breadStore/ADD_BREAD", []);
+      this.$refs.menu.close(`/orgsPage?id=${orgList.id}&name=${orgList.name}`);
+      this.$router.push("/");
     },
     handleChangeMenuUrl(item, key) {
-      this.defaultActive = key
+      this.defaultActive = key;
       if (item) {
-        item.activeIndex = true
+        item.activeIndex = true;
       }
       this.$router.push({
-        path: key
-      })
-    }
-  }
-}
+        path: key,
+      });
+    },
+  },
+};
 </script>
 <style lang="scss" scoped>
 .el-menu-vertical-demo:not(.el-menu--collapse) {
@@ -261,8 +325,7 @@ export default {
         }
 
         // background-color: rgb(64, 158, 255, 0.6);
-        transition: width 0.5s ease,
-        transform 0.5s ease;
+        transition: width 0.5s ease, transform 0.5s ease;
         /* 过渡效果 */
         transform-origin: left;
         /* 设置变换的原点在左侧 */

+ 41 - 28
src/views/home/components/mockData.js

@@ -1,35 +1,40 @@
 export const orgList = [
   {
-    name: '驾驶舱',
+    name: "驾驶舱",
     id: "1",
-    path: 'cockpitManage',
-    iconName: 'gps',
+    path: "cockpitManage",
+    iconName: "gps",
+    component: () => import("@/views/admin/cockpitManage/Index.vue"),
     children: [
       {
         id: 11,
-        name: '电子地图',
-        path: 'electronic-map'
-      }
-    ]
+        name: "电子地图",
+        path: "electronic-map",
+        component: () =>
+          import("@/views/admin/cockpitManage/electronicMap.vue"),
+      },
+    ],
   },
   {
-    name: '性能分析',
+    name: "性能分析",
     id: "2",
-    iconName: 'analyse',
+    iconName: "analyse",
+    component: () =>
+      import("@/views/admin/performanceAnalysisManage/Index.vue"),
     children: [
       {
         id: 21,
-        name: '新能分析评估'
+        name: "新能分析评估",
       },
       {
         id: 22,
-        name: '批次管理'
-      }
-    ]
+        name: "批次管理",
+      },
+    ],
   },
   {
-    name: '数据管理',
-    iconName: 'dataManage',
+    name: "数据管理",
+    iconName: "dataManage",
     id: "3",
     children: [
       {
@@ -40,8 +45,8 @@ export const orgList = [
     ]
   },
   {
-    name: '台账管理',
-    iconName: 'Ledger',
+    name: "台账管理",
+    iconName: "Ledger",
     id: "4",
     children: [
       {
@@ -72,25 +77,33 @@ export const orgList = [
     ]
   },
   {
-    name: '权限管理',
-    iconName: 'jurisdiction',
+    name: "权限管理",
+    iconName: "jurisdiction",
     id: "5",
+    path: "system",
+    component: () => import("@/views/system/index.vue"),
     children: [
       {
         id: 51,
-        name: '员工管理'
+        name: "用户管理",
+        path: "userMag",
+        component: () => import("@/views/system/userMag/index.vue"),
       },
       {
         id: 52,
-        name: '角色管理'
+        name: "角色管理",
+        path: "roleMag",
+        component: () => import("@/views/system/roleMag/index.vue"),
       },
       {
         id: 53,
-        name: '菜单管理'
-      }
-    ]
-  }
-]
+        name: "菜单权限",
+        path: "menuMag",
+        component: () => import("@/views/system/menuMag/index.vue"),
+      },
+    ],
+  },
+];
 export default {
-  orgList
-}
+  orgList,
+};

+ 60 - 43
src/views/login/Index.vue

@@ -1,30 +1,43 @@
 <template>
   <div class="background-image">
-
-
     <div class="border">
       <div class="leftLogin">
-
         <h1>风机数据管理平台</h1>
         <el-divider></el-divider>
         <div class="loginText">
-          <el-form :model="loginForm" ref="ruleForm" label-width="0px" :rules="rules" class="demo-ruleForm">
-            <el-form-item prop="email">
-              <el-input placeholder="请输入用户名或账号" v-model="loginForm.email"></el-input>
+          <el-form
+            :model="loginForm"
+            ref="ruleForm"
+            label-width="0px"
+            :rules="rules"
+            class="demo-ruleForm"
+          >
+            <el-form-item prop="userName">
+              <el-input
+                placeholder="请输入用户名或账号"
+                v-model="loginForm.userName"
+              ></el-input>
             </el-form-item>
             <!-- TODO:删除placeholder -->
             <el-form-item prop="password">
-              <el-input type="password" placeholder="请输入密码" v-model="loginForm.password"></el-input>
+              <el-input
+                type="password"
+                placeholder="请输入密码"
+                v-model="loginForm.password"
+              ></el-input>
             </el-form-item>
 
             <el-form-item>
-              <el-button type="primary" class="custom-button" @click="login('ruleForm')">登录</el-button>
+              <el-button
+                type="primary"
+                class="custom-button"
+                @click="login('ruleForm')"
+                >登录</el-button
+              >
             </el-form-item>
           </el-form>
         </div>
-
       </div>
-
     </div>
   </div>
 </template>
@@ -33,61 +46,64 @@
 export default {
   data() {
     var validatePass = (rule, value, callback) => {
-      if (value === '') {
-        callback(new Error('请输入密码'))
+      if (value === "") {
+        callback(new Error("请输入密码"));
       } else {
-        callback()
+        callback();
       }
-    }
+    };
     return {
       loginForm: {
-        email: '',
-        password: ''
+        userName: "",
+        password: "",
       },
       rules: {
-        email: [
-          { required: true, message: '请输入用户名或账号', trigger: 'blur' },
+        userName: [
+          { required: true, message: "请输入用户名或账号", trigger: "blur" },
           {
-            type: '',
-            message: '请输入用户名或账号',
-            trigger: ['blur']
-          }
+            type: "",
+            message: "请输入用户名或账号",
+            trigger: ["blur"],
+          },
         ],
-        password: [{ validator: validatePass, trigger: 'blur' }]
-      }
-    }
+        password: [{ validator: validatePass, trigger: "blur" }],
+      },
+    };
   },
-  created() { },
+  created() {},
   methods: {
     // 登录
     login(formName) {
       // 自带校验
       this.$refs[formName].validate((valid) => {
         if (valid) {
-          this.$router.push('/')
+          this.$store.dispatch("auth/goLogin", {
+            loginForm: this.loginForm,
+            router: this.$router,
+          });
+          // this.$router.push('/')
         } else {
-          console.log('error submit!!')
-          return false
+          console.log("error submit!!");
+          return false;
         }
-      })
+      });
     },
     //   忘记密码
     forgot() {
-      this.$router.push('/forgot')
-    }
-  }
-}
+      this.$router.push("/forgot");
+    },
+  },
+};
 </script>
 
 <style lang="scss" scoped>
 .background-image {
   width: 100vw;
   height: 100vh;
-  background-image: url('../../assets/login-img.png');
+  background-image: url("../../assets/login-img.png");
   background-size: cover;
   background-position: center;
   background-repeat: no-repeat;
-
 }
 
 .border {
@@ -113,29 +129,29 @@ export default {
       line-height: 50px;
       font-size: 26px;
       font-weight: 600;
-      color: #00BAAD;
+      color: #00baad;
       margin-top: 20px;
     }
 
     .el-divider--horizontal {
       margin: 10px 0;
       height: 4px;
-      background: #00BAAD;
+      background: #00baad;
     }
 
     .loginText {
       .custom-button {
         width: 300px;
         margin-bottom: 10px;
-        background-color: #00BAAD;
+        background-color: #00baad;
         color: white;
-        border: 2px solid #00BAAD;
+        border: 2px solid #00baad;
       }
 
       .custom-button:hover {
-        background-color:#00BAAD;
+        background-color: #00baad;
         color: white;
-        border: 2px solid #00BAAD;
+        border: 2px solid #00baad;
       }
     }
 
@@ -201,4 +217,5 @@ export default {
 
 // ::v-deep .el-form-item__error {
 //   left: 150;
-// }</style>
+// }
+</style>

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

@@ -0,0 +1,15 @@
+<!--
+ * @Author: your name
+ * @Date: 2024-05-17 16:02:11
+ * @LastEditTime: 2024-05-19 22:59:28
+ * @LastEditors: bogon
+ * @Description: In User Settings Edit
+ * @FilePath: /dasheng/performance-test/src/views/system/index.vue
+-->
+<template>
+  <div>
+    <router-view />
+  </div>
+</template>
+<script></script>
+<style scoped lang="scss"></style>

+ 93 - 0
src/views/system/menuMag/index.vue

@@ -0,0 +1,93 @@
+<!--
+ * @Author: your name
+ * @Date: 2024-05-17 15:59:21
+ * @LastEditTime: 2024-05-19 22:59:39
+ * @LastEditors: bogon
+ * @Description: In User Settings Edit
+ * @FilePath: /dasheng/performance-test/src/views/system/menuMag/index.vue
+-->
+<template>
+  <div>
+    <el-table :data="tableData" style="width: 100%">
+      <el-table-column label="日期" width="180">
+        <template slot-scope="scope">
+          <i class="el-icon-time"></i>
+          <span style="margin-left: 10px">{{ scope.row.date }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="姓名" width="180">
+        <template slot-scope="scope">
+          <el-popover trigger="hover" placement="top">
+            <p>姓名: {{ scope.row.name }}</p>
+            <p>住址: {{ scope.row.address }}</p>
+            <div slot="reference" class="name-wrapper">
+              <el-tag size="medium">{{ scope.row.name }}</el-tag>
+            </div>
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作">
+        <template slot-scope="scope">
+          <el-button size="mini" @click="handleEdit(scope.$index, scope.row)"
+            >编辑</el-button
+          >
+          <el-button
+            size="mini"
+            type="danger"
+            @click="handleDelete(scope.$index, scope.row)"
+            >删除</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      tableData: [
+        {
+          date: "2016-05-02",
+          name: "王小虎",
+          address: "上海市普陀区金沙江路 1518 弄",
+        },
+        {
+          date: "2016-05-04",
+          name: "王小虎",
+          address: "上海市普陀区金沙江路 1517 弄",
+        },
+        {
+          date: "2016-05-01",
+          name: "王小虎",
+          address: "上海市普陀区金沙江路 1519 弄",
+        },
+        {
+          date: "2016-05-03",
+          name: "王小虎",
+          address: "上海市普陀区金沙江路 1516 弄",
+        },
+      ],
+    };
+  },
+  methods: {
+    handleEdit(index, row) {
+      console.log(index, row);
+    },
+    handleDelete(index, row) {
+      console.log(index, row);
+    },
+  },
+};
+</script>
+<!-- <style lang="scss">
+// .box {
+//   width: 100px;
+//   height: 100px;
+//   background-color: var(--color);
+// }
+.el-table th.el-table__cell {
+  background-color: var(--color);
+  color: aliceblue;
+}
+</style> -->

+ 13 - 0
src/views/system/roleMag/index.vue

@@ -0,0 +1,13 @@
+<!--
+ * @Author: your name
+ * @Date: 2024-05-17 15:58:57
+ * @LastEditTime: 2024-05-17 15:59:09
+ * @LastEditors: bogon
+ * @Description: In User Settings Edit
+ * @FilePath: /dasheng/performance-test/src/views/system/roleMag/index.vue
+-->
+<template>
+  <div>角色管理</div>
+</template>
+<script></script>
+<style lang="scss"></style>

+ 5 - 0
src/views/system/userMag/index.vue

@@ -0,0 +1,5 @@
+<template>
+  <div>用户管理</div>
+</template>
+<script></script>
+<style lang="scss"></style>

+ 34 - 15
vue.config.js

@@ -1,33 +1,52 @@
-const path = require('path')
+const path = require("path");
 
 function resolve(dir) {
-  return path.join(__dirname, dir)
+  return path.join(__dirname, dir);
 }
 
 module.exports = {
   // 解析SVG组件
   chainWebpack(config) {
-    config.module.rule('svg').exclude.add(resolve('src/icons')).end()
+    config.module.rule("svg").exclude.add(resolve("src/icons")).end();
     config.module
-      .rule('icons')
+      .rule("icons")
       .test(/\.svg$/)
-      .include.add(resolve('src/icons'))
+      .include.add(resolve("src/icons"))
       .end()
-      .use('svg-sprite-loader')
-      .loader('svg-sprite-loader')
+      .use("svg-sprite-loader")
+      .loader("svg-sprite-loader")
       .options({
-        symbolId: 'icon-[name]'
+        symbolId: "icon-[name]",
       })
-      .end()
+      .end();
   },
   //vue.config.js
   css: {
     loaderOptions: {
       postcss: {
         postcssOptions: {
-          plugins: [require('tailwindcss'), require('autoprefixer')]
-        }
-      }
-    }
-  }
-}
+          plugins: [require("tailwindcss"), require("autoprefixer")],
+        },
+      },
+    },
+  },
+  devServer: {
+    proxy: {
+      "/api": {
+        target: "http://192.168.50.235:16200", //内网
+        // target: "http://106.120.102.238:16600",//外网
+        changeOrigin: true,
+        pathRewrite: {
+          "^/api": "", //需要rewrite重写的,
+        },
+      },
+    },
+  },
+  configureWebpack: {
+    resolve: {
+      alias: {
+        "@": resolve("src"),
+      },
+    },
+  },
+};

Деякі файли не було показано, через те що забагато файлів було змінено