猫妈狗爸伴宠师小程序后端代码
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.

375 lines
14 KiB

  1. <template>
  2. <el-dialog title="考核信息" :visible="dialogVisible" @close="handleClose" 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="base">
  14. <div v-for="(question, index) in examInfo.answerList.filter(n => n.type != '培训')" :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 v-if="!isQuestionAnswered(question)" class="unanswered-tag">未答题</span>
  19. <span class="question-content">{{ question.title }}</span>
  20. </div>
  21. <!-- 填空题答案 -->
  22. <template v-if="question.type === '培训'">
  23. <div class="answer-content">
  24. <div class="answer-label">答案</div>
  25. <div class="answer-text" :class="{ 'no-answer': !isQuestionAnswered(question) }">
  26. {{ question.userAppletAnswerTrain && question.userAppletAnswerTrain.answer || '暂无答案' }}
  27. </div>
  28. <div class="answer-requirement">最少字数要求{{ question.numberWords }}</div>
  29. </div>
  30. </template>
  31. <!-- 选择题答案 -->
  32. <template v-else>
  33. <div v-if="!isQuestionAnswered(question)" class="no-answer-tip">
  34. <i class="el-icon-warning"></i>
  35. 该题目尚未作答
  36. </div>
  37. <div v-else class="options-list">
  38. <div v-for="option in question.answerList" :key="option.orderNo"
  39. :class="['option-item', {
  40. 'correct': option.isTrue,
  41. 'selected': isOptionSelected(question, option.id),
  42. 'wrong-selected': isOptionSelected(question, option.id) && !option.isTrue
  43. }]">
  44. <span class="option-label">{{ String.fromCharCode(64 + option.orderNo) }}.</span>
  45. <span class="option-content">{{ option.title }}</span>
  46. <span v-if="option.isTrue" class="correct-tag">正确答案</span>
  47. <span v-if="isOptionSelected(question, option.id)"
  48. :class="['selected-tag', { 'wrong-tag': !option.isTrue }]">
  49. {{ option.isTrue ? '已选择' : '错误选择' }}
  50. </span>
  51. </div>
  52. </div>
  53. <div class="answer-result" :class="{ 'correct': isAnswerCorrect(question), 'wrong': !isAnswerCorrect(question) }">
  54. <i :class="['el-icon-' + (isAnswerCorrect(question) ? 'success' : 'error')]"></i>
  55. {{ isAnswerCorrect(question) ? '回答正确' : '回答错误' }}
  56. </div>
  57. </template>
  58. </div>
  59. </el-tab-pane>
  60. <el-tab-pane label="培训考核" name="answers">
  61. <div v-for="(question, index) in examInfo.answerList.filter(n => n.type == '培训')" :key="index" class="question-item">
  62. <div class="question-title">
  63. <span class="question-index">{{ index + 1 }}.</span>
  64. <span class="question-type">[{{ question.type === '培训' ? '填空题' : '选择题' }}]</span>
  65. <span v-if="!isQuestionAnswered(question)" class="unanswered-tag">未答题</span>
  66. <span class="question-content">{{ question.title }}</span>
  67. </div>
  68. <!-- 填空题答案 -->
  69. <template v-if="question.type === '培训'">
  70. <div class="answer-content">
  71. <div class="answer-label">答案</div>
  72. <div class="answer-text" :class="{ 'no-answer': !isQuestionAnswered(question) }">
  73. {{ question.userAppletAnswerTrain && question.userAppletAnswerTrain.answer || '暂无答案' }}
  74. </div>
  75. <div class="answer-requirement">最少字数要求{{ question.numberWords }}</div>
  76. </div>
  77. </template>
  78. <!-- 选择题答案 -->
  79. <template v-else>
  80. <div v-if="!isQuestionAnswered(question)" class="no-answer-tip">
  81. <i class="el-icon-warning"></i>
  82. 该题目尚未作答
  83. </div>
  84. <div v-else class="options-list">
  85. <div v-for="option in question.answerList" :key="option.orderNo"
  86. :class="['option-item', {
  87. 'correct': option.isTrue,
  88. 'selected': isOptionSelected(question, option.id),
  89. 'wrong-selected': isOptionSelected(question, option.id) && !option.isTrue
  90. }]">
  91. <span class="option-label">{{ String.fromCharCode(64 + option.orderNo) }}.</span>
  92. <span class="option-content">{{ option.title }}</span>
  93. <span v-if="option.isTrue" class="correct-tag">正确答案</span>
  94. <span v-if="isOptionSelected(question, option.id)"
  95. :class="['selected-tag', { 'wrong-tag': !option.isTrue }]">
  96. {{ option.isTrue ? '已选择' : '错误选择' }}
  97. </span>
  98. </div>
  99. </div>
  100. <div class="answer-result" :class="{ 'correct': isAnswerCorrect(question), 'wrong': !isAnswerCorrect(question) }">
  101. <i :class="['el-icon-' + (isAnswerCorrect(question) ? 'success' : 'error')]"></i>
  102. {{ isAnswerCorrect(question) ? '回答正确' : '回答错误' }}
  103. </div>
  104. </template>
  105. </div>
  106. </el-tab-pane>
  107. </el-tabs>
  108. </div>
  109. <div slot="footer" class="dialog-footer">
  110. <el-button @click="handleClose"> </el-button>
  111. </div>
  112. </el-dialog>
  113. </template>
  114. <script>
  115. import { getAppletUsersTeacher } from "@/api/model/AppletUsersTeacher";
  116. export default {
  117. name: "ExamInfo",
  118. props: {
  119. visible: {
  120. type: Boolean,
  121. default: false
  122. },
  123. userId: {
  124. type: [String, Number],
  125. default: null
  126. }
  127. },
  128. data() {
  129. return {
  130. loading: false,
  131. activeTab: 'base',
  132. // examInfo: {
  133. // name: '姓名',
  134. // phone: '手机号',
  135. // idCard: '身份证',
  136. // createTime: '提交时间',
  137. // answerList: [
  138. // {
  139. // title: '题目',
  140. // type: '类型',
  141. // userAnswer: '用户选择或者填写的答案',
  142. // numberWords: '最少字数',
  143. // answerList: [
  144. // {
  145. // title: '选项',
  146. // isTrue: '是否正确',
  147. // orderNo: '排序'
  148. // }
  149. // ]
  150. // }
  151. // ]
  152. // },
  153. examInfo: {
  154. name: '',
  155. phone: '',
  156. idCard: '',
  157. createTime: '',
  158. answerList: []
  159. },
  160. };
  161. },
  162. watch: {
  163. visible(val) {
  164. if (val && this.userId) {
  165. this.getExamInfo();
  166. }
  167. }
  168. },
  169. methods: {
  170. getExamInfo() {
  171. this.loading = true;
  172. getAppletUsersTeacher(this.userId).then(response => {
  173. this.examInfo = response.data;
  174. this.loading = false;
  175. }).catch(() => {
  176. this.loading = false;
  177. });
  178. },
  179. handleClose() {
  180. this.$emit('update:visible', false);
  181. },
  182. // 判断选项是否被选中
  183. isOptionSelected(question, optionId) {
  184. if (!question.userAnswerBaseList || !question.userAnswerBaseList.length) return false;
  185. return question.userAnswerBaseList.some(answer => answer.answerId === optionId);
  186. },
  187. // 判断答案是否正确
  188. isAnswerCorrect(question) {
  189. if (!question.userAnswerBaseList || !question.userAnswerBaseList.length) return false;
  190. // 获取所有正确答案的ID
  191. const correctOptionIds = question.answerList
  192. .filter(option => option.isTrue)
  193. .map(option => option.id);
  194. // 获取用户选择的答案ID
  195. const userAnswerIds = [...new Set(question.userAnswerBaseList.map(answer => answer.answerId))];
  196. // 判断用户选择的答案数量是否与正确答案数量相同
  197. if (userAnswerIds.length !== correctOptionIds.length) {
  198. return false;
  199. }
  200. // 判断用户选择的答案是否都是正确的
  201. return userAnswerIds.every(answerId => correctOptionIds.includes(answerId));
  202. },
  203. isQuestionAnswered(question) {
  204. if (question.type === '培训') {
  205. // 填空题:检查是否有答案且答案不为空
  206. return question.userAppletAnswerTrain &&
  207. question.userAppletAnswerTrain.answer &&
  208. question.userAppletAnswerTrain.answer.trim() !== '';
  209. } else {
  210. // 选择题:检查是否有选择的答案
  211. return question.userAnswerBaseList && question.userAnswerBaseList.length > 0;
  212. }
  213. }
  214. },
  215. computed: {
  216. dialogVisible() {
  217. return this.visible;
  218. }
  219. }
  220. };
  221. </script>
  222. <style lang="scss" scoped>
  223. .question-item {
  224. margin-bottom: 20px;
  225. padding: 15px;
  226. background: #f8f9fa;
  227. border-radius: 4px;
  228. .question-title {
  229. margin-bottom: 15px;
  230. font-size: 16px;
  231. font-weight: bold;
  232. .question-index {
  233. margin-right: 8px;
  234. }
  235. .question-type {
  236. color: #409EFF;
  237. margin-right: 8px;
  238. }
  239. .unanswered-tag {
  240. background: #f56c6c;
  241. color: #fff;
  242. font-size: 12px;
  243. padding: 2px 6px;
  244. border-radius: 2px;
  245. margin-right: 8px;
  246. }
  247. }
  248. .answer-content {
  249. padding: 10px;
  250. background: #fff;
  251. border-radius: 4px;
  252. .answer-label {
  253. font-weight: bold;
  254. margin-bottom: 8px;
  255. }
  256. .answer-text {
  257. margin-bottom: 8px;
  258. line-height: 1.5;
  259. &.no-answer {
  260. color: #909399;
  261. }
  262. }
  263. .answer-requirement {
  264. color: #909399;
  265. font-size: 13px;
  266. }
  267. }
  268. .options-list {
  269. .option-item {
  270. padding: 10px;
  271. margin-bottom: 8px;
  272. background: #fff;
  273. border-radius: 4px;
  274. display: flex;
  275. align-items: center;
  276. &.correct {
  277. background: #f0f9eb;
  278. }
  279. &.selected {
  280. background: #ecf5ff;
  281. }
  282. &.wrong-selected {
  283. background: #fef0f0;
  284. }
  285. .option-label {
  286. font-weight: bold;
  287. margin-right: 8px;
  288. }
  289. .option-content {
  290. flex: 1;
  291. }
  292. .correct-tag {
  293. color: #67c23a;
  294. margin-left: 10px;
  295. }
  296. .selected-tag {
  297. color: #409EFF;
  298. margin-left: 10px;
  299. &.wrong-tag {
  300. color: #f56c6c;
  301. }
  302. }
  303. }
  304. }
  305. .answer-result {
  306. margin-top: 10px;
  307. padding: 8px 12px;
  308. border-radius: 4px;
  309. display: flex;
  310. align-items: center;
  311. font-weight: bold;
  312. &.correct {
  313. background: #f0f9eb;
  314. color: #67c23a;
  315. }
  316. &.wrong {
  317. background: #fef0f0;
  318. color: #f56c6c;
  319. }
  320. i {
  321. margin-right: 8px;
  322. font-size: 16px;
  323. }
  324. }
  325. .no-answer-tip {
  326. margin-bottom: 10px;
  327. padding: 8px 12px;
  328. background: #fff;
  329. border-radius: 4px;
  330. display: flex;
  331. align-items: center;
  332. font-size: 14px;
  333. color: #909399;
  334. i {
  335. margin-right: 8px;
  336. font-size: 16px;
  337. }
  338. }
  339. }
  340. </style>