| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 | 
							- <template>
 
-   <QuestionBase>
 
-     <template #content>
 
-       <div class="stem">
 
-         <RichText v-model="data.stem" :font-size="18" placeholder="输入题干" />
 
-         <RichText
 
-           v-if="isEnable(data.property.is_enable_description)"
 
-           v-model="data.description"
 
-           placeholder="输入提示"
 
-         />
 
-       </div>
 
-       <div class="content">
 
-         <label class="subtitle">内容</label>
 
-         <ul>
 
-           <li v-for="(item, i) in data.option_list" :key="i" class="content-item">
 
-             <span class="question-number" title="双击切换序号类型" @dblclick="changeOptionType(data)">
 
-               {{ computedQuestionNumber(i, data.option_number_show_mode) }}
 
-             </span>
 
-             <el-input v-model="item.character" :placeholder="'汉字'" style="flex-shrink: 0; width: 80px" />
 
-             <el-input
 
-               v-model="item.content"
 
-               placeholder="拼音间用空格隔开,如:ni3 hao3"
 
-               @blur="handleItemAnswer(item)"
 
-               @change="changePinyin(item)"
 
-             />
 
-             <el-input
 
-               v-model="matically_pinyin_str[item.mark]"
 
-               :placeholder="'拼音预览'"
 
-               :readonly="true"
 
-               style="width: 200px"
 
-             />
 
-             <div v-if="item.audio_file_id">
 
-               <SoundRecord :wav-blob.sync="item.audio_file_id" />
 
-             </div>
 
-             <template v-else>
 
-               <div :class="['upload-audio-play']">
 
-                 <UploadAudio
 
-                   v-if="data.other.audio_generation_method === 'upload'"
 
-                   :key="item.audio_file_id || i"
 
-                   :file-id="item.audio_file_id"
 
-                   :item-index="i"
 
-                   :show-upload="!item.audio_file_id"
 
-                   @upload="uploads"
 
-                   @deleteFile="deleteFiles"
 
-                 />
 
-                 <div
 
-                   v-else-if="data.other.audio_generation_method === 'auto'"
 
-                   v-loading="loading_list[i] ? loading_list[i].loading : false"
 
-                   class="auto-matically"
 
-                   @click="handleMatically(item, i)"
 
-                 >
 
-                   <SvgIcon icon-class="voiceprint-line" class="record" />
 
-                   <span class="auto-btn">{{ item.audio_file_id ? '已生成' : '生成音频' }}</span>
 
-                 </div>
 
-                 <SoundRecord v-else :wav-blob.sync="item.audio_file_id" />
 
-               </div>
 
-             </template>
 
-             <SvgIcon icon-class="delete" class="delete pointer" @click="deleteOption(i, item.audio_file_id)" />
 
-           </li>
 
-         </ul>
 
-       </div>
 
-       <div class="footer">
 
-         <span class="add-option" @click="addOption">
 
-           <SvgIcon icon-class="add-circle" size="14" /> <span>增加选项</span>
 
-         </span>
 
-       </div>
 
-       <div v-if="isEnable(data.property.is_enable_analysis)" class="analysis">
 
-         <div class="analysis-title">解析:</div>
 
-         <RichText v-model="data.analysis" :is-border="true" :font-size="14" placeholder="输入解析" />
 
-       </div>
 
-     </template>
 
-     <template #property>
 
-       <el-form :model="data.property" label-width="72px" label-position="left">
 
-         <el-form-item label="题号">
 
-           <el-input v-model="data.property.question_number" />
 
-         </el-form-item>
 
-         <el-form-item>
 
-           <el-radio
 
-             v-for="{ value, label } in questionNumberTypeList"
 
-             :key="value"
 
-             v-model="data.other.question_number_type"
 
-             :label="value"
 
-           >
 
-             {{ label }}
 
-           </el-radio>
 
-         </el-form-item>
 
-         <el-form-item label="题干题号">
 
-           <el-select v-model="data.property.stem_question_number_font_size">
 
-             <el-option v-for="item in fontSizeList" :key="item" :label="item" :value="item" />
 
-           </el-select>
 
-         </el-form-item>
 
-         <el-form-item label="选项题号">
 
-           <el-select v-model="data.property.option_question_number_font_size">
 
-             <el-option v-for="item in fontSizeList" :key="item" :label="item" :value="item" />
 
-           </el-select>
 
-         </el-form-item>
 
-         <el-form-item label="提示">
 
-           <el-radio
 
-             v-for="{ value, label } in switchOption"
 
-             :key="value"
 
-             v-model="data.property.is_enable_description"
 
-             :label="value"
 
-           >
 
-             {{ label }}
 
-           </el-radio>
 
-         </el-form-item>
 
-         <el-form-item label="解析">
 
-           <el-radio
 
-             v-for="{ value, label } in switchOption"
 
-             :key="value"
 
-             v-model="data.property.is_enable_analysis"
 
-             :label="value"
 
-           >
 
-             {{ label }}
 
-           </el-radio>
 
-         </el-form-item>
 
-         <el-form-item label="分值">
 
-           <el-radio
 
-             v-for="{ value, label } in scoreTypeList"
 
-             :key="value"
 
-             v-model="data.property.score_type"
 
-             :label="value"
 
-           >
 
-             {{ label }}
 
-           </el-radio>
 
-         </el-form-item>
 
-         <el-form-item>
 
-           <el-input-number
 
-             v-model="data.property.score"
 
-             :min="0"
 
-             :step="data.property.score_type === scoreTypeList[0].value ? 1 : 0.1"
 
-           />
 
-         </el-form-item>
 
-         <el-form-item label="类型">
 
-           <el-radio
 
-             v-for="{ value, label } in toneTypeList"
 
-             :key="value"
 
-             v-model="data.property.answer_mode"
 
-             :label="value"
 
-             @change="handleChangeType"
 
-           >
 
-             {{ label }}
 
-           </el-radio>
 
-         </el-form-item>
 
-         <el-form-item label="音频">
 
-           <el-radio
 
-             v-for="{ value, label } in audioGenerationMethodList"
 
-             :key="value"
 
-             v-model="data.other.audio_generation_method"
 
-             :label="value"
 
-           >
 
-             {{ label }}
 
-           </el-radio>
 
-         </el-form-item>
 
-       </el-form>
 
-     </template>
 
-   </QuestionBase>
 
- </template>
 
- <script>
 
- import QuestionMixin from '@/views/exercise_questions/create/components/common/QuestionMixin';
 
- import UploadAudio from '../common/UploadAudio.vue';
 
- import SoundRecord from '../common/SoundRecord.vue';
 
- import { changeOptionType, addTone } from '@/views/exercise_questions/data/common';
 
- import {
 
-   getOption,
 
-   ChooseToneData,
 
-   audioGenerationMethodList,
 
-   toneList,
 
-   toneTypeList,
 
-   analysisRecognitionChooseToneData,
 
- } from '@/views/exercise_questions/data/chooseTone';
 
- import { GetStaticResources } from '@/api/app';
 
- export default {
 
-   name: 'ChooseToneQuestion',
 
-   components: {
 
-     UploadAudio,
 
-     SoundRecord,
 
-   },
 
-   mixins: [QuestionMixin],
 
-   data() {
 
-     return {
 
-       toneList,
 
-       changeOptionType,
 
-       audioGenerationMethodList,
 
-       toneTypeList,
 
-       data: JSON.parse(JSON.stringify(ChooseToneData)),
 
-       matically_pinyin_obj: {}, // 存放转成声调的拼音
 
-       matically_pinyin_str: {}, // 存放转成声调的字符串
 
-       res_arr: [],
 
-       loading_list: [
 
-         {
 
-           loading: false,
 
-         },
 
-         {
 
-           loading: false,
 
-         },
 
-         {
 
-           loading: false,
 
-         },
 
-       ],
 
-     };
 
-   },
 
-   watch: {
 
-     'data.option_list.length': {
 
-       handler(val) {
 
-         this.loading_list = [];
 
-         for (let i = 0; i < val; i++) {
 
-           let obj = {
 
-             loading: false,
 
-           };
 
-           this.loading_list.push(obj);
 
-         }
 
-         this.handleChangeType();
 
-       },
 
-       deep: true,
 
-       immediate: true,
 
-     },
 
-     'data.option_list': {
 
-       handler(val) {
 
-         if (!val) return;
 
-         // 删除答案中不存在的选项
 
-         this.data.answer.answer_list.forEach((item, i) => {
 
-           if (!val.find((li) => li.mark === item.mark)) {
 
-             this.data.answer.answer_list.splice(i, 1);
 
-           }
 
-         });
 
-       },
 
-     },
 
-   },
 
-   created() {},
 
-   methods: {
 
-     addOption() {
 
-       this.data.option_list.push(getOption());
 
-     },
 
-     uploads(file_id, index) {
 
-       this.data.option_list[index].audio_file_id = file_id;
 
-       this.data.file_id_list.push(file_id);
 
-     },
 
-     deleteFiles(file_id, itemIndex) {
 
-       this.data.option_list[itemIndex].audio_file_id = '';
 
-       this.data.file_id_list.splice(this.data.file_id_list.indexOf(file_id), 1);
 
-     },
 
-     /**
 
-      * 删除音频 id
 
-      * @param {number} i 选项下标
 
-      */
 
-     deleteAudio(i) {
 
-       this.data.file_id_list.splice(this.data.file_id_list.indexOf(this.data.option_list[i].audio_file_id), 1);
 
-       this.data.option_list[i].audio_file_id = '';
 
-     },
 
-     // 删除小题
 
-     deleteOption(i, file_id) {
 
-       this.$confirm('是否删除?', '提示', {
 
-         confirmButtonText: '确定',
 
-         cancelButtonText: '取消',
 
-         type: 'warning',
 
-       })
 
-         .then(() => {
 
-           this.data.option_list.splice(i, 1);
 
-           this.data.file_id_list.splice(this.data.file_id_list.indexOf(file_id), 1);
 
-           this.loading_list.splice(i, 1);
 
-         })
 
-         .catch(() => {});
 
-     },
 
-     // 自动生成音频
 
-     handleMatically(item, i) {
 
-       let MethodName = 'tool-TextToVoiceFile';
 
-       let data = {};
 
-       if (item.character.trim() || item.content_hz) {
 
-         data = {
 
-           text: item.character.trim() || item.content_hz,
 
-         };
 
-       } else if (item.content.trim()) {
 
-         if (!this.matically_pinyin_obj[item.mark]) {
 
-           this.handleItemAnswer(item);
 
-         }
 
-         MethodName = 'tool-PinyinToVoiceFile';
 
-         data = {
 
-           pinyin: this.matically_pinyin_obj[item.mark],
 
-         };
 
-       }
 
-       this.loading_list[i].loading = true;
 
-       GetStaticResources(MethodName, data)
 
-         .then((res) => {
 
-           this.loading_list[i].loading = false;
 
-           if (res.status === 1) {
 
-             item.audio_file_id = res.file_id;
 
-             this.data.file_id_list.push(res.file_id);
 
-           }
 
-         })
 
-         .catch(() => {
 
-           this.loading_list[i].loading = false;
 
-         });
 
-     },
 
-     handleReplaceTone(value, mark, itemIndex) {
 
-       if (!value) return;
 
-       value.split(/\s+/).forEach((item) => {
 
-         this.handleValue(item);
 
-       });
 
-       this.matically_pinyin_obj[mark] = this.res_arr
 
-         .map((item) =>
 
-           item.map(({ number, con }) => (number && con ? addTone(Number(number), con) : number || con || '')),
 
-         )
 
-         .filter((item) => item.length > 0)
 
-         .join(',');
 
-       this.matically_pinyin_str[mark] = this.res_arr
 
-         .map((item) =>
 
-           item.map(({ number, con }) => (number && con ? addTone(Number(number), con) : number || con || '')),
 
-         )
 
-         .filter((item) => item.length > 0)
 
-         .join(' ');
 
-       if (this.matically_pinyin_str[mark].indexOf(',') > -1) {
 
-         this.$message.warning('输入的拼音有误,请重新输入');
 
-         this.matically_pinyin_obj[mark] = [];
 
-         this.matically_pinyin_str[mark] = '';
 
-         this.data.option_list[itemIndex].content = '';
 
-       }
 
-     },
 
-     handleValue(valItem) {
 
-       let numList = [];
 
-       if (/[A-Za-zü]+\d/g.test(valItem)) {
 
-         valItem.split('').forEach((item, i) => {
 
-           if (/\d/.test(item)) {
 
-             let numIndex = numList.length === 0 ? 0 : numList[numList.length - 1].index;
 
-             let con = valItem.substring(numIndex, i).replace(/\d/g, '');
 
-             numList.push({
 
-               index: i,
 
-               number: item,
 
-               con,
 
-               isTran: true,
 
-             });
 
-           }
 
-         });
 
-       } else {
 
-         numList = [];
 
-       }
 
-       this.res_arr.push(numList.length === 0 ? [{ con: valItem }] : numList);
 
-     },
 
-     // 答案
 
-     handleItemAnswer(item) {
 
-       const itemIndex = this.data.answer.answer_list.findIndex((items) => items.mark === item.mark);
 
-       let content = item.content.trim();
 
-       const regex = /[\u4e00-\u9fa5]/g;
 
-       item.content_hz = content.match(regex) ? content.match(regex).join('') : '';
 
-       let content_arr = content.replace(regex, '').trim().split(' ');
 
-       let select_item = '';
 
-       let content_preview = '';
 
-       this.res_arr = [];
 
-       this.$set(this.matically_pinyin_obj, item.mark, []);
 
-       this.$set(this.matically_pinyin_str, item.mark, '');
 
-       content_arr.forEach((items, index) => {
 
-         let items_trim = items.trim();
 
-         if (items_trim) {
 
-           let items_yuan = JSON.parse(JSON.stringify(items_trim)).replace(/0|1|2|3|4/, '');
 
-           let indexs = items.search(/0|1|2|3|4/);
 
-           if (this.data.property.answer_mode === 'select') {
 
-             // 如果是选择声调 把声调放在拼音后面
 
-             // select_item += `${items_yuan + items_trim.substring(indexs, indexs + 1)} `;
 
-             select_item += `${items_trim.substring(indexs, indexs + 1)}${index === content_arr.length - 1 ? '' : ' '}`;
 
-           } else if (this.data.property.answer_mode === 'label') {
 
-             // 如果是标注声调 把声调放在对应字母后面
 
-             // select_item += `${items_trim}${index === content_arr.length - 1 ? '' : ' '}`;
 
-           }
 
-           content_preview += `${items_yuan}${index === content_arr.length - 1 ? '' : ' '}`;
 
-           this.handleReplaceTone(items_yuan + items_trim.substring(indexs, indexs + 1), item.mark, itemIndex);
 
-         }
 
-       });
 
-       if (this.data.property.answer_mode === 'label') {
 
-         content_preview.split(' ').forEach((items, index) => {
 
-           let items_trim = items.trim();
 
-           if (items_trim) {
 
-             let indexs = content_arr[index].search(/0|1|2|3|4/);
 
-             let items_tone = this.matically_pinyin_str[item.mark].split(' ')[index].split('');
 
-             for (let i = 0; i < items_trim.length; i++) {
 
-               if (items_trim[i] === items_tone[i]) {
 
-                 select_item += `${items_trim[i]}`;
 
-               } else {
 
-                 select_item += `${items_trim[i]}${content_arr[index].substring(indexs, indexs + 1)}`;
 
-               }
 
-             }
 
-             select_item += `${index === content_preview.split(' ').length - 1 ? '' : ' '}`;
 
-           }
 
-         });
 
-       }
 
-       if (itemIndex === -1) {
 
-         let obj = {
 
-           mark: item.mark,
 
-           value: select_item.split(' '),
 
-         };
 
-         this.data.answer.answer_list.push(obj);
 
-       } else {
 
-         this.data.answer.answer_list[itemIndex].value = select_item.split(' ');
 
-       }
 
-       item.content_view = content_preview.trim().split(' ');
 
-       // item.matically_pinyin = matically_pinyin.trim().split(' ').join(',');
 
-     },
 
-     // 改变类型
 
-     handleChangeType() {
 
-       this.data.option_list.forEach((item) => {
 
-         this.handleItemAnswer(item);
 
-       });
 
-     },
 
-     // 修改拼音
 
-     changePinyin(item) {
 
-       if (this.data.other.audio_generation_method === 'auto') {
 
-         item.audio_file_id = '';
 
-       }
 
-     },
 
-     /**
 
-      * 智能识别
 
-      * @param {string} text 识别数据
 
-      */
 
-     recognition(text) {
 
-       let arr = this.recognitionCommon(text);
 
-       let obj = analysisRecognitionChooseToneData(arr);
 
-       this.recognitionCommonSetObj(obj);
 
-       this.data.option_list.forEach((item) => {
 
-         this.handleItemAnswer(item);
 
-       });
 
-     },
 
-   },
 
- };
 
- </script>
 
- <style lang="scss" scoped>
 
- .content {
 
-   display: flex;
 
-   flex-direction: column;
 
-   .subtitle {
 
-     margin: 8px 0;
 
-     font-size: 14px;
 
-     color: $font-light-color;
 
-   }
 
-   .content-item {
 
-     .upload-wrapper {
 
-       width: 200px;
 
-       margin-top: 0;
 
-       overflow: hidden;
 
-     }
 
-     :deep .file-name {
 
-       width: 205px;
 
-       overflow: hidden;
 
-       text-overflow: ellipsis;
 
-       white-space: nowrap;
 
-     }
 
-     .auto-matically,
 
-     .upload-audio-play {
 
-       .audio-wrapper {
 
-         // margin-right: 12px;
 
-         :deep .audio-play {
 
-           width: 16px;
 
-           height: 16px;
 
-           color: #000;
 
-           background-color: initial;
 
-         }
 
-         :deep .audio-play.not-url {
 
-           color: #a1a1a1;
 
-         }
 
-         :deep .voice-play {
 
-           width: 16px;
 
-           height: 16px;
 
-         }
 
-       }
 
-     }
 
-     .upload-audio-play {
 
-       display: flex;
 
-       flex-shrink: 0;
 
-       align-items: center;
 
-       width: 200px;
 
-       background-color: $fill-color;
 
-       border-radius: 2px;
 
-       .upload-play {
 
-         display: flex;
 
-         column-gap: 8px;
 
-         align-items: center;
 
-         .svg-icon {
 
-           cursor: pointer;
 
-         }
 
-       }
 
-     }
 
-     .auto-matically {
 
-       display: flex;
 
-       flex-shrink: 0;
 
-       column-gap: 12px;
 
-       align-items: center;
 
-       width: 200px;
 
-       padding: 5px 12px;
 
-       background-color: $fill-color;
 
-       border-radius: 2px;
 
-       .auto-btn {
 
-         font-size: 16px;
 
-         font-weight: 400;
 
-         line-height: 22px;
 
-         color: #1d2129;
 
-         cursor: pointer;
 
-       }
 
-     }
 
-     .delete {
 
-       flex-shrink: 0;
 
-       width: 16px;
 
-       height: 16px;
 
-     }
 
-   }
 
- }
 
- </style>
 
 
  |