猫妈狗爸伴宠师小程序后端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
9.1 KiB

  1. <template>
  2. <el-dialog title="考核信息" :visible.sync="visible" width="60%" append-to-body>
  3. <div v-loading="loading">
  4. <el-tabs v-model="activeTab">
  5. <!-- <el-tab-pane label="基本信息" name="basic">
  6. <el-descriptions :column="2" border>
  7. <el-descriptions-item label="姓名">{{ examInfo.name }}</el-descriptions-item>
  8. <el-descriptions-item label="手机号">{{ examInfo.phone }}</el-descriptions-item>
  9. <el-descriptions-item label="身份证">{{ examInfo.idCard }}</el-descriptions-item>
  10. <el-descriptions-item label="提交时间">{{ examInfo.createTime }}</el-descriptions-item>
  11. </el-descriptions>
  12. </el-tab-pane> -->
  13. <el-tab-pane label="答题详情" name="answers">
  14. <div v-for="(question, index) in examInfo.answerList" :key="index" class="question-item">
  15. <div class="question-title">
  16. <span class="question-index">{{ index + 1 }}.</span>
  17. <span class="question-type">[{{ question.type === '培训' ? '填空题' : '选择题' }}]</span>
  18. <span class="question-content">{{ question.title }}</span>
  19. </div>
  20. <!-- 填空题答案 -->
  21. <template v-if="question.type === '培训'">
  22. <div class="answer-content">
  23. <div class="answer-label">答案</div>
  24. <div class="answer-text">{{ question.userAppletAnswerTrain.answer }}</div>
  25. <div class="answer-requirement">最少字数要求{{ question.numberWords }}</div>
  26. </div>
  27. </template>
  28. <!-- 选择题答案 -->
  29. <template v-else>
  30. <div class="options-list">
  31. <div v-for="option in question.answerList" :key="option.orderNo"
  32. :class="['option-item', {
  33. 'correct': option.isTrue,
  34. 'selected': isOptionSelected(question, option.id),
  35. 'wrong-selected': isOptionSelected(question, option.id) && !option.isTrue
  36. }]">
  37. <span class="option-label">{{ String.fromCharCode(64 + option.orderNo) }}.</span>
  38. <span class="option-content">{{ option.title }}</span>
  39. <span v-if="option.isTrue" class="correct-tag">正确答案</span>
  40. <span v-if="isOptionSelected(question, option.id)"
  41. :class="['selected-tag', { 'wrong-tag': !option.isTrue }]">
  42. {{ option.isTrue ? '已选择' : '错误选择' }}
  43. </span>
  44. </div>
  45. </div>
  46. <div class="answer-result" :class="{ 'correct': isAnswerCorrect(question), 'wrong': !isAnswerCorrect(question) }">
  47. <i :class="['el-icon-' + (isAnswerCorrect(question) ? 'success' : 'error')]"></i>
  48. {{ isAnswerCorrect(question) ? '回答正确' : '回答错误' }}
  49. </div>
  50. </template>
  51. </div>
  52. </el-tab-pane>
  53. </el-tabs>
  54. </div>
  55. <div slot="footer" class="dialog-footer">
  56. <el-button @click="handleClose"> </el-button>
  57. </div>
  58. </el-dialog>
  59. </template>
  60. <script>
  61. import { getAppletUsersTeacher } from "@/api/model/AppletUsersTeacher";
  62. export default {
  63. name: "ExamInfo",
  64. props: {
  65. visible: {
  66. type: Boolean,
  67. default: false
  68. },
  69. userId: {
  70. type: [String, Number],
  71. default: null
  72. }
  73. },
  74. data() {
  75. return {
  76. loading: false,
  77. activeTab: 'answers',
  78. // examInfo: {
  79. // name: '姓名',
  80. // phone: '手机号',
  81. // idCard: '身份证',
  82. // createTime: '提交时间',
  83. // answerList: [
  84. // {
  85. // title: '题目',
  86. // type: '类型',
  87. // userAnswer: '用户选择或者填写的答案',
  88. // numberWords: '最少字数',
  89. // answerList: [
  90. // {
  91. // title: '选项',
  92. // isTrue: '是否正确',
  93. // orderNo: '排序'
  94. // }
  95. // ]
  96. // }
  97. // ]
  98. // },
  99. examInfo: {
  100. name: '',
  101. phone: '',
  102. idCard: '',
  103. createTime: '',
  104. answerList: []
  105. },
  106. };
  107. },
  108. watch: {
  109. visible(val) {
  110. if (val && this.userId) {
  111. this.getExamInfo();
  112. }
  113. }
  114. },
  115. methods: {
  116. getExamInfo() {
  117. this.loading = true;
  118. getAppletUsersTeacher(this.userId).then(response => {
  119. this.examInfo = response.data;
  120. this.loading = false;
  121. }).catch(() => {
  122. this.loading = false;
  123. });
  124. },
  125. handleClose() {
  126. this.$emit('update:visible', false);
  127. },
  128. // 判断选项是否被选中
  129. isOptionSelected(question, optionId) {
  130. if (!question.userAnswerBaseList || !question.userAnswerBaseList.length) return false;
  131. return question.userAnswerBaseList.some(answer => answer.answerId === optionId);
  132. },
  133. // 判断答案是否正确
  134. isAnswerCorrect(question) {
  135. if (!question.userAnswerBaseList || !question.userAnswerBaseList.length) return false;
  136. // 获取所有正确答案的ID
  137. const correctOptionIds = question.answerList
  138. .filter(option => option.isTrue)
  139. .map(option => option.id);
  140. // 获取用户选择的答案ID
  141. const userAnswerIds = question.userAnswerBaseList.map(answer => answer.answerId);
  142. // 判断用户选择的答案数量是否与正确答案数量相同
  143. if (userAnswerIds.length !== correctOptionIds.length) {
  144. return false;
  145. }
  146. // 判断用户选择的答案是否都是正确的
  147. return userAnswerIds.every(answerId => correctOptionIds.includes(answerId));
  148. }
  149. }
  150. };
  151. </script>
  152. <style lang="scss" scoped>
  153. .question-item {
  154. margin-bottom: 20px;
  155. padding: 15px;
  156. background: #f8f9fa;
  157. border-radius: 4px;
  158. .question-title {
  159. margin-bottom: 15px;
  160. font-size: 16px;
  161. font-weight: bold;
  162. .question-index {
  163. margin-right: 8px;
  164. }
  165. .question-type {
  166. color: #409EFF;
  167. margin-right: 8px;
  168. }
  169. }
  170. .answer-content {
  171. padding: 10px;
  172. background: #fff;
  173. border-radius: 4px;
  174. .answer-label {
  175. font-weight: bold;
  176. margin-bottom: 8px;
  177. }
  178. .answer-text {
  179. margin-bottom: 8px;
  180. line-height: 1.5;
  181. }
  182. .answer-requirement {
  183. color: #909399;
  184. font-size: 13px;
  185. }
  186. }
  187. .options-list {
  188. .option-item {
  189. padding: 10px;
  190. margin-bottom: 8px;
  191. background: #fff;
  192. border-radius: 4px;
  193. display: flex;
  194. align-items: center;
  195. &.correct {
  196. background: #f0f9eb;
  197. }
  198. &.selected {
  199. background: #ecf5ff;
  200. }
  201. &.wrong-selected {
  202. background: #fef0f0;
  203. }
  204. .option-label {
  205. font-weight: bold;
  206. margin-right: 8px;
  207. }
  208. .option-content {
  209. flex: 1;
  210. }
  211. .correct-tag {
  212. color: #67c23a;
  213. margin-left: 10px;
  214. }
  215. .selected-tag {
  216. color: #409EFF;
  217. margin-left: 10px;
  218. &.wrong-tag {
  219. color: #f56c6c;
  220. }
  221. }
  222. }
  223. }
  224. .answer-result {
  225. margin-top: 10px;
  226. padding: 8px 12px;
  227. border-radius: 4px;
  228. display: flex;
  229. align-items: center;
  230. font-weight: bold;
  231. &.correct {
  232. background: #f0f9eb;
  233. color: #67c23a;
  234. }
  235. &.wrong {
  236. background: #fef0f0;
  237. color: #f56c6c;
  238. }
  239. i {
  240. margin-right: 8px;
  241. font-size: 16px;
  242. }
  243. }
  244. }
  245. </style>