wucl 2 年之前
父节点
当前提交
6f0c38d088
共有 9 个文件被更改,包括 732 次插入185 次删除
  1. 3 0
      src/api/modules/cycle.js
  2. 9 6
      src/api/modules/dashboard.js
  3. 二进制
      src/assets/QR_code.jpg
  4. 3 3
      src/pages/Cycle.vue
  5. 298 166
      src/pages/DashBoard.vue
  6. 24 8
      src/pages/Document.vue
  7. 374 0
      src/pages/History.vue
  8. 3 1
      src/router/index.js
  9. 18 1
      src/utils/table.js

+ 3 - 0
src/api/modules/cycle.js

@@ -10,6 +10,9 @@ export default {
 
   delScore(params){
     return request.delete(`professor/${params}`)
+  },
+  nextCycle(params){
+    return request.get(`document/next/${params}`)
   }
   
 }

+ 9 - 6
src/api/modules/dashboard.js

@@ -1,12 +1,12 @@
 import request from '@/utils/request'
 
 export default {
-    getAnalysisList() {
-        return request.get(`/analysis/current`)
+    getAnalysisList(params) {
+        return request.get(`/analysis/current`,{params:params})
     },
   
-    getOriginList() {
-        return request.get(`/professor/current`)
+    getOriginList(params) {
+        return request.get(`/professor/current`,{params:params})
     },
     getOriginListByCycleId(param){
         return request.get(`/professor/cycle/${param}`)
@@ -14,7 +14,10 @@ export default {
     getAnalysisListByCycleId(param) {
         return request.get(`/analysis/cycle/${param}`)
     },
-    getMergeData(){
-        return request.get(`/analysis/merge`)
+    getMergeData(params){
+        return request.get(`/analysis/merge`,{params:params})
+    },
+    overCycle(){
+        return request.get(`/analysis`)
     }
 }

二进制
src/assets/QR_code.jpg


+ 3 - 3
src/pages/Cycle.vue

@@ -12,7 +12,7 @@
           style="margin-left: 20px;width: 320px; float: left;">
           <el-option v-for="(o, index) in options" :label="o.label" :value="o.id" />
         </el-select>
-        <el-select v-model="listQuery.cycleName" placeholder="请选择轮数" clearable
+        <el-select v-model="listQuery.cycleNum" placeholder="请选择轮数" clearable
           style="margin-left: 20px;width: 320px;float: left;">
           <el-option v-for="(c, index) in cycleNames" :label="c" :value="c" />
         </el-select>
@@ -41,7 +41,7 @@
         </el-table-column>
         <el-table-column label="轮数" align="center">
           <template slot-scope="{row}">
-            <span>{{ row.cycleName }}</span>
+            <span>第 {{ row.cycleNum }} 轮</span>
           </template>
         </el-table-column>
         <el-table-column label="下发时间" align="center">
@@ -111,7 +111,7 @@ export default {
       options: [],
       listQueryKey: 'keyword',
       dialogVisible: false,
-      cycleNames: ['第一轮', '第二轮', '第三轮', '第四轮', '第五轮', '第六轮', '第七轮', '第八轮', '第九轮', '第十轮'],
+      cycleNames: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
       originData: [],
       dialogVisibleX: false,
       analysisData: [],

+ 298 - 166
src/pages/DashBoard.vue

@@ -1,98 +1,119 @@
 <template>
     <div class="board-container">
-        <div :style="listLoading?mask:''">
-            <div class="header">
-            <img src="../assets/logo.png" style="margin-left: 10px; margin-top: 10px;">
-        </div>
-        <div class="title_info">
-            <el-card shadow="always" style="background-color: rgb(201,235,251); border-radius: 5px;">
-                <p class="item_name">{{ itemName }}</p>
-                <p class="scope_cycleName">{{ type }} {{ scope }} 类 {{ cycleName }} 专家评分公示</p>
-            </el-card>
-        </div>
-        <div class="analysis_collect">
-            <span class="name"><i class="el-icon-s-data"></i>评分项平均得分</span>
-            <!-- <el-row :gutter="20">
-                <el-col :span="6" v-for="(item, index ) in analysisData">
-                    <el-card shadow="never">
-                        <span style="font-weight: 900; letter-spacing: 3px;">
-                            {{ item.questionName }}
-                        </span>
-                        <span style="float: right; color: red;">
-                            {{ item.avgScore }}
-                        </span>
+        <div :style="listLoading ? mask : ''">
+            <div class="fixed_area">
+                <div class="header">
+                    <img src="../assets/logo.png" style="margin-left: -12%;">
+                </div>
+
+                <div class="user_size">
+                    <span v-for="(u, index) in userSize">
+                        <i class="el-icon-s-custom" style="color: green; font-size: xx-large;"></i>
+                    </span>
+                </div>
+            </div>
+            <div class="data_area">
+                <div class="title_info">
+                    <el-card shadow="always" style="background-color: rgb(201,235,251); border-radius: 5px;">
+                        <p class="item_name">{{ itemName }}</p>
+                        <p class="scope_cycleName">{{ type }} 类 专家评分公示 <span style="font-size: x-large;"> 第 {{ cycleName }} 轮</span></p>  
+                        <div style="font-size: large; margin-top: 5px;">
+                            <span>专家人数n= {{ professorNum }}, 𝒳²(1-{{ probability }})={{ standardValue }}</span>
+                        </div>
+                       
                     </el-card>
-                </el-col>
-            </el-row> -->
-            <el-table :data="analysisData" :span-method="objectSpanMethod"
-                style="width: 100% ;letter-spacing: 2px; color: black; " border="border">
-                <el-table-column v-for="item in tableColumn" :key="item.prop" :prop="item.prop" :label="item.label"
-                    align="center" min-width="180" />
-            </el-table>
-            <!-- <y-page-list-layout>
-                <el-table :data="analysisData" slot="table" style="width: 100%;" border="border">
-                    <el-table-column v-if="analysisData != null && analysisData.length > 0" label="名称" align="center" width="150px">
-                        <template slot-scope="{row}">
-                            <span style=" letter-spacing: 3px;">{{ row.questionName }}-{{ row.avgScore }}</span>
-                        </template>
-                    </el-table-column>
-                    <el-table-column v-if="analysisData != null && analysisData.length > 0" label="定级因素" align="center">
-                        <template slot-scope="{row}">
-                            <div style="margin-bottom: 10px; letter-spacing: 3px;" v-for="(item, index) in row.children">{{ item.questionName }}-{{ item.avgScore }}</div>
-                        </template>
-                    </el-table-column>
-                    <el-table-column v-if="analysisData != null && analysisData.length > 0" label="一级因子" align="center">
-                        <template slot-scope="{row}">
-                            <div  v-for="(item, index) in row.children">
-                                <div style=" margin-bottom: 10px;  letter-spacing: 3px;" v-for="(item1, index) in item.children">
-                                    {{ item1.questionName }}-{{ item1.avgScore }}
-                                </div>
-                            </div>
-                        </template>
-                    </el-table-column>
-                    <el-table-column v-if="analysisData != null && analysisData.length > 0" label="二级因子" align="center">
-                        <template slot-scope="{row}">
-                            <div v-for="(item, index) in row.children">
-                                <div v-for="(item1, index) in item.children">
-                                    <div style=" margin-bottom: 10px;  letter-spacing: 3px;" v-for="(item2, index) in item1.children">
-                                        {{ item2.questionName }}-{{ item2.avgScore }}
-                                    </div>
-                                </div>
-                            </div>
-                        </template>
-                    </el-table-column>
-                </el-table>
-            </y-page-list-layout> -->
-
-        </div>
-        <!-- <div class="origin_collect">
-            <span class="name"><i class="el-icon-s-data"></i>专家评分值</span>
-            <el-table :data="originData" border style="width: 100%" stripe highlight-current-row>
-                <el-table-column prop="professorNo" label="专家编号" align="center">
-                </el-table-column>
-                <el-table-column prop="questionName" label="评分项" align="center">
-                </el-table-column>
-                <el-table-column prop="score" label="专家评分值" align="center">
-                </el-table-column>
-                <el-table-column prop="created" label="专家评分时间" align="center">
-                </el-table-column>
-            </el-table>
-        </div> -->
-        <div class="user_size">
-            <span v-for="(u, index) in userSize">
-                <i class="el-icon-s-custom" style="color: green; font-size: xx-large;"></i>
-            </span>
-        </div>
+                </div>
+                <div class="analysis_collect">
+                    <span class="name"><i class="el-icon-s-data"></i>评分项统计分析</span>
+                    <el-table :data="analysisData" :span-method="objectSpanMethod"
+                        style="width: 100% ; color: black; " border="border">
+                        <el-table-column v-for="item in tableColumn" :key="item.prop" :prop="item.prop" :label="item.label"
+                            align="left" min-width="180">
+                            <template slot-scope="{row}">
+                                <slot :info="{ label: item.prop, data: row }">
+                                    <span style=" font-size: large; font-weight: bolder;">
+                                        <span
+                                            :style="parseFloat(row[item.prop].validate === null ? '0' : row[item.prop].validate) > standardValue ? 'color:red' : ''">
+                                            {{ row[item.prop].label }}
+                                        </span>
+                                    </span>
+                                    <el-tag type="warning" style="margin-left: 5px; font-size: large;"
+                                        v-if="row[item.prop].avgScore != null">
+                                        {{ row[item.prop].avgScore }}
+                                    </el-tag>
+                                    <el-tag style="margin-left: 5px;  font-size: large;"
+                                        v-if="row[item.prop].variance != null">
+                                        {{ row[item.prop].variance }}
+                                    </el-tag>
+                                    <el-tag v-if="row[item.prop].validate != null" type="success"
+                                        style="margin-left: 5px;  font-size: large;">
+                                        {{ row[item.prop].validate }}
+                                    </el-tag>
+                                </slot>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+
+                </div>
+                <div class="origin_collect" v-if="analysisData!=null">
+                    <span class="name"><i class="el-icon-s-data"></i>专家评分值</span>
+                    <el-table :data="originData" border slot="table" style="width: 100%" stripe highlight-current-row>
+                        <el-table-column v-for="item in originTableColumn" :key="item.prop" :prop="item.prop"
+                            :label="item.label" align="center" min-width="180" :fixed="item.label === '专家编号'">
+                            <template slot-scope="{row}">
+                                <slot :info="{ label: item.prop, data: row }" v-if="item.prop === 'professorNo'">
+                                    <span>
+                                        {{ row.professorNo }}
+                                    </span>
+                                </slot>
+                                <slot :info="{ label: item.prop, data: row }" v-else>
+                                    <span :style="notPass(item.prop)">
+                                        {{ row.scoreMap[item.prop] }}
+                                    </span>
+                                </slot>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                    <el-button type="success" style="margin-left: 48%; margin-top: 20px;"
+                        @click="overCycle">结束本轮</el-button>
+                </div>
+            </div>
+
+
+            <div class="qr_code">
+                <div class="tuli_area">
+                    <div class="tuli_name">
+                        <div class="tuli" style="background-color: rgb(230, 162, 60);"></div> <span
+                            class="t_name">平均分</span>
+                    </div>
+                    <div class="tuli_name" style="margin-top: 40px;">
+                        <div class="tuli" style="background-color: rgb(64, 158, 255);"></div> <span class="t_name">方差</span>
+                    </div>
+                    <div class="tuli_name" style="margin-top: 80px;">
+                        <div class="tuli" style="background-color: rgb(103, 194, 58);"></div> <span
+                            class="t_name">检验值</span>
+                    </div>
+                </div>
+                <img src="../assets/QR_code.jpg" class="mini_qr" @click="dialogVisible = true">
+            </div>
+            <div class="history">
+                <div style="margin-top: 5px;" v-for="item in (cycleName - 1) " :key="index">
+                    <el-button round @click="goHistory(item)">第 {{ item }} 轮数据</el-button>
+                </div>
+            </div>
         </div>
         <div id="page" v-if="listLoading">
-        <div id="container">
-            <div id="ring"></div>
-            <div id="ring"></div>
-            <div id="ring"></div>
-            <div id="ring"></div>
-            <div id="h3">LOADING</div>
+            <div id="container">
+                <div id="ring"></div>
+                <div id="ring"></div>
+                <div id="ring"></div>
+                <div id="ring"></div>
+                <div id="h3">LOADING</div>
+            </div>
         </div>
-</div>
+        <el-dialog :visible.sync="dialogVisible" width="30%">
+            <img src="../assets/QR_code.jpg">
+        </el-dialog>
     </div>
 </template>
 
@@ -113,7 +134,6 @@ export default {
             originData: [],
             listLoading: false,
             itemName: "",
-            scope: "",
             cycleName: "",
             type: null,
             messages: [],
@@ -131,7 +151,14 @@ export default {
                 { prop: 'element1', label: '一级因子' },
                 { prop: 'element2', label: '二级因子' },
             ],
-            mask:'opacity: 0.3;'
+            originTableColumn: [],
+            mask: 'opacity: 0.3;',
+            dialogVisible: false,
+            professorNum: null,
+            probability: null,
+            standardValue: null,
+            notPassColumnName: [],
+            documentId:null
         }
     },
     computed: {
@@ -150,7 +177,7 @@ export default {
                 if (data != undefined) {
                     if (data.data != null) {
                         this.getAnalysisList();
-                       //this.getOriginList();
+                        this.getOriginList();
                     }
                     if (data.userSize != undefined) {
                         this.userSize = (data.userSize) - 1;
@@ -165,9 +192,37 @@ export default {
     },
     created() {
         this.getAnalysisList();
-        // this.getOriginList();
+        this.getOriginList();
+
     },
     methods: {
+        goHistory(cycleNum) {
+            let routeUrl = this.$router.resolve({
+                path: "/history",
+                query: {"documentId":this.documentId,"cycleNum":cycleNum}
+            });
+            window.open(routeUrl.href, '_blank');
+        },
+        notPass(columnName) {
+            if (this.notPassColumnName.indexOf(columnName) != -1) {
+                return "color:red;";
+            }
+
+        },
+        overCycle() {
+            this.$api.dashboard.overCycle().then(res => {
+                if (res.code == 200) {
+                    this.$notify({
+                        title: '成功',
+                        message: '',
+                        type: 'success'
+                    });
+                    this.getAnalysisList();
+                    this.getOriginList();
+                    this.notPassColumnName = [];
+                }
+            })
+        },
         objectSpanMethod({ row, column, rowIndex, columnIndex }) {
             return this.spanArr[rowIndex][columnIndex]
         },
@@ -177,42 +232,58 @@ export default {
                 console.log("您的浏览器不支持socket")
             } else {
                 // 创建 WebSocketClient 实例并连接到服务端 API 接口
-                 this.client = new WebSocketClient('wss://kps.scdayou.com/ws/apo/ws')
+                this.client = new WebSocketClient('wss://kps.scdayou.com/ws/apo/ws')
                 //this.client = new WebSocketClient('ws://127.0.0.1:8090/apo/ws')
                 this.client.connect()
             }
         },
         getAnalysisList() {
-
             const that = this
             that.listLoading = true;
+
             this.$api.dashboard.getMergeData()
                 .then((res) => {
                     that.analysisData = res.data.analysisData;
                     that.itemName = res.data.itemName;
-                    that.cycleName = res.data.cycleName;
+                    that.cycleName = res.data.cycleNum;
                     that.type = res.data.typeName;
-                    setTimeout(()=>{
+                    that.professorNum = res.data.professorNum;
+                    that.probability = res.data.probability;
+                    that.standardValue = res.data.standardValue;
+                    that.documentId = res.data.documentId;
+                    for (let i in that.analysisData) {
+                        for (let a in that.analysisData[i]) {
+                            let validate = that.analysisData[i][a].validate
+                            if (validate != null && validate > that.standardValue) {
+                                that.notPassColumnName.push(that.analysisData[i][a].label)
+                            }
+
+                        }
+                    }
+                    setTimeout(() => {
                         that.listLoading = false
-                    },2000)
-                    
+                    }, 1000)
+
                 })
                 .catch(() => {
                     that.listLoading = false
                 })
+
         },
         getOriginList() {
             const that = this
             this.$api.dashboard.getOriginList()
                 .then((res) => {
-                    if (res.data[0].score == null) {
-                        that.originData = null;
-                    } else {
-                        that.originData = res.data;
-
+                    that.originData = res.data;
+                    if (that.originData.length > 0) {
+                        let column = [];
+                        let coloumObj = that.originData[1].scoreMap;
+                        column.push({ prop: "professorNo", label: "专家编号" })
+                        for (let propName in coloumObj) {
+                            column.push({ prop: propName, label: propName })
+                        }
+                        that.originTableColumn = column;
                     }
-                    setTimeout(() => {
-                    }, 200)
                 })
                 .catch(() => {
                     that.listLoading = false
@@ -233,7 +304,7 @@ export default {
 </script>
 <style lang="css" scoped>
 .header {
-    height: 80px;
+    height: 100px;
     padding: 0;
     background-color: #ffffff;
     vertical-align: middle;
@@ -241,9 +312,19 @@ export default {
     position: relative;
     width: 100%;
 }
-.mask{
+
+.mask {
     opacity: 0.3;
 }
+
+.fixed_area {
+    position: fixed;
+    top: 0;
+    z-index: 1;
+    width: 80%;
+    margin-left: 10%;
+}
+
 .left {
     margin: 0;
     padding-left: 10px;
@@ -259,6 +340,11 @@ export default {
     top: -10;
     background-image: linear-gradient(to top, #ace0f9 0%, #ffffff 100%);
     overflow: auto;
+    height: 1200px;
+}
+
+.data_area {
+    margin-top: 120px;
 }
 
 .item_name {
@@ -276,28 +362,26 @@ export default {
 }
 
 .title_info {
-    margin-top: 1%;
-    width: 70%;
-    margin-left: 15%;
+    margin-top: 0;
     text-align: center;
+    width: 80%;
+    margin-left: 10%;
 }
 
 .analysis_collect {
     margin-top: 1%;
-    width: 70%;
-    margin-left: 15%;
-    height: 1200px;
+    width: 80%;
+    margin-left: 10%;
 }
 
 .origin_collect {
-    margin-top: 2%;
-    width: 70%;
+    margin-top: 1%;
+    width: 80%;
     margin-bottom: 2%;
-    margin-left: 15%;
+    margin-left: 10%;
 }
 
 .name {
-    /* font-family: 'Courier New', Courier, monospace; */
     margin-bottom: 5px;
     letter-spacing: 1px;
     font-weight: bold;
@@ -306,97 +390,145 @@ export default {
 
 .user_size {
     position: absolute;
-    right: 30px;
+    right: -10%;
     top: 1%;
     height: 40px;
 }
 
+.qr_code {
+    width: 9.5%;
+    height: 25%;
+    position: fixed;
+    bottom: 11%;
+}
+
+.history {
+    width: 8%;
+    position: fixed;
+    bottom: 10%;
+    right: 1%;
+}
+
 #page {
     position: absolute;
     top: 50%;
     left: 50%;
-  display: flex;
-  justify-content: center;
-  align-items: center;
+    display: flex;
+    justify-content: center;
+    align-items: center;
 }
 
 #container {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  position: relative;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    position: relative;
 }
 
 #h3 {
-  color: black;
-  font-weight: bold;
+    color: black;
+    font-weight: bold;
 }
 
 #ring {
-  width: 190px;
-  height: 190px;
-  border: 1px solid transparent;
-  border-radius: 50%;
-  position: absolute;
+    width: 190px;
+    height: 190px;
+    border: 1px solid transparent;
+    border-radius: 50%;
+    position: absolute;
 }
 
 #ring:nth-child(1) {
-  border-bottom: 8px solid rgb(255, 141, 249);
-  animation: rotate1 2s linear infinite;
+    border-bottom: 8px solid rgb(255, 141, 249);
+    animation: rotate1 2s linear infinite;
 }
 
 @keyframes rotate1 {
-  from {
-    transform: rotateX(50deg) rotateZ(110deg);
-  }
+    from {
+        transform: rotateX(50deg) rotateZ(110deg);
+    }
 
-  to {
-    transform: rotateX(50deg) rotateZ(470deg);
-  }
+    to {
+        transform: rotateX(50deg) rotateZ(470deg);
+    }
 }
 
 #ring:nth-child(2) {
-  border-bottom: 8px solid rgb(255,65,106);
-  animation: rotate2 2s linear infinite;
+    border-bottom: 8px solid rgb(255, 65, 106);
+    animation: rotate2 2s linear infinite;
 }
 
 @keyframes rotate2 {
-  from {
-    transform: rotateX(20deg) rotateY(50deg) rotateZ(20deg);
-  }
+    from {
+        transform: rotateX(20deg) rotateY(50deg) rotateZ(20deg);
+    }
 
-  to {
-    transform: rotateX(20deg) rotateY(50deg) rotateZ(380deg);
-  }
+    to {
+        transform: rotateX(20deg) rotateY(50deg) rotateZ(380deg);
+    }
 }
 
 #ring:nth-child(3) {
-  border-bottom: 8px solid rgb(0,255,255);
-  animation: rotate3 2s linear infinite;
+    border-bottom: 8px solid rgb(0, 255, 255);
+    animation: rotate3 2s linear infinite;
 }
 
 @keyframes rotate3 {
-  from {
-    transform: rotateX(40deg) rotateY(130deg) rotateZ(450deg);
-  }
+    from {
+        transform: rotateX(40deg) rotateY(130deg) rotateZ(450deg);
+    }
 
-  to {
-    transform: rotateX(40deg) rotateY(130deg) rotateZ(90deg);
-  }
+    to {
+        transform: rotateX(40deg) rotateY(130deg) rotateZ(90deg);
+    }
 }
 
 #ring:nth-child(4) {
-  border-bottom: 8px solid rgb(252, 183, 55);
-  animation: rotate4 2s linear infinite;
+    border-bottom: 8px solid rgb(252, 183, 55);
+    animation: rotate4 2s linear infinite;
 }
 
 @keyframes rotate4 {
-  from {
-    transform: rotateX(70deg) rotateZ(270deg);
-  }
+    from {
+        transform: rotateX(70deg) rotateZ(270deg);
+    }
 
-  to {
-    transform: rotateX(70deg) rotateZ(630deg);
-  }
+    to {
+        transform: rotateX(70deg) rotateZ(630deg);
+    }
 }
-</style>
+
+.tuli_area {
+    margin-left: 20px;
+}
+
+.tuli_name {
+    position: absolute;
+    display: flex;
+}
+
+.tuli {
+    height: 30px;
+    width: 70px;
+    background-color: antiquewhite;
+    border-radius: 8px;
+}
+
+.t_name {
+    margin-left: 20px;
+    margin-top: 5px;
+    font-weight: bold;
+}
+
+.mini_qr {
+    margin-top: 73%;
+
+}
+
+.mini_qr:hover {
+    cursor: pointer;
+}
+
+button:focus {
+    outline: none;
+}</style>

+ 24 - 8
src/pages/Document.vue

@@ -57,11 +57,17 @@
     </el-dialog>
     <el-dialog title="下发问卷" :visible.sync="dialogVisibleX" width="20%" center>
       <el-form :model="cycleForm" ref="cForm" label-width="100px" class="demo-ruleForm">
-        <el-form-item label="第几轮" prop="cycleName">
-          <el-select v-model="cycleForm.cycleName" placeholder="请选择">
-            <el-option v-for="(c, index) in cycleNames" :label="c" :value="c" />
+        <el-form-item label="轮数:" prop="cycleName">
+          <el-select v-model="cycleForm.cycleNum" placeholder="请选择" disabled >
+            <el-option v-for="(c, index) in cycleNames" :label="'第 '+c+' 轮'" :value="c" />
           </el-select>
         </el-form-item>
+        <el-form-item label="专家人数:" prop="professorNum">
+          <el-input v-model.number="cycleForm.professorNum" placeholder="请输入" />
+        </el-form-item>
+        <el-form-item label="累计概率:" prop="probability">
+          <el-input v-model="cycleForm.probability" placeholder="请输入" />
+        </el-form-item>
       </el-form>
       <span slot="footer" class="dialog-footer">
         <el-button @click="dialogVisible = false">取 消</el-button>
@@ -107,10 +113,12 @@ export default {
           { required: true, message: '请选择问卷类型', trigger: 'blur' }
         ],
       },
-      cycleNames: ['第一轮', '第二轮', '第三轮', '第四轮', '第五轮', '第六轮', '第七轮', '第八轮', '第九轮', '第十轮'],
+      cycleNames: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
       cycleForm: {
         documentId: null,
-        cycleName: null
+        cycleNum: null,
+        professorNum:null,
+        probability:null
       }
     }
   },
@@ -128,7 +136,7 @@ export default {
     },
     addCycle() {
       if (this.cycleForm.documentId) {
-        if (this.cycleForm.cycleName) {
+        if (this.cycleForm.cycleNum) {
           this.$api.cycle.add(this.cycleForm).then(res => {
             if (res.code === 200) {
               this.$notify({
@@ -149,8 +157,16 @@ export default {
       }
     },
     openCycleDiglog(document) {
-      this.dialogVisibleX = true;
-      this.cycleForm.documentId = document.id;
+      this.$api.cycle.nextCycle(document.id).then(res=>{
+        if (res.code ===200){
+          this.cycleForm.cycleNum = res.data.cycleNum;
+          this.cycleForm.professorNum = res.data.professorNum;
+          this.cycleForm.probability = res.data.probability;
+          this.dialogVisibleX = true;
+          this.cycleForm.documentId = document.id;
+        }
+      })
+     
     },
     openDialog() {
       this.dialogVisible = true;

+ 374 - 0
src/pages/History.vue

@@ -0,0 +1,374 @@
+<template>
+    <div class="board-container">
+        <div :style="listLoading ? mask : ''">
+            <div class="fixed_area">
+                <div class="header">
+                    <img src="../assets/logo.png" style="margin-left: -12%;">
+                </div>
+
+                <div class="user_size">
+                    <span v-for="(u, index) in userSize">
+                        <i class="el-icon-s-custom" style="color: green; font-size: xx-large;"></i>
+                    </span>
+                </div>
+            </div>
+            <div class="data_area">
+                <div class="title_info">
+                    <el-card shadow="always" style="background-color: rgb(232, 234, 235); border-radius: 5px;">
+                        <p class="item_name">{{ itemName }}</p>
+                        <p class="scope_cycleName">{{ type }} 类 专家评分公示 <span style="font-size: x-large;"> 第 {{ cycleName }} 轮</span></p>  
+                        <div style="font-size: large; margin-top: 5px;">
+                            <span>专家人数n= {{ professorNum }}, 𝒳²(1-{{ probability }})={{ standardValue }}</span>
+                        </div>
+                    </el-card>
+                </div>
+                <div class="analysis_collect">
+                    <span class="name"><i class="el-icon-s-data"></i>评分项统计分析</span>
+                    <el-table :data="analysisData" :span-method="objectSpanMethod"
+                        style="width: 100% ; color: black; " border="border">
+                        <el-table-column v-for="item in tableColumn" :key="item.prop" :prop="item.prop" :label="item.label"
+                            align="left" min-width="180">
+                            <template slot-scope="{row}">
+                                <slot :info="{ label: item.prop, data: row }">
+                                    <span style=" font-size: large; font-weight: bolder;">
+                                        <span
+                                            :style="parseFloat(row[item.prop].validate === null ? '0' : row[item.prop].validate) > standardValue ? 'color:red' : ''">
+                                            {{ row[item.prop].label }}
+                                        </span>
+                                    </span>
+                                    <el-tag type="warning" style="margin-left: 5px; font-size: large;"
+                                        v-if="row[item.prop].avgScore != null">
+                                        {{ row[item.prop].avgScore }}
+                                    </el-tag>
+                                    <el-tag style="margin-left: 5px;  font-size: large;"
+                                        v-if="row[item.prop].variance != null">
+                                        {{ row[item.prop].variance }}
+                                    </el-tag>
+                                    <el-tag v-if="row[item.prop].validate != null" type="success"
+                                        style="margin-left: 5px;  font-size: large;">
+                                        {{ row[item.prop].validate }}
+                                    </el-tag>
+                                </slot>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+
+                </div>
+                <div class="origin_collect" >
+                    <span class="name"><i class="el-icon-s-data"></i>专家评分值</span>
+                    <el-table :data="originData" border slot="table" style="width: 100%" stripe highlight-current-row>
+                        <el-table-column v-for="item in originTableColumn" :key="item.prop" :prop="item.prop" 
+                            :label="item.label" align="center" min-width="180" :fixed="item.label === '专家编号'">
+                            <template slot-scope="{row}">
+                                <slot :info="{ label: item.prop, data: row }" v-if="item.prop === 'professorNo'">
+                                    <span>
+                                        {{ row.professorNo }}
+                                    </span>
+                                </slot>
+                                <slot :info="{ label: item.prop, data: row }" v-else>
+                                    <span :style="notPass(item.prop)">
+                                        {{ row.scoreMap[item.prop] }}
+                                    </span>
+                                </slot>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                </div>
+            </div>
+
+            <div class="qr_code">
+                <div class="tuli_area">
+                    <div class="tuli_name">
+                        <div class="tuli" style="background-color: rgb(230, 162, 60);"></div> <span
+                            class="t_name">平均分</span>
+                    </div>
+                    <div class="tuli_name" style="margin-top: 40px;">
+                        <div class="tuli" style="background-color: rgb(64, 158, 255);"></div> <span class="t_name">方差</span>
+                    </div>
+                    <div class="tuli_name" style="margin-top: 80px;">
+                        <div class="tuli" style="background-color: rgb(103, 194, 58);"></div> <span
+                            class="t_name">检验值</span>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import YPageListLayout from '@/components/custom/YPageListLayout'
+import { getMergeCells } from '../utils/table.js'
+
+export default {
+    name: 'History',
+    components: {
+        YPageListLayout,
+        getMergeCells
+    },
+    data() {
+        return {
+            analysisData: [],
+            originData: [],
+            listLoading: false,
+            itemName: "",
+            cycleName: "",
+            type: null,
+            messages: [],
+            error: null,
+            client: {
+                messages: [
+                    { data: "*" },
+                    { userSize: 0 }
+                ]
+            },
+            userSize: 0,
+            tableColumn: [
+                { prop: 'name', label: '名称' },
+                { prop: 'element', label: '定级因素' },
+                { prop: 'element1', label: '一级因子' },
+                { prop: 'element2', label: '二级因子' },
+            ],
+            originTableColumn: [],
+            mask: 'opacity: 0.3;',
+            dialogVisible: false,
+            professorNum: null,
+            probability: null,
+            standardValue: null,
+            notPassColumnName:[],
+
+        }
+    },
+    computed: {
+        // 获取所有单元格合并数据
+        spanArr() {
+            if (!this.tableColumn.length) return []
+            const mergeCols = ['name', 'element', 'element1', 'element2'] // 需要合并的列(字段)
+            return getMergeCells(this.analysisData, this.tableColumn, mergeCols)
+        }
+    },
+
+    created() {
+        let cycleNum = this.$route.query.cycleNum;
+        let documentId = this.$route.query.documentId;
+        let params = {"cycleNum":cycleNum,"documentId":documentId}
+        this.getAnalysisList(params);
+        this.getOriginList(params);
+
+    },
+    methods: {
+      
+        notPass(columnName){
+            if (this.notPassColumnName.indexOf(columnName)!=-1){
+                return "color:red;";
+            }
+                
+        },
+        objectSpanMethod({ row, column, rowIndex, columnIndex }) {
+            return this.spanArr[rowIndex][columnIndex]
+        },
+
+        getAnalysisList(params) {
+            const that = this
+            that.listLoading = true;
+            
+            this.$api.dashboard.getMergeData(params)
+                .then((res) => {
+                    that.analysisData = res.data.analysisData;
+                    that.itemName = res.data.itemName;
+                    that.cycleName = res.data.cycleNum;
+                    that.type = res.data.typeName;
+                    that.professorNum = res.data.professorNum;
+                    that.probability = res.data.probability;
+                    that.standardValue = res.data.standardValue;
+             
+                    for (let i in that.analysisData){
+                        for (let a in that.analysisData[i]){
+                            let validate = that.analysisData[i][a].validate
+                            if (validate!=null && validate>that.standardValue){
+                            that.notPassColumnName.push(that.analysisData[i][a].label)
+                            }
+                            
+                        }
+                    }
+                    setTimeout(() => {
+                        that.listLoading = false
+                    }, 500)
+
+                })
+                .catch(() => {
+                    that.listLoading = false
+                })
+                
+        },
+        getOriginList(params) {
+            const that = this
+            this.$api.dashboard.getOriginList(params)
+                .then((res) => {
+                    that.originData = res.data;
+                    if (that.originData.length > 0) {
+                        let column = [];
+                        let coloumObj = that.originData[1].scoreMap;
+                        column.push({ prop: "professorNo", label: "专家编号" })
+                        for (let propName in coloumObj) {
+                            column.push({ prop: propName, label: propName })
+                        }
+                        that.originTableColumn = column;
+                    }
+                })
+                .catch(() => {
+                    that.listLoading = false
+                })
+        },
+    },
+
+}
+</script>
+<style lang="css" scoped>
+.header {
+    height: 100px;
+    padding: 0;
+    background-color: #ffffff;
+    vertical-align: middle;
+    display: flex;
+    position: relative;
+    width: 100%;
+}
+
+.mask {
+    opacity: 0.3;
+}
+
+.fixed_area {
+    position: fixed;
+    top: 0;
+    z-index: 1;
+    width: 80%;
+    margin-left: 10%;
+}
+
+.left {
+    margin: 0;
+    padding-left: 10px;
+    width: 30%;
+    height: 100%;
+}
+
+.board-container {
+    /* display: flex;
+    width: 100%;
+    justify-content: center;
+    overflow: auto; */
+    top: -10;
+    background-image: linear-gradient(to top, #cbcecf 0%, #ffffff 100%);
+    overflow: auto;
+    height: 1200px;
+}
+
+.data_area {
+    margin-top: 120px;
+}
+
+.item_name {
+    font-size: xx-large;
+    letter-spacing: 1px;
+    font-weight: 900;
+}
+
+.scope_cycleName {
+    font-size: large;
+    letter-spacing: 1px;
+    font-weight: bold;
+    color: red;
+
+}
+
+.title_info {
+    margin-top: 0;
+    text-align: center;
+    width: 80%;
+    margin-left: 10%;
+}
+
+.analysis_collect {
+    margin-top: 1%;
+    width: 80%;
+    margin-left: 10%;
+}
+
+.origin_collect {
+    margin-top: 1%;
+    width: 80%;
+    margin-bottom: 2%;
+    margin-left: 10%;
+}
+
+.name {
+    margin-bottom: 5px;
+    letter-spacing: 1px;
+    font-weight: bold;
+    font-size: small;
+}
+
+.user_size {
+    position: absolute;
+    right: -10%;
+    top: 1%;
+    height: 40px;
+}
+
+.qr_code {
+    width: 9.5%;
+    height: 13%;
+    position: fixed;
+    bottom: 1%;
+}
+
+#page {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+#container {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    position: relative;
+}
+
+
+.tuli_area {
+    margin-left: 20px;
+}
+
+.tuli_name {
+    position: absolute;
+    display: flex;
+}
+
+.tuli {
+    height: 30px;
+    width: 70px;
+    background-color: antiquewhite;
+    border-radius: 8px;
+}
+
+.t_name {
+    margin-left: 20px;
+    margin-top: 5px;
+    font-weight: bold;
+}
+
+.mini_qr {
+    margin-top: 73%;
+
+}
+
+.mini_qr:hover {
+    cursor: pointer;
+}
+
+</style>

+ 3 - 1
src/router/index.js

@@ -9,6 +9,7 @@ import Document from '@/pages/Document'
 import Cycle from '@/pages/Cycle'
 import Login from '@/pages/Login'
 import DashBoard from '@/pages/DashBoard'
+import History from '@/pages/History'
 
 Vue.use(VueRouter);
 
@@ -41,7 +42,8 @@ const routes = [
       }
     ]
   },
-  { path: '/dashboard', name: 'DashBoard', component: DashBoard }
+  { path: '/dashboard', name: 'DashBoard', component: DashBoard },
+  { path: '/history', name: 'History', component: History }
 ]
 
 

+ 18 - 1
src/utils/table.js

@@ -35,7 +35,7 @@ export const getMergeCells = (tableData = [], tableColumn = [], mergeCols = [])
         }
   
         // 5.合并相同数据的单元格
-        if (tableData[row][fields[col]] === tableData[row + 1][fields[col]]) {
+        if (isObjectEqual(tableData[row][fields[col]],tableData[row + 1][fields[col]])) {
           const beforeCell = array[row + 1][col]
           array[row][col] = [1 + beforeCell[0], 1]
           beforeCell[0] = 0
@@ -47,4 +47,21 @@ export const getMergeCells = (tableData = [], tableColumn = [], mergeCols = [])
     }
     // console.log(array, 'array')
     return array
+  }
+
+  function isObjectEqual(obj1, obj2) {
+    const obj1Keys = Object.keys(obj1);
+    const obj2Keys = Object.keys(obj2);
+  
+    if (obj1Keys.length !== obj2Keys.length) {
+      return false;
+    }
+  
+    for (let key of obj1Keys) {
+      if (obj1[key] !== obj2[key]) {
+        return false;
+      }
+    }
+  
+    return true;
   }