Преглед на файлове

Merge branch 'dev_v4.0.1' of http://git.qmth.com.cn/examcloud-frontend/examcloud-admin-web into dev_v4.0.1

lideyin преди 4 години
родител
ревизия
3fb88948ac
променени са 3 файла, в които са добавени 534 реда и са изтрити 8 реда
  1. 6 0
      src/modules/basic/routes/routes.js
  2. 377 0
      src/modules/basic/view/sys_login_rule_list.vue
  3. 151 8
      src/modules/examwork/view/student.vue

+ 6 - 0
src/modules/basic/routes/routes.js

@@ -16,6 +16,7 @@ import client_config from "../view/clientConfig";
 import school_config from "../view/school_config";
 import unimportant_school_config from "../view/unimportant_school_config";
 import sys_notice from "../view/sys_notice";
+import sysLoginRuleList from "../view/sys_login_rule_list";
 
 export default [
   {
@@ -105,6 +106,11 @@ export default [
         path: "sys_notice", //系统通知
         meta: { privilegeCodes: "sys_notice" },
         component: sys_notice
+      },
+      {
+        path: "sysLoginRuleList",
+        meta: { privilegeCodes: "sys_login_rule_list" },
+        component: sysLoginRuleList //登录规则列表
       }
     ]
   }

+ 377 - 0
src/modules/basic/view/sys_login_rule_list.vue

@@ -0,0 +1,377 @@
+<template>
+  <section style="margin-top: 0px;">
+    <el-form
+      :model="searchForm"
+      :inline="true"
+      style="border-bottom: 1px solid rgb(221, 221, 221);margin-bottom: 10px;"
+    >
+      <el-form-item label="学校">
+        <el-select
+          v-if="isSuperAdmin"
+          v-model="searchForm.rootOrgId"
+          placeholder="请选择"
+          filterable
+          clearable
+          size="small"
+          class="w180"
+        >
+          <el-option
+            v-for="item in rootOrgList"
+            :label="item.name"
+            :value="item.id"
+            :key="item.id"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="规则类型">
+        <el-select
+          v-model="searchForm.type"
+          size="small"
+          class="w180"
+          placeholder="请选择"
+          @clear="clearTypeValue"
+          clearable
+        >
+          <el-option
+            v-for="item in loginRuleTypes"
+            :label="item.label"
+            :value="item.value"
+            :key="item.value"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button
+          size="small"
+          type="primary"
+          icon="el-icon-search"
+          @click="doSearch(1)"
+          >查询
+        </el-button>
+
+        <el-button size="small" icon="el-icon-refresh" @click="resetSearchForm">
+          重置
+        </el-button>
+      </el-form-item>
+    </el-form>
+
+    <div style="margin-bottom: 5px;">
+      操作:
+      <el-button
+        size="small"
+        type="primary"
+        icon="el-icon-plus"
+        @click="loginRuleDialogOpen(null)"
+        >新增
+      </el-button>
+
+      <el-button
+        size="small"
+        type="primary"
+        icon="el-icon-refresh"
+        @click="doRefreshRule"
+        >刷新
+      </el-button>
+    </div>
+
+    <el-table
+      v-loading="loading"
+      :data="tableData"
+      element-loading-text="数据加载中"
+      style="width:100%;"
+      border
+      stripe
+    >
+      <el-table-column label="ID" prop="id" width="80px" sortable />
+      <el-table-column label="学校ID" prop="rootOrgId" width="110px" sortable />
+
+      <el-table-column label="规则类型" width="150px">
+        <template slot-scope="scope">
+          <span>{{ getTypeTitle(scope.row.type) }} </span></template
+        >
+      </el-table-column>
+
+      <el-table-column label="是否例外(白名单)" width="150px">
+        <template slot-scope="scope">
+          <span>{{ scope.row.allow ? "是" : "否" }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="创建时间" prop="creationTime" sortable />
+      <el-table-column label="更新时间" prop="updateTime" sortable />
+
+      <el-table-column label="操作" width="180px">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="primary"
+            icon="el-icon-edit"
+            @click="loginRuleDialogOpen(scope.row)"
+            plain
+            >编辑
+          </el-button>
+
+          <el-button
+            size="mini"
+            type="danger"
+            icon="el-icon-delete"
+            @click="doDeleteRule(scope.row)"
+            plain
+            >删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <div class="page pull-right">
+      <el-pagination
+        @current-change="handlePagerNo"
+        :current-page="searchForm.pageNo"
+        @size-change="handlePagerSize"
+        :page-size="searchForm.pageSize"
+        :page-sizes="[10, 20, 50, 100, 200, 300]"
+        :total="totalElements"
+        layout="total, sizes, prev, pager, next, jumper"
+      ></el-pagination>
+    </div>
+
+    <el-dialog
+      title="规则新增"
+      width="380px"
+      :visible.sync="loginRuleDialog"
+      @close="loginRuleDialogClose"
+    >
+      <el-form
+        :model="loginRuleForm"
+        ref="loginRuleForm"
+        :rules="formRules"
+        label-position="right"
+        label-width="120px"
+        inline-message
+      >
+        <el-form-item label="学校">
+          <el-select
+            v-if="isSuperAdmin"
+            v-model="loginRuleForm.rootOrgId"
+            placeholder="请选择"
+            filterable
+            clearable
+            size="small"
+            class="w180"
+          >
+            <el-option
+              v-for="item in rootOrgList"
+              :label="item.name"
+              :value="item.id"
+              :key="item.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="规则类型">
+          <el-select
+            v-model="loginRuleForm.type"
+            size="small"
+            class="w180"
+            placeholder="请选择"
+            clearable
+          >
+            <el-option
+              v-for="item in loginRuleTypes"
+              :label="item.label"
+              :value="item.value"
+              :key="item.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="是否白名单">
+          <el-radio-group v-model="loginRuleForm.allow">
+            <el-radio label="true">是</el-radio>
+            <el-radio label="false">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+
+        <div style="text-align: center">
+          <el-button type="primary" @click="doAddRule">确 定</el-button>
+          <el-button @click="loginRuleDialogClose">取 消</el-button>
+        </div>
+      </el-form>
+    </el-dialog>
+  </section>
+</template>
+
+<script>
+import { mapState } from "vuex";
+import { CORE_API } from "@/constants/constants.js";
+
+export default {
+  data() {
+    return {
+      searchForm: {
+        rootOrgId: null,
+        type: null,
+        allow: null,
+        pageNo: 1,
+        pageSize: 10
+      },
+      loading: false,
+      tableData: [],
+      totalElements: 0,
+      rootOrgList: [],
+      loginRuleTypes: [
+        { label: "考生登录", value: "STUDENT_LOGIN" },
+        { label: "考生端登录", value: "STUDENT_CLIENT_LOGIN" },
+        { label: "极验验证码登录", value: "GEETEST_LOGIN" }
+      ],
+      loginRuleDialog: false,
+      loginRuleForm: {
+        rootOrgId: null,
+        type: null,
+        allow: null
+      },
+      formRules: {
+        rootOrgId: [
+          { required: true, message: "学校不能为空!", trigger: "change" }
+        ],
+        type: [
+          { required: true, message: "规则类型不能为空!", trigger: "change" }
+        ]
+      }
+    };
+  },
+  methods: {
+    getRootOrgList() {
+      if (this.isSuperAdmin) {
+        this.$httpWithMsg
+          .get(CORE_API + "/org/getRootOrgList")
+          .then(response => {
+            this.rootOrgList = response.data;
+          });
+      }
+    },
+    doSearch(pageNo) {
+      this.searchForm.pageNo = pageNo;
+
+      this.loading = true;
+      let url = CORE_API + "/sys/xlogin/rule/list";
+      this.$http.post(url, this.searchForm).then(
+        response => {
+          this.tableData = response.data.content;
+          this.totalElements = response.data.totalElements;
+          this.loading = false;
+        },
+        error => {
+          console.log(error);
+          this.loading = false;
+        }
+      );
+    },
+    loginRuleDialogOpen(row) {
+      if (row) {
+        this.loginRuleForm.rootOrgId = row.rootOrgId;
+        this.loginRuleForm.type = row.type;
+        this.loginRuleForm.allow = row.allow;
+      } else {
+        this.loginRuleForm.rootOrgId = null;
+        this.loginRuleForm.type = null;
+        this.loginRuleForm.allow = null;
+      }
+      this.loginRuleDialog = true;
+    },
+    loginRuleDialogClose() {
+      this.loginRuleDialog = false;
+    },
+    doAddRule() {
+      this.$refs.loginRuleForm.validate(valid => {
+        if (!valid) {
+          return false;
+        }
+
+        this.loginRuleDialogClose();
+      });
+    },
+    doEditRule() {
+      this.loginRuleDialogClose();
+    },
+    doDeleteRule(row) {
+      this.$confirm("确认删除?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        let url = CORE_API + "/sys/xlogin/rule/delete?ruleId=" + row.id;
+        this.$http.post(url).then(() => {
+          this.$notify({
+            type: "success",
+            message: "删除成功"
+          });
+          this.doSearch();
+        });
+      });
+    },
+    doRefreshRule() {
+      this.$confirm("确认刷新?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        let url = CORE_API + "/sys/xlogin/rule/refresh";
+        this.$http.post(url).then(() => {
+          this.$notify({
+            type: "success",
+            message: "刷新成功"
+          });
+        });
+      });
+    },
+    handlePagerNo(pageNo) {
+      this.doSearch(pageNo);
+    },
+    handlePagerSize(pageSize) {
+      this.searchForm.pageSize = pageSize;
+      this.doSearch(1);
+    },
+    clearTypeValue() {
+      this.searchForm.type = null;
+    },
+    getTypeTitle(val) {
+      for (let type of this.loginRuleTypes) {
+        if (type.value == val) {
+          return type.label;
+        }
+      }
+    },
+    resetSearchForm() {
+      this.searchForm.rootOrgId = null;
+      this.searchForm.type = null;
+      this.searchForm.allow = null;
+      this.doSearch(1);
+    }
+  },
+  computed: {
+    ...mapState({ user: state => state.user }),
+    isSuperAdmin() {
+      return this.user.roleList.some(role => role.roleCode == "SUPER_ADMIN");
+    }
+  },
+  created() {
+    this.getRootOrgList();
+    this.doSearch(1);
+  }
+};
+</script>
+
+<style scoped>
+.page {
+  margin-top: 10px;
+}
+.pull-right {
+  float: right;
+}
+.w180 {
+  width: 180px;
+}
+</style>

+ 151 - 8
src/modules/examwork/view/student.vue

@@ -288,12 +288,13 @@
             label="学习中心"
             sortable
           ></el-table-column>
-          <el-table-column
-            prop="updateTime"
-            width="168"
-            label="更新时间"
-            sortable
-          ></el-table-column>
+          <el-table-column width="168" label="更新时间" sortable>
+            <template slot-scope="scope">
+              <el-button @click="gotoOperateLog(scope.row.id)" type="text">{{
+                scope.row.updateTime
+              }}</el-button>
+            </template>
+          </el-table-column>
           <el-table-column width="50" label="状态">
             <span slot-scope="scope">
               <span v-if="scope.row.enable">
@@ -613,6 +614,80 @@
         >
           <img :src="photo.url" height="100%" width="100%" />
         </el-dialog>
+
+        <el-dialog
+          title="学生日志"
+          width="60%"
+          :visible.sync="stuLogDialog"
+          v-loading="studentLog.loading"
+          :close-on-click-modal="false"
+          element-loading-text="拼命加载中"
+        >
+          <!-- 表单 -->
+          <el-form inline :model="studentLog.formSearch">
+            <el-form-item label="操作内容">
+              <el-input
+                placeholder="请输入操作内容"
+                v-model="studentLog.formSearch.operate"
+                style="width: 180px"
+              />
+            </el-form-item>
+            <el-form-item label="操作时间">
+              <el-date-picker
+                class="input"
+                v-model="studentLog.timeRange"
+                type="datetimerange"
+                start-placeholder="开始日期"
+                range-separator="至"
+                end-placeholder="结束日期"
+                value-format="yyyy/MM/dd HH:mm:ss"
+                :clearable="false"
+                size="small"
+                @change="changeTimeRange"
+              ></el-date-picker>
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                size="small"
+                type="primary"
+                icon="el-icon-search"
+                @click="loghandleSearchBtn"
+              >
+                查询
+              </el-button>
+            </el-form-item>
+          </el-form>
+
+          <div class="block-seperator"></div>
+          <!-- 页面列表 -->
+          <el-table
+            :data="studentLog.tableData"
+            border
+            resizable
+            stripe
+            style="width: 100%;"
+          >
+            <el-table-column width="200" prop="operateTime" label="操作时间">
+            </el-table-column>
+            <el-table-column width="200" prop="operateIp" label="IP">
+            </el-table-column>
+            <el-table-column width="200" prop="operateClient" label="操作端">
+            </el-table-column>
+            <el-table-column prop="operate" label="操作内容"> </el-table-column>
+          </el-table>
+          <div class="page pull-right">
+            <el-pagination
+              v-if="studentLog.paginationShow"
+              @current-change="loghandleCurrentChange"
+              :current-page="studentLog.currentPage"
+              :page-size="studentLog.pageSize"
+              :page-sizes="[10, 20, 50, 100, 200, 300]"
+              @size-change="loghandleSizeChange"
+              layout="total, sizes, prev, pager, next, jumper"
+              :total="studentLog.total"
+            />
+          </div>
+        </el-dialog>
       </div>
     </div>
   </section>
@@ -622,7 +697,8 @@
 import {
   CORE_API,
   EXAM_WORK_API,
-  EXCHANGE_API
+  EXCHANGE_API,
+  REPORTS_API
 } from "@/constants/constants.js";
 import { mapState } from "vuex";
 
@@ -678,6 +754,7 @@ export default {
       pageSize: 10,
       total: 10,
       photoDialog: false,
+      stuLogDialog: false,
       photo: { url: "" },
 
       unbindStudentCodeDialog: false,
@@ -726,7 +803,21 @@ export default {
       },
       examStageDisabled4Search: true,
       queryExamStages4SearchLoading: false,
-      examStageList4Search: []
+      examStageList4Search: [],
+      studentLog: {
+        loading: false,
+        timeRange: [],
+        paginationShow: false,
+        formSearch: {
+          studentId: "",
+          startTime: null,
+          endTime: null
+        },
+        tableData: [],
+        currentPage: 1,
+        pageSize: 10,
+        total: 10
+      }
     };
   },
   computed: {
@@ -750,6 +841,58 @@ export default {
     }
   },
   methods: {
+    gotoOperateLog(studentId) {
+      this.studentLog.formSearch.studentId = studentId;
+      this.studentLog.tableData = [];
+      this.studentLog.total = 0;
+      this.studentLog.currentPage = 1;
+      this.stuLogDialog = true;
+      this.logsearchForm();
+    },
+    changeTimeRange(e) {
+      if (e && e.length > 0) {
+        this.studentLog.formSearch.startTime = e[0];
+        this.studentLog.formSearch.endTime = e[1];
+      } else {
+        this.studentLog.formSearch.startTime = "";
+        this.studentLog.formSearch.endTime = "";
+      }
+    },
+    loghandleSearchBtn() {
+      this.studentLog.currentPage = 1;
+      this.logsearchForm();
+    },
+    loghandleSizeChange(val) {
+      this.studentLog.pageSize = val;
+      this.studentLog.currentPage = 1;
+      this.logsearchForm();
+    },
+    loghandleCurrentChange(val) {
+      this.studentLog.currentPage = val;
+      this.logsearchForm();
+    },
+    //查询
+    logsearchForm() {
+      this.studentLog.loading = true;
+      var url =
+        REPORTS_API +
+        "/studentOperate/page/" +
+        this.studentLog.currentPage +
+        "/" +
+        this.studentLog.pageSize;
+      this.$httpWithMsg
+        .get(url, { params: this.studentLog.formSearch })
+        .then(response => {
+          this.studentLog.tableData = response.data.list;
+          this.studentLog.total = response.data.total;
+          this.studentLog.loading = false;
+
+          this.$nextTick(function() {
+            this.studentLog.paginationShow = true;
+          });
+        })
+        .finally(() => (this.studentLog.loading = false));
+    },
     resetPasswordByOrgId() {
       this.orgList4RestPassword = [];
       this.resetPasswordByOrgIdForm.orgId = null;