|  | @@ -3,10 +3,18 @@
 | 
	
		
			
				|  |  |      <template #content>
 | 
	
		
			
				|  |  |        <!-- eslint-disable max-len -->
 | 
	
		
			
				|  |  |        <div class="fill-wrapper">
 | 
	
		
			
				|  |  | -        <RichText
 | 
	
		
			
				|  |  | +        <el-input v-model="data.character" :placeholder="'汉字'" style="flex-shrink: 0; width: 80px" />
 | 
	
		
			
				|  |  | +        <el-input
 | 
	
		
			
				|  |  |            v-model="data.content"
 | 
	
		
			
				|  |  | -          toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
 | 
	
		
			
				|  |  | -          :wordlimit-num="false"
 | 
	
		
			
				|  |  | +          placeholder="拼音间用空格隔开,如:ni3 hao3"
 | 
	
		
			
				|  |  | +          @blur="handleItemAnswer(data)"
 | 
	
		
			
				|  |  | +          @change="changePinyin(data)"
 | 
	
		
			
				|  |  | +        />
 | 
	
		
			
				|  |  | +        <el-input
 | 
	
		
			
				|  |  | +          v-model="matically_pinyin_str[data.mark]"
 | 
	
		
			
				|  |  | +          :placeholder="'拼音预览'"
 | 
	
		
			
				|  |  | +          :readonly="true"
 | 
	
		
			
				|  |  | +          style="width: 200px"
 | 
	
		
			
				|  |  |          />
 | 
	
		
			
				|  |  |          <div v-if="data.audio_file_id">
 | 
	
		
			
				|  |  |            <SoundRecord :wav-blob.sync="data.audio_file_id" />
 | 
	
	
		
			
				|  | @@ -20,7 +28,11 @@
 | 
	
		
			
				|  |  |                @upload="uploads"
 | 
	
		
			
				|  |  |                @deleteFile="deleteFiles"
 | 
	
		
			
				|  |  |              />
 | 
	
		
			
				|  |  | -            <div v-else-if="data.property.audio_generation_method === 'auto'" class="auto-matic" @click="handleMatic">
 | 
	
		
			
				|  |  | +            <div
 | 
	
		
			
				|  |  | +              v-else-if="data.property.audio_generation_method === 'auto'"
 | 
	
		
			
				|  |  | +              class="auto-matic"
 | 
	
		
			
				|  |  | +              @click="handleMatically"
 | 
	
		
			
				|  |  | +            >
 | 
	
		
			
				|  |  |                <SvgIcon icon-class="voiceprint-line" class="record" />
 | 
	
		
			
				|  |  |                <span class="auto-btn">{{ data.audio_file_id ? '已生成' : '生成音频' }}</span
 | 
	
		
			
				|  |  |                >{{ data.audio_file_id ? '成功' : '' }}
 | 
	
	
		
			
				|  | @@ -53,94 +65,146 @@ export default {
 | 
	
		
			
				|  |  |    data() {
 | 
	
		
			
				|  |  |      return {
 | 
	
		
			
				|  |  |        data: getPinyinBaseData(),
 | 
	
		
			
				|  |  | +      matically_pinyin_obj: {}, // 存放转成声调的拼音
 | 
	
		
			
				|  |  | +      matically_pinyin_str: {}, // 存放转成声调的字符串
 | 
	
		
			
				|  |  | +      res_arr: [],
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |    methods: {
 | 
	
		
			
				|  |  | -    // 识别文本
 | 
	
		
			
				|  |  | -    identifyText() {
 | 
	
		
			
				|  |  | -      this.data.model_essay = [];
 | 
	
		
			
				|  |  | -      this.data.answer.answer_list = [];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      this.data.content
 | 
	
		
			
				|  |  | -        .split(/<(p|div)[^>]*>(.*?)<\/(p|div)>/g)
 | 
	
		
			
				|  |  | -        .filter((s) => s && !s.match(/^(p|div)$/))
 | 
	
		
			
				|  |  | -        .forEach((item) => {
 | 
	
		
			
				|  |  | -          if (item.charCodeAt() === 10) return;
 | 
	
		
			
				|  |  | -          let str = item
 | 
	
		
			
				|  |  | -            // 去除所有的 font-size 样式
 | 
	
		
			
				|  |  | -            .replace(/font-size:\s*\d+(\.\d+)?px;/gi, '')
 | 
	
		
			
				|  |  | -            // 匹配 class 名为 rich-fill 的 span 标签和三个以上的_,并将它们组成数组
 | 
	
		
			
				|  |  | -            .replace(/<span class="rich-fill".*?>(.*?)<\/span>|([_]{3,})/gi, '###$1$2###');
 | 
	
		
			
				|  |  | -          this.data.model_essay.push(this.splitRichText(str));
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | +    uploads(file_id) {
 | 
	
		
			
				|  |  | +      this.data.audio_file_id = file_id;
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    deleteFiles() {
 | 
	
		
			
				|  |  | +      this.data.audio_file_id = '';
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  | -    // 分割富文本
 | 
	
		
			
				|  |  | -    splitRichText(str) {
 | 
	
		
			
				|  |  | -      let _str = str;
 | 
	
		
			
				|  |  | -      let start = 0;
 | 
	
		
			
				|  |  | -      let index = 0;
 | 
	
		
			
				|  |  | -      let arr = [];
 | 
	
		
			
				|  |  | -      let matchNum = 0;
 | 
	
		
			
				|  |  | -      while (index !== -1) {
 | 
	
		
			
				|  |  | -        index = _str.indexOf('###', start);
 | 
	
		
			
				|  |  | -        if (index === -1) break;
 | 
	
		
			
				|  |  | -        matchNum += 1;
 | 
	
		
			
				|  |  | -        arr.push({ content: _str.slice(start, index), type: 'text' });
 | 
	
		
			
				|  |  | -        if (matchNum % 2 === 0 && arr.length > 0) {
 | 
	
		
			
				|  |  | -          arr[arr.length - 1].type = 'input';
 | 
	
		
			
				|  |  | -          let mark = getRandomNumber();
 | 
	
		
			
				|  |  | -          arr[arr.length - 1].mark = mark;
 | 
	
		
			
				|  |  | -          let content = arr[arr.length - 1].content;
 | 
	
		
			
				|  |  | -          // 设置答案数组
 | 
	
		
			
				|  |  | -          let isUnderline = /^_{3,}$/.test(content);
 | 
	
		
			
				|  |  | -          this.data.answer.answer_list.push({
 | 
	
		
			
				|  |  | -            value: isUnderline ? '' : content,
 | 
	
		
			
				|  |  | -            mark,
 | 
	
		
			
				|  |  | -            type: isUnderline ? 'any_one' : 'only_one',
 | 
	
		
			
				|  |  | -          });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          // 将 content 设置为空,为预览准备
 | 
	
		
			
				|  |  | -          arr[arr.length - 1].content = '';
 | 
	
		
			
				|  |  | +    // 自动生成音频
 | 
	
		
			
				|  |  | +    handleMatically() {
 | 
	
		
			
				|  |  | +      let MethodName = 'tool-TextToVoiceFile';
 | 
	
		
			
				|  |  | +      let data = {};
 | 
	
		
			
				|  |  | +      if (this.data.character.trim() || this.data.content_hz) {
 | 
	
		
			
				|  |  | +        data = {
 | 
	
		
			
				|  |  | +          text: this.data.character.trim() || this.data.content_hz,
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +      } else if (this.data.content.trim()) {
 | 
	
		
			
				|  |  | +        if (!this.matically_pinyin_obj[this.data.mark]) {
 | 
	
		
			
				|  |  | +          this.handleItemAnswer(this.data);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        start = index + 3;
 | 
	
		
			
				|  |  | +        MethodName = 'tool-PinyinToVoiceFile';
 | 
	
		
			
				|  |  | +        data = {
 | 
	
		
			
				|  |  | +          pinyin: this.matically_pinyin_obj[this.data.mark],
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      let last = _str.slice(start);
 | 
	
		
			
				|  |  | -      if (last) {
 | 
	
		
			
				|  |  | -        arr.push({ content: last, type: 'text' });
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      return arr;
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    handleTone(value, i) {
 | 
	
		
			
				|  |  | -      if (!/^[a-zA-Z0-9\s]+$/.test(value)) return;
 | 
	
		
			
				|  |  | -      this.data.answer.answer_list[i].value = value
 | 
	
		
			
				|  |  | -        .trim()
 | 
	
		
			
				|  |  | -        .split(/\s+/)
 | 
	
		
			
				|  |  | -        .map((item) => {
 | 
	
		
			
				|  |  | -          return handleToneValue(item);
 | 
	
		
			
				|  |  | +      GetStaticResources(MethodName, data)
 | 
	
		
			
				|  |  | +        .then((res) => {
 | 
	
		
			
				|  |  | +          if (res.status === 1) {
 | 
	
		
			
				|  |  | +            this.data.audio_file_id = res.file_id;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  |          })
 | 
	
		
			
				|  |  | +        .catch(() => {});
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    handleReplaceTone(value, mark) {
 | 
	
		
			
				|  |  | +      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.content = '';
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  | -    uploads(file_id) {
 | 
	
		
			
				|  |  | -      this.data.audio_file_id = file_id;
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    deleteFiles() {
 | 
	
		
			
				|  |  | -      this.data.audio_file_id = '';
 | 
	
		
			
				|  |  | +    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);
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  | -    // 自动生成音频
 | 
	
		
			
				|  |  | -    handleMatic() {
 | 
	
		
			
				|  |  | -      GetStaticResources('tool-TextToVoiceFile', {
 | 
	
		
			
				|  |  | -        text: this.data.content.replace(/<[^>]+>/g, ''),
 | 
	
		
			
				|  |  | -      })
 | 
	
		
			
				|  |  | -        .then(({ status, file_id }) => {
 | 
	
		
			
				|  |  | -          if (status === 1) {
 | 
	
		
			
				|  |  | -            this.data.audio_file_id = file_id;
 | 
	
		
			
				|  |  | +    // 答案
 | 
	
		
			
				|  |  | +    handleItemAnswer(item) {
 | 
	
		
			
				|  |  | +      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 ? '' : ' '}`;
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  | -        })
 | 
	
		
			
				|  |  | -        .catch(() => {});
 | 
	
		
			
				|  |  | +          content_preview += `${items_yuan}${index === content_arr.length - 1 ? '' : ' '}`;
 | 
	
		
			
				|  |  | +          this.handleReplaceTone(items_yuan + items_trim.substring(indexs, indexs + 1), item.mark);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  | +      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 ? '' : ' '}`;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      this.data.answer.answer_list[0].value = select_item.split(' ');
 | 
	
		
			
				|  |  | +      item.content_view = content_preview.trim().split(' ');
 | 
	
		
			
				|  |  | +      // item.matically_pinyin = matically_pinyin.trim().split(' ').join(',');
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 改变类型
 | 
	
		
			
				|  |  | +    handleChangeType() {
 | 
	
		
			
				|  |  | +      this.handleItemAnswer(this.data);
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 修改拼音
 | 
	
		
			
				|  |  | +    changePinyin(item) {
 | 
	
		
			
				|  |  | +      if (this.data.other.audio_generation_method === 'auto') {
 | 
	
		
			
				|  |  | +        item.audio_file_id = '';
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |  };
 |