index.vue 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. <!-- eslint-disable vue/no-v-html -->
  2. <template>
  3. <div class="article-preview" :style="[getAreaStyle(), getComponentStyle()]">
  4. <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
  5. <div class="main">
  6. <div class="NPC-ArticleView NPC-ArticleView-container">
  7. <div class="ArticleView-header">
  8. <a class="ArticleView-full" :title="convertText('黑板模式')" @click="fullScreen">
  9. <svg-icon
  10. icon-class="icon-full"
  11. size="24"
  12. :style="{
  13. color: data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '',
  14. }"
  15. />
  16. </a>
  17. <div>
  18. <!-- v-if="
  19. (tokenData && tokenData.popedom_code_list && tokenData.popedom_code_list.indexOf(2100001) != -1) ||
  20. (tokenData && tokenData.user_type === 'APP')
  21. " -->
  22. <div
  23. class="left"
  24. :style="{ marginLeft: '40px', cursor: 'pointer' }"
  25. :title="convertText('文本分析')"
  26. @click="submit"
  27. >
  28. <!-- <img src="@/assets/wbfx-icon.png" alt="" /> -->
  29. <svg-icon
  30. icon-class="icon-wbfx"
  31. size="24"
  32. :style="{
  33. color: data.unified_attrib && data.unified_attrib.topic_color ? data.unified_attrib.topic_color : '',
  34. }"
  35. />
  36. </div>
  37. </div>
  38. <div class="right">
  39. <!-- <template v-if="data.property.is_enable_new_word === 'true'">
  40. <el-switch
  41. v-model="showPhrases"
  42. style="display: block"
  43. :active-color="bookInfo.theme_color"
  44. inactive-color="rgba(0,0,0,0.1)"
  45. active-text=""
  46. inactive-text="本课生词"
  47. @change="handleSwitchChange('showPractice', 'showWord')"
  48. />
  49. </template>
  50. <template v-if="data.property.is_enable_read === 'true'">
  51. <el-switch
  52. v-model="showPractice"
  53. style="display: block"
  54. :active-color="bookInfo.theme_color"
  55. inactive-color="rgba(0,0,0,0.1)"
  56. active-text=""
  57. inactive-text="语音练习"
  58. @change="handleSwitchChange('showPhrases', 'showWord')"
  59. />
  60. </template>
  61. <template v-if="data.property.is_enable_word === 'true'">
  62. <el-switch
  63. v-model="showWord"
  64. style="display: block"
  65. :active-color="bookInfo.theme_color"
  66. inactive-color="rgba(0,0,0,0.1)"
  67. active-text=""
  68. inactive-text="取词"
  69. @change="handleSwitchChange('showPhrases', 'showPractice')"
  70. />
  71. </template> -->
  72. <a
  73. v-if="data.property.is_enable_new_word === 'true'"
  74. :style="{
  75. color:
  76. showPhrases && data.unified_attrib && data.unified_attrib.topic_color
  77. ? data.unified_attrib.topic_color
  78. : '',
  79. }"
  80. :title="convertText('本课生词')"
  81. @click="handleSwitchChange('showPractice', 'showWord', 'showPhrases')"
  82. >
  83. <svg-icon icon-class="icon-article-ci" size="24" />
  84. </a>
  85. <a
  86. v-if="data.property.is_enable_read === 'true'"
  87. :style="{
  88. color:
  89. showPractice && data.unified_attrib && data.unified_attrib.topic_color
  90. ? data.unified_attrib.topic_color
  91. : '',
  92. }"
  93. :title="convertText('语音练习')"
  94. @click="handleSwitchChange('showPhrases', 'showWord', 'showPractice')"
  95. >
  96. <svg-icon icon-class="icon-article-practice" size="24" />
  97. </a>
  98. <a
  99. v-if="data.property.is_enable_word === 'true'"
  100. :style="{
  101. color:
  102. showWord && data.unified_attrib && data.unified_attrib.topic_color
  103. ? data.unified_attrib.topic_color
  104. : '',
  105. }"
  106. :title="convertText('取词模式')"
  107. @click="handleSwitchChange('showPhrases', 'showPractice', 'showWord')"
  108. >
  109. <svg-icon icon-class="icon-article-phrase" size="24" />
  110. </a>
  111. </div>
  112. </div>
  113. <div ref="ArticleViewbody" class="ArticleView-body">
  114. <NormalModelChs
  115. v-if="!showPhrases && !showPractice && !showWord"
  116. :cur-que="data"
  117. :title-fontsize="titleFontsize"
  118. :word-fontsize="wordFontsize"
  119. :body-left="bodyLeft"
  120. :body-width="bodyWidth"
  121. :attrib="data.unified_attrib"
  122. :is-mobile="isMobile"
  123. :no-font="noFont"
  124. :config="config"
  125. :NNPEAnnotationList="NNPEAnnotationList"
  126. :col-length="colLength"
  127. :multilingual="showLang && getLang() ? getLang() : ''"
  128. @changeConfig="changeConfig"
  129. />
  130. <PhraseModel
  131. v-if="showPhrases"
  132. :cur-que="data"
  133. :title-fontsize="titleFontsize"
  134. :word-fontsize="wordFontsize"
  135. :NNPENewWordList="NNPENewWordList"
  136. :attrib="data.unified_attrib"
  137. :is-mobile="isMobile"
  138. :no-font="noFont"
  139. :body-left="bodyLeft"
  140. :config="config"
  141. :TaskModel="isJudgingRightWrong ? 'ANSWER' : ''"
  142. :NNPEAnnotationList="NNPEAnnotationList"
  143. :col-length="colLength"
  144. :NpcNewWordMp3="NpcNewWordMp3"
  145. :multilingual="showLang && getLang() ? getLang() : ''"
  146. @changeConfig="changeConfig"
  147. />
  148. <Practice
  149. v-if="showPractice"
  150. :cur-que="data"
  151. :title-fontsize="titleFontsize"
  152. :word-fontsize="wordFontsize"
  153. :attrib="data.unified_attrib"
  154. :is-mobile="isMobile"
  155. :no-font="noFont"
  156. :NNPENewWordList="NNPENewWordList"
  157. :NNPEAnnotationList="NNPEAnnotationList"
  158. :config="config"
  159. :TaskModel="isJudgingRightWrong ? 'ANSWER' : ''"
  160. :col-length="colLength"
  161. :NpcNewWordMp3="NpcNewWordMp3"
  162. :is-full="isFull"
  163. :multilingual="showLang && getLang() ? getLang() : ''"
  164. @changeConfig="changeConfig"
  165. />
  166. <WordModel
  167. v-if="showWord"
  168. :cur-que="data"
  169. :title-fontsize="titleFontsize"
  170. :word-fontsize="wordFontsize"
  171. :body-left="bodyLeft"
  172. :body-width="bodyWidth"
  173. :NNPENewWordList="NNPENewWordList"
  174. :attrib="data.unified_attrib"
  175. :is-mobile="isMobile"
  176. :no-font="noFont"
  177. :config="config"
  178. :TaskModel="isJudgingRightWrong ? 'ANSWER' : ''"
  179. :col-length="colLength"
  180. :multilingual="showLang && getLang() ? getLang() : ''"
  181. @changeConfig="changeConfig"
  182. />
  183. </div>
  184. <div :id="'screen-' + mathNum" class="voice-full-screen">
  185. <Voicefullscreen
  186. v-if="isFull && resObj"
  187. :theme-color="bookInfo.theme_color"
  188. :cur-que="data"
  189. :sent-list="resObj.sentList"
  190. :sent-index="0"
  191. :mp3="data.mp3_list && data.mp3_list[0] ? data.mp3_list[0].url : ''"
  192. :no-font="noFont"
  193. :NNPENewWordList="NNPENewWordList"
  194. :NNPEAnnotationList="NNPEAnnotationList"
  195. :is-full="isFull"
  196. :config="config"
  197. :TaskModel="isJudgingRightWrong ? 'ANSWER' : ''"
  198. :NpcNewWordMp3="NpcNewWordMp3"
  199. :attrib="data.unified_attrib"
  200. :is-mobile="isMobile"
  201. @handleWav="handleWav"
  202. @changePinyin="changePinyins"
  203. @changeEN="changeENs"
  204. @exitFullscreen="exitFullscreen"
  205. @changeIsFull="changeIsFull"
  206. />
  207. </div>
  208. </div>
  209. <template
  210. v-if="
  211. data.new_word_list &&
  212. data.new_word_list.new_word_list &&
  213. data.new_word_list.new_word_list.length > 0 &&
  214. data.new_word_list.property.is_show === 'true'
  215. "
  216. >
  217. <NewWordPreview :new-data="data.new_word_list" :is-mobile="isMobile" />
  218. </template>
  219. <template
  220. v-if="
  221. data.other_word_list &&
  222. data.other_word_list.new_word_list &&
  223. data.other_word_list.new_word_list.length > 0 &&
  224. data.other_word_list.property.is_show === 'true'
  225. "
  226. >
  227. <NewWordPreview :new-data="data.other_word_list" :is-mobile="isMobile" />
  228. </template>
  229. <template
  230. v-if="
  231. data.notes_list &&
  232. data.notes_list.option &&
  233. data.notes_list.option.length > 0 &&
  234. data.notes_list.property.is_show === 'true'
  235. "
  236. >
  237. <NotesPreview :notes-data="data.notes_list" :is-mobile="isMobile" />
  238. </template>
  239. </div>
  240. </div>
  241. </template>
  242. <script>
  243. import { getArticleData } from '@/views/book/courseware/data/dialogueArticle';
  244. import PreviewMixin from '../common/PreviewMixin';
  245. import PhraseModel from './PhraseModelChs.vue';
  246. import NormalModelChs from './NormalModelChs.vue';
  247. import Practice from './Practicechs.vue'; // 语音练习模式
  248. import WordModel from './WordModelChs.vue'; // 语音练习模式
  249. import Voicefullscreen from '../article/Voicefullscreen.vue';
  250. import { getToken } from '@/utils/auth';
  251. import { GetFileURLMap } from '@/api/app';
  252. import { analysSubmit, getSysConfig } from '@/api/article';
  253. import NewWordPreview from '../new_word/NewWordPreview.vue';
  254. import NotesPreview from '../notes/NotesPreview.vue';
  255. export default {
  256. name: 'DialogueArticlePreview',
  257. components: {
  258. NormalModelChs,
  259. Practice,
  260. WordModel,
  261. PhraseModel,
  262. Voicefullscreen,
  263. NewWordPreview,
  264. NotesPreview,
  265. },
  266. mixins: [PreviewMixin],
  267. inject: ['bookInfo'],
  268. props: ['isMobile'],
  269. data() {
  270. return {
  271. data: getArticleData(),
  272. showPreview: true, // 全文预览
  273. showPhrases: false, // 显示单词和短语
  274. showPractice: false, // 语音练习
  275. showWord: false, // 取词
  276. titleFontsize: 20, // 标题字号初始值
  277. wordFontsize: 16, // 文章内容字号初始值
  278. bodyLeft: 0,
  279. bodyWidth: 0,
  280. noFont: ['~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '/'],
  281. config: {
  282. isShowEN: false,
  283. isHasEN: false,
  284. isShowPY: false,
  285. isHasPY: false,
  286. },
  287. userAnswer: {
  288. normalModel: {
  289. recordList: [],
  290. },
  291. writeModel: {}, // 生词/取词模式
  292. practiceModel: {}, // 练习模式
  293. wordModel: {
  294. recordList: [],
  295. },
  296. },
  297. tokenData: getToken(),
  298. mathNum: Math.random().toString(36).substr(2),
  299. isFull: false,
  300. resObj: null,
  301. chsFhList: [',', '。', '”', ':', '》', '?', '!', ';', '、'],
  302. highWords: null,
  303. highWordsArr: [],
  304. highIndex: 0,
  305. newWordList: [],
  306. NNPEAnnotationList: [],
  307. NNPENewWordList: [],
  308. NpcNewWordMp3: [],
  309. colLength: 1,
  310. multilingualTextList: {},
  311. analyser_url: '',
  312. };
  313. },
  314. computed: {},
  315. watch: {
  316. showLang: {
  317. handler(val) {
  318. if (val) {
  319. this.data.multilingual.forEach((item) => {
  320. let trans_arr = item.translation ? item.translation.split('\n') : [];
  321. this.data.detail.forEach((items) => {
  322. let items_trans_arr = [];
  323. if (items && !items.hasOwnProperty('multilingualTextList')) {
  324. this.$set(items, 'multilingualTextList', {});
  325. }
  326. if (items.para) {
  327. items_trans_arr = trans_arr.splice(0, items.sentences.length);
  328. }
  329. this.$set(items.multilingualTextList, item.type, items_trans_arr);
  330. });
  331. });
  332. }
  333. },
  334. deep: true,
  335. immediate: true,
  336. },
  337. 'data.detail.length': {
  338. handler(val) {
  339. if (val) {
  340. this.handleData();
  341. let _this = this;
  342. _this.$nextTick(() => {
  343. _this.bodyLeft = _this.$refs.ArticleViewbody.getBoundingClientRect().left;
  344. });
  345. for (let i = 0; i < this.data.detail.length; i++) {
  346. let enStr = this.data.detail[i].sentencesEn ? this.data.detail[i].sentencesEn.join('') : '';
  347. if (enStr) {
  348. this.config.isShowEN = false;
  349. this.config.isHasEN = true;
  350. }
  351. let pinyin = this.handleObj(this.data.detail[i].wordsList);
  352. if (pinyin && this.isEnable(this.data.property.view_pinyin)) {
  353. this.config.isShowPY = true;
  354. this.config.isHasPY = true;
  355. }
  356. if (enStr && pinyin) {
  357. break;
  358. }
  359. }
  360. }
  361. },
  362. deep: true,
  363. immediate: true,
  364. },
  365. isJudgingRightWrong(val) {
  366. if (!val) return;
  367. this.data.Bookanswer = this.answer.answer_list;
  368. },
  369. },
  370. created() {},
  371. methods: {
  372. changeConfig(obj) {
  373. this.config[obj] = !this.config[obj];
  374. },
  375. changeIsFull() {
  376. this.isFull = false;
  377. },
  378. // 拼音的显示和隐藏
  379. changePinyins() {
  380. if (this.config.isHasPY) {
  381. this.changeConfig('isShowPY');
  382. }
  383. },
  384. // 英文的显示和隐藏
  385. changeENs() {
  386. if (this.config.isHasEN) {
  387. this.changeConfig('isShowEN');
  388. }
  389. },
  390. // 处理字体大小
  391. handleFontsize(symbol) {
  392. if (symbol === '+') {
  393. if (this.wordFontsize < 24) {
  394. this.titleFontsize += 2;
  395. this.wordFontsize += 2;
  396. }
  397. } else if (symbol === '-') {
  398. if (this.wordFontsize > 12) {
  399. this.titleFontsize -= 2;
  400. this.wordFontsize -= 2;
  401. }
  402. }
  403. },
  404. // 切换开关
  405. handleSwitchChange(obj1, obj2, obj3) {
  406. this[obj1] = false;
  407. this[obj2] = false;
  408. this[obj3] = !this[obj3];
  409. this.showPreview = false;
  410. },
  411. handleObj(list) {
  412. let pinyin = '';
  413. list.forEach((item) => {
  414. item.forEach((items) => {
  415. if (items.pinyin) pinyin += items.pinyin;
  416. });
  417. });
  418. return pinyin;
  419. },
  420. submit() {
  421. let access_token =
  422. this.tokenData && this.tokenData.gcls_sys_session_info ? this.tokenData.gcls_sys_session_info.access_token : '';
  423. let loading = this.$loading({
  424. lock: true,
  425. text: 'Loading',
  426. spinner: 'el-icon-loading',
  427. background: 'rgba(0, 0, 0, 0.7)',
  428. });
  429. getSysConfig()
  430. .then((ress) => {
  431. let content = '';
  432. this.data.detail.forEach((item) => {
  433. content += `${item.para}\n`;
  434. });
  435. analysSubmit({
  436. app_user_id: '',
  437. text: content,
  438. })
  439. .then((res) => {
  440. window.open(
  441. `${ress.text_analyser_page_address}GCLS-TC/#/textanalysis/Result?id=${res.record.id}&type=文本分析&AccessToken=${access_token}&fromEEP=true`,
  442. );
  443. loading.close();
  444. })
  445. .catch((res) => {
  446. loading.close();
  447. });
  448. })
  449. .catch((res) => {
  450. loading.close();
  451. });
  452. },
  453. // 语音全屏
  454. fullScreen() {
  455. this.pauseAudio();
  456. this.pauseVideo();
  457. this.isFull = true;
  458. // this.goFullscreen();
  459. },
  460. pauseAudio() {
  461. let audio = document.getElementsByTagName('audio');
  462. if (audio && audio.length > 0 && window.location.href.indexOf('GCLS-Learn') === -1 && audio.forEach) {
  463. audio.forEach((item) => {
  464. item.pause();
  465. });
  466. }
  467. },
  468. pauseVideo() {
  469. let video = document.getElementsByTagName('video');
  470. if (video && video.length > 0 && window.location.href.indexOf('GCLS-Learn') === -1 && video.forEach) {
  471. video.forEach((item) => {
  472. item.pause();
  473. });
  474. }
  475. },
  476. goFullscreen() {
  477. let id = `screen-${this.mathNum}`;
  478. let element = document.getElementById(id);
  479. if (element.requestFullscreen) {
  480. element.requestFullscreen();
  481. } else if (element.msRequestFullscreen) {
  482. element.msRequestFullscreen();
  483. } else if (element.mozRequestFullScreen) {
  484. element.mozRequestFullScreen();
  485. } else if (element.webkitRequestFullscreen) {
  486. element.webkitRequestFullscreen();
  487. }
  488. },
  489. exitFullscreen() {
  490. this.isFull = false;
  491. // if (document.exitFullscreen) {
  492. // document.exitFullscreen();
  493. // } else if (document.msExitFullscreen) {
  494. // document.msExitFullscreen();
  495. // } else if (document.mozCancelFullScreen) {
  496. // document.mozCancelFullScreen();
  497. // } else if (document.webkitExitFullscreen) {
  498. // document.webkitExitFullscreen();
  499. // }
  500. },
  501. handleData() {
  502. if (this.data.new_word_list) {
  503. this.$set(this.data.new_word_list, 'unified_attrib', this.data.unified_attrib);
  504. }
  505. if (this.data.other_word_list) {
  506. this.$set(this.data.other_word_list, 'unified_attrib', this.data.unified_attrib);
  507. }
  508. if (this.data.notes_list) {
  509. this.$set(this.data.notes_list, 'unified_attrib', this.data.unified_attrib);
  510. }
  511. if (this.showLang) {
  512. this.data.multilingual.forEach((item) => {
  513. let trans_arr = item.translation ? item.translation.split('\n') : [];
  514. this.data.detail.forEach((items) => {
  515. let items_trans_arr = [];
  516. if (!items.hasOwnProperty('multilingualTextList')) {
  517. this.$set(items, 'multilingualTextList', {});
  518. }
  519. if (items.para) {
  520. items_trans_arr = trans_arr.splice(0, items.sentences.length);
  521. }
  522. this.$set(items.multilingualTextList, item.type, items_trans_arr);
  523. });
  524. });
  525. }
  526. let userAnswer = JSON.parse(JSON.stringify(this.userAnswer));
  527. this.$set(this.data, 'Bookanswer', userAnswer);
  528. if (!this.isJudgingRightWrong) {
  529. this.answer.answer_list = this.data.Bookanswer;
  530. }
  531. if (this.data.mp3_list && this.data.mp3_list.length > 0) {
  532. this.data.mp3_list[0].url = this.data.mp3_list[0].temporary_url;
  533. // GetFileURLMap({ file_id_list: [this.data.mp3_list[0].file_id] }).then(({ url_map }) => {
  534. // this.data.mp3_list[0].url = url_map[this.data.mp3_list[0].file_id];
  535. // });
  536. }
  537. this.NNPENewWordList = (
  538. this.data.new_word_list_other_component_input ? this.data.new_word_list_other_component_input : []
  539. )
  540. .concat(
  541. this.data.new_word_list && this.data.new_word_list.new_word_list ? this.data.new_word_list.new_word_list : [],
  542. )
  543. .concat(
  544. this.data.other_word_list && this.data.other_word_list.new_word_list
  545. ? this.data.other_word_list.new_word_list
  546. : [],
  547. );
  548. this.NNPEAnnotationList = this.data.notes_list && this.data.notes_list.option ? this.data.notes_list.option : [];
  549. let resArr = [];
  550. let sentArrTotal = [];
  551. let timeArr = [];
  552. let curQue = JSON.parse(JSON.stringify(this.data));
  553. let wordTimeList = curQue.wordTime;
  554. let dhaspinyin = false; // 每段是否有拼音
  555. let dhaspinyinArr = [];
  556. curQue.detail.forEach((dItem, dIndex) => {
  557. dhaspinyin = false;
  558. dItem.wordsList.forEach((sItem, sIndex) => {
  559. let sentArr = [];
  560. let sentence = dItem.sentences[sIndex];
  561. sItem.forEach((wItem, wIndex) => {
  562. let startIndex = wIndex === 0 ? 0 : sentArr[wIndex - 1].startIndex + sentArr[wIndex - 1].chs.length;
  563. let endIndex = wIndex === 0 ? wItem.chs.length : sentArr[wIndex - 1].endIndex + wItem.chs.length;
  564. // this.judgePad(sItem, wItem, wIndex);
  565. this.mergeWordSymbol(wItem);
  566. let words = '';
  567. if (this.newWordList.length > 0) {
  568. if (!this.highWords) {
  569. this.findLightWord(wItem, wIndex, sentence, sItem);
  570. words = this.highWords ? this.highWords.words : '';
  571. } else if (wIndex > this.highWords.endIndex - 1) {
  572. this.highWords = null;
  573. this.findLightWord(wItem, wIndex, sentence, sItem);
  574. words = this.highWords ? this.highWords.words : '';
  575. } else {
  576. words = this.highWords ? this.highWords.words : '';
  577. }
  578. }
  579. let obj = {
  580. paraIndex: dIndex, // 段落索引
  581. sentIndex: sIndex, // 在段落中句子索引
  582. wordIndex: wIndex, // 单词的索引
  583. pinyin: wItem.pinyin,
  584. chs: wItem.chs,
  585. padding: true,
  586. className: wItem.className,
  587. isShow: wItem.isShow,
  588. startIndex,
  589. endIndex,
  590. leg: wItem.chs.length,
  591. timeList: [],
  592. words,
  593. config: {
  594. fontFamily: wItem.fontFamily,
  595. color: wItem.color,
  596. textDecoration: wItem.textDecoration,
  597. border: wItem.border,
  598. fontWeight: wItem.fontWeight,
  599. },
  600. matchWords: wItem.matchWords,
  601. matchNotes: wItem.matchNotes,
  602. notesColor: wItem.notesColor,
  603. matchNotesObj: wItem.matchNotesObj,
  604. img: wItem.img,
  605. imgPosition: wItem.imgPosition,
  606. };
  607. sentArr.push(obj);
  608. if (wItem.pinyin) dhaspinyin = true;
  609. });
  610. let objs = {
  611. sentArr,
  612. enwords: dItem.sentencesEn && dItem.sentencesEn[sIndex] && dItem.sentencesEn[sIndex].replace(/'/g, '’'),
  613. };
  614. sentArrTotal.push(sentArr);
  615. resArr.push(objs);
  616. });
  617. timeArr.push(dItem.timeList);
  618. if (this.isEnable(curQue.property.view_pinyin)) {
  619. dhaspinyinArr.push(dhaspinyin);
  620. }
  621. });
  622. if (wordTimeList && wordTimeList.length > 0) {
  623. this.mergeWordTime(sentArrTotal, wordTimeList);
  624. }
  625. let timeList = [];
  626. timeArr.forEach((item) => {
  627. item.forEach((aItem) => {
  628. if (timeList.indexOf(aItem) < 0) {
  629. timeList.push(aItem);
  630. }
  631. });
  632. });
  633. this.resObj = {
  634. sentList: resArr,
  635. timeList,
  636. dhaspinyinArr,
  637. };
  638. },
  639. mergeWordTime(resArr, wordTimeList) {
  640. resArr.forEach((item, index) => {
  641. let wordsResultList = wordTimeList[index].wordsResultList;
  642. item.forEach((wItem) => {
  643. let startIndex = wItem.startIndex;
  644. let endIndex = wItem.endIndex;
  645. wItem.timeList = wordsResultList.slice(startIndex, endIndex);
  646. });
  647. });
  648. },
  649. findLightWord(wItem, startIndex, sentence, sItem) {
  650. let endIndex = 0;
  651. let words = '';
  652. this.newWordList.forEach((item) => {
  653. if (item.length === 1) {
  654. if (item === wItem.chs && !wItem.banLight) {
  655. words = wItem.chs;
  656. endIndex = startIndex + 1;
  657. }
  658. } else if (item[0] === wItem.chs && sentence.indexOf(item) > -1) {
  659. let index = null;
  660. let chsStr = '';
  661. for (let i = startIndex; i < sItem.length + 1; i++) {
  662. index = i;
  663. if (chsStr.length === item.length) {
  664. break;
  665. } else {
  666. chsStr += sItem[i] ? sItem[i].chs : '';
  667. }
  668. }
  669. if (chsStr === item && !wItem.banLight) {
  670. words = item;
  671. endIndex = index;
  672. }
  673. } else if (wItem.new_word && wItem.new_word === item && !wItem.banLight) {
  674. words = item;
  675. endIndex = startIndex + 1;
  676. }
  677. });
  678. if (words) {
  679. this.highWords = { words, endIndex };
  680. } else {
  681. this.highWords = null;
  682. }
  683. },
  684. // 词和标点合一起
  685. mergeWordSymbol(wItem) {
  686. if (this.chsFhList.indexOf(wItem.chs) > -1) {
  687. wItem.isShow = false;
  688. } else {
  689. wItem.isShow = true;
  690. }
  691. },
  692. handleWav(list, tmIndex) {
  693. let i = tmIndex || 0;
  694. this.data.Bookanswer.practiceModel[i] = {
  695. recordList: [],
  696. };
  697. this.$set(this.data.Bookanswer.practiceModel[i], 'recordList', list);
  698. },
  699. handleNewword() {
  700. let NewWordList = [];
  701. this.NNPENewWordList.forEach((wItem) => {
  702. // item.forEach((wItem) => {
  703. if (wItem.new_word) {
  704. NewWordList.push(wItem.new_word);
  705. } else if (wItem.detail && wItem.detail.sentence) {
  706. NewWordList.push(wItem.detail.sentence);
  707. }
  708. // });
  709. });
  710. this.newWordList = JSON.parse(JSON.stringify(NewWordList));
  711. },
  712. /**
  713. * 获取无文本内容的数据结构,用于保存为个人模板时的样式模板
  714. */
  715. getNoTextContentData() {
  716. let noTextContentData = JSON.parse(JSON.stringify(this.data));
  717. const resetFieldMap = {
  718. content: '', // 课文内容
  719. mp3_list: [], // 音频列表
  720. detail: [], // 分段分句分词详情
  721. wordTime: [], // 字幕时间
  722. new_word_list: {
  723. title_con: '',
  724. property: {
  725. audio_generation_method: 'upload',
  726. pinyin_position: 'front',
  727. auto_wrap: 'true', // 自动换行
  728. is_has_infor: 'true',
  729. voice_type: '', // 音色
  730. emotion: '', // 风格,情感
  731. speed_ratio: '', // 语速
  732. is_show: 'false',
  733. },
  734. new_word_list: [],
  735. lrc_arr: [], // lrc 文件解析后的数据
  736. // lrc 文件数据
  737. lrc_data: {
  738. name: '',
  739. url: '',
  740. id: '',
  741. file_id: '',
  742. },
  743. // 音频文件数据
  744. audio_data: {
  745. name: '',
  746. media_duration: 0,
  747. temporary_url: '',
  748. url: '',
  749. file_id: '',
  750. },
  751. wordTime: [], // 字幕时间节点
  752. taskId: '',
  753. file_id_list: [], // 文件 id
  754. multilingual: [], // 多语言
  755. }, // 生词列表
  756. other_word_list: {
  757. title_con: '',
  758. property: {
  759. audio_generation_method: 'upload',
  760. pinyin_position: 'front',
  761. auto_wrap: 'true', // 自动换行
  762. is_has_infor: 'true',
  763. voice_type: '', // 音色
  764. emotion: '', // 风格,情感
  765. speed_ratio: '', // 语速
  766. is_show: 'false',
  767. },
  768. new_word_list: [],
  769. lrc_arr: [], // lrc 文件解析后的数据
  770. // lrc 文件数据
  771. lrc_data: {
  772. name: '',
  773. url: '',
  774. id: '',
  775. file_id: '',
  776. },
  777. // 音频文件数据
  778. audio_data: {
  779. name: '',
  780. media_duration: 0,
  781. temporary_url: '',
  782. url: '',
  783. file_id: '',
  784. },
  785. wordTime: [], // 字幕时间节点
  786. taskId: '',
  787. file_id_list: [], // 文件 id
  788. multilingual: [], // 多语言
  789. },
  790. notes_list: {
  791. title_con: '',
  792. option: [],
  793. multilingual: [], // 多语言
  794. file_id_list: [], // 文件 id
  795. property: {
  796. view_pinyin: 'false', // 显示拼音
  797. pinyin_position: 'back', // top bottom
  798. is_first_sentence_first_hz_pinyin_first_char_upper_case: 'true', // 句首大写
  799. is_show: 'false',
  800. },
  801. },
  802. sentence_list_mp: [], // 句子+分词数组
  803. pinyin_type: 'pinyin',
  804. };
  805. Object.assign(noTextContentData, resetFieldMap);
  806. return noTextContentData;
  807. },
  808. },
  809. };
  810. </script>
  811. <style lang="scss" scoped>
  812. @use '@/styles/mixin.scss' as *;
  813. .article-preview {
  814. @include preview-base;
  815. .main {
  816. display: grid;
  817. row-gap: 24px;
  818. align-items: center;
  819. }
  820. .NPC-ArticleView {
  821. width: 100%;
  822. .ArticleView-full {
  823. position: absolute;
  824. top: 0;
  825. left: 0;
  826. z-index: 1;
  827. font-size: 16px;
  828. font-weight: bold;
  829. line-height: 24px;
  830. color: #000;
  831. cursor: pointer;
  832. // background: url('@/assets/full-screen-red.png') left center no-repeat;
  833. // background-size: 20px 20px;
  834. }
  835. .ArticleView-header {
  836. position: relative;
  837. display: flex;
  838. align-items: center;
  839. justify-content: space-between;
  840. height: 24px;
  841. margin-bottom: 16px;
  842. .left {
  843. display: flex;
  844. align-items: center;
  845. justify-content: center;
  846. // padding-left: 24px;
  847. font-size: 16px;
  848. font-weight: bold;
  849. line-height: 24px;
  850. cursor: pointer;
  851. // background: url('@/assets/wbfx-icon.png') left center no-repeat;
  852. // background-size: 20px;
  853. img {
  854. width: 20px;
  855. height: 20px;
  856. margin-right: 4px;
  857. }
  858. }
  859. .right {
  860. display: flex;
  861. gap: 24px;
  862. a {
  863. display: flex;
  864. gap: 4px;
  865. align-items: center;
  866. color: rgba(0, 0, 0, 65%);
  867. cursor: pointer;
  868. }
  869. }
  870. .setting-fontsize {
  871. display: flex;
  872. margin-left: 24px;
  873. a {
  874. box-sizing: border-box;
  875. display: block;
  876. width: 24px;
  877. height: 24px;
  878. border: 1px solid rgba(0, 0, 0, 10%);
  879. border-radius: 4px;
  880. }
  881. img {
  882. width: 100%;
  883. }
  884. > img {
  885. width: 24px;
  886. margin: 0 8px;
  887. }
  888. }
  889. }
  890. .ArticleView-body {
  891. box-sizing: border-box;
  892. border: 1px solid rgba(0, 0, 0, 10%);
  893. border-radius: 4px;
  894. .aduioLine-box {
  895. width: 100%;
  896. border-bottom: 1px solid rgba(0, 0, 0, 10%);
  897. &-bottom {
  898. border-top: 1px solid rgba(0, 0, 0, 10%);
  899. border-bottom: none;
  900. }
  901. }
  902. }
  903. }
  904. }
  905. </style>
  906. <style lang="scss">
  907. .NPC-ArticleView {
  908. .ArticleView-header {
  909. .el-switch {
  910. margin-left: 24px;
  911. }
  912. .el-switch__core {
  913. width: 44px !important;
  914. height: 24px;
  915. border-radius: 20px;
  916. }
  917. .el-switch__core::after {
  918. top: 3px;
  919. left: 3px;
  920. }
  921. .el-switch.is-checked .el-switch__core::after {
  922. left: 100%;
  923. margin-left: -19px;
  924. }
  925. .el-switch__label {
  926. color: #000;
  927. }
  928. .el-switch__label.is-active {
  929. color: rgba($color: #000, $alpha: 30%);
  930. }
  931. .el-switch__label--left {
  932. margin-right: 8px;
  933. }
  934. }
  935. .pinyin-16 {
  936. cursor: pointer;
  937. // background: url('@/assets/icon/pinyin-16-normal-red.png') no-repeat left top;
  938. // background-size: 100% 100%;
  939. // &.disabled {
  940. // background: url('@/assets/icon/pinyin-16-disable-Black.png') no-repeat left top;
  941. // background-size: 100% 100%;
  942. // }
  943. }
  944. .EN-16 {
  945. cursor: pointer;
  946. // background: url('@/assets/icon/EN-16-normal-red.png') no-repeat left top;
  947. // background-size: 100% 100%;
  948. // &.disabled {
  949. // background: url('@/assets/icon/EN-16-disable-Black.png') no-repeat left top;
  950. // background-size: 100% 100%;
  951. // }
  952. }
  953. }
  954. .ArticleView-body {
  955. .aduioLine-box {
  956. width: 100%;
  957. border-bottom: 1px solid rgba(0, 0, 0, 10%);
  958. &-bottom {
  959. border-top: 1px solid rgba(0, 0, 0, 10%);
  960. border-bottom: none;
  961. }
  962. }
  963. .el-slider {
  964. flex: 1;
  965. width: auto !important;
  966. }
  967. }
  968. </style>