Procházet zdrojové kódy

1、问卷功能
2、上传视频大小限制

liyanbo před 9 měsíci
rodič
revize
80f8811719

+ 46 - 0
src/api/bjdxResult/questionnaireresult/index.ts

@@ -0,0 +1,46 @@
+import request from '@/config/axios'
+
+// 北京大学-问卷结果 VO
+export interface QuestionnaireResultVO {
+  id: number // id
+  bqrUserId: number // 用户id
+  bqrQuestionnaireId: number // 问卷id
+  bqrStatus: string // 答卷状态
+  bqrSorce: number // 试卷得分
+  bqrStartTime: Date // 答题开始时间
+  bqrEndTime: Date // 答题结束时间
+  bqrQuestTime: number // 答题耗时
+}
+
+// 北京大学-问卷结果 API
+export const QuestionnaireResultApi = {
+  // 查询北京大学-问卷结果分页
+  getQuestionnaireResultPage: async (params: any) => {
+    return await request.get({ url: `/bjdxResult/questionnaire-result/page`, params })
+  },
+
+  // 查询北京大学-问卷结果详情
+  getQuestionnaireResult: async (id: number) => {
+    return await request.get({ url: `/bjdxResult/questionnaire-result/get?id=` + id })
+  },
+
+  // 新增北京大学-问卷结果
+  createQuestionnaireResult: async (data: QuestionnaireResultVO) => {
+    return await request.post({ url: `/bjdxResult/questionnaire-result/create`, data })
+  },
+
+  // 修改北京大学-问卷结果
+  updateQuestionnaireResult: async (data: QuestionnaireResultVO) => {
+    return await request.put({ url: `/bjdxResult/questionnaire-result/update`, data })
+  },
+
+  // 删除北京大学-问卷结果
+  deleteQuestionnaireResult: async (id: number) => {
+    return await request.delete({ url: `/bjdxResult/questionnaire-result/delete?id=` + id })
+  },
+
+  // 导出北京大学-问卷结果 Excel
+  exportQuestionnaireResult: async (params) => {
+    return await request.download({ url: `/bjdxResult/questionnaire-result/export-excel`, params })
+  }
+}

+ 46 - 0
src/api/bjdxResult/questionnaireresultdetails/index.ts

@@ -0,0 +1,46 @@
+import request from '@/config/axios'
+
+// 问卷结果-详情 VO
+export interface QuestionnaireResultDetailsVO {
+  id: number // id
+  bqrdUserId: number // 用户id
+  bqrdQuestionnaireResultId: number // 答卷结果id
+  bqrdQuestionnaireId: number // 问卷id
+  bqrdQuestionId: number // 试题id
+  bqrdQuestOptionId: number // 选择
+  bqrdIsCorrect: string // 是否答对
+  bqrdQuestSorce: number // 试题得分
+}
+
+// 问卷结果-详情 API
+export const QuestionnaireResultDetailsApi = {
+  // 查询问卷结果-详情分页
+  getQuestionnaireResultDetailsPage: async (params: any) => {
+    return await request.get({ url: `/bjdxResult/questionnaire-result-details/page`, params })
+  },
+
+  // 查询问卷结果-详情详情
+  getQuestionnaireResultDetails: async (id: number) => {
+    return await request.get({ url: `/bjdxResult/questionnaire-result-details/get?id=` + id })
+  },
+
+  // 新增问卷结果-详情
+  createQuestionnaireResultDetails: async (data: QuestionnaireResultDetailsVO) => {
+    return await request.post({ url: `/bjdxResult/questionnaire-result-details/create`, data })
+  },
+
+  // 修改问卷结果-详情
+  updateQuestionnaireResultDetails: async (data: QuestionnaireResultDetailsVO) => {
+    return await request.put({ url: `/bjdxResult/questionnaire-result-details/update`, data })
+  },
+
+  // 删除问卷结果-详情
+  deleteQuestionnaireResultDetails: async (id: number) => {
+    return await request.delete({ url: `/bjdxResult/questionnaire-result-details/delete?id=` + id })
+  },
+
+  // 导出问卷结果-详情 Excel
+  exportQuestionnaireResultDetails: async (params) => {
+    return await request.download({ url: `/bjdxResult/questionnaire-result-details/export-excel`, params })
+  }
+}

+ 1 - 1
src/components/UploadFile/src/UploadMusic.vue

@@ -22,7 +22,7 @@
     >
       <el-button type="primary">
         <Icon icon="ep:upload-filled" />
-        选取
+        选取
       </el-button>
       <template v-if="isShowTip" #tip>
         <div style="font-size: 8px">

+ 1 - 1
src/components/UploadFile/src/UploadVideo.vue

@@ -82,7 +82,7 @@ const props = defineProps({
   modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
   fileType: propTypes.array.def(['MP4', 'AVI', 'MOV', 'FLV',
                                       'mp4', 'avi', 'mov', 'flv']), // 视频类型
-  fileSize: propTypes.number.def(64), // 大小限制(MB)
+  fileSize: propTypes.number.def(500), // 大小限制(MB)
   limit: propTypes.number.def(1), // 数量限制
   autoUpload: propTypes.bool.def(true), // 自动上传
   drag: propTypes.bool.def(false), // 拖拽上传

+ 4 - 0
src/utils/dict.ts

@@ -251,4 +251,8 @@ export enum DICT_TYPE {
   COURSE_LABEL = 'bjdx_course_label', // 课程标签
   COURSE_COUTNET_TYPE = 'bjdx_course_content_type', // 课程内容类型
   COURSE_QUEST_SHOW_TYPE = 'bjdx_course_quest_show_type', // 课程试题呈现类型
+
+  // ========== QUESTIONNAIRE - 评估模块  ==========
+  BJDX_QUESTIONNAIRE_STATUS = 'bjdx_questionnaire_status', // 问卷状态
+  BJDX_QUEST_IS_CORRECT = 'bjdx_quest_is_correct', // 问卷状态
 }

+ 70 - 5
src/views/bjdx/course/CoursePreview.vue

@@ -28,7 +28,7 @@
           :src="courseInfo.courseVideoPath"
           controls
           width="100%"
-          height="480px"
+          height="450px"
           preload="metadata"
           @timeupdate="handleTimeUpdate"
         >
@@ -47,8 +47,8 @@
     class="exam-popup"
   >
     <div v-if="currentQuestion" class="question-item">
-      <p class="question-text" v-html="currentQuestion.courseQuestion.cqQuestion"></p>
-      <div v-for="option in currentQuestion.courseQuestion.courseQuestOptionList" :key="option"
+      <p class="question-text" v-html="currentQuestion.ccQuestContent"></p>
+      <div v-for="option in currentQuestion.courseQuestOptionList" :key="option"
            class="option-item" 
            :class="{ 'selected': currentQuestion.selected === option.cqoValue }"
            @click="handleOptionSelect(option.cqoValue)"
@@ -62,6 +62,8 @@
 import { ref, defineProps } from 'vue'
 import { DICT_TYPE } from '@/utils/dict'
 import { CourseConfigApi } from '@/api/bjdx/courseconfig'
+// 导入HLS库
+import Hls from 'hls.js'
 
 const props = defineProps({})
 const visible = ref(false)
@@ -70,7 +72,8 @@ const title = ref('课程预览')
 
 
 // 视频引用
-const videoRef = ref<HTMLVideoElement | null>(null)
+const videoRef = ref<HTMLVideoElement | null>(null)// HLS控制器实例
+let HLS_Controller = Hls
 // 试题数据(示例,可根据实际接口调整)
 const examQuestions = ref<any[]>([
   { id: 1, content: '问题1:这是测试题吗?', options: ['是', '否'], ccTime: 3 },
@@ -90,11 +93,71 @@ const open = async (row) => {
 
   // 调用 API 并等待结果
   examQuestions.value = await CourseConfigApi.getCourseConfigQuestion(row.id)
+
+  // 销毁之前的HLS实例(如果存在)
+  if (HLS_Controller) {
+    HLS_Controller.destroy()
+    HLS_Controller = null
+  }
+
+  // 获取视频元素
+  const videoElement = videoRef.value
+  if (!videoElement) return
+
+  // 视频地址从courseInfo获取(假设courseVideoPath是m3u8地址)
+  const videoUrl = courseInfo.value.courseVideoPath
+
+  // 处理HLS视频播放
+  if (videoUrl && videoUrl.endsWith('.m3u8')) {
+    if (Hls.isSupported()) {
+      HLS_Controller = new Hls()
+      HLS_Controller.loadSource(videoUrl)
+      HLS_Controller.attachMedia(videoElement)
+      HLS_Controller.on(Hls.Events.MANIFEST_PARSED, () => {
+        videoElement.play().catch(err => console.error('视频播放失败:', err))
+      })
+    } else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) {
+      // Safari浏览器原生支持HLS
+      videoElement.src = videoUrl
+      videoElement.addEventListener('loadedmetadata', () => {
+        videoElement.play().catch(err => console.error('视频播放失败:', err))
+      })
+    }
+  } else {
+    // 非m3u8格式视频直接播放
+    videoElement.src = videoUrl
+    videoElement.play().catch(err => console.error('视频播放失败:', err))
+  }
 }
 
+// 关闭弹窗时销毁HLS实例
+onUnmounted(() => {
+  if (HLS_Controller) {
+    HLS_Controller.destroy()
+  }
+})
+
 // 关闭弹窗方法
 const handleClose = () => {
-  visible.value = false
+  visible.value = false// 暂停视频播放并清理资源
+
+  const videoElement = videoRef.value
+  if (videoElement) {
+    videoElement.pause()          // 暂停视频播放
+    videoElement.src = ''         // 清除视频源,释放资源
+    videoElement.load()           // 触发资源卸载
+  }
+
+  // 销毁HLS实例(如果存在)
+  if (HLS_Controller) {
+    HLS_Controller.destroy()
+    HLS_Controller = null
+  }
+
+  // 重置试题相关状态
+  currentQuestionIndex.value = 0
+  currentQuestion.value = null
+  showExamMask.value = false
 }
 
 
@@ -105,6 +168,8 @@ const handleTimeUpdate = () => {
   let currentTime = videoRef.value?.currentTime || 0
   currentTime = Math.floor(currentTime);
 
+  console.log("--------------",examQuestions.value)
+
   // 遍历剩余未触发的试题(从当前索引开始)
   examQuestions.value.forEach(question => {
     if (currentTime == question.ccTime && !showExamMask.value) {

+ 1 - 1
src/views/bjdx/coursequestion/CourseQuestionForm.vue

@@ -23,7 +23,7 @@
       <el-form-item label="试题解析" prop="cqQuestAnalysis">
         <Editor v-model="formData.cqQuestAnalysis" height="150px" />
       </el-form-item>
-      <el-form-item label="试题答案id" prop="cqQuestAnswerId" v-if="false">
+      <el-form-item label="试题答案id" prop="cqQuestAnswerId">
         <el-input v-model="formData.cqQuestAnswerId" placeholder="请输入试题答案id" />
       </el-form-item>
     </el-form>

+ 2 - 2
src/views/bjdxReport/reportmanage/index.vue

@@ -139,7 +139,7 @@
           <el-button
             link
             type="primary"
-            @click="openForm('update', scope.row.id)"
+            @click="openForm('update', scope.row.brcId)"
             v-hasPermi="['report:manage:update']"
           >
             编辑
@@ -147,7 +147,7 @@
           <el-button
             link
             type="danger"
-            @click="handleDelete(scope.row.id)"
+            @click="handleDelete(scope.row.brcId)"
             v-hasPermi="['report:manage:delete']"
           >
             删除

+ 145 - 0
src/views/bjdxResult/questionnaireresult/QuestionnaireResultForm.vue

@@ -0,0 +1,145 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="用户id" prop="bqrUserId">
+        <el-input v-model="formData.bqrUserId" placeholder="请输入用户id" />
+      </el-form-item>
+      <el-form-item label="问卷id" prop="bqrQuestionnaireId">
+        <el-input v-model="formData.bqrQuestionnaireId" placeholder="请输入问卷id" />
+      </el-form-item>
+      <el-form-item label="答卷状态" prop="bqrStatus">
+        <el-radio-group v-model="formData.bqrStatus">
+          <el-radio
+            v-for="dict in getStrDictOptions(DICT_TYPE.BJDX_QUESTIONNAIRE_STATUS)"
+            :key="dict.value"
+            :label="dict.value"
+          >
+            {{ dict.label }}
+          </el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="试卷得分" prop="bqrSorce">
+        <el-input v-model="formData.bqrSorce" placeholder="请输入试卷得分" />
+      </el-form-item>
+      <el-form-item label="答题开始时间" prop="bqrStartTime">
+        <el-date-picker
+          v-model="formData.bqrStartTime"
+          type="date"
+          value-format="x"
+          placeholder="选择答题开始时间"
+        />
+      </el-form-item>
+      <el-form-item label="答题结束时间" prop="bqrEndTime">
+        <el-date-picker
+          v-model="formData.bqrEndTime"
+          type="date"
+          value-format="x"
+          placeholder="选择答题结束时间"
+        />
+      </el-form-item>
+      <el-form-item label="答题耗时" prop="bqrQuestTime">
+        <el-date-picker
+          v-model="formData.bqrQuestTime"
+          type="date"
+          value-format="x"
+          placeholder="选择答题耗时"
+        />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
+import { QuestionnaireResultApi, QuestionnaireResultVO } from '@/api/bjdxResult/questionnaireresult'
+
+/** 北京大学-问卷结果 表单 */
+defineOptions({ name: 'QuestionnaireResultForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  bqrUserId: undefined,
+  bqrQuestionnaireId: undefined,
+  bqrStatus: undefined,
+  bqrSorce: undefined,
+  bqrStartTime: undefined,
+  bqrEndTime: undefined,
+  bqrQuestTime: undefined
+})
+const formRules = reactive({
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await QuestionnaireResultApi.getQuestionnaireResult(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as QuestionnaireResultVO
+    if (formType.value === 'create') {
+      await QuestionnaireResultApi.createQuestionnaireResult(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await QuestionnaireResultApi.updateQuestionnaireResult(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    bqrUserId: undefined,
+    bqrQuestionnaireId: undefined,
+    bqrStatus: undefined,
+    bqrSorce: undefined,
+    bqrStartTime: undefined,
+    bqrEndTime: undefined,
+    bqrQuestTime: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 282 - 0
src/views/bjdxResult/questionnaireresult/index.vue

@@ -0,0 +1,282 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="100px"
+    >
+      <el-form-item label="用户id" prop="bqrUserId">
+        <el-input
+          v-model="queryParams.bqrUserId"
+          placeholder="请输入用户id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="问卷id" prop="bqrQuestionnaireId">
+        <el-input
+          v-model="queryParams.bqrQuestionnaireId"
+          placeholder="请输入问卷id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="答卷状态" prop="bqrStatus">
+        <el-select
+          v-model="queryParams.bqrStatus"
+          placeholder="请选择答卷状态"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getStrDictOptions(DICT_TYPE.BJDX_QUESTIONNAIRE_STATUS)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="试卷得分" prop="bqrSorce">
+        <el-input
+          v-model="queryParams.bqrSorce"
+          placeholder="请输入试卷得分"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="答题开始时间" prop="bqrStartTime">
+        <el-date-picker
+          v-model="queryParams.bqrStartTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="答题结束时间" prop="bqrEndTime">
+        <el-date-picker
+          v-model="queryParams.bqrEndTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="答题耗时" prop="bqrQuestTime">
+        <el-date-picker
+          v-model="queryParams.bqrQuestTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['bjdxResult:questionnaire-result:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['bjdxResult:questionnaire-result:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="用户id" align="center" prop="bqrUserId" />
+      <el-table-column label="问卷id" align="center" prop="bqrQuestionnaireId" />
+      <el-table-column label="答卷状态" align="center" prop="bqrStatus">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.BJDX_QUESTIONNAIRE_STATUS" :value="scope.row.bqrStatus" />
+        </template>
+      </el-table-column>
+      <el-table-column label="试卷得分" align="center" prop="bqrSorce" />
+      <el-table-column
+        label="答题开始时间"
+        align="center"
+        prop="bqrStartTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column
+        label="答题结束时间"
+        align="center"
+        prop="bqrEndTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="答题耗时" align="center" prop="bqrQuestTime" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['bjdxResult:questionnaire-result:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['bjdxResult:questionnaire-result:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <QuestionnaireResultForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { QuestionnaireResultApi, QuestionnaireResultVO } from '@/api/bjdxResult/questionnaireresult'
+import QuestionnaireResultForm from './QuestionnaireResultForm.vue'
+
+/** 北京大学-问卷结果 列表 */
+defineOptions({ name: 'QuestionnaireResult' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<QuestionnaireResultVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  bqrUserId: undefined,
+  bqrQuestionnaireId: undefined,
+  bqrStatus: undefined,
+  bqrSorce: undefined,
+  bqrStartTime: [],
+  bqrEndTime: [],
+  bqrQuestTime: [],
+  createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await QuestionnaireResultApi.getQuestionnaireResultPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await QuestionnaireResultApi.deleteQuestionnaireResult(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await QuestionnaireResultApi.exportQuestionnaireResult(queryParams)
+    download.excel(data, '北京大学-问卷结果.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 130 - 0
src/views/bjdxResult/questionnaireresultdetails/QuestionnaireResultDetailsForm.vue

@@ -0,0 +1,130 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="用户id" prop="bqrdUserId">
+        <el-input v-model="formData.bqrdUserId" placeholder="请输入用户id" />
+      </el-form-item>
+      <el-form-item label="答卷结果id" prop="bqrdQuestionnaireResultId">
+        <el-input v-model="formData.bqrdQuestionnaireResultId" placeholder="请输入答卷结果id" />
+      </el-form-item>
+      <el-form-item label="问卷id" prop="bqrdQuestionnaireId">
+        <el-input v-model="formData.bqrdQuestionnaireId" placeholder="请输入问卷id" />
+      </el-form-item>
+      <el-form-item label="试题id" prop="bqrdQuestionId">
+        <el-input v-model="formData.bqrdQuestionId" placeholder="请输入试题id" />
+      </el-form-item>
+      <el-form-item label="选择" prop="bqrdQuestOptionId">
+        <el-input v-model="formData.bqrdQuestOptionId" placeholder="请输入选择" />
+      </el-form-item>
+      <el-form-item label="是否答对" prop="bqrdIsCorrect">
+        <el-radio-group v-model="formData.bqrdIsCorrect">
+          <el-radio
+            v-for="dict in getStrDictOptions(DICT_TYPE.BJDX_QUEST_IS_CORRECT)"
+            :key="dict.value"
+            :label="dict.value"
+          >
+            {{ dict.label }}
+          </el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="试题得分" prop="bqrdQuestSorce">
+        <el-input v-model="formData.bqrdQuestSorce" placeholder="请输入试题得分" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
+import { QuestionnaireResultDetailsApi, QuestionnaireResultDetailsVO } from '@/api/bjdxResult/questionnaireresultdetails'
+
+/** 问卷结果-详情 表单 */
+defineOptions({ name: 'QuestionnaireResultDetailsForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  bqrdUserId: undefined,
+  bqrdQuestionnaireResultId: undefined,
+  bqrdQuestionnaireId: undefined,
+  bqrdQuestionId: undefined,
+  bqrdQuestOptionId: undefined,
+  bqrdIsCorrect: undefined,
+  bqrdQuestSorce: undefined
+})
+const formRules = reactive({
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await QuestionnaireResultDetailsApi.getQuestionnaireResultDetails(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as QuestionnaireResultDetailsVO
+    if (formType.value === 'create') {
+      await QuestionnaireResultDetailsApi.createQuestionnaireResultDetails(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await QuestionnaireResultDetailsApi.updateQuestionnaireResultDetails(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    bqrdUserId: undefined,
+    bqrdQuestionnaireResultId: undefined,
+    bqrdQuestionnaireId: undefined,
+    bqrdQuestionId: undefined,
+    bqrdQuestOptionId: undefined,
+    bqrdIsCorrect: undefined,
+    bqrdQuestSorce: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 254 - 0
src/views/bjdxResult/questionnaireresultdetails/index.vue

@@ -0,0 +1,254 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="100px"
+    >
+      <el-form-item label="用户id" prop="bqrdUserId">
+        <el-input
+          v-model="queryParams.bqrdUserId"
+          placeholder="请输入用户id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="答卷结果id" prop="bqrdQuestionnaireResultId">
+        <el-input
+          v-model="queryParams.bqrdQuestionnaireResultId"
+          placeholder="请输入答卷结果id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="问卷id" prop="bqrdQuestionnaireId">
+        <el-input
+          v-model="queryParams.bqrdQuestionnaireId"
+          placeholder="请输入问卷id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="试题id" prop="bqrdQuestionId">
+        <el-input
+          v-model="queryParams.bqrdQuestionId"
+          placeholder="请输入试题id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="选择" prop="bqrdQuestOptionId">
+        <el-input
+          v-model="queryParams.bqrdQuestOptionId"
+          placeholder="请输入选择"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="是否答对" prop="bqrdIsCorrect">
+        <el-select
+          v-model="queryParams.bqrdIsCorrect"
+          placeholder="请选择是否答对"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getStrDictOptions(DICT_TYPE.BJDX_QUEST_IS_CORRECT)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-220px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['bjdxResult:questionnaire-result-details:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['bjdxResult:questionnaire-result-details:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="用户id" align="center" prop="bqrdUserId" />
+      <el-table-column label="答卷结果id" align="center" prop="bqrdQuestionnaireResultId" />
+      <el-table-column label="问卷id" align="center" prop="bqrdQuestionnaireId" />
+      <el-table-column label="试题id" align="center" prop="bqrdQuestionId" />
+      <el-table-column label="选择" align="center" prop="bqrdQuestOptionId" />
+      <el-table-column label="是否答对" align="center" prop="bqrdIsCorrect">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.BJDX_QUEST_IS_CORRECT" :value="scope.row.bqrdIsCorrect" />
+        </template>
+      </el-table-column>
+      <el-table-column label="试题得分" align="center" prop="bqrdQuestSorce" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['bjdxResult:questionnaire-result-details:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['bjdxResult:questionnaire-result-details:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <QuestionnaireResultDetailsForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { QuestionnaireResultDetailsApi, QuestionnaireResultDetailsVO } from '@/api/bjdxResult/questionnaireresultdetails'
+import QuestionnaireResultDetailsForm from './QuestionnaireResultDetailsForm.vue'
+
+/** 问卷结果-详情 列表 */
+defineOptions({ name: 'QuestionnaireResultDetails' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<QuestionnaireResultDetailsVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  bqrdUserId: undefined,
+  bqrdQuestionnaireResultId: undefined,
+  bqrdQuestionnaireId: undefined,
+  bqrdQuestionId: undefined,
+  bqrdQuestOptionId: undefined,
+  bqrdIsCorrect: undefined,
+  createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await QuestionnaireResultDetailsApi.getQuestionnaireResultDetailsPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await QuestionnaireResultDetailsApi.deleteQuestionnaireResultDetails(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await QuestionnaireResultDetailsApi.exportQuestionnaireResultDetails(queryParams)
+    download.excel(data, '问卷结果-详情.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>