Explorar o código

Merge branch 'develop3.0-tmd' of http://106.12.23.251:10080/TEAMMODEL/TEAMModelOS into develop3.0-tmd

CrazyIter_Bin %!s(int64=4) %!d(string=hai) anos
pai
achega
0ffb6ab841
Modificáronse 24 ficheiros con 1332 adicións e 1097 borrados
  1. 1 1
      TEAMModelOS/ClientApp/src/api/totalAnalysis.js
  2. 8 2
      TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue
  3. 7 7
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseBar.vue
  4. 4 3
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseEntryBar.vue
  5. 35 7
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseLineBar.vue
  6. 2 1
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseMyTable.vue
  7. 342 320
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseScatter.vue
  8. 261 294
      TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseTestScatter.vue
  9. 4 5
      TEAMModelOS/ClientApp/src/store/module/totalAnalysis.js
  10. 1 1
      TEAMModelOS/ClientApp/src/utils/evTools.js
  11. 2 0
      TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue
  12. 2 0
      TEAMModelOS/ClientApp/src/view/learnactivity/CreatePrivEva.vue
  13. 2 0
      TEAMModelOS/ClientApp/src/view/learnactivity/CreateSchoolEva.vue
  14. 40 8
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/AchievementAnalysis/AchievementAnalysis.vue
  15. 50 27
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/AchievementAnalysis/EarlyWarning.vue
  16. 33 19
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/AchievementAnalysis/EntryTables.vue
  17. 19 8
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/EvaluationList/TotalIndex.vue
  18. 50 11
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/ScatterAnalysis/ScatterAnalysis.vue
  19. 13 18
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/QuestionList.css
  20. 81 154
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/QuestionList.vue
  21. 74 34
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/TestAnalysis.vue
  22. 37 60
      TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/index.vue
  23. 263 116
      TEAMModelOS/Controllers/Analysis/AchievementController.cs
  24. 1 1
      TEAMModelOS/Controllers/School/ClassRoomController.cs

+ 1 - 1
TEAMModelOS/ClientApp/src/api/totalAnalysis.js

@@ -33,6 +33,6 @@ export default {
 	
 	/* 最新学情对接接口 */
 	getAnalysis: function(data) {
-        return post('/analysis/getAnalysis', data)
+        return post('/analysis/process', data)
     },
 }

+ 8 - 2
TEAMModelOS/ClientApp/src/components/evaluation/ExerciseList.vue

@@ -84,7 +84,7 @@
 					<span class="item-tools-info">难度:{{ exersicesDiff[item.level - 1] }}</span>
 					<span class="item-tools-info">认知层次:{{ exersicesField[item.field - 1] }}</span>
 					<span class="item-tools-info">使用次数:{{ item.usageCount || 0 }} 次</span>
-					<Button type="info" :style="{backgroundColor:selectList.map(i => i.id).indexOf(item.id) > -1 ? '#bbbbbb' : '#2db7f5'}"
+					<Button type="info" v-if="!isAnalysis" :style="{backgroundColor:selectList.map(i => i.id).indexOf(item.id) > -1 ? '#bbbbbb' : '#2db7f5'}"
 					 @click.stop="onSelectItem(item,index)">{{ selectList.map(i => i.id).indexOf(item.id) > -1 ? '移除' : '选题'}}</Button>
 				</div>
 			</div>
@@ -92,7 +92,7 @@
 
 
 		<!-- 底部分页区域 -->
-		<Page :total="totalNum" show-sizer show-total :page-size="pageSize" :current="pageNum" @on-page-size-change="pageSizeChange"
+		<Page :total="totalNum" v-if="!isAnalysis" show-sizer show-total :page-size="pageSize" :current="pageNum" @on-page-size-change="pageSizeChange"
 		 @on-change="pageChange" :page-size-opts="[5, 10, 15, 20]" />
 	</div>
 </template>
@@ -113,6 +113,10 @@
 			        return []
 			    }
 			},
+			isAnalysis:{
+				type:Boolean,
+				default:false
+			}
 		},
 		data() {
 			return {
@@ -144,6 +148,7 @@
 		},
 		created() {
 			console.log('接收到的',this.propsList)
+			this.pageSize = this.isAnalysis ? 999 : 5
 			this.pageChange(1)
 		},
 		methods: {
@@ -208,6 +213,7 @@
 					let exerciseItemDom = e.path.filter(
 						(i) => i.className === "exercise-item"
 					);
+					console.log(exerciseItemDom)
 					if (exerciseItemDom.length) {
 						this.$emit("pageScroll", exerciseItemDom[0].offsetTop);
 					}

+ 7 - 7
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseBar.vue

@@ -114,7 +114,7 @@
                 var option = {
                     legend: {
                         // data: data.datas.map(item => item.name).concat([this.$t('totalAnalysis.ach_text5'), this.$t('totalAnalysis.ach_text6')]),
-                        data: data.subjects.map(item => item.name).concat([this.$t('totalAnalysis.ach_text5'), this.$t('totalAnalysis.ach_text6')]),
+                        data: data.classes[0].subjects.map(item => item.name).concat([this.$t('totalAnalysis.ach_text5'), this.$t('totalAnalysis.ach_text6')]),
                         textStyle: {
                             color: '#e4eadb'
                         }
@@ -246,7 +246,7 @@
                         splitArea: {
                             show: false // 是否显示,默认为false
                         },
-                        data: data.classes.map(i => i.name)
+                        data: data.classes.map(i => i.className)
                     },
                     yAxis: {
                         show: true, // 是否显示
@@ -366,16 +366,16 @@
 			// 获取每个学科下每个班级的平均分
 			getSeriesData(val){
 				let result = []
-				val.subjects.forEach((i,index) => {
-					val.classAnalyses.forEach(j => {
-						result.push(j.subjects[index].averageScore)
+				val.classes[0].subjects.forEach((i,index) => {
+					val.classes.forEach(j => {
+						result.push(j.subjects[index].average)
 					})
 				})
 				return result
 			},
 			
 			doRender(val){
-				let subjectList = val.subjects
+				let subjectList = val.classes[0].subjects
 				this.subjectSeries = []
 				// 配置 柱状图的 Series 根据科目 配置
 				subjectList.forEach((item, index) => {
@@ -412,7 +412,7 @@
             getBaseBarData(val) {
                 if (!val) return
 				console.log('BaseBar接收到watch的vuex',val)
-				this.doRender(val)
+				// this.doRender(val)
                 // this.handleOptions(val.average)
             }
         }

+ 4 - 3
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseEntryBar.vue

@@ -12,6 +12,7 @@
 
         methods: {
             drawLine(data) {
+				console.log('进线人数统计数据',data)
                 // 基于准备好的dom,初始化echarts实例
                 let myBar = this.$echarts.init(document.getElementById('entryNumberBar'))
 
@@ -291,10 +292,10 @@
 			getEntryBarData(analysisJson){
 				let result = []
 				analysisJson.classes.forEach((classItem,classIndex) => {
-					let totalNum = analysisJson.classAnalyses[classIndex].stuCount
-					let	entryNum = analysisJson.classAnalyses[classIndex].lineCount
+					let totalNum = classItem.stuCount
+					let	entryNum = classItem.lineCount
 					result.push({
-						name:classItem.name,
+						name:classItem.className,
 						totalNum:totalNum,
 						entryNum:entryNum,
 						overAverageRate:((entryNum / totalNum) * 100).toFixed(2)

+ 35 - 7
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseLineBar.vue

@@ -16,6 +16,7 @@
         },
         methods: {
             drawLine(echartData, exerciseIndex) {
+				console.log('年级得分率图表数据',echartData)
                 let that = this
                 let myBar = this.$echarts.init(document.getElementById('stuAverageBar'))
                 var option = {
@@ -159,7 +160,7 @@
                                 ]
                             },
 							barMaxWidth:40,
-                            data: echartData.map(item => item.datas[exerciseIndex])
+                            data: echartData.map(item => item.classScoreRate)
                         },
                         {
                             name: that.$t('totalAnalysis.ta_chart_text5'),
@@ -216,6 +217,33 @@
                     myBar.resize()
                 })
             },
+			
+			// 调整图表所需数据结构格式
+			renderData(data) {
+				console.log(this.currentExerciseIndex)
+				let analysisJson = JSON.parse(JSON.stringify(this.getAnalysisJson))
+				let curSubjectIndex = analysisJson.subjects.map(i => i.name).indexOf(this.$store.state.totalAnalysis.currentSubject)
+				let result = []
+				analysisJson.paper[curSubjectIndex].Value.forEach((exercise,exerciseIndex) => {
+					let obj = {}
+					analysisJson.paperKey.forEach((key, index) => {
+						obj[key] = exercise[index]
+					})
+					result.push(obj)
+				})
+				console.log(result)
+				this.gradeRate = result[this.currentExerciseIndex].gradeScoreRate
+				this.areaRate = result[this.currentExerciseIndex].areaScoreRate
+				
+				let echartsData = []
+				analysisJson.classes.forEach((classItem, classIndex) => {
+					echartsData.push({
+						className: classItem.className,
+						classScoreRate: classItem.subjects[curSubjectIndex].item[this.currentExerciseIndex]
+					})
+				})
+				this.drawLine(echartsData, this.currentExerciseIndex)
+			},
 
             // 监听变化处理重新渲染
             doRender(data) {
@@ -227,18 +255,18 @@
             }
         },
         mounted() {
-            if (this.getClassExerciseData) {
-                this.doRender(this.getClassExerciseData)
+            if (this.getAnalysisJson) {
+                this.renderData(this.getAnalysisJson)
             }
         },
         computed: {
             // 获取最新柱状图数据
-            getClassExerciseData() {
-                return this.$store.state.totalAnalysis.classExerciseData
+            getAnalysisJson() {
+                return this.$store.state.totalAnalysis.analysisJson
             }
         },
         watch: {
-            getClassExerciseData(val) {
+            getAnalysisJson(val) {
                 if (!val) return
                 this.doRender(val)
             },
@@ -246,7 +274,7 @@
             exerciseIndex(val) {
                 if (val) {
                     this.currentExerciseIndex = +val - 1 // 拿到当前所选择的题号 确认数据下标
-                    this.doRender(this.getClassExerciseData)
+                    this.renderData(this.getAnalysisJson)
                 }
             }
 

+ 2 - 1
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseMyTable.vue

@@ -438,7 +438,8 @@
                 this.originData = JSON.parse(JSON.stringify(data))
                 if (this.isFirst) this.firstData = JSON.parse(JSON.stringify(data))
                 // 获取当前测评班级数据
-                this.subjectList = ['全部'].concat(this.$store.state.totalAnalysis.subjectList)
+                this.subjectList = this.$store.state.totalAnalysis.subjectList
+                // this.subjectList = ['全部'].concat(this.$store.state.totalAnalysis.subjectList)
                 this.pageChange(1)
                 this.isFirst = false
             },

+ 342 - 320
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseScatter.vue

@@ -1,354 +1,376 @@
 <template>
-    <div id="myScatter"></div>
+	<div id="myScatter"></div>
 </template>
 
 <script>
-    export default {
-        name: 'myScatter',
-        props: ['scatterData'],
-        data() {
-            return {
-                originArr: [],
-                dataArr: [],
-                childIndex: 0,
-                activeItemIndex: 0
-            }
-        },
-        created() {
+	export default {
+		name: 'myScatter',
+		props: ['scatterData'],
+		data() {
+			return {
+				originArr: [],
+				dataArr: [],
+				childIndex: 0,
+				activeItemIndex: 0
+			}
+		},
+		created() {
 
-        },
-        mounted() {
+		},
+		mounted() {
 
-        },
-        methods: {
+		},
+		methods: {
 
-            // 调整图表所需数据结构格式
-            renderData(arr) {
-                let newArr = []
-                arr.forEach(item => {
-                    let arr = []
-                    arr.push(item.x)
-                    arr.push(item.y)
-                    arr.push(item.name)
-                    arr.push(item.memberId)
-                    newArr.push(arr)
-                })
-                return newArr
-            },
+			// 调整图表所需数据结构格式
+			renderData(data) {
+				let analysisJson = JSON.parse(JSON.stringify(this.getAnalysisJson))
+				let result = []
+				analysisJson.subjects.forEach((subject, subjectIndex) => {
+					result.push({
+						subject: subject.name,
+						students: this.getSubjectStudents(analysisJson, subjectIndex)
+					})
+				})
+				let arr = result[0].students
+				let newArr = []
+				arr.forEach(item => {
+					let arr2 = []
+					arr2.push((item.x * 100).toFixed(2))
+					arr2.push((item.y * 100).toFixed(2))
+					arr2.push(item.name)
+					arr2.push(item.memberId)
+					newArr.push(arr2)
+				})
+				return newArr
+			},
+			
+			/* 获取每个学生每个科目下的落点数据 */
+			getSubjectStudents(analysisJson, subjectIndex) {
+				let result = []
+				analysisJson.students.forEach(stu => {
+					let obj = {}
+					analysisJson.scatterKey.forEach((key, index) => {
+						obj[key] = stu.subjects[subjectIndex].scatter[index]
+					})
+					result.push(obj)
+				})
+				return result
+			},
 
-            // 渲染散点图
-            drawLine(data) {
-                // 基于准备好的dom,初始化echarts实例
-                let myScatter = this.$echarts.init(document.getElementById('myScatter'), 'chalk')
-                let _this = this
-
-                // 指定图表的配置项和数据
-                var option = {
-                    tooltip: {
-                        trigger: 'item',
-                        showDelay: 0,
-                        axisPointer: {
-                            show: true,
-                            lineStyle: {
-                                type: 'dashed',
-                                width: 1
-                            }
-                        },
-                        textStyle: {
-                            height: '160px'
-                        },
-                        formatter: function(params) {
-                            const item = params
-                            return `${_this.$t('totalAnalysis.base_name')}:${item.data[2]}
+			// 渲染散点图
+			drawLine(data) {
+				// 基于准备好的dom,初始化echarts实例
+				let myScatter = this.$echarts.init(document.getElementById('myScatter'), 'chalk')
+				let _this = this
+				console.log('落点图数据', data)
+				// 指定图表的配置项和数据
+				var option = {
+					tooltip: {
+						trigger: 'item',
+						showDelay: 0,
+						axisPointer: {
+							show: true,
+							lineStyle: {
+								type: 'dashed',
+								width: 1
+							}
+						},
+						textStyle: {
+							height: '160px'
+						},
+						formatter: function(params) {
+							const item = params
+							return `${_this.$t('totalAnalysis.base_name')}:${item.data[2]}
                         <br/>${_this.$t('totalAnalysis.sca_chart_text1')}:${item.data[1]}%
                         <br/>${_this.$t('totalAnalysis.sca_chart_text2')}:${item.data[0]}
                        `
-                        }
-                    },
-                    legend: {
-                        data: [_this.$t('totalAnalysis.sca_text4')]
-                    },
-                    // toolbox: {
-                    //    show: true,
-                    //    right: '70px',
-                    //    feature: {
-                    //        dataZoom: { show: true },
-                    //        restore: { show: false }
-                    //    }
-                    // },
-                    xAxis: [
-                        {
-                            type: 'value',
-                            splitNumber: 2,
-                            name: _this.$t('totalAnalysis.sca_chart_text2'),
-                            nameTextStyle: {
-                                color: '#e4eadb'
-                            },
-                            scale: true,
-                            splitLine: {
-                                show: true,
-                                lineStyle: {
-                                    color: '#595959'
-                                }
-                            }
-                        }
-                    ],
-                    yAxis: [
-                        {
-                            type: 'value',
-                            name: _this.$t('totalAnalysis.sca_chart_text1'),
-                            nameTextStyle: {
-                                color: '#e4eadb'
-                            },
-                            max: 100,
-                            min: 0,
-                            splitLine: {
-                                show: false,
-                                lineStyle: {
-                                    color: '#595959'
-                                }
-                            },
-                            interval: 25,
-                            axisLabel: {
-                                show: true,
-                                formatter: function(value) {
-                                    let val = []
-                                    if (value !== 25) {
-                                        val.push(value + '%')
-                                    }
-                                    return val
-                                }
-                            },
-                            spiltArea: {
-                                show: true
-                            }
-                        }
-                    ],
-                    dataZoom: [{
-                        show: true,
-                        type: 'inside',
-                        start: 0,
-                        end: 100,
-                        bottom: 10,
-                        height: 15
-                    },
-                    {
-                        show: true,
-                        type: 'slider',
-                        start: 0,
-                        end: 100,
-                        bottom: 0,
-                        height: 35,
-                        textStyle: {
-                            color: '#BBBBBB'
-                        }
-                    }],
-                    series: [
-                        {
-                            name: _this.$t('totalAnalysis.sca_text4'),
-                            type: 'scatter',
-                            symbolSize: 15,
-                            z: 0,
-                            data: data,
-                            itemStyle: {
-                                color: '#79c8e8'
-                            },
-                            emphasis: {
-                                itemStyle: {
-                                    color: '#ff99cc'
-                                }
-                            },
-                            markLine: {
-                                silent: true,
-                                animation: false,
-                                data: [
-                                    { yAxis: 75 }, { yAxis: 50 }, { yAxis: 100 }
-                                ],
-                                label: {
-                                    color: '#e4eadb',
-                                    formatter: '{c}%'
-                                },
-                                lineStyle: {
-                                    color: '#595959',
-                                    type: 'solid'
-                                }
-                            },
-                            markArea: {
-                                silent: true,
-                                data: [
-                                    [{
-                                        xAxis: '0.5',
-                                        yAxis: '100',
-                                        itemStyle: {
-                                            color: 'rgba(90,90,90,.1)'
+						}
+					},
+					legend: {
+						data: [_this.$t('totalAnalysis.sca_text4')]
+					},
+					// toolbox: {
+					//    show: true,
+					//    right: '70px',
+					//    feature: {
+					//        dataZoom: { show: true },
+					//        restore: { show: false }
+					//    }
+					// },
+					xAxis: [{
+						type: 'value',
+						splitNumber: 2,
+						name: _this.$t('totalAnalysis.sca_chart_text2'),
+						nameTextStyle: {
+							color: '#e4eadb'
+						},
+						scale: true,
+						splitLine: {
+							show: true,
+							lineStyle: {
+								color: '#595959'
+							}
+						}
+					}],
+					yAxis: [{
+						type: 'value',
+						name: _this.$t('totalAnalysis.sca_chart_text1'),
+						nameTextStyle: {
+							color: '#e4eadb'
+						},
+						max: 100,
+						min: 0,
+						splitLine: {
+							show: false,
+							lineStyle: {
+								color: '#595959'
+							}
+						},
+						interval: 25,
+						axisLabel: {
+							show: true,
+							formatter: function(value) {
+								let val = []
+								if (value !== 25) {
+									val.push(value + '%')
+								}
+								return val
+							}
+						},
+						spiltArea: {
+							show: true
+						}
+					}],
+					dataZoom: [{
+							show: true,
+							type: 'inside',
+							start: 0,
+							end: 100,
+							bottom: 10,
+							height: 15
+						},
+						{
+							show: true,
+							type: 'slider',
+							start: 0,
+							end: 100,
+							bottom: 0,
+							height: 35,
+							textStyle: {
+								color: '#BBBBBB'
+							}
+						}
+					],
+					series: [{
+						name: _this.$t('totalAnalysis.sca_text4'),
+						type: 'scatter',
+						symbolSize: 15,
+						z: 0,
+						data: data,
+						itemStyle: {
+							color: '#79c8e8'
+						},
+						emphasis: {
+							itemStyle: {
+								color: '#ff99cc'
+							}
+						},
+						markLine: {
+							silent: true,
+							animation: false,
+							data: [{
+								yAxis: 75
+							}, {
+								yAxis: 50
+							}, {
+								yAxis: 100
+							}],
+							label: {
+								color: '#e4eadb',
+								formatter: '{c}%'
+							},
+							lineStyle: {
+								color: '#595959',
+								type: 'solid'
+							}
+						},
+						markArea: {
+							silent: true,
+							data: [
+								[{
+									xAxis: '0.5',
+									yAxis: '100',
+									itemStyle: {
+										color: 'rgba(90,90,90,.1)'
 
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['90%', '10%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'A'
-                                        }
+									},
+									label: {
+										show: true,
+										position: ['90%', '10%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'A'
+									}
 
-                                    }, {
-                                        xAxis: '0',
-                                        yAxis: '75',
-                                        itemStyle: {
-                                            color: ''
+								}, {
+									xAxis: '0',
+									yAxis: '75',
+									itemStyle: {
+										color: ''
 
-                                        }
+									}
 
-                                    }],
-                                    [{
-                                        xAxis: '1',
-                                        yAxis: '100',
-                                        itemStyle: {
-                                            color: 'rgba(128,128,128,0)'
+								}],
+								[{
+									xAxis: '1',
+									yAxis: '100',
+									itemStyle: {
+										color: 'rgba(128,128,128,0)'
 
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['5%', '10%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'A-'
-                                        }
+									},
+									label: {
+										show: true,
+										position: ['5%', '10%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'A-'
+									}
 
-                                    }, {
-                                        xAxis: '0.5',
-                                        yAxis: '75'
-                                    }],
-                                    [{
-                                        xAxis: '0.5',
-                                        yAxis: '75',
-                                        itemStyle: {
-                                            color: 'rgba(128,128,128,0)'
+								}, {
+									xAxis: '0.5',
+									yAxis: '75'
+								}],
+								[{
+									xAxis: '0.5',
+									yAxis: '75',
+									itemStyle: {
+										color: 'rgba(128,128,128,0)'
 
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['90%', '10%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'B'
-                                        }
+									},
+									label: {
+										show: true,
+										position: ['90%', '10%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'B'
+									}
 
-                                    }, {
-                                        xAxis: '0',
-                                        yAxis: '50'
-                                    }],
-                                    [{
-                                        xAxis: '1',
-                                        yAxis: '75',
-                                        itemStyle: {
-                                            color: 'rgba(90,90,90,.1)'
+								}, {
+									xAxis: '0',
+									yAxis: '50'
+								}],
+								[{
+									xAxis: '1',
+									yAxis: '75',
+									itemStyle: {
+										color: 'rgba(90,90,90,.1)'
 
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['5%', '10%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            zIndex: 99999,
-                                            formatter: 'B-'
-                                        }
+									},
+									label: {
+										show: true,
+										position: ['5%', '10%'],
+										color: '#66ff33',
+										fontSize: 20,
+										zIndex: 99999,
+										formatter: 'B-'
+									}
 
-                                    }, {
-                                        xAxis: '0.5',
-                                        yAxis: '50'
-                                    }],
-                                    [{
-                                        xAxis: '0.5',
-                                        yAxis: '50',
-                                        itemStyle: {
-                                            color: 'rgba(90,90,90,.1)'
+								}, {
+									xAxis: '0.5',
+									yAxis: '50'
+								}],
+								[{
+									xAxis: '0.5',
+									yAxis: '50',
+									itemStyle: {
+										color: 'rgba(90,90,90,.1)'
 
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['90%', '10%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'C'
-                                        }
+									},
+									label: {
+										show: true,
+										position: ['90%', '10%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'C'
+									}
 
-                                    }, {
-                                        xAxis: '0',
-                                        yAxis: '0'
-                                    }],
-                                    [{
-                                        xAxis: '1',
-                                        yAxis: '50',
-                                        itemStyle: {
-                                            color: 'rgba(128,128,128,0)'
+								}, {
+									xAxis: '0',
+									yAxis: '0'
+								}],
+								[{
+									xAxis: '1',
+									yAxis: '50',
+									itemStyle: {
+										color: 'rgba(128,128,128,0)'
 
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['5%', '10%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'C-'
-                                        }
+									},
+									label: {
+										show: true,
+										position: ['5%', '10%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'C-'
+									}
 
-                                    }, {
-                                        xAxis: '0.5',
-                                        yAxis: '0'
-                                    }]
-                                ]
-                            }
-                        }
-                    ]
-                }
+								}, {
+									xAxis: '0.5',
+									yAxis: '0'
+								}]
+							]
+						}
+					}]
+				}
 
-                // 绘制图表
-                myScatter.setOption(option)
-                window.addEventListener('resize', function() {
-                    myScatter.resize()
-                })
+				// 绘制图表
+				myScatter.setOption(option)
+				window.addEventListener('resize', function() {
+					myScatter.resize()
+				})
 
-                // 散点图元素点击事件
-                myScatter.on('click', function(item) {
-                    _this.activeItemIndex = item.dataIndex
-                })
-            }
-        },
+				// 散点图元素点击事件
+				myScatter.on('click', function(item) {
+					_this.activeItemIndex = item.dataIndex
+				})
+			}
+		},
 
-        mounted() {
-            // 缓存有数据则渲染缓存数据
-            if (this.getScatterData) {
-                this.drawLine(this.renderData(this.getScatterData))
-            }
-        },
+		mounted() {
+			// 缓存有数据则渲染缓存数据
+			if (this.getAnalysisJson) {
+				this.drawLine(this.renderData(this.getAnalysisJson))
+			}
+		},
 
-        computed: {
-            // 获取最新散点图数据
-            getScatterData() {
-                return this.$store.state.totalAnalysis.scatterData
-            }
-        },
-        watch: {
-            scatterData: {
-                deep: true,
-                handler(val) {
-                    if (val.length) {
-                        this.drawLine(this.renderData(val)) // 获取最新落点图数据 进行渲染
-                    } else {
-                        this.drawLine(this.renderData(this.getScatterData))
-                    }
-                }
+		computed: {
+			// 获取最新散点图数据
+			getAnalysisJson() {
+				return this.$store.state.totalAnalysis.analysisJson
+			}
+		},
+		watch: {
+			scatterData: {
+				deep: true,
+				handler(val) {
+					console.log('变化了',val)
+					if (val.length) {
+						this.drawLine(this.renderData(val)) // 获取最新落点图数据 进行渲染
+					} else {
+						this.drawLine([])
+					}
+				}
 
-            }
-        }
-    }
+			}
+		}
+	}
 </script>
 
 <style scoped>
-    #myScatter {
-        width: 100%;
-        height: 500px;
-        margin: 0 auto;
-        display: block;
-    }
+	#myScatter {
+		width: 100%;
+		height: 500px;
+		margin: 0 auto;
+		display: block;
+	}
 </style>

+ 261 - 294
TEAMModelOS/ClientApp/src/components/student-analysis/total/BaseTestScatter.vue

@@ -1,316 +1,283 @@
 <template>
-    <div id="testScatter"></div>
+	<div id="testScatter"></div>
 </template>
 
 <script>
-    export default {
-        name: 'hello',
-        props: ['currentIndex'],
-        data() {
-            return {
-                originArr: [],
-                dataArr: [],
-                activeItemIndex: 0
-            }
-        },
-        created() {
+	export default {
+		name: 'testScatter',
+		props: ['currentIndex','scatterData'],
+		data() {
+			return {
+				originArr: [],
+				dataArr: [],
+				activeItemIndex: 0
+			}
+		},
+		created() {
 
-        },
+		},
 
-        methods: {
+		methods: {
+			drawLine(data) {
+				// 基于准备好的dom,初始化echarts实例
+				let myScatter = this.$echarts.init(document.getElementById('testScatter'), 'chalk')
+				let _this = this
+				console.log('试题落点数据',data)
 
-            // 调整图表所需数据结构格式
-            renderData(arr) {
-                let newArr = []
-                arr.forEach(item => {
-                    let arr = []
-                    arr.push(item.X)
-                    arr.push(item.Y)
-                    arr.push(item.type)
-                    arr.push(item.id)
-                    newArr.push(arr)
-                })
-                return newArr
-            },
-
-            drawLine(data) {
-                // 基于准备好的dom,初始化echarts实例
-                let myScatter = this.$echarts.init(document.getElementById('testScatter'), 'chalk')
-                let _this = this
-
-                // 指定图表的配置项和数据
-                var option = {
-                    tooltip: {
-                        trigger: 'item',
-                        showDelay: 0,
-                        axisPointer: {
-                            show: true,
-                            lineStyle: {
-                                type: 'dashed',
-                                width: 1
-                            }
-                        },
-                        textStyle: {
-                            height: '160px'
-                        },
-                        formatter: function(params) {
-                            const item = params
-                            return `${_this.$t('totalAnalysis.ta_table_text1')}:${item.data[3]}
+				// 指定图表的配置项和数据
+				var option = {
+					tooltip: {
+						trigger: 'item',
+						showDelay: 0,
+						axisPointer: {
+							show: true,
+							lineStyle: {
+								type: 'dashed',
+								width: 1
+							}
+						},
+						textStyle: {
+							height: '160px'
+						},
+						formatter: function(params) {
+							const item = params
+							return `${_this.$t('totalAnalysis.ta_table_text1')}:${item.data[3]}
                         <br/>${_this.$t('totalAnalysis.ta_table_text2')}:${item.data[2]}
                         <br/>${_this.$t('totalAnalysis.ta_chart_text2')}:${item.data[1]}%
                        `
-                        }
-                    },
-                    legend: {
-                        data: [_this.$t('totalAnalysis.ta_chart_text1')]
-                    },
-                    dataZoom: [{
-                        show: true,
-                        type: 'inside',
-                        start: 0,
-                        end: 100,
-                        bottom: 10,
-                        height: 15
-                    },
-                    {
-                        show: true,
-                        type: 'slider',
-                        start: 0,
-                        end: 100,
-                        bottom: 0,
-                        height: 35,
-                        textStyle: {
-                            color: '#BBBBBB'
-                        }
-                    }],
-                    xAxis: [
-                        {
-                            type: 'value',
-                            splitNumber: 2,
-                            name: _this.$t('totalAnalysis.ta_chart_text3'),
-                            nameTextStyle: {
-                                color: '#e4eadb'
-                            },
-                            scale: true,
-                            splitLine: {
-                                show: true,
-                                lineStyle: {
-                                    color: '#595959'
-                                }
-                            }
-                        }
-                    ],
-                    yAxis: [
-                        {
-                            type: 'value',
-                            name: _this.$t('totalAnalysis.ta_chart_text2'),
-                            nameTextStyle: {
-                                color: '#e4eadb'
-                            },
-                            max: 100,
-                            min: 0,
-                            splitLine: {
-                                show: false,
-                                lineStyle: {
-                                    color: '#595959'
-                                }
-                            },
-                            interval: 50,
-                            axisLabel: {
-                                show: true,
-                                formatter: function(value) {
-                                    let val = []
-                                    if (value !== 25) {
-                                        val.push(value + '%')
-                                    }
-                                    return val
-                                }
-                            },
-                            spiltArea: {
-                                show: true
-                            }
-                        }
-                    ],
-                    series: [
-                        {
-                            name: _this.$t('totalAnalysis.ta_chart_text1'),
-                            type: 'scatter',
-                            data: data,
-                            symbolSize: 20,
-                            emphasis: {
-                                itemStyle: {
-                                    color: '#ff99cc'
-                                }
-                            },
-                            // itemStyle: {
-                            //  color: "#79c8e8"
-                            // },
-                            itemStyle: {
-                                color: function(params) {
-                                    var key = params.dataIndex
-                                    if (key === _this.activeItemIndex) {
-                                        return '#ff99cc'
-                                    } else {
-                                        return '#79c8e8'
-                                    }
-                                },
-                                width: 20
-                            },
-                            markLine: {
-                                silent: true,
-                                animation: false,
-                                data: [
-                                    { yAxis: 50 }, { yAxis: 100 }
-                                ],
-                                label: {
-                                    color: '#e4eadb',
-                                    formatter: '{c}%'
-                                },
-                                lineStyle: {
-                                    color: '#595959',
-                                    type: 'solid'
-                                }
-                            },
-                            markArea: {
-                                silent: true,
-                                data: [
-                                    [{
-                                        xAxis: '0.5',
-                                        yAxis: '50',
-                                        itemStyle: {
-                                            color: 'rgba(128,28,128,0)'
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['90%', '10%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'B'
-                                        }
-                                    }, {
-                                        xAxis: '0',
-                                        yAxis: '0'
-                                    }],
-                                    [{
-                                        xAxis: '1',
-                                        yAxis: '50',
-                                        itemStyle: {
-                                            color: 'rgba(90,90,90,.2)'
-
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['5%', '10%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'B-'
-                                        }
+						}
+					},
+					legend: {
+						data: [_this.$t('totalAnalysis.ta_chart_text1')]
+					},
+					dataZoom: [{
+							show: true,
+							type: 'inside',
+							start: 0,
+							end: 100,
+							bottom: 10,
+							height: 15
+						},
+						{
+							show: true,
+							type: 'slider',
+							start: 0,
+							end: 100,
+							bottom: 0,
+							height: 35,
+							textStyle: {
+								color: '#BBBBBB'
+							}
+						}
+					],
+					xAxis: [{
+						type: 'value',
+						splitNumber: 2,
+						name: _this.$t('totalAnalysis.ta_chart_text3'),
+						nameTextStyle: {
+							color: '#e4eadb'
+						},
+						scale: true,
+						splitLine: {
+							show: true,
+							lineStyle: {
+								color: '#595959'
+							}
+						}
+					}],
+					yAxis: [{
+						type: 'value',
+						name: _this.$t('totalAnalysis.ta_chart_text2'),
+						nameTextStyle: {
+							color: '#e4eadb'
+						},
+						max: 100,
+						min: 0,
+						splitLine: {
+							show: false,
+							lineStyle: {
+								color: '#595959'
+							}
+						},
+						interval: 50,
+						axisLabel: {
+							show: true,
+							formatter: function(value) {
+								let val = []
+								if (value !== 25) {
+									val.push(value + '%')
+								}
+								return val
+							}
+						},
+						spiltArea: {
+							show: true
+						}
+					}],
+					series: [{
+						name: _this.$t('totalAnalysis.ta_chart_text1'),
+						type: 'scatter',
+						data: data,
+						symbolSize: 20,
+						emphasis: {
+							itemStyle: {
+								color: '#ff99cc'
+							}
+						},
+						// itemStyle: {
+						//  color: "#79c8e8"
+						// },
+						itemStyle: {
+							color: function(params) {
+								var key = params.dataIndex
+								if (key === _this.activeItemIndex) {
+									return '#ff99cc'
+								} else {
+									return '#79c8e8'
+								}
+							},
+							width: 20
+						},
+						markLine: {
+							silent: true,
+							animation: false,
+							data: [{
+								yAxis: 50
+							}, {
+								yAxis: 100
+							}],
+							label: {
+								color: '#e4eadb',
+								formatter: '{c}%'
+							},
+							lineStyle: {
+								color: '#595959',
+								type: 'solid'
+							}
+						},
+						markArea: {
+							silent: true,
+							data: [
+								[{
+									xAxis: '0.5',
+									yAxis: '50',
+									itemStyle: {
+										color: 'rgba(128,28,128,0)'
+									},
+									label: {
+										show: true,
+										position: ['90%', '10%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'B'
+									}
+								}, {
+									xAxis: '0',
+									yAxis: '0'
+								}],
+								[{
+									xAxis: '1',
+									yAxis: '50',
+									itemStyle: {
+										color: 'rgba(90,90,90,.2)'
 
-                                    }, {
-                                        xAxis: '0.5',
-                                        yAxis: '0'
-                                    }],
-                                    [{
-                                        xAxis: '0.5',
-                                        yAxis: '100',
-                                        itemStyle: {
-                                            color: 'rgba(90,90,90,.2)'
+									},
+									label: {
+										show: true,
+										position: ['5%', '10%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'B-'
+									}
 
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['90%', '80%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'A'
-                                        }
+								}, {
+									xAxis: '0.5',
+									yAxis: '0'
+								}],
+								[{
+									xAxis: '0.5',
+									yAxis: '100',
+									itemStyle: {
+										color: 'rgba(90,90,90,.2)'
 
-                                    }, {
-                                        xAxis: '0',
-                                        yAxis: '50'
-                                    }],
-                                    [{
-                                        xAxis: '1',
-                                        yAxis: '100',
-                                        itemStyle: {
-                                            color: 'rgba(128,128,128,0)'
+									},
+									label: {
+										show: true,
+										position: ['90%', '80%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'A'
+									}
 
-                                        },
-                                        label: {
-                                            show: true,
-                                            position: ['5%', '40%'],
-                                            color: '#66ff33',
-                                            fontSize: 20,
-                                            formatter: 'A-'
-                                        }
-                                    }, {
-                                        xAxis: '0.5',
-                                        yAxis: '0'
-                                    }]
-                                ]
-                            }
-                        }
-                    ]
-                }
+								}, {
+									xAxis: '0',
+									yAxis: '50'
+								}],
+								[{
+									xAxis: '1',
+									yAxis: '100',
+									itemStyle: {
+										color: 'rgba(128,128,128,0)'
 
-                // 绘制图表
-                myScatter.setOption(option)
-                window.addEventListener('resize', function() {
-                    myScatter.resize()
-                })
+									},
+									label: {
+										show: true,
+										position: ['5%', '40%'],
+										color: '#66ff33',
+										fontSize: 20,
+										formatter: 'A-'
+									}
+								}, {
+									xAxis: '0.5',
+									yAxis: '0'
+								}]
+							]
+						}
+					}]
+				}
 
-                let that = this
-                myScatter.on('click', function(item) {
-                    that.activeItemIndex = item.dataIndex
-                    that.$emit('handleIndexClick', item.dataIndex + 1)
-                    myScatter.setOption(option)
-                })
-            }
-        },
+				// 绘制图表
+				myScatter.setOption(option)
+				window.addEventListener('resize', function() {
+					myScatter.resize()
+				})
 
-        mounted() {
-            // 缓存有数据则渲染缓存数据
-            if (this.getExerciseData) {
-                this.drawLine(this.renderData(this.getExerciseData))
-            }
-        },
-
-        computed: {
-            // 获取最新散点图数据
-            getExerciseData() {
-                return this.$store.state.totalAnalysis.exerciseData
-            }
-        },
-        watch: {
-            getExerciseData: {
-                deep: true,
-                handler(val) {
-                    if (val) {
-                        this.drawLine(this.renderData(val)) // 获取最新落点图数据 进行渲染
-                    }
-                }
-
-            },
-            currentIndex: {
-                deep: true,
-                handler(val) {
-                    if (val && this.getExerciseData) {
-                        this.activeItemIndex = +val - 1
-                        this.drawLine(this.renderData(this.getExerciseData))
-                    }
-                }
-            }
-        }
-    }
+				let that = this
+				myScatter.on('click', function(item) {
+					that.activeItemIndex = item.dataIndex
+					that.$emit('handleIndexClick', item.dataIndex + 1)
+					myScatter.setOption(option)
+				})
+			}
+		},
+		watch: {
+			scatterData:{
+				deep: true,
+				handler(val) {
+					if (val) {
+						this.drawLine(val)
+					}
+				}
+			},
+			currentIndex: {
+				deep: true,
+				handler(val) {
+					if (val && this.scatterData) {
+						this.activeItemIndex = +val - 1
+						this.drawLine(this.scatterData)
+					}
+				}
+			}
+		}
+	}
 </script>
 
 <!-- Add "scoped" attribute to limit CSS to this component only -->
 <style scoped>
-
-    #testScatter {
-        width: 100%;
-        height: 500px;
-        margin: 0 auto;
-        display: block;
-    }
+	#testScatter {
+		width: 100%;
+		height: 500px;
+		margin: 0 auto;
+		display: block;
+	}
 </style>

+ 4 - 5
TEAMModelOS/ClientApp/src/store/module/totalAnalysis.js

@@ -194,17 +194,16 @@ export default {
     actions: {
 		
 		// 获取最新学情数据
-		getAnalysisJson(context){
+		getAnalysisJson(context,params){
 			return new Promise((r, j) => {
 			    if (context.state.analysisJson) {
 			        console.log('Cache-analysisJson')
 			        r(context.state.analysisJson)
 			    } else {
-			        apiTools.totalAnalysis.getAnalysis({ 
-						id:'8aed5f91-7e4f-4e57-b17e-538cd1a985ca',
-						code:'hbcn'
-					}).then(res => { // api请求
+			        apiTools.totalAnalysis.getAnalysis(params).then(res => { // api请求
 			            context.commit('updateAnalysisJson', res) // 提交到vuex保存数据
+			            context.commit('updateSubjectList', res.subjects.map(i => i.name)) // 提交到vuex保存数据
+			            context.commit('updateCurSubject', res.subjects.map(i => i.name)[0]) // 提交到vuex保存数据
 			            console.log('API-analysisJson', res)
 			            r(res)
 			        }).catch(err => {

+ 1 - 1
TEAMModelOS/ClientApp/src/utils/evTools.js

@@ -117,7 +117,7 @@ export default {
 						const blobHost = list[i].scope === 'school' ?  JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri :  JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8")).blob_uri
 						// 根据试题的Blob地址 去读取JSON文件
 						let sasString = list[i].scope === 'school' ?  await $tools.getSchoolSas() : await $tools.getPrivateSas()
-						let jsonInfo = await $tools.getFile(blobHost + list[i].blob + sasString.sas)
+						let jsonInfo = list[i].blob.includes('https://') ? await $tools.getFile(list[i].blob + sasString.sas) : await $tools.getFile(blobHost + list[i].blob + sasString.sas)
 						let jsonData = JSON.parse(jsonInfo)
 						// 如果是综合题 那就拿到children里面的小题id集合 去换取小题的blobJSON文件 然后替换children的内容
 						if(jsonData.exercise.children.length && jsonData.exercise.type === 'compose'){

+ 2 - 0
TEAMModelOS/ClientApp/src/view/evaluation/index/CreatePaper.vue

@@ -461,6 +461,8 @@
 							let o = {
 								url: item.id + '.json',
 								type: item.type,
+								knowledge:item.points,
+								field:item.field,
 								scoring: {
 									score: item.score,
 									ans: nullType.includes(item.type) ? [] : item.answer

+ 2 - 0
TEAMModelOS/ClientApp/src/view/learnactivity/CreatePrivEva.vue

@@ -524,6 +524,8 @@ export default {
                         if (rule[i].slides[k].type !== 'compose') {
                             paper.answers.push(rule[i].slides[k].scoring.ans)
                             paper.point.push(rule[i].slides[k].scoring.score)
+                            paper.knowledge.push(rule[i].slides[k].scoring.knowledge)
+                            paper.field.push(rule[i].slides[k].scoring.field)
                         }
                     }
                     paperDto.push(paper)

+ 2 - 0
TEAMModelOS/ClientApp/src/view/learnactivity/CreateSchoolEva.vue

@@ -680,6 +680,8 @@ export default {
                         if (rule[i].slides[k].type !== 'compose') {
                             paper.answers.push(rule[i].slides[k].scoring.ans)
                             paper.point.push(rule[i].slides[k].scoring.score)
+							paper.knowledge.push(rule[i].slides[k].scoring.knowledge)
+							paper.field.push(rule[i].slides[k].scoring.field)
                         }
                     }
                     paperDto.push(paper)

+ 40 - 8
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/AchievementAnalysis/AchievementAnalysis.vue

@@ -161,29 +161,60 @@
         methods: {
 			/* 获取成绩分析模块 -- 及格率统计数据 */
 			getPassRate(analysisJson){
+				console.log(analysisJson)
 				let result = []
-				analysisJson.classAnalyses[0].subjects.forEach((item,index) => {
+				analysisJson.classes[0].subjects.forEach((item,index) => {
 					result.push({
-						name:this.subjectList.filter(i => i.id === item.id)[0].name,
+						name:item.name,
 						class:(+item.passPercent * 100) + '%',
-						grade:+analysisJson.gradeAnalyses[0].subjects[index].passPercent * 100 + '%'
+						grade:+analysisJson.grades.subjects[index].passPercent * 100 + '%'
 					})
 				})
 				console.log('passRate',result)
 				return result
+			},
+			
+			/* 获取成绩分西-预警统计表格数据 */
+			getEarlyWarningData(analysisJson){
+				let result = []
+				analysisJson.classes.forEach((item,index) => {
+					result.push({
+						classId:item.className,
+						totalNum:item.stuCount,
+						average:item.totalAverage,
+						standardDeviation:item.standardDeviation.toFixed(2),
+						overAverageRate:0,
+						gradeRank:0
+					})
+				})
+				return result
 			}
         },
         mounted() {
             this.$parent.dataSelectIndex = 0
             this.$refs.achievementTable.$el.childNodes[1].style.borderRight = '0'
+			
+			
 
             // 如果有缓存的数据 则读取缓存数据
             if (this.getAnalysisJson) {
-                // this.earlyWarningData = this.$tools.jsonTransform(this.getAchievementData.earlyWarning)
-                this.subjectList = this.getAnalysisJson.subjects
-                this.passRate = this.getPassRate(this.getAnalysisJson)
+                this.earlyWarningData = this.getEarlyWarningData(this.getAnalysisJson)
+                this.subjectList = this.getAnalysisJson.classes.subjects
+                // this.passRate = this.getPassRate(this.getAnalysisJson)
 				console.log('achievement页面接收的JSON',this.getAnalysisJson)
-            }
+            }else if(localStorage.getItem('curExam')){
+				console.log('没有')
+				let item = JSON.parse(localStorage.getItem('curExam'))
+				this.$store.dispatch('getAnalysisJson',{
+					code:item.code.replace('Exam-',''),
+					id:item.id
+				}).then(res => {
+					this.earlyWarningData = this.getEarlyWarningData(this.getAnalysisJson)
+					this.subjectList = this.getAnalysisJson.classes.subjects
+					// this.passRate = this.getPassRate(this.getAnalysisJson)
+					console.log('achievement页面接收的JSON',this.getAnalysisJson)
+				})
+			}
 			this.$EventBus.$off('onExport')
             this.$EventBus.$on("onExport", exportTables => {
                 console.log(exportTables)
@@ -216,7 +247,8 @@
                 // this.passRate = val.passRate // 及格率统计
                 // this.subjectList = val.average.datas.map(item => item.name) // 科目列表
 				this.subjectList = val.subjects
-				this.passRate = this.getPassRate(val)
+				this.earlyWarningData = this.getEarlyWarningData(this.getAnalysisJson)
+				// this.passRate = this.getPassRate(val)
             },
             // 渲染最新预警统计数据
             getSubjectList(val) {

+ 50 - 27
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/AchievementAnalysis/EarlyWarning.vue

@@ -166,16 +166,38 @@
              * @param subjectIndex
              */
             onGetClassTable(subjectIndex) {
-                let list = JSON.parse(JSON.stringify(this.getAchievementData.rankPR))
+				console.log(this.getAnalysisJson)
+				let result = []
+                let analysisJson = JSON.parse(JSON.stringify(this.getAnalysisJson))
+				let curClassItem = analysisJson.classes.filter(i => i.className === this.className)[0]
+				let studentIds = curClassItem.studentIds
+				this.classAverage = curClassItem.totalAverage
+				studentIds.forEach((stuId,stuIndex) => {
+					let stuItem = analysisJson.students.filter(i => i.id === stuId)[0]
+					let stuSubjectItem = analysisJson.students.filter(i => i.id === stuId)[0].subjects[subjectIndex]
+					result.push({
+						name:stuItem.name,
+						setNo:stuItem.no,
+						score:stuSubjectItem.score,
+						classPR:stuSubjectItem.cpr,
+						classRank:stuSubjectItem.csort, 
+						gradePR:stuSubjectItem.gpr,
+						gradeRank:stuSubjectItem.gsort,
+						areaPR:0,
+						areaRank:0
+					})
+				})
+				console.log(result)
+				return result
                 // let classList = list[subjectIndex].datas.keys()
-                let totalItem = list.splice(list.length - 1, 1)
-                list.unshift(totalItem[0]) // 把总分数据放到list第一位 与下拉框对应
-                let keys = list[subjectIndex].keys
-                let datas = list[subjectIndex].datas[this.className] // 获取当前所选班级的学生数据
-                this.classAverage = list[subjectIndex].classAverage[this.className]
-                this.gradeAverage = list[subjectIndex].gradeAverage
-                this.areaAverage = list[subjectIndex].gradeAverage
-                return this.$tools.jsonTransform({ datas: datas, keys: keys })
+                // let totalItem = list.splice(list.length - 1, 1)
+                // list.unshift(totalItem[0]) // 把总分数据放到list第一位 与下拉框对应
+                // let keys = list[subjectIndex].keys
+                // let datas = list[subjectIndex].datas[this.className] // 获取当前所选班级的学生数据
+                
+                // this.gradeAverage = list[subjectIndex].gradeAverage
+                // this.areaAverage = list[subjectIndex].gradeAverage
+                // return this.$tools.jsonTransform({ datas: datas, keys: keys })
             },
 
             /**
@@ -428,33 +450,34 @@
             this.$parent.isShowQuestions = true
             this.$refs.percentTable.$el.childNodes[1].style.borderRight = '0'
 
-            if (this.getAchievementData) {
+            if (this.getAnalysisJson) {
                 this.tableData = this.onGetClassTable(0)
-                this.echartData = this.onGetClassTable(0)
-                this.subjectList = this.getAchievementData.average.datas.map(item => item.name)
-                this.drawLine(this.echartData)
+                this.subjectList = this.getAnalysisJson.subjects.map(item => item.name)
+                this.drawLine(this.tableData)
             }
         },
 
         computed: {
-            getAchievementData() {
-                return this.$store.state.totalAnalysis.achievementData
+            getAnalysisJson() {
+                return this.$store.state.totalAnalysis.analysisJson
             }
         },
         watch: {
-            getAchievementData(val) {
+            getAnalysisJson(val) {
                 if (!val) return
-
-                let totalItem = val.rankPR.splice(val.rankPR.length - 1, 1)
-                let PRData = val.rankPR.unshift(totalItem)
-                console.log(PRData)
-
-                let keys = PRData[0].keys
-                let datas = PRData[0].datas.filter(item => item.hasOwnProperty(this.className))[0]
-                this.tableData = this.$tools.jsonTransform({ datas: datas, keys: keys })
-                this.echartData = this.$tools.jsonTransform({ datas: datas, keys: keys })
-                this.subjectList = val.average.datas.map(item => item.name)
-                this.drawLine(this.echartData)
+				this.tableData = this.onGetClassTable(0)
+				this.subjectList = val.subjects.map(item => item.name)
+				this.drawLine(this.tableData)
+                // let totalItem = val.rankPR.splice(val.rankPR.length - 1, 1)
+                // let PRData = val.rankPR.unshift(totalItem)
+                // console.log(PRData)
+
+                // let keys = PRData[0].keys
+                // let datas = PRData[0].datas.filter(item => item.hasOwnProperty(this.className))[0]
+                // this.tableData = this.$tools.jsonTransform({ datas: datas, keys: keys })
+                // this.echartData = this.$tools.jsonTransform({ datas: datas, keys: keys })
+                // this.subjectList = val.average.datas.map(item => item.name)
+                // this.drawLine(this.echartData)
             }
 
         }

+ 33 - 19
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/AchievementAnalysis/EntryTables.vue

@@ -125,13 +125,13 @@
 
             renderColumns(data) {
                 // 渲染进线表格
-                let subjectList = data.keys.slice(4)
+                let subjectList = data.classes[0].subjects
 				let subjectColumns = []
                 subjectList.forEach(item => {
                     let subjectColumn = {
-                        title: item,
+                        title: item.name,
                         sortable: 'custom',
-                        key: item
+                        key: item.name
                     }
 					subjectColumns.push(subjectColumn)
                 })
@@ -139,16 +139,37 @@
 				this.entryNumberColumns.splice(4,this.entryNumberColumns.length - 4,...subjectColumns)
             },
 			
+			/* 获取进线情况统计表格数据 */
 			getTableDatas(analysisJson){
 				let result = []
-				analysisJson.analysis.names.forEach((stu,stuIndex) => {
+				analysisJson.students.forEach((stu,stuIndex) => {
 					result.push({
 						name:stu.name,
-						className:0,
+						className:stu.className,
 						gradeRank:0,
-						score:0,
+						score:stu.total,
+					})
+					// 动态添加学生每个科目的得分
+					stu.subjects.forEach(subject => {
+						result[stuIndex][subject.name] = subject.score
+					})
+				})
+				return result
+			},
+			
+			/* 获取进线率统计数据 */
+			getEntryBarData(analysisJson){
+				let result = []
+				analysisJson.classes.forEach((classItem,classIndex) => {
+					result.push({
+						gradeRank:0,
+						name:classItem.className,
+						entryNum:classItem.lineCount,
+						totalNum:classItem.stuCount,
+						overAverageRate:(classItem.lineCount / classItem.stuCount).toFixed(2) * 100,
 					})
 				})
+				return result
 			}
         },
         mounted() {
@@ -156,12 +177,9 @@
             this.$refs.entryTable.$el.childNodes[1].style.borderRight = '0'
 
             if (this.getAnalysisJson) {
-                // this.entryBarData = this.$tools.jsonTransform(this.getEntryData.entryLineBar) // 进线人数统计柱状图数据
-                // this.renderColumns(this.getEntryData.entryTable) // 渲染科目表头
-                // this.entryTableData = this.$tools.jsonTransform(this.getEntryData.entryTable) // 进线人数统计表格数据
-                // let tableList = this.entryTableData
-                // this.entryTableData = tableList
-				console.log('进线情况统计表格',this.getAnalysisJson)
+				this.renderColumns(this.getAnalysisJson) // 渲染科目表头
+				this.entryTableData = this.getTableDatas(this.getAnalysisJson)
+				this.entryBarData = this.getEntryBarData(this.getAnalysisJson)
             }
         },
         computed: {
@@ -172,13 +190,9 @@
         watch: {
             getAnalysisJson(val) {
                 if (!val) return
-                // let vuexData = val.entryTable // 拿到最新的 成绩分析模块 进线人数和进线情况数据
-                // this.entryBarData = this.$tools.jsonTransform(val.entryLineBar) // 渲染进线人数统计柱状图表格
-                // this.renderColumns(vuexData)
-                // this.entryTableData = this.$tools.jsonTransform(vuexData)
-                // let tableList = this.entryTableData
-                // this.entryTableData = tableList
-				console.log('进线情况统计表格Watch',val)
+				this.renderColumns(val)
+				this.entryTableData = this.getTableDatas(val)
+				this.entryBarData = this.getEntryBarData(val)
             }
         }
     }

+ 19 - 8
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/EvaluationList/TotalIndex.vue

@@ -389,8 +389,8 @@ export default {
                         res.examInfo = res.examInfo.sort((a, b) => {
                             return a.createTime - b.createTime > 0 ? -1 : 1
                         })
-                        this.examList = res.examInfo
-                        this.originList = res.examInfo
+                        this.examList = res.examInfo.filter(i => i.progress === 'finish')
+                        this.originList = res.examInfo.filter(i => i.progress === 'finish')
                         this.searchList = this.examList.length ? this.examList.map((item) => item.name) : []
                         this.$store.commit("updateExamList", res.examInfo);
                         this.isLoadingList = false;
@@ -623,12 +623,23 @@ export default {
         },
 
         handleChooseExam(item, index) {
-            this.$router.push({
-                path: "/total",
-                query: {
-                    index: index,
-                },
-            });
+			this.isLoadingList = true
+			this.$store.commit('updateAnalysisJson',null)
+			this.$store.dispatch('getAnalysisJson',{
+				code:item.code.replace('Exam-',''),
+				id:item.id
+			}).then(res => {
+			    console.log(res)
+				localStorage.setItem('curExam',JSON.stringify(item))
+				this.isLoadingList = false
+				this.$router.push({
+				    path: "/total",
+				    query: {
+				        index: index,
+				    },
+				});
+			})
+            
         },
     },
     mounted() {

+ 50 - 11
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/ScatterAnalysis/ScatterAnalysis.vue

@@ -78,6 +78,7 @@
         data() {
             return {
                 tableData: [],
+				originTableData:[],
                 currentClass: 0,
                 classList: [],
                 tableColumns: [
@@ -155,34 +156,72 @@
         methods: {
             onClassSelect(val) {
                 if (val === 0) {
-                    this.tableData = this.getScatterData
+                    this.tableData = this.originTableData
                 } else {
-                    this.tableData = this.getScatterData.filter(item => item.className === this.classList[val])
+                    this.tableData = this.originTableData.filter(item => item.className === this.classList[val])
                 }
-            }
+				console.log(this.tableData)
+            },
+			
+			// 调整图表所需数据结构格式
+			renderData(analysisJson) {
+				let curSubject = this.$store.state.totalAnalysis.currentSubject
+				let result = []
+				analysisJson.subjects.forEach((subject, subjectIndex) => {
+					if(subject.name === curSubject){
+						result.push({
+							subject: subject.name,
+							students: this.getSubjectStudents(analysisJson, subjectIndex)
+						})
+					}
+				})
+				return result[0].students
+			},
+			
+			/* 获取每个学生每个科目下的落点数据 */
+			getSubjectStudents(analysisJson, subjectIndex) {
+				let result = []
+				analysisJson.students.forEach(stu => {
+					let obj = {}
+					analysisJson.scatterKey.forEach((key, index) => {
+						obj[key] = stu.subjects[subjectIndex].scatter[index]
+					})
+					result.push(obj)
+				})
+				return result
+			},
         },
 
         mounted() {
             this.$refs.scatterTable.$el.childNodes[1].style.borderRight = '0'
-            if (this.getScatterData) {
-                this.tableData = this.getScatterData
-                this.classList = ['全部'].concat([...new Set(this.getScatterData.map(item => item.className))]) // 获取班级列表
+            if (this.getAnalysisJson) {
+                this.tableData = this.renderData(this.getAnalysisJson)
+				this.originTableData = JSON.parse(JSON.stringify(this.tableData)) 
+                this.classList = ['全部'].concat([...new Set(this.getAnalysisJson.classes.map(item => item.className))]) // 获取班级列表
             }
+			
+			this.$EventBus.$off('onSubjectChange')
+			this.$EventBus.$on('onSubjectChange',val => {
+				this.tableData = this.renderData(this.getAnalysisJson)
+				this.originTableData = JSON.parse(JSON.stringify(this.tableData)) 
+				this.currentClass = 0
+			})
         },
 
         computed: {
             // 获取最新散点图数据
-            getScatterData() {
-                return this.$store.state.totalAnalysis.scatterData
+            getAnalysisJson() {
+                return this.$store.state.totalAnalysis.analysisJson
             }
         },
         watch: {
-            getScatterData: {
+            getAnalysisJson: {
                 deep: true,
                 handler(val) {
                     if (val) {
-                        this.tableData = val // 获取最新落点图数据 进行渲染表格
-                        this.classList = ['全部'].concat([...new Set(val.map(item => item.className))])
+                        this.tableData = this.renderData(JSON.parse(JSON.stringify(val)) )
+						this.originTableData = JSON.parse(JSON.stringify(this.tableData)) 
+                        this.classList = ['全部'].concat([...new Set(val.classes.map(item => item.className))])
                     }
                 }
 

+ 13 - 18
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/QuestionList.css

@@ -12,7 +12,7 @@
 .ql-left-box {
     position:relative;
     width:80%;
-    background:#fff;
+    background:#dddddd;
     color:#525252;
     font-size:14px;
 }
@@ -37,7 +37,7 @@
 		right: 24px;
         font-size: 14px;
         cursor: pointer;
-        background: #3c8fa2;
+        background: #2db7f5;
         box-shadow: 0px 2px 3px 0px #8f8f8f;
         padding: 10px 30px;
         color: #fff;
@@ -159,47 +159,42 @@
     top:232px; */
 	position: sticky;
 	top: 0;
+	background: #fff;
+	color: #333;
 }
 
 .ql-right-box .ql-right-score {
     width: 100%;
     padding: 20px;
-    background: #525252;
-    font-size: 18px;
-    font-weight: bold;
+    font-size: 14px;
+	display: flex;
+	flex-direction: column;
 }
 
     .ql-right-box .ql-right-list {
         width: 100%;
         max-height:700px;
-        overflow-y:scroll;
-        padding: 20px;
-        margin-top: 20px;
-        background: #525252;
+        padding: 0 20px 40px 20px;
     }
         .ql-right-box .ql-right-list .ql-right-part {
-            margin-top: 20px;
+            margin-top: 10px;
         }
         .ql-right-box .ql-right-list .ql-right-part-title {
             padding-left:5px;
-            font-weight:bold;
-            font-size:16px;
         }
         .ql-right-box .ql-right-list .ql-right-items {
             display:flex;
             flex-direction:row;
             flex-wrap:wrap;
             margin-top:10px;
+			color: #fff;
         }
         .ql-right-box .ql-right-list .ql-right-item {
-            width: 32px;
-            height: 32px;
-            line-height: 32px;
+			padding: 5px 10px;
             text-align: center;
             margin: 5px;
             cursor: pointer;
-            background: #3c8fa2;
-            box-shadow: -3px -2px 5px #2d2c2c;
+            background: #2db7f5;
         }
 
     .ql-right-box .ql-line {
@@ -208,7 +203,7 @@
         height: 12px;
         margin-right: 5px;
         margin-top: 5px;
-        background: #3c8fa2;
+        background: #2db7f5;
     }
 
 

+ 81 - 154
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/QuestionList.vue

@@ -5,93 +5,21 @@
             <!--<p style="font-size:28px;text-align:center;margin:20px 0">芳草小学2019年5月期中考试数学试卷</p>
             <p style="font-size:16px;text-align:center">考试时间:120分钟&nbsp;&nbsp;&nbsp;出卷人:张纪中</p>-->
 
-            <span class="btn-back" @click="handleBackTo" ref="btnBack"><Icon type="ios-arrow-back" />{{$t('totalAnalysis.ql_text13')}}</span>
+            <!-- <span class="btn-back" @click="handleBackTo" ref="btnBack"><Icon type="ios-arrow-back" />{{$t('totalAnalysis.ql_text13')}}</span> -->
             <Loading :top="300" v-show="dataLoading" type="3"></Loading>
-            <div class="ql-item" v-for="(question,index) in questionList" :key="index" :ref="'q'+index">
-                <div>
-                    <div class="item-question">
-                        <p>
-                            <span>{{index+1}} :</span>
-                            <span v-html="question.question"></span>
-                        </p>
-
-                    </div>
-                    <div class="item-question-score">
-                        <span class="item-type">{{question.type}}</span>
-                        <span class="item-type" style="background: #05b454;">{{question.score || 5}}{{$t('totalAnalysis.ql_text8')}}</span>
-                    </div>
-                </div>
-                <div class="item-option-wrap">
-                    <div v-for="(option,optionIndex) in question.option" :key="optionIndex" class="item-option">
-                        <p>{{String.fromCharCode(64 + parseInt(optionIndex+1))}} : <span v-html="option.value"></span></p>
-                    </div>
-                </div>
-
-                <!-- 如果是组合题 -->
-                <!--<div v-if="question.children.length">
-                    <div v-for="(childQuestion,childIndex) in question.children" :key="childIndex">
-                        <div class="item-question" style="margin-top:20px;">
-                            <p>{{childIndex+1}} : <span v-html="childQuestion.question"></span></p>
-                        </div>
-                        <div v-for="(childOption,childOptionIndex) in childQuestion.option" :key="childOptionIndex" style="margin:10px 0">
-                            <p>{{String.fromCharCode(64 + parseInt(childOptionIndex+1))}} : <span v-html="childOption.value"></span></p>
-                        </div>
-                        <div class="item-concept" style="margin-top:20px;">
-                        </div>
-                        <div class="item-answer">
-                            <span class="item-header-title">【答案】:</span>
-                            <span v-html="childQuestion.answer[0] || childQuestion.answer" v-if="childQuestion.type === 'Subjective'"></span>
-                            <span :class="[ childQuestion.type === 'Complete' ? 'item-answer-item':'']" v-for="(answer,answerIndex) in childQuestion.answer" :key="answerIndex" v-else-if="childQuestion.type == 'Complete'" v-html="answer"></span>
-                            <span :class="[ childQuestion.type === 'Complete' ? 'item-answer-item':'']" v-for="(answer,answerIndex) in childQuestion.answer" :key="answerIndex" v-else>{{answer}}</span>
-                        </div>
-                        <div class="item-explain">
-                            <div class="item-header-title">【解析】:</div>
-                            <div v-html="childQuestion.explain"></div>
-                        </div>
-                    </div>
-                </div>-->
-
-                <Collapse simple @on-change="handleCollapseChange">
-                    <Panel :name="index+'answer'">
-                        <!-- 查看答案与解析 -->
-                        <span>{{$t('totalAnalysis.ql_text9')}}</span>
-                        <div class="answerAndExplain" slot="content" style="margin-top:10px;margin-left: 25px;">
-                            <div class="item-answer" v-show="question.type !== 'Compose'">
-                                <span class="item-header-title">【{{$t('totalAnalysis.ql_text11')}}】</span>
-                                <span v-html="question.answer[0] || question.answer" v-if="question.type === 'Subjective'"></span>
-                                <span :class="[ question.type === 'Complete' ? 'item-answer-item':'']" v-for="(answer,answerIndex) in question.answer" :key="answerIndex" v-else-if="question.type == 'Complete'" v-html="answer"></span>
-                                <span :class="[ question.type === 'Complete' ? 'item-answer-item':'']" v-for="(answer,answerIndex) in question.answer" :key="answerIndex" v-else>{{answer}}</span>
-                            </div>
-                            <div class="item-explain" v-show="question.type !== 'Compose'">
-                                <div class="item-header-title">【{{$t('totalAnalysis.ql_text12')}}】</div>
-                                <div v-html="question.explain || '暂无解析'"></div>
-                            </div>
-                        </div>
-                    </Panel>
-                    <Panel :name="index+''">
-                        <!-- 查看数据分析 -->
-                        <span>{{$t('totalAnalysis.ql_text10')}}</span>
-                        <div class="answerAndExplain" slot="content" style="margin-top:10px" v-if="collapseList.indexOf(index.toString()) > -1">
-                            <Table :columns="dataColumns"  :data="tableData.filter((item,index2) => index2 === index)"></Table>
-                            <Table :columns="optionColumns" v-if="question.type === 'Single' || question.type === 'Multiple'" :data="optionsData" style="margin-top:20px"></Table>
-                            <div class="analysis-charts">
-                                <BaseLine :ids="'myLine' + index" :echartsData="tableData[index]"></BaseLine>
-                                <BaseRateLine :ids="'myRateLine' + index" v-if="question.type === 'Single' || question.type === 'Multiple'" :echartsData="optionsData"></BaseRateLine>
-                            </div>
-                        </div>
-                    </Panel>
-                </Collapse>
-
-            </div>
+			<ExerciseList :propsList="questionList" isAnalysis @pageScroll="doScroll" ref="exList"></ExerciseList>
         </div>
 
         <!-- 右侧题目列表题型概览 -->
         <div class='ql-right-box' ref="rightBox" :style="{width: isOpen ? '17%' : '18%'}">
             <div class="ql-right-score">
-                {{$t('totalAnalysis.ql_text1')}} :<span>{{sumArr(questionList.map(item => item.score))}} {{$t('totalAnalysis.ql_text8')}}</span>
+				<Button type="info" @click="handleBackTo">返回上级</Button>
+				<p style="margin-top: 20px;">试卷科目:{{ $store.state.totalAnalysis.currentSubject }}</p>
+				<p style="margin-top: 10px;">试卷题数:{{ questionList.length }}</p>
+                <p style="margin-top: 10px;">{{$t('totalAnalysis.ql_text1')}} :<span>{{sumArr(questionList.map(item => item.score))}} {{$t('totalAnalysis.ql_text8')}}</span></p> 
             </div>
+			
             <div class="ql-right-list">
-                <vuescroll>
                     <div>
                         <div class="ql-right-part" v-if="SingleList.length">
                             <span class="ql-right-part-title"><span class="ql-line"></span>{{$t('totalAnalysis.ql_text2')}}({{sumArr(SingleList.map(item => item.score))}}{{$t('totalAnalysis.ql_text8')}})</span>
@@ -130,8 +58,6 @@
                             </div>
                         </div>
                     </div>
-                    <!--<div style="margin-top:30px">注:标红题号为班级易错题目</div>-->
-                </vuescroll>
             </div>
         </div>
     </div>
@@ -140,12 +66,13 @@
 <script>
     import BaseLine from '@/components/student-analysis/total/BaseLine.vue'
     import BaseRateLine from '@/components/student-analysis/total/BaseRateLine.vue'
+    import ExerciseList from '@/components/evaluation/ExerciseList.vue'
     import Loading from '@/common/Loading.vue'
     // import questions from '@/static/questions.json'
     import { setTimeout } from 'timers'
     export default {
         components: {
-            BaseRateLine, BaseLine, Loading
+            BaseRateLine, BaseLine, Loading,ExerciseList
         },
         data() {
             return {
@@ -166,12 +93,12 @@
                 SubjectiveList: [],
                 ComposeList: [],
                 typeTransfer: {
-                    'Single': '单选',
-                    'Multiple': '多选',
-                    'Judge': '判断',
-                    'Complete': '填空',
-                    'Subjective': '主观',
-                    'Compose': '综合'
+                    'single': '单选',
+                    'multiple': '多选',
+                    'judge': '判断',
+                    'complete': '填空',
+                    'subjective': '主观',
+                    'compose': '综合'
                 },
                 diffColors: ['#32CF74', '#E8BE15', '#F19300', '#EB5E00', '#D30000'],
                 dataColumns: [
@@ -327,50 +254,13 @@
             let that = this
             let parentVm = this.$parent.$parent.$parent
             parentVm.isShowQuestions = true
-            this.$store.dispatch('getExamPaper').then(res => {
-                console.log(res)
-                this.rightTableData = this.$store.state.totalAnalysis.classList
-                this.questionList = res[0].item
-                this.SingleList = this.questionList.filter(item => item.type === 'Single')
-                this.MultipleList = this.questionList.filter(item => item.type === 'Multiple')
-                this.JudgeList = this.questionList.filter(item => item.type === 'Judge')
-                this.CompleteList = this.questionList.filter(item => item.type === 'Complete')
-                this.SubjectiveList = this.questionList.filter(item => item.type === 'Subjective')
-                this.ComposeList = this.questionList.filter(item => item.type === 'Compose')
-                this.dataLoading = false
-
-                // 如果是试题页面过来带有题序 则获取指定题目并进行滚动
-                if (this.$route.query.QIndex) {
-                    this.$nextTick(() => {
-                        let index = +this.$route.query.QIndex - 1
-                        this.handleCollapseChange([index.toString()])
-                        this.activeCollapseIndex.push(index + 'answer')
-                        setTimeout(function () {
-                            that.$refs['indexRef' + index][0].click() // 根据路由携带的题序 来触发对应题序的点击事件 完成滚动
-                        }, 1000)
-                    })
-                } else {
-                    this.$nextTick(() => {
-                        this.$refs.indexRef0[0].click()
-                    })
-                }
-            })
-
-            if (this.getExerciseData) {
-                this.tableData = this.getExerciseData
-            } else {
-                // 如果刷新试题页面 获取不到 缓存的试题数据 则根据缓存的参数再次请求API
-                this.$store.commit('updateCurSubject', localStorage.getItem('cur_s'))
-                this.$store.dispatch('getExerciseData').then(res => {
-                    console.log('试题F5操作获取最新试题数据')
-                    this.tableData = this.$store.state.totalAnalysis.exerciseData
-                })
-            }
-
-            let testScatter = this.$store.state.totalAnalysis.testScatter
-
-            console.log(this.tableData)
+			
+			let curExam = JSON.parse(localStorage.getItem('curExam'))
+			console.log('当前的评测数据',curExam)
+			let curPaper = curExam.papers[0]
+			this.initFullPaper(curPaper)
 
+            
             this.optionsData = [
                 {
                     option: 'A',
@@ -408,7 +298,33 @@
         },
 
         methods: {
-
+			
+			async initFullPaper(examPaper){
+				let fullPaperJson =  await this.$evTools.getFullPaper(examPaper)
+				this.questionList = fullPaperJson.item
+				this.SingleList = this.questionList.filter(item => item.type === 'single')
+				this.MultipleList = this.questionList.filter(item => item.type === 'multiple')
+				this.JudgeList = this.questionList.filter(item => item.type === 'judge')
+				this.CompleteList = this.questionList.filter(item => item.type === 'complete')
+				this.SubjectiveList = this.questionList.filter(item => item.type === 'subjective')
+				this.ComposeList = this.questionList.filter(item => item.type === 'compose')
+				this.dataLoading = false
+				console.log('当前的评测试卷数据',fullPaperJson)
+			},
+			
+			/* 页面滚动逻辑 */
+			doScroll(scrollDistance){
+				this.$nextTick(() => {
+					let parentVm = this.$parent.$parent.$parent
+					parentVm.$refs['vs'].scrollTo({
+							y: scrollDistance,
+						},
+						500,
+						"easeInQuad"
+					);
+				})
+			},
+			
             // 指定容器滚动到指定位置
             scrollToTop(element, to, duration) {
                 if (duration <= 0) return
@@ -423,31 +339,27 @@
 
             // 点击右边题序 获取到题目DOM 进行滚动操作
             handleItemClick(item, e) {
-                let parentVm = this.$parent.$parent.$parent
-                let currentSpan = e.target || e
-                let allList = document.getElementsByClassName('ql-right-item')
-                let questionList = document.getElementsByClassName('ql-item')
-                let itemIndex = this.questionList.indexOf(item)
-                let questionDom = questionList[itemIndex]
-                let scrollDistance = questionDom.offsetTop + 134 // 相对父级容器高度加上头部高度即为滚动距离
-                parentVm.$refs['vs'].scrollTo(
-                    {
-                        y: scrollDistance
-                    },
-                    500, 'easeInQuad'
-                )
-
-                // 伪数组处理统一背景颜色
-                Array.prototype.slice.call(allList).forEach(item => {
-                    item.style.background = '#3c8fa2'
-                })
-                // 将当前选中项修改选中色
-                currentSpan.style.background = '#139c51'
+				this.$nextTick(() => {
+					let parentVm = this.$parent.$parent.$parent
+					let currentSpan = e.target || e
+					let allList = document.getElementsByClassName('ql-right-item')
+					let questionList = this.$refs.exList.$el.getElementsByClassName('exercise-item')
+					let itemIndex = this.questionList.indexOf(item)
+					let questionDom = questionList[itemIndex]
+					this.doScroll(questionDom.offsetTop)
+					// 伪数组处理统一背景颜色
+					Array.prototype.slice.call(allList).forEach(item => {
+					    item.style.background = '#2db7f5'
+					})
+					// 将当前选中项修改选中色
+					currentSpan.style.background = '#139c51'
+				})
+                
             },
 
             // 点击返回
             handleBackTo() {
-                this.$refs.btnBack.style.display = 'none'
+                // this.$refs.btnBack.style.display = 'none'
                 this.$parent.$parent.$parent.isShowQuestions = false
                 this.$router.back(-1)
             },
@@ -471,7 +383,6 @@
 
             // 返回题目区域总分 字符串换算
             sumArr(arr) {
-				console.log(arr)
 				if(arr.length){
 					return arr.reduce((a,b) => a + b)
 				}else{
@@ -487,6 +398,22 @@
 				// 如果侧边栏展开的时候
 				this.isOpen = !val
 			})
+			
+			// 如果是试题页面过来带有题序 则获取指定题目并进行滚动
+			if (this.$route.query.QIndex) {
+				this.$nextTick(() => {
+					let index = +this.$route.query.QIndex - 1
+					this.handleCollapseChange([index.toString()])
+					this.activeCollapseIndex.push(index + 'answer')
+					setTimeout(() => {
+						this.$refs['indexRef' + index][0].click() // 根据路由携带的题序 来触发对应题序的点击事件 完成滚动
+					}, 1000)
+				})
+			} else {
+				this.$nextTick(() => {
+					this.$refs.indexRef0[0].click()
+				})
+			}
 
         },
 

+ 74 - 34
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/TestAnalysis/TestAnalysis.vue

@@ -3,7 +3,7 @@
         <Row>
             <Col span="12">
             <span class="component-title">{{$t('totalAnalysis.ta_title1')}}</span>
-            <BaseTestScatter @handleIndexClick="handleIndexClick" :currentIndex="currentExerciseIndex"></BaseTestScatter>
+            <BaseTestScatter @handleIndexClick="handleIndexClick" :scatterData="scatterData" :currentIndex="currentExerciseIndex"></BaseTestScatter>
             </Col>
             <Col span="12">
             <div class="scatter-statistics">
@@ -107,6 +107,7 @@
         data() {
             return {
                 tableData: [],
+				scatterData:[],
                 exerciseIndexList: [],
                 currentExerciseIndex: 0,
                 A1List: [],
@@ -264,14 +265,13 @@
         methods: {
             renderClassColumns(classData) {
                 // 渲染进线表格的班级数据
-                let classList = classData.map(item => item.className)
-                classList.forEach(item => {
+                classData.classes.forEach(item => {
                     let classColumn = {
-                        title: item,
+                        title: item.className,
                         sortable: 'custom',
-                        key: item,
+                        key: item.className,
                         render: (h, params) => {
-                            return h('span', (Number(params.row[item])).toFixed(0) + '%')
+                            return h('span', (Number(params.row.classScoreRate)).toFixed(0) + '%')
                         },
                         minWidth: 150
                     }
@@ -304,42 +304,82 @@
 
             handleIndexClick(index) {
                 this.$router.push({ path: '/total/questionList', query: { QIndex: index } })
-            }
-
+            },
+			
+			
+			// 调整图表所需数据结构格式
+			renderData(data) {
+				let analysisJson = JSON.parse(JSON.stringify(this.getAnalysisJson))
+				let curSubjectIndex = analysisJson.subjects.map(i => i.name).indexOf(this.$store.state.totalAnalysis.currentSubject)
+				let result = []
+				analysisJson.paper[curSubjectIndex].Value.forEach((exercise,exerciseIndex) => {
+					let obj = {}
+					analysisJson.paperKey.forEach((key, index) => {
+						obj[key] = exercise[index]
+					})
+					result.push(obj)
+				})
+				console.log(result)
+				return result
+			},
+			
+			doRender(analysisJson){
+				let exerciseList = this.renderData(analysisJson)
+				this.renderClassColumns(analysisJson)
+				this.exerciseIndexList = exerciseList.map(item => item.id)
+				this.A1List = exerciseList.filter(item => item.areaName === 'A')
+				this.A2List = exerciseList.filter(item => item.areaName === 'A-')
+				this.B1List = exerciseList.filter(item => item.areaName === 'B')
+				this.B2List = exerciseList.filter(item => item.areaName === 'B-')
+				this.tableData = JSON.parse(JSON.stringify(exerciseList))
+				this.getScatterData()
+				console.log('最新试题数据',this.tableData)
+			},
+			
+			getScatterData(){
+				let analysisJson = JSON.parse(JSON.stringify(this.getAnalysisJson))
+				let curSubjectIndex = analysisJson.subjects.map(i => i.name).indexOf(this.$store.state.totalAnalysis.currentSubject)
+				let result = []
+				analysisJson.paper[curSubjectIndex].Value.forEach((exercise, exerciseIndex) => {
+					let obj = {}
+					analysisJson.paperKey.forEach((key, index) => {
+						obj[key] = exercise[index]
+					})
+					result.push(obj)
+				})
+				let arr = result
+				let newArr = []
+				arr.forEach(item => {
+					let arr2 = []
+					arr2.push((item.X * 100).toFixed(2))
+					arr2.push((item.Y * 100).toFixed(2))
+					arr2.push(item.type)
+					arr2.push(item.id)
+					newArr.push(arr2)
+				})
+				this.scatterData = newArr
+			},
+			
+			getLineBarData(){
+				
+			}
         },
 
         mounted() {
             this.$refs.analysisTable.$el.childNodes[1].style.borderRight = '0'
             this.handleItemClick({ data: [1] })
-
-            let list = this.getExerciseData
-            if (list) {
-                this.renderClassColumns(this.$store.state.totalAnalysis.classExerciseData)
-                this.exerciseIndexList = list.map(item => item.id)
-                this.A1List = list.filter(item => item.areaName === 'A')
-                this.A2List = list.filter(item => item.areaName === 'A-')
-                this.B1List = list.filter(item => item.areaName === 'B')
-                this.B2List = list.filter(item => item.areaName === 'B-')
-                this.tableData = JSON.parse(JSON.stringify(list))
-            }
+			this.getAnalysisJson && this.doRender(this.getAnalysisJson)
+			
+			this.$EventBus.$off('onSubjectChange')
+			this.$EventBus.$on('onSubjectChange',val => {
+				this.doRender(this.getAnalysisJson)
+				this.$refs.lineBar.renderData(this.getAnalysisJson)
+			})
         },
         computed: {
             // 获取最新试题分析模块数据
-            getExerciseData() {
-                return this.$store.state.totalAnalysis.exerciseData
-            }
-        },
-        watch: {
-            // 渲染最新试题统计数据
-            getExerciseData(val) {
-                if (!val) return
-                this.renderClassColumns(this.$store.state.totalAnalysis.classExerciseData)
-                this.exerciseIndexList = val.map(item => item.id)
-                this.A1List = val.filter(item => item.areaName === 'A')
-                this.A2List = val.filter(item => item.areaName === 'A-')
-                this.B1List = val.filter(item => item.areaName === 'B')
-                this.B2List = val.filter(item => item.areaName === 'B-')
-                this.tableData = JSON.parse(JSON.stringify(val))
+            getAnalysisJson() {
+                return this.$store.state.totalAnalysis.analysisJson
             }
         }
     }

+ 37 - 60
TEAMModelOS/ClientApp/src/view/student-analysis/total-analysis/index.vue

@@ -22,19 +22,19 @@
 					</div>
                     <div class="basic-info" v-if="!isShowEvaluations && currentExamItem.name">
                         <p>
-                            <span class="info-type" :style="{color:colorTransfer[currentExamItem.conditions.range] || 'red',borderColor:colorTransfer[currentExamItem.conditions.range]|| 'red'}">{{currentExamItem.conditions.range}}</span>
+                            <span class="info-type" :style="{color:colorTransfer[currentExamItem.type] || 'red',borderColor:colorTransfer[currentExamItem.type]|| 'red'}">{{currentExamItem.type}}</span>
                             <span class="info-name">{{currentExamItem.name}}</span>
-                            <span class="info-grade">{{currentExamItem.conditions.period + currentExamItem.conditions.grade}}</span>
-                            <span class="info-subject" v-for="(subject,index) in currentExamItem.conditions.subject" :key="index">{{subject.substr(0,1)}}</span>
+                            <span class="info-grade">{{currentExamItem.period.name}}</span>
+                            <span class="info-subject" v-for="(subject,index) in currentExamItem.subjects" :key="index">{{subject.name}}</span>
                         </p>
                         <p class="info-date-person">
                             <!--<span class="info-person">{{$t('totalAnalysis.text7')}}:<span style="color:#fff">{{currentExamItem.stuCount}}人</span></span>-->
                             <!--<span class="info-date">{{$t('totalAnalysis.text8')}}:<span style="color:#fff">{{currentExamItem.time || '2019-02-11'}}</span></span>-->
                             <span class="info-item">{{$t('totalAnalysis.echarts_text11')}}: <span style="color:#fff;font-weight:bold">{{ $tools.formatTime(currentExamItem.startTime,'yyyy-MM-dd')}}</span></span>
                             <span class="info-item">{{$t('totalAnalysis.echarts_text12')}}: <span style="color:#fff;font-weight:bold">{{currentExamItem.stuCount}}</span></span>
-                            <span class="info-item">{{$t('totalAnalysis.echarts_text13')}}: <span style="color:#fff;font-weight:bold">{{currentExamItem.realCount}}</span></span>
+                            <span class="info-item">{{$t('totalAnalysis.echarts_text13')}}: <span style="color:#fff;font-weight:bold">{{currentExamItem.stuCount || 0}}</span></span>
                             <span class="info-item">{{$t('totalAnalysis.echarts_text14')}}: <span style="color:#fff;font-weight:bold">{{getJoinRate}}</span></span>
-                            <span class="info-item">{{$t('totalAnalysis.echarts_text15')}}: <span style="color:#fff;font-weight:bold">{{currentExamItem.piont.toFixed(2)}}</span></span>
+                            <span class="info-item">{{$t('totalAnalysis.echarts_text15')}}: <span style="color:#fff;font-weight:bold">{{currentExamItem.stuCount}}</span></span>
                         </p>
                         <!-- <div class="basic-tools">
                             <span class="basic-tool-export" @click="handleExportTables"> {{$t('totalAnalysis.exportTable')}} <Icon type="md-archive" /></span>
@@ -52,7 +52,7 @@
                         <span style="float:right;margin-bottom:4px;" v-show="dataSelectIndex !== '0'">
                             <span class="select-title">{{$t('totalAnalysis.currentSubject')}}:</span>
                             <Select v-model="subjectSelectVal" style="width:150px" @on-change="handleSubjectChange">
-                                <Option v-for="(item,index) in subjectSplitList" :value="item" :key="index" :label="item"></Option>
+                                <Option v-for="(item,index) in getSubjectList" :value="item" :key="index" :label="item"></Option>
                             </Select>
                         </span>
                     </div>
@@ -109,9 +109,9 @@
                 subjectList: [],
 				examList:[],
                 colorTransfer: {
-                    '校级测验': '#fbd103',
-                    '诊断测验': '#baecff',
-                    '全国测验': '#00ff8a'
+                    'regular': '#fbd103',
+                    'simulation': '#baecff',
+                    'normal': '#00ff8a'
                 },
                 scrollTopssss: 0
             }
@@ -122,9 +122,9 @@
 			// }else{
 			// 	this.examList = await this.getExamList()
 			// }
-			this.$store.dispatch('getAnalysisJson').then(res => {
-			    console.log(res)
-			})
+			// this.$store.dispatch('getAnalysisJson').then(res => {
+			//     console.log(res)
+			// })
         },
 
         methods: {
@@ -143,14 +143,14 @@
 						if(!vuexAchievement){
 							this.$store.commit('updateCurExam', this.currentExamItem)
 						}
-                        this.$store.dispatch('getAchievementData').then(res => {
-                            setTimeout(function() {
-                                that.dataLoading = false
-                            }, 800)
-                        }).catch(err => {
-							this.$Message.error('分析数据读取异常!')
-							this.dataLoading = false
-						})
+      //                   this.$store.dispatch('getAchievementData').then(res => {
+      //                       setTimeout(function() {
+      //                           that.dataLoading = false
+      //                       }, 800)
+      //                   }).catch(err => {
+						// 	this.$Message.error('分析数据读取异常!')
+						// 	this.dataLoading = false
+						// })
                         this.$store.commit('updateExportTable', [{
                             tableRef: 'entryTable',
                             tableName:'进线情况统计'
@@ -165,11 +165,6 @@
                         break
                     case 1:
                         path = '/total/scatter'
-                        this.$store.dispatch('getScatterData').then(res => {
-                            setTimeout(function() {
-                                that.dataLoading = false
-                            }, 800)
-                        })
                         this.$store.commit('updateExportTable', [{
                             tableRef: 'scatterTable',
                             tableName:'学生稳定度统计表'
@@ -177,11 +172,6 @@
                         break
                     case 2:
                         path = '/total/test'
-                        this.$store.dispatch('getExerciseData').then(res => {
-                            setTimeout(function() {
-                                that.dataLoading = false
-                            }, 800)
-                        })
                         this.$store.commit('updateExportTable', [{
                             tableRef: 'exerciseAnalsisTable',
                             tableName:'试题分析总表'
@@ -192,11 +182,6 @@
                         break
                     case 3:
                         path = '/total/knowledge'
-                        this.$store.dispatch('getKnowledgeData').then(res => {
-                            setTimeout(function() {
-                                that.dataLoading = false
-                            }, 800)
-                        })
                         this.$store.commit('updateExportTable', [{
                             tableRef: 'pointScoreRateTable',
                             tableName:'知识点得分率关系表'
@@ -210,11 +195,6 @@
                         break
                     case 4:
                         path = '/total/cognitionLevel'
-                        this.$store.dispatch('getLevelData').then(res => {
-                            setTimeout(function() {
-                                that.dataLoading = false
-                            }, 800)
-                        })
                         this.$store.commit('updateExportTable', [{
                             tableRef: 'levelScoreRateTable',
                             tableName:'认知层次得分率关系表'
@@ -229,7 +209,7 @@
                     default:
                         break
                 }
-
+				that.dataLoading = false
                 this.$router.push(path)
             },
 
@@ -338,18 +318,11 @@
             // 切换科目时更换页面图表数据
             handleSubjectChange(val) {
                 let that = this
-                this.dataLoading = true
+                // this.dataLoading = true
 				console.log('API===========================' + val)
                 this.$store.commit('updateCurSubject', val)
-                // this.$store.dispatch('getAchievementData')
-                this.$store.dispatch('getScatterData')
-                this.$store.dispatch('getExerciseData')
-                this.$store.dispatch('getLevelData')
-                this.$store.dispatch('getKnowledgeData').then(res => {
-                    setTimeout(function() {
-                        that.dataLoading = false
-                    }, 800)
-                })
+				this.$EventBus.$emit('onSubjectChange',val)
+                
             },
 
             // 判断容器滚动距离
@@ -394,9 +367,13 @@
 					// this.getExamData(examIndex)
 				}
 			})
+			
+			this.currentExamItem = JSON.parse(localStorage.getItem('curExam'))
+			console.log(this.currentExamItem)
         },
         computed: {
             getSubjectList() {
+				this.subjectSelectVal = this.$store.state.totalAnalysis.currentSubject
                 return this.$store.state.totalAnalysis.subjectList
             },
 			getVuexExamList() {
@@ -406,7 +383,7 @@
 			    return this.$store.state.totalAnalysis.exportTableParams
 			},
 			getJoinRate(){
-				return (this.currentExamItem.realCount / this.currentExamItem.stuCount).toFixed(2) * 100 + '%'
+				return (this.currentExamItem.stuCount / this.currentExamItem.stuCount).toFixed(2) * 100 + '%'
 			}
         },
         // 监听部分路由变化
@@ -419,14 +396,14 @@
                     this.$refs.examListRef.examIndex = to.query.index
                 }
             },
-            getSubjectList(val) {
-                console.log('科目列表变化为' + val)
-                console.log(this.subjectList)
-				console.log(this.$store.state.totalAnalysis.currentExam)
-                this.subjectList = val
-                this.subjectSelectVal = this.subjectList[0]
-                this.handleSubjectChange(this.subjectSelectVal)
-            },
+    //         getSubjectList(val) {
+    //             console.log('科目列表变化为' + val)
+    //             console.log(this.subjectList)
+				// console.log(this.$store.state.totalAnalysis.currentExam)
+    //             this.subjectList = val
+    //             this.subjectSelectVal = this.subjectList[0]
+    //             // this.handleSubjectChange(this.subjectSelectVal)
+    //         },
             getVuexExamList(val) {
 				console.log(val)
                 if(val.length){

+ 263 - 116
TEAMModelOS/Controllers/Analysis/AchievementController.cs

@@ -35,11 +35,13 @@ namespace TEAMModelOS.Controllers.Analysis
         private readonly Option _option;
         private const string CacheCosmosPrefix = "Analysis:";
         private const int timeoutSeconds = 3600;
-        public AchievementController(AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option)
+        public readonly AzureStorageFactory _azureStorage;
+        public AchievementController(AzureCosmosFactory azureCosmos, DingDing dingDing, IOptionsSnapshot<Option> option, AzureStorageFactory azureStorage)
         {
             _azureCosmos = azureCosmos;
             _dingDing = dingDing;
             _option = option?.Value;
+            _azureStorage = azureStorage;
 
 
         }
@@ -118,7 +120,8 @@ namespace TEAMModelOS.Controllers.Analysis
                 exams = await FindExamResultRedis(dict, "FindExamResultRedis");
             }*/
             List<string> subjectCouns = JsonExtensions.ToObject<List<string>>(subjectCode.ToJsonString());
-            for (int i =0;i < subjectCouns.Count;i++ ) {
+            for (int i = 0; i < subjectCouns.Count; i++)
+            {
                 if (RedisHelper.Exists(CacheCosmosPrefix + "examResult" + subjectCouns[i]))
                 {
                     ExamResultDto result = RedisHelper.HGet<ExamResultDto>(CacheCosmosPrefix + "examResult" + subjectCouns[i], ShaHashHelper.GetSHA1(code.ToString()));
@@ -578,7 +581,7 @@ namespace TEAMModelOS.Controllers.Analysis
             }*/
             return builder.build();
         }
-        
+
 
         [HttpPost("ExerciseScatter")]
         public async Task<BaseResponse> ExerciseScatter(JsonElement request)
@@ -606,9 +609,9 @@ namespace TEAMModelOS.Controllers.Analysis
                  info = await FindExerciseScatterRedis(dict, "ExerciseScatter");
                  builder.Data(info);
              }*/
-            return null ;
+            return null;
         }
-        
+
 
 
         public async Task<Dictionary<string, dynamic>> FindKnowledgePointRedis(Dictionary<string, object> dict, string method)
@@ -896,10 +899,11 @@ namespace TEAMModelOS.Controllers.Analysis
                         }
                         valuew[2] = itemNos[0..^1];
                     }
-                    else {
+                    else
+                    {
                         valuew[2] = itemNos;
                     }
-                    
+
                 });
                 int rhwC = 0;
                 int rhlC = 0;
@@ -1004,7 +1008,8 @@ namespace TEAMModelOS.Controllers.Analysis
                             values[4] = "0";
                             values[5] = "0";
                         }
-                        else {
+                        else
+                        {
                             double stuPser = anwPoint / po;
                             values[3] = po.ToString();
                             values[4] = anwPoint.ToString();
@@ -1022,11 +1027,12 @@ namespace TEAMModelOS.Controllers.Analysis
                 {
                     knowPer.Add("0");
                 }
-                else {
+                else
+                {
                     knowPser = anwGPoint / poG;
                     knowPer.Add(knowPser.ToString("0.00"));
                 }
-               
+
                 //错题关系表
                 valuew[3] = knowPser.ToString("0.00");
                 valuew[4] = wrongCount.ToString();
@@ -1089,11 +1095,12 @@ namespace TEAMModelOS.Controllers.Analysis
                         //double classPser = anwCPoint / cpo;
                         knowledgeClass.Add("0");
                     }
-                    else {
+                    else
+                    {
                         double classPser = anwCPoint / cpo;
                         knowledgeClass.Add(classPser.ToString("0.00"));
                     }
-                   
+
                 }
                 classMap.Add(knowledgeName[k], knowledgeClass);
                 per.Add(persent.ToString("0.00"));
@@ -1175,12 +1182,12 @@ namespace TEAMModelOS.Controllers.Analysis
                     /// RedisHelper.Instance.CurrentDeserialize = (json, type) => System.Text.Json.JsonSerializer.Deserialize(json, type);
                     List<ExamInfoDto> info = await RedisHelper.CacheShellAsync(CacheCosmosPrefix + "FindExamInfo",
                     ShaHashHelper.GetSHA1(dict.ToJsonString()), timeoutSeconds, () => { return FindExamInfoRedis(dict, "FindExamInfo"); });
-                 
+
                     builder.Data(info);
                 }
                 catch (Exception e)
                 {
-                  //  throw new BizException(e.Message);
+                    //  throw new BizException(e.Message);
                 }
             }
             else
@@ -1288,31 +1295,31 @@ namespace TEAMModelOS.Controllers.Analysis
 
             return builder.build();
         }
-       /* public async Task<List<Paper>> FindExamPaperRedis(Dictionary<string, object> dict, string method)
-        {
-            try
-            {
-                List<Paper> info = await _azureCosmos.FindByDict<Paper>(dict);
-                if (RedisHelper.Instance != null)
-                {
-                    if (!RedisHelper.Exists(CacheCosmosPrefix + method))
-                    {
-                        await RedisHelper.HSetAsync(CacheCosmosPrefix + method, ShaHashHelper.GetSHA1(dict.ToJsonString()), info);
-                    }
-                    else
-                    {
-                        await RedisHelper.HSetAsync(CacheCosmosPrefix + method, ShaHashHelper.GetSHA1(dict.ToJsonString()), info);
-                        await RedisHelper.ExpireAsync(CacheCosmosPrefix + method, timeoutSeconds);
-                    }
-                }
-                return info;
-            }
-            catch (Exception e)
-            {
-                throw new BizException(e.Message);
+        /* public async Task<List<Paper>> FindExamPaperRedis(Dictionary<string, object> dict, string method)
+         {
+             try
+             {
+                 List<Paper> info = await _azureCosmos.FindByDict<Paper>(dict);
+                 if (RedisHelper.Instance != null)
+                 {
+                     if (!RedisHelper.Exists(CacheCosmosPrefix + method))
+                     {
+                         await RedisHelper.HSetAsync(CacheCosmosPrefix + method, ShaHashHelper.GetSHA1(dict.ToJsonString()), info);
+                     }
+                     else
+                     {
+                         await RedisHelper.HSetAsync(CacheCosmosPrefix + method, ShaHashHelper.GetSHA1(dict.ToJsonString()), info);
+                         await RedisHelper.ExpireAsync(CacheCosmosPrefix + method, timeoutSeconds);
+                     }
+                 }
+                 return info;
+             }
+             catch (Exception e)
+             {
+                 throw new BizException(e.Message);
 
-            }
-        }*/
+             }
+         }*/
         [HttpPost("FindExamAnswer")]
         public BaseResponse FindExamAnswer(JsonElement request)
         {
@@ -1412,7 +1419,7 @@ namespace TEAMModelOS.Controllers.Analysis
         }
         public async Task<List<Dictionary<string, dynamic>>> FindHomeStatisticsRedis(Dictionary<string, object> dict, string method)
         {
-            return new  List<Dictionary<string, dynamic>>();
+            return new List<Dictionary<string, dynamic>>();
             //request.@params.TryGetValue("subjectCode", out object subjectCode);
             //   dict.TryGetValue("schoolCode", out object schoolCode);
             //   dict.TryGetValue("code", out object code);
@@ -1796,11 +1803,13 @@ namespace TEAMModelOS.Controllers.Analysis
         }
 
         [HttpPost("getAnalysis")]
-        public async Task<IActionResult> getAnalysis(JsonElement request) {
+        public async Task<IActionResult> getAnalysis(JsonElement request)
+        {
             //获取评测的ID
             if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
             if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
-            try {
+            try
+            {
                 var client = _azureCosmos.GetCosmosClient();
                 //获取本次评测所有科目结算结果
                 ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{code}"));
@@ -1836,30 +1845,35 @@ namespace TEAMModelOS.Controllers.Analysis
                 }
                 //获取进线标准
                 int touch = 0;
-                foreach (Period period in school.period) {
-                    if (info.period.id.Equals(period.id)) {
+                foreach (Period period in school.period)
+                {
+                    if (info.period.id.Equals(period.id))
+                    {
                         touch = period.analysis.touch;
                     }
                 }
                 //获取进线人数
 
-                int personCount = (int)System.Math.Round( info.stuCount * (touch / 100.0), MidpointRounding.AwayFromZero);
-                
+                int personCount = (int)System.Math.Round(info.stuCount * (touch / 100.0), MidpointRounding.AwayFromZero);
+
                 StudentAnalysis analysis = new StudentAnalysis();
                 List<ClassAnalysis> classAnalyses = new List<ClassAnalysis>();
-               /* //声明年级所有科目总分
-                List<double> total = new List<double>();*/
+                /* //声明年级所有科目总分
+                 List<double> total = new List<double>();*/
                 //以班级为单位
                 List<double> stuTotals = new List<double>();
                 List<dynamic> classes = new List<dynamic>();
                 HashSet<string> idName = new HashSet<string>();
-                foreach (ExamResult examResult in examResults) {
-                    foreach (string ids in examResult.studentIds) {
+                foreach (ExamResult examResult in examResults)
+                {
+                    foreach (string ids in examResult.studentIds)
+                    {
                         idName.Add(ids);
                     }
                 }
-                foreach (string s in info.targetClassIds) {
-                   
+                foreach (string s in info.targetClassIds)
+                {
+
                     //存放每个班级学生总分
                     List<double> totalClass = new List<double>();
                     ClassAnalysis classAnalysis = new ClassAnalysis();
@@ -1869,17 +1883,18 @@ namespace TEAMModelOS.Controllers.Analysis
                     {
                         using var json = await JsonDocument.ParseAsync(sresponse.ContentStream);
                         Class classroom = json.ToObject<Class>();
-                        classes.Add(new {name=classroom.name,id=s });
+                        classes.Add(new { name = classroom.name, id = s });
                         //初始化参考人数
                         int count = 0;
-                        
+
                         foreach (StudentSimple stu in classroom.students)
                         {
                             if (idName.Contains(stu.id))
                             {
                                 count++;
                             }
-                            else {
+                            else
+                            {
                                 continue;
                             }
                             classAnalysis.studentIds.Add(stu.id);
@@ -1890,7 +1905,8 @@ namespace TEAMModelOS.Controllers.Analysis
                             foreach (ExamResult examResult in examResults)
                             {
                                 int index = examResult.studentIds.IndexOf(stu.id);
-                                if (index >= 0) {
+                                if (index >= 0)
+                                {
                                     stuTotal = stuTotal + examResult.studentScores[index].Sum();
                                 }
                             }
@@ -1904,7 +1920,8 @@ namespace TEAMModelOS.Controllers.Analysis
                     }
                     /* //声明单个班级单科总分
                      double subjectTotal = 0;*/
-                    info.subjects.ForEach(sub => {
+                    info.subjects.ForEach(sub =>
+                    {
                         //初始化及格人数
                         int i = 0;
                         //初始化单科总分
@@ -1951,8 +1968,8 @@ namespace TEAMModelOS.Controllers.Analysis
                                 double percentClass = i / (result.studentIds.Count * 1.0);
                                 double averageClass = sumClass / (result.studentIds.Count * 1.0);
                                 //total += averageClass;
-                                subjectScore.passPercent= percentClass;
-                                subjectScore.averageScore= averageClass;
+                                subjectScore.passPercent = percentClass;
+                                subjectScore.averageScore = averageClass;
                                 classAnalysis.subjects.Add(subjectScore);
                                 //analysis.scores.Add(score);
                             }
@@ -1986,18 +2003,21 @@ namespace TEAMModelOS.Controllers.Analysis
                 stuTotals.Sort(delegate (double s1, double s2) { return s2.CompareTo(s1); });
                 ipoint = stuTotals[personCount];
                 //补充班级总平均分/进行人数/标准差
-                foreach (ClassAnalysis classAnalysis in classAnalyses) {
+                foreach (ClassAnalysis classAnalysis in classAnalyses)
+                {
                     //初始化进线人数
                     int i = 0;
                     //初始化班级总分
                     double score = 0;
                     //标准差
                     double powSum = 0;
-                    foreach (double sc in classAnalysis.total) {
-                        if (sc > ipoint) {
+                    foreach (double sc in classAnalysis.total)
+                    {
+                        if (sc > ipoint)
+                        {
                             i++;
                         }
-                        score = score + sc;                       
+                        score = score + sc;
                     }
                     //总平均分
                     double totalAverage = 0;
@@ -2007,7 +2027,7 @@ namespace TEAMModelOS.Controllers.Analysis
                     {
                         powSum += Math.Pow(sc - totalAverage, 2);
                     }
-                    
+
                     var pow = Math.Pow(powSum / classAnalysis.stuCount, 0.5);
 
                     classAnalysis.standardDeviation = pow;
@@ -2015,9 +2035,10 @@ namespace TEAMModelOS.Controllers.Analysis
                     classAnalysis.lineCount = i;
                 }
                 //处理全科年级PR值
-                foreach (double no in analysis.total) {
+                foreach (double no in analysis.total)
+                {
                     int index = stuTotals.IndexOf(no);
-                    int GPR = 100 - (100 * (index+1) - 50) / analysis.total.Count;
+                    int GPR = 100 - (100 * (index + 1) - 50) / analysis.total.Count;
                     analysis.gpr.Add(GPR);
                 }
                 List<GradeAnalysis> gradeAnalyses = new List<GradeAnalysis>();
@@ -2037,12 +2058,14 @@ namespace TEAMModelOS.Controllers.Analysis
                 return BadRequest();
             }
 
-        
+
         }
-        private List<GradeAnalysis> GetGradeAnalyses(ExamInfo info, List<ExamResult> examResults, List<ExamClassResult> examClassResults,StudentAnalysis analysis) {
+        private List<GradeAnalysis> GetGradeAnalyses(ExamInfo info, List<ExamResult> examResults, List<ExamClassResult> examClassResults, StudentAnalysis analysis)
+        {
             List<GradeAnalysis> gradeAnalyses = new List<GradeAnalysis>();
-           
-            info.grades.ForEach(g => {
+
+            info.grades.ForEach(g =>
+            {
                 GradeAnalysis gradeAnalysis = new GradeAnalysis();
                 gradeAnalysis.gradeId = g.id;
                 //初始化单个年级总分
@@ -2074,8 +2097,10 @@ namespace TEAMModelOS.Controllers.Analysis
                     //存放单科每个班级学生总分
                     List<double> totalClass = new List<double>();
                     //存放学生单科记录
-                    foreach (Score score in analysis.scores) {
-                        if (score.subjectId.Equals(sub.id)) {
+                    foreach (Score score in analysis.scores)
+                    {
+                        if (score.subjectId.Equals(sub.id))
+                        {
                             //处理每个班级各个学生各科总分
                             foreach (ExamClassResult result in examClassResults)
                             {
@@ -2098,11 +2123,11 @@ namespace TEAMModelOS.Controllers.Analysis
                                 }
                             }
                             //处理班级及格率以及均分
-                            double persentClass = i / (count*1.0);
+                            double persentClass = i / (count * 1.0);
                             double averageClass = sumClass / (count * 1.0);
                             gradeScore += averageClass;
-                            subjectScore.passPercent= persentClass;
-                            subjectScore.averageScore= averageClass;
+                            subjectScore.passPercent = persentClass;
+                            subjectScore.averageScore = averageClass;
                             gradeAnalysis.subjects.Add(subjectScore);
                             gradeAnalyses.Add(gradeAnalysis);
                             //处理单科科年级PR
@@ -2116,18 +2141,19 @@ namespace TEAMModelOS.Controllers.Analysis
                             }
                             //analysis.scores.Add(score);
                         }
-                    }                                                  
+                    }
                 });
-                foreach (GradeAnalysis grade in gradeAnalyses) {
+                foreach (GradeAnalysis grade in gradeAnalyses)
+                {
                     grade.GradeaverageScore = gradeScore / grade.subjects.Count;
                 }
-                });
+            });
             return gradeAnalyses;
-            }
+        }
 
 
         //落点分析
-        private List<Dictionary<string, dynamic>> getPointAnalysis(List<ExamResult> exams,ExamInfo exam)
+        private List<Dictionary<string, dynamic>> getPointAnalysis(List<ExamResult> exams, ExamInfo exam)
         {
             List<Dictionary<string, dynamic>> scatterAnalysis = new List<Dictionary<string, dynamic>>();
             List<string> key = new List<string>
@@ -2147,10 +2173,10 @@ namespace TEAMModelOS.Controllers.Analysis
             //key.Add("areaName");
             if (exams.Count > 0)
             {
-               /* //提取班级信息
-                List<Dictionary<string, int[]>> classToName = exams[0].classes;
-                //提取学生ID信息
-                List<string> idToName = exams[0].ids;*/
+                /* //提取班级信息
+                 List<Dictionary<string, int[]>> classToName = exams[0].classes;
+                 //提取学生ID信息
+                 List<string> idToName = exams[0].ids;*/
                 exams.ForEach(e =>
                 {
                     Dictionary<string, object> detail = new Dictionary<string, object>
@@ -2261,7 +2287,7 @@ namespace TEAMModelOS.Controllers.Analysis
                         Console.WriteLine("---------------------" + ex.Message + "--------------------------");
                     }
 
-                });              
+                });
                 return scatterAnalysis;
             }
             else return scatterAnalysis;
@@ -2270,7 +2296,7 @@ namespace TEAMModelOS.Controllers.Analysis
 
         private List<Dictionary<string, dynamic>> getExerciseScatter(List<ExamResult> exams, ExamInfo exam)
         {
-           /* ResponseBuilder builder = ResponseBuilder.custom();*/
+            /* ResponseBuilder builder = ResponseBuilder.custom();*/
             List<string> classList = new List<string>();
             List<Dictionary<string, object>> exerciseScatter = new List<Dictionary<string, object>>();
             //Dictionary<string, object> scatterAnalysis = new Dictionary<string, object>();
@@ -2320,10 +2346,10 @@ namespace TEAMModelOS.Controllers.Analysis
                             Qnum++;
                         }
                     });
-                   /* Dictionary<string, object> detail = new Dictionary<string, object>
-                    {
-                        { "keys", key }
-                    };*/
+                    /* Dictionary<string, object> detail = new Dictionary<string, object>
+                     {
+                         { "keys", key }
+                     };*/
                     List<List<string>> datas = new List<List<string>>();
                     List<string[]> itemAnalysis = new List<string[]>();
                     Dictionary<string, object> subject = new Dictionary<string, object>
@@ -2346,37 +2372,37 @@ namespace TEAMModelOS.Controllers.Analysis
                             }
                             int qCount = 0;
                             //int right = 0;
-/*                            //c.Keys遍历key值
-                            foreach (string keys in c.Keys)
-                            {
-                                classList.Add(keys);
-                            }*/
+                            /*                            //c.Keys遍历key值
+                                                        foreach (string keys in c.Keys)
+                                                        {
+                                                            classList.Add(keys);
+                                                        }*/
                             //每个班级得分占比
 
-                                for (int i = c.range[0]; i <= c.range[1]; i++)
+                            for (int i = c.range[0]; i <= c.range[1]; i++)
+                            {
+                                if (e.studentScores[i].Sum() > 0)
                                 {
-                                    if (e.studentScores[i].Sum() > 0)
+                                    for (int j = 0; j < e.studentScores[i].Count; j++)
                                     {
-                                        for (int j = 0; j < e.studentScores[i].Count; j++)
+                                        if (e.studentScores[i][j] > 0)
                                         {
-                                            if (e.studentScores[i][j] > 0)
-                                            {
-                                                //记录班级每题得分数
-                                                answerCount[j] = answerCount[j] + 1;
-                                                //记录年级每题得分数
-                                                gradeAnswer[j] = gradeAnswer[j] + 1;
-
-                                                //right++;
-                                            }
+                                            //记录班级每题得分数
+                                            answerCount[j] = answerCount[j] + 1;
+                                            //记录年级每题得分数
+                                            gradeAnswer[j] = gradeAnswer[j] + 1;
+
+                                            //right++;
                                         }
                                     }
-                                    else
-                                    {
-                                        qCount++;
-                                    }
-
-                                    peopleCount = c.range[1] - c.range[0] + 1 - qCount;
                                 }
+                                else
+                                {
+                                    qCount++;
+                                }
+
+                                peopleCount = c.range[1] - c.range[0] + 1 - qCount;
+                            }
                             foreach (int p in answerCount)
                             {
                                 var t = Math.Floor(Math.Round(decimal.Parse((p * 1.0 / peopleCount).ToString("0.000")), 2) * 100);
@@ -2437,7 +2463,8 @@ namespace TEAMModelOS.Controllers.Analysis
                                 values[18] = itemAnalysis[k][8];
                                 values[19] = itemAnalysis[k][9];
                             }
-                            else {
+                            else
+                            {
                                 values[4] = "-";
                                 values[5] = "-";
                                 values[12] = "-";
@@ -2448,9 +2475,9 @@ namespace TEAMModelOS.Controllers.Analysis
                                 values[17] = "-";
                                 values[18] = "-";
                                 values[19] = "-";
-                            }                          
+                            }
                             values[7] = grasdepersent[k];
-                            values[8] = grasdepersent[k];                            
+                            values[8] = grasdepersent[k];
                             values[20] = quality[k].ToString();
                             values[21] = answer[k].ToString();
                             string pointName = "";
@@ -2483,10 +2510,130 @@ namespace TEAMModelOS.Controllers.Analysis
                         // throw new BizException(ex.Message);
                     }
 
-                });               
+                });
                 return exerciseScatter;
             }
             else return exerciseScatter;
         }
+
+        [HttpPost("point")]
+        public async Task<IActionResult> point(JsonElement request)
+        {
+            //获取评测的ID
+            if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
+            if (!request.TryGetProperty("code", out JsonElement code)) return BadRequest();
+            try
+            {
+                var client = _azureCosmos.GetCosmosClient();
+                //获取本次评测所有科目结算结果
+                ExamInfo info = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{code}"));
+                School school = await client.GetContainer("TEAMModelOS", "School").ReadItemAsync<School>(code.ToString(), new PartitionKey($"Base"));
+                List<ExamResult> examResults = new List<ExamResult>();
+                var query = $"select c.id,c.name,c.subjectId,c.studentScores,c.studentIds,c.paper,c.classes from c where c.examId =  '{id}' ";
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<ExamResult>(queryText: query, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamResult-{id}") }))
+                {
+                    /*using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            examResults.Add(obj.ToObject<ExamResult>());
+                        }
+                    }*/
+                    examResults.Add(item);
+                }
+                //获取本次评测所有班级作答结果
+                List<ExamClassResult> examClassResults = new List<ExamClassResult>();
+                var queryClass = $"select c.id,c.code,c.name,c.school,c.examId,c.year,c.scope,c.pk,c.subjectId,c.studentScores,c.studentIds,c.gradeId,c.info,c.studentAnswers,c.sum,c.progress from c where c.examId =  '{id}' ";
+                await foreach (var item in client.GetContainer("TEAMModelOS", "Common").GetItemQueryIterator<ExamClassResult>(queryText: queryClass, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ExamClassResult-{code}") }))
+                {
+                    examClassResults.Add(item);
+                    /*using var json = await JsonDocument.ParseAsync(item.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    {
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            examClassResults.Add(obj.ToObject<ExamClassResult>());
+                        }
+                    }*/
+                }
+                int m = 0;               
+                foreach (ExamSubject subject in info.subjects) {
+                    foreach (ExamClassResult classResult in examClassResults)
+                    {
+                        if (subject.id.Equals(classResult.subjectId)) {
+                            int k = 0;
+                            foreach (string stu in classResult.studentIds)
+                            {
+                                int n = 0;
+                                List<List<string>> ans = new List<List<string>>();
+                                foreach (List<string> simple in info.papers[m].answers) {
+                                    List<string> option = new List<string>();
+                                    if (simple.Count > 0)
+                                    {
+                                        List<string> opt = new  List<string>{ "A", "B", "C", "D" };
+                                        int rd=new Random().Next(0,3);
+                                        if (rd == 1 || rd == 2)
+                                        {
+                                            option.AddRange(simple);
+                                            classResult.studentScores[k][n] = info.papers[m].point[n];
+                                        }
+                                        else {
+                                            simple.ForEach(x => { opt.Remove(x); });
+                                            option.Add(opt[new Random().Next(0, opt.Count-1)]);
+                                            classResult.studentScores[k][n] = 0;
+                                        }
+                                        ans.Add(option);
+                                    }
+                                    else {
+                                        classResult.studentScores[k][n] = new Random().Next(0, (int)info.papers[m].point[n]) * 1.0; 
+                                    }                              
+                                    n++;
+                                }
+                                string FileName = classResult.examId + "/" + classResult.subjectId + "/" + stu;
+                                string blob = await _azureStorage.UploadFileByContainer(code.ToString(), ans.ToJsonString(), "exam", FileName + "/" + "ans.json");
+                                classResult.studentAnswers[k].Add(blob);
+                                classResult.sum[k] = classResult.studentScores[k].Sum();
+                                k++;   
+                            }
+                            //await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(classResult, classResult.id, new PartitionKey($"ExamClassResult-{code}"));
+                            bool flag = true;
+                            foreach (List<double> scores in classResult.studentScores)
+                            {
+                                foreach (double score in scores)
+                                {
+                                    if (score == -1)
+                                    {
+                                        flag = false;
+                                        break;
+                                    }
+                                }
+                            }
+                            if (flag)
+                            {
+                                //ExamInfo exam = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"Exam-{school}"));
+                                classResult.progress = true;
+/*                                info.subjects.ForEach(s =>
+                                {        
+                                    s.classCount += 1;
+                                });*/
+                                info.subjects[m].classCount += 1;
+                                
+                            }                           
+                            await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(classResult, classResult.id, new PartitionKey($"ExamClassResult-{code}"));
+                        }
+                        
+                    }
+                }
+                m++;
+                await client.GetContainer("TEAMModelOS", "Common").ReplaceItemAsync(info, id.ToString(), new PartitionKey($"Exam-{code}"));
+                return Ok(new { examClassResults });
+            }
+            catch (Exception e)
+            {
+                await _dingDing.SendBotMsg($"OS,{_option.Location},analysis/getAnalysis()\n{e.Message}", GroupNames.醍摩豆服務運維群組);
+                return BadRequest();
+            }
+        }
     }
 }

+ 1 - 1
TEAMModelOS/Controllers/School/ClassRoomController.cs

@@ -465,7 +465,7 @@ namespace TEAMModelOS.Controllers
             }
             catch (Exception ex)
             {
-                await _dingDing.SendBotMsg($"OS,{_option.Location},class/Delete()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
+                await _dingDing.SendBotMsg($"OS,{_option.Location},class/name()\n{ex.Message}", GroupNames.醍摩豆服務運維群組);
                 return BadRequest();
             }
         }