index.vue 35 KB

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