|
@@ -1,20 +1,13 @@
|
|
<template>
|
|
<template>
|
|
<div class="realtime-monitoring">
|
|
<div class="realtime-monitoring">
|
|
<div class="realtime-top clear-float">
|
|
<div class="realtime-top clear-float">
|
|
- <p v-if="examName">考场名称:{{ examName }}</p>
|
|
|
|
|
|
+ <p>考场名称:{{ curExamBatch.name }}</p>
|
|
<div
|
|
<div
|
|
class="el-select el-select--small"
|
|
class="el-select el-select--small"
|
|
@click="$refs.ExamBatchDialog.open()"
|
|
@click="$refs.ExamBatchDialog.open()"
|
|
>
|
|
>
|
|
<div class="el-input el-input--small el-input--suffix">
|
|
<div class="el-input el-input--small el-input--suffix">
|
|
- <input
|
|
|
|
- type="text"
|
|
|
|
- readonly="readonly"
|
|
|
|
- autocomplete="off"
|
|
|
|
- placeholder="请选择批次"
|
|
|
|
- v-model="curExamBatch.label"
|
|
|
|
- class="el-input__inner"
|
|
|
|
- />
|
|
|
|
|
|
+ <div class="el-input__inner">{{ curExamBatch.label }}</div>
|
|
<span class="el-input__suffix">
|
|
<span class="el-input__suffix">
|
|
<span class="el-input__suffix-inner"
|
|
<span class="el-input__suffix-inner"
|
|
><i
|
|
><i
|
|
@@ -23,7 +16,7 @@
|
|
></span>
|
|
></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- <p>现在是2020年6月2日 星期二 上午 09:30:12</p>
|
|
|
|
|
|
+ <text-clock></text-clock>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="part-box-head">
|
|
<div class="part-box-head">
|
|
@@ -31,85 +24,41 @@
|
|
<h1>实时监控台</h1>
|
|
<h1>实时监控台</h1>
|
|
</div>
|
|
</div>
|
|
<div class="part-box-head-right">
|
|
<div class="part-box-head-right">
|
|
- <el-radio-group
|
|
|
|
- size="small"
|
|
|
|
- v-model="pageType"
|
|
|
|
- @change="pageTypeChange"
|
|
|
|
|
|
+ <div
|
|
|
|
+ :class="[
|
|
|
|
+ 'realtime-switch',
|
|
|
|
+ { 'realtime-switch-warning': hasNewWarning },
|
|
|
|
+ ]"
|
|
>
|
|
>
|
|
- <el-radio-button label="0">
|
|
|
|
- <i class="el-icon-s-fold"></i>列表</el-radio-button
|
|
|
|
|
|
+ <div
|
|
|
|
+ :class="[
|
|
|
|
+ 'realtime-switch-item',
|
|
|
|
+ { 'realtime-switch-item-act': pageType === '0' },
|
|
|
|
+ ]"
|
|
|
|
+ @click="pageTypeChange('0')"
|
|
>
|
|
>
|
|
- <el-radio-button label="1"
|
|
|
|
- ><i class="el-icon-video-camera"></i> 视频</el-radio-button
|
|
|
|
|
|
+ <i class="el-icon-s-fold"></i><span>列表</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ :class="[
|
|
|
|
+ 'realtime-switch-item',
|
|
|
|
+ { 'realtime-switch-item-act': pageType === '1' },
|
|
|
|
+ ]"
|
|
|
|
+ @click="pageTypeChange('1')"
|
|
>
|
|
>
|
|
- </el-radio-group>
|
|
|
|
|
|
+ <i class="el-icon-video-camera"></i><span>视频</span>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="part-filter">
|
|
<div class="part-filter">
|
|
<div class="part-filter-info">
|
|
<div class="part-filter-info">
|
|
- <div class="part-filter-info-main summary-line">
|
|
|
|
- <p class="summary-line-item">
|
|
|
|
- <i class="icon icon-users"></i>
|
|
|
|
- <el-popover
|
|
|
|
- placement="top-start"
|
|
|
|
- width="200"
|
|
|
|
- trigger="hover"
|
|
|
|
- content="全部应考:参加考试的全部考生。"
|
|
|
|
- >
|
|
|
|
- <span class="line-name" slot="reference">全部应考</span>
|
|
|
|
- </el-popover>
|
|
|
|
- <span>{{ examPropData.allCount }}人</span>
|
|
|
|
- </p>
|
|
|
|
- <p class="summary-line-item">
|
|
|
|
- <i class="line-point line-point-info"></i>
|
|
|
|
- <el-popover
|
|
|
|
- placement="top-start"
|
|
|
|
- width="200"
|
|
|
|
- trigger="hover"
|
|
|
|
- content="已登录:已成功登录考生端的考生。"
|
|
|
|
- >
|
|
|
|
- <span class="line-name" slot="reference">已登录</span>
|
|
|
|
- </el-popover>
|
|
|
|
- <span>{{ examPropData.loginCount }}人</span>
|
|
|
|
- </p>
|
|
|
|
- <p class="summary-line-item">
|
|
|
|
- <i class="line-point line-point-success"></i>
|
|
|
|
- <el-popover
|
|
|
|
- placement="top-start"
|
|
|
|
- width="200"
|
|
|
|
- trigger="hover"
|
|
|
|
- content="已待考:已进入待考界面等待开考的考生。"
|
|
|
|
- >
|
|
|
|
- <span class="line-name" slot="reference">已待考</span>
|
|
|
|
- </el-popover>
|
|
|
|
- <span>{{ examPropData.prepareCount }}人</span>
|
|
|
|
- </p>
|
|
|
|
- <p class="summary-line-item">
|
|
|
|
- <i class="line-point line-point-primary"></i>
|
|
|
|
- <el-popover
|
|
|
|
- placement="top-start"
|
|
|
|
- width="200"
|
|
|
|
- trigger="hover"
|
|
|
|
- content="考试中:正在答题的考生。"
|
|
|
|
- >
|
|
|
|
- <span class="line-name" slot="reference">考试中</span>
|
|
|
|
- </el-popover>
|
|
|
|
- <span>{{ examPropData.notComplete }}人</span>
|
|
|
|
- </p>
|
|
|
|
- <p class="summary-line-item">
|
|
|
|
- <i class="line-point line-point-danger"></i>
|
|
|
|
- <el-popover
|
|
|
|
- placement="top-start"
|
|
|
|
- width="200"
|
|
|
|
- trigger="hover"
|
|
|
|
- content="通讯故障:考生端出现断网、断电、软硬件故障等异常导致考生端与监考端无法正常连接的考生。"
|
|
|
|
- >
|
|
|
|
- <span class="line-name" slot="reference">通讯故障</span>
|
|
|
|
- </el-popover>
|
|
|
|
- <span>1人</span>
|
|
|
|
- </p>
|
|
|
|
- </div>
|
|
|
|
|
|
+ <summary-line
|
|
|
|
+ class="part-filter-info-main"
|
|
|
|
+ data-type="trouble"
|
|
|
|
+ :exam-id="filter.examId"
|
|
|
|
+ ></summary-line>
|
|
<div class="part-filter-info-sub">
|
|
<div class="part-filter-info-sub">
|
|
<el-button
|
|
<el-button
|
|
icon="el-icon-phone-outline"
|
|
icon="el-icon-phone-outline"
|
|
@@ -228,7 +177,8 @@
|
|
@selection-change="handleSelectionChange"
|
|
@selection-change="handleSelectionChange"
|
|
v-if="pageType === '0'"
|
|
v-if="pageType === '0'"
|
|
>
|
|
>
|
|
- <el-table-column type="selection" width="55"> </el-table-column>
|
|
|
|
|
|
+ <el-table-column type="selection" width="55" align="center">
|
|
|
|
+ </el-table-column>
|
|
<el-table-column prop="identity" label="证件号"></el-table-column>
|
|
<el-table-column prop="identity" label="证件号"></el-table-column>
|
|
<el-table-column prop="name" 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="courseName" label="科目名称"></el-table-column>
|
|
@@ -261,7 +211,7 @@
|
|
<div class="invigilation-student-list" v-else>
|
|
<div class="invigilation-student-list" v-else>
|
|
<div
|
|
<div
|
|
class="invigilation-student-item"
|
|
class="invigilation-student-item"
|
|
- v-for="item in dataList"
|
|
|
|
|
|
+ v-for="item in videoList"
|
|
:key="item.examStudentId"
|
|
:key="item.examStudentId"
|
|
>
|
|
>
|
|
<invigilation-student :data="item"></invigilation-student>
|
|
<invigilation-student :data="item"></invigilation-student>
|
|
@@ -280,10 +230,17 @@
|
|
</el-pagination>
|
|
</el-pagination>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
+ <!-- 考试批次选择 -->
|
|
<exam-batch-dialog
|
|
<exam-batch-dialog
|
|
@confirm="examChange"
|
|
@confirm="examChange"
|
|
ref="ExamBatchDialog"
|
|
ref="ExamBatchDialog"
|
|
></exam-batch-dialog>
|
|
></exam-batch-dialog>
|
|
|
|
+ <!-- 手动收卷 -->
|
|
|
|
+ <handle-rollup-dialog
|
|
|
|
+ :data-list="multipleSelection"
|
|
|
|
+ @modified="rollupOver"
|
|
|
|
+ ref="handleRollupDialog"
|
|
|
|
+ ></handle-rollup-dialog>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
@@ -291,20 +248,27 @@
|
|
import {
|
|
import {
|
|
invigilateList,
|
|
invigilateList,
|
|
invigilateVideoList,
|
|
invigilateVideoList,
|
|
- invigilateFinish,
|
|
|
|
invigilateExamFinish,
|
|
invigilateExamFinish,
|
|
- examPropCount,
|
|
|
|
} from "@/api/invigilation";
|
|
} from "@/api/invigilation";
|
|
import ExamBatchDialog from "./ExamBatchDialog";
|
|
import ExamBatchDialog from "./ExamBatchDialog";
|
|
import InvigilationStudent from "../common/InvigilationStudent";
|
|
import InvigilationStudent from "../common/InvigilationStudent";
|
|
|
|
+import SummaryLine from "../common/SummaryLine";
|
|
|
|
+import handleRollupDialog from "./handleRollupDialog";
|
|
|
|
+import TextClock from "../common/TextClock";
|
|
|
|
|
|
export default {
|
|
export default {
|
|
name: "realtime-monitoring",
|
|
name: "realtime-monitoring",
|
|
- components: { ExamBatchDialog, InvigilationStudent },
|
|
|
|
|
|
+ components: {
|
|
|
|
+ ExamBatchDialog,
|
|
|
|
+ InvigilationStudent,
|
|
|
|
+ SummaryLine,
|
|
|
|
+ handleRollupDialog,
|
|
|
|
+ TextClock,
|
|
|
|
+ },
|
|
data() {
|
|
data() {
|
|
return {
|
|
return {
|
|
filter: {
|
|
filter: {
|
|
- examId: null,
|
|
|
|
|
|
+ examId: "",
|
|
paperDownload: null,
|
|
paperDownload: null,
|
|
status: null,
|
|
status: null,
|
|
monitorStatusSource: null,
|
|
monitorStatusSource: null,
|
|
@@ -312,10 +276,9 @@ export default {
|
|
maxWarningCount: undefined,
|
|
maxWarningCount: undefined,
|
|
minWarningCount: undefined,
|
|
minWarningCount: undefined,
|
|
},
|
|
},
|
|
- examName: "",
|
|
|
|
|
|
+ hasNewWarning: false,
|
|
curExamBatch: {},
|
|
curExamBatch: {},
|
|
curViewingAngle: {},
|
|
curViewingAngle: {},
|
|
- examPropData: {},
|
|
|
|
current: 1,
|
|
current: 1,
|
|
total: 0,
|
|
total: 0,
|
|
size: 10,
|
|
size: 10,
|
|
@@ -325,7 +288,31 @@ export default {
|
|
exams: [],
|
|
exams: [],
|
|
subjects: [],
|
|
subjects: [],
|
|
pageType: "0",
|
|
pageType: "0",
|
|
- dataList: [],
|
|
|
|
|
|
+ dataList: [
|
|
|
|
+ {
|
|
|
|
+ breachStatus: 0,
|
|
|
|
+ clientCommunicationStatus: "12",
|
|
|
|
+ clientCurrentIp: "192.168.10.12",
|
|
|
|
+ courseCode: "F001",
|
|
|
|
+ courseName: "数学",
|
|
|
|
+ examActivityId: 0,
|
|
|
|
+ examId: 111,
|
|
|
|
+ examRecordId: 222,
|
|
|
|
+ examStudentId: 333,
|
|
|
|
+ identity: "000000000000008",
|
|
|
|
+ monitorStatusSource: "",
|
|
|
|
+ name: "楚一一",
|
|
|
|
+ paperDownload: 0,
|
|
|
|
+ progress: 0,
|
|
|
|
+ roomCode: "123",
|
|
|
|
+ roomName: "第一教师",
|
|
|
|
+ status: "1",
|
|
|
|
+ statusCode: "1",
|
|
|
|
+ updateTime: "2020-12-12",
|
|
|
|
+ warningCount: 0,
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ videoList: [],
|
|
viewingAngles: [
|
|
viewingAngles: [
|
|
{
|
|
{
|
|
code: "1",
|
|
code: "1",
|
|
@@ -354,28 +341,31 @@ export default {
|
|
let res = null;
|
|
let res = null;
|
|
if (this.pageType === "0") {
|
|
if (this.pageType === "0") {
|
|
res = await invigilateList(datas);
|
|
res = await invigilateList(datas);
|
|
|
|
+ this.dataList = res.data.data.records.map((item) => {
|
|
|
|
+ item.label = `${item.identity} ${item.courseName}(${item.courseCode}) ${item.name}`;
|
|
|
|
+ return item;
|
|
|
|
+ });
|
|
} else {
|
|
} else {
|
|
res = await invigilateVideoList(datas);
|
|
res = await invigilateVideoList(datas);
|
|
|
|
+ this.videoList = res.data.data.records;
|
|
}
|
|
}
|
|
|
|
|
|
- this.dataList = res.data.data.records;
|
|
|
|
this.total = res.data.data.records.total;
|
|
this.total = res.data.data.records.total;
|
|
},
|
|
},
|
|
toPage(page) {
|
|
toPage(page) {
|
|
this.current = page;
|
|
this.current = page;
|
|
this.getList();
|
|
this.getList();
|
|
},
|
|
},
|
|
- async getExamPropCount() {
|
|
|
|
- this.examPropData = await examPropCount(this.filter.examId);
|
|
|
|
- },
|
|
|
|
examChange(examBatch) {
|
|
examChange(examBatch) {
|
|
if (!examBatch) return;
|
|
if (!examBatch) return;
|
|
this.filter.examId = examBatch.id;
|
|
this.filter.examId = examBatch.id;
|
|
this.curExamBatch = examBatch;
|
|
this.curExamBatch = examBatch;
|
|
- this.toPage(1);
|
|
|
|
|
|
+ // this.toPage(1);
|
|
},
|
|
},
|
|
- pageTypeChange() {
|
|
|
|
|
|
+ pageTypeChange(pageType) {
|
|
|
|
+ this.pageType = pageType;
|
|
this.toPage(1);
|
|
this.toPage(1);
|
|
|
|
+ this.multipleSelection = [];
|
|
},
|
|
},
|
|
handleSelectionChange(val) {
|
|
handleSelectionChange(val) {
|
|
console.log(val);
|
|
console.log(val);
|
|
@@ -385,20 +375,15 @@ export default {
|
|
this.curViewingAngle = data;
|
|
this.curViewingAngle = data;
|
|
},
|
|
},
|
|
async finishInvigilation() {
|
|
async finishInvigilation() {
|
|
- const result = await this.$confirm("确定要手动收卷吗?", {
|
|
|
|
- confirmButtonText: "确定",
|
|
|
|
- cancelButtonText: "取消",
|
|
|
|
- type: "confirm",
|
|
|
|
- }).catch(() => {});
|
|
|
|
-
|
|
|
|
- if (!result) return;
|
|
|
|
-
|
|
|
|
- await invigilateFinish({ examRecordId: "", type: false });
|
|
|
|
- this.toPage(1);
|
|
|
|
- this.$message({
|
|
|
|
- type: "success",
|
|
|
|
- message: "操作成功!",
|
|
|
|
- });
|
|
|
|
|
|
+ if (!this.multipleSelection.length) {
|
|
|
|
+ this.$message.error("请先选择数据!");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ this.$refs.handleRollupDialog.open();
|
|
|
|
+ },
|
|
|
|
+ rollupOver() {
|
|
|
|
+ this.multipleSelection = [];
|
|
|
|
+ this.getList();
|
|
},
|
|
},
|
|
async finishInvigilationExam() {
|
|
async finishInvigilationExam() {
|
|
const result = await this.$confirm("确定要结束监考吗?", {
|
|
const result = await this.$confirm("确定要结束监考吗?", {
|
|
@@ -456,8 +441,12 @@ export default {
|
|
line-height: 32px;
|
|
line-height: 32px;
|
|
margin: 0;
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
+ .el-select {
|
|
|
|
+ min-width: 200px;
|
|
|
|
+ }
|
|
> p:first-child {
|
|
> p:first-child {
|
|
margin-right: 40px;
|
|
margin-right: 40px;
|
|
|
|
+ min-width: 150px;
|
|
}
|
|
}
|
|
> p:last-child {
|
|
> p:last-child {
|
|
float: right;
|
|
float: right;
|
|
@@ -465,6 +454,53 @@ export default {
|
|
opacity: 0.8;
|
|
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 {
|
|
.invigilation-student-list {
|
|
background: #ffffff;
|
|
background: #ffffff;
|
|
border-radius: 6px;
|
|
border-radius: 6px;
|