select-question.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. <template>
  2. <!-- 选择题 -->
  3. <view class="select-area" v-model="questionData">
  4. <view class="question_title">
  5. <text class="question_number">
  6. {{ questionNumberEndIsBracket(questionData.property.question_number) }}
  7. </text>
  8. <text class="question_stem" v-html="sanitizeHTML(questionData.stem)"
  9. :ref="'richText-1-1'+questionData.question_id"
  10. @longpress="previewByRichTextImg(-1,-1,questionData.question_id)">
  11. </text>
  12. </view>
  13. <view class="description"
  14. v-if="isEnable(questionData.property.is_enable_description)&&questionData.description.length > 0"
  15. v-html="sanitizeHTML(questionData.description)" :ref="'richText-2-2'+questionData.question_id"
  16. @longpress="previewByRichTextImg(-2,-2,questionData.question_id)">
  17. </view>
  18. <template v-if="isSubdivision">
  19. <view class="selected-area">
  20. <view class="selected-box" v-for="(item, indexI) in questionData.option_list">
  21. <text class="serial-number" :style="{'font-size':questionData.property.option_question_number_font_size}">
  22. {{ isEnable(isEnableManualModify)?(item.custom_number?item.custom_number+'.':''):computedQuestionNumber(indexI,questionData.option_number_show_mode) }}
  23. </text>
  24. <view class="selected-cell-box">
  25. <view v-for="(opt, indexO) in item.data_list" :key="opt.mark"
  26. :class="['selected-cell', { active: isAnswer(opt.mark,item.mark) },...computedAnswerClass(opt.mark,item.mark)]"
  27. @click="selectAnswer(opt.mark,item.mark)">
  28. <text class="content" v-html="sanitizeHTML(opt.content)"
  29. :ref="'richText'+indexI+indexO+questionData.question_id"
  30. @longpress="previewByRichTextImg(indexI,indexO,questionData.question_id)"></text>
  31. </view>
  32. </view>
  33. </view>
  34. </view>
  35. </template>
  36. <template v-else>
  37. <view class="radio-area" v-if="viewSingle">
  38. <radio-group @change="radioChange">
  39. <label :class="['uni-list-cell', { active: isAnswer(item.mark) },...computedAnswerClass(item.mark)]"
  40. v-for="(item, index) in questionData.option_list" :key="item.mark">
  41. <view>
  42. <radio :value="item.mark" :checked="index === current" style="transform: scale(0.7); margin-right: 24rpx"
  43. color="#306EFF" :disabled="answer_control[questionData.question_id].isReadOnly" />
  44. </view>
  45. <text class="serial-number" :style="{'font-size':questionData.property.option_question_number_font_size}">
  46. {{ isEnable(isEnableManualModify)?(item.custom_number?item.custom_number+'.':''):computedQuestionNumber(index,questionData.option_number_show_mode) }}
  47. </text>
  48. <text class="content" v-html="sanitizeHTML(item.content)" :ref="'richText'+index+1+questionData.question_id"
  49. @longpress="previewByRichTextImg(index,1,questionData.question_id)"></text>
  50. </label>
  51. </radio-group>
  52. </view>
  53. <view class="checkbox-area" v-else>
  54. <checkbox-group @change="checkboxChange">
  55. <label :class="['uni-list-cell', { active: isAnswer(item.mark) },...computedAnswerClass(item.mark)]"
  56. v-for="(item, index) in questionData.option_list" :key="item.mark">
  57. <view>
  58. <checkbox :value="item.mark" :checked="item.checked" style="transform: scale(0.7); margin-right: 24rpx;"
  59. color="#306EFF" :disabled="answer_control[questionData.question_id].isReadOnly" />
  60. </view>
  61. <text class="serial-number" :style="{'font-size':questionData.property.option_question_number_font_size}">
  62. {{ isEnable(isEnableManualModify)?(item.custom_number?item.custom_number+'.':''):computedQuestionNumber(index,questionData.option_number_show_mode) }}
  63. </text>
  64. <text class="content" v-html="sanitizeHTML(item.content)" :ref="'richText'+index+1+questionData.question_id"
  65. @longpress="previewByRichTextImg(index,1,questionData.question_id)"></text>
  66. </label>
  67. </checkbox-group>
  68. </view>
  69. </template>
  70. <view class="reference" v-if="isViewAnalysis&&answer_control[questionData.question_id].isViewRightAnswer">
  71. <text class="reference-title">解析</text>
  72. <text class="reference-answer" v-html="sanitizeHTML(questionData.analysis)"
  73. :ref="'richText-3-3'+questionData.question_id"
  74. @longpress="previewByRichTextImg(-3,-3,questionData.question_id)">
  75. </text>
  76. </view>
  77. </view>
  78. </template>
  79. <script>
  80. import {
  81. selectTypeList,
  82. questionData,
  83. sanitizeHTML,
  84. isEnable,
  85. computedQuestionNumber,
  86. answer_control
  87. } from '@/pages/answer_question/common/data/common.js';
  88. import {
  89. changeNumToHan,
  90. checkNum
  91. } from '@/utils/transform.js';
  92. import AnswerControlMixin from '@/pages/answer_question/common/data/AnswerControlMixin.js';
  93. export default {
  94. name: "select-question",
  95. mixins: [AnswerControlMixin],
  96. props: {
  97. questionData: questionData,
  98. isEnableManualModify: {
  99. type: String,
  100. default: 'false',
  101. },
  102. },
  103. data() {
  104. return {
  105. computedQuestionNumber,
  106. isEnable,
  107. sanitizeHTML,
  108. current: -1,
  109. answer_control,
  110. }
  111. },
  112. watch: {
  113. 'questionData.question_id': {
  114. handler(val) {
  115. this.setUserAnswer();
  116. },
  117. immediate: true,
  118. deep: true
  119. }
  120. },
  121. computed: {
  122. viewSingle: function() {
  123. return this.questionData.property.select_type === selectTypeList[0].value ? true : false;
  124. },
  125. isSubdivision() {
  126. return isEnable(this.questionData.property.is_option_subdivision);
  127. },
  128. isViewAnalysis: function() {
  129. return isEnable(this.questionData.property.is_enable_analysis);
  130. }
  131. },
  132. methods: {
  133. selectAnswer(mark, parent_mark) {
  134. if (this.answer_control[this.questionData.question_id].isReadOnly) return;
  135. let _answer_list = this.questionData.user_answer[this.questionData.question_id].answer_list;
  136. const en = _answer_list.find(item => item.mark === parent_mark);
  137. if (en == undefined) {
  138. _answer_list.push({
  139. 'mark': parent_mark,
  140. 'value_list': [mark],
  141. });
  142. } else {
  143. if (this.viewSingle) {
  144. en.value_list = [mark];
  145. } else {
  146. let markIndex = en.value_list.findIndex(p => p === mark);
  147. if (markIndex !== -1) {
  148. //存在删除
  149. en.value_list.splice(markIndex, 1);
  150. } else {
  151. //不存在添加
  152. en.value_list.push(mark);
  153. }
  154. }
  155. }
  156. this.isAnswer(mark, parent_mark);
  157. this.$forceUpdate();
  158. this.saveUserAnswer();
  159. },
  160. radioChange: function(e) {
  161. if (this.answer_control[this.questionData.question_id].isReadOnly) return;
  162. this.questionData.user_answer[this.questionData.question_id].answer_list = [e.detail.value];
  163. this.current = this.questionData.option_list.findIndex(p => p.mark === e.detail.value);
  164. this.saveUserAnswer();
  165. },
  166. checkboxChange: function(e) {
  167. if (this.answer_control[this.questionData.question_id].isReadOnly) return;
  168. this.questionData.user_answer[this.questionData.question_id].answer_list = e.detail.value;
  169. this.questionData.option_list.forEach(p => {
  170. p.checked = false
  171. if (e.detail.value.find(x => x === p.mark))
  172. p.checked = true
  173. })
  174. this.saveUserAnswer();
  175. },
  176. //切换选项保存答案
  177. saveUserAnswer: function() {
  178. var questionId = this.questionData.question_id;
  179. this.questionData.user_answer[questionId].isEdit = true;
  180. var ansed = this.questionData.user_answer[questionId].answer_list;
  181. this.questionData.user_answer[questionId].is_fill_answer = ansed.length > 0;
  182. this.questionData.user_answer[questionId].content = JSON.stringify(ansed);
  183. this.questionData.user_answer[questionId].answer_list = ansed;
  184. this.$emit("setSubAnswer", this.questionData.user_answer[questionId], questionId);
  185. },
  186. //回显
  187. setUserAnswer: function() {
  188. var that = this;
  189. var callback = function() {
  190. var userAnswer = [];
  191. var questionId = that.questionData.question_id;
  192. var _ua = that.questionData.user_answer[questionId];
  193. if (_ua && _ua.answer_list && _ua.answer_list.length > 0)
  194. userAnswer = _ua.answer_list;
  195. if (userAnswer.length == 0) return;
  196. if (that.isSubdivision) {
  197. that.questionData.option_list.forEach(p => {
  198. if (that.viewSingle) {
  199. let find_mark = userAnswer.find(x => x.mark === p.mark);
  200. that.isAnswer(find_mark.value_list[0], find_mark.mark);
  201. that.computedAnswerClass(find_mark.value_list[0], find_mark.mark);
  202. that.$forceUpdate();
  203. } else {
  204. userAnswer.forEach((m, i) => {
  205. if (p.mark === m.mark) {
  206. that.isAnswer(m.value_list[i], m.mark);
  207. that.computedAnswerClass(m.value_list[i], m.mark);
  208. that.$forceUpdate();
  209. }
  210. });
  211. }
  212. })
  213. } else {
  214. if (that.viewSingle) {
  215. that.current = that.questionData.option_list.findIndex(p => p.mark === userAnswer[0]);
  216. } else {
  217. that.questionData.option_list.forEach(p => {
  218. if (userAnswer.find(x => x === p.mark))
  219. p.checked = true
  220. })
  221. }
  222. }
  223. };
  224. if (that.questionData.isSubSub) {
  225. callback();
  226. } else {
  227. this.$emit("getUserAnswer", this.questionData.question_id, callback);
  228. }
  229. },
  230. //是否标准答案
  231. isAnswer(mark, parent_mark) {
  232. setTimeout(function() {});
  233. if (this.isSubdivision) {
  234. return this.questionData.user_answer[this.questionData.question_id].answer_list.find((item) => item
  235. .mark === parent_mark)?.value_list?.includes(mark);
  236. }
  237. return this.questionData.user_answer[this.questionData.question_id].answer_list.includes(mark);
  238. },
  239. computedAnswerClass(mark, parent_mark) {
  240. var cur = this.commonComputedAnswerControl(this.questionData.question_id);
  241. if (!cur.isJudgeAnswer && !cur.isViewRightAnswer) {
  242. return [];
  243. }
  244. let answer_list = this.questionData.user_answer[this.questionData.question_id].answer_list;
  245. let isHas = this.isSubdivision ?
  246. answer_list.find((item) => item.mark === parent_mark)?.value_list?.includes(mark) :
  247. answer_list.includes(mark); // 是否已选中的选项
  248. let isRight = this.isSubdivision ?
  249. this.questionData.answer.answer_list.find((item) => item.mark === parent_mark)?.value_list?.includes(mark) :
  250. this.questionData.answer.answer_list.includes(mark);
  251. //显示标准答案
  252. if (!isHas && cur.isViewRightAnswer) {
  253. return isRight ? ['answer-right'] : [];
  254. }
  255. //判断对错
  256. if (cur.isJudgeAnswer) {
  257. return isRight ? ['right'] : ['wrong'];
  258. }
  259. return [];
  260. },
  261. }
  262. }
  263. </script>
  264. <style lang="scss" scoped>
  265. .select-area {
  266. .selected-area {
  267. margin: 32rpx 0;
  268. display: flex;
  269. flex-direction: column;
  270. row-gap: 32rpx;
  271. .selected-box {
  272. display: flex;
  273. flex-direction: row;
  274. align-items: center;
  275. column-gap: 32rpx;
  276. .serial-number {
  277. font-size: $font-size-serial;
  278. align-self: flex-start;
  279. margin-top: 18rpx;
  280. }
  281. .selected-cell-box {
  282. display: flex;
  283. flex-wrap: wrap;
  284. column-gap: 32rpx;
  285. row-gap: 16rpx;
  286. .selected-cell {
  287. display: flex;
  288. flex-wrap: nowrap;
  289. padding: 24rpx 48rpx;
  290. border-radius: 80rpx;
  291. font-size: $font-size-serial;
  292. background-color: $uni-bg-color-grey;
  293. &.answer-right {
  294. background-color: $right-bc-color;
  295. }
  296. &.active {
  297. color: #34343a;
  298. background-color: $main-active-color;
  299. &.right {
  300. background-color: $uni-bg-color-grey;
  301. border: 1px solid $right-color;
  302. }
  303. &.wrong {
  304. background-color: $uni-bg-color-grey;
  305. border: 1px solid $error-color;
  306. }
  307. }
  308. }
  309. }
  310. }
  311. }
  312. .uni-list-cell {
  313. display: flex;
  314. column-gap: 8rpx;
  315. align-items: center;
  316. padding: 24rpx 48rpx;
  317. border-radius: 80rpx;
  318. margin: 32rpx auto;
  319. font-size: $font-size-serial;
  320. background-color: $uni-bg-color-grey;
  321. .serial-number {
  322. align-self: flex-start;
  323. }
  324. .content {
  325. flex: 1;
  326. }
  327. &.answer-right {
  328. background-color: $right-bc-color;
  329. &::after {
  330. font-size: 14px;
  331. color: $right-color;
  332. content: '正确答案';
  333. }
  334. }
  335. &.active {
  336. color: #34343a;
  337. background-color: $main-active-color;
  338. &.right {
  339. background-color: $uni-bg-color-grey;
  340. border: 1px solid $right-color;
  341. &::after {
  342. font-size: 14px;
  343. color: $right-color;
  344. content: '已选';
  345. }
  346. }
  347. &.wrong {
  348. background-color: $uni-bg-color-grey;
  349. border: 1px solid $error-color;
  350. &::after {
  351. font-size: 14px;
  352. color: $error-color;
  353. content: '已选';
  354. }
  355. }
  356. }
  357. }
  358. .reference {
  359. margin: 32rpx 0;
  360. background-color: #f9f8f9;
  361. padding: 24rpx;
  362. .reference-title {
  363. display: block;
  364. line-height: 64rpx;
  365. color: #4E5969;
  366. font-size: 28rpx;
  367. }
  368. .reference-answer {
  369. color: #1D2129;
  370. line-height: 48rpx;
  371. font-size: 14pt;
  372. }
  373. }
  374. }
  375. </style>