Browse Source

invigilation md

zhangjie 4 years ago
parent
commit
aad9ac058c
32 changed files with 2390 additions and 179 deletions
  1. 2 0
      package.json
  2. 2 2
      public/index.html
  3. 49 6
      src/api/invigilation.js
  4. BIN
      src/assets/icon-bat.png
  5. 1 1
      src/constant/constants.js
  6. 176 2
      src/features/invigilation/ExamInvigilation/ExamInvigilation.vue
  7. 8 5
      src/features/invigilation/InvigilationDetail/InvigilationDetail.vue
  8. 104 11
      src/features/invigilation/OnlinePatrol/OnlinePatrol.vue
  9. 1 1
      src/features/invigilation/ProgressDetail/ProgressDetail.vue
  10. 0 0
      src/features/invigilation/RealtimeMonitoring/FlvMedia.vue
  11. 86 61
      src/features/invigilation/RealtimeMonitoring/RealtimeMonitoring.vue
  12. 66 32
      src/features/invigilation/RealtimeMonitoring/VideoCommunication.vue
  13. 27 17
      src/features/invigilation/RealtimeMonitoring/WainingDetail.vue
  14. 1 1
      src/features/invigilation/ReexamChecked/ReexamChecked.vue
  15. 1 1
      src/features/invigilation/ReexamPending/ReexamPending.vue
  16. 1 1
      src/features/invigilation/StudentLogManage/StudentLogDetailDialog.vue
  17. 1 1
      src/features/invigilation/StudentLogManage/StudentLogManage.vue
  18. 4 4
      src/features/invigilation/WainingManage/WainingManage.vue
  19. 539 0
      src/features/invigilation/common/EchartRender.vue
  20. 1 0
      src/main.js
  21. 32 0
      src/plugins/VueCharts.js
  22. 2 1
      src/plugins/element.js
  23. 11 0
      src/plugins/trtc.js
  24. 18 15
      src/router/invigilation.js
  25. 8 2
      src/store/index.js
  26. 31 3
      src/styles/base.scss
  27. 108 0
      src/styles/element-ui-custom.scss
  28. 1058 0
      src/styles/element-var.scss
  29. 6 0
      src/styles/icons.scss
  30. 20 8
      src/views/Layout/components/NavBar.vue
  31. 0 4
      src/views/Layout/components/menu.js
  32. 26 0
      yarn.lock

+ 2 - 0
package.json

@@ -22,6 +22,7 @@
     "bootstrap": "^4.5.0",
     "core-js": "^3.6.5",
     "crypto-js": "^4.0.0",
+    "echarts": "^4.8.0",
     "element-ui": "^2.13.2",
     "flv.js": "^1.5.0",
     "js-cookie": "^2.2.1",
@@ -33,6 +34,7 @@
     "trtc-js-sdk": "^4.6.1",
     "vue": "^2.6.11",
     "vue-awesome": "^4.1.0",
+    "vue-echarts": "^5.0.0-beta.0",
     "vue-router": "^3.3.4",
     "vuex": "^3.5.1",
     "vuex-persistedstate": "^3.0.1"

+ 2 - 2
public/index.html

@@ -15,7 +15,7 @@
       >
     </noscript>
     <div id="app"></div>
-    <!-- <script>
+    <script>
       var _hmt = _hmt || [];
       (function () {
         var hmId = "xxxxx";
@@ -24,7 +24,7 @@
         var s = document.getElementsByTagName("script")[0];
         s.parentNode.insertBefore(hm, s);
       })();
-    </script> -->
+    </script>
     <!-- built files will be auto injected -->
   </body>
 </html>

+ 49 - 6
src/api/invigilation.js

@@ -1,27 +1,70 @@
 import { httpApp } from "@/plugins/axiosIndex";
+import { pickBy } from "lodash-es";
+import { object2QueryString } from "@/utils/utils";
+
+// realtime-monitoring
+export function invigilateList(datas) {
+  const data = pickBy(datas, (v) => v !== "");
+  return httpApp.post(
+    "/api/admin/invigilate/list?" + object2QueryString(data),
+    {}
+  );
+}
+export function invigilateDetail(recordId) {
+  return httpApp.post(
+    "/api/admin/invigilate/list/detail?examRecordId=" + recordId,
+    {}
+  );
+}
+
+export function examList(datas) {
+  const data = pickBy(datas, (v) => v !== "");
+  return httpApp.post("/api/admin/exam/list?" + object2QueryString(data), {});
+}
 
 export function warningStudentDetail({ recordId }) {
   const data = {
     recordId,
   };
-  return httpApp.post("/api/oe/monitor/call/query", data);
+  return httpApp.post(
+    "/api/admin/monitor/call/query?" + object2QueryString(data),
+    {}
+  );
 }
 
-export function communicationList() {
+export function communicationList({
+  examActivityId,
+  pageNumber = 1,
+  pageSize = 10,
+}) {
+  const data = pickBy(
+    { examActivityId, pageNumber, pageSize },
+    (v) => v !== ""
+  );
   return httpApp.post(
-    "/api/oe/monitor/call/list",
+    "/api/admin/monitor/call/list?" + object2QueryString(data),
     {},
     {
       noErrorMessage: true,
     }
   );
 }
-export function communicationOver(callCancel) {
+
+export function communicationOver(callCancelBackendMobile) {
   return httpApp.post(
-    "/api/oe/monitor/call/cancel",
-    { callCancel },
+    "/api/admin/monitor/call/cancel",
+    { callCancelBackendMobile },
     {
       noErrorMessage: true,
     }
   );
 }
+
+// invigilation-detail
+export function invigilationHistoryList({ pageNumber = 1, pageSize = 10 }) {
+  const data = pickBy({ pageNumber, pageSize }, (v) => v !== "");
+  return httpApp.post(
+    "/api/admin/invigilate/history/list?" + object2QueryString(data),
+    {}
+  );
+}

BIN
src/assets/icon-bat.png


+ 1 - 1
src/constant/constants.js

@@ -1,5 +1,5 @@
 export const YYYYMMDDHHmmss = "YYYY-MM-DD HH:mm:ss";
-export const PLATFORM = "web";
+export const PLATFORM = "WEB";
 
 if (!localStorage.getItem("deviceId")) {
   localStorage.setItem("deviceId", Math.random() + "-" + Date.now());

+ 176 - 2
src/features/invigilation/ExamInvigilation/ExamInvigilation.vue

@@ -101,6 +101,11 @@
             <i class="el-icon-question" slot="reference"></i>
           </el-popover>
         </h3>
+        <echart-render
+          :chart-data="onlineData"
+          chart-type="bar"
+          v-if="chartDataReady"
+        ></echart-render>
       </div>
       <div class="invigilation-warning">
         <el-row :gutter="20">
@@ -117,6 +122,11 @@
                   <i class="el-icon-question" slot="reference"></i>
                 </el-popover>
               </h3>
+              <echart-render
+                :chart-data="orgWarningData"
+                chart-type="pie"
+                v-if="chartDataReady"
+              ></echart-render>
             </div>
           </el-col>
           <el-col :span="12">
@@ -132,6 +142,11 @@
                   <i class="el-icon-question" slot="reference"></i>
                 </el-popover>
               </h3>
+              <echart-render
+                :chart-data="typeWarningData"
+                chart-type="pie"
+                v-if="chartDataReady"
+              ></echart-render>
             </div>
           </el-col>
         </el-row>
@@ -148,6 +163,11 @@
             <i class="el-icon-question" slot="reference"></i>
           </el-popover>
         </h3>
+        <echart-render
+          :chart-data="warningTrendData"
+          chart-type="line"
+          v-if="chartDataReady"
+        ></echart-render>
       </div>
       <div class="invigilation-message part-box">
         <h3 class="invigilation-part-title">
@@ -210,12 +230,145 @@
 </template>
 
 <script>
+import EchartRender from "../common/EchartRender";
+
 export default {
   name: "exam-invigilation",
+  components: { EchartRender },
   data() {
-    return {};
+    return {
+      onlineData: {
+        dataList: [
+          {
+            name: "数学学院",
+            count: 500,
+          },
+          {
+            name: "物理学院",
+            count: 700,
+          },
+          {
+            name: "计算机学院",
+            count: 300,
+          },
+          {
+            name: "外语学院",
+            count: 400,
+          },
+        ],
+        type: "light", // light or dark
+      },
+      orgWarningData: {
+        dataList: [
+          {
+            name: "数学学院",
+            count: 50,
+          },
+          {
+            name: "物理学院",
+            count: 5,
+          },
+          {
+            name: "计算机学院",
+            count: 20,
+          },
+          {
+            name: "外语学院",
+            count: 25,
+          },
+        ],
+        type: "light",
+      },
+      typeWarningData: {
+        dataList: [
+          {
+            name: "频繁离开座位",
+            count: 50,
+          },
+          {
+            name: "身份验证不通过",
+            count: 5,
+          },
+          {
+            name: "陌生人入境",
+            count: 20,
+          },
+          {
+            name: "疑似:开启虚拟摄像头",
+            count: 25,
+          },
+        ],
+        type: "light",
+      },
+      warningTrendData: {
+        dataList: [
+          {
+            name: "8:00",
+            count: 13,
+          },
+          {
+            name: "9:00",
+            count: 16,
+          },
+          {
+            name: "10:00",
+            count: 20,
+          },
+          {
+            name: "11:00",
+            count: 16,
+          },
+          {
+            name: "12:00",
+            count: 10,
+          },
+          {
+            name: "13:00",
+            count: 16,
+          },
+          {
+            name: "14:00",
+            count: 25,
+          },
+          {
+            name: "15:00",
+            count: 30,
+          },
+          {
+            name: "16:00",
+            count: 22,
+          },
+          {
+            name: "17:00",
+            count: 15,
+          },
+          {
+            name: "18:00",
+            count: 12,
+          },
+          {
+            name: "19:00",
+            count: 20,
+          },
+        ],
+        type: "light",
+      },
+      chartDataReady: false,
+    };
+  },
+  computed: {
+    isFullScreen() {
+      return this.$store.state.isFullScreen;
+    },
+  },
+  watch: {
+    isFullScreen(val) {
+      this.fullScreenChange(val);
+    },
+  },
+  mounted() {
+    this.chartDataReady = true;
   },
-  mounted() {},
   methods: {
     exitFullscreen() {
       const exitFullscreen =
@@ -225,6 +378,25 @@ export default {
 
       exitFullscreen.call(document);
     },
+    checkDocIsFullscreen() {
+      return (
+        document.fullscreenElement ||
+        document.msFullscreenElement ||
+        document.mozFullscreenElement ||
+        document.webkitFullscreenElement
+      );
+    },
+    fullScreenChange(isFullScreen) {
+      this.chartDataReady = false;
+      this.$nextTick(() => {
+        const colorType = isFullScreen ? "dark" : "light";
+        this.onlineData.type = colorType;
+        this.orgWarningData.type = colorType;
+        this.typeWarningData.type = colorType;
+        this.warningTrendData.type = colorType;
+        this.chartDataReady = true;
+      });
+    },
   },
 };
 </script>
@@ -428,6 +600,8 @@ export default {
 .invigilation-warning {
   .part-box {
     height: 282px;
+    padding-top: 50px;
+    padding-bottom: 10px;
   }
 }
 .invigilation-trend {

+ 8 - 5
src/features/invigilation/InvigilationDetail/InvigilationDetail.vue

@@ -124,7 +124,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.strangePersonUp"
@@ -139,7 +139,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.exceptionUp"
@@ -154,7 +154,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.warningUp"
@@ -202,7 +202,7 @@
       </div>
     </div>
 
-    <el-table ref="TableList" :data="dataList" border stripe>
+    <el-table ref="TableList" :data="dataList">
       <el-table-column prop="batchName" label="批次"></el-table-column>
       <el-table-column prop="examName" label="场次"></el-table-column>
       <el-table-column prop="examroom" label="考场"> </el-table-column>
@@ -297,7 +297,10 @@ export default {
     batchAction() {},
     toDetail(row) {
       console.log(row);
-      this.$router.push({ name: "WainingDetail", params: { id: row.id } });
+      this.$router.push({
+        name: "WainingDetail",
+        params: { recordId: row.id },
+      });
     },
   },
 };

+ 104 - 11
src/features/invigilation/OnlinePatrol/OnlinePatrol.vue

@@ -90,7 +90,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.strangePersonUp"
@@ -105,7 +105,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.exceptionUp"
@@ -120,7 +120,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.warningUp"
@@ -168,7 +168,7 @@
       </div>
     </div>
 
-    <el-table ref="TableList" :data="dataList" border stripe>
+    <el-table ref="TableList" :data="dataList">
       <el-table-column prop="examroom" label="考场(代码)"> </el-table-column>
       <el-table-column prop="stdCardNo" label="证件号"></el-table-column>
       <el-table-column prop="stdName" label="姓名"></el-table-column>
@@ -208,13 +208,21 @@
       </el-pagination>
     </div>
 
-    <div class="patrol-analysis part-box"></div>
+    <div class="patrol-analysis part-box">
+      <echart-render
+        :chart-data="statData"
+        chart-type="barGroup"
+      ></echart-render>
+    </div>
   </div>
 </template>
 
 <script>
+import EchartRender from "../common/EchartRender";
+
 export default {
   name: "online-patrol",
+  components: { EchartRender },
   data() {
     return {
       filter: {
@@ -231,7 +239,7 @@ export default {
         warningDown: null,
       },
       current: 1,
-      total: 0,
+      total: 30,
       size: 10,
       batchs: [],
       exams: [],
@@ -253,6 +261,96 @@ export default {
           isDiscipline: "",
           auditStatus: "未阅",
         },
+        {
+          id: 2,
+          batchName: "第一批次",
+          examName: "第一场次",
+          examroom: "第一考场",
+          examId: "123456",
+          stdCardNo: "000000000000000008",
+          stdName: "张龙龙",
+          subjectName: "大学英语",
+          subjectCode: "10006",
+          strangeNumber: "0",
+          exceptionNumber: "2",
+          warningNumber: "2",
+          isDiscipline: "",
+          auditStatus: "未阅",
+        },
+      ],
+      statData: [
+        {
+          name: "苏州市第一中学",
+          login: 0.6,
+          waiting: 0.25,
+          error: 0.15,
+        },
+        {
+          name: "中山纪念中学",
+          login: 0.5,
+          waiting: 0.35,
+          error: 0.15,
+        },
+        {
+          name: "东华高级中学",
+          login: 0.4,
+          waiting: 0.25,
+          error: 0.35,
+        },
+        {
+          name: "重庆市开州中学",
+          login: 0.8,
+          waiting: 0.1,
+          error: 0.1,
+        },
+        {
+          name: "重庆市铜梁中学校",
+          login: 0.55,
+          waiting: 0.25,
+          error: 0.2,
+        },
+        {
+          name: "北京市鼎石学校",
+          login: 0.8,
+          waiting: 0.05,
+          error: 0.15,
+        },
+        {
+          name: "重庆市第八中学",
+          login: 0.7,
+          waiting: 0.15,
+          error: 0.15,
+        },
+        {
+          name: "柯桥中学",
+          login: 0.75,
+          waiting: 0.05,
+          error: 0.2,
+        },
+        {
+          name: "伊川县第一高中",
+          login: 0.6,
+          waiting: 0.2,
+          error: 0.2,
+        },
+        {
+          name: "汝南高中",
+          login: 0.6,
+          waiting: 0.05,
+          error: 0.35,
+        },
+        {
+          name: "博罗榕城中学",
+          login: 0.7,
+          waiting: 0.25,
+          error: 0.05,
+        },
+        {
+          name: "海亮高级中学",
+          login: 0.7,
+          waiting: 0.1,
+          error: 0.2,
+        },
       ],
     };
   },
@@ -270,11 +368,6 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.online-patrol {
-  .el-form {
-    margin-bottom: 10px;
-  }
-}
 .patrol-analysis {
   height: 355px;
   margin-top: 20px;

+ 1 - 1
src/features/invigilation/ProgressDetail/ProgressDetail.vue

@@ -96,7 +96,7 @@
       </div>
     </div>
 
-    <el-table ref="TableList" :data="dataList" border stripe>
+    <el-table ref="TableList" :data="dataList">
       <el-table-column prop="examroom" label="批次名称(代码)">
       </el-table-column>
       <el-table-column

+ 0 - 0
src/features/invigilation/WainingManage/FlvMedia.vue → src/features/invigilation/RealtimeMonitoring/FlvMedia.vue


+ 86 - 61
src/features/invigilation/RealtimeMonitoring/RealtimeMonitoring.vue

@@ -1,10 +1,15 @@
 <template>
   <div class="realtime-monitoring">
     <div class="realtime-top clear-float">
-      <p>考场名称:哈尔滨工业大学第十一考场</p>
-      <el-select v-model="batchId" placeholder="请选择批次" clearable>
+      <p v-if="examName">考场名称:{{ examName }}</p>
+      <el-select
+        v-model="filter.examId"
+        placeholder="请选择批次"
+        @change="examChange"
+        clearable
+      >
         <el-option
-          v-for="item in batchs"
+          v-for="item in exams"
           :key="item.id"
           :value="item.id"
           :label="item.name"
@@ -62,7 +67,10 @@
           </p>
         </div>
         <div class="part-filter-info-sub">
-          <el-button icon="el-icon-phone-outline" type="success"
+          <el-button
+            icon="el-icon-phone-outline"
+            type="success"
+            @click="toCommunication"
             >通话待办</el-button
           >
         </div>
@@ -72,7 +80,7 @@
         <el-form ref="FilterForm" label-position="left" inline>
           <el-form-item>
             <el-select
-              v-model="filter.batchId"
+              v-model="filter.paperDownload"
               placeholder="试题下载"
               clearable
             >
@@ -85,11 +93,7 @@
             </el-select>
           </el-form-item>
           <el-form-item>
-            <el-select
-              v-model="filter.examroom"
-              placeholder="考试状态"
-              clearable
-            >
+            <el-select v-model="filter.status" placeholder="考试状态" clearable>
               <el-option
                 v-for="item in exams"
                 :key="item.id"
@@ -100,7 +104,7 @@
           </el-form-item>
           <el-form-item>
             <el-select
-              v-model="filter.examroom"
+              v-model="filter.monitorStatusSource"
               placeholder="通讯故障"
               clearable
             >
@@ -115,21 +119,21 @@
           <el-form-item label="预警量">
             <el-input-number
               style="width: 52px;"
-              v-model.trim="filter.warningDown"
+              v-model.trim="filter.minWarningCount"
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
-              v-model.trim="filter.warningUp"
+              v-model.trim="filter.maxWarningCount"
               placeholder="上限"
               :controls="false"
             ></el-input-number>
           </el-form-item>
           <el-form-item>
             <el-input
-              v-model.trim="filter.content"
+              v-model.trim="filter.identity"
               placeholder="姓名/证件号"
               clearable
             ></el-input>
@@ -140,31 +144,34 @@
         </el-form>
 
         <div class="part-filter-form-action">
-          <el-button type="primary" icon="icon icon-clean" @click="cleanUnread"
+          <el-button type="primary" icon="icon icon-handle" @click="cleanUnread"
             >手动收卷</el-button
           >
-          <el-button type="danger" icon="icon icon-warning" @click="batchAction"
+          <el-button type="danger" icon="icon icon-over" @click="batchAction"
             >结束监考</el-button
           >
         </div>
       </div>
     </div>
 
-    <el-table ref="TableList" :data="dataList" border stripe>
-      <el-table-column prop="stdCardNo" label="证件号"></el-table-column>
-      <el-table-column prop="stdName" label="姓名"></el-table-column>
-      <el-table-column prop="subjectCode" label="科目名称"></el-table-column>
-      <el-table-column prop="subjectCode" label="科目代码"></el-table-column>
+    <el-table ref="TableList" :data="dataList">
+      <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="subjectCode" label="剩余时间"></el-table-column>
-      <el-table-column prop="subjectCode" label="试题下载"></el-table-column>
-      <el-table-column prop="subjectCode" label="考试状态"></el-table-column>
-      <el-table-column prop="subjectCode" label="进度"></el-table-column>
-      <el-table-column prop="subjectCode" label="通讯"></el-table-column>
+      <el-table-column prop="paperDownload" label="试题下载"></el-table-column>
+      <el-table-column prop="status" label="考试状态"></el-table-column>
+      <el-table-column prop="progress" label="进度"></el-table-column>
+      <el-table-column
+        prop="clientCommunicationStatus"
+        label="通讯"
+      ></el-table-column>
       <el-table-column prop="subjectCode" label="推流通讯"></el-table-column>
-      <el-table-column prop="subjectCode" label="IP"></el-table-column>
-      <el-table-column prop="subjectCode" label="更新时间"></el-table-column>
-      <el-table-column prop="warningNumber" label="预警数"></el-table-column>
-      <el-table-column prop="isDiscipline" label="违纪"></el-table-column>
+      <el-table-column prop="clientCurrentIp" label="IP"></el-table-column>
+      <el-table-column prop="updateTime" label="更新时间"></el-table-column>
+      <el-table-column prop="warningCount" label="预警数"></el-table-column>
+      <el-table-column prop="breachStatus" label="违纪"></el-table-column>
       <el-table-column label="操作">
         <template slot-scope="scope">
           <el-button
@@ -192,22 +199,22 @@
 </template>
 
 <script>
+import { invigilateList, examList } from "@/api/invigilation";
+
 export default {
   name: "realtime-monitoring",
   data() {
     return {
       filter: {
-        examroom: null,
-        subjectId: null,
-        auditStatus: null,
-        content: "",
-        strangePersonUp: null,
-        strangePersonDown: null,
-        exceptionUp: null,
-        exceptionDown: null,
-        warningUp: null,
-        warningDown: null,
+        examId: null,
+        paperDownload: null,
+        status: null,
+        monitorStatusSource: null,
+        identity: null,
+        maxWarningCount: undefined,
+        minWarningCount: undefined,
       },
+      examName: "",
       current: 1,
       total: 0,
       size: 10,
@@ -216,34 +223,52 @@ export default {
       exams: [],
       subjects: [],
       pageType: "0",
-      dataList: [
-        {
-          id: 1,
-          batchName: "第一批次",
-          examName: "第一场次",
-          examroom: "第一考场",
-          examId: "123456",
-          stdCardNo: "000000000000000008",
-          stdName: "张龙龙",
-          subjectName: "大学英语",
-          subjectCode: "10006",
-          strangeNumber: "0",
-          exceptionNumber: "2",
-          warningNumber: "2",
-          isDiscipline: "",
-          auditStatus: "未阅",
-        },
-      ],
+      dataList: [],
     };
   },
+  mounted() {
+    this.initData();
+  },
   methods: {
-    getList() {},
-    toPage() {},
+    async initData() {
+      await this.getExamList();
+      this.filter.examId = this.exams[0] && this.exams[0].id;
+      this.examChange();
+      this.getList();
+    },
+    async getList() {
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current - 1,
+        pageSize: this.size,
+      };
+      const res = await invigilateList(datas);
+      this.dataList = res.data.data.records;
+      this.total = res.data.data.records.total;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    examChange() {
+      const exam = this.exams.find((item) => item.id === this.filter.examId);
+      this.examName = exam.name;
+    },
+    async getExamList() {
+      const res = await examList({ pageNumber: 0, pageSize: 100 });
+      this.exams = res.data.data.records;
+    },
     cleanUnread() {},
     batchAction() {},
+    toCommunication() {
+      this.$router.push({ name: "VideoCommunication" });
+    },
     toDetail(row) {
       console.log(row);
-      this.$router.push({ name: "WainingDetail", params: { id: row.id } });
+      this.$router.push({
+        name: "WainingDetail",
+        params: { recordId: row.examRecordId },
+      });
     },
   },
 };

+ 66 - 32
src/features/invigilation/VideoCommunication/VideoCommunication.vue → src/features/invigilation/RealtimeMonitoring/VideoCommunication.vue

@@ -16,7 +16,7 @@
             <div class="student-cover">
               <img :src="item.stdAvatar" :alt="item.stdName" />
             </div>
-            <h4 class="student-name">{{ item.stdName }}</h4>
+            <h4 class="student-name">{{ item.monitorKey }}</h4>
             <el-button round type="success" @click="answer(item, 0)"
               >语音通话</el-button
             >
@@ -29,6 +29,18 @@
       </el-row>
     </div>
 
+    <div class="part-page">
+      <el-pagination
+        background
+        layout="prev, pager, next,total,sizes,jumper"
+        :current-page="current"
+        :total="total"
+        :page-size="size"
+        @current-change="toPage"
+      >
+      </el-pagination>
+    </div>
+
     <!-- 通话弹出层 -->
     <el-dialog
       custom-class="communication-dialog"
@@ -57,9 +69,15 @@
 </template>
 
 <script>
-import TRTC from "trtc-js-sdk";
+import { createClient, createStream } from "@/plugins/trtc";
 import { communicationList, communicationOver } from "@/api/invigilation";
 
+const stdAvatars = [
+  "/img/avatars/1.jpg",
+  "/img/avatars/2.jpg",
+  "/img/avatars/3.jpg",
+];
+
 export default {
   name: "video-communication",
   data() {
@@ -67,25 +85,16 @@ export default {
       pageType: "0",
       dialogVisible: false,
       students: [
-        {
-          id: 1,
-          roomId: "8888",
-          stdAvatar: "/img/avatars/1.jpg",
-          stdName: "邹朵朵",
-        },
-        {
-          id: 2,
-          roomId: "2",
-          stdAvatar: "/img/avatars/2.jpg",
-          stdName: "罗图图",
-        },
-        {
-          id: 3,
-          roomId: "3",
-          stdAvatar: "/img/avatars/3.jpg",
-          stdName: "于梁",
-        },
+        // {
+        //   id: 1,
+        //   roomId: "8888",
+        //   stdAvatar: "/img/avatars/1.jpg",
+        //   stdName: "邹朵朵",
+        // },
       ],
+      current: 1,
+      total: 0,
+      size: 100,
       setT: null,
       durationTime: "00:10:23",
       appId: "1400411036",
@@ -102,30 +111,55 @@ export default {
   },
   methods: {
     async initClinet() {
-      this.client = TRTC.createClient({
-        mode: "rtc",
+      this.client = createClient({
+        mode: "live",
         sdkAppId: this.appId,
         userId: this.videoUserId,
         userSig: this.videoUserSig,
       });
     },
     async getCommunicationList() {
-      const data = await communicationList().catch(() => {});
-      this.students = data.records;
+      if (this.setT) clearTimeout(this.setT);
 
-      // this.setT = setTimeout(() => {
-      //   this.getCommunicationList();
-      // }, 2000);
+      const res = await communicationList({
+        // examActivityId: 1,
+        pageNumber: this.current,
+        pageSize: this.size,
+      }).catch(() => {});
+      this.students = res.data.data.records
+        .filter((item) => item.callStatus === "START")
+        .map((item, index) => {
+          const lindex = index % 3;
+          return {
+            ...item,
+            stdAvatar: stdAvatars[lindex],
+            stdName: "",
+          };
+        });
+      this.total = res.data.data.records.total;
+      // 当前页没有数据,同时当前页不是第一页,则自动跳到前一页。
+      if (!this.students.length && this.current > 1) {
+        this.current--;
+        this.getCommunicationList();
+      } else {
+        this.setT = setTimeout(() => {
+          this.getCommunicationList();
+        }, 3000);
+      }
+    },
+    toPage(page) {
+      this.current = page;
+      this.getCommunicationList();
     },
     async answer(student, isVideo) {
-      this.dialogVisible = true;
       // 结束学生的通话申请
-      await communicationOver({ recordId: student.recordId });
+      await communicationOver({ recordId: student.examRecordId });
 
+      this.dialogVisible = true;
       // 添加远程用户视频发布监听
       this.client.on("stream-added", (event) => {
+        console.log(event);
         const remoteStream = event.stream;
-        if (remoteStream.userId_ !== "s01") return;
 
         this.client
           .subscribe(remoteStream, { audio: true, video: true })
@@ -145,7 +179,7 @@ export default {
       let roomJoinResult = true;
       await this.client
         .join({
-          roomId: student.roomId,
+          roomId: student.monitorKey,
           role: "audience",
           // role: "anchor"
         })
@@ -164,7 +198,7 @@ export default {
       if (!switchResult) return;
 
       // 初始化stream
-      this.localStream = TRTC.createStream({
+      this.localStream = createStream({
         userId: this.videoUserId,
         audio: true,
         video: isVideo,

+ 27 - 17
src/features/invigilation/WainingManage/WainingDetail.vue → src/features/invigilation/RealtimeMonitoring/WainingDetail.vue

@@ -3,7 +3,9 @@
     <div class="warning-detail-head">
       <div class="warning-detail-title">
         <h2>预警详情</h2>
-        <el-button size="mini" icon="el-icon-arrow-left">返回列表</el-button>
+        <el-button size="mini" icon="el-icon-arrow-left" @click="goBack"
+          >返回列表</el-button
+        >
         <el-button
           @click="initSubscribeVideo"
           type="primary"
@@ -159,16 +161,17 @@
 </template>
 
 <script>
-import TRTC from "trtc-js-sdk";
+import { createClient, createStream } from "@/plugins/trtc";
 import FlvMedia from "./FlvMedia";
-import { warningStudentDetail } from "@/api/invigilation";
+import { invigilateDetail, warningStudentDetail } from "@/api/invigilation";
 
 export default {
   name: "warning-detail",
   components: { FlvMedia },
   data() {
     return {
-      recordId: "777",
+      recordId: "32145907927482368",
+      // recordId: this.$route.params.recordId,
       exceptionList: [
         {
           title: "身份验证不通过",
@@ -190,7 +193,7 @@ export default {
         stdName: "张龙龙",
         subjectName: "大学英语",
         subjectCode: "10006",
-        roomId: "8888",
+        roomId: "6",
       },
       firstViewVideo: {
         id: "111",
@@ -218,30 +221,36 @@ export default {
     };
   },
   mounted() {
-    // this.initClinet();
-    // this.initData();
+    this.initClinet();
+    this.initData();
   },
   methods: {
     initClinet() {
-      this.client = TRTC.createClient({
-        mode: "rtc",
+      this.client = createClient({
+        mode: "live",
         sdkAppId: this.appId,
         userId: this.videoUserId,
         userSig: this.videoUserSig,
       });
     },
     async initData() {
-      const data = await warningStudentDetail({ recordId: this.recordId });
-      const records = data.records.map((item) => {
-        item.src = `http://live.qmth.com.cn/live/${item.liveUrl}.flv`;
+      this.getInvigilateDetail();
+      const res = await warningStudentDetail({ recordId: this.recordId });
+      const records = res.data.data.map((item) => {
+        item.src = `http://live.qmth.com.cn/live/${item.liveUrl.toLowerCase()}.flv`;
         item.name = item.source;
         return item;
       });
+      console.log(records.map((item) => item.src));
       this.firstViewVideo = records[0] || {};
-      this.secondViewVideo = records[1] || {};
+      this.secondViewVideo = records[2] || {};
 
       if (records.length) this.initSubscribeVideo();
     },
+    async getInvigilateDetail() {
+      const res = await invigilateDetail(this.recordId);
+      console.log(res);
+    },
     initSubscribeVideo() {
       if (this.firstViewVideo.id) this.firstViewVideoReady = true;
       if (this.secondViewVideo.id) this.secondViewVideoReady = true;
@@ -258,7 +267,6 @@ export default {
       this.client.on("stream-added", (event) => {
         console.log(event);
         const remoteStream = event.stream;
-        if (remoteStream.userId_ !== "s01") return;
 
         // 延迟订阅视频
         this.setT = setTimeout(() => {
@@ -274,7 +282,6 @@ export default {
       });
       this.client.on("stream-subscribed", (event) => {
         const remoteStream = event.stream;
-        if (remoteStream.userId_ !== "s01") return;
 
         this.isWaiting = false;
         this.$nextTick(() => {
@@ -304,7 +311,7 @@ export default {
       if (!switchResult) return;
 
       // 初始化stream
-      this.localStream = TRTC.createStream({
+      this.localStream = createStream({
         userId: this.videoUserId,
         audio: true,
         video: isVideo,
@@ -354,7 +361,10 @@ export default {
       this.dialogVisible = false;
       this.localStream = null;
       this.isWaiting = true;
-      // this.initSubscribeVideo();
+      this.initSubscribeVideo();
+    },
+    goBack() {
+      window.history.go(-1);
     },
   },
   beforeDestroy() {

+ 1 - 1
src/features/invigilation/ReexamChecked/ReexamChecked.vue

@@ -94,7 +94,7 @@
       </div>
     </div>
 
-    <el-table ref="TableList" :data="dataList" border stripe>
+    <el-table ref="TableList" :data="dataList">
       <el-table-column prop="examroom" label="考场(代码)"> </el-table-column>
       <el-table-column prop="stdCardNo" label="证件号"></el-table-column>
       <el-table-column prop="stdCardNo" label="科目名称"></el-table-column>

+ 1 - 1
src/features/invigilation/ReexamPending/ReexamPending.vue

@@ -94,7 +94,7 @@
       </div>
     </div>
 
-    <el-table ref="TableList" :data="dataList" border stripe>
+    <el-table ref="TableList" :data="dataList">
       <el-table-column prop="examroom" label="考场(代码)"> </el-table-column>
       <el-table-column prop="stdCardNo" label="证件号"></el-table-column>
       <el-table-column prop="stdCardNo" label="科目名称"></el-table-column>

+ 1 - 1
src/features/invigilation/StudentLogManage/StudentLogDetailDialog.vue

@@ -10,7 +10,7 @@
     append-to-body
     @open="visibleChange"
   >
-    <el-table ref="TableList" :data="dataList" border stripe>
+    <el-table ref="TableList" :data="dataList">
       <el-table-column prop="creatTime" label="发生时间"></el-table-column>
       <el-table-column prop="type" label="事件类型"></el-table-column>
       <el-table-column prop="content" label="详情"></el-table-column>

+ 1 - 1
src/features/invigilation/StudentLogManage/StudentLogManage.vue

@@ -77,7 +77,7 @@
       </div>
     </div>
 
-    <el-table ref="TableList" :data="dataList" border stripe>
+    <el-table ref="TableList" :data="dataList">
       <el-table-column prop="batchName" label="排序"></el-table-column>
       <el-table-column prop="batchName" label="批次名称(ID)"></el-table-column>
       <el-table-column prop="examName" label="场次ID"></el-table-column>

+ 4 - 4
src/features/invigilation/WainingManage/WainingManage.vue

@@ -79,7 +79,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.strangePersonUp"
@@ -94,7 +94,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.exceptionUp"
@@ -109,7 +109,7 @@
               placeholder="下限"
               :controls="false"
             ></el-input-number>
-            <span>-</span>
+            <span class="line-split">-</span>
             <el-input-number
               style="width: 52px;"
               v-model.trim="filter.warningUp"
@@ -132,7 +132,7 @@
       </div>
     </div>
 
-    <el-table ref="TableList" :data="dataList" border stripe>
+    <el-table ref="TableList" :data="dataList">
       <el-table-column prop="batchName" label="批次"></el-table-column>
       <el-table-column prop="examName" label="场次"></el-table-column>
       <el-table-column prop="examroom" label="考场"> </el-table-column>

+ 539 - 0
src/features/invigilation/common/EchartRender.vue

@@ -0,0 +1,539 @@
+<template>
+  <div class="echart-render chart-box">
+    <vue-charts
+      :options="chartOption"
+      :init-options="initOptions"
+      v-if="chartOption"
+      autoresize
+      ref="vueChart"
+    ></vue-charts>
+    <p class="chart-none" v-else>暂无数据</p>
+  </div>
+</template>
+
+<script>
+import echarts from "echarts/lib/echarts";
+import VueCharts from "@/plugins/VueCharts";
+
+export default {
+  name: "echart-render",
+  components: { VueCharts },
+  props: {
+    chartType: {
+      type: String,
+      required: true,
+      validator(value) {
+        return ["bar", "pie", "line", "barGroup"].indexOf(value) !== -1;
+      },
+    },
+    rendererType: {
+      type: String,
+      default: "canvas",
+      validator(val) {
+        return ["canvas", "svg"].indexOf(val) !== -1;
+      },
+    },
+    animationIsOpen: {
+      type: Boolean,
+      default: true,
+    },
+    chartData: {
+      type: [Object, Array],
+      required: true,
+    },
+    chartTitle: {
+      type: String,
+      default: "",
+    },
+    chartColor: {
+      type: Array,
+      default() {
+        return [
+          "#1886FE",
+          "#1CD1A1",
+          "#FECA57",
+          "#5FC9FA",
+          "#FE5863",
+          "#dd7755",
+        ];
+      },
+    },
+  },
+  data() {
+    return {
+      chartOption: null,
+      initOptions: { renderer: "canvas" },
+    };
+  },
+  mounted() {
+    if (this.rendererType) this.initOptions.renderer = this.rendererType;
+    this.getOptions();
+  },
+  methods: {
+    getOptions() {
+      const name = this.chartType[0].toUpperCase() + this.chartType.slice(1);
+      this.chartOption = this[`get${name}Option`](this.chartData);
+    },
+    getDataURL(options) {
+      return this.$refs.vueChart && this.$refs.vueChart.getDataURL(options);
+    },
+    getLineOption(datas) {
+      const linearColor = new echarts.graphic.LinearGradient(0, 1, 0, 0, [
+        {
+          offset: 1,
+          color: "rgba(58,147,251,1)",
+        },
+        {
+          offset: 0,
+          color: "rgba(58,147,251,0)",
+        },
+      ]);
+      const tipShadowColor = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+        {
+          offset: 1,
+          color: "rgba(58,147,251,0.8)",
+        },
+        {
+          offset: 0,
+          color: "rgba(58,147,251,0)",
+        },
+      ]);
+
+      const colors = {
+        light: {
+          lineColor: "#F0F4F9",
+          labelColor: "#8C94AC",
+        },
+        dark: {
+          lineColor: "#262A4D",
+          labelColor: "#737AAE",
+        },
+      };
+      const color = colors[datas.type];
+
+      return {
+        animation: this.animationIsOpen,
+        grid: {
+          top: "18%",
+          bottom: "12%",
+          left: "5%",
+          right: "5%",
+        },
+        tooltip: {
+          show: false,
+        },
+        xAxis: {
+          type: "category",
+          data: datas.dataList.map((item) => item.name),
+          splitLine: {
+            show: false,
+          },
+          axisLine: {
+            lineStyle: {
+              color: color.lineColor,
+            },
+          },
+          axisLabel: {
+            color: color.labelColor,
+            fontSize: 14,
+            margin: 14,
+          },
+          axisTick: {
+            show: false,
+          },
+        },
+        yAxis: {
+          type: "value",
+          splitLine: {
+            show: true,
+            lineStyle: {
+              color: color.lineColor,
+            },
+          },
+          axisLine: {
+            show: false,
+          },
+          axisLabel: {
+            fontSize: 14,
+            color: color.labelColor,
+            // formatter: function (value) {
+            //   return value + "%";
+            // },
+          },
+          axisTick: {
+            show: false,
+          },
+        },
+        series: [
+          {
+            name: "数量",
+            type: "line",
+            smooth: true,
+            data: datas.dataList.map((item) => item.count),
+            itemStyle: {
+              color: "#3A93FB",
+            },
+            lineStyle: {
+              color: "#3A93FB",
+            },
+            areaStyle: {
+              color: linearColor,
+            },
+          },
+          {
+            name: "其他",
+            type: "bar",
+            data: datas.dataList.map((item) => item.count),
+            itemStyle: {
+              color: "transparent",
+            },
+            emphasis: {
+              itemStyle: {
+                color: tipShadowColor,
+              },
+              label: {
+                show: true,
+                position: "top",
+                backgroundColor: "#3A93FB",
+                color: "#fff",
+                fontSize: 14,
+                offset: [0, -5],
+                padding: [5, 4, 3, 3],
+                borderRadius: 5,
+              },
+            },
+          },
+        ],
+      };
+    },
+    getPieOption(datas) {
+      if (!datas.dataList.length) return;
+
+      const colors = {
+        light: {
+          aColor: "#8C94AC",
+          bColor: "#202B4B",
+        },
+        dark: {
+          aColor: "#737AAE",
+          bColor: "#ffffff",
+        },
+      };
+      const color = colors[datas.type];
+
+      const seriesData = datas.dataList.map((item) => {
+        return {
+          name: `${item.name}_${item.count}`,
+          value: item.count,
+        };
+      });
+
+      return {
+        animation: this.animationIsOpen,
+        color: this.chartColor,
+        grid: {
+          top: "20%",
+          bottom: "10%",
+        },
+        tooltip: {
+          trigger: "item",
+          formatter: "{a} <br/>{b} : {c} ({d}%)",
+        },
+        legend: {
+          show: true,
+          orient: "vertical",
+          left: "50%",
+          top: "middle",
+          itemGap: 20,
+          itemWidth: 8,
+          itemHeight: 8,
+          textStyle: {
+            rich: {
+              a: {
+                color: color.aColor,
+                fontSize: 14,
+                width: 150,
+                padding: [0, 0, 0, 5],
+              },
+              b: {
+                color: color.bColor,
+                fontSize: 16,
+                padding: [0, 0, 0, 10],
+                fontWeight: "bold",
+              },
+            },
+          },
+          formatter: (label) => {
+            const [name, count] = label.split("_");
+            return `{a|${name}}{b|${count}%}`;
+          },
+        },
+        series: [
+          {
+            name: "占比",
+            type: "pie",
+            radius: ["55%", "80%"],
+            data: seriesData,
+            label: {
+              show: false,
+            },
+            center: ["25%", "50%"],
+          },
+        ],
+      };
+    },
+    getBarOption(datas) {
+      if (!datas.dataList.length) return;
+      const colors = {
+        light: {
+          lineColor: "#F0F4F9",
+          labelColor: "#8C94AC",
+          series: "#5FC9FA",
+        },
+        dark: {
+          lineColor: "#262A4D",
+          labelColor: "#737AAE",
+          series: "#5FC9FA",
+        },
+      };
+      const color = colors[datas.type];
+
+      return {
+        animation: this.animationIsOpen,
+        color: this.chartColor,
+        grid: {
+          top: "20%",
+          bottom: "10%",
+          left: "5%",
+          right: "5%",
+        },
+        tooltip: {
+          show: true,
+        },
+        xAxis: {
+          type: "category",
+          data: datas.dataList.map((item) => item.name),
+          axisLine: {
+            lineStyle: {
+              color: color.lineColor,
+            },
+          },
+          axisLabel: {
+            color: color.labelColor,
+            fontSize: 14,
+            padding: [3, 0, 0, 0],
+          },
+          axisTick: {
+            show: false,
+          },
+        },
+        yAxis: {
+          type: "value",
+          splitLine: {
+            show: true,
+            lineStyle: {
+              color: color.lineColor,
+            },
+          },
+          axisLine: {
+            show: false,
+          },
+          axisLabel: {
+            color: color.labelColor,
+            fontSize: 14,
+          },
+          axisTick: {
+            show: false,
+          },
+        },
+        series: [
+          {
+            name: "数值",
+            type: "bar",
+            barMaxWidth: 80,
+            barMinWidth: 10,
+            data: datas.dataList.map((item) => item.count),
+            itemStyle: {
+              color: color.series,
+            },
+          },
+        ],
+      };
+    },
+    getBarGroupOption(dataList) {
+      const PLACE_STATES = {
+        login: {
+          name: "已登录",
+          color: "#5FC9FA",
+        },
+        error: {
+          name: "通讯故障",
+          color: "#FE5863",
+        },
+        waiting: {
+          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);
+
+      Object.entries(PLACE_STATES).map(([key, { name, color }]) => {
+        let seriesItemData = dataList.map((item) => item[key]);
+        seriesList.push({
+          name: name,
+          type: "bar",
+          data: seriesItemData,
+          barWidth: 10,
+          barGap: "0",
+          itemStyle: {
+            barBorderRadius: [5, 5, 0, 0],
+            color: color,
+          },
+          label: {
+            show: false,
+          },
+        });
+      });
+
+      return {
+        tooltip: {
+          trigger: "axis",
+          axisPointer: {
+            type: "shadow",
+          },
+        },
+        legend: {
+          data: legendData,
+          top: "2%",
+          right: 0,
+          itemGap: 20,
+          itemWidth: 8,
+          itemHeight: 8,
+          textStyle: {
+            color: "#626A82",
+            fontSize: 14,
+          },
+        },
+        grid: {
+          left: "1%",
+          right: "1%",
+          bottom: "5%",
+          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: {
+              color: "#F0F4F9",
+            },
+          },
+          axisTick: { show: false },
+          splitLine: {
+            lineStyle: {
+              color: "#F0F4F9",
+            },
+          },
+          axisLabel: {
+            color: "#8C94AC",
+            fontSize: 14,
+            formatter: function (value) {
+              return Math.round(value * 100) + "%";
+            },
+          },
+        },
+        xAxis: {
+          type: "category",
+          data: yAxisLabels,
+          boundaryGap: ["5%", "5%"],
+          axisLine: {
+            lineStyle: {
+              color: "#F0F4F9",
+            },
+          },
+          axisTick: { show: false },
+          splitLine: {
+            show: false,
+            lineStyle: {
+              color: "#F0F4F9",
+            },
+          },
+          axisLabel: {
+            color: "#8C94AC",
+            fontSize: 14,
+            margin: 20,
+            align: "center",
+            formatter: (value) => {
+              return this.splitStrByStep(value, 4).join("\n");
+            },
+          },
+        },
+        series: seriesList,
+      };
+    },
+    splitStrByStep(str, step = 2) {
+      if (!step) return str;
+      if (str.length < step) return [str];
+
+      let strs = str.split("");
+      let strArr = [];
+      let part = [];
+      strs.map((element) => {
+        part.push(element);
+        if (part.length >= step) {
+          strArr.push(part.join(""));
+          part = [];
+        }
+      });
+      if (part.length) strArr.push(part.join(""));
+      return strArr;
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.chart-box {
+  height: 100%;
+  position: relative;
+}
+.chart-box .chart-none {
+  padding-top: 150px;
+  font-size: 20px;
+  text-align: center;
+  color: #8c94ac;
+}
+</style>

+ 1 - 0
src/main.js

@@ -23,6 +23,7 @@ import "./styles/bootstrap.scss";
 import "./styles/global.css";
 import "./styles/icons.scss";
 import "./styles/base.scss";
+import "./styles/element-ui-custom.scss";
 // styles end
 
 Vue.config.productionTip = false;

+ 32 - 0
src/plugins/VueCharts.js

@@ -0,0 +1,32 @@
+// import Vue from "vue";
+import VueCharts from "vue-echarts"; // refers to components/ECharts.vue in webpack
+// https://github.com/ecomfe/vue-echarts
+
+// import ECharts modules manually to reduce bundle size
+// 按需模块:https://github.com/apache/incubator-echarts/blob/master/index.js
+// component
+import "echarts/lib/component/title";
+import "echarts/lib/component/legend";
+import "echarts/lib/component/tooltip";
+import "echarts/lib/component/dataZoom";
+// import "echarts/lib/component/geo";
+// import "echarts/lib/component/visualMap";
+
+// chart
+import "echarts/lib/chart/bar";
+import "echarts/lib/chart/line";
+import "echarts/lib/chart/pie";
+// import "echarts/lib/chart/map";
+import "zrender/lib/svg/svg";
+// map
+// import "echarts/map/js/china";
+// import "echarts/map/js/china-contour";
+
+// If you want to use ECharts extensions, just import the extension package and it will work
+// Taking ECharts-GL as an example:
+// You only need to install the package with `npm install --save echarts-gl` and import it as follows
+// import "echarts-gl";
+
+// register component to use
+export default VueCharts;
+// Vue.component("v-chart", VueCharts);

+ 2 - 1
src/plugins/element.js

@@ -1,5 +1,6 @@
 import Vue from "vue";
 import Element from "element-ui";
-import "../styles/element-variables.scss";
+// import "../styles/element-variables.scss";
+import "element-ui/lib/theme-chalk/index.css";
 
 Vue.use(Element, { size: "small" });

+ 11 - 0
src/plugins/trtc.js

@@ -0,0 +1,11 @@
+import TRTC from "trtc-js-sdk";
+// 输出INFO以上日志等级
+TRTC.Logger.setLogLevel(TRTC.Logger.LogLevel.WARN);
+
+export const createClient = (options) => {
+  return TRTC.createClient(options);
+};
+
+export const createStream = (options) => {
+  return TRTC.createStream(options);
+};

+ 18 - 15
src/router/invigilation.js

@@ -1,12 +1,12 @@
 import ExamInvigilation from "../features/invigilation/ExamInvigilation/ExamInvigilation";
 import OnlinePatrol from "../features/invigilation/OnlinePatrol/OnlinePatrol";
 import RealtimeMonitoring from "../features/invigilation/RealtimeMonitoring/RealtimeMonitoring";
+import VideoCommunication from "../features/invigilation/RealtimeMonitoring/VideoCommunication";
+import WainingDetail from "../features/invigilation/RealtimeMonitoring/WainingDetail";
 import InvigilationDetail from "../features/invigilation/InvigilationDetail/InvigilationDetail";
 import WainingManage from "../features/invigilation/WainingManage/WainingManage";
-import WainingDetail from "../features/invigilation/WainingManage/WainingDetail";
 import ReexamApply from "../features/invigilation/ReexamApply/ReexamApply";
 import ProgressDetail from "../features/invigilation/ProgressDetail/ProgressDetail";
-import VideoCommunication from "../features/invigilation/VideoCommunication/VideoCommunication";
 import ReexamPending from "../features/invigilation/ReexamPending/ReexamPending";
 import ReexamChecked from "../features/invigilation/ReexamChecked/ReexamChecked";
 import ExamReport from "../features/invigilation/ExamReport/ExamReport";
@@ -28,6 +28,22 @@ const routes = [
     name: "RealtimeMonitoring",
     component: RealtimeMonitoring,
   },
+  {
+    path: "/invigilation/video-communication",
+    name: "VideoCommunication",
+    component: VideoCommunication,
+    meta: {
+      relate: "RealtimeMonitoring",
+    },
+  },
+  {
+    path: "/invigilation/waining-detail/:recordId",
+    name: "WainingDetail",
+    component: WainingDetail,
+    meta: {
+      relate: "RealtimeMonitoring",
+    },
+  },
   {
     path: "/invigilation/invigilation-detail",
     name: "InvigilationDetail",
@@ -38,14 +54,6 @@ const routes = [
     name: "WainingManage",
     component: WainingManage,
   },
-  {
-    path: "/invigilation/waining-detail/:id",
-    name: "WainingDetail",
-    component: WainingDetail,
-    meta: {
-      relate: "WainingManage",
-    },
-  },
   {
     path: "/invigilation/reexam-apply",
     name: "ReexamApply",
@@ -56,11 +64,6 @@ const routes = [
     name: "ProgressDetail",
     component: ProgressDetail,
   },
-  {
-    path: "/invigilation/video-communication",
-    name: "VideoCommunication",
-    component: VideoCommunication,
-  },
   {
     path: "/invigilation/reexam-pending",
     name: "ReexamPending",

+ 8 - 2
src/store/index.js

@@ -10,7 +10,13 @@ export default new Vuex.Store({
   modules: {
     user,
   },
-  state: {},
-  mutations: {},
+  state: {
+    isFullScreen: false,
+  },
+  mutations: {
+    setIsFullScreen(state, isFullScreen) {
+      state.isFullScreen = isFullScreen;
+    },
+  },
   actions: {},
 });

+ 31 - 3
src/styles/base.scss

@@ -1,3 +1,12 @@
+input::-webkit-input-placeholder,
+input::-moz-placeholder,
+input:-ms-input-placeholder,
+input:-moz-placeholder {
+  font-size: 14px;
+  font-weight: 400;
+  color: #8c94ac;
+}
+// part-box
 .part-box {
   padding: 20px;
   margin-bottom: 20px;
@@ -34,10 +43,16 @@
   &-filter {
     margin-bottom: 20px;
     background-color: #fff;
-    border-radius: 10px;
+    border-radius: 6px;
 
     div:nth-of-type(2) {
-      border-top: 1px solid #e9e9e9;
+      border-top: 1px solid #f0f4f9;
+    }
+    .line-split {
+      display: inline-block;
+      margin: 0 5px;
+      color: #ccd4e2;
+      font-weight: 600;
     }
 
     &-info {
@@ -70,6 +85,9 @@
       .el-form-item__label {
         margin-bottom: 0;
       }
+      .el-button {
+        vertical-align: top;
+      }
     }
   }
 }
@@ -88,6 +106,12 @@
   }
 }
 
+// other
+.echarts {
+  height: 100% !important;
+  width: 100% !important;
+}
+
 // :fullscreen
 .app-fullscreen {
   .nav-bar,
@@ -213,7 +237,7 @@
     font-size: 14px;
     display: inline-block;
     vertical-align: middle;
-    margin: 0 36px 0 0;
+    margin: 0 30px 0 0;
     line-height: 20px;
     color: #202b4b;
 
@@ -226,6 +250,10 @@
       color: #626a82;
       margin-right: 8px;
     }
+    > span:last-child {
+      color: #202b4b;
+      font-weight: 600;
+    }
 
     i.line-point {
       display: inline-block;

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

@@ -0,0 +1,108 @@
+// el-input
+.el-input {
+  // &.is-focus {
+  //   .el-input__inner {
+  //     border-color: $--color-primary !important;
+  //   }
+  // }
+  .el-input__inner {
+    border-radius: 6px;
+    border-color: #e8edf3;
+    background-color: #f0f4f9;
+    padding-left: 12px;
+  }
+}
+.el-input-number {
+  &.is-without-controls {
+    .el-input__inner {
+      padding: 0 12px;
+    }
+  }
+}
+
+// .el-button
+.el-button {
+  border-radius: 6px;
+}
+.el-button--small,
+.el-button--small.is-round {
+  padding: 8px 12px 9px;
+}
+
+// .el-table
+.el-table {
+  color: #626a82;
+  font-weight: 400;
+  background-color: #fff;
+  font-size: 14px;
+  border-radius: 6px;
+
+  &__header {
+    th {
+      color: #202b4b;
+      font-weight: bold;
+    }
+  }
+  tr.el-table__row {
+    border-top: 1px solid #f0f4f9;
+  }
+  td,
+  th {
+    padding-top: 16px;
+    padding-bottom: 16px;
+  }
+  // .el-table__row.row-danger {
+  //   color: $--color-danger;
+  // }
+}
+
+// el-pagination
+.el-pagination-li {
+  width: 32px;
+  height: 32px;
+  border-radius: 6px;
+  overflow: hidden;
+  background-color: #fff;
+}
+.el-pagination {
+  &.is-background {
+    .btn-prev,
+    .btn-next {
+      @extend .el-pagination-li;
+    }
+
+    .el-pager li {
+      color: #8c94ac;
+      margin: 0 4px;
+      line-height: 32px;
+
+      @extend .el-pagination-li;
+      &:not(.disabled).active {
+        color: #fff;
+        background-color: #5fc9fa;
+      }
+    }
+  }
+  &__total {
+    color: #8c94ac;
+    margin: 0 16px 0 6px;
+  }
+  &__sizes {
+    color: #8c94ac;
+    background-color: #fff;
+    .el-input__inner {
+      background-color: #fff;
+      border-color: #fff;
+    }
+  }
+  &__jump {
+    margin-left: 6px;
+    color: #8c94ac;
+    .el-input__inner {
+      background-color: #fff;
+      border-color: #fff;
+      padding-left: 10px;
+      padding-right: 10px;
+    }
+  }
+}

+ 1058 - 0
src/styles/element-var.scss

@@ -0,0 +1,1058 @@
+/* Element Chalk Variables */
+
+// Special comment for theme configurator
+// type|skipAutoTranslation|Category|Order
+// skipAutoTranslation 1
+
+/* Transition
+-------------------------- */
+$--all-transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) !default;
+$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default;
+$--fade-linear-transition: opacity 200ms linear !default;
+$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1),
+  opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default;
+$--border-transition-base: border-color 0.2s
+  cubic-bezier(0.645, 0.045, 0.355, 1) !default;
+$--color-transition-base: color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !default;
+
+/* Color
+-------------------------- */
+/// color|1|Brand Color|0
+$--color-primary: #409eff !default;
+/// color|1|Background Color|4
+$--color-white: #ffffff !default;
+/// color|1|Background Color|4
+$--color-black: #000000 !default;
+$--color-primary-light-1: mix(
+  $--color-white,
+  $--color-primary,
+  10%
+) !default; /* 53a8ff */
+$--color-primary-light-2: mix(
+  $--color-white,
+  $--color-primary,
+  20%
+) !default; /* 66b1ff */
+$--color-primary-light-3: mix(
+  $--color-white,
+  $--color-primary,
+  30%
+) !default; /* 79bbff */
+$--color-primary-light-4: mix(
+  $--color-white,
+  $--color-primary,
+  40%
+) !default; /* 8cc5ff */
+$--color-primary-light-5: mix(
+  $--color-white,
+  $--color-primary,
+  50%
+) !default; /* a0cfff */
+$--color-primary-light-6: mix(
+  $--color-white,
+  $--color-primary,
+  60%
+) !default; /* b3d8ff */
+$--color-primary-light-7: mix(
+  $--color-white,
+  $--color-primary,
+  70%
+) !default; /* c6e2ff */
+$--color-primary-light-8: mix(
+  $--color-white,
+  $--color-primary,
+  80%
+) !default; /* d9ecff */
+$--color-primary-light-9: mix(
+  $--color-white,
+  $--color-primary,
+  90%
+) !default; /* ecf5ff */
+/// color|1|Functional Color|1
+$--color-success: #67c23a !default;
+/// color|1|Functional Color|1
+$--color-warning: #e6a23c !default;
+/// color|1|Functional Color|1
+$--color-danger: #f56c6c !default;
+/// color|1|Functional Color|1
+$--color-info: #909399 !default;
+
+$--color-success-light: mix($--color-white, $--color-success, 80%) !default;
+$--color-warning-light: mix($--color-white, $--color-warning, 80%) !default;
+$--color-danger-light: mix($--color-white, $--color-danger, 80%) !default;
+$--color-info-light: mix($--color-white, $--color-info, 80%) !default;
+
+$--color-success-lighter: mix($--color-white, $--color-success, 90%) !default;
+$--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default;
+$--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default;
+$--color-info-lighter: mix($--color-white, $--color-info, 90%) !default;
+/// color|1|Font Color|2
+$--color-text-primary: #303133 !default;
+/// color|1|Font Color|2
+$--color-text-regular: #606266 !default;
+/// color|1|Font Color|2
+$--color-text-secondary: #909399 !default;
+/// color|1|Font Color|2
+$--color-text-placeholder: #c0c4cc !default;
+/// color|1|Border Color|3
+$--border-color-base: #dcdfe6 !default;
+/// color|1|Border Color|3
+$--border-color-light: #e4e7ed !default;
+/// color|1|Border Color|3
+$--border-color-lighter: #ebeef5 !default;
+/// color|1|Border Color|3
+$--border-color-extra-light: #f2f6fc !default;
+
+// Background
+/// color|1|Background Color|4
+$--background-color-base: #f5f7fa !default;
+
+/* Link
+-------------------------- */
+$--link-color: $--color-primary-light-2 !default;
+$--link-hover-color: $--color-primary !default;
+
+/* Border
+-------------------------- */
+$--border-width-base: 1px !default;
+$--border-style-base: solid !default;
+$--border-color-hover: $--color-text-placeholder !default;
+$--border-base: $--border-width-base $--border-style-base $--border-color-base !default;
+/// borderRadius|1|Radius|0
+$--border-radius-base: 4px !default;
+/// borderRadius|1|Radius|0
+$--border-radius-small: 2px !default;
+/// borderRadius|1|Radius|0
+$--border-radius-circle: 100% !default;
+/// borderRadius|1|Radius|0
+$--border-radius-zero: 0 !default;
+
+// Box-shadow
+/// boxShadow|1|Shadow|1
+$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04) !default;
+// boxShadow|1|Shadow|1
+$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.12) !default;
+/// boxShadow|1|Shadow|1
+$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default;
+
+/* Fill
+-------------------------- */
+$--fill-base: $--color-white !default;
+
+/* Typography
+-------------------------- */
+$--font-path: "fonts" !default;
+$--font-display: "auto" !default;
+/// fontSize|1|Font Size|0
+$--font-size-extra-large: 20px !default;
+/// fontSize|1|Font Size|0
+$--font-size-large: 18px !default;
+/// fontSize|1|Font Size|0
+$--font-size-medium: 16px !default;
+/// fontSize|1|Font Size|0
+$--font-size-base: 14px !default;
+/// fontSize|1|Font Size|0
+$--font-size-small: 13px !default;
+/// fontSize|1|Font Size|0
+$--font-size-extra-small: 12px !default;
+/// fontWeight|1|Font Weight|1
+$--font-weight-primary: 500 !default;
+/// fontWeight|1|Font Weight|1
+$--font-weight-secondary: 100 !default;
+/// fontLineHeight|1|Line Height|2
+$--font-line-height-primary: 24px !default;
+/// fontLineHeight|1|Line Height|2
+$--font-line-height-secondary: 16px !default;
+$--font-color-disabled-base: #bbb !default;
+/* Size
+-------------------------- */
+$--size-base: 14px !default;
+
+/* z-index
+-------------------------- */
+$--index-normal: 1 !default;
+$--index-top: 1000 !default;
+$--index-popper: 2000 !default;
+
+/* Disable base
+-------------------------- */
+$--disabled-fill-base: $--background-color-base !default;
+$--disabled-color-base: $--color-text-placeholder !default;
+$--disabled-border-base: $--border-color-light !default;
+
+/* Icon
+-------------------------- */
+$--icon-color: #666 !default;
+$--icon-color-base: $--color-info !default;
+
+/* Checkbox
+-------------------------- */
+/// fontSize||Font|1
+$--checkbox-font-size: 14px !default;
+/// fontWeight||Font|1
+$--checkbox-font-weight: $--font-weight-primary !default;
+/// color||Color|0
+$--checkbox-font-color: $--color-text-regular !default;
+$--checkbox-input-height: 14px !default;
+$--checkbox-input-width: 14px !default;
+/// borderRadius||Border|2
+$--checkbox-border-radius: $--border-radius-small !default;
+/// color||Color|0
+$--checkbox-background-color: $--color-white !default;
+$--checkbox-input-border: $--border-base !default;
+
+/// color||Color|0
+$--checkbox-disabled-border-color: $--border-color-base !default;
+$--checkbox-disabled-input-fill: #edf2fc !default;
+$--checkbox-disabled-icon-color: $--color-text-placeholder !default;
+
+$--checkbox-disabled-checked-input-fill: $--border-color-extra-light !default;
+$--checkbox-disabled-checked-input-border-color: $--border-color-base !default;
+$--checkbox-disabled-checked-icon-color: $--color-text-placeholder !default;
+
+/// color||Color|0
+$--checkbox-checked-font-color: $--color-primary !default;
+$--checkbox-checked-input-border-color: $--color-primary !default;
+/// color||Color|0
+$--checkbox-checked-background-color: $--color-primary !default;
+$--checkbox-checked-icon-color: $--fill-base !default;
+
+$--checkbox-input-border-color-hover: $--color-primary !default;
+/// height||Other|4
+$--checkbox-bordered-height: 40px !default;
+/// padding||Spacing|3
+$--checkbox-bordered-padding: 9px 20px 9px 10px !default;
+/// padding||Spacing|3
+$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default;
+/// padding||Spacing|3
+$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default;
+/// padding||Spacing|3
+$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default;
+$--checkbox-bordered-medium-input-height: 14px !default;
+$--checkbox-bordered-medium-input-width: 14px !default;
+/// height||Other|4
+$--checkbox-bordered-medium-height: 36px !default;
+$--checkbox-bordered-small-input-height: 12px !default;
+$--checkbox-bordered-small-input-width: 12px !default;
+/// height||Other|4
+$--checkbox-bordered-small-height: 32px !default;
+$--checkbox-bordered-mini-input-height: 12px !default;
+$--checkbox-bordered-mini-input-width: 12px !default;
+/// height||Other|4
+$--checkbox-bordered-mini-height: 28px !default;
+
+/// color||Color|0
+$--checkbox-button-checked-background-color: $--color-primary !default;
+/// color||Color|0
+$--checkbox-button-checked-font-color: $--color-white !default;
+/// color||Color|0
+$--checkbox-button-checked-border-color: $--color-primary !default;
+
+/* Radio
+-------------------------- */
+/// fontSize||Font|1
+$--radio-font-size: $--font-size-base !default;
+/// fontWeight||Font|1
+$--radio-font-weight: $--font-weight-primary !default;
+/// color||Color|0
+$--radio-font-color: $--color-text-regular !default;
+$--radio-input-height: 14px !default;
+$--radio-input-width: 14px !default;
+/// borderRadius||Border|2
+$--radio-input-border-radius: $--border-radius-circle !default;
+/// color||Color|0
+$--radio-input-background-color: $--color-white !default;
+$--radio-input-border: $--border-base !default;
+/// color||Color|0
+$--radio-input-border-color: $--border-color-base !default;
+/// color||Color|0
+$--radio-icon-color: $--color-white !default;
+
+$--radio-disabled-input-border-color: $--disabled-border-base !default;
+$--radio-disabled-input-fill: $--disabled-fill-base !default;
+$--radio-disabled-icon-color: $--disabled-fill-base !default;
+
+$--radio-disabled-checked-input-border-color: $--disabled-border-base !default;
+$--radio-disabled-checked-input-fill: $--disabled-fill-base !default;
+$--radio-disabled-checked-icon-color: $--color-text-placeholder !default;
+
+/// color||Color|0
+$--radio-checked-font-color: $--color-primary !default;
+/// color||Color|0
+$--radio-checked-input-border-color: $--color-primary !default;
+/// color||Color|0
+$--radio-checked-input-background-color: $--color-white !default;
+/// color||Color|0
+$--radio-checked-icon-color: $--color-primary !default;
+
+$--radio-input-border-color-hover: $--color-primary !default;
+
+$--radio-bordered-height: 40px !default;
+$--radio-bordered-padding: 12px 20px 0 10px !default;
+$--radio-bordered-medium-padding: 10px 20px 0 10px !default;
+$--radio-bordered-small-padding: 8px 15px 0 10px !default;
+$--radio-bordered-mini-padding: 6px 15px 0 10px !default;
+$--radio-bordered-medium-input-height: 14px !default;
+$--radio-bordered-medium-input-width: 14px !default;
+$--radio-bordered-medium-height: 36px !default;
+$--radio-bordered-small-input-height: 12px !default;
+$--radio-bordered-small-input-width: 12px !default;
+$--radio-bordered-small-height: 32px !default;
+$--radio-bordered-mini-input-height: 12px !default;
+$--radio-bordered-mini-input-width: 12px !default;
+$--radio-bordered-mini-height: 28px !default;
+
+/// fontSize||Font|1
+$--radio-button-font-size: $--font-size-base !default;
+/// color||Color|0
+$--radio-button-checked-background-color: $--color-primary !default;
+/// color||Color|0
+$--radio-button-checked-font-color: $--color-white !default;
+/// color||Color|0
+$--radio-button-checked-border-color: $--color-primary !default;
+$--radio-button-disabled-checked-fill: $--border-color-extra-light !default;
+
+/* Select
+-------------------------- */
+$--select-border-color-hover: $--border-color-hover !default;
+$--select-disabled-border: $--disabled-border-base !default;
+/// fontSize||Font|1
+$--select-font-size: $--font-size-base !default;
+$--select-close-hover-color: $--color-text-secondary !default;
+
+$--select-input-color: $--color-text-placeholder !default;
+$--select-multiple-input-color: #666 !default;
+/// color||Color|0
+$--select-input-focus-border-color: $--color-primary !default;
+/// fontSize||Font|1
+$--select-input-font-size: 14px !default;
+
+$--select-option-color: $--color-text-regular !default;
+$--select-option-disabled-color: $--color-text-placeholder !default;
+$--select-option-disabled-background: $--color-white !default;
+/// height||Other|4
+$--select-option-height: 34px !default;
+$--select-option-hover-background: $--background-color-base !default;
+/// color||Color|0
+$--select-option-selected-font-color: $--color-primary !default;
+$--select-option-selected-hover: $--background-color-base !default;
+
+$--select-group-color: $--color-info !default;
+$--select-group-height: 30px !default;
+$--select-group-font-size: 12px !default;
+
+$--select-dropdown-background: $--color-white !default;
+$--select-dropdown-shadow: $--box-shadow-light !default;
+$--select-dropdown-empty-color: #999 !default;
+/// height||Other|4
+$--select-dropdown-max-height: 274px !default;
+$--select-dropdown-padding: 6px 0 !default;
+$--select-dropdown-empty-padding: 10px 0 !default;
+$--select-dropdown-border: solid 1px $--border-color-light !default;
+
+/* Alert
+-------------------------- */
+$--alert-padding: 8px 16px !default;
+/// borderRadius||Border|2
+$--alert-border-radius: $--border-radius-base !default;
+/// fontSize||Font|1
+$--alert-title-font-size: 13px !default;
+/// fontSize||Font|1
+$--alert-description-font-size: 12px !default;
+/// fontSize||Font|1
+$--alert-close-font-size: 12px !default;
+/// fontSize||Font|1
+$--alert-close-customed-font-size: 13px !default;
+
+$--alert-success-color: $--color-success-lighter !default;
+$--alert-info-color: $--color-info-lighter !default;
+$--alert-warning-color: $--color-warning-lighter !default;
+$--alert-danger-color: $--color-danger-lighter !default;
+
+/// height||Other|4
+$--alert-icon-size: 16px !default;
+/// height||Other|4
+$--alert-icon-large-size: 28px !default;
+
+/* MessageBox
+-------------------------- */
+/// color||Color|0
+$--messagebox-title-color: $--color-text-primary !default;
+$--msgbox-width: 420px !default;
+$--msgbox-border-radius: 4px !default;
+/// fontSize||Font|1
+$--messagebox-font-size: $--font-size-large !default;
+/// fontSize||Font|1
+$--messagebox-content-font-size: $--font-size-base !default;
+/// color||Color|0
+$--messagebox-content-color: $--color-text-regular !default;
+/// fontSize||Font|1
+$--messagebox-error-font-size: 12px !default;
+$--msgbox-padding-primary: 15px !default;
+/// color||Color|0
+$--messagebox-success-color: $--color-success !default;
+/// color||Color|0
+$--messagebox-info-color: $--color-info !default;
+/// color||Color|0
+$--messagebox-warning-color: $--color-warning !default;
+/// color||Color|0
+$--messagebox-danger-color: $--color-danger !default;
+
+/* Message
+-------------------------- */
+$--message-shadow: $--box-shadow-base !default;
+$--message-min-width: 380px !default;
+$--message-background-color: #edf2fc !default;
+$--message-padding: 15px 15px 15px 20px !default;
+/// color||Color|0
+$--message-close-icon-color: $--color-text-placeholder !default;
+/// height||Other|4
+$--message-close-size: 16px !default;
+/// color||Color|0
+$--message-close-hover-color: $--color-text-secondary !default;
+
+/// color||Color|0
+$--message-success-font-color: $--color-success !default;
+/// color||Color|0
+$--message-info-font-color: $--color-info !default;
+/// color||Color|0
+$--message-warning-font-color: $--color-warning !default;
+/// color||Color|0
+$--message-danger-font-color: $--color-danger !default;
+
+/* Notification
+-------------------------- */
+$--notification-width: 330px !default;
+/// padding||Spacing|3
+$--notification-padding: 14px 26px 14px 13px !default;
+$--notification-radius: 8px !default;
+$--notification-shadow: $--box-shadow-light !default;
+/// color||Color|0
+$--notification-border-color: $--border-color-lighter !default;
+$--notification-icon-size: 24px !default;
+$--notification-close-font-size: $--message-close-size !default;
+$--notification-group-margin-left: 13px !default;
+$--notification-group-margin-right: 8px !default;
+/// fontSize||Font|1
+$--notification-content-font-size: $--font-size-base !default;
+/// color||Color|0
+$--notification-content-color: $--color-text-regular !default;
+/// fontSize||Font|1
+$--notification-title-font-size: 16px !default;
+/// color||Color|0
+$--notification-title-color: $--color-text-primary !default;
+
+/// color||Color|0
+$--notification-close-color: $--color-text-secondary !default;
+/// color||Color|0
+$--notification-close-hover-color: $--color-text-regular !default;
+
+/// color||Color|0
+$--notification-success-icon-color: $--color-success !default;
+/// color||Color|0
+$--notification-info-icon-color: $--color-info !default;
+/// color||Color|0
+$--notification-warning-icon-color: $--color-warning !default;
+/// color||Color|0
+$--notification-danger-icon-color: $--color-danger !default;
+
+/* Input
+-------------------------- */
+$--input-font-size: $--font-size-base !default;
+/// color||Color|0
+$--input-font-color: $--color-text-regular !default;
+/// height||Other|4
+$--input-width: 140px !default;
+/// height||Other|4
+$--input-height: 40px !default;
+$--input-border: $--border-base !default;
+$--input-border-color: $--border-color-base !default;
+/// borderRadius||Border|2
+$--input-border-radius: $--border-radius-base !default;
+$--input-border-color-hover: $--border-color-hover !default;
+/// color||Color|0
+$--input-background-color: $--color-white !default;
+$--input-fill-disabled: $--disabled-fill-base !default;
+$--input-color-disabled: $--font-color-disabled-base !default;
+/// color||Color|0
+$--input-icon-color: $--color-text-placeholder !default;
+/// color||Color|0
+$--input-placeholder-color: $--color-text-placeholder !default;
+$--input-max-width: 314px !default;
+
+$--input-hover-border: $--border-color-hover !default;
+$--input-clear-hover-color: $--color-text-secondary !default;
+
+$--input-focus-border: $--color-primary !default;
+$--input-focus-fill: $--color-white !default;
+
+$--input-disabled-fill: $--disabled-fill-base !default;
+$--input-disabled-border: $--disabled-border-base !default;
+$--input-disabled-color: $--disabled-color-base !default;
+$--input-disabled-placeholder-color: $--color-text-placeholder !default;
+
+/// fontSize||Font|1
+$--input-medium-font-size: 14px !default;
+/// height||Other|4
+$--input-medium-height: 36px !default;
+/// fontSize||Font|1
+$--input-small-font-size: 13px !default;
+/// height||Other|4
+$--input-small-height: 32px !default;
+/// fontSize||Font|1
+$--input-mini-font-size: 12px !default;
+/// height||Other|4
+$--input-mini-height: 28px !default;
+
+/* Cascader
+-------------------------- */
+/// color||Color|0
+$--cascader-menu-font-color: $--color-text-regular !default;
+/// color||Color|0
+$--cascader-menu-selected-font-color: $--color-primary !default;
+$--cascader-menu-fill: $--fill-base !default;
+$--cascader-menu-font-size: $--font-size-base !default;
+$--cascader-menu-radius: $--border-radius-base !default;
+$--cascader-menu-border: solid 1px $--border-color-light !default;
+$--cascader-menu-shadow: $--box-shadow-light !default;
+$--cascader-node-background-hover: $--background-color-base !default;
+$--cascader-node-color-disabled: $--color-text-placeholder !default;
+$--cascader-color-empty: $--color-text-placeholder !default;
+$--cascader-tag-background: #f0f2f5;
+
+/* Group
+-------------------------- */
+$--group-option-flex: 0 0 (1/5) * 100% !default;
+$--group-option-offset-bottom: 12px !default;
+$--group-option-fill-hover: rgba($--color-black, 0.06) !default;
+$--group-title-color: $--color-black !default;
+$--group-title-font-size: $--font-size-base !default;
+$--group-title-width: 66px !default;
+
+/* Tab
+-------------------------- */
+$--tab-font-size: $--font-size-base !default;
+$--tab-border-line: 1px solid #e4e4e4 !default;
+$--tab-header-color-active: $--color-text-secondary !default;
+$--tab-header-color-hover: $--color-text-regular !default;
+$--tab-header-color: $--color-text-regular !default;
+$--tab-header-fill-active: rgba($--color-black, 0.06) !default;
+$--tab-header-fill-hover: rgba($--color-black, 0.06) !default;
+$--tab-vertical-header-width: 90px !default;
+$--tab-vertical-header-count-color: $--color-white !default;
+$--tab-vertical-header-count-fill: $--color-text-secondary !default;
+
+/* Button
+-------------------------- */
+/// fontSize||Font|1
+$--button-font-size: $--font-size-base !default;
+/// fontWeight||Font|1
+$--button-font-weight: $--font-weight-primary !default;
+/// borderRadius||Border|2
+$--button-border-radius: $--border-radius-base !default;
+/// padding||Spacing|3
+$--button-padding-vertical: 12px !default;
+/// padding||Spacing|3
+$--button-padding-horizontal: 20px !default;
+
+/// fontSize||Font|1
+$--button-medium-font-size: $--font-size-base !default;
+/// borderRadius||Border|2
+$--button-medium-border-radius: $--border-radius-base !default;
+/// padding||Spacing|3
+$--button-medium-padding-vertical: 10px !default;
+/// padding||Spacing|3
+$--button-medium-padding-horizontal: 20px !default;
+
+/// fontSize||Font|1
+$--button-small-font-size: 12px !default;
+$--button-small-border-radius: #{$--border-radius-base - 1} !default;
+/// padding||Spacing|3
+$--button-small-padding-vertical: 9px !default;
+/// padding||Spacing|3
+$--button-small-padding-horizontal: 15px !default;
+/// fontSize||Font|1
+$--button-mini-font-size: 12px !default;
+$--button-mini-border-radius: #{$--border-radius-base - 1} !default;
+/// padding||Spacing|3
+$--button-mini-padding-vertical: 7px !default;
+/// padding||Spacing|3
+$--button-mini-padding-horizontal: 15px !default;
+
+/// color||Color|0
+$--button-default-font-color: $--color-text-regular !default;
+/// color||Color|0
+$--button-default-background-color: $--color-white !default;
+/// color||Color|0
+$--button-default-border-color: $--border-color-base !default;
+
+/// color||Color|0
+$--button-disabled-font-color: $--color-text-placeholder !default;
+/// color||Color|0
+$--button-disabled-background-color: $--color-white !default;
+/// color||Color|0
+$--button-disabled-border-color: $--border-color-lighter !default;
+
+/// color||Color|0
+$--button-primary-border-color: $--color-primary !default;
+/// color||Color|0
+$--button-primary-font-color: $--color-white !default;
+/// color||Color|0
+$--button-primary-background-color: $--color-primary !default;
+/// color||Color|0
+$--button-success-border-color: $--color-success !default;
+/// color||Color|0
+$--button-success-font-color: $--color-white !default;
+/// color||Color|0
+$--button-success-background-color: $--color-success !default;
+/// color||Color|0
+$--button-warning-border-color: $--color-warning !default;
+/// color||Color|0
+$--button-warning-font-color: $--color-white !default;
+/// color||Color|0
+$--button-warning-background-color: $--color-warning !default;
+/// color||Color|0
+$--button-danger-border-color: $--color-danger !default;
+/// color||Color|0
+$--button-danger-font-color: $--color-white !default;
+/// color||Color|0
+$--button-danger-background-color: $--color-danger !default;
+/// color||Color|0
+$--button-info-border-color: $--color-info !default;
+/// color||Color|0
+$--button-info-font-color: $--color-white !default;
+/// color||Color|0
+$--button-info-background-color: $--color-info !default;
+
+$--button-hover-tint-percent: 20% !default;
+$--button-active-shade-percent: 10% !default;
+
+/* cascader
+-------------------------- */
+$--cascader-height: 200px !default;
+
+/* Switch
+-------------------------- */
+/// color||Color|0
+$--switch-on-color: $--color-primary !default;
+/// color||Color|0
+$--switch-off-color: $--border-color-base !default;
+/// fontSize||Font|1
+$--switch-font-size: $--font-size-base !default;
+$--switch-core-border-radius: 10px !default;
+// height||Other|4 TODO: width 代码写死的40px 所以下面这三个属性都没意义
+$--switch-width: 40px !default;
+// height||Other|4
+$--switch-height: 20px !default;
+// height||Other|4
+$--switch-button-size: 16px !default;
+
+/* Dialog
+-------------------------- */
+$--dialog-background-color: $--color-white !default;
+$--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default;
+/// fontSize||Font|1
+$--dialog-title-font-size: $--font-size-large !default;
+/// fontSize||Font|1
+$--dialog-content-font-size: 14px !default;
+/// fontLineHeight||LineHeight|2
+$--dialog-font-line-height: $--font-line-height-primary !default;
+/// padding||Spacing|3
+$--dialog-padding-primary: 20px !default;
+
+/* Table
+-------------------------- */
+/// color||Color|0
+$--table-border-color: $--border-color-lighter !default;
+$--table-border: 1px solid $--table-border-color !default;
+/// color||Color|0
+$--table-font-color: $--color-text-regular !default;
+/// color||Color|0
+$--table-header-font-color: $--color-text-secondary !default;
+/// color||Color|0
+$--table-row-hover-background-color: $--background-color-base !default;
+$--table-current-row-background-color: $--color-primary-light-9 !default;
+/// color||Color|0
+$--table-header-background-color: $--color-white !default;
+$--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, 0.12) !default;
+
+/* Pagination
+-------------------------- */
+/// fontSize||Font|1
+$--pagination-font-size: 13px !default;
+/// color||Color|0
+$--pagination-background-color: $--color-white !default;
+/// color||Color|0
+$--pagination-font-color: $--color-text-primary !default;
+$--pagination-border-radius: 3px !default;
+/// color||Color|0
+$--pagination-button-color: $--color-text-primary !default;
+/// height||Other|4
+$--pagination-button-width: 35.5px !default;
+/// height||Other|4
+$--pagination-button-height: 28px !default;
+/// color||Color|0
+$--pagination-button-disabled-color: $--color-text-placeholder !default;
+/// color||Color|0
+$--pagination-button-disabled-background-color: $--color-white !default;
+/// color||Color|0
+$--pagination-hover-color: $--color-primary !default;
+
+/* Popup
+-------------------------- */
+/// color||Color|0
+$--popup-modal-background-color: $--color-black !default;
+/// opacity||Other|1
+$--popup-modal-opacity: 0.5 !default;
+
+/* Popover
+-------------------------- */
+/// color||Color|0
+$--popover-background-color: $--color-white !default;
+/// fontSize||Font|1
+$--popover-font-size: $--font-size-base !default;
+/// color||Color|0
+$--popover-border-color: $--border-color-lighter !default;
+$--popover-arrow-size: 6px !default;
+/// padding||Spacing|3
+$--popover-padding: 12px !default;
+$--popover-padding-large: 18px 20px !default;
+/// fontSize||Font|1
+$--popover-title-font-size: 16px !default;
+/// color||Color|0
+$--popover-title-font-color: $--color-text-primary !default;
+
+/* Tooltip
+-------------------------- */
+/// color|1|Color|0
+$--tooltip-fill: $--color-text-primary !default;
+/// color|1|Color|0
+$--tooltip-color: $--color-white !default;
+/// fontSize||Font|1
+$--tooltip-font-size: 12px !default;
+/// color||Color|0
+$--tooltip-border-color: $--color-text-primary !default;
+$--tooltip-arrow-size: 6px !default;
+/// padding||Spacing|3
+$--tooltip-padding: 10px !default;
+
+/* Tag
+-------------------------- */
+/// color||Color|0
+$--tag-info-color: $--color-info !default;
+/// color||Color|0
+$--tag-primary-color: $--color-primary !default;
+/// color||Color|0
+$--tag-success-color: $--color-success !default;
+/// color||Color|0
+$--tag-warning-color: $--color-warning !default;
+/// color||Color|0
+$--tag-danger-color: $--color-danger !default;
+/// fontSize||Font|1
+$--tag-font-size: 12px !default;
+$--tag-border-radius: 4px !default;
+$--tag-padding: 0 10px !default;
+
+/* Tree
+-------------------------- */
+/// color||Color|0
+$--tree-node-hover-background-color: $--background-color-base !default;
+/// color||Color|0
+$--tree-font-color: $--color-text-regular !default;
+/// color||Color|0
+$--tree-expand-icon-color: $--color-text-placeholder !default;
+
+/* Dropdown
+-------------------------- */
+$--dropdown-menu-box-shadow: $--box-shadow-light !default;
+$--dropdown-menuItem-hover-fill: $--color-primary-light-9 !default;
+$--dropdown-menuItem-hover-color: $--link-color !default;
+
+/* Badge
+-------------------------- */
+/// color||Color|0
+$--badge-background-color: $--color-danger !default;
+$--badge-radius: 10px !default;
+/// fontSize||Font|1
+$--badge-font-size: 12px !default;
+/// padding||Spacing|3
+$--badge-padding: 6px !default;
+/// height||Other|4
+$--badge-size: 18px !default;
+
+/* Card
+--------------------------*/
+/// color||Color|0
+$--card-border-color: $--border-color-lighter !default;
+$--card-border-radius: 4px !default;
+/// padding||Spacing|3
+$--card-padding: 20px !default;
+
+/* Slider
+--------------------------*/
+/// color||Color|0
+$--slider-main-background-color: $--color-primary !default;
+/// color||Color|0
+$--slider-runway-background-color: $--border-color-light !default;
+$--slider-button-hover-color: mix($--color-primary, black, 97%) !default;
+$--slider-stop-background-color: $--color-white !default;
+$--slider-disable-color: $--color-text-placeholder !default;
+$--slider-margin: 16px 0 !default;
+$--slider-border-radius: 3px !default;
+/// height|1|Other|4
+$--slider-height: 6px !default;
+/// height||Other|4
+$--slider-button-size: 16px !default;
+$--slider-button-wrapper-size: 36px !default;
+$--slider-button-wrapper-offset: -15px !default;
+
+/* Steps
+--------------------------*/
+$--steps-border-color: $--disabled-border-base !default;
+$--steps-border-radius: 4px !default;
+$--steps-padding: 20px !default;
+
+/* Menu
+--------------------------*/
+/// fontSize||Font|1
+$--menu-item-font-size: $--font-size-base !default;
+/// color||Color|0
+$--menu-item-font-color: $--color-text-primary !default;
+/// color||Color|0
+$--menu-background-color: $--color-white !default;
+$--menu-item-hover-fill: $--color-primary-light-9 !default;
+
+/* Rate
+--------------------------*/
+$--rate-height: 20px !default;
+/// fontSize||Font|1
+$--rate-font-size: $--font-size-base !default;
+/// height||Other|3
+$--rate-icon-size: 18px !default;
+/// margin||Spacing|2
+$--rate-icon-margin: 6px !default;
+$--rate-icon-color: $--color-text-placeholder !default;
+
+/* DatePicker
+--------------------------*/
+$--datepicker-font-color: $--color-text-regular !default;
+/// color|1|Color|0
+$--datepicker-off-font-color: $--color-text-placeholder !default;
+/// color||Color|0
+$--datepicker-header-font-color: $--color-text-regular !default;
+$--datepicker-icon-color: $--color-text-primary !default;
+$--datepicker-border-color: $--disabled-border-base !default;
+$--datepicker-inner-border-color: #e4e4e4 !default;
+/// color||Color|0
+$--datepicker-inrange-background-color: $--border-color-extra-light !default;
+/// color||Color|0
+$--datepicker-inrange-hover-background-color: $--border-color-extra-light !default;
+/// color||Color|0
+$--datepicker-active-color: $--color-primary !default;
+/// color||Color|0
+$--datepicker-hover-font-color: $--color-primary !default;
+$--datepicker-cell-hover-color: #fff !default;
+
+/* Loading
+--------------------------*/
+/// height||Other|4
+$--loading-spinner-size: 42px !default;
+/// height||Other|4
+$--loading-fullscreen-spinner-size: 50px !default;
+
+/* Scrollbar
+--------------------------*/
+$--scrollbar-background-color: rgba($--color-text-secondary, 0.3) !default;
+$--scrollbar-hover-background-color: rgba(
+  $--color-text-secondary,
+  0.5
+) !default;
+
+/* Carousel
+--------------------------*/
+/// fontSize||Font|1
+$--carousel-arrow-font-size: 12px !default;
+$--carousel-arrow-size: 36px !default;
+$--carousel-arrow-background: rgba(31, 45, 61, 0.11) !default;
+$--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23) !default;
+/// width||Other|4
+$--carousel-indicator-width: 30px !default;
+/// height||Other|4
+$--carousel-indicator-height: 2px !default;
+$--carousel-indicator-padding-horizontal: 4px !default;
+$--carousel-indicator-padding-vertical: 12px !default;
+$--carousel-indicator-out-color: $--border-color-hover !default;
+
+/* Collapse
+--------------------------*/
+/// color||Color|0
+$--collapse-border-color: $--border-color-lighter !default;
+/// height||Other|4
+$--collapse-header-height: 48px !default;
+/// color||Color|0
+$--collapse-header-background-color: $--color-white !default;
+/// color||Color|0
+$--collapse-header-font-color: $--color-text-primary !default;
+/// fontSize||Font|1
+$--collapse-header-font-size: 13px !default;
+/// color||Color|0
+$--collapse-content-background-color: $--color-white !default;
+/// fontSize||Font|1
+$--collapse-content-font-size: 13px !default;
+/// color||Color|0
+$--collapse-content-font-color: $--color-text-primary !default;
+
+/* Transfer
+--------------------------*/
+$--transfer-border-color: $--border-color-lighter !default;
+$--transfer-border-radius: $--border-radius-base !default;
+/// height||Other|4
+$--transfer-panel-width: 200px !default;
+/// height||Other|4
+$--transfer-panel-header-height: 40px !default;
+/// color||Color|0
+$--transfer-panel-header-background-color: $--background-color-base !default;
+/// height||Other|4
+$--transfer-panel-footer-height: 40px !default;
+/// height||Other|4
+$--transfer-panel-body-height: 246px !default;
+/// height||Other|4
+$--transfer-item-height: 30px !default;
+/// height||Other|4
+$--transfer-filter-height: 32px !default;
+
+/* Header
+  --------------------------*/
+$--header-padding: 0 20px !default;
+
+/* Footer
+--------------------------*/
+$--footer-padding: 0 20px !default;
+
+/* Main
+--------------------------*/
+$--main-padding: 20px !default;
+
+/* Timeline
+--------------------------*/
+$--timeline-node-size-normal: 12px !default;
+$--timeline-node-size-large: 14px !default;
+$--timeline-node-color: $--border-color-light !default;
+
+/* Backtop
+--------------------------*/
+/// color||Color|0
+$--backtop-background-color: $--color-white !default;
+/// color||Color|0
+$--backtop-font-color: $--color-primary !default;
+/// color||Color|0
+$--backtop-hover-background-color: $--border-color-extra-light !default;
+
+/* Link
+--------------------------*/
+/// fontSize||Font|1
+$--link-font-size: $--font-size-base !default;
+/// fontWeight||Font|1
+$--link-font-weight: $--font-weight-primary !default;
+/// color||Color|0
+$--link-default-font-color: $--color-text-regular !default;
+/// color||Color|0
+$--link-default-active-color: $--color-primary !default;
+/// color||Color|0
+$--link-disabled-font-color: $--color-text-placeholder !default;
+/// color||Color|0
+$--link-primary-font-color: $--color-primary !default;
+/// color||Color|0
+$--link-success-font-color: $--color-success !default;
+/// color||Color|0
+$--link-warning-font-color: $--color-warning !default;
+/// color||Color|0
+$--link-danger-font-color: $--color-danger !default;
+/// color||Color|0
+$--link-info-font-color: $--color-info !default;
+/* Calendar
+--------------------------*/
+/// border||Other|4
+$--calendar-border: $--table-border !default;
+/// color||Other|4
+$--calendar-selected-background-color: #f2f8fe !default;
+$--calendar-cell-width: 85px !default;
+
+/* Form
+-------------------------- */
+/// fontSize||Font|1
+$--form-label-font-size: $--font-size-base !default;
+
+/* Avatar
+--------------------------*/
+/// color||Color|0
+$--avatar-font-color: #fff !default;
+/// color||Color|0
+$--avatar-background-color: #c0c4cc !default;
+/// fontSize||Font Size|1
+$--avatar-text-font-size: 14px !default;
+/// fontSize||Font Size|1
+$--avatar-icon-font-size: 18px !default;
+/// borderRadius||Border|2
+$--avatar-border-radius: $--border-radius-base !default;
+/// size|1|Avatar Size|3
+$--avatar-large-size: 40px !default;
+/// size|1|Avatar Size|3
+$--avatar-medium-size: 36px !default;
+/// size|1|Avatar Size|3
+$--avatar-small-size: 28px !default;
+
+/* Break-point
+--------------------------*/
+$--sm: 768px !default;
+$--md: 992px !default;
+$--lg: 1200px !default;
+$--xl: 1920px !default;
+
+$--breakpoints: (
+  "xs": (
+    max-width: $--sm - 1,
+  ),
+  "sm": (
+    min-width: $--sm,
+  ),
+  "md": (
+    min-width: $--md,
+  ),
+  "lg": (
+    min-width: $--lg,
+  ),
+  "xl": (
+    min-width: $--xl,
+  ),
+);
+
+$--breakpoints-spec: (
+  "xs-only": (
+    max-width: $--sm - 1,
+  ),
+  "sm-and-up": (
+    min-width: $--sm,
+  ),
+  "sm-only": "(min-width: #{$--sm}) and (max-width: #{$--md - 1})",
+  "sm-and-down": (
+    max-width: $--md - 1,
+  ),
+  "md-and-up": (
+    min-width: $--md,
+  ),
+  "md-only": "(min-width: #{$--md}) and (max-width: #{$--lg - 1})",
+  "md-and-down": (
+    max-width: $--lg - 1,
+  ),
+  "lg-and-up": (
+    min-width: $--lg,
+  ),
+  "lg-only": "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})",
+  "lg-and-down": (
+    max-width: $--xl - 1,
+  ),
+  "xl-only": (
+    min-width: $--xl,
+  ),
+);

+ 6 - 0
src/styles/icons.scss

@@ -41,6 +41,12 @@
   &-clean {
     background-image: url(../assets/icon-clean.png);
   }
+  &-handle {
+    background-image: url(../assets/icon-handle.png);
+  }
+  &-over {
+    background-image: url(../assets/icon-over.png);
+  }
   &-scan {
     background-image: url(../assets/icon-scan.png);
   }

+ 20 - 8
src/views/Layout/components/NavBar.vue

@@ -35,9 +35,9 @@
             <span v-if="username">{{ username }},欢迎你</span>
           </div>
         </li>
-        <li>
+        <li v-if="showFullScreenBtn">
           <div class="menu-item" @click="toFullscreen">
-            <i class="icon icon-full-screen"></i>
+            <i class="icon icon-scan"></i>
             <span>全屏</span>
           </div>
         </li>
@@ -66,6 +66,12 @@ export default {
     username() {
       return this.$store.state.user.name;
     },
+    isFullScreen() {
+      return this.$store.state.isFullScreen;
+    },
+    showFullScreenBtn() {
+      return this.$route.name === "ExamInvigilation";
+    },
   },
   data() {
     return {
@@ -93,6 +99,7 @@ export default {
       if (curRouter) this.toPage({ name: mkey });
     });
     this.registFullscreenChange();
+    this.$store.commit("setIsFullScreen", this.checkDocIsFullscreen());
   },
   methods: {
     toPage(nav) {
@@ -113,11 +120,11 @@ export default {
     },
     registFullscreenChange() {
       document.documentElement.onfullscreenchange = () => {
-        if (this.checkDocIsFullscreen()) {
-          this.isFullscreen = true;
+        const isFullScreen = this.checkDocIsFullscreen();
+        this.$store.commit("setIsFullScreen", isFullScreen);
+        if (isFullScreen) {
           document.body.className += "app-fullscreen";
         } else {
-          this.isFullscreen = false;
           document.body.className = document.body.className.replace(
             "app-fullscreen",
             ""
@@ -201,9 +208,7 @@ export default {
   &-menu {
     float: left;
   }
-  &-user {
-    float: right;
-  }
+
   .menu-list {
     ul {
       padding: 0;
@@ -232,5 +237,12 @@ export default {
       }
     }
   }
+
+  &-user {
+    float: right;
+    &.menu-list li {
+      padding: 20px 10px;
+    }
+  }
 }
 </style>

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

@@ -113,10 +113,6 @@ const invigilationMenuConfig = [
         title: "进度查询",
         name: "ProgressDetail",
       },
-      {
-        title: "视频互动",
-        name: "VideoCommunication",
-      },
     ],
   },
   {

+ 26 - 0
yarn.lock

@@ -4372,6 +4372,13 @@ ecc-jsbn@~0.1.1:
     jsbn "~0.1.0"
     safer-buffer "^2.1.0"
 
+echarts@^4.8.0:
+  version "4.8.0"
+  resolved "https://registry.npm.taobao.org/echarts/download/echarts-4.8.0.tgz?cache=0&sync_timestamp=1597689252070&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fecharts%2Fdownload%2Fecharts-4.8.0.tgz#b2c1cfb9229b13d368ee104fc8eea600b574d4c4"
+  integrity sha1-ssHPuSKbE9No7hBPyO6mALV01MQ=
+  dependencies:
+    zrender "4.3.1"
+
 editorconfig@^0.15.3:
   version "0.15.3"
   resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5"
@@ -9486,6 +9493,11 @@ requires-port@^1.0.0:
   resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
   integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
 
+resize-detector@^0.1.10:
+  version "0.1.10"
+  resolved "https://registry.npm.taobao.org/resize-detector/download/resize-detector-0.1.10.tgz#1da3f961aa5f914ccbcfd3752d52fd45beeb692c"
+  integrity sha1-HaP5YapfkUzLz9N1LVL9Rb7raSw=
+
 resize-observer-polyfill@^1.5.0:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
@@ -11077,6 +11089,15 @@ vue-cli-plugin-element@^1.0.1:
   resolved "https://registry.yarnpkg.com/vue-cli-plugin-element/-/vue-cli-plugin-element-1.0.1.tgz#34e58fb65b36cf59afaf14f503288e5e578b1554"
   integrity sha512-OJSOnJtn7f1v/8xX+MJae+RrE8WguhiiG9QTBx/MNOPXYsxqut6Ommo+ZD3raNc7eryhqdM2T/DlMfdvIKpCtw==
 
+vue-echarts@^5.0.0-beta.0:
+  version "5.0.0-beta.0"
+  resolved "https://registry.npm.taobao.org/vue-echarts/download/vue-echarts-5.0.0-beta.0.tgz#438dd4b0fc5ccea281709c1f7c6321b05352bdf4"
+  integrity sha1-Q43UsPxczqKBcJwffGMhsFNSvfQ=
+  dependencies:
+    core-js "^3.4.4"
+    lodash "^4.17.15"
+    resize-detector "^0.1.10"
+
 vue-eslint-parser@^7.0.0:
   version "7.1.0"
   resolved "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.1.0.tgz?cache=0&sync_timestamp=1589539313907&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-eslint-parser%2Fdownload%2Fvue-eslint-parser-7.1.0.tgz#9cdbcc823e656b087507a1911732b867ac101e83"
@@ -11780,3 +11801,8 @@ yorkie@^2.0.0:
     is-ci "^1.0.10"
     normalize-path "^1.0.0"
     strip-indent "^2.0.0"
+
+zrender@4.3.1:
+  version "4.3.1"
+  resolved "https://registry.npm.taobao.org/zrender/download/zrender-4.3.1.tgz#baf8aa6dc8187a2f819692d7d5f9bedfa2b90fa3"
+  integrity sha1-uviqbcgYei+BlpLX1fm+36K5D6M=