index.tsx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import { Tag, Image, Button } from 'vant'
  2. import { computed, defineComponent, nextTick, onMounted, PropType, reactive } from 'vue'
  3. import { AnswerType, labelOptions, QuestionType } from '../../unit'
  4. import Draggable from 'vuedraggable'
  5. import styles from './index.module.less'
  6. import Sortable from 'sortablejs'
  7. import deepClone from '@/helpers/deep-clone'
  8. import AnserTitle from '../anser-title'
  9. import AnswerAnalysis from '../answer-analysis'
  10. // 单选和多选题
  11. export default defineComponent({
  12. name: 'choice-question',
  13. props: {
  14. value: {
  15. type: Array,
  16. default: () => []
  17. },
  18. index: {
  19. // 题目是第几道
  20. type: Number,
  21. default: 1
  22. },
  23. data: {
  24. type: Object,
  25. default: () => ({})
  26. },
  27. /* 只读 */
  28. readOnly: {
  29. type: Boolean,
  30. default: false
  31. },
  32. showRate: {
  33. // 是否显示答题的正确率
  34. type: Boolean,
  35. default: false
  36. },
  37. showAnalysis: {
  38. // 是否显示解析
  39. type: Boolean,
  40. default: false
  41. },
  42. analysis: {
  43. type: Object,
  44. default: () => ({
  45. message: '',
  46. topic: false, // 是否显示结果
  47. userResult: true // 用户答题对错
  48. })
  49. }
  50. },
  51. emits: ['update:value'],
  52. setup(props, { emit }) {
  53. const state = reactive({
  54. domId: 'draggableContainer' + +new Date(),
  55. drag: false,
  56. sortable: null as any,
  57. list: [] as any,
  58. options: [] as any
  59. })
  60. onMounted(() => {
  61. nextTick(() => {
  62. const el = document.getElementById(state.domId)
  63. state.sortable = Sortable.create(el, {
  64. disabled: props.readOnly,
  65. animation: 150,
  66. sort: true,
  67. fallbackTolerance: 3,
  68. onUpdate: (evt: any) => {
  69. const updatePosition = (list: any) =>
  70. list.splice(evt.newIndex, 0, list.splice(evt.oldIndex, 1)[0])
  71. if (state.list && state.list.length > 0) {
  72. updatePosition(state.list)
  73. } else {
  74. state.list = [...state.options]
  75. updatePosition(state.list)
  76. }
  77. onSelect()
  78. }
  79. })
  80. })
  81. })
  82. // 返回选中的结果
  83. const onSelect = () => {
  84. // const options = state.options || []
  85. const list = state.list || []
  86. const result: any = []
  87. console.log(list, '1212')
  88. list.forEach((item: any, index: number) => {
  89. console.log(index, '测试返回')
  90. result.push({
  91. answerId: item.index,
  92. answer: item.leftValue,
  93. answerExtra: index + 1
  94. })
  95. })
  96. emit('update:value', result)
  97. }
  98. // 修改题目逻辑
  99. const onSelectAnswer = (item: any) => {
  100. // 判断是否已经选中了
  101. if (item.checked) return
  102. const result: any = []
  103. state.options.forEach((option: any, index: any) => {
  104. result.push({
  105. answerId: option.index,
  106. answer: option.leftValue,
  107. answerExtra: index + 1
  108. })
  109. })
  110. result.push({
  111. answerId: item.examinationQuestionAnswerId,
  112. answer: item.questionAnswer,
  113. answerExtra: state.options.length + 1
  114. })
  115. emit('update:value', result)
  116. initOptions()
  117. }
  118. const answers = computed(() => {
  119. const list: any = props.data.answers || []
  120. const value: any = props.value || []
  121. list.forEach((item: any) => {
  122. const tempIndex = value.findIndex(
  123. (c: any) => c.answerId === item.examinationQuestionAnswerId
  124. )
  125. if (tempIndex !== -1) {
  126. item.checked = tempIndex !== -1 ? true : false
  127. }
  128. })
  129. return list
  130. })
  131. const initOptions = () => {
  132. const answers = props.data.answers || []
  133. const userAnswer = props.data.userAnswer || [] // 用户填写的答案
  134. console.log(answers, userAnswer)
  135. state.options = []
  136. if (userAnswer.length > 0) {
  137. userAnswer.forEach((answer: any, index: any) => {
  138. const rightOption = answers.find(
  139. (child: any) => answer.answerId === child.examinationQuestionAnswerId
  140. )
  141. const rightValue = answers.find(
  142. (child: any) => answer.answerExtra === child.questionExtra
  143. )
  144. const tmp = {
  145. itemIndex: index,
  146. index: answer.answerId, // 左边的值
  147. leftValue: answer.answer, // 左边的值
  148. rightValue: answer.answerExtra, // 右边的值
  149. leftType: rightOption.questionAnswerTypeCode || 'TXT', // 左边类型
  150. rightType: rightOption.questionExtraTypeCode || 'TXT', // 右边类型
  151. rightIndex: rightValue ? rightValue.examinationQuestionAnswerId : ''
  152. }
  153. state.options.push(tmp)
  154. })
  155. }
  156. // else {
  157. // const resultValue: any = []
  158. // answers.forEach((answer: any) => {
  159. // const tmp = {
  160. // index: answer.examinationQuestionAnswerId, // 左边的值
  161. // leftValue: answer.questionAnswer, // 左边的值
  162. // rightValue: answer.questionExtra, // 右边的值
  163. // leftType: answer.questionAnswerTypeCode || 'TXT', // 左边类型
  164. // rightType: answer.questionExtraTypeCode || 'TXT' // 右边类型
  165. // }
  166. // resultValue.push({
  167. // answerId: answer.examinationQuestionAnswerId,
  168. // answer: answer.questionAnswer,
  169. // answerExtra: answer.questionExtra
  170. // })
  171. // state.options.push(tmp)
  172. // })
  173. // // 进页面就默认初始化答案
  174. // }
  175. }
  176. onMounted(() => {
  177. initOptions()
  178. })
  179. return () => (
  180. <>
  181. <div class={styles.unitSubject}>
  182. {/* 标题 */}
  183. <AnserTitle
  184. index={props.index}
  185. name={props.data.name}
  186. showRate={props.showRate}
  187. score={props.data.totalScore}
  188. answerType={QuestionType.SORT}
  189. extra={{
  190. rightRate: props.data.rightRate,
  191. questionDetail: props.data.questionDetail,
  192. mediaUrls: props.data.mediaUrls
  193. }}
  194. />
  195. <div class={[styles.unitAnswers]}>
  196. {answers.value.map((item: any, index: number) => (
  197. <div
  198. class={[styles.unitAnswer, item.checked && styles.active]}
  199. onClick={() => onSelectAnswer(item)}
  200. >
  201. <div class={styles.answerContent}>
  202. <span class={styles.option}>{labelOptions[index + 1]}.</span>
  203. {item.questionAnswerTypeCode === AnswerType.IMAGE && (
  204. <div class={styles.value}>
  205. <Image src={item.questionAnswer} />
  206. </div>
  207. )}
  208. {item.questionAnswerTypeCode === AnswerType.TXT && (
  209. <div class={styles.value}>{item.questionAnswer}</div>
  210. )}
  211. </div>
  212. </div>
  213. ))}
  214. <div class={[styles.sortReset, 'van-hairline--top']}>
  215. <span class={styles.tips}>我的回答(可拖拽)</span>
  216. <Button
  217. type="primary"
  218. round
  219. disabled={props.readOnly}
  220. onClick={() => {
  221. const ids: any = []
  222. const answers = state.options || []
  223. // console.log(answers, 'reset')
  224. answers.forEach((item: any) => {
  225. ids.push(item.itemIndex)
  226. })
  227. console.log(ids)
  228. state.sortable.sort(
  229. ids.sort((a: any, b: any) => a - b),
  230. true
  231. )
  232. // state.options.forEach((item: any) => {
  233. // item.checked = false
  234. // })
  235. // state.list = []
  236. onSelect()
  237. }}
  238. >
  239. 重置
  240. </Button>
  241. </div>
  242. <div id={state.domId}>
  243. {state.options.map((item: any) => (
  244. <>
  245. {item.leftType === AnswerType.TXT && (
  246. <Tag class={[styles.items]} data-id={item.itemIndex}>
  247. {item.leftValue}
  248. </Tag>
  249. )}
  250. {item.leftType === AnswerType.IMAGE && (
  251. <Image
  252. src={item.leftValue}
  253. data-id={item.index}
  254. class={[styles.imgs, 'van-hairline--surround']}
  255. fit="cover"
  256. />
  257. )}
  258. </>
  259. ))}
  260. </div>
  261. </div>
  262. </div>
  263. {props.showAnalysis && (
  264. <div class={styles.unitSubject}>
  265. <AnswerAnalysis
  266. answerAnalysis={props.analysis.message}
  267. topic={props.analysis.topic}
  268. userResult={props.analysis.userResult}
  269. />
  270. </div>
  271. )}
  272. </>
  273. )
  274. }
  275. })