CzRger 2 months ago
parent
commit
611908d117

+ 1 - 1
src/App.vue

@@ -1,7 +1,7 @@
 <template>
   <div style="overflow: hidden; width: 100%; height: 100%">
     <el-config-provider :locale="zhCn">
-      <router-view />
+      <router-view :key="$route.name" />
     </el-config-provider>
   </div>
 </template>

+ 27 - 0
src/api/modules/study/index.ts

@@ -51,3 +51,30 @@ export const trainingCampQuestionTypeIpadGetKnowledgeMasteryStats = (
     {},
     {},
   )
+// 练习完成度
+export const trainingCampQuestionTypeIpadGetExerciseCompletionStats = (
+  category,
+  subject,
+) =>
+  get(
+    `/trainingCamp/questionType/ipad/getExerciseCompletionStats/${category}/${subject}`,
+    {},
+    {},
+  )
+// 板块统计
+export const trainingCampQuestionTypeIpadGetSectionImprovementStats = (
+  category,
+  subject,
+) =>
+  get(
+    `/trainingCamp/questionType/ipad/getSectionImprovementStats/${category}/${subject}`,
+    {},
+    {},
+  )
+// 历史做题记录
+export const trainingCampPaperQuestionRelIpadHistoryRecords = (questionId) =>
+  get(
+    `/trainingCamp/paperQuestionRel/ipad/historyRecords/${questionId}`,
+    {},
+    {},
+  )

+ 13 - 0
src/stores/modules/app.ts

@@ -66,9 +66,22 @@ export const useAppStore = defineStore('app', {
                         root: menu1.name,
                       },
                     }
+                    const menu4 = {
+                      path: menu1.path + '/error',
+                      name: menu1.name + 'error',
+                      component: () =>
+                        import('@/views/study/subject/question/error.vue'),
+                      meta: {
+                        subjectId: su.subjectId,
+                        res: su,
+                        title: su.subject,
+                        root: menu1.name,
+                      },
+                    }
                     categoryMenus.push(menu1)
                     categoryMenus.push(menu2)
                     categoryMenus.push(menu3)
+                    categoryMenus.push(menu4)
                   })
                   this.subjectMap = map
                   categoryMenus.forEach((v) => {

+ 4 - 17
src/views/global/login/index.vue

@@ -118,9 +118,8 @@
 <script setup lang="ts">
 import { onMounted, reactive, ref } from 'vue'
 import { useRouter } from 'vue-router'
-import { Notify } from 'quasar'
 import { authCode, authLogin } from '@/api/modules/global'
-import axios from 'axios'
+import { ElMessage } from 'element-plus'
 
 const router = useRouter()
 const state: any = reactive({
@@ -155,11 +154,7 @@ const onLogin = () => {
         authLogin(state.form)
           .then(({ code, msg, data }: any) => {
             if (code === 200) {
-              Notify.create({
-                message: '登录成功!',
-                position: 'top',
-                type: 'success',
-              })
+              ElMessage.success('登录成功!')
               localStorage.setItem(
                 (import.meta as any).env.VITE_TOKEN,
                 'Bearer ' + data.access_token,
@@ -169,11 +164,7 @@ const onLogin = () => {
               state.loading = false
             } else {
               initCode()
-              Notify.create({
-                message: msg,
-                position: 'top',
-                type: 'error',
-              })
+              ElMessage.error(msg)
             }
           })
           .catch(() => {})
@@ -182,11 +173,7 @@ const onLogin = () => {
           })
       })
       .catch((e) => {
-        Notify.create({
-          message: e[0].message,
-          position: 'top',
-          type: 'warning',
-        })
+        ElMessage.warning(e[0].message)
       })
   }
 }

+ 2 - 8
src/views/study/components/study-layout.vue

@@ -122,9 +122,7 @@
 <script setup lang="ts">
 import { computed, onMounted, reactive } from 'vue'
 import { useRouter } from 'vue-router'
-import { Plus } from '@element-plus/icons-vue'
-import { Notify } from 'quasar'
-import { ElMessageBox } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
 import { authLogout } from '@/api/modules/global'
 import { useAppStore, useDictionaryStore } from '@/stores'
 
@@ -194,11 +192,7 @@ const handleAvatarSuccess = (response, uploadFile) => {
 
 const beforeAvatarUpload = (rawFile) => {
   if (rawFile.type !== 'image/jpeg') {
-    Notify.create({
-      message: '头像格式错误!',
-      position: 'top',
-      type: 'warning',
-    })
+    ElMessage.warning('头像格式错误!')
     return false
   } else if (rawFile.size / 1024 / 1024 > 2) {
     // ElMessage.error('Avatar picture size can not exceed 2MB!')

+ 42 - 13
src/views/study/subject/index.vue

@@ -87,25 +87,33 @@
               class="stat-card rounded-lg border-l-4 border-[var(--czr-main-color)] bg-gray-50 p-3"
             >
               <div class="text-xs text-gray-500">当前难度等级</div>
-              <div class="mt-1 text-xl font-bold text-gray-800">S</div>
+              <div class="mt-1 text-xl font-bold text-gray-800">
+                {{ state.statistic.card.data.level }}
+              </div>
             </div>
             <div
               class="stat-card rounded-lg border-l-4 border-[var(--czr-main-color)] bg-gray-50 p-3"
             >
               <div class="text-xs text-gray-500">正确率</div>
-              <div class="mt-1 text-xl font-bold text-gray-800">85%</div>
+              <div class="mt-1 text-xl font-bold text-gray-800">
+                {{ state.statistic.card.data.totalAccuracyRate }}
+              </div>
             </div>
             <div
               class="stat-card rounded-lg border-l-4 border-[var(--czr-main-color)] bg-gray-50 p-3"
             >
               <div class="text-xs text-gray-500">待提升板块</div>
-              <div class="mt-1 text-xl font-bold text-gray-800">文言文</div>
+              <div class="mt-1 text-sm font-bold text-gray-800">
+                {{ state.statistic.card.data.maxIncorrectSections }}
+              </div>
             </div>
             <div
               class="stat-card rounded-lg border-l-4 border-[var(--czr-main-color)] bg-gray-50 p-3"
             >
               <div class="text-xs text-gray-500">优秀板块</div>
-              <div class="mt-1 text-xl font-bold text-gray-800">作文</div>
+              <div class="mt-1 text-sm font-bold text-gray-800">
+                {{ state.statistic.card.data.maxCorrectSections }}
+              </div>
             </div>
           </div>
 
@@ -349,10 +357,7 @@
                 class="subject-questions-btn bg-subject-color ml-auto flex items-center rounded-full px-3 py-1 text-sm"
                 @click="
                   $router.push({
-                    name: $route.meta.subjectId + 'plan',
-                    query: {
-                      onlyError: true,
-                    },
+                    name: $route.meta.subjectId + 'error',
                   })
                 "
               >
@@ -430,7 +435,9 @@ import chart3 from './chart-3.vue'
 import chart4 from './chart-4.vue'
 import {
   trainingCampLearningPlanList,
+  trainingCampQuestionTypeIpadGetExerciseCompletionStats,
   trainingCampQuestionTypeIpadGetKnowledgeMasteryStats,
+  trainingCampQuestionTypeIpadGetSectionImprovementStats,
   trainingCampQuestionTypeIpadGetWrongStatInfo,
 } from '@/api/modules/study'
 import { oneDayTime, YM, YMD } from '@/utils/czr-util'
@@ -468,6 +475,7 @@ const state: any = reactive({
     },
     card: {
       loading: false,
+      data: {},
     },
   },
   error: {
@@ -552,6 +560,17 @@ const initTraining = () => {
     })
 }
 const initStatistic = () => {
+  state.statistic.radar.loading = true
+  trainingCampQuestionTypeIpadGetKnowledgeMasteryStats(
+    AppStore.studentInfo?.grade,
+    route.meta.subjectId,
+  )
+    .then(({ data }: any) => {
+      state.statistic.radar.data = data
+    })
+    .finally(() => {
+      state.statistic.radar.loading = false
+    })
   state.statistic.line.loading = true
   trainingCampLearningPlanList({
     pageNum: 1,
@@ -570,17 +589,27 @@ const initStatistic = () => {
     .finally(() => {
       state.statistic.line.loading = false
     })
-
-  state.statistic.radar.loading = true
-  trainingCampQuestionTypeIpadGetKnowledgeMasteryStats(
+  state.statistic.bar.loading = true
+  trainingCampQuestionTypeIpadGetExerciseCompletionStats(
     AppStore.studentInfo?.grade,
     route.meta.subjectId,
   )
     .then(({ data }: any) => {
-      state.statistic.radar.data = data
+      state.statistic.bar.data = data
     })
     .finally(() => {
-      state.statistic.radar.loading = false
+      state.statistic.bar.loading = false
+    })
+  state.statistic.card.loading = true
+  trainingCampQuestionTypeIpadGetSectionImprovementStats(
+    AppStore.studentInfo?.grade,
+    route.meta.subjectId,
+  )
+    .then(({ data }: any) => {
+      state.statistic.card.data = data
+    })
+    .finally(() => {
+      state.statistic.card.loading = false
     })
 }
 const initError = () => {

+ 103 - 0
src/views/study/subject/question/error.vue

@@ -0,0 +1,103 @@
+<template>
+  <StudyLayout>
+    <div class="grid h-full w-full grid-cols-4 gap-6 overflow-hidden p-6">
+      <div
+        class="col-span-4 flex h-full flex-col overflow-hidden rounded-xl bg-white shadow-md"
+      >
+        <div class="bg-[var(--czr-main-sub-color)] p-4 text-white">
+          <div class="relative flex items-center text-xl font-bold">
+            <i class="fas fa-book mr-2"></i>
+            题目列表
+            <span class="text-base"> (共{{ state.question.total }}题) </span>
+          </div>
+        </div>
+        <div
+          class="flex-1 overflow-y-auto p-4"
+          id="questionsContainer"
+          v-loading="state.question.loading"
+        >
+          <template v-if="state.question.data?.length > 0">
+            <listCom :data="state.question.data" />
+            <!-- 分页控件 -->
+            <div class="mt-6 flex justify-center">
+              <div class="q-pa-lg flex-center flex">
+                <q-pagination
+                  v-model="state.question.page"
+                  :max="
+                    Math.ceil(state.question.data.length / state.question.size)
+                  "
+                  :max-pages="6"
+                  boundary-numbers
+                />
+              </div>
+            </div>
+          </template>
+          <template v-else>
+            <div
+              class="flex size-full items-center justify-center text-xl font-semibold text-gray-700"
+            >
+              暂无数据
+            </div>
+          </template>
+        </div>
+      </div>
+    </div>
+  </StudyLayout>
+</template>
+
+<script setup lang="ts">
+import { computed, onBeforeMount, onMounted, reactive, ref } from 'vue'
+import StudyLayout from '@/views/study/components/study-layout.vue'
+import { Plus } from '@element-plus/icons-vue'
+import {
+  trainingCampPaperConfigGetPaperMarkInfoByPlanId,
+  trainingCampQuestionList,
+} from '@/api/modules/study'
+import { useAppStore } from '@/stores'
+import { useRoute } from 'vue-router'
+import listCom from './list.vue'
+
+const AppStore = useAppStore()
+const route = useRoute()
+const state: any = reactive({
+  showVideo: false,
+  showHistory: false,
+  question: {
+    loading: false,
+    data: [],
+    total: 0,
+    page: 1,
+    size: 10,
+  },
+})
+const initQuestion = () => {
+  state.question.loading = true
+  state.question.data = []
+  // trainingCampPaperConfigGetPaperMarkInfoByPlanId(route.query.planId, {
+  //   correct: state.question.type !== '错题',
+  // })
+  //   .then(({ data }: any) => {
+  //     state.question.data = data.questionList
+  //   })
+  //   .finally(() => {
+  //     state.question.loading = false
+  //   })
+}
+const dataCpt = computed(() => {
+  return state.question.data.slice(
+    (state.question.page - 1) * state.question.size,
+    state.question.page * state.question.size,
+  )
+})
+onMounted(() => {
+  initQuestion()
+})
+onBeforeMount(() => {
+  // document.documentElement.style.setProperty(
+  //   '--czr-quasar-color',
+  //   'var(--czr-main-color)',
+  // )
+})
+</script>
+
+<style lang="scss" scoped></style>

+ 2 - 132
src/views/study/subject/question/index.vue

@@ -106,71 +106,7 @@
           v-loading="state.question.loading"
         >
           <template v-if="state.question.data?.length > 0">
-            <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
-              <template v-for="(item, index) in state.question.data">
-                <div
-                  class="question-card overflow-hidden rounded-xl border border-[#e5e7eb] bg-white shadow-sm"
-                >
-                  <div class="p-4">
-                    <div class="mb-3 flex items-start justify-between">
-                      <div class="text-base font-semibold text-gray-800">
-                        题目 {{ index + 1 }}
-                      </div>
-                      <div class="flex space-x-1">
-                        <q-btn
-                          round
-                          size="xs"
-                          icon="book"
-                          color="red"
-                          @click="state.showHistory = true"
-                        />
-                      </div>
-                    </div>
-                    <!-- 题目的图片 -->
-                    <div
-                      class="bg-gray-light mb-4 flex justify-center rounded-lg p-4"
-                    >
-                      <img
-                        :src="item.questionContent"
-                        alt="题目图片"
-                        class="max-h-40 rounded"
-                      />
-                    </div>
-                    <!-- 答案的图片 -->
-                    <div
-                      class="bg-gray-light mb-4 flex justify-center rounded-lg p-4"
-                    >
-                      <img
-                        :src="item.questionAnswer"
-                        alt="答案图片"
-                        class="max-h-32 rounded"
-                      />
-                    </div>
-                    <!-- 视频解析列表 -->
-                    <div>
-                      <div class="mb-2 text-sm font-medium text-gray-800">
-                        视频解析:
-                      </div>
-                      <ul class="space-y-2">
-                        <template v-for="video in item.questionVideos">
-                          <li
-                            class="video-item flex items-center justify-between rounded-lg border border-[#e5e7eb] p-2"
-                          >
-                            <span class="text-sm">{{ video.fileName }}</span>
-                            <div
-                              class="play-video bg-subject-color hover:bg-subject-dark rounded-full p-1.5 transition-colors"
-                              @click="state.showVideo = true"
-                            >
-                              <i class="fas fa-circle-play text-xl"></i>
-                            </div>
-                          </li>
-                        </template>
-                      </ul>
-                    </div>
-                  </div>
-                </div>
-              </template>
-            </div>
+            <listCom :data="state.question.data" />
             <!-- 分页控件 -->
             <div class="mt-6 flex justify-center">
               <div class="q-pa-lg flex-center flex">
@@ -194,64 +130,6 @@
         </div>
       </div>
     </div>
-    <q-dialog v-model="state.showVideo">
-      <q-card style="width: 60%; max-width: 60%">
-        <q-card-section>
-          <div class="text-h6">视频解析(汉字结构类型及特点)</div>
-        </q-card-section>
-
-        <q-card-section>
-          <video
-            class="h-full w-full"
-            src="http://cyberplayer.bcelive.com/videoworks/mda-kbuhu4wqdi08dwix/cyberplayer/mp4/cyberplayer-demo.mp4"
-          />
-        </q-card-section>
-      </q-card>
-    </q-dialog>
-    <q-dialog v-model="state.showHistory">
-      <q-card style="max-width: 60%">
-        <q-card-section>
-          <div class="text-h6">
-            历史做题记录(下列汉字中属于独体字的是哪一项?)
-          </div>
-        </q-card-section>
-
-        <q-card-section>
-          <div class="px-4">
-            <q-timeline>
-              <q-timeline-entry heading>
-                <div class="text-xl">2023-02-11</div>
-              </q-timeline-entry>
-              <q-timeline-entry
-                subtitle="11:22:33"
-                icon="fa-solid fa-xmark "
-                color="red"
-              />
-              <q-timeline-entry
-                subtitle="14:22:33"
-                icon="fa-solid fa-check "
-                color="green"
-              />
-            </q-timeline>
-            <q-timeline>
-              <q-timeline-entry heading>
-                <div class="text-xl">2023-01-24</div>
-              </q-timeline-entry>
-              <q-timeline-entry
-                subtitle="08:22:33"
-                icon="fa-solid fa-check "
-                color="green"
-              />
-              <q-timeline-entry
-                subtitle="14:22:33"
-                icon="fa-solid fa-check "
-                color="green"
-              />
-            </q-timeline>
-          </div>
-        </q-card-section>
-      </q-card>
-    </q-dialog>
   </StudyLayout>
 </template>
 
@@ -265,6 +143,7 @@ import {
 } from '@/api/modules/study'
 import { useAppStore } from '@/stores'
 import { useRoute } from 'vue-router'
+import listCom from './list.vue'
 
 const AppStore = useAppStore()
 const route = useRoute()
@@ -283,8 +162,6 @@ const state: any = reactive({
     page: 1,
     size: 10,
   },
-  showVideo: false,
-  showHistory: false,
 })
 const ref_tree = ref()
 const treeMapCpt = computed(() => {
@@ -377,14 +254,7 @@ $primary: red;
 .search-input:focus {
   box-shadow: 0 0 0 3px rgba(var(--czr-main-color-rgb), 0.2);
 }
-.question-card {
-  transition: all 0.3s ease;
-}
 
-.question-card:hover {
-  transform: translateY(-5px);
-  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
-}
 :deep(.select) {
   .ellipsis {
     color: #ffffff;

+ 172 - 0
src/views/study/subject/question/list.vue

@@ -0,0 +1,172 @@
+<template>
+  <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
+    <template v-for="(item, index) in data">
+      <div
+        class="question-card overflow-hidden rounded-xl border border-[#e5e7eb] bg-white shadow-sm"
+      >
+        <div class="p-4">
+          <div class="mb-3 flex items-start justify-between">
+            <div class="text-base font-semibold text-gray-800">
+              题目 {{ index + 1 }}
+            </div>
+            <div class="flex space-x-1">
+              <q-btn
+                round
+                size="xs"
+                icon="book"
+                color="red"
+                @click="onHistory(item)"
+              />
+            </div>
+          </div>
+          <!-- 题目的图片 -->
+          <div class="bg-gray-light mb-4 flex justify-center rounded-lg p-4">
+            <img
+              :src="item.questionContent"
+              alt="题目图片"
+              class="max-h-40 rounded"
+            />
+          </div>
+          <!-- 答案的图片 -->
+          <div class="bg-gray-light mb-4 flex justify-center rounded-lg p-4">
+            <img
+              :src="item.questionAnswer"
+              alt="答案图片"
+              class="max-h-32 rounded"
+            />
+          </div>
+          <!-- 视频解析列表 -->
+          <div v-if="item.questionVideos?.length > 0">
+            <div class="mb-2 text-sm font-medium text-gray-800">视频解析:</div>
+            <ul class="space-y-2">
+              <template v-for="video in item.questionVideos">
+                <li
+                  class="video-item flex items-center justify-between rounded-lg border border-[#e5e7eb] p-2"
+                >
+                  <span class="text-sm">{{ video.fileName }}</span>
+                  <div
+                    class="play-video bg-subject-color hover:bg-subject-dark rounded-full p-1.5 transition-colors"
+                    @click="state.showVideo = true"
+                  >
+                    <i class="fas fa-circle-play text-xl"></i>
+                  </div>
+                </li>
+              </template>
+            </ul>
+          </div>
+        </div>
+      </div>
+    </template>
+  </div>
+  <q-dialog v-model="state.showVideo">
+    <q-card style="width: 60%; max-width: 60%">
+      <q-card-section>
+        <div class="text-h6">视频解析(汉字结构类型及特点)</div>
+      </q-card-section>
+
+      <q-card-section>
+        <video
+          class="h-full w-full"
+          src="http://cyberplayer.bcelive.com/videoworks/mda-kbuhu4wqdi08dwix/cyberplayer/mp4/cyberplayer-demo.mp4"
+        />
+      </q-card-section>
+    </q-card>
+  </q-dialog>
+  <q-dialog v-model="state.history.show">
+    <q-card style="max-width: 60%">
+      <q-card-section>
+        <div class="text-h6 w-100">历史做题记录</div>
+      </q-card-section>
+
+      <q-card-section>
+        <div class="px-4">
+          <template v-for="item in state.history.data">
+            <q-timeline>
+              <q-timeline-entry heading>
+                <div class="text-xl">{{ item.date }}</div>
+              </q-timeline-entry>
+              <template v-for="son in item.list">
+                <template v-if="son.isCorrect == 0">
+                  <q-timeline-entry
+                    :subtitle="Hms(son.solvingTime)"
+                    icon="fa-solid fa-xmark "
+                    color="red"
+                  />
+                </template>
+                <template v-else-if="son.isCorrect == 1">
+                  <q-timeline-entry
+                    :subtitle="Hms(son.solvingTime)"
+                    icon="fa-solid fa-check "
+                    color="green"
+                  />
+                </template>
+              </template>
+            </q-timeline>
+          </template>
+        </div>
+      </q-card-section>
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup lang="ts">
+import { reactive } from 'vue'
+import { trainingCampPaperQuestionRelIpadHistoryRecords } from '@/api/modules/study'
+import { Hms } from '@/utils/czr-util'
+import { ElMessage } from 'element-plus'
+
+const props = defineProps({
+  data: { default: () => [] },
+})
+const state: any = reactive({
+  showVideo: false,
+  history: {
+    show: false,
+    data: [],
+  },
+})
+const onHistory = (row) => {
+  trainingCampPaperQuestionRelIpadHistoryRecords(row.questionId)
+    .then((data: any) => {
+      if (data?.length > 0) {
+        // 按年月日分组
+        const groupedData = data.reduce((acc, item) => {
+          // 提取年月日部分(格式:YYYY-MM-DD)
+          const datePart = item.solvingTime.split(' ')[0] // 取日期部分(去掉时间)
+
+          // 查找是否已有该日期的分组
+          const existingGroup = acc.find((group) => group.date === datePart)
+
+          if (existingGroup) {
+            // 如果已有该分组,添加到对应的 list 中
+            existingGroup.list.push(item)
+          } else {
+            // 如果没有该分组,创建新分组
+            acc.push({
+              date: datePart,
+              list: [item],
+            })
+          }
+
+          return acc
+        }, [])
+        state.history.data = groupedData
+        state.history.show = true
+      } else {
+        ElMessage.info('暂无历史做题记录!')
+      }
+    })
+    .finally(() => {})
+}
+</script>
+
+<style lang="scss" scoped>
+.question-card {
+  transition: all 0.3s ease;
+}
+
+.question-card:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
+}
+</style>

+ 3 - 145
src/views/study/subject/question/plan.vue

@@ -8,12 +8,9 @@
           <div class="relative flex items-center text-xl font-bold">
             <i class="fas fa-book mr-2"></i>
             题目列表
-            <span class="text-base" v-if="state.selected">
-              (共{{ state.question.total }}题)
-            </span>
+            <span class="text-base"> (共{{ state.question.total }}题) </span>
             <div class="absolute right-2 ml-auto flex">
               <q-select
-                v-if="!$route.query.onlyError"
                 class="select ml-4 w-[100px]"
                 rounded
                 standout="focus"
@@ -32,71 +29,7 @@
           v-loading="state.question.loading"
         >
           <template v-if="state.question.data?.length > 0">
-            <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
-              <template v-for="(item, index) in dataCpt">
-                <div
-                  class="question-card overflow-hidden rounded-xl border border-[#e5e7eb] bg-white shadow-sm"
-                >
-                  <div class="p-4">
-                    <div class="mb-3 flex items-start justify-between">
-                      <div class="text-base font-semibold text-gray-800">
-                        题目 {{ index + 1 }}
-                      </div>
-                      <div class="flex space-x-1">
-                        <q-btn
-                          round
-                          size="xs"
-                          icon="book"
-                          color="red"
-                          @click="state.showHistory = true"
-                        />
-                      </div>
-                    </div>
-                    <!-- 题目的图片 -->
-                    <div
-                      class="bg-gray-light mb-4 flex justify-center rounded-lg p-4"
-                    >
-                      <img
-                        :src="item.questionContent"
-                        alt="题目图片"
-                        class="max-h-40 rounded"
-                      />
-                    </div>
-                    <!-- 答案的图片 -->
-                    <div
-                      class="bg-gray-light mb-4 flex justify-center rounded-lg p-4"
-                    >
-                      <img
-                        :src="item.questionAnswer"
-                        alt="答案图片"
-                        class="max-h-32 rounded"
-                      />
-                    </div>
-                    <!-- 视频解析列表 -->
-                    <div v-if="item.questionVideo?.length > 0">
-                      <div class="mb-2 text-sm font-medium text-gray-800">
-                        视频解析:
-                      </div>
-                      <ul class="space-y-2">
-                        <template v-for="video in item.questionVideos">
-                          <li
-                            class="video-item flex items-center justify-between rounded-lg border border-[#e5e7eb] p-2"
-                          >
-                            <span class="text-sm">{{ video.fileName }}</span>
-                            <div
-                              class="play-video bg-subject-color hover:bg-subject-dark rounded-full p-1.5 transition-colors"
-                              @click="state.showVideo = true"
-                            >
-                              <i class="fas fa-circle-play text-xl"></i>
-                            </div>
-                          </li>
-                        </template>
-                      </ul>
-                    </div>
-                  </div>
-                </div>
-              </template>
-            </div>
+            <listCom :data="state.question.data" />
             <!-- 分页控件 -->
             <div class="mt-6 flex justify-center">
               <div class="q-pa-lg flex-center flex">
@@ -121,64 +54,6 @@
         </div>
       </div>
     </div>
-    <q-dialog v-model="state.showVideo">
-      <q-card style="width: 60%; max-width: 60%">
-        <q-card-section>
-          <div class="text-h6">视频解析(汉字结构类型及特点)</div>
-        </q-card-section>
-
-        <q-card-section>
-          <video
-            class="h-full w-full"
-            src="http://cyberplayer.bcelive.com/videoworks/mda-kbuhu4wqdi08dwix/cyberplayer/mp4/cyberplayer-demo.mp4"
-          />
-        </q-card-section>
-      </q-card>
-    </q-dialog>
-    <q-dialog v-model="state.showHistory">
-      <q-card style="max-width: 60%">
-        <q-card-section>
-          <div class="text-h6">
-            历史做题记录(下列汉字中属于独体字的是哪一项?)
-          </div>
-        </q-card-section>
-
-        <q-card-section>
-          <div class="px-4">
-            <q-timeline>
-              <q-timeline-entry heading>
-                <div class="text-xl">2023-02-11</div>
-              </q-timeline-entry>
-              <q-timeline-entry
-                subtitle="11:22:33"
-                icon="fa-solid fa-xmark "
-                color="red"
-              />
-              <q-timeline-entry
-                subtitle="14:22:33"
-                icon="fa-solid fa-check "
-                color="green"
-              />
-            </q-timeline>
-            <q-timeline>
-              <q-timeline-entry heading>
-                <div class="text-xl">2023-01-24</div>
-              </q-timeline-entry>
-              <q-timeline-entry
-                subtitle="08:22:33"
-                icon="fa-solid fa-check "
-                color="green"
-              />
-              <q-timeline-entry
-                subtitle="14:22:33"
-                icon="fa-solid fa-check "
-                color="green"
-              />
-            </q-timeline>
-          </div>
-        </q-card-section>
-      </q-card>
-    </q-dialog>
   </StudyLayout>
 </template>
 
@@ -192,12 +67,11 @@ import {
 } from '@/api/modules/study'
 import { useAppStore } from '@/stores'
 import { useRoute } from 'vue-router'
+import listCom from './list.vue'
 
 const AppStore = useAppStore()
 const route = useRoute()
 const state: any = reactive({
-  showVideo: false,
-  showHistory: false,
   question: {
     loading: false,
     type: '错题',
@@ -238,17 +112,6 @@ onBeforeMount(() => {
 </script>
 
 <style lang="scss" scoped>
-.search-input:focus {
-  box-shadow: 0 0 0 3px rgba(var(--czr-main-color-rgb), 0.2);
-}
-.question-card {
-  transition: all 0.3s ease;
-}
-
-.question-card:hover {
-  transform: translateY(-5px);
-  box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
-}
 :deep(.select) {
   .ellipsis {
     color: #ffffff;
@@ -257,11 +120,6 @@ onBeforeMount(() => {
     color: #ffffff;
   }
 }
-:deep(.date) {
-  .q-placeholder {
-    color: #ffffff;
-  }
-}
 :deep(.focus) {
   background: rgba(0, 0, 0, 0.1) !important;
 }