liujiejie преди 1 година
родител
ревизия
48c062a624

+ 25 - 21
src/App.vue

@@ -1,34 +1,19 @@
 <template>
-  <div id="app" :style="{ '--color': defaultTheme }" v-loading="defaultLoading">
-    <theme-picker v-show="false" />
-
+  <div id="app" v-loading="defaultLoading">
+    <!-- <transition name="fade" mode="out-in"> -->
     <router-view />
+    <!-- </transition> -->
   </div>
 </template>
 <script>
-import ThemePicker from "@/components/ThemePicker";
 import { login } from "@/api/login";
 import { testApi } from "@/api/test";
-import "@/assets/style/index.css";
+// import "@/assets/style/index.css";
+
 export default {
   created() {},
-  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;
     },
@@ -60,9 +45,28 @@ body {
   width: 100%;
   height: 100%;
 }
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.5s ease;
+}
+
+.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
+  opacity: 0;
+}
 </style>
 <style scoped>
 #app .theme-picker {
   display: none;
 }
 </style>
+<style>
+::v-deep .el-color-dropdown .el-color-dropdown__main-wrapper {
+  display: none !important;
+}
+.el-color-svpanel {
+  display: none !important;
+}
+.el-color-hue-slider {
+  display: none !important;
+}
+</style>

+ 55 - 15
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">
@@ -23,7 +28,26 @@
           <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" />
+            <el-select
+              v-model="currentTheme"
+              placeholder="Select theme"
+              @change="changeTheme"
+              size="mini"
+            >
+              <el-option
+                v-for="item in colorData"
+                :label="item.lable"
+                :value="item.value"
+              >
+                <span style="float: left">{{ item.lable }}</span>
+                <el-color-picker
+                  v-model="item.color"
+                  size="mini"
+                  style="float: right"
+                >
+                </el-color-picker>
+              </el-option>
+            </el-select>
           </div>
           <el-divider></el-divider>
           <div class="cursor-pointer boxmini" @click="skip(1)">
@@ -37,28 +61,38 @@
 
 <script>
 import { userLogout } from "@/api/system";
-import ThemePicker from "@/components/ThemePicker";
 export default {
   data() {
     return {
       currentDate: "",
+      currentTheme: this.$store.state.themes.theme,
+      colorData: [
+        { lable: "Light", value: "light", color: "#f90" },
+        { lable: "Dark", value: "dark", color: "#1f2d3d" },
+        { lable: "Green", value: "green", color: "#008080" },
+        { lable: "Blue", value: "blue", color: "#409eff" },
+      ],
     };
   },
-  components: {
-    ThemePicker,
+  components: {},
+  watch: {
+    "$store.state.themes.theme": {
+      handler(newTheme) {
+        console.log(newTheme, "newTheme");
+        this.currentTheme = newTheme;
+      },
+      immediate: true,
+    },
   },
+
   mounted() {
     this.updateCurrentDateTime();
     setInterval(this.updateCurrentDateTime, 1000);
   },
 
   methods: {
-    themeChange(val) {
-      this.$store.dispatch("settings/changeSetting", {
-        key: "theme",
-        value: val,
-      });
-      this.theme = val;
+    changeTheme(theme) {
+      this.$store.dispatch("switchTheme", theme);
     },
     updateCurrentDateTime() {
       const now = new Date();
@@ -73,12 +107,17 @@ export default {
       this.currentDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
     },
     skip() {
+      this.$emit("setLoding", true);
       userLogout({
         phone: this.$store.state.auth.userInfo.userInfo.userPhone,
-      }).then((res) => {
-        this.$store.commit("auth/RESET_USER_STATE");
-        this.$router.push("/login");
-      });
+      })
+        .then((res) => {
+          this.$store.commit("auth/RESET_USER_STATE");
+          this.$router.push("/login");
+        })
+        .catch(() => {
+          this.$emit("setLoding", false);
+        });
     },
   },
 };
@@ -138,6 +177,7 @@ export default {
   p {
     font-size: 14px;
     font-weight: 600;
+    width: 120px !important;
   }
 
   .logout {

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

@@ -1,16 +0,0 @@
-/*
- * @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 };

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

@@ -1,217 +0,0 @@
-<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;
-    },
-
-    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>

+ 19 - 1
src/main.js

@@ -2,7 +2,7 @@ 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";
+// import "./assets/style/element-variables.module.scss";
 import "./icons/index"; // icon
 // 引入element ui
 import ElementUI from "element-ui";
@@ -32,5 +32,23 @@ if (store.state.auth.userInfo.permission !== undefined) {
 new Vue({
   router,
   store,
+  mounted() {
+    this.applyTheme();
+  },
+  watch: {
+    "$store.state.themes.theme": {
+      handler(newTheme) {
+        console.log(newTheme, "newTheme");
+        this.applyTheme(newTheme);
+      },
+      immediate: true,
+    },
+  },
+  methods: {
+    applyTheme(theme) {
+      const themeFile = theme || this.$store.state.themes.theme;
+      import(`./themes/${themeFile}.scss`);
+    },
+  },
   render: (h) => h(App),
 }).$mount("#app");

+ 2 - 0
src/store/index.js

@@ -4,6 +4,7 @@ import breadStore from "./breadStore.js"; //引入子模块
 import auth from "./auth.js";
 import createPersistedState from "vuex-persistedstate";
 import settings from "./settings.js";
+import themes from "./themes.js";
 Vue.use(Vuex);
 export const store = new Vuex.Store({
   state: {
@@ -31,6 +32,7 @@ export const store = new Vuex.Store({
     breadStore,
     auth,
     settings,
+    themes,
   },
   plugins: [
     createPersistedState({

+ 24 - 0
src/store/themes.js

@@ -0,0 +1,24 @@
+/*
+ * @Author: your name
+ * @Date: 2024-05-27 15:09:27
+ * @LastEditTime: 2024-05-27 15:09:54
+ * @LastEditors: bogon
+ * @Description: In User Settings Edit
+ * @FilePath: /performance-test/src/store/themes.js
+ */
+export default {
+  state: {
+    theme: localStorage.getItem("theme") || "light",
+  },
+  mutations: {
+    setTheme(state, theme) {
+      state.theme = theme;
+      localStorage.setItem("theme", theme);
+    },
+  },
+  actions: {
+    switchTheme({ commit }, theme) {
+      commit("setTheme", theme);
+    },
+  },
+};

+ 32 - 0
src/styles/global.scss

@@ -0,0 +1,32 @@
+.el-button--primary {
+  background-color: var(--primary-color);
+  border-color: var(--primary-color);
+  color: var(--text-color) !important;
+}
+.el-button--text {
+  color: var(--primary-color);
+}
+
+.el-menu {
+  background-color: var(--background-color);
+  color: var(--text-color);
+}
+
+.el-table th.el-table__cell {
+  background-color: var(--background-color) !important;
+  color: var(--text-color);
+}
+.el-pager li.active {
+  color: var(--primary-color);
+}
+
+.el-tag {
+  background-color: var(--primary-color);
+  border-color: var(--primary-color);
+  color: var(--text-color);
+}
+.el-switch {
+  background-color: var(--primary-color);
+  border-color: var(--primary-color);
+  color: var(--text-color);
+}

+ 9 - 0
src/themes/blue.scss

@@ -0,0 +1,9 @@
+$primary-color: #409eff;
+$background-color: #ffffff;
+$text-color: #ffffff;
+
+:root {
+  --primary-color: #{$primary-color};
+  --background-color: #{$background-color};
+  --text-color: #{$text-color};
+}

+ 9 - 0
src/themes/dark.scss

@@ -0,0 +1,9 @@
+$primary-color: #1f2d3d;
+$background-color: #2e2e2e;
+$text-color: #ffffff;
+
+:root {
+  --primary-color: #{$primary-color};
+  --background-color: #{$background-color};
+  --text-color: #{$text-color};
+}

+ 9 - 0
src/themes/green.scss

@@ -0,0 +1,9 @@
+$primary-color: #008080;
+$background-color: #ffffff;
+$text-color: #ffffff;
+
+:root {
+  --primary-color: #{$primary-color};
+  --background-color: #{$background-color};
+  --text-color: #{$text-color};
+}

+ 9 - 0
src/themes/light.scss

@@ -0,0 +1,9 @@
+$primary-color: #f90;
+$background-color: #f90;
+$text-color: #ffffff;
+
+:root {
+  --primary-color: #{$primary-color};
+  --background-color: #{$background-color};
+  --text-color: #{$text-color};
+}

+ 32 - 9
src/views/home/Index.vue

@@ -1,12 +1,14 @@
 <template>
-  <div class="homeWrap">
+  <div class="homeWrap" v-loading="loading">
     <el-container>
       <Menu></Menu>
       <el-main>
-        <HeaderCom />
+        <HeaderCom @setLoding="setLoding" />
         <!-- 主体内容-->
         <div class="">
-          <router-view />
+          <transition name="slide-fade">
+            <router-view />
+          </transition>
         </div>
       </el-main>
     </el-container>
@@ -14,21 +16,28 @@
 </template>
 
 <script>
-import HeaderCom from '@/components/HeaderCom.vue'
-import Menu from './components/Menu'
+import HeaderCom from "@/components/HeaderCom.vue";
+import Menu from "./components/Menu";
 
 export default {
   components: {
     Menu,
-    HeaderCom
+    HeaderCom,
   },
   data() {
-    return {}
+    return {
+      loading: false,
+    };
   },
   mounted() {},
   created() {},
-  methods: {}
-}
+  methods: {
+    setLoding(state) {
+      console.log(state);
+      this.loading = state;
+    },
+  },
+};
 </script>
 
 <style lang="scss" scoped>
@@ -43,4 +52,18 @@ export default {
     padding: 0;
   }
 }
+
+.slide-fade-enter-active {
+  transition: all 0.3s ease-out;
+}
+
+.slide-fade-leave-active {
+  transition: all 0.5s cubic-bezier(1, 0.5, 0.6, 1);
+}
+
+.slide-fade-enter-from,
+.slide-fade-leave-to {
+  transform: translateX(50px);
+  opacity: 0;
+}
 </style>

+ 6 - 0
src/views/home/components/Menu.vue

@@ -86,12 +86,18 @@ export default {
           path: "cockpitManage",
           name: "驾驶舱",
           iconName: "gps",
+          meta: {
+            hidden: false,
+          },
           children: [
             {
               id:11,
               iconName: "gps",
               path: "electronic-map",
               name: "电子地图",
+              meta: {
+                hidden: false,
+              },
             },
           ],
         },

+ 14 - 5
src/views/login/Index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="background-image">
+  <div class="background-image" v-loading="loadingView">
     <div class="border">
       <div class="leftLogin">
         <h1>风机数据管理平台</h1>
@@ -58,6 +58,7 @@ export default {
         userName: "",
         password: "",
       },
+      loadingView: false,
       rules: {
         userName: [
           { required: true, message: "请输入用户名或账号", trigger: "blur" },
@@ -75,15 +76,23 @@ export default {
   methods: {
     // 登录
     login(formName) {
+      this.loadingView = true;
       // 自带校验
       this.$refs[formName].validate((valid) => {
         if (valid) {
-          this.$store.dispatch("auth/goLogin", {
-            loginForm: this.loginForm,
-            router: this.$router,
-          });
+          try {
+            this.$store.dispatch("auth/goLogin", {
+              loginForm: this.loginForm,
+              router: this.$router,
+            });
+          } catch (error) {
+            this.loadingView = false;
+            console.log("error submit!!");
+          }
+
           // this.$router.push('/')
         } else {
+          this.loadingView = false;
           console.log("error submit!!");
           return false;
         }

+ 536 - 4
src/views/performance/batchMag.vue

@@ -1,13 +1,545 @@
 <!--
  * @Author: your name
  * @Date: 2024-05-27 09:23:37
- * @LastEditTime: 2024-05-27 09:29:56
+ * @LastEditTime: 2024-05-27 10:34:49
  * @LastEditors: bogon
  * @Description: In User Settings Edit
  * @FilePath: /performance-test/src/views/performance/batchMag.vue
 -->
 <template>
-  <div>性能批次管理</div>
+  <div class="global-variable">
+    <div class="condition">
+      <el-form
+        :inline="true"
+        ref="ruleForm"
+        :model="formInline"
+        class="demo-form-inline"
+        :rules="rules"
+      >
+        <el-form-item label="风场名称:" prop="userName">
+          <el-input
+            size="small"
+            v-model="formInline.userName"
+            placeholder="请输入风场名称"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="角色名称:" prop="roleId">
+          <el-select
+            v-model="formInline.roleId"
+            placeholder="请选择角色"
+            size="small"
+          >
+            <el-option
+              :label="item.roleDescription"
+              v-for="item in roleList"
+              :value="item.id + ''"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="onSubmit" size="small"
+            >查询</el-button
+          >
+          <el-button @click="reset('ruleForm')" size="small">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+    <div class="list-page">
+      <div class="newly">
+        <el-button type="primary" @click="newnuedialog" size="small"
+          >新增</el-button
+        >
+      </div>
+      <el-table
+        v-loading="loading"
+        class="center-align-table"
+        :data="tableData"
+        border
+        :cell-style="rowStyle"
+      >
+        <el-table-column
+          align="center"
+          fixed
+          prop="userId"
+          label="员工ID"
+          width="100"
+        >
+        </el-table-column>
+
+        <el-table-column align="center" label="批次编号" prop="userName">
+        </el-table-column>
+
+        <el-table-column prop="loginName" align="center" label="关联风场">
+        </el-table-column>
+
+        <el-table-column prop="state" align="center" label="状态" width="100">
+          <template slot-scope="scope">
+            <span>
+              {{
+                scope.row.state == 0
+                  ? "未启用"
+                  : scope.row.state == 1
+                  ? "启用"
+                  : "禁用"
+              }}</span
+            >
+          </template>
+        </el-table-column>
+        <el-table-column prop="roleName" align="center" label="创建时间">
+        </el-table-column>
+        <el-table-column
+          prop="transition"
+          align="center"
+          fixed="right"
+          label="操作"
+          width="200"
+        >
+          <template slot-scope="scope">
+            <el-button @click="compile(scope.row)" type="text" size="small"
+              >编辑</el-button
+            >
+            <el-button
+              v-if="scope.row.state == 0 || scope.row.state == 2"
+              @click="setState(1, scope.row.userId)"
+              type="text"
+              size="small"
+              >启用</el-button
+            >
+            <el-button
+              v-else
+              style="color: #666"
+              @click="setState(2, scope.row.userId)"
+              type="text"
+              size="small"
+              >停用</el-button
+            >
+
+            <el-button
+              style="color: #f00"
+              @click="deleted(scope.row)"
+              type="text"
+              size="small"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="pagination-container">
+        <el-pagination
+          @current-change="handleCurrentChange"
+          :current-page.sync="formInline.pageNum"
+          layout="total, prev, pager, next"
+          :page-size="formInline.pageSize"
+          :total="formInline.totalSize"
+        >
+        </el-pagination>
+      </div>
+    </div>
+
+    <!-- 弹出层 -->
+    <!-- 新增 /编辑-->
+    <el-dialog :title="title" :visible.sync="nuedialog" width="500px">
+      <div v-loading="loadingView" class="views">
+        <el-form
+          :model="ruleForm"
+          :rules="addUserRules"
+          ref="addUserForm"
+          label-width="100px"
+          class="demo-ruleForm"
+        >
+          <el-form-item label="员工名称" prop="userName">
+            <el-input
+              v-model="ruleForm.userName"
+              placeholder="请输入员工名称"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="电话号码" prop="phone">
+            <el-input
+              v-model="ruleForm.phone"
+              placeholder="请输入电话号码"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="账号名称" prop="loginName">
+            <el-input
+              v-model="ruleForm.loginName"
+              placeholder="请输入账号名称"
+              autocomplete="off"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="密码" prop="pwd" v-if="title === '新增'">
+            <el-input
+              v-model="ruleForm.pwd"
+              autocomplete="new-password"
+              show-password
+              placeholder="请输入密码"
+            ></el-input>
+          </el-form-item>
+          <el-form-item label="角色名称:" prop="roleId">
+            <el-select
+              v-model="ruleForm.roleId"
+              placeholder="请选择角色"
+              style="width: 100%"
+            >
+              <el-option
+                :label="item.roleDescription"
+                v-for="item in roleList"
+                :value="item.id + ''"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+        </el-form>
+        <span slot="footer" class="dialog-footer">
+          <el-button @click="cancel('addUserForm')" size="small"
+            >取 消</el-button
+          >
+          <el-button
+            type="primary"
+            @click="submitForm('addUserForm')"
+            size="small"
+            >确 定</el-button
+          >
+        </span>
+      </div>
+    </el-dialog>
+  </div>
 </template>
-<script></script>
-<style scoped lang="scss"></style>
+
+<script>
+import {
+  getUserTableList,
+  getRoleTableList,
+  enableUser,
+  disableUser,
+  getUserInfoByUserId,
+  addUser,
+  editUser,
+  deleteUserInfo,
+  updatePWD,
+} from "@/api/system.js";
+export default {
+  data() {
+    const validateUserName = (rule, value, callback) => {
+      const regex = /^[^\u4e00-\u9fa5\W]+$/;
+      if (!value) {
+        callback(new Error("账号名称不能为空"));
+      } else if (!regex.test(value)) {
+        callback(new Error("账号名称不能包含中文及特殊字符"));
+      } else {
+        callback();
+      }
+    };
+    const validatePhone = (rule, value, callback) => {
+      const phoneRegex = /^[1][3-9][0-9]{9}$/;
+      if (!value) {
+        return callback(new Error("手机号不能为空"));
+      }
+      if (!phoneRegex.test(value)) {
+        return callback(new Error("请输入正确的手机号"));
+      }
+      callback();
+    };
+    return {
+      loadingView: false,
+      loading: false, //数据加载中
+      rules: {
+        roleId: { trigger: "change" },
+        userName: { trigger: "blur" },
+      },
+      roleList: [],
+      formInline: {
+        userName: undefined,
+        roleId: undefined,
+        pageNum: 1,
+        pageSize: 10,
+        // sort: "desc",
+        totalSize: 0,
+      },
+      tableData: [],
+      // 新增编辑表单
+      ruleForm: {
+        phone: null,
+        pwd: null,
+        roleId: null,
+        userName: null,
+        loginName: null,
+      },
+      addUserRules: {
+        phone: [
+          { required: true, message: "请输入手机号", trigger: "blur" },
+          { validator: validatePhone, trigger: "blur" },
+        ],
+        loginName: [
+          { required: true, message: "请输入账号名称", trigger: "blur" },
+          { validator: validateUserName, trigger: "blur" },
+        ],
+        pwd: { required: true, message: "请输入密码", trigger: "blur" },
+        roleId: { required: true, message: "请选择角色", trigger: "change" },
+        userName: [
+          { required: true, message: "请输入员工姓名", trigger: "blur" },
+        ],
+      },
+      //修改密码
+      editUserPassword: {
+        oldPWD: "",
+        newPWD: "",
+        userId: "",
+      },
+      nuedialog: false,
+      title: "",
+    };
+  },
+  created() {
+    this.getTableList();
+    this.getRoleList();
+  },
+
+  methods: {
+    //分页数据切换
+    handleCurrentChange(val) {
+      this.formInline.pageNum = val;
+      this.getTableList();
+    },
+    //修改状态
+    setState(state, userId) {
+      switch (state) {
+        case 1:
+          //启用接口
+          enableUser({ userId })
+            .then((res) => {
+              this.$message({
+                message: res.msg,
+                type: "success",
+              });
+              this.getTableList();
+            })
+            .catch((error) => {});
+          break;
+        case 2:
+          //禁用接口
+          disableUser({ userId })
+            .then((res) => {
+              this.$message({
+                message: res.msg,
+                type: "success",
+              });
+              this.getTableList();
+            })
+            .catch((error) => {});
+          break;
+        default:
+          return;
+      }
+    },
+    async getTableList() {
+      try {
+        this.loading = true;
+        const result = await getUserTableList({
+          ...this.formInline,
+          totalSize: undefined,
+        });
+        this.tableData = result.data.list;
+        this.formInline.totalSize = result.data.totalSize;
+        this.loading = false;
+      } catch (error) {
+        this.$message({
+          type: "error",
+          message: "请检查是否连接网络",
+        });
+      }
+    },
+    async getRoleList() {
+      try {
+        const result = await getRoleTableList({ pageNum: 1, pageSize: 100000 });
+        this.roleList = result.data.list;
+      } catch (error) {
+        this.$message({
+          type: "error",
+          message: "请检查是否连接网络",
+        });
+      }
+    },
+    rowStyle() {
+      return "text-align:center";
+    },
+    // 查询
+    onSubmit() {
+      this.getTableList();
+    },
+    // 重置
+    reset(formName) {
+      this.$refs[formName].resetFields();
+      this.getTableList();
+    },
+
+    // 新增,编辑确定
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          this.loadingView = true;
+          switch (this.title) {
+            case "新增":
+              addUser({ ...this.ruleForm, userId: undefined })
+                .then((res) => {
+                  this.$message({
+                    type: "success",
+                    message: res.msg,
+                  });
+                  this.getTableList();
+                  this.nuedialog = false;
+                  this.loadingView = false;
+                })
+                .catch(() => {
+                  this.loadingView = false;
+                });
+
+              break;
+            case "编辑":
+              editUser({ ...this.ruleForm })
+                .then((res) => {
+                  this.$message({
+                    type: "success",
+                    message: res.msg,
+                  });
+                  this.getTableList();
+                  this.nuedialog = false;
+                  this.loadingView = false;
+                })
+                .catch(() => {
+                  this.loadingView = false;
+                });
+
+              break;
+          }
+          // this.nuedialog = false;
+        } else {
+          return false;
+        }
+      });
+    },
+    //点击取消
+    cancel(formName) {
+      this.$refs[formName] && this.$refs[formName].resetFields();
+      this.ruleForm = {
+        phone: null,
+        pwd: null,
+        roleId: null,
+        userName: null,
+        userId: null,
+        loginName: null,
+      };
+      this.nuedialog = false;
+      this.loadingView = false;
+    },
+    // 编辑 回显数据
+    async compile(row) {
+      try {
+        const result = await getUserInfoByUserId({ userId: row.userId });
+        const userInfo = result.data;
+        // 直接替换整个对象,以确保 Vue 的响应式系统能够检测到变化
+        this.ruleForm = {
+          phone: userInfo.userPhone,
+          pwd: undefined, // 如果需要重置密码字段
+          roleId: userInfo.roleId.toString(),
+          userName: userInfo.userName,
+          userId: userInfo.userId, // 如果需要用户ID
+          loginName: userInfo.loginName,
+        };
+        this.nuedialog = true;
+        this.title = "编辑";
+      } catch (error) {
+        this.$message.error("获取用户信息失败");
+      }
+    },
+    // 删除
+    deleted(row) {
+      this.$confirm("此操作将永久删除该用户, 是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          deleteUserInfo({ userId: row.userId })
+            .then((res) => {
+              this.$message({
+                type: "success",
+                message: "删除成功!",
+              });
+              this.getTableList();
+            })
+            .catch(() => {});
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+    // 新增
+    newnuedialog() {
+      this.cancel("addUserForm");
+      this.ruleForm = {
+        loginName: "",
+        pwd: "",
+        userName: "",
+      };
+      this.nuedialog = true;
+      this.title = "新增";
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.general {
+  display: flex;
+  flex-wrap: wrap;
+
+  .condition {
+    width: 50%;
+    display: flex;
+
+    p {
+      width: 100px;
+      text-align: right;
+      line-height: 40px;
+    }
+
+    span {
+      line-height: 40px;
+
+      padding-left: 20px;
+    }
+
+    .el-select {
+      width: 100%;
+      margin-bottom: 20px;
+    }
+
+    .el-input {
+      margin-bottom: 20px;
+    }
+  }
+}
+
+.attachment {
+  display: flex;
+  padding-top: 10px;
+
+  p {
+    margin-right: 20px;
+    color: #409eff;
+  }
+}
+
+.addition {
+  display: flex;
+  justify-content: flex-end;
+  margin-bottom: 10px;
+}
+.demo-ruleForm {
+  .el-form-item {
+    margin-bottom: 25px;
+  }
+}
+</style>

+ 19 - 3
src/views/system/index.vue

@@ -1,15 +1,31 @@
 <!--
  * @Author: your name
  * @Date: 2024-05-17 16:02:11
- * @LastEditTime: 2024-05-19 22:59:28
+ * @LastEditTime: 2024-05-27 14:53:07
  * @LastEditors: bogon
  * @Description: In User Settings Edit
  * @FilePath: /dasheng/performance-test/src/views/system/index.vue
 -->
 <template>
   <div>
-    <router-view />
+    <transition name="slide-fade">
+      <router-view />
+    </transition>
   </div>
 </template>
 <script></script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.slide-fade-enter-active {
+  transition: all 0.3s ease-out;
+}
+
+.slide-fade-leave-active {
+  transition: all 0.5s cubic-bezier(1, 0.5, 0.6, 1);
+}
+
+.slide-fade-enter-from,
+.slide-fade-leave-to {
+  transform: translateX(50px);
+  opacity: 0;
+}
+</style>

+ 5 - 0
vue.config.js

@@ -51,6 +51,11 @@ module.exports = {
           plugins: [require("tailwindcss"), require("autoprefixer")],
         },
       },
+      sass: {
+        additionalData: `
+          @import "@/styles/global.scss";
+        `,
+      },
     },
   },
   devServer: {