Practicechs.vue 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. <!-- -->
  2. <template>
  3. <div class="NNPE-ArticleView" v-if="curQue">
  4. <a class="ArticleView-full" @click="fullScreen">全屏模式</a>
  5. <div class="aduioLine-box aduioLine-practice">
  6. <div class="aduioLine-content">
  7. <template
  8. v-if="
  9. curQue.mp3_list &&
  10. curQue.mp3_list.length > 0 &&
  11. curQue.mp3_list[0].id
  12. "
  13. >
  14. <AudioLine
  15. audioId="diaPraAudio"
  16. :mp3="curQue.mp3_list[0].id"
  17. :getCurTime="getCurTime"
  18. ref="audioLine"
  19. :stopAudio="stopAudio"
  20. :width="555"
  21. :isRepeat="isRepeat"
  22. :mp3Source="curQue.mp3_list[0].source"
  23. :ed="ed"
  24. type="audioLine"
  25. @handleChangeStopAudio="handleChangeStopAudio"
  26. @emptyEd="emptyEd"
  27. />
  28. </template>
  29. </div>
  30. <div class="aduioLine-right">
  31. <span
  32. :class="['Repeat-16', isRepeat ? '' : 'disabled']"
  33. @click="changeRepeat"
  34. ></span>
  35. <span
  36. :class="['pinyin-16', config.isShowPY ? '' : 'disabled']"
  37. @click="changePinyin"
  38. ></span>
  39. <span
  40. :class="['EN-16', config.isShowEN ? '' : 'disabled']"
  41. @click="changeEN"
  42. ></span>
  43. </div>
  44. </div>
  45. <template v-if="resObj">
  46. <p class="notice" v-if="curQue.notice" style="padding-top: 24px">
  47. {{ curQue.notice }}
  48. </p>
  49. <div class="NPC-sentences-list">
  50. <div
  51. :class="['NNPE-detail-box', sentIndex == index ? 'active' : '']"
  52. v-for="(item, index) in resObj.sentList"
  53. :key="'detail' + index"
  54. >
  55. <div
  56. class="NNPE-detail"
  57. @click="
  58. handleChangeTime(
  59. curQue.wordTime &&
  60. curQue.wordTime[index] &&
  61. curQue.wordTime[index].bg,
  62. index,
  63. curQue.wordTime &&
  64. curQue.wordTime[index] &&
  65. curQue.wordTime[index].ed
  66. )
  67. "
  68. >
  69. <template v-if="item.sentArr[0].sentIndex == 0">
  70. <RoleChs
  71. :curRole="item.roleDetail"
  72. :color="
  73. (curQue.wordTime &&
  74. curQue.wordTime[index] &&
  75. curTime >= curQue.wordTime[index].bg &&
  76. curTime <= curQue.wordTime[index].ed) ||
  77. sentIndex == index
  78. ? 'rgba(0,0,0,0.85)'
  79. : 'rgba(0,0,0,0.45)'
  80. "
  81. :type="1"
  82. />
  83. </template>
  84. <div v-else style="width: 36px; height: 36px"></div>
  85. <div class="sentence-box">
  86. <template v-if="item.sentArr[0].sentIndex == 0">
  87. <div
  88. class="roleDetail"
  89. v-if="item.roleDetail.detail.wordsList.length > 0"
  90. >
  91. <span
  92. :class="[
  93. 'pinyin',
  94. (curQue.wordTime &&
  95. curQue.wordTime[index] &&
  96. curTime >= curQue.wordTime[index].bg &&
  97. curTime <= curQue.wordTime[index].ed) ||
  98. sentIndex == index
  99. ? 'color85'
  100. : 'color45',
  101. ]"
  102. >{{ item.roleDetail.detail.wordsList | handlePinyin }}</span
  103. >
  104. <span
  105. :class="[
  106. 'chs',
  107. (curQue.wordTime &&
  108. curQue.wordTime[index] &&
  109. curTime >= curQue.wordTime[index].bg &&
  110. curTime <= curQue.wordTime[index].ed) ||
  111. sentIndex == index
  112. ? 'color85'
  113. : 'color45',
  114. ]"
  115. >{{ item.roleDetail.detail.wordsList | handleChs }}</span
  116. >
  117. </div>
  118. </template>
  119. <div
  120. class="sentence-box-inner"
  121. :style="{ background: item.roleDetail.color.bg }"
  122. >
  123. <div class="NNPE-words-box">
  124. <div
  125. class="NNPE-words"
  126. v-for="(pItem, pIndex) in item.sentArr"
  127. :key="'wordsList' + pIndex"
  128. :class="[pItem.wordIndex == 0 ? 'textLeft' : 'textCenter']"
  129. >
  130. <template v-if="!pItem.width">
  131. <template v-if="pItem.isShow">
  132. <template
  133. v-if="
  134. item.sentArr[pIndex + 1] &&
  135. item.sentArr[pIndex + 1].chs &&
  136. chsFhList.indexOf(item.sentArr[pIndex + 1].chs) > -1
  137. "
  138. >
  139. <span class="NNPE-words-box">
  140. <template v-if="curQue.pyPosition == 'top'">
  141. <span
  142. v-if="config.isShowPY"
  143. class="NNPE-pinyin"
  144. :class="[
  145. pItem.className ? pItem.className : '',
  146. sentIndex == index ? 'wordBlank' : '',
  147. noFont.indexOf(pItem.pinyin) > -1
  148. ? 'noFont'
  149. : '',
  150. ]"
  151. >{{ pItem.pinyin }}</span
  152. >
  153. </template>
  154. <span
  155. class="NNPE-chs"
  156. :class="[
  157. pItem.padding && config.isShowPY
  158. ? 'padding'
  159. : '',
  160. sentIndex == index ? 'wordBlank' : '',
  161. ]"
  162. >
  163. <template>
  164. <span
  165. v-for="(wItem, wIndex) in pItem.leg"
  166. :key="'ci' + wIndex + pIndex + index"
  167. :class="[
  168. isPlaying &&
  169. pItem.timeList &&
  170. pItem.timeList[wIndex] &&
  171. curTime >= pItem.timeList[wIndex].wordBg &&
  172. curQue.wordTime &&
  173. curQue.wordTime[index] &&
  174. curTime <= curQue.wordTime[index].ed
  175. ? 'active'
  176. : '',
  177. sentIndex == index ? 'wordBlank' : '',
  178. ]"
  179. >{{ pItem.chs[wIndex] }}</span
  180. >
  181. </template>
  182. </span>
  183. <template v-if="curQue.pyPosition == 'bottom'">
  184. <span
  185. v-if="config.isShowPY"
  186. class="NNPE-pinyin"
  187. :class="[
  188. pItem.className ? pItem.className : '',
  189. sentIndex == index ? 'wordBlank' : '',
  190. noFont.indexOf(pItem.pinyin) > -1
  191. ? 'noFont'
  192. : '',
  193. ]"
  194. >{{ pItem.pinyin }}</span
  195. >
  196. </template>
  197. </span>
  198. <span class="NNPE-words-box">
  199. <template v-if="curQue.pyPosition == 'top'">
  200. <span
  201. v-if="config.isShowPY"
  202. :class="[
  203. 'NNPE-pinyin',
  204. sentIndex == index ? 'wordBlank' : '',
  205. noFont.indexOf(
  206. item.sentArr[pIndex + 1].pinyin
  207. ) > -1
  208. ? 'noFont'
  209. : '',
  210. ]"
  211. style="text-align: left"
  212. >{{ item.sentArr[pIndex + 1].pinyin }}</span
  213. >
  214. </template>
  215. <span class="NNPE-chs" style="text-align: left">
  216. <span
  217. :class="[
  218. isPlaying &&
  219. pItem.timeList[pItem.leg - 1] &&
  220. curTime >=
  221. pItem.timeList[pItem.leg - 1].wordBg &&
  222. curQue.wordTime &&
  223. curQue.wordTime[index] &&
  224. curTime <= curQue.wordTime[index].ed
  225. ? 'active'
  226. : '',
  227. sentIndex == index ? 'wordBlank' : '',
  228. ]"
  229. >
  230. {{ item.sentArr[pIndex + 1].chs }}</span
  231. >
  232. </span>
  233. <template v-if="curQue.pyPosition == 'bottom'">
  234. <span
  235. v-if="config.isShowPY"
  236. :class="[
  237. 'NNPE-pinyin',
  238. sentIndex == index ? 'wordBlank' : '',
  239. noFont.indexOf(
  240. item.sentArr[pIndex + 1].pinyin
  241. ) > -1
  242. ? 'noFont'
  243. : '',
  244. ]"
  245. style="text-align: left"
  246. >{{ item.sentArr[pIndex + 1].pinyin }}</span
  247. >
  248. </template>
  249. </span>
  250. </template>
  251. <template v-else>
  252. <template v-if="curQue.pyPosition == 'top'">
  253. <template
  254. v-if="NumberList.indexOf(pItem.pinyin) < 0"
  255. >
  256. <span
  257. v-if="config.isShowPY"
  258. class="NNPE-pinyin"
  259. :class="[
  260. pItem.padding ? 'padding' : '',
  261. pItem.className ? pItem.className : '',
  262. sentIndex == index ? 'wordBlank' : '',
  263. noFont.indexOf(item.pinyin) > -1
  264. ? 'noFont'
  265. : '',
  266. ]"
  267. >{{ pItem.pinyin }}</span
  268. >
  269. </template>
  270. </template>
  271. <span
  272. v-if="pItem.chs != '#'"
  273. class="NNPE-chs"
  274. :class="[
  275. pItem.padding && config.isShowPY ? 'padding' : '',
  276. sentIndex == index ? 'wordBlank' : '',
  277. ]"
  278. >
  279. <template>
  280. <span
  281. v-for="(wItem, wIndex) in pItem.leg"
  282. :key="'ci' + wIndex + pIndex + index"
  283. :class="[
  284. isPlaying &&
  285. pItem.timeList &&
  286. pItem.timeList[wIndex] &&
  287. curTime >= pItem.timeList[wIndex].wordBg &&
  288. curQue.wordTime &&
  289. curQue.wordTime[index] &&
  290. curTime <= curQue.wordTime[index].ed
  291. ? 'active'
  292. : '',
  293. ]"
  294. >{{ pItem.chs[wIndex] }}</span
  295. >
  296. </template>
  297. </span>
  298. <template v-if="curQue.pyPosition == 'bottom'">
  299. <template
  300. v-if="NumberList.indexOf(pItem.pinyin) < 0"
  301. >
  302. <span
  303. v-if="config.isShowPY"
  304. class="NNPE-pinyin"
  305. :class="[
  306. pItem.padding ? 'padding' : '',
  307. pItem.className ? pItem.className : '',
  308. sentIndex == index ? 'wordBlank' : '',
  309. ]"
  310. >{{ pItem.pinyin }}</span
  311. >
  312. </template>
  313. </template>
  314. </template>
  315. </template>
  316. </template>
  317. <template v-else>
  318. <span
  319. :style="{
  320. height: pItem.height + 'px',
  321. width: pItem.width + 'px',
  322. }"
  323. ></span>
  324. </template>
  325. </div>
  326. </div>
  327. <div style="clear: both; overflow: hidden"></div>
  328. <div
  329. v-if="item.enwords && config.isShowEN"
  330. :class="['enwords', sentIndex == index ? 'wordBlank' : '']"
  331. >
  332. {{ item.enwords }}
  333. </div>
  334. </div>
  335. </div>
  336. </div>
  337. <div v-show="sentIndex == index" class="Soundrecord-content">
  338. <div class="Soundrecord-content-inner">
  339. <Soundrecord
  340. type="promax"
  341. class="luyin-box"
  342. @getWavblob="getWavblob"
  343. @handleParentPlay="handleParentPlay"
  344. @sentPause="sentPause"
  345. :TaskModel="TaskModel"
  346. :answerRecordList="
  347. curQue.Bookanswer.practiceModel[index] &&
  348. curQue.Bookanswer.practiceModel[index].recordList
  349. "
  350. :tmIndex="index"
  351. @handleWav="handleWav"
  352. v-if="refresh"
  353. />
  354. <div
  355. class="compare-box"
  356. v-if="curQue.mp3_list && curQue.mp3_list.length > 0"
  357. >
  358. <Audio-compare
  359. :themeColor="themeColor"
  360. :index="index"
  361. :sentIndex="sentIndex"
  362. :url="curQue.mp3_list[0].id"
  363. :bg="curQue.wordTime[index].bg"
  364. :ed="curQue.wordTime[index].ed"
  365. :wavblob="wavblob"
  366. :getCurTime="getCurTime"
  367. :sentPause="sentPause"
  368. :isRecord="isRecord"
  369. :handleChangeStopAudio="handleChangeStopAudio"
  370. :getPlayStatus="getPlayStatus"
  371. />
  372. </div>
  373. </div>
  374. <span class="full-screen-icon" @click="fullScreen"> </span>
  375. </div>
  376. </div>
  377. </div>
  378. </template>
  379. <div class="voice-full-screen" :id="'screen-' + mathNum">
  380. <Voicefullscreen
  381. v-if="isFull && resObj"
  382. :themeColor="themeColor"
  383. :curQue="curQue"
  384. :sentList="resObj.sentList"
  385. :sentIndex="sentIndex"
  386. :mp3="curQue.mp3_list[0].id"
  387. :noFont="noFont"
  388. :NNPENewWordList="NNPENewWordList"
  389. :currentTreeID="currentTreeID"
  390. :isFull="isFull"
  391. :config="config"
  392. :TaskModel="TaskModel"
  393. @handleWav="handleWav"
  394. @changePinyin="changePinyin"
  395. @changeEN="changeEN"
  396. @exitFullscreen="exitFullscreen"
  397. @changeIsFull="changeIsFull"
  398. />
  399. </div>
  400. </div>
  401. </template>
  402. <script>
  403. import { timeStrToSen } from "../../../../utils/index";
  404. import AudioLine from "../AudioLine.vue";
  405. import Soundrecord from "../../preview/Soundrecord.vue"; // 录音模板
  406. import RoleChs from "./RoleChs.vue";
  407. import AudioCompare from "../AudioCompare.vue";
  408. import Voicefullscreen from "../Voicefullscreen.vue";
  409. export default {
  410. name: "ArticleView",
  411. props: [
  412. "curQue",
  413. "colorBox",
  414. "noFont",
  415. "themeColor",
  416. "config",
  417. "NNPENewWordList",
  418. "currentTreeID",
  419. "TaskModel",
  420. ],
  421. components: {
  422. AudioLine,
  423. Soundrecord,
  424. RoleChs,
  425. AudioCompare,
  426. Voicefullscreen,
  427. },
  428. filters: {
  429. handlePinyin(wordsList) {
  430. let str = "";
  431. wordsList.forEach((item, index) => {
  432. if (index < wordsList.length - 1) {
  433. str += item.pinyin + " ";
  434. } else {
  435. str += item.pinyin;
  436. }
  437. });
  438. return str;
  439. },
  440. handleChs(wordsList) {
  441. let str = "";
  442. wordsList.forEach((item, index) => {
  443. if (index < wordsList.length - 1) {
  444. str += item.chs + " ";
  445. } else {
  446. str += item.chs;
  447. }
  448. });
  449. return str;
  450. },
  451. },
  452. data() {
  453. return {
  454. wavblob: null,
  455. resObj: null,
  456. curTime: 0, //单位s
  457. chsFhList: [",", "。", "“", ":", "》", "《", "?", "!", ";"],
  458. enFhList: [",", ".", ";", "?", "!", ":", ">", "<"],
  459. NumberList: [
  460. "①",
  461. "②",
  462. "③",
  463. "④",
  464. "⑤",
  465. "⑥",
  466. "⑦",
  467. "⑧",
  468. "⑨",
  469. "⑩",
  470. "⑪",
  471. "⑫",
  472. "⑬",
  473. "⑭",
  474. "⑮",
  475. "⑯",
  476. "⑰",
  477. "⑱",
  478. "⑲",
  479. "⑳",
  480. ],
  481. stopAudio: false,
  482. sentIndex: 0,
  483. isRepeat: false,
  484. currSent: null, //当前句子的时间
  485. isRecord: false,
  486. isFull: false,
  487. mathNum: Math.random().toString(36).substr(2),
  488. ed: undefined,
  489. refresh: true,
  490. };
  491. },
  492. computed: {
  493. isPlaying: function () {
  494. let playing = false;
  495. if (this.$refs.audioLine) {
  496. playing = this.$refs.audioLine.audio.isPlaying;
  497. }
  498. return playing;
  499. },
  500. },
  501. watch: {
  502. sentIndex: {
  503. handler: function (newVal, oldVal) {
  504. if (newVal != oldVal) {
  505. this.wavblob = "";
  506. }
  507. },
  508. deep: true,
  509. },
  510. isFull: {
  511. handler: function (newVal, oldVal) {
  512. let _this = this;
  513. _this.refresh = false;
  514. if (!newVal) {
  515. _this.$nextTick(() => {
  516. // 重新渲染组件
  517. _this.refresh = true;
  518. });
  519. }
  520. },
  521. deep: true,
  522. },
  523. },
  524. //方法集合
  525. methods: {
  526. getPlayStatus(val) {
  527. //this.isPlaying = val;
  528. },
  529. pauseAudio() {
  530. let audio = document.getElementsByTagName("audio");
  531. audio.forEach((item) => {
  532. item.pause();
  533. });
  534. },
  535. pauseVideo() {
  536. let video = document.getElementsByTagName("video");
  537. video.forEach((item) => {
  538. item.pause();
  539. });
  540. },
  541. //语音全屏
  542. fullScreen(type) {
  543. this.pauseAudio();
  544. this.pauseVideo();
  545. this.isFull = true;
  546. this.goFullscreen();
  547. },
  548. goFullscreen() {
  549. let id = "screen-" + this.mathNum;
  550. var element = document.getElementById(id);
  551. if (element.requestFullscreen) {
  552. element.requestFullscreen();
  553. } else if (element.msRequestFullscreen) {
  554. element.msRequestFullscreen();
  555. } else if (element.mozRequestFullScreen) {
  556. element.mozRequestFullScreen();
  557. } else if (element.webkitRequestFullscreen) {
  558. element.webkitRequestFullscreen();
  559. }
  560. },
  561. exitFullscreen() {
  562. this.isFull = false;
  563. if (document.exitFullscreen) {
  564. document.exitFullscreen();
  565. } else if (document.msExitFullscreen) {
  566. document.msExitFullscreen();
  567. } else if (document.mozCancelFullScreen) {
  568. document.mozCancelFullScreen();
  569. } else if (document.webkitExitFullscreen) {
  570. document.webkitExitFullscreen();
  571. }
  572. },
  573. changeIsFull() {
  574. this.isFull = false;
  575. },
  576. getWavblob(wavblob) {
  577. this.wavblob = wavblob;
  578. },
  579. sentPause(isRecord) {
  580. this.isRecord = isRecord;
  581. },
  582. getCurTime(curTime) {
  583. let _this = this;
  584. if (_this.isRepeat) {
  585. let time = curTime * 1000;
  586. console.log(time, _this.currSent.ed);
  587. if (time > _this.currSent.ed || time < _this.currSent.bg) {
  588. _this.curTime = _this.currSent.bg;
  589. this.$refs.audioLine.onTimeupdateTime(_this.currSent.bg / 1000);
  590. } else {
  591. _this.curTime = curTime * 1000;
  592. }
  593. } else {
  594. _this.curTime = curTime * 1000;
  595. _this.getSentIndex(_this.curTime);
  596. }
  597. },
  598. getSentIndex(curTime) {
  599. for (let i = 0; i < this.curQue.wordTime.length; i++) {
  600. let bg = this.curQue.wordTime[i].bg;
  601. let ed = this.curQue.wordTime[i].ed;
  602. if (curTime >= bg && curTime <= ed) {
  603. this.sentIndex = i;
  604. break;
  605. }
  606. }
  607. },
  608. handleData() {
  609. let resArr = [],
  610. timeArr = [],
  611. sentArrTotal = [],
  612. enList = [];
  613. let curQue = JSON.parse(JSON.stringify(this.curQue));
  614. let wordTimeList = curQue.wordTime;
  615. curQue.detail.forEach((dItem, dIndex) => {
  616. let roleDetail = this.getRole(dItem);
  617. dItem.wordsList.forEach((sItem, sIndex) => {
  618. let sentArr = [];
  619. sItem.forEach((wItem, wIndex) => {
  620. let startIndex =
  621. wIndex == 0
  622. ? 0
  623. : sentArr[wIndex - 1].startIndex +
  624. sentArr[wIndex - 1].chs.length;
  625. let endIndex =
  626. wIndex == 0
  627. ? wItem.chs.length
  628. : sentArr[wIndex - 1].endIndex + wItem.chs.length;
  629. // this.judgePad(sItem, wItem, wIndex);
  630. this.mergeWordSymbol(wItem);
  631. let obj = {
  632. paraIndex: dIndex, //段落索引
  633. sentIndex: sIndex, //在段落中句子索引
  634. wordIndex: wIndex, //单词的索引
  635. pinyin: wItem.pinyin,
  636. chs: wItem.chs,
  637. padding: true,
  638. className: wItem.className,
  639. isShow: wItem.isShow,
  640. startIndex: startIndex,
  641. endIndex: endIndex,
  642. leg: wItem.chs.length,
  643. timeList: [],
  644. };
  645. sentArr.push(obj);
  646. });
  647. let obj = {
  648. roleDetail: roleDetail,
  649. sentArr: sentArr,
  650. enwords: dItem.sentencesEn && dItem.sentencesEn[sIndex],
  651. };
  652. sentArrTotal.push(sentArr);
  653. resArr.push(obj);
  654. });
  655. });
  656. if (wordTimeList && wordTimeList.length > 0) {
  657. this.mergeWordTime(sentArrTotal, wordTimeList);
  658. }
  659. this.resObj = { sentList: resArr };
  660. console.log("语音练习");
  661. console.log(this.resObj);
  662. },
  663. //获取角色
  664. getRole(dItem) {
  665. let roleIndex = dItem.roleIndex;
  666. let resObj = null;
  667. let roleList = JSON.parse(JSON.stringify(this.curQue.roleList));
  668. for (let i = 0; i < roleList.length; i++) {
  669. let item = roleList[i];
  670. if (item.id == roleIndex) {
  671. resObj = item;
  672. resObj.color = this.colorBox[i];
  673. break;
  674. }
  675. }
  676. return resObj;
  677. },
  678. mergeWordTime(resArr, wordTimeList) {
  679. resArr.forEach((item, index) => {
  680. let wordsResultList = wordTimeList[index].wordsResultList;
  681. item.forEach((wItem) => {
  682. let startIndex = wItem.startIndex;
  683. let endIndex = wItem.endIndex;
  684. wItem.timeList = wordsResultList.slice(startIndex, endIndex);
  685. });
  686. });
  687. },
  688. //词和标点合一起
  689. mergeWordSymbol(wItem) {
  690. if (this.chsFhList.indexOf(wItem.chs) > -1) {
  691. wItem.isShow = false;
  692. } else {
  693. wItem.isShow = true;
  694. }
  695. },
  696. //判断是否有padding
  697. judgePad(sItem, wItem, curIndex) {
  698. let leg = sItem.length;
  699. if (curIndex < leg - 1) {
  700. let nextIndex = curIndex + 1;
  701. let chs = sItem[nextIndex].chs;
  702. if (
  703. this.chsFhList.indexOf(chs) > -1 ||
  704. this.chsFhList.indexOf(wItem.chs) > -1
  705. ) {
  706. wItem.padding = false;
  707. } else {
  708. wItem.padding = true;
  709. }
  710. if (this.enFhList.indexOf(wItem.pinyin) > -1) {
  711. wItem.className = "textLeft";
  712. }
  713. }
  714. },
  715. //转化时间
  716. handleTimeList(list) {
  717. let listRes = [];
  718. list.forEach((item) => {
  719. let res = timeStrToSen(item);
  720. listRes.push(res);
  721. });
  722. return listRes;
  723. },
  724. //计算总时间
  725. countWordTime(sentArr) {
  726. let total = 0;
  727. sentArr.forEach((item) => {
  728. total += item.endTime;
  729. });
  730. return total;
  731. },
  732. //点击播放某个句子
  733. handleChangeTime(time, index, ed) {
  734. let _this = this;
  735. if (_this.isRepeat) {
  736. _this.currSent = _this.curQue.wordTime[index];
  737. }
  738. _this.sentIndex = index;
  739. _this.ed = ed;
  740. if (time) {
  741. _this.curTime = time;
  742. _this.$refs.audioLine.onTimeupdateTime(time / 1000, true);
  743. }
  744. },
  745. emptyEd() {
  746. this.ed = undefined;
  747. },
  748. handleWav(list, tmIndex) {
  749. tmIndex = tmIndex ? tmIndex : 0;
  750. this.curQue.Bookanswer.practiceModel[tmIndex] = {
  751. recordList: [],
  752. };
  753. this.$set(
  754. this.curQue.Bookanswer.practiceModel[tmIndex],
  755. "recordList",
  756. list
  757. );
  758. },
  759. // 录音时暂停音频播放
  760. handleParentPlay() {
  761. this.stopAudio = true;
  762. },
  763. // 音频播放时改变布尔值
  764. handleChangeStopAudio() {
  765. this.stopAudio = false;
  766. },
  767. //拼音的显示和隐藏
  768. changePinyin() {
  769. if (this.config.isHasPY) {
  770. this.$emit("changeConfig", "isShowPY");
  771. }
  772. },
  773. // 英文的显示和隐藏
  774. changeEN() {
  775. if (this.config.isHasEN) {
  776. this.$emit("changeConfig", "isShowEN");
  777. }
  778. },
  779. // 单句是否重复播放
  780. changeRepeat() {
  781. let _this = this;
  782. _this.isRepeat = !_this.isRepeat;
  783. this.currSent = _this.curQue.wordTime[_this.sentIndex];
  784. },
  785. },
  786. //生命周期 - 创建完成(可以访问当前this实例)
  787. created() {},
  788. //生命周期 - 挂载完成(可以访问DOM元素)
  789. mounted() {
  790. if (this.curQue) {
  791. this.handleData();
  792. }
  793. },
  794. beforeCreate() {}, //生命周期 - 创建之前
  795. beforeMount() {}, //生命周期 - 挂载之前
  796. beforeUpdate() {}, //生命周期 - 更新之前
  797. updated() {}, //生命周期 - 更新之后
  798. beforeDestroy() {}, //生命周期 - 销毁之前
  799. destroyed() {}, //生命周期 - 销毁完成
  800. activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
  801. };
  802. </script>
  803. <style lang='scss' scoped>
  804. //@import url(); 引入公共css类
  805. .NNPE-ArticleView {
  806. width: 100%;
  807. position: relative;
  808. .ArticleView-full {
  809. position: absolute;
  810. top: -33px;
  811. background: url("../../../../assets/NPC/full-screen-red.png") left center
  812. no-repeat;
  813. background-size: 16px 16px;
  814. padding-left: 24px;
  815. color: #000000;
  816. font-size: 14px;
  817. line-height: 24px;
  818. font-weight: bold;
  819. left: 0;
  820. z-index: 99999;
  821. }
  822. .NPC-sentences-list {
  823. padding: 0px 0 24px 0;
  824. }
  825. .aduioLine-content {
  826. flex: 1;
  827. }
  828. .aduioLine-practice {
  829. display: flex;
  830. justify-content: flex-start;
  831. align-items: center;
  832. .aduioLine-right {
  833. display: flex;
  834. justify-content: space-between;
  835. align-items: center;
  836. width: 92px;
  837. height: 40px;
  838. box-sizing: border-box;
  839. padding: 0 12px;
  840. border-left: 1px solid rgba(0, 0, 0, 0.1);
  841. > span {
  842. width: 16px;
  843. height: 16px;
  844. cursor: pointer;
  845. }
  846. }
  847. }
  848. .NNPE-detail-box {
  849. &.active {
  850. background: rgba(0, 0, 0, 0.06);
  851. }
  852. }
  853. .enwords {
  854. font-family: "robot";
  855. font-weight: normal;
  856. font-size: 14px;
  857. line-height: 22px;
  858. color: rgba(0, 0, 0, 0.45);
  859. padding-left: 3px;
  860. &.wordBlank {
  861. color: rgba(0, 0, 0, 0.85);
  862. }
  863. }
  864. .NNPE-detail {
  865. display: flex;
  866. justify-content: flex-start;
  867. align-items: flex-start;
  868. clear: both;
  869. overflow: hidden;
  870. width: 100%;
  871. box-sizing: border-box;
  872. padding: 8px 24px 8px;
  873. color: rgba(0, 0, 0, 0.45);
  874. .sentence-box {
  875. padding-left: 8px;
  876. clear: both;
  877. overflow: hidden;
  878. &-inner {
  879. padding: 8px 12px;
  880. box-sizing: border-box;
  881. border-radius: 8px;
  882. border: 1px solid rgba(0, 0, 0, 0.1);
  883. float: left;
  884. }
  885. .roleDetail {
  886. height: 36px;
  887. display: flex;
  888. justify-content: flex-start;
  889. align-items: center;
  890. .pinyin {
  891. font-family: "GB-PINYINOK-B";
  892. font-size: 14px;
  893. line-height: 22px;
  894. color: rgba(0, 0, 0, 0.85);
  895. margin-right: 4px;
  896. &.noFont {
  897. font-family: initial;
  898. }
  899. }
  900. .chs {
  901. font-family: "FZJCGFKTK";
  902. font-size: 16px;
  903. line-height: 24px;
  904. color: rgba(0, 0, 0, 0.85);
  905. }
  906. .color85 {
  907. color: rgba(0, 0, 0, 0.85);
  908. }
  909. .color45 {
  910. color: rgba(0, 0, 0, 0.45);
  911. }
  912. }
  913. }
  914. .NNPE-words {
  915. float: left;
  916. &-box {
  917. float: left;
  918. > span {
  919. display: block;
  920. &.NNPE-pinyin {
  921. font-family: "GB-PINYINOK-B";
  922. font-weight: normal;
  923. font-size: 14px;
  924. line-height: 20px;
  925. height: 20px;
  926. &.noFont {
  927. font-family: initial;
  928. }
  929. &.textLeft {
  930. text-align: left;
  931. }
  932. &.wordBlank {
  933. color: rgba(0, 0, 0, 0.85);
  934. }
  935. }
  936. &.NNPE-chs {
  937. font-family: "FZJCGFKTK";
  938. font-size: 20px;
  939. line-height: 28px;
  940. .active {
  941. color: #de4444;
  942. }
  943. &.wordBlank {
  944. color: rgba(0, 0, 0, 0.85);
  945. }
  946. }
  947. // &.padding {
  948. // padding-right: 6px;
  949. // }
  950. }
  951. }
  952. &.textLeft {
  953. text-align: left;
  954. }
  955. &.textCenter {
  956. text-align: center;
  957. }
  958. > span {
  959. display: block;
  960. &.NNPE-pinyin {
  961. font-family: "GB-PINYINOK-B";
  962. font-weight: normal;
  963. font-size: 14px;
  964. line-height: 20px;
  965. height: 20px;
  966. &.noFont {
  967. font-family: initial;
  968. }
  969. &.textLeft {
  970. text-align: left;
  971. }
  972. &.wordBlank {
  973. color: rgba(0, 0, 0, 0.85);
  974. }
  975. }
  976. &.NNPE-chs {
  977. font-family: "FZJCGFKTK";
  978. font-size: 20px;
  979. line-height: 28px;
  980. .active {
  981. color: #de4444;
  982. }
  983. &.wordBlank {
  984. color: rgba(0, 0, 0, 0.85);
  985. }
  986. }
  987. &.padding {
  988. padding: 0 3px;
  989. }
  990. }
  991. }
  992. }
  993. .Soundrecord-content {
  994. padding: 0px 10px 8px 68px;
  995. display: flex;
  996. justify-content: space-between;
  997. align-items: center;
  998. &-inner {
  999. display: flex;
  1000. justify-content: flex-start;
  1001. align-items: center;
  1002. width: 304px;
  1003. border-radius: 8px;
  1004. background: #ffffff;
  1005. padding: 4px 12px;
  1006. border: 1px solid rgba(0, 0, 0, 0.1);
  1007. .luyin-box {
  1008. width: 280px;
  1009. }
  1010. .compare-box {
  1011. height: 32px;
  1012. display: flex;
  1013. justify-content: center;
  1014. align-items: center;
  1015. }
  1016. }
  1017. .full-screen-icon {
  1018. width: 16px;
  1019. height: 16px;
  1020. background: url("../../../../assets/NPC/full-screen-red.png") no-repeat
  1021. left top;
  1022. background-size: 100% 100%;
  1023. cursor: pointer;
  1024. }
  1025. }
  1026. .voice-full-screen {
  1027. // position: fixed;
  1028. // top: 0;
  1029. // left: 0;
  1030. // z-index: 9999;
  1031. }
  1032. }
  1033. </style>
  1034. <style lang="scss">
  1035. .NPC-Big-Book-preview-green {
  1036. .NNPE-ArticleView {
  1037. .ArticleView-full {
  1038. background: url("../../../../assets/NPC/full-screen-green.png") left
  1039. center no-repeat;
  1040. background-size: 16px 16px;
  1041. }
  1042. .Soundrecord-content {
  1043. .full-screen-icon {
  1044. background: url("../../../../assets/NPC/full-screen-green.png") left
  1045. center no-repeat;
  1046. background-size: 16px 16px;
  1047. }
  1048. }
  1049. }
  1050. }
  1051. .NPC-Big-Book-preview-brown {
  1052. .Soundrecord-content {
  1053. .ArticleView-full {
  1054. background: url("../../../../assets/NPC/full-screen-brown.png") left
  1055. center no-repeat;
  1056. background-size: 16px 16px;
  1057. }
  1058. .full-screen-icon {
  1059. background: url("../../../../assets/NPC/full-screen-brown.png") left
  1060. center no-repeat;
  1061. background-size: 16px 16px;
  1062. }
  1063. }
  1064. }
  1065. </style>