123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745 |
- <template>
- <!-- 选择声调题 -->
- <view class="choosetone-area" v-model="questionData">
- <view class="question_title">
- <text class="question_number">
- {{ questionNumberEndIsBracket(questionData.property.question_number) }}
- </text>
- <text class="question_stem" v-html="sanitizeHTML(questionData.stem)"
- :ref="'richText-1-1'+questionData.question_id"
- @longpress="previewByRichTextImg(-1,-1,questionData.question_id)"></text>
- </view>
- <view class="description"
- v-if="isEnable(questionData.property.is_enable_description)&&questionData.description.length > 0"
- v-html="sanitizeHTML(questionData.description)" :ref="'richText-2-2'+questionData.question_id"
- @longpress="previewByRichTextImg(-2,-2,questionData.question_id)">
- </view>
- <view class="option-area">
- <view class="option-box" v-for="(item,i) in questionData.option_list" :key="i">
- <view class="option-serial">
- <text class="serial-number" :style="{'font-size':questionData.property.option_question_number_font_size}">
- {{ computedQuestionNumber(i,questionData.option_number_show_mode) }}</text>
- </view>
- <view class="option-content-area">
- <AudioPlay v-if="item.audio_file_id" :file-id="item.audio_file_id" :showProgress="true" :showSlider="true"
- :isPlaying="item.isPlaying" :questionId="questionData.question_id" />
- <view :class="['option-content', computedIsJudgeRight(item.mark)]">
- <span class="items-hz" v-if="item.content_hz">{{ item.content_hz }}</span>
- <template v-if="questionData.property.answer_mode === 'select'">
- <text v-for="(itemc, indexc) in con_preview[i].item_con" :key="indexc" :class="['item-con', active_index_str === i + '-' + indexc ? 'active' : '',
- computedIsJudgeRight(item.mark,indexc)]" @click="handleSelectItemTone('select',item.mark,i,indexc)">
- {{itemc}}
- <!-- con_preview[i].item_active_index = indexc;
- active_index_str = i + '-' + indexc; -->
- </text>
- </template>
- <template v-else>
- <text class="item-con" v-for="(itemc, indexc) in con_preview[i].item_con" :key="indexc">
- <text v-for="(itemi, indexi) in itemc" :key="indexi"
- :class="['items-con', active_index_str === i + '-' + indexc + '-' + indexi ? 'active' : '',computedIsJudgeRight(item.mark,indexc,indexi)]"
- @click="handleSelectItemTone('label',item.mark,i, indexc, indexi, con_preview[i].item_con_yuan[indexc][indexi])">
- {{itemi}}
- </text>
- </text>
- </template>
- </view>
- <view class="option-tone">
- <view ref="toneView" v-for="({ img, value }, j) in toneList" :key="j"
- @click="choosetone( con_preview[i] , value , i )"
- :class="['tone',isViewActive(con_preview[i] , value , i),isRightAnswer(item.mark,j,active_index_str)]">
- <SvgIcon :icon-class="img" />
- </view>
- </view>
- </view>
- </view>
- </view>
- <view class="answer-tips-box">
- <template v-if="show_tips&&questionData.property.answer_mode === 'label'">
- <img v-if="show_tips" class="answer-tips" src="static/select_tone_tips.png" />
- </template>
- <template v-if="show_tips&&questionData.property.answer_mode === 'select'">
- <img v-if="show_tips" class="answer-tips" src="static/select_tone_tips2.png" />
- </template>
- <text :class="['tips-btn', show_tips ? 'tips-btn-active' : '']" @click="show_tips = !show_tips">
- <img src="static/tips_icon.png" />
- </text>
- </view>
- <view class="reference" v-if="isViewAnalysis&&answer_control[questionData.question_id].isViewRightAnswer">
- <text class="reference-title">解析</text>
- <text class="reference-answer" v-html="sanitizeHTML(questionData.analysis)"
- :ref="'richText-3-3'+questionData.question_id"
- @longpress="previewByRichTextImg(-3,-3,questionData.question_id)">
- </text>
- </view>
- </view>
- </template>
- <script>
- import {
- questionData,
- sanitizeHTML,
- isEnable,
- computedQuestionNumber,
- answer_control,
- } from '@/pages/answer_question/common/data/common.js';
- import {
- GetFileStoreInfo
- } from '@/api/api.js';
- import AnswerControlMixin from '@/pages/answer_question/common/data/AnswerControlMixin.js';
- export default {
- name: "choose-tone-question",
- mixins: [AnswerControlMixin],
- props: {
- questionData: questionData
- },
- data() {
- return {
- computedQuestionNumber,
- isEnable,
- sanitizeHTML,
- answer_control,
- curMark: '',
- toneList: [{
- value: '1',
- label: '一声',
- img: 'first-tone'
- },
- {
- value: '2',
- label: '二声',
- img: 'second-tone'
- },
- {
- value: '3',
- label: '三声',
- img: 'third-tone'
- },
- {
- value: '4',
- label: '四声',
- img: 'fourth-tone'
- }
- ],
- con_preview: [],
- tone_data: [
- ['ā', 'á', 'ǎ', 'à'],
- ['ō', 'ó', 'ǒ', 'ò'],
- ['ē', 'é', 'ě', 'è'],
- ['ī', 'í', 'ǐ', 'ì'],
- ['ū', 'ú', 'ǔ', 'ù'],
- ['ǖ', 'ǘ', 'ǚ', 'ǜ'],
- ['ǖ', 'ǘ', 'ǚ', 'ǜ'],
- ['Ā', 'Á', 'Â', 'À'],
- ['Ō', 'Ó', 'Ô', 'Ò'],
- ['Ē', 'É', 'Ê', 'È'],
- ['Ī', 'Í', 'Î', 'Ì'],
- ['Ū', 'Ú', 'Û', 'Ù'],
- ],
- final_con: '',
- active_index_str: '', // 高亮索引的字符串
- active_letter: '', // 选中字母的值
- active_letter_index: 0, // 选择字母索引
- select_item_index: 0, // 小题索引
- show_tips: false, // 是否显示答题提示
- answer_list: [], // 初始化用户答案,未答题也回传相应标记
- };
- },
- watch: {
- 'questionData.question_id': {
- handler(val) {
- this.commonComputedAnswerControl(val);
- this.isAnswerReady = true;
- this.show_tips = false;
- this.active_index_str = '';
- this.handleData();
- this.setUserAnswer();
- },
- immediate: true,
- deep: true
- }
- },
- mounted() {
- uni.$on('setOtherAudioPlaying', this.otherAudioPlaying);
- },
- onUnload() {
- uni.$off('setOtherAudioPlaying', this.otherAudioPlaying);
- },
- computed: {
- isViewAnalysis: function() {
- return isEnable(this.questionData.property.is_enable_analysis);
- }
- },
- methods: {
- // 处理选项列表数据
- handleData() {
- this.con_preview = [];
- this.answer_list = []; //初始化答案
- this.questionData.option_list.forEach((item) => {
- item.isPlaying = false;
- let con_arr = JSON.parse(JSON.stringify(item.content_view));
- let user_answer = [];
- let value = [];
- con_arr.forEach((con) => {
- user_answer.push({
- select_tone: null,
- select_letter: '',
- select_index: '',
- });
- if (this.questionData.property.answer_mode === 'label') {
- value.push(con + '');
- } else {
- value.push('');
- }
- });
- let obj = {
- item_con: con_arr,
- item_con_yuan: JSON.parse(JSON.stringify(con_arr)),
- mark: item.mark,
- user_answer,
- item_active_index: 0,
- active_letter: '',
- };
- this.con_preview.push(obj);
- this.answer_list.push({
- mark: item.mark,
- value: value
- });
- if (!item.audio_file_id) return false;
- GetFileStoreInfo({
- file_id: item.audio_file_id
- }).then((res) => {
- item.audio_file_url = res.file_url; //题目音频
- });
- });
- },
- //播放当前音频的时候暂停其他音频
- otherAudioPlaying(audio_file_id, playing) {
- this.questionData.option_list.forEach(p => {
- p.isPlaying = false;
- if (p.audio_file_id == audio_file_id) {
- p.isPlaying = true;
- }
- });
- this.$forceUpdate();
- },
- //选择字母
- handleSelectItemTone(mode, mark, i, indexc, indexi, itemi) {
- if (mode == 'select') {
- this.con_preview[i].item_active_index = indexc;
- this.active_index_str = `${i}-${indexc}`;
- } else {
- this.con_preview[i].item_active_index = indexc;
- this.con_preview[i].user_answer[indexc].select_index = indexi;
- this.active_index_str = `${i}-${indexc}-${indexi}`;
- this.active_letter = itemi; //选中的字母
- this.active_letter_index = indexi;
- this.select_item_index = i;
- }
- },
- isViewActive(item, value, i) {
- const activeAnswer = item.user_answer[item.item_active_index];
- if (!activeAnswer) {
- return '';
- }
- const isSelectMode = this.questionData.property.answer_mode === 'select' && activeAnswer.select_tone === value;
- const isLabelMode = this.questionData.property.answer_mode === 'label' &&
- activeAnswer.select_tone === value &&
- activeAnswer.select_letter === this.active_letter &&
- this.select_item_index === i;
- let className = isSelectMode || isLabelMode ? 'active' : '';
- return className;
- },
- //选择声调
- choosetone(item, value, i) {
- if (this.answer_control[this.questionData.question_id].isReadOnly) return;
- const activeClass = this.isViewActive(item, value, i);
- if ((!this.active_letter || this.select_item_index !== i) &&
- this.questionData.property.answer_mode === 'label') return;
- item.user_answer[item.item_active_index].select_tone = value;
- //标注声调
- if (this.questionData.property.answer_mode === 'label') {
- item.user_answer[item.item_active_index].select_letter = this.active_letter;
- this.active_index_str = `${i}-${item.item_active_index}-${this.active_letter_index}`;
- if (activeClass === 'active') {
- this.handleReplaceTone(this.active_letter + '');
- } else {
- this.handleReplaceTone(this.active_letter + value);
- }
- setTimeout(() => {
- let new_con = item.item_con_yuan[item.item_active_index].split(this.active_letter);
- item.item_con[item.item_active_index] = new_con[0] + this.final_con + new_con[1];
- this.$forceUpdate();
- }, 100);
- } else {
- this.active_index_str = `${i}-${item.item_active_index}`;
- if (activeClass === 'active') {
- this.handleReplaceTone(item.item_con_yuan[item.item_active_index] + '');
- } else {
- this.handleReplaceTone(item.item_con_yuan[item.item_active_index] + value);
- }
- setTimeout(() => {
- item.item_con[item.item_active_index] = this.final_con;
- this.$forceUpdate();
- }, 100);
- }
- if (activeClass === 'active') {
- item.user_answer[item.item_active_index].select_tone = '';
- }
- this.saveUserAnswer(item, this.questionData.property.answer_mode);
- },
- handleReplaceTone(e) {
- var that = this;
- this.$nextTick(() => {
- that.replaceTone(e);
- })
- },
- replaceTone(value) {
- this.resArr = [];
- if (value) {
- let reg = /\s+/g;
- let valueArr = value.split(reg);
- valueArr.forEach((item) => {
- this.handleValue(item);
- });
- let str = '';
- this.resArr.forEach((item) => {
- str += ' ';
- item.forEach((sItem) => {
- if (sItem.number && sItem.con) {
- let number = Number(sItem.number);
- let con = sItem.con;
- let word = this.addTone(number, con);
- str += word;
- } else if (sItem.number) {
- str += sItem.number;
- } else if (sItem.con) {
- str += ` ${sItem.con} `;
- }
- });
- });
- this.final_con = str.trim();
- }
- },
- handleValue(valItem) {
- let reg = /\d/;
- // let reg2 = /[A-Za-z]+\d/g;
- let reg2 = /[A-Za-zü]+\d/g;
- let numList = [];
- let valArr = valItem.split('');
- if (reg2.test(valItem)) {
- for (let i = 0; i < valArr.length; i++) {
- let item = valItem[i];
- if (reg.test(item)) {
- let numIndex = numList.length === 0 ? 0 : numList[numList.length - 1].index;
- let con = valItem.substring(numIndex, i);
- con = con.replace(/\d/g, '');
- let obj = {
- index: i,
- number: item,
- con,
- isTran: true,
- };
- numList.push(obj);
- }
- }
- } else {
- numList = [];
- }
- if (numList.length === 0) {
- this.resArr.push([{
- con: valItem
- }]);
- } else {
- this.resArr.push(numList);
- }
- },
- addTone(number, con) {
- let zmList = ['a', 'o', 'e', 'i', 'u', 'v', 'ü', 'A', 'O', 'E', 'I', 'U'];
- let cons = con;
- if (number) {
- for (let i = 0; i < zmList.length; i++) {
- let zm = zmList[i];
- if (con.indexOf(zm) > -1) {
- let zm2 = this.tone_data[i][number - 1];
- if (con.indexOf('iu') > -1) {
- zm2 = this.tone_data[4][number - 1];
- cons = con.replace('u', zm2);
- } else if (con.indexOf('ui') > -1) {
- zm2 = this.tone_data[3][number - 1];
- cons = con.replace('i', zm2);
- } else if (/yv|jv|qv|xv/.test(con)) {
- zm2 = tone_data[4][number - 1];
- cons = con.replace('v', zm2);
- } else if (/yü|jü|qü|xü/.test(con)) {
- zm2 = tone_data[4][number - 1];
- cons = con.replace('ü', zm2);
- } else {
- cons = con.replace(zm, zm2);
- }
- break;
- }
- }
- }
- return cons;
- },
- //切换选项保存答案
- saveUserAnswer: function(item, answer_mode) {
- var questionId = this.questionData.question_id;
- var _userAnswer = this.questionData.user_answer[questionId];
- var _index = _userAnswer.answer_list.findIndex(p => p.mark == item.mark);
- if (_index > -1) {
- _userAnswer.answer_list.splice(_index, 1);
- }
- var value = [];
- var is_fill_answer = false;
- item.item_con_yuan.forEach((p, i) => {
- var letArr = p.split('');
- var _user_answer = item.user_answer[i];
- if (answer_mode === 'label') {
- if (_user_answer.select_tone) {
- let {
- select_index,
- select_letter,
- select_tone
- } = item.user_answer[i];
- letArr.splice(select_index, 1, select_letter + select_tone);
- }
- value.push(letArr.join(''));
- } else {
- value.push(null === _user_answer.select_tone ? '' : _user_answer.select_tone);
- }
- is_fill_answer = true;
- })
- _userAnswer.answer_list.push({
- mark: item.mark,
- value: value
- })
- if (answer_mode === 'label') {
- this.questionData.option_list.forEach(p => {
- if (_userAnswer.answer_list.findIndex(x => x.mark == p.mark) == -1)
- _userAnswer.answer_list.push({
- mark: p.mark,
- value: p.content_view
- })
- })
- }
- this.questionData.user_answer[questionId].isEdit = true;
- this.questionData.user_answer[questionId].is_fill_answer =
- this.questionData.user_answer[questionId].is_fill_answer || is_fill_answer;
- this.questionData.user_answer[questionId].content = JSON.stringify(_userAnswer.answer_list);
- },
- //回显
- setUserAnswer: function() {
- var that = this;
- var callback = function() {
- var userAnswer = [];
- var questionId = that.questionData.question_id;
- var _ua = that.questionData.user_answer[questionId];
- if (_ua && _ua.answer_list && _ua.answer_list.length > 0) {
- userAnswer = _ua.answer_list;
- } else {
- _ua.answer_list = that.answer_list;
- _ua.content = JSON.stringify(that.answer_list);
- }
- let _answer_mode = that.questionData.property.answer_mode;
- that.con_preview.forEach((item, m) => {
- var rowEn = userAnswer.find(x => x.mark == item.mark);
- if (!rowEn) return false;
- if (_answer_mode === 'select') {
- item.item_con_yuan.forEach((letter, i, arr) => {
- var _val = rowEn.value[i];
- if (!_val) return false;
- item.user_answer[i].select_tone = rowEn.value[i];
- that.replaceTone(letter + _val);
- item.item_con[i] = that.final_con
- })
- } else {
- item.item_con.forEach((letter, i, arr) => {
- var _val = rowEn.value[i];
- if (!_val) return false;
- // var _ze = /[a-zA-Z]\d(?!a-zA-Z)/g; //匹配字母和声调,用此替换成带声调的字母
- var _ze = /[a-zA-Zü]\d(?!a-zA-Zü)/g;
- var lettertoneArr = _val.match(_ze) || [];
- lettertoneArr.forEach(p => {
- var _e = p.split('');
- let word = that.addTone(Number(_e[1]), _e[0]);
- _val = _val.replace(_ze, word);
- item.user_answer[i].select_tone = _e[1];
- item.user_answer[i].select_letter = _e[0];
- })
- item.item_con[i] = _val;
- })
- }
- setTimeout(function() {
- that.$forceUpdate();
- }, 200)
- })
- };
- this.$emit("getUserAnswer", this.questionData.question_id, callback);
- },
- /**
- * @param {标识} mark
- * @param {拼音的索引} indexc
- * @param {字母的索引} indexi
- * 判断小题题干及拼音或字母样式
- */
- computedIsJudgeRight(mark, indexc, indexi) {
- var cur = this.commonComputedAnswerControl(this.questionData.question_id);
- var answer_mode = this.questionData.property.answer_mode; //select【选择音调】,label【标注音调】
- if (!cur.isJudgeAnswer && !cur.isViewRightAnswer) {
- return '';
- }
- var rightAnswer = this.questionData.answer.answer_list;
- var cur_answer = rightAnswer.find(p => p.mark == mark);
- if (!cur_answer) return '';
- // cur.value
- var user_answer_list = this.questionData.user_answer[this.questionData.question_id].answer_list;
- var user = user_answer_list.find(p => p.mark == mark);
- if (!user || !user.value || user.value.length <= 0) return 'wrong';
- var isRight = true;
- if (cur_answer.value.length !== user.value.length) return 'wrong';
- cur_answer.value.forEach((m, i) => {
- if (indexc !== undefined) {
- if (m !== user.value[i] && i == indexc) {
- isRight = false;
- return false;
- }
- } else {
- if (m !== user.value[i]) {
- isRight = false;
- return false;
- }
- }
- });
- return isRight ? 'right' : 'wrong';
- },
- /**
- * @param {String} 标识
- * @param {Number} 声调索引
- * @param {String} 选择的拼音或者字母的索引
- * 判断标准答案显示样式
- */
- isRightAnswer(mark, j, active_index_str) {
- if (!active_index_str) return;
- var cur = this.commonComputedAnswerControl(this.questionData.question_id);
- if (!cur.isJudgeAnswer && !cur.isViewRightAnswer) {
- return '';
- }
- var indexArr = active_index_str.split('-');
- var rowIndex = indexArr[0];
- var pinyin_index = indexArr[1];
- var letter_index = -1;
- if (indexArr.length == 3) {
- letter_index = indexArr[2];
- }
- var rightAnswer = this.questionData.answer.answer_list;
- if (rightAnswer.findIndex(p => p.mark == mark) != rowIndex) return;
- var cur_answer = rightAnswer.find(p => p.mark == mark);
- if (!cur_answer) return '';
- var curPinYinTone = cur_answer.value[pinyin_index];
- if (this.questionData.property.answer_mode == 'label') {
- var tone = rightAnswer[rowIndex].value[pinyin_index].substr(Number(letter_index) + 1, 1);
- if (tone) {
- curPinYinTone = tone;
- }
- }
- return j + 1 == curPinYinTone ? 'answer-right' : '';
- },
- }
- }
- </script>
- <style lang="scss" scoped>
- .choosetone-area {
- .question_title {
- display: flex;
- flex-direction: row;
- margin-top: 70rpx;
- margin-bottom: 32rpx;
- .question_number,
- .question_stem {
- color: #34343A;
- }
- .question_number {
- margin-right: 10rpx;
- }
- }
- .description {
- padding: 24rpx 48rpx;
- border-radius: 40rpx;
- background-color: $uni-bg-color-grey;
- margin-top: 32rpx;
- font-size: $font-size-serial;
- }
- .option-area {
- display: flex;
- flex-direction: column;
- margin-top: 32rpx;
- row-gap: 32rpx;
- .option-box {
- display: flex;
- align-items: flex-start;
- justify-content: left;
- column-gap: 16rpx;
- .option-serial {
- width: 36rpx;
- margin-top: 16rpx;
- }
- .option-content-area {
- width: 100%;
- display: flex;
- flex-direction: column;
- row-gap: 16rpx;
- .option-content {
- background-color: $uni-bg-color-grey;
- border-radius: 40rpx;
- display: flex;
- align-items: center;
- justify-content: left;
- column-gap: 20rpx;
- padding: 16rpx 32rpx;
- &.right {
- background-color: $right-bc-color;
- }
- &.wrong {
- border: 1px solid $error-color;
- }
- &.active {
- color: #2f6fec;
- }
- .items-hz {
- margin-right: 8rpx;
- font-size: 32rpx;
- font-weight: 500;
- line-height: 48rpx;
- color: #000000;
- }
- .item-con,
- .items-con {
- font-family: 'League';
- color: #000000;
- &.wrong {
- color: $error-color;
- }
- &.active {
- color: #2f6fec;
- }
- }
- .items-con {
- margin-right: 6rpx;
- }
- }
- .option-tone {
- display: flex;
- justify-content: left;
- column-gap: 8rpx;
- .tone {
- width: 64rpx;
- height: 64rpx;
- border-radius: 32rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- color: #9f9f9f;
- &.answer-right {
- color: $right-color !important;
- background-color: $right-bc-color !important;
- }
- &.active {
- background-color: #DFE9FD;
- color: #2f6fec;
- }
- }
- }
- }
- }
- }
- .answer-tips-box {
- position: absolute;
- top: 126rpx;
- right: 50rpx;
- display: flex;
- .answer-tips {
- width: 307px;
- margin-top: 32px;
- }
- .tips-btn {
- width: 68rpx;
- height: 68rpx;
- font-size: 0;
- background: #fff5e3;
- border: 1px solid rgba(0, 0, 0, 0.1);
- border-radius: 8px;
- display: flex;
- justify-content: center;
- align-items: center;
- &-active {
- background: #e3d5b3;
- }
- img {
- width: 40rpx;
- height: 40rpx;
- margin-top: -4px;
- }
- }
- }
- .reference {
- margin: 32rpx 0;
- background-color: #f9f8f9;
- padding: 24rpx;
- .reference-title {
- display: block;
- line-height: 64rpx;
- color: #4E5969;
- font-size: 28rpx;
- }
- .reference-answer {
- color: #1D2129;
- line-height: 48rpx;
- font-size: 14pt;
- }
- }
- }
- .audio-wrapper {
- margin: 0;
- }
- </style>
|