Bläddra i källkod

Merge branch 'master' of https://git.cocorobo.cn/jack/PPT

lsc 1 dag sedan
förälder
incheckning
3b614a71a5
1 ändrade filer med 206 tillägg och 18 borttagningar
  1. 206 18
      src/views/Student/components/ChoiceStatistics.vue

+ 206 - 18
src/views/Student/components/ChoiceStatistics.vue

@@ -6,13 +6,45 @@
         总提交:{{ statistics.totalSubmissions }} 人
       </div>
       <div class="statistics-chart">
-        <div v-for="option in statistics.options" :key="option" class="statistics-item">
+				<div class="tool45" v-if="statistics.tool=='45'">
+					<div v-for="(item,index) in statistics.titles" :key="index">
+						<div class="t45_title">
+							<span>{{ index+1 }}、</span>
+							<div>{{ item.title }}</div>
+						</div>
+						<div class="t45_list">
+							<div class="t45_l_item" v-for="(i,index2) in item.checkList" :key="index+'_'+index2">
+								<div class="t45_l_i_option">
+									<span>{{ i.index }}:</span>
+									<div>
+										<div :style="{width:i.proportion}"></div>
+									</div>
+									<span>{{ i.proportion }}</span>
+								</div>
+								<div class="t45_l_i_user">
+									<template v-for="(j,index3) in i.user" :key="index+'_'+index2+'_'+index3">
+										<div  v-if="item.showAllUser || (!item.showAllUser && index3 < 3)">
+											<span>{{ j }}</span>
+										</div>
+									</template>
+									<span class="t45_o_btn" v-if="i.user.length > 3 && !item.showAllUser" @click="()=>{item.showAllUser = true,$forceUpdate()}">
+										<svg t="1756278651830" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7545" width="200" height="200"><path d="M293.546667 253.013333l264.533333 266.666667-264.106667 266.24 70.4 70.826667 334.506667-337.066667-334.933333-337.066667z" p-id="7546"></path></svg>
+									</span>
+									<span class="t45_o_btn" v-if="i.user.length > 3 && item.showAllUser" @click="()=>{item.showAllUser = false,$forceUpdate()}">
+										<svg style="transform: rotate(180deg);" t="1756278651830" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7545" width="200" height="200"><path d="M293.546667 253.013333l264.533333 266.666667-264.106667 266.24 70.4 70.826667 334.506667-337.066667-334.933333-337.066667z" p-id="7546"></path></svg>
+									</span>
+								</div>
+							</div>
+						</div>
+					</div>
+				</div>
+        <!-- <div v-for="option in statistics.options" :key="option" class="statistics-item">
           <div class="option-label">{{ option }}</div>
           <div class="option-bar">
             <div class="option-fill" :style="{ width: (statistics.stats[option] / statistics.totalSubmissions * 100) + '%' }"></div>
           </div>
           <div class="option-count">{{ statistics.stats[option] }}人</div>
-        </div>
+        </div> -->
       </div>
     </div>
     <div v-else class="statistics-empty">
@@ -39,32 +71,89 @@ const isChoiceQuestion = computed(() => {
   return frame?.toolType === 45
 })
 
+const optionList: Array<string> = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
+
+
+
 // 选择题统计信息
 const statistics = computed(() => {
   if (!isChoiceQuestion.value || !props.workArray || props.workArray.length === 0) return null
-  
-  // 统计每个选项的选择人数
-  const stats: { [key: string]: number } = {}
+
+  // 统计信息结构优化
+  let titles: Array<{
+    title: string,
+		showAllUser: boolean,
+    checkList: Array<{ options: string, num: number, proportion: string, index :string, user: Array<[]>}>
+  }> = []
   let totalSubmissions = 0
-  
-  props.workArray.forEach(work => {
-    if (work.content) {
-      try {
-        // const content = typeof work.content === 'string' ? JSON.parse(work.content) : work.content
-        // const choice = content.choice || content.answer || content.selected || '未知'
-        // stats[choice] = (stats[choice] || 0) + 1
+
+  let tool: string = ''
+
+  // 只初始化一次题目结构
+  let isTitleInitialized = false
+
+  props.workArray.forEach((work) => {
+    if (!work.content) return
+    try {
+      if (work.atool === '45') {
+        const content = JSON.parse(decodeURIComponent(work.content))
+        const testJson = content.testJson
+
+        // 初始化题目结构
+        if (!isTitleInitialized && Array.isArray(testJson)) {
+          tool = work.atool
+          titles = testJson.map((item: any) => ({
+            title: item.teststitle || '',
+            showAllUser: false,
+            checkList: Array.isArray(item.checkList)
+              ? item.checkList.map((i: any) => ({ options: i, num: 0, user: [], proportion: '', index: '' }))
+              : []
+          }))
+          isTitleInitialized = true
+        }
+
+        // 统计每道题的选项被选择次数
+        if (Array.isArray(titles) && Array.isArray(testJson)) {
+          testJson.forEach((item: any, index: number) => {
+            const answer = item.userAnswer
+            if (typeof answer === 'number') {
+              if (titles[index] && titles[index].checkList[answer]) {
+                titles[index].checkList[answer].num += 1
+                titles[index].checkList[answer].user.push(work.name)
+              }
+            } 
+            else if (Array.isArray(answer) && answer.length > 0) {
+              answer.forEach((i: number) => {
+                if (titles[index] && titles[index].checkList[i]) {
+                  titles[index].checkList[i].num += 1
+                  titles[index].checkList[i].user.push(work.name)
+                }
+              })
+            }
+          })
+        }
         totalSubmissions++
       }
-      catch (e) {
-        console.log('解析选择题答案失败:', work.content)
-      }
+    } 
+    catch (e) {
+      // eslint-disable-next-line no-console
+      console.log('解析选择题答案失败:', e, work.content)
     }
   })
-  
+
+  titles.forEach((item: any) => {
+    const total = item.checkList.reduce((sum: number, cur: any) => sum + cur.num, 0)
+    item.checkList.forEach((option: any, index :number) => {
+      option.proportion = total > 0 ? ((option.num / total) * 100).toFixed(1) + '%' : '0.0%'
+      option.index = optionList[index]
+    })
+  })
+
+  // 返回结构优化,便于前端展示
   return {
     totalSubmissions,
-    stats,
-    options: Object.keys(stats)
+    titles,
+    tool
   }
 })
 </script>
@@ -147,4 +236,103 @@ const statistics = computed(() => {
   color: #999;
   font-size: 14px;
 }
+
+.tool45{
+	width: 100%;
+	height: auto;
+	&>div{
+		width: 100%;
+		height: auto;
+		margin-bottom: 20px;
+		.t45_title{
+			width: 100%;
+			display: flex;
+			align-items: center;
+			margin-bottom: 5px;
+			span{
+				font-size: 16px;
+				color: #1890ff;
+			}
+		}
+	}
+	.t45_list{
+		width: 100%;
+		height: auto;
+		.t45_l_item{
+			
+			margin-top: 5px;
+			.t45_l_i_option{
+				display: flex;
+				align-items: center;
+				height: auto;
+				width: 100%;
+				justify-content: space-between;
+				span{
+					display: flex;
+					width: 40px;
+					&:nth-of-type(1){
+						width: 20px;
+					}
+				}
+				&>div{
+					margin: 0 5px;
+					width: calc(100% - 10px - 20px - 40px);
+					height: 15px;
+					background-color: #FFFFFF;
+					// box-sizing: border-box;
+					border: solid 1px #E9ECEF;
+					border-radius: 4px;
+					overflow: hidden;
+					&>div{
+						height: 100%;
+						background-color: #3681FC;
+					}
+				}
+			}
+			.t45_l_i_user{
+				width: 100%;
+				height: auto;
+				display: flex;
+				align-items: center;
+				flex-wrap: wrap;
+				margin-top: 8px;
+				margin-bottom: 8px;
+				&>div{
+					align-items: center;
+					flex-wrap: wrap;
+					height: 35px;
+					span{
+						width: auto;
+						height: auto;
+						padding: 4px 10px;
+						background-color: #fff;
+						border: solid 1px #2f80ed;
+						border-radius: 6px;
+						margin-right:8px ;
+						margin-bottom: 5px;
+						color: #2f80ed;
+					}
+				}
+				&>span{
+					width: auto;
+					height: auto;
+					padding: 4px 10px;
+					background-color: #fff;
+					border: solid 1px #E9ECEF;
+					border-radius: 6px;
+					margin-right:8px;
+					cursor: pointer;
+					transition: .2s;
+					&:hover{
+						background-color: #f1f1f1;
+					}
+					svg{
+						width: 15px;
+						height: 15px;
+					}
+				}
+			}
+		}
+	}
+}
 </style>