InputPreview.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <!-- eslint-disable vue/no-v-html -->
  2. <template>
  3. <div class="input-preview" :style="getAreaStyle()">
  4. <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
  5. <div class="main" :style="getMainStyle()">
  6. <span class="rich-text" v-html="convertText(sanitizeHTML(data.content))"></span>
  7. <el-input
  8. ref="input"
  9. v-model="data.answer.text"
  10. type="text"
  11. :style="{
  12. cursor: disabled ? 'not-allowed' : 'pointer',
  13. font: data.property.font,
  14. fontSize: data.property.font_size + 'px',
  15. color: data.property.text_color,
  16. }"
  17. :disabled="disabled"
  18. :class="[
  19. 'input',
  20. { 'input-horizontal': data.property.input_style === inputStyleList[0].value },
  21. `input-${data.property.text_align}`,
  22. ]"
  23. @change="onInputChange"
  24. />
  25. <div v-show="showLang" class="lang">
  26. {{ data.multilingual.find((item) => item.type === getLang())?.translation }}
  27. </div>
  28. </div>
  29. <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @retry="retry" />
  30. <AnswerCorrect
  31. :answer-correct="data?.answer_correct"
  32. :visible.sync="visibleAnswerCorrect"
  33. @closeAnswerCorrect="closeAnswerCorrect"
  34. />
  35. <AnswerAnalysis
  36. :visible.sync="visibleAnswerAnalysis"
  37. :answer-list="data.answer_list"
  38. :analysis-list="data.analysis_list"
  39. @closeAnswerAnalysis="closeAnswerAnalysis"
  40. />
  41. </div>
  42. </template>
  43. <script>
  44. import { getInputData, inputStyleList } from '@/views/book/courseware/data/input';
  45. import { addTone, handleToneValue } from '@/utils/common';
  46. import PreviewMixin from '../common/PreviewMixin';
  47. export default {
  48. name: 'InputPreview',
  49. mixins: [PreviewMixin],
  50. data() {
  51. return {
  52. data: getInputData(),
  53. inputStyleList,
  54. };
  55. },
  56. watch: {
  57. 'data.answer.text'(newVal) {
  58. this.answer.text = newVal;
  59. },
  60. answer(newVal) {
  61. this.data.answer.text = newVal?.text || '';
  62. },
  63. },
  64. mounted() {
  65. this.$nextTick(() => {
  66. this.$refs.input.$el.querySelector('.el-input__inner').style.backgroundColor =
  67. this.data.property.background_color;
  68. });
  69. },
  70. methods: {
  71. // 输入后输入框根据property属性,更新内容
  72. onInputChange() {
  73. if (!this.data.property.is_enable_pinyin) {
  74. return;
  75. }
  76. let answer = this.data.answer.text;
  77. // 句首大写
  78. if (this.data.property.is_enable_sentence_case) {
  79. answer = answer.charAt(0).toUpperCase() + answer.slice(1);
  80. }
  81. // 自动修正为拼音
  82. if (this.data.property.is_enable_auto_correct) {
  83. answer = answer
  84. .trim()
  85. .split(/\s+/)
  86. .map((item) => {
  87. return handleToneValue(item);
  88. })
  89. .map((item) =>
  90. item.map(({ number, con }) => (number && con ? addTone(Number(number), con) : number || con || '')),
  91. )
  92. .filter((item) => item.length > 0)
  93. .join(' ');
  94. }
  95. this.data.answer.text = answer;
  96. },
  97. getMainStyle() {
  98. return {
  99. gridTemplateAreas: this.showLang ? "'rich input' 'lang lang'" : "'rich input'",
  100. };
  101. },
  102. retry() {
  103. this.data.answer.text = '';
  104. },
  105. },
  106. };
  107. </script>
  108. <style lang="scss" scoped>
  109. @use '@/styles/mixin.scss' as *;
  110. .input-preview {
  111. @include preview-base;
  112. .main {
  113. display: grid;
  114. grid-template-columns: auto 1fr;
  115. gap: 4px;
  116. align-items: center;
  117. .rich-text {
  118. grid-area: rich;
  119. :deep p {
  120. word-break: keep-all;
  121. }
  122. }
  123. .input {
  124. grid-area: input;
  125. }
  126. .input.input-horizontal :deep .el-input__inner {
  127. background-color: #fff;
  128. border-top-width: 0;
  129. border-right-width: 0;
  130. border-bottom: 1px solid #333;
  131. border-left-width: 0;
  132. border-radius: 0;
  133. }
  134. .input.input-left :deep .el-input__inner {
  135. text-align: left;
  136. }
  137. .input.input-center :deep .el-input__inner {
  138. text-align: center;
  139. }
  140. .input.input-right :deep .el-input__inner {
  141. text-align: right;
  142. }
  143. .input :deep .el-input__inner {
  144. color: currentColor;
  145. }
  146. }
  147. }
  148. </style>