FillQuestion.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <template>
  2. <QuestionBase>
  3. <template #content>
  4. <div class="stem">
  5. <RichText v-model="data.stem" :font-size="18" placeholder="输入题干" />
  6. <el-input
  7. v-if="isEnable(data.property.is_enable_description)"
  8. v-model="data.description"
  9. rows="3"
  10. resize="none"
  11. type="textarea"
  12. placeholder="输入填空内容"
  13. />
  14. </div>
  15. <div class="content">
  16. <RichText
  17. ref="modelEssay"
  18. v-model="data.article"
  19. :is-fill="true"
  20. :toolbar="false"
  21. :wordlimit-num="false"
  22. placeholder="输入文段"
  23. />
  24. <el-button @click="identifyText">识别</el-button>
  25. <div v-if="data.answer.answer_list.length > 0" class="correct-answer">
  26. <div class="subtitle">正确答案</div>
  27. <el-input
  28. v-for="(item, i) in data.answer.answer_list.filter(({ type }) => type === 'any_one')"
  29. :key="item.mark"
  30. v-model="item.value"
  31. @blur="handleTone(item.value, i)"
  32. >
  33. <span slot="prefix">{{ i + 1 }}.</span>
  34. </el-input>
  35. </div>
  36. </div>
  37. </template>
  38. <template #property>
  39. <el-form :model="data.property" label-width="72px" label-position="left">
  40. <el-form-item label="题号">
  41. <el-input v-model="data.property.question_number" />
  42. </el-form-item>
  43. <el-form-item>
  44. <el-radio
  45. v-for="{ value, label } in questionNumberTypeList"
  46. :key="value"
  47. v-model="data.other.question_number_type"
  48. :label="value"
  49. >
  50. {{ label }}
  51. </el-radio>
  52. </el-form-item>
  53. <el-form-item label="题干题号">
  54. <el-select v-model="data.property.stem_question_number_font_size">
  55. <el-option v-for="item in fontSizeList" :key="item" :label="item" :value="item" />
  56. </el-select>
  57. </el-form-item>
  58. <el-form-item label="描述">
  59. <el-radio
  60. v-for="{ value, label } in switchOption"
  61. :key="value"
  62. v-model="data.property.is_enable_description"
  63. :label="value"
  64. >
  65. {{ label }}
  66. </el-radio>
  67. </el-form-item>
  68. <el-form-item label="分值">
  69. <el-radio
  70. v-for="{ value, label } in scoreTypeList"
  71. :key="value"
  72. v-model="data.property.score_type"
  73. :label="value"
  74. >
  75. {{ label }}
  76. </el-radio>
  77. </el-form-item>
  78. <el-form-item>
  79. <el-input-number
  80. v-model="data.property.score"
  81. :min="0"
  82. :step="data.property.score_type === scoreTypeList[0].value ? 1 : 0.1"
  83. />
  84. </el-form-item>
  85. </el-form>
  86. </template>
  87. </QuestionBase>
  88. </template>
  89. <script>
  90. import QuestionMixin from '../common/QuestionMixin.js';
  91. import { getRandomNumber } from '@/utils';
  92. import { addTone } from '@/views/exercise_questions/data/common';
  93. import { fillData, handleToneValue } from '@/views/exercise_questions/data/fill';
  94. export default {
  95. name: 'FillQuestion',
  96. mixins: [QuestionMixin],
  97. data() {
  98. return {
  99. data: JSON.parse(JSON.stringify(fillData)),
  100. };
  101. },
  102. methods: {
  103. // 识别文本
  104. identifyText() {
  105. this.data.model_essay = [];
  106. this.data.answer.answer_list = [];
  107. this.data.article
  108. .split(/<p.*?>(.*?)<\/p>/gi)
  109. .filter((item) => item)
  110. .forEach((item) => {
  111. if (item.charCodeAt() === 10) return;
  112. let str = item
  113. // 去除所有的 font-size 样式
  114. .replace(/font-size:\s*\d+(\.\d+)?px;/gi, '')
  115. // 匹配 class 名为 rich-fill 的 span 标签和三个以上的_,并将它们组成数组
  116. .replace(/<span class="rich-fill".*?>(.*?)<\/span>|([_]{3,})/gi, '###$1$2###');
  117. this.data.model_essay.push(this.splitRichText(str));
  118. });
  119. },
  120. // 分割富文本
  121. splitRichText(str) {
  122. let _str = str;
  123. let start = 0;
  124. let index = 0;
  125. let arr = [];
  126. let matchNum = 0;
  127. while (index !== -1) {
  128. index = _str.indexOf('###', start);
  129. if (index === -1) break;
  130. matchNum += 1;
  131. arr.push({ content: _str.slice(start, index), type: 'text' });
  132. if (matchNum % 2 === 0 && arr.length > 0) {
  133. arr[arr.length - 1].type = 'input';
  134. let mark = getRandomNumber();
  135. arr[arr.length - 1].mark = mark;
  136. let content = arr[arr.length - 1].content;
  137. // 设置答案数组
  138. let isUnderline = /^_{3,}$/.test(content);
  139. this.data.answer.answer_list.push({
  140. value: isUnderline ? '' : content,
  141. mark,
  142. type: isUnderline ? 'any_one' : 'only_one',
  143. });
  144. // 将 content 设置为空,为预览准备
  145. arr[arr.length - 1].content = '';
  146. }
  147. start = index + 3;
  148. }
  149. let last = _str.slice(start);
  150. if (last) {
  151. arr.push({ content: last, type: 'text' });
  152. }
  153. return arr;
  154. },
  155. handleTone(value, i) {
  156. if (!/^[a-zA-Z0-9\s]+$/.test(value)) return;
  157. this.data.answer.answer_list[i].value = value
  158. .trim()
  159. .split(/\s+/)
  160. .map((item) => {
  161. return handleToneValue(item);
  162. })
  163. .map((item) =>
  164. item.map(({ number, con }) => (number && con ? addTone(Number(number), con) : number || con || '')),
  165. )
  166. .filter((item) => item.length > 0)
  167. .join(' ');
  168. },
  169. },
  170. };
  171. </script>
  172. <style lang="scss" scoped>
  173. .content {
  174. position: relative;
  175. .el-button {
  176. margin-top: 8px;
  177. }
  178. .correct-answer {
  179. .subtitle {
  180. margin: 8px 0;
  181. font-size: 14px;
  182. color: #4e5969;
  183. }
  184. .el-input {
  185. width: 180px;
  186. :deep &__prefix {
  187. display: flex;
  188. align-items: center;
  189. color: $text-color;
  190. }
  191. + .el-input {
  192. margin-left: 8px;
  193. }
  194. }
  195. }
  196. }
  197. </style>