Browse Source

conflict merge

zhangjie 4 years ago
parent
commit
0f1e784c8f

+ 1 - 0
package.json

@@ -26,6 +26,7 @@
     "js-cookie": "^2.2.1",
     "lodash-es": "^4.17.15",
     "moment": "^2.27.0",
+    "query-string": "^6.13.1",
     "register-service-worker": "^1.7.1",
     "vue": "^2.6.11",
     "vue-awesome": "^4.1.0",

+ 10 - 0
src/api/login.js

@@ -1,4 +1,5 @@
 import { httpApp } from "@/plugins/axiosIndex";
+import { object2QueryString } from "@/utils/utils";
 
 const CryptoJS = require("crypto-js");
 
@@ -39,3 +40,12 @@ export function logout() {
     url: "/login/logout",
   });
 }
+
+export function getLogo(code) {
+  return httpApp.post(
+    "/api/admin/sys/org/queryByOrgCode?" +
+      object2QueryString({
+        code,
+      })
+  );
+}

+ 17 - 0
src/api/system-org.js

@@ -0,0 +1,17 @@
+import { httpApp } from "@/plugins/axiosIndex";
+import { pickBy } from "lodash-es";
+import { object2QueryString } from "@/utils/utils";
+
+export function searchOrgs({
+  code = "",
+  name = "",
+  enable = "",
+  pageNumber = 1,
+  pageSize = 10,
+}) {
+  const data = pickBy(
+    { code, name, enable, pageNumber, pageSize },
+    (v) => v !== ""
+  );
+  return httpApp.post("/api/admin/org/query?" + object2QueryString(data));
+}

+ 41 - 0
src/api/system-user.js

@@ -0,0 +1,41 @@
+import { httpApp } from "@/plugins/axiosIndex";
+import { pickBy } from "lodash-es";
+import { object2QueryString } from "@/utils/utils";
+
+export function searchUsers({
+  role,
+  loginName = "",
+  name = "",
+  enable = "",
+  pageNumber = 1,
+  pageSize = 10,
+}) {
+  const data = pickBy(
+    { role, loginName, name, enable, pageNumber, pageSize },
+    (v) => v !== ""
+  );
+  return httpApp.post("/api/admin/user/query?" + object2QueryString(data));
+}
+
+export function saveUser({
+  roles,
+  loginName = "",
+  name = "",
+  enable = "",
+  password = "",
+  mobileNumber = "",
+}) {
+  const data = pickBy(
+    { roles, loginName, name, enable, password, mobileNumber },
+    (v) => v !== ""
+  );
+  return httpApp.post("/api/admin/user/save", data);
+}
+
+export function toggleEnableUser({ id, enable }) {
+  return httpApp.post("/api/admin/user/enable", { id, enable });
+}
+
+export function resetUserPassword({ id, password }) {
+  return httpApp.post("/api/admin/user/updatePwd", { id, password });
+}

+ 0 - 146
src/components/HelloWorld.vue

@@ -1,146 +0,0 @@
-<template>
-  <div class="hello">
-    <h1>{{ msg }}</h1>
-    <p>
-      For a guide and recipes on how to configure / customize this project,<br />
-      check out the
-      <a href="https://cli.vuejs.org" target="_blank" rel="noopener"
-        >vue-cli documentation</a
-      >.
-    </p>
-    <h3>Installed CLI Plugins</h3>
-    <ul>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
-          target="_blank"
-          rel="noopener"
-          >babel</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa"
-          target="_blank"
-          rel="noopener"
-          >pwa</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
-          target="_blank"
-          rel="noopener"
-          >eslint</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-unit-jest"
-          target="_blank"
-          rel="noopener"
-          >unit-jest</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router"
-          target="_blank"
-          rel="noopener"
-          >router</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex"
-          target="_blank"
-          rel="noopener"
-          >vuex</a
-        >
-      </li>
-    </ul>
-    <h3>Essential Links</h3>
-    <ul>
-      <li>
-        <a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
-      </li>
-      <li>
-        <a href="https://forum.vuejs.org" target="_blank" rel="noopener"
-          >Forum</a
-        >
-      </li>
-      <li>
-        <a href="https://chat.vuejs.org" target="_blank" rel="noopener"
-          >Community Chat</a
-        >
-      </li>
-      <li>
-        <a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
-          >Twitter</a
-        >
-      </li>
-      <li>
-        <a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
-      </li>
-    </ul>
-    <h3>Ecosystem</h3>
-    <ul>
-      <li>
-        <a href="https://router.vuejs.org" target="_blank" rel="noopener"
-          >vue-router</a
-        >
-      </li>
-      <li>
-        <a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-devtools#vue-devtools"
-          target="_blank"
-          rel="noopener"
-          >vue-devtools</a
-        >
-      </li>
-      <li>
-        <a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
-          >vue-loader</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/awesome-vue"
-          target="_blank"
-          rel="noopener"
-          >awesome-vue</a
-        >
-      </li>
-    </ul>
-  </div>
-</template>
-
-<script>
-export default {
-  name: "HelloWorld",
-  props: {
-    msg: String,
-  },
-};
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="scss">
-h3 {
-  margin: 40px 0 0;
-}
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-li {
-  display: inline-block;
-  margin: 0 10px;
-}
-a {
-  color: #42b983;
-}
-</style>

+ 56 - 0
src/components/RoleSelect.vue

@@ -0,0 +1,56 @@
+<template>
+  <el-select
+    v-model="selected"
+    class="size-select"
+    placeholder="请选择"
+    @change="select"
+    style="width: 100px;"
+    :multiple="multiple"
+  >
+    <el-option
+      v-for="item in optionList"
+      :key="item.roleCode"
+      :label="item.roleName"
+      :value="item.roleCode"
+    >
+      <span>{{ item.roleName }}</span>
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+export default {
+  name: "RoleSelect",
+  props: {
+    value: [String, Array],
+    multiple: Boolean,
+  },
+  data() {
+    return {
+      optionList: [],
+      selected: "",
+    };
+  },
+  async created() {
+    const res = await this.$http.post("/api/admin/sys/role/query");
+    // console.log(res.data);
+    this.optionList = res.data.data.records;
+  },
+  watch: {
+    value: {
+      immediate: true,
+      handler(val) {
+        this.selected = val;
+      },
+    },
+  },
+  methods: {
+    select() {
+      this.$emit("input", this.selected);
+      this.$emit("change", this.selected);
+    },
+  },
+};
+</script>
+
+<style></style>

+ 56 - 0
src/components/StateSelect.vue

@@ -0,0 +1,56 @@
+<template>
+  <el-select
+    v-model="selected"
+    class="size-select"
+    placeholder="请选择"
+    @change="select"
+    style="width: 100px;"
+  >
+    <el-option
+      v-for="item in optionList"
+      :key="item.code"
+      :label="item.name"
+      :value="item.code"
+    >
+      <span>{{ item.name }}</span>
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+export default {
+  name: "StateSelect",
+  props: {
+    value: {
+      type: String,
+      default: "",
+    },
+  },
+  data() {
+    return {
+      optionList: [
+        { code: "0", name: "禁用" },
+        { code: "1", name: "启用" },
+      ],
+      selected: "",
+    };
+  },
+  async created() {},
+  watch: {
+    value: {
+      immediate: true,
+      handler(val) {
+        this.selected = val;
+      },
+    },
+  },
+  methods: {
+    select() {
+      this.$emit("input", this.selected);
+      this.$emit("change", this.selected);
+    },
+  },
+};
+</script>
+
+<style></style>

+ 3 - 0
src/constant/constants.js

@@ -5,3 +5,6 @@ if (!localStorage.getItem("deviceId")) {
   localStorage.setItem("deviceId", Math.random() + "-" + Date.now());
 }
 export const DEVICE_ID = localStorage.getItem("deviceId");
+
+export const ORG_CODE =
+  process.env.VUE_APP_ORG_CODE || window.location.hostname.split(".")[0];

+ 48 - 33
src/features/Login/Login.vue

@@ -1,30 +1,28 @@
 <template>
   <div class="user-login">
-    <div
-      class="user-login-bg"
-      :style="{ 'background-image': `url(${backgroundImage})` }"
-    ></div>
+    <div class="user-login-bg"></div>
     <div class="content-wrapper">
-      <h2 class="slogan">
+      <!-- <h2 class="slogan">
         欢迎使用 <br />
         在线考试管理系统
-      </h2>
+      </h2> -->
       <div class="form-container">
-        <h4 class="form-title">登录</h4>
+        <div>
+          <img :src="schoolLogo" class="school-logo" alt="学校logo" />
+          <div class="text-center title">在线考试平台后台管理系统</div>
+        </div>
         <el-form ref="form" :model="user" label-width="0">
           <div class="form-items">
             <el-row class="form-item">
               <el-col>
                 <el-form-item
                   prop="username"
-                  :rules="[
-                    { required: true, message: '会员名/邮箱/手机号不能为空' },
-                  ]"
+                  :rules="[{ required: true, message: '用户名不能为空' }]"
                 >
                   <div class="form-line">
-                    <i class="el-icon-user input-icon"></i>
                     <el-input
-                      placeholder="会员名/邮箱/手机号"
+                      prefix-icon="el-icon-user"
+                      placeholder="请输入用户名"
                       v-model="user.username"
                     ></el-input>
                   </div>
@@ -38,10 +36,10 @@
                   :rules="[{ required: true, message: '密码不能为空' }]"
                 >
                   <div class="form-line">
-                    <i class="el-icon-lock input-icon"></i>
                     <el-input
+                      prefix-icon="el-icon-lock"
                       type="password"
-                      placeholder="密码"
+                      placeholder="请输入密码"
                       v-model="user.password"
                     ></el-input>
                   </div>
@@ -52,7 +50,7 @@
               <el-col>
                 <el-form-item>
                   <div v-show="user.errorInfo">
-                    {{ user.errorInfo }}
+                    <i class="el-icon-error"></i>{{ user.errorInfo }}
                   </div>
                 </el-form-item>
               </el-col>
@@ -87,20 +85,21 @@
         </el-form>
       </div>
     </div>
+    <div class="footer">Copyright © www.qmth.com.cn, All Rights Reserved.</div>
   </div>
 </template>
 
 <script>
 import { LOGIN_BY_USERNAME } from "../../store/action-types";
-// import BasicContainer from "@/samples/BasicContainer/BasicContainer";
-const backgroundImage =
-  "https://img.alicdn.com/tfs/TB1zsNhXTtYBeNjy1XdXXXXyVXa-2252-1500.png";
+import { ORG_CODE } from "../../constant/constants";
+import { getLogo } from "@/api/login";
+
 export default {
   // components: { BasicContainer },
   name: "Login",
   data() {
     return {
-      backgroundImage: backgroundImage,
+      schoolLogo: "",
       user: {
         username: "",
         password: "",
@@ -108,6 +107,10 @@ export default {
       },
     };
   },
+  async created() {
+    const res = await getLogo(ORG_CODE);
+    this.schoolLogo = res.data.data.logo;
+  },
   methods: {
     async submitBtn() {
       this.$refs["form"].validate(async (valid) => {
@@ -123,7 +126,8 @@ export default {
             this.$message({
               message: "登录成功",
               type: "success",
-              duration: 1500,
+              duration: 1.5,
+              showClose: true,
             });
             this.$router.push("/home");
           } catch (error) {
@@ -146,6 +150,7 @@ export default {
     right: 0;
     bottom: 0;
     background-size: cover;
+    background-image: url(./login-bg.png);
   }
   .el-checkbox__label {
     color: #999;
@@ -197,13 +202,6 @@ export default {
       left: 0;
       width: 100%;
       box-sizing: border-box;
-      border-width: 1px;
-      border-style: solid;
-      border-top: 0;
-      border-left: 0;
-      border-right: 0;
-      border-color: #dcdcdc;
-      border-radius: 0;
     }
   }
   .el-input {
@@ -216,12 +214,6 @@ export default {
       font-size: 13px;
     }
   }
-  .form-title {
-    margin: 0 0 20px;
-    text-align: center;
-    color: #3080fe;
-    letter-spacing: 12px;
-  }
   .input-icon {
     color: #999;
   }
@@ -262,9 +254,32 @@ export default {
     }
   }
 }
+.school-logo {
+  text-align: center;
+  height: 60px;
+  width: 200px;
+}
+.title {
+  color: #626a82;
+  font-size: 18px;
+  font-weight: 700;
+
+  margin-bottom: 30px;
+}
+.form-item {
+  margin-bottom: 5px;
+}
 .error-info {
   height: 30px;
   overflow: hidden;
   color: red;
 }
+
+.footer {
+  bottom: 10px;
+  position: absolute;
+  font-size: 12px;
+  text-align: center;
+  width: 100%;
+}
 </style>

BIN
src/features/Login/login-bg.png


+ 115 - 0
src/features/system/OrgManagement/OrgManagement.vue

@@ -0,0 +1,115 @@
+<template>
+  <div>
+    <el-form :model="form" inline>
+      <el-form-item label="中心代码">
+        <el-input v-model.trim="form.code"></el-input>
+      </el-form-item>
+      <el-form-item label="中心名称">
+        <el-input v-model.trim="form.name"></el-input>
+      </el-form-item>
+      <el-form-item label="状态">
+        <StateSelect v-model="form.enableState"></StateSelect>
+      </el-form-item>
+      <el-button @click="searchForm">查询</el-button>
+      <el-button>新增</el-button>
+      <el-button>导入</el-button>
+    </el-form>
+
+    <el-table :data="tableData" stripe style="width: 100%;">
+      <el-table-column type="selection" width="40" />
+      <el-table-column width="55" label="ID">
+        <span slot-scope="scope">{{ scope.row.id }}</span>
+      </el-table-column>
+      <el-table-column width="200" label="机构名称">
+        <span slot-scope="scope">{{ scope.row.name }}</span>
+      </el-table-column>
+      <el-table-column width="200" label="机构代码">
+        <span slot-scope="scope">{{ scope.row.code }}</span>
+      </el-table-column>
+      <el-table-column label="状态">
+        <span slot-scope="scope">{{
+          scope.row.enable | zeroOneEnableDisableFilter
+        }}</span>
+      </el-table-column>
+      <el-table-column width="100" label="负责人">
+        <span slot-scope="scope">{{ scope.row.contactName }}</span>
+      </el-table-column>
+      <el-table-column width="120" label="联系方式">
+        <span slot-scope="scope">{{ scope.row.contactPhone }}</span>
+      </el-table-column>
+      <el-table-column width="120" label="更新人">
+        <span slot-scope="scope">{{ scope.row.updateName }}</span>
+      </el-table-column>
+      <el-table-column sortable width="170" label="更新时间" prop="updateTime">
+      </el-table-column>
+      <el-table-column :context="_self" label="操作" width="210">
+        <div slot-scope="scope">
+          <el-button size="mini" type="primary" plain @click="edit(scope.row)">
+            <i class="el-icon-edit"></i> 编辑
+          </el-button>
+        </div>
+      </el-table-column>
+    </el-table>
+    <div class="page float-right">
+      <el-pagination
+        @current-change="handleCurrentChange"
+        :current-page="currentPage"
+        :page-size="pageSize"
+        :page-sizes="[10, 20, 50, 100, 200, 300]"
+        @size-change="handleSizeChange"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="total"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+import StateSelect from "@/components/StateSelect";
+import { searchOrgs } from "../../../api/system-org";
+
+export default {
+  name: "OrgManagement",
+  components: {
+    StateSelect,
+  },
+  data() {
+    return {
+      form: {
+        code: "",
+        name: "",
+        enableState: "",
+      },
+      tableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: 10,
+    };
+  },
+  async created() {},
+  methods: {
+    async searchForm() {
+      this.tableData = (
+        await searchOrgs({
+          enable: this.form.enableState,
+          code: this.form.code,
+          name: this.form.name,
+          pageNumber: this.currentPage,
+          pageSize: this.pageSize,
+        })
+      ).data.data.records.records;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.searchForm();
+    },
+    handleSizeChange(val) {
+      this.pageSize = val;
+      this.currentPage = 1;
+      this.searchForm();
+    },
+  },
+};
+</script>
+
+<style></style>

+ 127 - 0
src/features/system/UserManagement/UserManagement.vue

@@ -0,0 +1,127 @@
+<template>
+  <div>
+    <el-form :model="form" inline>
+      <el-form-item label="角色">
+        <RoleSelect v-model="form.roleCode"></RoleSelect>
+      </el-form-item>
+      <el-form-item label="登录名">
+        <el-input v-model.trim="form.loginName"></el-input>
+      </el-form-item>
+      <el-form-item label="姓名">
+        <el-input v-model.trim="form.name"></el-input>
+      </el-form-item>
+      <el-form-item label="状态">
+        <StateSelect v-model="form.enableState"></StateSelect>
+      </el-form-item>
+      <el-button @click="searchForm">查询</el-button>
+      <el-button>新增</el-button>
+      <el-button>导入</el-button>
+    </el-form>
+
+    <el-table :data="tableData" stripe style="width: 100%;">
+      <el-table-column type="selection" width="40" />
+      <el-table-column width="55" label="ID">
+        <span slot-scope="scope">{{ scope.row.id }}</span>
+      </el-table-column>
+      <el-table-column
+        width="200"
+        v-if="$store.state.user.orgId === null"
+        label="机构名称"
+      >
+        <span slot-scope="scope">{{ scope.row.orgName }}</span>
+      </el-table-column>
+      <el-table-column width="200" label="姓名">
+        <span slot-scope="scope">{{ scope.row.name }}</span>
+      </el-table-column>
+      <el-table-column label="登录名">
+        <span slot-scope="scope">{{ scope.row.loginName }}</span>
+      </el-table-column>
+      <el-table-column width="100" label="角色">
+        <span slot-scope="scope">{{ scope.row.roleName }}</span>
+      </el-table-column>
+      <el-table-column width="120" label="状态">
+        <span slot-scope="scope">{{
+          scope.row.enable | zeroOneEnableDisableFilter
+        }}</span>
+      </el-table-column>
+      <el-table-column width="120" label="更新人">
+        <span slot-scope="scope">{{ scope.row.updateName }}</span>
+      </el-table-column>
+      <el-table-column sortable width="170" label="更新时间" prop="updateTime">
+      </el-table-column>
+      <el-table-column :context="_self" label="操作" width="210">
+        <div slot-scope="scope">
+          <el-button size="mini" type="primary" plain @click="edit(scope.row)">
+            <i class="el-icon-edit"></i> 编辑
+          </el-button>
+        </div>
+      </el-table-column>
+    </el-table>
+    <div class="page float-right">
+      <el-pagination
+        @current-change="handleCurrentChange"
+        :current-page="currentPage"
+        :page-size="pageSize"
+        :page-sizes="[10, 20, 50, 100, 200, 300]"
+        @size-change="handleSizeChange"
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="total"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+import RoleSelect from "@/components/RoleSelect.vue";
+import StateSelect from "@/components/StateSelect";
+import { searchUsers } from "../../../api/system-user";
+
+export default {
+  name: "UserManagement",
+  components: {
+    RoleSelect,
+    StateSelect,
+  },
+  data() {
+    return {
+      form: {
+        orgList: [],
+        roleCode: "",
+        loginName: "",
+        name: "",
+        enableState: "",
+      },
+      tableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: 10,
+    };
+  },
+  async created() {},
+  methods: {
+    async searchForm() {
+      this.tableData = (
+        await searchUsers({
+          role: this.form.roleCode,
+          enable: this.form.enableState,
+          loginName: this.form.loginName,
+          name: this.form.name,
+          pageNumber: this.currentPage,
+          pageSize: this.pageSize,
+        })
+      ).data.data.records.records;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.searchForm();
+    },
+    handleSizeChange(val) {
+      this.pageSize = val;
+      this.currentPage = 1;
+      this.searchForm();
+    },
+  },
+};
+</script>
+
+<style></style>

+ 15 - 0
src/filters/index.js

@@ -14,3 +14,18 @@ Vue.filter("booleanPassFilter", function (val) {
   if (val === null) return "无";
   return { true: "通过", false: "不通过" }[val];
 });
+
+Vue.filter("zeroOneYesNoFilter", function (val) {
+  if (val === null) return "无";
+  return { 1: "是", 0: "否" }[val];
+});
+
+Vue.filter("zeroOneEnableDisableFilter", function (val) {
+  if (val === null) return "无";
+  return { 1: "启用", 0: "禁用" }[val];
+});
+
+Vue.filter("zeroOnePassFilter", function (val) {
+  if (val === null) return "无";
+  return { 1: "通过", 0: "不通过" }[val];
+});

+ 1 - 3
src/plugins/axiosApp.js

@@ -6,11 +6,9 @@ import cachingGet from "./axiosCache";
 import { notifyInvalidTokenThrottled } from "./axiosNotice";
 import { getToken, removeToken } from "../auth/auth";
 import axiosRetry from "axios-retry";
-import { DEVICE_ID } from "@/constant/constants";
+import { PLATFORM, DEVICE_ID } from "@/constant/constants";
 import { Notification } from "element-ui";
 
-const PLATFORM = "web";
-
 // Full config:  https://github.com/axios/axios#request-config
 // axios.defaults.baseURL = process.env.BASE_URL || process.env.apiUrl || '';
 // axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;

+ 22 - 20
src/router/index.js

@@ -47,32 +47,34 @@ const routes = [
     ],
   },
   {
-    path: "/about",
-    name: "About",
-    // route level code-splitting
-    // this generates a separate chunk (about.[hash].js) for this route
-    // which is lazy-loaded when the route is visited.
-    component: () =>
-      import(/* webpackChunkName: "about" */ "../views/About.vue"),
+    path: "/system",
+    name: "System",
+    component: Layout,
+    children: [
+      {
+        path: "user",
+        name: "UserManagement",
+        component: () =>
+          import(
+            /* webpackChunkName: "system" */ "../features/system/UserManagement/UserManagement.vue"
+          ),
+      },
+      {
+        path: "org",
+        name: "OrgManagement",
+        component: () =>
+          import(
+            /* webpackChunkName: "system" */ "../features/system/OrgManagement/OrgManagement.vue"
+          ),
+      },
+    ],
   },
   {
     path: "/login",
     name: "Login",
     component: () =>
-      import(/* webpackChunkName: "about" */ "../features/Login/Login.vue"),
+      import(/* webpackChunkName: "Login" */ "../features/Login/Login.vue"),
   },
-  // {
-  //   path: "/xxx/:id",
-  //   component: XXX,
-  //   props(route) {
-  //     return propsValidator(route, XXX);
-  //   }
-  // }
-  // {
-  //   path: "/login",
-  //   component: () =>
-  //     import(/* webpackChunkName: "login" */ "../features/Login/Login.vue"),
-  // },
   {
     path: "/*",
     component: () =>

+ 2 - 0
src/store/action-types.js

@@ -1,3 +1,5 @@
 export const LOGIN_BY_USERNAME = "LOGIN_BY_USERNAME";
+export const LOG_OUT = "LOG_OUT";
+export const FED_LOG_OUT = "FED_LOG_OUT";
 export const LOGIN_BY_PHONE = "LOGIN_BY_PHONE";
 export const SEND_SMS = "SEND_SMS";

+ 3 - 3
src/store/modules/user.js

@@ -1,7 +1,7 @@
 import { loginByUsername, logout } from "@/api/login";
 // import { removeKeyToken, setKeyToken } from "@/auth/auth";
 import { omit } from "lodash-es";
-import { LOGIN_BY_USERNAME } from "../action-types";
+import { LOGIN_BY_USERNAME, LOG_OUT, FED_LOG_OUT } from "../action-types";
 import { setToken } from "@/auth/auth";
 
 const user = {
@@ -31,7 +31,7 @@ const user = {
     },
 
     // 登出
-    LogOut({ commit, state }) {
+    [LOG_OUT]({ commit, state }) {
       return new Promise((resolve, reject) => {
         logout(state.token)
           .then(() => {
@@ -46,7 +46,7 @@ const user = {
     },
 
     // 前端 登出
-    FedLogOut({ commit }) {
+    [FED_LOG_OUT]({ commit }) {
       return new Promise((resolve) => {
         commit("SET_USER", null);
         // removeKeyToken();

+ 2 - 2
src/utils/monitors.js

@@ -11,14 +11,14 @@ Vue.config.errorHandler = (error) => {
 
 window.addEventListener("error", function (event) {
   errorLog(event.message, {
-    stack: event.error.stack.replace(/\n/g, "||||"),
+    stack: event?.error?.stack?.replace(/\n/g, "||||"),
     code: "全局JS错误",
   });
 });
 
 window.addEventListener("unhandledrejection", function (event) {
   errorLog(event?.reason?.message, {
-    stack: event.error.stack.replace(/\n/g, "||||"),
+    stack: event?.error?.stack?.replace(/\n/g, "||||"),
     code: "全局JS错误",
   });
 });

+ 5 - 0
src/utils/utils.js

@@ -1,5 +1,6 @@
 import { YYYYMMDDHHmmss } from "@/constant/constants";
 import moment from "moment";
+import queryString from "query-string";
 
 export function dateFormatForAPI(date) {
   return moment(date).format(YYYYMMDDHHmmss);
@@ -22,3 +23,7 @@ export function errorLog(message, { stack = "", code = "" }) {
     code && "code: " + code,
   ]);
 }
+
+export function object2QueryString(obj) {
+  return queryString.stringify(obj);
+}

+ 2 - 4
src/views/Layout/Layout.vue

@@ -15,8 +15,7 @@ import AppFooter from "./components/AppFooter.vue";
 import SideBar from "./components/SideBar.vue";
 import NavBar from "./components/NavBar.vue";
 import {
-  baseMenuConfig,
-  userMenuConfig,
+  systemMenuConfig,
   businessMenuConfig,
   invigilationMenuConfig,
 } from "./components/menu";
@@ -33,8 +32,7 @@ export default {
     return {
       curMenus: [],
       navs: {
-        baseMenuConfig,
-        userMenuConfig,
+        systemMenuConfig,
         businessMenuConfig,
         invigilationMenuConfig,
       },

+ 10 - 42
src/views/Layout/components/menu.js

@@ -4,15 +4,10 @@
 
 const headerMenuConfig = [
   {
-    title: "基础管理",
-    name: "base",
+    title: "系统管理",
+    name: "system",
     icon: "icon-base",
   },
-  {
-    title: "用户管理",
-    name: "user",
-    icon: "icon-user",
-  },
   {
     title: "考务管理",
     name: "business",
@@ -25,45 +20,19 @@ const headerMenuConfig = [
   },
 ];
 
-const baseMenuConfig = [
+const systemMenuConfig = [
   {
-    title: "基础管理",
-    name: "Base",
-    icon: "el-icon-menu",
-    children: [
-      {
-        title: "基础管理",
-        name: "Base",
-      },
-      {
-        title: "监控页",
-        name: "Base",
-      },
-      {
-        title: "工作台",
-        name: "Base",
-      },
-    ],
-  },
-];
-
-const userMenuConfig = [
-  {
-    title: "用户管理",
-    name: "User",
+    title: "系统管理",
+    name: "System",
     icon: "el-icon-menu",
     children: [
       {
-        title: "基础管理",
-        name: "Base",
-      },
-      {
-        title: "监控页",
-        name: "Base",
+        title: "用户管理",
+        name: "UserManagement",
       },
       {
-        title: "工作台",
-        name: "Base",
+        title: "机构管理",
+        name: "OrgManagement",
       },
     ],
   },
@@ -199,8 +168,7 @@ const invigilationMenuConfig = [
 
 export {
   headerMenuConfig,
-  baseMenuConfig,
-  userMenuConfig,
+  systemMenuConfig,
   businessMenuConfig,
   invigilationMenuConfig,
 };

+ 19 - 0
yarn.lock

@@ -9131,6 +9131,15 @@ query-string@^4.1.0:
     object-assign "^4.1.0"
     strict-uri-encode "^1.0.0"
 
+query-string@^6.13.1:
+  version "6.13.1"
+  resolved "https://registry.npm.taobao.org/query-string/download/query-string-6.13.1.tgz?cache=0&sync_timestamp=1591853352562&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fquery-string%2Fdownload%2Fquery-string-6.13.1.tgz#d913ccfce3b4b3a713989fe6d39466d92e71ccad"
+  integrity sha1-2RPM/OO0s6cTmJ/m05Rm2S5xzK0=
+  dependencies:
+    decode-uri-component "^0.2.0"
+    split-on-first "^1.0.0"
+    strict-uri-encode "^2.0.0"
+
 querystring-es3@^0.2.0:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
@@ -10099,6 +10108,11 @@ spdy@^4.0.2:
     select-hose "^2.0.0"
     spdy-transport "^3.0.0"
 
+split-on-first@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.npm.taobao.org/split-on-first/download/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
+  integrity sha1-9hCv7uOxK84dDDBCXnY5i3gkml8=
+
 split-string@^3.0.1, split-string@^3.0.2:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
@@ -10211,6 +10225,11 @@ strict-uri-encode@^1.0.0:
   resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
   integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
 
+strict-uri-encode@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
+  integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
+
 string-argv@0.3.1:
   version "0.3.1"
   resolved "https://registry.npm.taobao.org/string-argv/download/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"