Browse Source

接口调试

zhangjie 2 years ago
parent
commit
f94f2194b1

+ 28 - 15
src/api/system.js

@@ -3,36 +3,49 @@ import { httpApp } from "@/plugins/axiosIndex";
 // import { pickBy } from "lodash-es";
 
 // black-list
-export function searchBlackList() {
-  return httpApp.post("/api/admin/user/query", {});
+export function searchBlackList(datas) {
+  return httpApp.post("/api/admin/black/list/select", {}, { params: datas });
 }
 export function saveBlackItem(datas) {
-  return httpApp.post("/api/admin/user/query", datas);
+  return httpApp.post("/api/admin/black/list/save", datas);
 }
 export function deleteBlackItem(id) {
-  return httpApp.post("/api/admin/black/delete", { id });
+  return httpApp.post("/api/admin/black/list/delete", {}, { params: { id } });
 }
 // system-notice
-export function searchSystemNoice() {
-  return httpApp.post("/api/admin/user/query", {});
+export function searchSystemNoice(datas) {
+  return httpApp.post("/api/admin/notify/select", {}, { params: datas });
 }
 export function saveSystemNotice(datas) {
-  return httpApp.post("/api/admin/user/query", datas);
+  return httpApp.post("/api/admin/notify/save", datas);
 }
 export function enableSystemNotice({ id, enable }) {
-  return httpApp.post("/api/admin/user/query", { id, enable });
+  return httpApp.post(
+    "/api/admin/notify/enable",
+    {},
+    { params: { id, enable } }
+  );
 }
 // export function deleteSystemNotice(id) {
 //   return httpApp.post("/api/admin/black/delete", { id });
 // }
 
 // data-statistics
-export function statSummary() {
-  return httpApp.post("/api/admin/statistics/summary", {});
+export function sysStatisticsData() {
+  return httpApp.post("/api/admin/sys/data_count", {});
 }
-export function statOrgStudent() {
-  return httpApp.post("/api/admin/statistics/org", {});
-}
-export function statAreaStudent() {
-  return httpApp.post("/api/admin/statistics/area", {});
+
+// system-config
+export function searchSystemConfig(datas) {
+  return httpApp.post("/api/admin/sys/config/select", {}, { params: datas });
+}
+export function saveSystemConfig(datas) {
+  return httpApp.post("/api/admin/sys/config/save", datas);
+}
+export function enableSystemConfig({ id, enable }) {
+  return httpApp.post(
+    "/api/admin/sys/config/enable",
+    {},
+    { params: { id, enable } }
+  );
 }

+ 3 - 3
src/features/examwork/ExamManagement/ExamEdit.vue

@@ -514,10 +514,10 @@
           </div>
           <el-row v-if="isOpenMonitorVideo">
             <el-form-item label="是否允许考生发起语音通话">
-              <el-radio v-model="form.studentCanCall" :label="1">
+              <el-radio v-model="form.examStudentCallEnable" :label="1">
               </el-radio>
-              <el-radio v-model="form.studentCanCall" :label="0">
+              <el-radio v-model="form.examStudentCallEnable" :label="0">
               </el-radio>
             </el-form-item>
@@ -775,7 +775,7 @@ export default {
         monitorProxy: false,
         monitorRecord: [],
         monitorVideoSource: [],
-        studentCanCall: 1,
+        examStudentCallEnable: 1,
         ipAllow: "",
       },
       rules: {

+ 8 - 11
src/features/examwork/ExamManagement/ExamManagement.vue

@@ -150,19 +150,16 @@
       />
     </div>
     <CopyExamDialog ref="theDialog" :exam="selected" @reload="searchForm" />
+    <PushSetDialog ref="PushSetDialog" :exam-id="curExamId" />
   </div>
 </template>
 
 <script>
 import StateSelect from "@/components/StateSelect";
 import ExamTypeSelect from "@/components/ExamTypeSelect";
-import {
-  searchExams,
-  toggleEnableExam,
-  reCalcExam,
-  pushCloudMarkExam,
-} from "@/api/examwork-exam";
+import { searchExams, toggleEnableExam, reCalcExam } from "@/api/examwork-exam";
 import CopyExamDialog from "./CopyExamDialog";
+import PushSetDialog from "./PushSetDialog.vue";
 
 export default {
   name: "ExamManagement",
@@ -170,6 +167,7 @@ export default {
     StateSelect,
     ExamTypeSelect,
     CopyExamDialog,
+    PushSetDialog,
   },
   data() {
     return {
@@ -185,6 +183,7 @@ export default {
       pageSize: 10,
       total: 10,
       selected: null,
+      curExamId: null,
     };
   },
   created() {
@@ -282,11 +281,9 @@ export default {
         })
         .catch(() => {});
     },
-    async pushExam(exam) {
-      await pushCloudMarkExam({
-        examId: exam.id,
-      });
-      this.$message.success("操作成功!");
+    pushExam(exam) {
+      this.curExamId = exam.id;
+      this.$refs.PushSetDialog.open();
     },
   },
 };

+ 84 - 0
src/features/examwork/ExamManagement/PushSetDialog.vue

@@ -0,0 +1,84 @@
+<template>
+  <el-dialog
+    class="push-set-dialog"
+    :visible.sync="modalIsShow"
+    title="推送云阅卷设置"
+    top="10vh"
+    width="600px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @open="visibleChange"
+  >
+    <el-form label-width="150px">
+      <el-form-item label="是否推送客观分:">
+        <el-radio-group v-model="modalForm.objectiveScorePush">
+          <el-radio :label="true">是</el-radio>
+          <el-radio :label="false">否</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="是否推送违纪考生:">
+        <el-radio-group v-model="modalForm.examStudentBreachPush">
+          <el-radio :label="true">是</el-radio>
+          <el-radio :label="false">否</el-radio>
+        </el-radio-group>
+      </el-form-item>
+    </el-form>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button @click="cancel">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { pushCloudMarkExam } from "@/api/examwork-exam";
+
+const initModalForm = {
+  examId: null,
+  objectiveScorePush: true,
+  examStudentBreachPush: true,
+};
+
+export default {
+  name: "PushSetDialog",
+  props: {
+    examId: {
+      type: [String, Number],
+      default: "",
+    },
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: { ...initModalForm },
+    };
+  },
+  methods: {
+    visibleChange() {
+      this.modalForm = { ...initModalForm, examId: this.examId };
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const data = await pushCloudMarkExam(this.modalForm).catch(() => {});
+      this.isSubmit = false;
+
+      if (!data) return;
+
+      this.$message.success("操作成功!");
+      this.$emit("modified");
+      this.cancel();
+    },
+  },
+};
+</script>

+ 7 - 2
src/features/examwork/StudentManagement/StudentTrackRecord.vue

@@ -59,8 +59,7 @@
                 <div class="warning-track-info">
                   <div class="warning-track-info-title">
                     <template v-if="log.type === 'BREACH_HANDLE'">
-                      <!-- todo: 日志撤销状态 -->
-                      <span>已撤销</span>
+                      <span v-if="log.breachLogStatus">已撤销</span>
                     </template>
                     <h3>{{ log.title }}</h3>
                   </div>
@@ -336,6 +335,12 @@ export default {
             info.updateTime - info.createTime
           );
         }
+
+        // 撤销违纪的特别处理
+        if (item.type === "BREACH_HANDLE" && item.title.includes('{"')) {
+          const tinfo = JSON.parse(item.title);
+          info.breachLogStatus = tinfo.breachLogStatus;
+        }
         return info;
       });
       return logs;

+ 7 - 2
src/features/invigilation/OnlinePatrol/PatrolWarningDetail.vue

@@ -136,8 +136,7 @@
                 <div class="warning-track-info">
                   <div class="warning-track-info-title">
                     <template v-if="log.type === 'BREACH_HANDLE'">
-                      <!-- todo: 日志撤销状态 -->
-                      <span>已撤销</span>
+                      <span v-if="log.breachLogStatus">已撤销</span>
                     </template>
                     <h3>{{ log.title }}</h3>
                   </div>
@@ -364,6 +363,12 @@ export default {
             info.updateTime - info.createTime
           );
         }
+
+        // 撤销违纪的特别处理
+        if (item.type === "BREACH_HANDLE" && item.title.includes('{"')) {
+          const tinfo = JSON.parse(item.title);
+          info.breachLogStatus = tinfo.breachLogStatus;
+        }
         return info;
       });
       return logs;

+ 12 - 13
src/features/invigilation/RealtimeMonitoring/StudentBreachDialog.vue

@@ -11,7 +11,7 @@
   >
     <div class="tips-info tips-error">
       <i class="el-icon-warning"></i>
-      <p v-if="modalForm.breachStatus">
+      <p v-if="!modalForm.status">
         本操作记录考生的违规事实,并对考生进行违纪处理,请监考老师仔细核对好考生的信息,谨慎操作!
       </p>
       <p v-else>
@@ -74,13 +74,15 @@ import { updateBreachInfo } from "@/api/invigilation";
 import { BREACH_REASON_TYPE, BREACH_REPEAL_TYPE } from "@/constant/constants";
 
 const initModalForm = {
+  // info
   examStudentName: "",
   identity: "",
   courseNameCode: "",
+  // api
   description: "",
   examRecordId: [],
-  breachStatus: 0,
-  status: 1,
+  status: 0,
+  breachLogId: null,
   type: "",
 };
 
@@ -115,18 +117,14 @@ export default {
   },
   methods: {
     opened() {
-      // breachStatus: 0:违纪,1:正常
+      // 状态,0:新建,1:撤销
       this.modalForm = Object.assign({}, initModalForm, this.instance);
-      this.reasonTitle = this.modalForm.breachStatus
-        ? "违规类型:"
-        : "撤销原因:";
-      this.descTitle = this.modalForm.breachStatus
-        ? "违规描述:"
-        : "原因详述:";
-      this.rules.type[0].message = this.modalForm.breachStatus
+      this.reasonTitle = !this.modalForm.status ? "违规类型:" : "撤销原因:";
+      this.descTitle = !this.modalForm.status ? "违规描述:" : "原因详述:";
+      this.rules.type[0].message = !this.modalForm.status
         ? "请选择违规类型"
         : "请选择撤销原因";
-      const options = this.modalForm.breachStatus
+      const options = !this.modalForm.status
         ? BREACH_REASON_TYPE
         : BREACH_REPEAL_TYPE;
       let typeList = [];
@@ -158,8 +156,9 @@ export default {
       this.isSubmit = false;
       if (!result) return;
 
-      this.$emit("modified");
+      this.$message.success("操作成功!");
       this.cancel();
+      this.$emit("modified");
     },
   },
 };

+ 17 - 9
src/features/invigilation/RealtimeMonitoring/WarningDetail.vue

@@ -215,11 +215,13 @@
                 <div class="warning-track-info">
                   <div class="warning-track-info-title">
                     <template v-if="log.type === 'BREACH_HANDLE'">
-                      <el-button type="text" @click="toBreach(1, log.id)"
-                        >撤销违纪</el-button
+                      <span
+                        v-if="!log.breachLogStatus"
+                        class="warning-track-cancel"
+                        @click="toBreach(1, log.objId)"
+                        >撤销违纪</span
                       >
-                      <!-- todo: 日志撤销状态 -->
-                      <span>已撤销</span>
+                      <span v-else>已撤销</span>
                     </template>
                     <h3>{{ log.title }}</h3>
                   </div>
@@ -593,6 +595,13 @@ export default {
             info.updateTime - info.createTime
           );
         }
+
+        // 撤销违纪的特别处理
+        if (item.type === "BREACH_HANDLE" && item.title.includes('{"')) {
+          const tinfo = JSON.parse(item.title);
+          info.breachLogStatus = tinfo.breachLogStatus;
+        }
+
         return info;
       });
       return logs;
@@ -626,18 +635,17 @@ export default {
         },
       });
     },
-    toBreach(status = 0, logId = null) {
+    toBreach(status = 0, breachLogId = null) {
       this.curDetail = {
         examStudentName: this.detailInfo.examStudentName,
         identity: this.detailInfo.identity,
         courseNameCode: this.detailInfo.courseNameCode,
         description: "",
         examRecordId: [this.detailInfo.examRecordId],
-        breachStatus: this.detailInfo.breachStatus,
-        status,
-        logId,
         // 状态,0:新建,1:撤销
-        // 违纪状态:正常(1)=>新建,违纪(0)=>撤销
+        status,
+        // 违纪日志id,新建违纪时为null,撤销违纪时需填值
+        breachLogId,
         type: "",
       };
       this.$refs.StudentBreachDialog.open();

+ 24 - 5
src/features/system/BlackList/BlackList.vue

@@ -16,10 +16,10 @@
 
     <el-table :data="tableData">
       <el-table-column label="软件名称">
-        <span slot-scope="scope">{{ scope.row.name }}</span>
+        <span slot-scope="scope">{{ scope.row.softName }}</span>
       </el-table-column>
       <el-table-column label="进程名称">
-        <span slot-scope="scope">{{ scope.row.code }}</span>
+        <span slot-scope="scope">{{ scope.row.processName }}</span>
       </el-table-column>
       <el-table-column label="操作" width="100" fixed="right">
         <div slot-scope="scope">
@@ -34,6 +34,18 @@
         </div>
       </el-table-column>
     </el-table>
+    <div class="part-page">
+      <el-pagination
+        background
+        @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>
 
     <ModifyBlackItem
       ref="ModifyBlackItem"
@@ -55,6 +67,9 @@ export default {
   data() {
     return {
       tableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: 10,
       curRow: {},
     };
   },
@@ -63,8 +78,12 @@ export default {
   },
   methods: {
     async searchForm() {
-      const res = await searchBlackList();
-      this.tableData = res.data.data;
+      const res = await searchBlackList({
+        pageNumber: this.currentPage,
+        pageSize: this.pageSize,
+      });
+      this.tableData = res.data.data.records;
+      this.total = res.data.data.total;
     },
     toAdd() {
       this.curRow = {};
@@ -72,7 +91,7 @@ export default {
     },
     async toDelete(row) {
       const result = await this.$confirm(
-        `确定要删除黑名单【${row.name}】吗?`,
+        `确定要删除黑名单【${row.softName}】吗?`,
         "操作提醒",
         {
           confirmButtonText: "确定",

+ 5 - 5
src/features/system/BlackList/ModifyBlackItem.vue

@@ -14,11 +14,11 @@
       ref="modalFormComp"
       :model="modalForm"
       :rules="rules"
-      label-width="90px"
+      label-width="120px"
     >
-      <el-form-item prop="name" label="软件名称:">
+      <el-form-item prop="softName" label="软件名称:">
         <el-input
-          v-model.trim="modalForm.name"
+          v-model.trim="modalForm.softName"
           placeholder="请输入软件名称"
           clearable
         ></el-input>
@@ -46,7 +46,7 @@ import { saveBlackItem } from "@/api/system";
 
 const initModalForm = {
   id: null,
-  name: "",
+  softName: "",
   processName: "",
 };
 
@@ -74,7 +74,7 @@ export default {
       isSubmit: false,
       modalForm: { ...initModalForm },
       rules: {
-        name: [
+        softName: [
           {
             required: true,
             message: "请输入软件名称",

+ 116 - 63
src/features/system/DataStatistics/DataStatistics.vue

@@ -11,18 +11,20 @@
         <div class="stat-summary-item">
           <h4>当前考试中人数</h4>
           <p>
-            <animate-number :value="summary.examingCount"></animate-number>
+            <animate-number :value="summary.examCount"></animate-number>
           </p>
         </div>
         <div class="stat-summary-item">
           <h4>累计考试科次</h4>
           <p>
-            <animate-number :value="summary.stdExamCount"></animate-number>
+            <animate-number :value="summary.examRecordCount"></animate-number>
           </p>
         </div>
         <div class="stat-summary-item">
           <h4>累计服务考生</h4>
-          <p><animate-number :value="summary.studentCount"></animate-number></p>
+          <p>
+            <animate-number :value="summary.examStudentCount"></animate-number>
+          </p>
         </div>
       </div>
     </div>
@@ -30,9 +32,17 @@
       <div class="data-stat-table">
         <div class="data-stat-table-title">机构考生分布</div>
         <el-table :data="tableData" stripe>
-          <el-table-column label="机构名称"></el-table-column>
-          <el-table-column width="80" label="在线人数"></el-table-column>
-          <el-table-column width="80" label="在考人数"></el-table-column>
+          <el-table-column label="机构名称" prop="name"></el-table-column>
+          <el-table-column
+            width="80"
+            label="在线人数"
+            prop="onlineCount"
+          ></el-table-column>
+          <el-table-column
+            width="80"
+            label="在考人数"
+            prop="examCount"
+          ></el-table-column>
         </el-table>
       </div>
       <div class="data-stat-chart">
@@ -48,84 +58,127 @@
 </template>
 
 <script>
-import {
-  statSummary,
-  statOrgStudent,
-  statAreaStudent,
-} from "../../../api/system";
+import timeMixin from "@/mixins/timeMixin";
+import { sysStatisticsData } from "../../../api/system";
+import VueCharts from "@/plugins/VueCharts";
 
 export default {
   name: "DataStatistics",
+  components: { VueCharts },
+  mixins: [timeMixin],
   data() {
     return {
       summary: {
         onlineCount: 0,
-        examingCount: 0,
-        stdExamCount: 0,
-        studentCount: 0,
+        examCount: 0,
+        examRecordCount: 0,
+        examStudentCount: 0,
       },
       tableData: [],
       areaChartOption: null,
-      // setTs
-      setTsMap: {
-        summary: [],
-        areaMap: [],
-      },
     };
   },
   mounted() {
-    // this.initData();
+    this.getData();
   },
   beforeDestroy() {
     this.clearSetTs();
   },
   methods: {
-    addSetTime(typeName, action, time = 1 * 1000) {
-      this.setTsMap[typeName].push(setTimeout(action, time));
-    },
-    clearSetTs(typeName) {
-      if (typeName) {
-        if (!this.setTsMap[typeName] || !this.setTsMap[typeName].length) return;
-        this.setTsMap[typeName].forEach((t) => clearTimeout(t));
-        this.setTsMap[typeName] = [];
-        return;
-      }
-      Object.keys(this.setTsMap).forEach((k) => {
-        this.setTsMap[k].forEach((t) => clearTimeout(t));
-        this.setTsMap[k] = [];
-      });
-    },
-    initData() {
-      this.intervalSummary();
-      this.intervalStudent();
-    },
-    async getSummary() {
-      const res = await statSummary();
-      this.summary = res.data;
-    },
-    async getStatOrgStudent() {
-      const res = await statOrgStudent();
-      this.tableData = res.data;
-    },
-    async getStatAreaStudent() {
-      const res = await statAreaStudent();
-      // todo:
-      this.areaChartOption = res.data;
-    },
-    async intervalSummary() {
-      const typeName = "summary";
-      this.clearSetTs(typeName);
+    async getData() {
+      this.clearSetTs();
+
+      const res = await sysStatisticsData();
+      const data = res.data.data || {};
+
+      this.summary = {
+        onlineCount: data.onlineCount,
+        examCount: data.examCount,
+        examRecordCount: data.examRecordCount,
+        examStudentCount: data.examStudentCount,
+      };
 
-      await this.getSummary();
-      this.addSetTime(typeName, this.intervalSummary, 5 * 1000);
+      this.tableData = data.orgDataCountBeanList || [];
+      this.areaChartOption = this.getInviMapOption(data.mapDataCountBeanList);
+
+      this.addSetTime(this.getData, 10 * 1000);
     },
-    async intervalStudent() {
-      const typeName = "areaMap";
-      this.clearSetTs(typeName);
+    getInviMapOption(dataList) {
+      // if (!dataList.length) return;
+
+      let countData = dataList.map((item) => {
+        return {
+          name: item.province,
+          ...item,
+          itemStyle: {
+            areaColor: "rgba(45, 153, 255, 0.5)",
+          },
+        };
+      });
+      // 隐藏南海诸岛
+      countData.push({
+        name: "南海诸岛",
+        label: {
+          show: false,
+        },
+        itemStyle: {
+          opacity: 0,
+        },
+        emphasis: {
+          itemStyle: {
+            opacity: 0,
+          },
+        },
+      });
 
-      await this.getStatOrgStudent();
-      await this.getStatAreaStudent();
-      this.addSetTime(typeName, this.intervalStudent, 10 * 1000);
+      return {
+        tooltip: {
+          trigger: "item",
+          formatter(params) {
+            if (!params.data) return;
+            const { name, onlineCount } = params.data;
+            return `<span style="color:#2D99FF">${name}</span><br />在线人数:${onlineCount}`;
+          },
+          backgroundColor: "rgba(63,67,87,0.9)",
+          padding: 10,
+          triggerOn: "click",
+          textStyle: {
+            fontSize: 12,
+            color: "#E1E6EF",
+            fontWeight: 500,
+            lineHeight: 18,
+            rich: {
+              n: {
+                color: "#2D99FF",
+              },
+            },
+          },
+        },
+        series: [
+          {
+            name: "数量",
+            type: "map",
+            mapType: "china",
+            layoutCenter: ["50%", "50%"],
+            layoutSize: "100%",
+            data: countData,
+            itemStyle: {
+              areaColor: "rgba(45, 153, 255, 0.2)",
+              borderColor: "#2D99FF",
+              borderWidth: 1,
+            },
+            label: {
+              show: true,
+            },
+            emphasis: {
+              itemStyle: {
+                areaColor: "rgba(22, 206, 185, 1)",
+                borderColor: "rgba(45, 153, 255, 0.3)",
+              },
+            },
+          },
+        ],
+      };
     },
   },
 };

+ 160 - 0
src/features/system/SystemConfig/ModifyConfigItem.vue

@@ -0,0 +1,160 @@
+<template>
+  <el-dialog
+    class="modify-black-item"
+    :visible.sync="modalIsShow"
+    :title="title"
+    top="10vh"
+    width="600px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @open="visibleChange"
+  >
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :rules="rules"
+      label-width="120px"
+    >
+      <el-form-item prop="configKey" label="参数名称:">
+        <el-input
+          v-model.trim="modalForm.configKey"
+          placeholder="请输入参数名称"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="configValue" label="参数值:">
+        <el-input
+          v-model.trim="modalForm.configValue"
+          placeholder="请输入参数值"
+          clearable
+        ></el-input>
+      </el-form-item>
+      <el-form-item prop="configName" label="描述:">
+        <el-input
+          v-model.trim="modalForm.configName"
+          placeholder="请输入描述"
+          clearable
+        ></el-input>
+      </el-form-item>
+    </el-form>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button @click="cancel">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { objAssign } from "@/utils/utils";
+import { saveSystemConfig } from "@/api/system";
+
+const initModalForm = {
+  id: null,
+  configKey: "", //参数名称
+  configName: "", //描述
+  configValue: "", //参数值,
+  enable: null,
+};
+
+export default {
+  name: "modify-config-item",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  computed: {
+    isEdit() {
+      return !!this.instance.id;
+    },
+    title() {
+      return (this.isEdit ? "编辑" : "新增") + "系统参数";
+    },
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: { ...initModalForm },
+      rules: {
+        configKey: [
+          {
+            required: true,
+            message: "请设置参数名称",
+            trigger: "change",
+          },
+          {
+            message: "参数名称不能超过100个字",
+            max: 100,
+            trigger: "change",
+          },
+        ],
+        configValue: [
+          {
+            required: true,
+            message: "请设置参数值",
+            trigger: "change",
+          },
+          {
+            message: "参数值不能超过200个字",
+            max: 200,
+            trigger: "change",
+          },
+        ],
+        configName: [
+          {
+            required: true,
+            message: "请输入描述",
+            trigger: "change",
+          },
+          {
+            message: "描述不能超过100个字",
+            max: 100,
+            trigger: "change",
+          },
+        ],
+      },
+    };
+  },
+  methods: {
+    initData(val) {
+      if (val.id) {
+        this.modalForm = objAssign(initModalForm, val);
+      } else {
+        this.modalForm = { ...initModalForm };
+      }
+    },
+    visibleChange() {
+      this.initData(this.instance);
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      let datas = { ...this.modalForm };
+      const data = await saveSystemConfig(datas).catch(() => {});
+      this.isSubmit = false;
+
+      if (!data) return;
+
+      this.$message.success(this.title + "成功!");
+      this.$emit("modified");
+      this.cancel();
+    },
+  },
+};
+</script>

+ 138 - 0
src/features/system/SystemConfig/SystemConfig.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="system-config">
+    <div class="part-box-head">
+      <div class="part-box-head-left"><h1>系统参数</h1></div>
+    </div>
+    <div class="part-filter">
+      <div class="part-filter-form">
+        <div></div>
+        <div class="part-filter-form-action">
+          <el-button type="primary" icon="icon icon-add" @click="toAdd"
+            >新增</el-button
+          >
+        </div>
+      </div>
+    </div>
+
+    <el-table :data="tableData">
+      <el-table-column label="参数名称" prop="configKey"> </el-table-column>
+      <el-table-column label="参数值" prop="configValue"> </el-table-column>
+      <el-table-column label="描述" prop="configName"> </el-table-column>
+      <el-table-column prop="enable" label="状态" width="80">
+        <template slot-scope="scope">
+          {{ scope.row.enable | booleanEnableDisableFilter }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="160" fixed="right">
+        <div slot-scope="scope">
+          <el-button
+            size="mini"
+            type="primary"
+            plain
+            @click="toEdit(scope.row)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            size="mini"
+            :type="scope.row.enable ? 'danger' : 'primary'"
+            plain
+            @click="toEnable(scope.row)"
+            >{{ scope.row.enable ? "禁用" : "启用" }}</el-button
+          >
+        </div>
+      </el-table-column>
+    </el-table>
+
+    <div class="part-page">
+      <el-pagination
+        background
+        @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>
+
+    <!-- ModifyConfigItem -->
+    <modify-config-item
+      ref="ModifyConfigItem"
+      :instance="curRow"
+      @modified="searchForm"
+    ></modify-config-item>
+  </div>
+</template>
+
+<script>
+import { searchSystemConfig, enableSystemConfig } from "@/api/system";
+import ModifyConfigItem from "./ModifyConfigItem.vue";
+
+export default {
+  name: "system-config",
+  components: { ModifyConfigItem },
+  data() {
+    return {
+      tableData: [],
+      currentPage: 1,
+      pageSize: 10,
+      total: 10,
+      curRow: {},
+    };
+  },
+  mounted() {
+    this.searchForm();
+  },
+  methods: {
+    async searchForm() {
+      const res = await searchSystemConfig({
+        pageNumber: this.currentPage,
+        pageSize: this.pageSize,
+      });
+      this.tableData = res.data.data.records;
+      this.total = res.data.data.total;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.searchForm();
+    },
+    handleSizeChange(val) {
+      this.pageSize = val;
+      this.currentPage = 1;
+      this.searchForm();
+    },
+    toAdd() {
+      this.curRow = {};
+      this.$refs.ModifyConfigItem.open();
+    },
+    toEdit(row) {
+      this.curRow = row;
+      this.$refs.ModifyConfigItem.open();
+    },
+    async toEnable(row) {
+      const action = row.enable ? "禁用" : "启用";
+      const result = await this.$confirm(
+        `确定要${action}参数【${row.configKey}】吗?`,
+        "操作提醒",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          iconClass: "el-icon-warning",
+          customClass: "el-message-box__error",
+        }
+      ).catch(() => {});
+      if (result !== "confirm") return;
+
+      const enable = !row.enable;
+      await enableSystemConfig({
+        id: row.id,
+        enable,
+      });
+      row.enable = enable;
+      this.$message.success("操作成功!");
+    },
+  },
+};
+</script>

+ 1 - 1
src/features/system/SystemNotice/ModifySystemNotice.vue

@@ -14,7 +14,7 @@
       ref="modalFormComp"
       :model="modalForm"
       :rules="rules"
-      label-width="60px"
+      label-width="80px"
     >
       <el-form-item prop="title" label="标题:">
         <el-input

+ 2 - 2
src/features/system/SystemNotice/SystemNotice.vue

@@ -15,7 +15,7 @@
     </div>
 
     <el-table :data="tableData">
-      <el-table-column prop="id" label="ID" width="80"> </el-table-column>
+      <el-table-column prop="id" label="ID" width="180"> </el-table-column>
       <el-table-column prop="title" label="标题" min-width="120">
       </el-table-column>
       <el-table-column prop="content" label="通知内容" min-width="240">
@@ -25,7 +25,7 @@
           {{ scope.row.enable | booleanEnableDisableFilter }}
         </template>
       </el-table-column>
-      <el-table-column label="操作" width="100" fixed="right">
+      <el-table-column label="操作" width="160" fixed="right">
         <div slot-scope="scope">
           <el-button
             size="mini"

+ 11 - 3
src/router/index.js

@@ -74,7 +74,7 @@ const routes = [
       },
       {
         path: "statistics",
-        name: "DataStatistics",
+        name: "DataCountManagement",
         component: () =>
           import(
             /* webpackChunkName: "system" */ "../features/system/DataStatistics/DataStatistics.vue"
@@ -82,7 +82,7 @@ const routes = [
       },
       {
         path: "black-list",
-        name: "BlackList",
+        name: "BlackListManagement",
         component: () =>
           import(
             /* webpackChunkName: "system" */ "../features/system/BlackList/BlackList.vue"
@@ -90,12 +90,20 @@ const routes = [
       },
       {
         path: "system-notice",
-        name: "SystemNotice",
+        name: "SystemNotifyManagement",
         component: () =>
           import(
             /* webpackChunkName: "system" */ "../features/system/SystemNotice/SystemNotice.vue"
           ),
       },
+      {
+        path: "system-config",
+        name: "SysConfigManagement",
+        component: () =>
+          import(
+            /* webpackChunkName: "system" */ "../features/system/SystemConfig/SystemConfig.vue"
+          ),
+      },
     ],
   },
   {

+ 13 - 2
src/styles/base.scss

@@ -672,8 +672,20 @@ body {
     flex-grow: 2;
     padding-bottom: 30px;
   }
+  &-cancel {
+    font-weight: 600;
+    color: #fe5863 !important;
+    cursor: pointer;
+
+    &:hover {
+      color: mix(#000, #fe5863, 20%) !important;
+    }
+  }
   &-info {
     &-title {
+      margin-bottom: 6px;
+      line-height: 20px;
+
       > span {
         display: inline-block;
         vertical-align: middle;
@@ -685,8 +697,7 @@ body {
         font-size: 16px;
         font-weight: 600;
         color: #202b4b;
-        line-height: 1;
-        margin-bottom: 6px;
+        margin: 0;
         display: inline-block;
         vertical-align: middle;
       }

+ 6 - 0
src/styles/element-ui-custom.scss

@@ -282,8 +282,14 @@
 .el-form {
   &-item__label {
     color: #202b4b;
+    margin-bottom: 0;
   }
 }
 .el-form--inline .el-form-item__content {
   vertical-align: middle;
 }
+
+//
+.el-radio {
+  margin-bottom: 0;
+}

+ 16 - 0
src/views/Layout/components/menu.js

@@ -34,6 +34,22 @@ const systemMenuConfig = [
         title: "机构管理",
         name: "OrgManagement",
       },
+      {
+        title: "黑名单管理",
+        name: "BlackListManagement",
+      },
+      {
+        title: "系统通知",
+        name: "SystemNotifyManagement",
+      },
+      {
+        title: "数据统计",
+        name: "DataCountManagement",
+      },
+      {
+        title: "系统参数",
+        name: "SysConfigManagement",
+      },
     ],
   },
 ];