浏览代码

在线巡考修改

zhangjie 4 年之前
父节点
当前提交
1b623b8d76

+ 5 - 0
src/constant/constants.js

@@ -23,6 +23,11 @@ export const BOOLEAN_TYPE = {
   0: "否",
   1: "是",
 };
+// 审核状态
+export const AUDITING_STATUS = {
+  0: "通过",
+  1: "不通过",
+};
 // 是 / 否
 export const BOOLEAN_INVERSE_TYPE = {
   1: "否",

+ 48 - 6
src/features/invigilation/OnlinePatrol/OnlinePatrol.vue

@@ -232,6 +232,7 @@
       <echart-render
         :chart-data="statData"
         chart-type="barGroup"
+        :chart-click="barGroupClick"
       ></echart-render>
     </div>
   </div>
@@ -252,6 +253,7 @@ import {
 import EchartRender from "../common/EchartRender";
 import SummaryLine from "../common/SummaryLine";
 import RightOrWrong from "../common/RightOrWrong";
+import { mapState, mapMutations, mapActions } from "vuex";
 
 export default {
   name: "OnlinePatrol",
@@ -297,17 +299,23 @@ export default {
         },
       ],
       statData: [],
+      cacheDetailIds: [],
     };
   },
+  computed: {
+    ...mapState("invigilation", ["detailIds"]),
+  },
   mounted() {
     this.initData();
   },
   methods: {
+    ...mapActions("invigilation", ["updateDetailIds"]),
+    ...mapMutations("invigilation", ["setDetailIds"]),
     async initData() {
       await this.getExamBatchList();
       this.filter.examId = this.examBatchs[0] ? this.examBatchs[0].id : "";
       if (!this.filter.examId) return;
-      this.toPage(1);
+      this.toSearch();
       this.getExamActivityRoomList();
     },
     async getList() {
@@ -328,9 +336,21 @@ export default {
       this.current = page;
       this.getList();
     },
-    toSearch() {
-      this.toPage(1);
+    async toSearch() {
+      this.current = 1;
+      await this.getList();
+
       this.getPatrolReportList();
+
+      if (this.total > this.size) {
+        this.updateDetailIds({
+          filterData: this.filter,
+          fetchFunc: patrolList,
+        });
+      } else {
+        const ids = this.dataList.map((item) => item.examRecordId);
+        this.setDetailIds([...new Set(ids)]);
+      }
     },
     async getExamBatchList() {
       const res = await examBatchList();
@@ -351,8 +371,8 @@ export default {
     },
     toDetail(row) {
       this.$router.push({
-        name: "PatrolExamDetail",
-        params: { examId: row.examId },
+        name: "PatrolWarningDetail",
+        params: { recordId: row.examRecordId },
       });
     },
     async getPatrolReportList() {
@@ -389,13 +409,35 @@ export default {
           : a[statItem.key] - b[statItem.key];
       });
     },
+    barGroupClick(params) {
+      if (params.componentType !== "series") return;
+
+      this.cacheDetailIds = [...this.detailIds];
+      const row = this.statData[params.dataIndex];
+      console.log(row);
+      this.$router.push({
+        name: "PatrolExamDetail",
+        params: {
+          examId: this.filter.examId,
+          roomCode: row.roomCode,
+          roomName: row.roomName,
+        },
+      });
+    },
   },
   beforeRouteLeave(to, from, next) {
-    if (to.name !== "PatrolExamDetail") {
+    if (to.name !== "PatrolExamDetail" && to.name !== "PatrolWarningDetail") {
       this.$destroy();
     }
     next();
   },
+  beforeRouteEnter(to, from, next) {
+    if (from.name === "PatrolExamDetail") {
+      next((vm) => vm.$nextTick(() => vm.setDetailIds(vm.cacheDetailIds)));
+    } else {
+      next();
+    }
+  },
 };
 </script>
 

+ 599 - 0
src/features/invigilation/OnlinePatrol/PatrolExamDetail.vue

@@ -0,0 +1,599 @@
+<template>
+  <div class="realtime-monitoring">
+    <div class="realtime-top clear-float">
+      <p v-if="curExamBatch.name">
+        考场名称:{{ curExamBatch.name + "-" }}{{ roomName }}
+      </p>
+      <text-clock></text-clock>
+    </div>
+
+    <div class="part-box-head">
+      <div class="part-box-head-left">
+        <h1>
+          <i class="realtime-back el-icon-arrow-left" @click="goBack"></i>
+          查看考场
+        </h1>
+      </div>
+      <div class="part-box-head-right">
+        <div
+          :class="[
+            'realtime-switch',
+            { 'realtime-switch-warning': hasNewWarning },
+          ]"
+        >
+          <div
+            :class="[
+              'realtime-switch-item',
+              { 'realtime-switch-item-act': pageType === '0' },
+            ]"
+            @click="pageTypeChange('0')"
+          >
+            <i class="el-icon-s-fold"></i><span>列表</span>
+          </div>
+          <div
+            :class="[
+              'realtime-switch-item',
+              { 'realtime-switch-item-act': pageType === '1' },
+            ]"
+            @click="pageTypeChange('1')"
+          >
+            <i class="el-icon-video-camera"></i><span>视频</span>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="part-filter">
+      <div class="part-filter-info">
+        <summary-line
+          class="part-filter-info-main"
+          data-type="trouble"
+          :exam-id="filter.examId"
+          ref="SummaryLine"
+        ></summary-line>
+      </div>
+
+      <div class="part-filter-form">
+        <el-form ref="FilterForm" label-position="left" inline>
+          <el-form-item>
+            <el-select
+              v-model="filter.paperDownload"
+              placeholder="试题下载"
+              clearable
+            >
+              <el-option
+                v-for="(val, key) in BOOLEAN_INVERSE_TYPE"
+                :key="key"
+                :value="key * 1"
+                :label="val"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-select v-model="filter.status" placeholder="考试状态" clearable>
+              <el-option
+                v-for="(val, key) in STUDENT_ONLINE_STATUS"
+                :key="key"
+                :value="key"
+                :label="val"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-select
+              v-model="filter.monitorStatusSource"
+              placeholder="通讯故障"
+              clearable
+            >
+              <el-option
+                v-for="(val, key) in BOOLEAN_TYPE"
+                :key="key"
+                :value="key * 1"
+                :label="val"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="预警量">
+            <el-input-number
+              style="width: 52px;"
+              v-model.trim="filter.minWarningCount"
+              placeholder="下限"
+              :controls="false"
+            ></el-input-number>
+            <span class="line-split">-</span>
+            <el-input-number
+              style="width: 52px;"
+              v-model.trim="filter.maxWarningCount"
+              placeholder="上限"
+              :controls="false"
+            ></el-input-number>
+          </el-form-item>
+          <el-form-item>
+            <el-input
+              v-model.trim="filter.name"
+              placeholder="姓名"
+              clearable
+            ></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-input
+              v-model.trim="filter.identity"
+              placeholder="证件号"
+              clearable
+            ></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="toSearch">查询</el-button>
+          </el-form-item>
+        </el-form>
+
+        <div class="part-filter-form-action">
+          <el-dropdown
+            @command="viewingAngleChange"
+            style="margin-right: 10px;"
+            trigger="click"
+            v-if="pageType === '1'"
+          >
+            <el-button type="primary"
+              >切换视频源<i class="el-icon-arrow-down el-icon--right"></i
+            ></el-button>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item
+                v-for="item in viewingAngles"
+                :key="item.code"
+                :command="item"
+              >
+                <span
+                  :class="{
+                    'color-primary': item.code === curViewingAngle.code,
+                  }"
+                >
+                  {{ item.name }}
+                </span>
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </div>
+      </div>
+    </div>
+
+    <el-table ref="TableList" :data="dataList" v-if="pageType === '0'">
+      <el-table-column prop="identity" label="证件号"></el-table-column>
+      <el-table-column prop="name" label="姓名"></el-table-column>
+      <el-table-column prop="courseName" label="科目名称"></el-table-column>
+      <el-table-column prop="courseCode" label="科目代码"></el-table-column>
+      <el-table-column prop="remainTime" label="剩余时间"></el-table-column>
+      <el-table-column prop="paperDownload" label="试题下载">
+        <span slot-scope="scope">
+          {{ BOOLEAN_INVERSE_TYPE[scope.row.paperDownload] }}
+        </span>
+      </el-table-column>
+      <el-table-column prop="status" label="考试状态"></el-table-column>
+      <el-table-column prop="progress" label="进度">
+        <span slot-scope="scope">{{ scope.row.progress }}%</span>
+      </el-table-column>
+      <el-table-column prop="clientWebsocketStatus" label="通讯">
+        <template slot-scope="scope">
+          <right-or-wrong
+            :status="CLIENT_WEBSOCKET_STATUS[scope.row.clientWebsocketStatus]"
+          ></right-or-wrong>
+        </template>
+      </el-table-column>
+      <el-table-column
+        v-for="source in viewingAngles"
+        :key="source.param"
+        :prop="source.param"
+        :label="`${source.name}通讯`"
+      >
+        <template slot-scope="scope">
+          <right-or-wrong
+            :status="MONITOR_STATUS_SOURCE[scope.row[source.param]]"
+          ></right-or-wrong>
+        </template>
+      </el-table-column>
+      <el-table-column
+        prop="clientCurrentIp"
+        label="IP"
+        v-if="curExamBatch.enableIpLimit"
+      >
+      </el-table-column>
+      <el-table-column prop="updateTime" label="更新时间">
+        <span slot-scope="scope">
+          {{ scope.row.updateTime | datetimeFilter }}
+        </span>
+      </el-table-column>
+      <el-table-column prop="warningCount" label="预警数"></el-table-column>
+      <el-table-column prop="breachStatus" label="违纪">
+        <template slot-scope="scope">
+          <span :class="{ 'color-danger': !scope.row.breachStatus }">
+            {{ !scope.row.breachStatus ? "违纪" : "正常" }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="125" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            :class="[
+              'btn-table-icon',
+              { 'warn-new-tips': scope.row.warningNew },
+            ]"
+            type="primary"
+            icon="icon icon-view"
+            @click="toDetail(scope.row)"
+            >详情</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="invigilation-student-list" v-else>
+      <div
+        class="invigilation-student-item"
+        v-for="item in dataList"
+        :key="item.examRecordId"
+      >
+        <invigilation-student :data="item"></invigilation-student>
+      </div>
+    </div>
+
+    <div class="part-page">
+      <el-pagination
+        background
+        hide-on-single-page
+        layout="prev, pager, next,total,jumper"
+        :current-page="current"
+        :total="total"
+        :page-size="size"
+        @current-change="toPage"
+      >
+      </el-pagination>
+    </div>
+  </div>
+</template>
+
+<script>
+import { invigilateVideoList, examMonitorBatchList } from "@/api/invigilation";
+import RightOrWrong from "../common/RightOrWrong";
+import InvigilationStudent from "../common/InvigilationStudent";
+import SummaryLine from "../common/SummaryLine";
+import TextClock from "../common/TextClock";
+import {
+  BOOLEAN_TYPE,
+  VIDEO_SOURCE_TYPE,
+  BOOLEAN_INVERSE_TYPE,
+  STUDENT_ONLINE_STATUS,
+  CLIENT_WEBSOCKET_STATUS,
+  MONITOR_STATUS_SOURCE,
+} from "@/constant/constants";
+import { mapState, mapMutations, mapActions } from "vuex";
+
+export default {
+  name: "realtime-monitoring",
+  components: {
+    RightOrWrong,
+    InvigilationStudent,
+    SummaryLine,
+    TextClock,
+  },
+  data() {
+    return {
+      roomCode: this.$route.params.roomCode,
+      roomName: this.$route.params.roomName,
+      filter: {
+        examId: this.$route.params.examId,
+        paperDownload: null,
+        status: null,
+        monitorStatusSource: null,
+        monitorVideoSource: null,
+        name: null,
+        identity: null,
+        maxWarningCount: undefined,
+        minWarningCount: undefined,
+      },
+      BOOLEAN_TYPE,
+      VIDEO_SOURCE_TYPE,
+      BOOLEAN_INVERSE_TYPE,
+      STUDENT_ONLINE_STATUS,
+      CLIENT_WEBSOCKET_STATUS,
+      MONITOR_STATUS_SOURCE,
+      hasNewWarning: false,
+      loopRunning: false,
+      loopSetTs: [],
+      curExamBatch: {},
+      curViewingAngle: {},
+      current: 1,
+      total: 0,
+      size: 24,
+      exams: [],
+      subjects: [],
+      pageType: "0",
+      dataList: [],
+      videoSourceStatusParams: {
+        CLIENT_CAMERA: "cameraMonitorStatusSource",
+        CLIENT_SCREEN: "screenMonitorStatusSource",
+        MOBILE_FIRST: "mobileFirstMonitorStatusSource",
+        MOBILE_SECOND: "mobileSecondMonitorStatusSource",
+      },
+      viewingAngles: [],
+    };
+  },
+  computed: {
+    ...mapState("invigilation", ["liveDomains"]),
+  },
+  mounted() {
+    this.initData();
+  },
+  methods: {
+    ...mapActions("invigilation", ["updateDetailIds"]),
+    ...mapMutations("invigilation", ["setDetailIds"]),
+    async initData() {
+      await this.getExamDetail();
+      if (this.curExamBatch.monitorVideoSource) {
+        this.viewingAngles = this.curExamBatch.monitorVideoSource
+          .split(",")
+          .map((item) => {
+            return {
+              code: item,
+              name: this.VIDEO_SOURCE_TYPE[item],
+              param: this.videoSourceStatusParams[item],
+            };
+          });
+      } else {
+        this.viewingAngles = [];
+      }
+      this.curViewingAngle = this.viewingAngles[0] || {};
+      this.filter.monitorVideoSource = this.curViewingAngle.code || "";
+
+      this.toSearch();
+
+      // 正在考试的考试,开启定时更新;
+      if (this.curExamBatch.isExaming) {
+        this.loopRunning = true;
+        this.clearLoopSetTs();
+        this.loopSetTs.push(
+          setTimeout(() => {
+            this.timerUpdatePage();
+          }, 10 * 1000)
+        );
+      } else {
+        this.loopRunning = false;
+        this.clearLoopSetTs();
+      }
+    },
+    clearLoopSetTs() {
+      if (!this.loopSetTs.length) return;
+      this.loopSetTs.forEach((sett) => {
+        clearTimeout(sett);
+      });
+      this.loopSetTs = [];
+    },
+    async timerUpdatePage() {
+      this.clearLoopSetTs();
+      if (!this.loopRunning) return;
+
+      let fetchAll = [this.getList()];
+      if (this.$refs.SummaryLine)
+        fetchAll.push(this.$refs.SummaryLine.initData());
+      await Promise.all(fetchAll).catch(() => {});
+
+      this.loopSetTs.push(
+        setTimeout(() => {
+          this.timerUpdatePage();
+        }, 10 * 1000)
+      );
+    },
+    async getExamDetail() {
+      const res = await examMonitorBatchList({
+        id: this.filter.examId,
+        pageNumber: 1,
+        pageSize: 100,
+      });
+      const dnow = Date.now();
+      this.curExamBatch = res.data.data.records[0];
+      this.curExamBatch.isExaming =
+        dnow > this.curExamBatch.startTime && dnow < this.curExamBatch.endTime;
+    },
+    pageTypeChange(pageType) {
+      this.pageType = pageType;
+      this.multipleSelection = [];
+    },
+    viewingAngleChange(data) {
+      if (data.code === this.curViewingAngle.code) return;
+      this.curViewingAngle = data;
+      this.filter.monitorVideoSource = data.code;
+      this.dataList = [];
+      this.getList();
+    },
+    async getList() {
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size,
+      };
+
+      const res = await invigilateVideoList(datas);
+      const domainLen = this.liveDomains.length;
+      this.dataList = res.data.data.records.map((item, index) => {
+        const domain = domainLen ? this.liveDomains[index % domainLen] : "";
+        item.label = `${item.identity} ${item.courseName}(${item.courseCode}) ${item.name}`;
+        item.liveUrl = item.monitorLiveUrl
+          ? `${domain}/live/${item.monitorLiveUrl.toLowerCase()}.flv`
+          : "";
+        item.progress = item.progress ? Math.round(item.progress * 100) : 0;
+        return item;
+      });
+
+      this.hasNewWarning = this.dataList.some((item) => item.warningNew);
+      this.total = res.data.data.total;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    async toSearch() {
+      this.current = 1;
+      await this.getList();
+
+      if (this.total > this.size) {
+        this.updateDetailIds({
+          filterData: this.filter,
+          fetchFunc: invigilateVideoList,
+        });
+      } else {
+        const ids = this.dataList.map((item) => item.examRecordId);
+        this.setDetailIds([...new Set(ids)]);
+      }
+    },
+    toDetail(row) {
+      this.$router.push({
+        name: "PatrolWarningDetail",
+        params: { recordId: row.examRecordId },
+      });
+    },
+    goBack() {
+      window.history.go(-1);
+    },
+  },
+  beforeDestroy() {
+    this.loopRunning = false;
+    this.clearLoopSetTs();
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.realtime-top {
+  position: relative;
+  padding: 9px 20px 9px 73px;
+  background: rgba(24, 134, 254, 1);
+  border-radius: 6px;
+  color: #fff;
+  margin-bottom: 30px;
+  line-height: 32px;
+
+  &::before {
+    content: "";
+    display: block;
+    position: absolute;
+    width: 59px;
+    height: 49px;
+    left: 13px;
+    top: 0;
+    background-image: url(../../../assets/bg-stars.png);
+    background-size: 100% 100%;
+  }
+
+  > p {
+    float: left;
+    margin: 0;
+  }
+  > p:first-child {
+    margin-right: 40px;
+    min-width: 150px;
+  }
+  .realtime-top-select {
+    display: inline-block;
+    position: relative;
+    height: 32px;
+    line-height: 32px;
+    border-radius: 6px;
+    min-width: 200px;
+    background-color: #fff;
+    color: #1886fe;
+    padding: 0 26px 0 12px;
+    cursor: pointer;
+
+    > i {
+      position: absolute;
+      right: 8px;
+      top: 9px;
+    }
+  }
+  .text-clock {
+    float: right;
+    font-size: 12px;
+    opacity: 0.8;
+  }
+}
+.realtime-switch {
+  font-size: 0;
+  &-warning {
+    .realtime-switch-item {
+      &::before {
+        content: "";
+        display: block;
+        position: absolute;
+        width: 10px;
+        height: 10px;
+        top: -5px;
+        right: -5px;
+        border-radius: 50%;
+        border: 2px solid #fff;
+        background: #fe5863;
+        z-index: 9;
+      }
+    }
+  }
+
+  &-item {
+    display: inline-block;
+    vertical-align: top;
+    font-size: 12px;
+    color: #8c94ac;
+    background: #fff;
+    line-height: 18px;
+    padding: 5px 14px;
+    position: relative;
+    cursor: pointer;
+
+    > i {
+      margin-right: 5px;
+    }
+    &:first-child {
+      border-radius: 6px 0px 0px 6px;
+    }
+    &:last-child {
+      border-radius: 0px 6px 6px 0px;
+    }
+
+    &-act {
+      color: #fff;
+      background: #5fc9fa;
+    }
+  }
+}
+.invigilation-student-list {
+  background: #ffffff;
+  border-radius: 6px;
+  padding: 10px 10px;
+  font-size: 0;
+  min-height: 200px;
+  .invigilation-student-item {
+    font-size: 14px;
+    display: inline-block;
+    vertical-align: top;
+    padding: 10px;
+    width: 25%;
+  }
+}
+.warn-new-tips {
+  position: relative;
+
+  &::after {
+    content: "";
+    display: block;
+    position: absolute;
+    width: 32px;
+    height: 16px;
+    right: -32px;
+    top: 0;
+    background-image: url(../../../assets/icon-new-tips.png);
+    background-size: 100% 100%;
+  }
+}
+.realtime-back {
+  cursor: pointer;
+  &:hover {
+    color: #1886fe;
+  }
+}
+</style>

+ 1 - 0
src/features/invigilation/OnlinePatrol/PatrolWarningDetail.vue

@@ -265,6 +265,7 @@ export default {
           "EYE_CLOSE_ERROR",
           "LIVENESS_ACTION_ERROR",
           "REALNESS",
+          "NONE",
         ],
         exception: [
           "NET_TIME_OUT",

+ 18 - 25
src/features/invigilation/RealtimeMonitoring/RealtimeMonitoring.vue

@@ -1,7 +1,9 @@
 <template>
   <div class="realtime-monitoring">
     <div class="realtime-top clear-float">
-      <p>考场名称:{{ curExamBatch.name }}</p>
+      <p :title="curExamBatch.roomName">
+        考场名称:{{ curExamBatch.roomName }}
+      </p>
       <p class="realtime-top-select" @click="$refs.ExamBatchDialog.open()">
         <span>{{ curExamBatch.label || "请选择批次" }}</span>
         <i class="el-icon-caret-bottom"></i>
@@ -11,7 +13,7 @@
 
     <div class="part-box-head">
       <div class="part-box-head-left">
-        <h1>{{ IS_INSPECTION ? "查看考场" : "实时监控台" }}</h1>
+        <h1>实时监控台</h1>
       </div>
       <div class="part-box-head-right">
         <div
@@ -50,7 +52,7 @@
           :exam-id="filter.examId"
           ref="SummaryLine"
         ></summary-line>
-        <div class="part-filter-info-sub" v-if="!this.IS_INSPECTION">
+        <div class="part-filter-info-sub">
           <el-badge
             :value="communicationCount"
             :max="99"
@@ -170,14 +172,12 @@
             type="primary"
             icon="icon icon-handle"
             @click="finishInvigilation"
-            v-if="!this.IS_INSPECTION"
             >手动收卷</el-button
           > -->
           <el-button
             type="danger"
             icon="icon icon-over"
             @click="finishInvigilationExam"
-            v-if="!this.IS_INSPECTION"
             >结束监考</el-button
           >
         </div>
@@ -333,6 +333,7 @@ export default {
   data() {
     return {
       initExamid: this.$route.params.examId,
+      initRoomCode: this.$route.params.roomCode,
       filter: {
         examId: "",
         paperDownload: null,
@@ -350,7 +351,6 @@ export default {
       STUDENT_ONLINE_STATUS,
       CLIENT_WEBSOCKET_STATUS,
       MONITOR_STATUS_SOURCE,
-      IS_INSPECTION: false,
       hasNewWarning: false,
       loopRunning: false,
       loopSetTs: [],
@@ -377,13 +377,6 @@ export default {
     };
   },
   created() {
-    this.loopRunning = true;
-    const user = this.$store.state.user;
-    this.IS_INSPECTION =
-      user.roleCodes.includes("INSPECTION") &&
-      !user.roleCodes.includes("INVIGILATE");
-    if (this.IS_INSPECTION) return;
-
     window.inviligateWarning = (id) => {
       this.toDetail({ examRecordId: id });
     };
@@ -408,10 +401,10 @@ export default {
       let fetchAll = [this.getList()];
       if (this.$refs.SummaryLine)
         fetchAll.push(this.$refs.SummaryLine.initData());
-      if (!this.IS_INSPECTION) {
-        fetchAll.push(this.getMonitorCallCount());
-        fetchAll.push(this.fetchWarningNotice());
-      }
+
+      fetchAll.push(this.getMonitorCallCount());
+      fetchAll.push(this.fetchWarningNotice());
+
       await Promise.all(fetchAll).catch(() => {});
 
       this.loopSetTs.push(
@@ -442,10 +435,9 @@ export default {
 
       this.toSearch();
 
-      if (!this.IS_INSPECTION) {
-        this.getMonitorCallCount();
-        this.fetchWarningNotice();
-      }
+      this.getMonitorCallCount();
+      this.fetchWarningNotice();
+
       // 正在考试的考试,开启定时更新;
       if (examBatch.isExaming) {
         this.loopRunning = true;
@@ -599,11 +591,8 @@ export default {
       });
     },
     toDetail(row) {
-      const routerName = this.IS_INSPECTION
-        ? "PatrolWarningDetail"
-        : "WarningDetail";
       this.$router.push({
-        name: routerName,
+        name: "WarningDetail",
         params: { recordId: row.examRecordId },
       });
     },
@@ -645,6 +634,10 @@ export default {
   > p:first-child {
     margin-right: 40px;
     min-width: 150px;
+    max-width: 300px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
   }
   .realtime-top-select {
     display: inline-block;

+ 9 - 0
src/features/invigilation/RealtimeMonitoring/VideoCommunication.vue

@@ -11,6 +11,12 @@
           <el-radio-button label="START">待处理</el-radio-button>
           <el-radio-button label="STOP">已处理</el-radio-button>
         </el-radio-group>
+        <el-button
+          style="vertical-align: top; margin-left: 10px;"
+          icon="el-icon-arrow-left"
+          @click="goBack"
+          >返回</el-button
+        >
       </div>
     </div>
     <div class="student-list">
@@ -284,6 +290,9 @@ export default {
       this.userMonitor = {};
       this.dialogVisible = false;
     },
+    goBack() {
+      window.history.go(-1);
+    },
   },
   beforeDestroy() {
     this.loopRunning = false;

+ 1 - 0
src/features/invigilation/RealtimeMonitoring/WarningDetail.vue

@@ -435,6 +435,7 @@ export default {
           "EYE_CLOSE_ERROR",
           "LIVENESS_ACTION_ERROR",
           "REALNESS",
+          "NONE",
         ],
         exception: [
           "NET_TIME_OUT",

+ 7 - 6
src/features/invigilation/ReexamChecked/ReexamChecked.vue

@@ -51,14 +51,14 @@
           </el-form-item>
           <el-form-item>
             <el-select
-              v-model="filter.reason"
-              placeholder="请选择申请理由"
+              v-model="filter.auditingStatus"
+              placeholder="请选择审核结果"
               clearable
             >
               <el-option
-                v-for="(val, key) in REEXAM_REASON"
+                v-for="(val, key) in AUDITING_STATUS"
                 :key="key"
-                :value="key"
+                :value="key * 1"
                 :label="val"
               ></el-option>
             </el-select>
@@ -173,7 +173,7 @@ import {
   examActivityRoomList,
   reexamCheckedList,
 } from "@/api/invigilation";
-import { REEXAM_REASON } from "@/constant/constants";
+import { AUDITING_STATUS } from "@/constant/constants";
 import CheckReexamDialog from "../ReexamPending/CheckReexamDialog";
 import { mapState, mapActions, mapMutations } from "vuex";
 
@@ -186,13 +186,14 @@ export default {
         examId: null,
         roomCode: null,
         courseCode: null,
+        auditingStatus: null,
         name: "",
         identity: "",
         applyName: "",
         reasonStartTime: "",
         reasonEndTime: "",
       },
-      REEXAM_REASON,
+      AUDITING_STATUS,
       current: 1,
       total: 0,
       size: 10,

+ 39 - 33
src/features/invigilation/common/EchartRender.vue

@@ -5,6 +5,7 @@
       :init-options="initOptions"
       autoresize
       v-if="chartOption"
+      @click="chartClick"
       ref="vueChart"
     ></vue-charts>
     <p class="chart-none" v-else>暂无数据</p>
@@ -62,6 +63,10 @@ export default {
         ];
       },
     },
+    chartClick: {
+      type: Function,
+      default() {},
+    },
   },
   data() {
     return {
@@ -533,14 +538,13 @@ export default {
           name: "通讯故障",
           color: "#FE5863",
         },
-        waiting: {
+        warning: {
           name: "预警数",
           color: "#FECA57",
         },
       };
 
       const legendData = Object.entries(PLACE_STATES).map((el) => el[1].name);
-      const dataZoomRange = Math.floor((10 / dataList.length) * 100);
 
       let seriesList = [];
       let yAxisLabels = dataList.map((item) => item.name);
@@ -563,7 +567,7 @@ export default {
         });
       });
 
-      return {
+      let options = {
         tooltip: {
           trigger: "axis",
           axisPointer: {
@@ -590,35 +594,8 @@ export default {
           top: "20%",
           containLabel: true,
         },
-        dataZoom: [
-          {
-            type: "slider",
-            xAxisIndex: [0],
-            bottom: "0%",
-            start: 0,
-            end: dataZoomRange,
-            minSpan: dataZoomRange,
-            maxSpan: dataZoomRange,
-            backgroundColor: "transparent",
-            fillerColor: "#8C94AC",
-            borderColor: "transparent",
-            handleSize: "0%",
-            showDetail: false,
-            throttle: 200,
-            height: 5,
-          },
-          {
-            type: "inside",
-            xAxisIndex: [0],
-            start: 0,
-            end: dataZoomRange,
-          },
-        ],
         yAxis: {
           type: "value",
-          min: 0,
-          max: 1,
-          interval: 0.25,
           position: "top",
           axisLine: {
             lineStyle: {
@@ -634,9 +611,9 @@ export default {
           axisLabel: {
             color: "#8C94AC",
             fontSize: 14,
-            formatter: function (value) {
-              return Math.round(value * 100) + "%";
-            },
+            // formatter: function (value) {
+            //   return Math.round(value * 100) + "%";
+            // },
           },
         },
         xAxis: {
@@ -667,6 +644,35 @@ export default {
         },
         series: seriesList,
       };
+
+      if (dataList.length > 10) {
+        const dataZoomRange = Math.floor((10 / dataList.length) * 100);
+        options.dataZoom = [
+          {
+            type: "slider",
+            xAxisIndex: [0],
+            bottom: "0%",
+            start: 0,
+            end: dataZoomRange,
+            minSpan: dataZoomRange,
+            maxSpan: dataZoomRange,
+            backgroundColor: "transparent",
+            fillerColor: "#8C94AC",
+            borderColor: "transparent",
+            handleSize: "0%",
+            showDetail: false,
+            throttle: 200,
+            height: 5,
+          },
+          {
+            type: "inside",
+            xAxisIndex: [0],
+            start: 0,
+            end: dataZoomRange,
+          },
+        ];
+      }
+      return options;
     },
     splitStrByStep(str, step = 2) {
       if (!step) return str;

+ 2 - 2
src/router/invigilation.js

@@ -30,11 +30,11 @@ const routes = [
       ),
   },
   {
-    path: "online-patrol/exam-detail/:examId",
+    path: "online-patrol/exam-detail/:examId/:roomCode/:roomName",
     name: "PatrolExamDetail",
     component: () =>
       import(
-        /* webpackChunkName: "inspection" */ "../features/invigilation/RealtimeMonitoring/RealtimeMonitoring"
+        /* webpackChunkName: "inspection" */ "../features/invigilation/OnlinePatrol/PatrolExamDetail"
       ),
     meta: {
       relate: "OnlinePatrol",

+ 1 - 0
src/views/Layout/Layout.vue

@@ -56,6 +56,7 @@ export default {
 
       if (name === "Invigilation") {
         this.initNavTips();
+        if (!this.loopFuncList.length) return;
         this.loopRunning = true;
         this.timerUpdatePage();
       } else {