PhraseModelChs.vue 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387
  1. <!-- -->
  2. <template>
  3. <div class="NNPE-ArticleView" v-if="curQue">
  4. <div
  5. class="aduioLine-box aduioLine-practice-npc"
  6. v-if="
  7. (curQue.mp3_list &&
  8. curQue.mp3_list.length > 0 &&
  9. curQue.mp3_list[0].id) ||
  10. config.isHasPY ||
  11. config.isHasEN
  12. "
  13. >
  14. <div class="aduioLine-content">
  15. <template
  16. v-if="
  17. curQue.mp3_list &&
  18. curQue.mp3_list.length > 0 &&
  19. curQue.mp3_list[0].id
  20. "
  21. >
  22. <AudioLine
  23. audioId="diaPhraAudio"
  24. :mp3="curQue.mp3_list[0].id"
  25. :getCurTime="getCurTime"
  26. :mp3Source="curQue.mp3_list[0].source"
  27. :width="windowWidth - 220"
  28. ref="audioLine"
  29. :baseSizePhone="baseSizePhone"
  30. />
  31. </template>
  32. </div>
  33. <div class="aduioLine-right">
  34. <span
  35. :class="['pinyin-16', config.isShowPY ? '' : 'disabled']"
  36. @click="changePinyin"
  37. v-if="config.isHasPY"
  38. ></span>
  39. <span
  40. :class="['EN-16', config.isShowEN ? '' : 'disabled']"
  41. @click="changeEN"
  42. v-if="config.isHasEN"
  43. ></span>
  44. </div>
  45. </div>
  46. <template v-if="resArr.length > 0">
  47. <div class="NPC-sentences-list">
  48. <div class="NPC-article-empty">
  49. <div :class="['empty-left', isHasRemark ? 'hasRemark' : '']"></div>
  50. <div class="empty-right"></div>
  51. </div>
  52. <p
  53. :class="['notice', isHasRemark ? 'hasRemark' : '']"
  54. v-if="curQue.notice"
  55. :style="{ fontSize: baseSizePhone + 'px' }"
  56. >
  57. {{ curQue.notice }}
  58. </p>
  59. <div
  60. :class="['NNPE-detail', item.isTitle ? 'NNPE-detail-title' : '']"
  61. v-for="(item, index) in resArr"
  62. :key="'detail' + index"
  63. >
  64. <div :class="['article-content', isHasRemark ? 'hasRemark' : '']">
  65. <RoleChs
  66. :curRole="item.roleDetail"
  67. :type="1"
  68. :baseSizePhone="baseSizePhone"
  69. />
  70. <div class="wordsList-box">
  71. <img
  72. :src="articleImg[index]"
  73. v-if="articleImg[0] && index == 0"
  74. />
  75. <div
  76. class="roleDetail"
  77. v-if="item.roleDetail.detail.wordsList.length > 0"
  78. >
  79. <span
  80. class="pinyin"
  81. :style="{ fontSize: baseSizePhone + 'px' }"
  82. >{{ item.roleDetail.detail.wordsList | handlePinyin }}</span
  83. >
  84. <span
  85. class="chs"
  86. :style="{ fontSize: baseSizePhone + 2 + 'px' }"
  87. >{{ item.roleDetail.detail.wordsList | handleChs }}</span
  88. >
  89. </div>
  90. <div
  91. class="para-con"
  92. :style="{ background: item.roleDetail.color.bg }"
  93. >
  94. <div
  95. v-if="
  96. config.isShowEN &&
  97. item.enwords &&
  98. curQue.enPosition &&
  99. curQue.enPosition == 'top'
  100. "
  101. class="enwords"
  102. :style="{ fontSize: baseSizePhone + 'px' }"
  103. >
  104. {{ item.enwords }}
  105. </div>
  106. <div style="clear: both; overflow: hidden"></div>
  107. <div
  108. class="NNPE-words"
  109. v-for="(pItem, pIndex) in item.wordsList"
  110. :key="'wordsList' + pIndex"
  111. :class="[
  112. pItem.chs != '“' && pItem.wordIndex == 0
  113. ? 'textLeft'
  114. : 'textCenter',
  115. pItem.chs == '“' ? 'textRight' : ''
  116. ]"
  117. @click="showWordDetail($event, pItem.chs, pItem.words)"
  118. >
  119. <template v-if="!pItem.width">
  120. <template v-if="pItem.isShow">
  121. <template
  122. v-if="
  123. item.wordsList[pIndex + 1] &&
  124. item.wordsList[pIndex + 1].chs &&
  125. (chsFhList.indexOf(item.wordsList[pIndex + 1].chs) >
  126. -1 ||
  127. NumberList.indexOf(
  128. item.wordsList[pIndex + 1].chs
  129. ) > -1)
  130. "
  131. >
  132. <span class="NNPE-words-box">
  133. <span
  134. v-if="
  135. curQue.pyPosition == 'top' &&
  136. config.isShowPY &&
  137. item.dhaspinyin
  138. "
  139. class="NNPE-pinyin"
  140. :class="[
  141. pItem.className ? pItem.className : '',
  142. noFont.indexOf(item.pinyin) > -1 ? 'noFont' : ''
  143. ]"
  144. @click.stop="viewNotes($event, pItem.pinyin)"
  145. :style="{ fontSize: baseSizePhone + 'px' }"
  146. >{{ pItem.pinyin }}</span
  147. >
  148. <span
  149. class="NNPE-chs"
  150. :class="[
  151. newWordList.indexOf(pItem.chs) > -1
  152. ? 'newActive'
  153. : '',
  154. pItem.words ? 'newActive' : ''
  155. ]"
  156. @click.stop="
  157. viewNotes(
  158. $event,
  159. pItem.words ? pItem.words : pItem.chs
  160. )
  161. "
  162. :style="{
  163. fontFamily: pItem.config.fontFamily,
  164. height: '28px',
  165. display: 'inline-block',
  166. fontSize: baseSizePhone + 6 + 'px'
  167. }"
  168. >{{
  169. NumberList.indexOf(pItem.pinyin) == -1
  170. ? pItem.chs
  171. : ""
  172. }}</span
  173. >
  174. <span
  175. v-if="
  176. curQue.pyPosition == 'bottom' &&
  177. config.isShowPY &&
  178. item.dhaspinyin
  179. "
  180. class="NNPE-pinyin"
  181. :class="[
  182. pItem.className ? pItem.className : '',
  183. noFont.indexOf(item.pinyin) > -1 ? 'noFont' : ''
  184. ]"
  185. @click.stop="viewNotes($event, pItem.pinyin)"
  186. :style="{ fontSize: baseSizePhone + 'px' }"
  187. >{{ pItem.pinyin }}</span
  188. >
  189. </span>
  190. <span class="NNPE-words-box">
  191. <span
  192. v-if="
  193. curQue.pyPosition == 'top' &&
  194. config.isShowPY &&
  195. item.dhaspinyin
  196. "
  197. class="NNPE-pinyin"
  198. style="text-align: left"
  199. :class="[
  200. noFont.indexOf(
  201. item.wordsList[pIndex + 1].pinyin
  202. ) > -1
  203. ? 'noFont'
  204. : ''
  205. ]"
  206. @click.stop="
  207. viewNotes(
  208. $event,
  209. item.wordsList[pIndex + 1].pinyin
  210. )
  211. "
  212. :style="{ fontSize: baseSizePhone + 'px' }"
  213. >{{ item.wordsList[pIndex + 1].pinyin }}</span
  214. >
  215. <span
  216. class="NNPE-chs"
  217. style="text-align: left"
  218. @click.stop="
  219. viewNotes(
  220. $event,
  221. item.wordsList[pIndex + 1].words
  222. ? item.wordsList[pIndex + 1].words
  223. : item.wordsList[pIndex + 1].chs
  224. )
  225. "
  226. :style="{
  227. fontFamily:
  228. item.wordsList[pIndex + 1].config.fontFamily,
  229. height: '28px',
  230. display: 'inline-block',
  231. fontSize: baseSizePhone + 6 + 'px'
  232. }"
  233. >{{
  234. NumberList.indexOf(
  235. item.wordsList[pIndex + 1].pinyin
  236. ) == -1
  237. ? item.wordsList[pIndex + 1].chs
  238. : ""
  239. }}</span
  240. >
  241. <span
  242. v-if="
  243. curQue.pyPosition == 'bottom' &&
  244. config.isShowPY &&
  245. item.dhaspinyin
  246. "
  247. class="NNPE-pinyin"
  248. :class="[
  249. noFont.indexOf(
  250. item.wordsList[pIndex + 1].pinyin
  251. ) > -1
  252. ? 'noFont'
  253. : ''
  254. ]"
  255. @click.stop="
  256. viewNotes(
  257. $event,
  258. item.wordsList[pIndex + 1].pinyin
  259. )
  260. "
  261. style="text-align: left"
  262. :style="{ fontSize: baseSizePhone + 'px' }"
  263. >{{ item.wordsList[pIndex + 1].pinyin }}</span
  264. >
  265. </span>
  266. <span
  267. class="NNPE-words-box"
  268. v-if="
  269. item.wordsList[pIndex + 2] &&
  270. item.wordsList[pIndex + 2].chs &&
  271. (chsFhList.indexOf(
  272. item.wordsList[pIndex + 2].chs
  273. ) > -1 ||
  274. NumberList.indexOf(
  275. item.wordsList[pIndex + 2].chs
  276. ) > -1)
  277. "
  278. >
  279. <span
  280. v-if="
  281. curQue.pyPosition == 'top' &&
  282. config.isShowPY &&
  283. item.dhaspinyin
  284. "
  285. :class="[
  286. 'NNPE-pinyin',
  287. noFont.indexOf(
  288. item.wordsList[pIndex + 2].pinyin
  289. ) > -1
  290. ? 'noFont'
  291. : ''
  292. ]"
  293. @click.stop="
  294. viewNotes(
  295. $event,
  296. item.wordsList[pIndex + 2].pinyin
  297. )
  298. "
  299. style="text-align: left"
  300. :style="{ fontSize: baseSizePhone + 'px' }"
  301. >{{ item.wordsList[pIndex + 2].pinyin }}</span
  302. >
  303. <span
  304. class="NNPE-chs"
  305. style="text-align: left"
  306. :class="[
  307. pItem.chstimeList &&
  308. pItem.chstimeList[pItem.leg - 1] &&
  309. curTime >=
  310. pItem.chstimeList[pItem.leg - 1].wordBg &&
  311. curQue.wordTime &&
  312. curTime <= item.timeList[pItem.sentIndex].ed
  313. ? 'wordActive'
  314. : ''
  315. ]"
  316. @click.stop="
  317. viewNotes(
  318. $event,
  319. item.wordsList[pIndex + 2].words
  320. ? item.wordsList[pIndex + 2].words
  321. : item.wordsList[pIndex + 2].chs
  322. )
  323. "
  324. :style="{
  325. fontFamily:
  326. item.wordsList[pIndex + 2].config.fontFamily,
  327. height: '28px',
  328. display: 'inline-block',
  329. fontSize: baseSizePhone + 6 + 'px'
  330. }"
  331. >{{
  332. NumberList.indexOf(
  333. item.wordsList[pIndex + 2].pinyin
  334. ) == -1
  335. ? item.wordsList[pIndex + 2].chs
  336. : ""
  337. }}</span
  338. >
  339. <span
  340. v-if="
  341. curQue.pyPosition == 'bottom' &&
  342. config.isShowPY &&
  343. item.dhaspinyin
  344. "
  345. :class="[
  346. 'NNPE-pinyin',
  347. noFont.indexOf(
  348. item.wordsList[pIndex + 2].pinyin
  349. ) > -1
  350. ? 'noFont'
  351. : ''
  352. ]"
  353. @click.stop="
  354. viewNotes(
  355. $event,
  356. item.wordsList[pIndex + 2].pinyin
  357. )
  358. "
  359. style="text-align: left"
  360. :style="{ fontSize: baseSizePhone + 'px' }"
  361. >{{ item.wordsList[pIndex + 2].pinyin }}</span
  362. >
  363. </span>
  364. </template>
  365. <template v-else>
  366. <span
  367. v-if="
  368. curQue.pyPosition == 'top' &&
  369. config.isShowPY &&
  370. item.dhaspinyin
  371. "
  372. class="NNPE-pinyin"
  373. :class="[
  374. pItem.chs != '“' && pItem.padding ? 'padding' : '',
  375. pItem.className ? pItem.className : '',
  376. noFont.indexOf(pItem.pinyin) > -1 ? 'noFont' : ''
  377. ]"
  378. :style="{ fontSize: baseSizePhone + 'px' }"
  379. @click.stop="viewNotes($event, pItem.pinyin)"
  380. >{{ pItem.pinyin }}</span
  381. >
  382. <span
  383. v-if="pItem.chs != '#'"
  384. class="NNPE-chs"
  385. :class="[
  386. newWordList.indexOf(pItem.chs) > -1
  387. ? 'newActive'
  388. : '',
  389. pItem.chs != '“' && pItem.padding && config.isShowPY
  390. ? 'padding'
  391. : '',
  392. pItem.words ? 'newActive' : ''
  393. ]"
  394. @click.stop="
  395. viewNotes(
  396. $event,
  397. pItem.words ? pItem.words : pItem.chs
  398. )
  399. "
  400. :style="{
  401. fontFamily: pItem.config.fontFamily,
  402. height: '28px',
  403. display: 'inline-block',
  404. fontSize: baseSizePhone + 6 + 'px'
  405. }"
  406. >{{
  407. NumberList.indexOf(pItem.pinyin) == -1
  408. ? pItem.chs
  409. : ""
  410. }}</span
  411. >
  412. <span
  413. v-if="
  414. curQue.pyPosition == 'bottom' &&
  415. config.isShowPY &&
  416. item.dhaspinyin
  417. "
  418. class="NNPE-pinyin"
  419. :class="[
  420. pItem.chs != '“' && pItem.padding ? 'padding' : '',
  421. pItem.className ? pItem.className : '',
  422. noFont.indexOf(pItem.pinyin) > -1 ? 'noFont' : ''
  423. ]"
  424. :style="{ fontSize: baseSizePhone + 'px' }"
  425. @click.stop="viewNotes($event, pItem.pinyin)"
  426. >{{ pItem.pinyin }}</span
  427. >
  428. </template>
  429. </template>
  430. </template>
  431. <template v-else>
  432. <span
  433. :style="{
  434. height: pItem.height + 'px',
  435. width: pItem.width + 'px'
  436. }"
  437. ></span>
  438. </template>
  439. </div>
  440. <div style="clear: both; overflow: hidden"></div>
  441. <div
  442. v-if="
  443. config.isShowEN &&
  444. item.enwords &&
  445. (!curQue.enPosition ||
  446. (curQue.enPosition && curQue.enPosition == 'bottom'))
  447. "
  448. class="enwords"
  449. :style="{ fontSize: baseSizePhone + 'px' }"
  450. >
  451. {{ item.enwords }}
  452. </div>
  453. </div>
  454. <img :src="articleImg[index + 1]" v-if="articleImg[index + 1]" />
  455. </div>
  456. </div>
  457. <div class="remarkBox remark-top">
  458. <RemarkChs
  459. :remarkDetail="item.remarkDetail"
  460. :marginTop="item.roleDetail.detail.wordsList.length > 0 ? 44 : 8"
  461. :baseSizePhone="baseSizePhone"
  462. />
  463. </div>
  464. </div>
  465. <div class="NPC-article-empty NPC-article-empty-bottom">
  466. <div :class="['empty-left', isHasRemark ? 'hasRemark' : '']"></div>
  467. <div class="empty-right"></div>
  468. </div>
  469. <div class="dia-article-record" v-if="1 == 2">
  470. <Soundrecord @handleWav="handleWav" type="promax" class="luyin-box" />
  471. </div>
  472. </div>
  473. </template>
  474. <template v-if="isShow">
  475. <div
  476. ref="wordcard"
  477. class="NNPE-wordDetail"
  478. :style="{
  479. marginLeft:
  480. word.detail.new_word.length === 1
  481. ? '-152px'
  482. : windowWidth > word.detail.new_word.length * 126 + 48
  483. ? '-' + (word.detail.new_word.length * 63 + 24) + 'px'
  484. : '0px',
  485. left:
  486. windowWidth > word.detail.new_word.length * 126 + 48 ? '' : '0px'
  487. }"
  488. >
  489. <Wordcard
  490. :word="word"
  491. :changeWordCard="changeWordCard"
  492. :themeColor="themeColor"
  493. :currentTreeID="currentTreeID"
  494. :TaskModel="TaskModel"
  495. :writeList="curQue.Bookanswer.writeModel"
  496. @changeCurQue="changeCurQue"
  497. :mp3Url="wordPlayMp3"
  498. :bg="wordbgs"
  499. :ed="wordeds"
  500. :baseSizePhone="baseSizePhone"
  501. :themeColorPhone="themeColorPhone"
  502. />
  503. </div>
  504. </template>
  505. <template v-if="isNoteShow">
  506. <div
  507. ref="notecard"
  508. class="NNPE-wordDetail NNPE-noteDetail"
  509. :style="{
  510. marginLeft: windowWidth > 642 ? '-321px' : '0px',
  511. left: windowWidth > 642 ? '' : '0px'
  512. }"
  513. >
  514. <Notecard
  515. :item="curNoteCon"
  516. :changeCard="changeCard"
  517. :baseSizePhone="baseSizePhone"
  518. :themeColorPhone="themeColorPhone"
  519. />
  520. </div>
  521. </template>
  522. </div>
  523. </template>
  524. <script>
  525. import { timeStrToSen } from "../../../../utils/index";
  526. import AudioLine from "../AudioLine.vue";
  527. import Wordcard from "../components/Wordcard.vue"; // 卡片
  528. import Notecard from "../components/Notecard.vue"; // 注释
  529. import RoleChs from "./RoleChs.vue";
  530. import RemarkChs from "./RemarkChs.vue";
  531. import Soundrecord from "../Soundrecord.vue";
  532. export default {
  533. name: "PhraseModelChs",
  534. props: [
  535. "curQue",
  536. "bodyLeft",
  537. "NNPENewWordList",
  538. "NNPEAnnotationList",
  539. "colorBox",
  540. "themeColor",
  541. "noFont",
  542. "currentTreeID",
  543. "config",
  544. "TaskModel",
  545. "colLength",
  546. "NpcNewWordMp3",
  547. "baseSizePhone",
  548. "themeColorPhone"
  549. ],
  550. components: {
  551. AudioLine,
  552. Wordcard,
  553. RoleChs,
  554. RemarkChs,
  555. Soundrecord,
  556. Notecard
  557. },
  558. filters: {
  559. handlePinyin(wordsList) {
  560. let str = "";
  561. wordsList.forEach((item, index) => {
  562. if (index < wordsList.length - 1) {
  563. str += item.pinyin + " ";
  564. } else {
  565. str += item.pinyin;
  566. }
  567. });
  568. return str;
  569. },
  570. handleChs(wordsList) {
  571. let str = "";
  572. wordsList.forEach((item, index) => {
  573. if (index < wordsList.length - 1) {
  574. str += item.chs + " ";
  575. } else {
  576. str += item.chs;
  577. }
  578. });
  579. return str;
  580. }
  581. },
  582. data() {
  583. return {
  584. resArr: [],
  585. curTime: 0, //单位s
  586. chsFhList: [",", "。", "”", ":", "》", "?", "!", ";", "#", "、"],
  587. enFhList: [",", ".", ";", "?", "!", ":", ">", "<"],
  588. NumberList: [
  589. "①",
  590. "②",
  591. "③",
  592. "④",
  593. "⑤",
  594. "⑥",
  595. "⑦",
  596. "⑧",
  597. "⑨",
  598. "⑩",
  599. "⑪",
  600. "⑫",
  601. "⑬",
  602. "⑭",
  603. "⑮",
  604. "⑯",
  605. "⑰",
  606. "⑱",
  607. "⑲",
  608. "⑳"
  609. ],
  610. newWords: ["鱼", "辩礼义"],
  611. oldHz: "",
  612. hz: "",
  613. clientY: "",
  614. top: 0,
  615. left: 0,
  616. articleImg: {}, // 文章图片
  617. newWordList: [],
  618. word: null,
  619. isShow: false,
  620. screenHeight: 0,
  621. cardHeight: 0,
  622. isHasRemark: false,
  623. clickType: "",
  624. isNoteShow: false,
  625. noteNum: "",
  626. oldNoteNum: "",
  627. curNoteCon: null,
  628. contentWidth: 732,
  629. highWords: null,
  630. highWordsArr: [],
  631. highIndex: 0,
  632. wordbgs: 0,
  633. wordeds: 0,
  634. wordPlayMp3: "",
  635. windowWidth: window.innerWidth
  636. };
  637. },
  638. computed: {},
  639. watch: {
  640. hz: {
  641. handler: function(val, oldVal) {
  642. let _this = this;
  643. if (val) {
  644. _this.handleNewWords(val, _this.top, _this.left);
  645. }
  646. },
  647. // 深度观察监听
  648. deep: true
  649. },
  650. isShow: {
  651. handler: function(val, oldVal) {
  652. let _this = this;
  653. if (val) {
  654. setTimeout(() => {
  655. _this.cardHeight = _this.$refs.wordcard.offsetHeight;
  656. if (_this.screenHeight - _this.clientY > _this.cardHeight) {
  657. _this.top = _this.clientY + 20;
  658. } else {
  659. _this.top = _this.clientY - _this.cardHeight - 30;
  660. }
  661. }, 50);
  662. }
  663. },
  664. // 深度观察监听
  665. deep: true
  666. },
  667. noteNum: {
  668. handler: function(val, oldVal) {
  669. let _this = this;
  670. if (val) {
  671. _this.handleNote(val);
  672. }
  673. },
  674. // 深度观察监听
  675. deep: true
  676. },
  677. isNoteShow: {
  678. handler: function(val, oldVal) {
  679. let _this = this;
  680. if (val) {
  681. setTimeout(() => {
  682. _this.cardHeight = _this.$refs.notecard.offsetHeight;
  683. if (_this.screenHeight - _this.clientY > _this.cardHeight) {
  684. _this.top = _this.clientY + 20;
  685. } else {
  686. _this.top = _this.clientY - _this.cardHeight - 30;
  687. }
  688. }, 50);
  689. }
  690. },
  691. // 深度观察监听
  692. deep: true
  693. }
  694. },
  695. //方法集合
  696. methods: {
  697. //拼音的显示和隐藏
  698. changePinyin() {
  699. if (this.config.isHasPY) {
  700. this.$emit("changeConfig", "isShowPY");
  701. }
  702. },
  703. // 英文的显示和隐藏
  704. changeEN() {
  705. if (this.config.isHasEN) {
  706. this.$emit("changeConfig", "isShowEN");
  707. }
  708. },
  709. handleWav() {},
  710. getCurTime(curTime) {
  711. this.curTime = curTime;
  712. },
  713. handleData() {
  714. let resArr = [];
  715. let leg = this.curQue.detail.length;
  716. let curQue = JSON.parse(JSON.stringify(this.curQue));
  717. let dhaspinyin = false; // 每段是否有拼音
  718. curQue.detail.forEach((dItem, dIndex) => {
  719. dhaspinyin = false;
  720. let roleDetail = this.getRole(dItem);
  721. let remarkDetail = dItem.remark;
  722. if (
  723. remarkDetail &&
  724. (remarkDetail.chs ||
  725. remarkDetail.en ||
  726. (remarkDetail.img_list && remarkDetail.img_list.length > 0))
  727. ) {
  728. this.isHasRemark = true;
  729. }
  730. let paraArr = [];
  731. dItem.wordsList.forEach((sItem, sIndex) => {
  732. let sentence = dItem.sentences[sIndex];
  733. sItem.forEach((wItem, wIndex) => {
  734. //this.judgePad(sItem, wItem, wIndex);
  735. this.mergeWordSymbol(wItem);
  736. let words = "";
  737. if (this.newWordList.length > 0) {
  738. if (!this.highWords) {
  739. this.findLightWord(wItem, wIndex, sentence, sItem);
  740. words = this.highWords ? this.highWords.words : "";
  741. } else {
  742. if (wIndex > this.highWords.endIndex - 1) {
  743. this.highWords = null;
  744. this.findLightWord(wItem, wIndex, sentence, sItem);
  745. words = this.highWords ? this.highWords.words : "";
  746. } else {
  747. words = this.highWords ? this.highWords.words : "";
  748. }
  749. }
  750. }
  751. let obj = {
  752. paraIndex: dIndex, //段落索引
  753. sentIndex: sIndex, //在段落中句子索引
  754. wordIndex: wIndex, //单词的索引
  755. pinyin: wItem.pinyin,
  756. chs: wItem.chs,
  757. padding: true, //wItem.padding,
  758. className: wItem.className,
  759. isShow: wItem.isShow,
  760. words: words,
  761. isNewWord: this.newWords.indexOf(wItem.chs) > -1 ? true : false,
  762. config: {
  763. fontFamily: wItem.fontFamily
  764. }
  765. };
  766. paraArr.push(obj);
  767. if (wItem.pinyin) dhaspinyin = true;
  768. });
  769. });
  770. let enwords =
  771. dItem.sentencesEn && dItem.sentencesEn.length > 0
  772. ? dItem.sentencesEn.join(" ").replace(/\'/g, "’")
  773. : "";
  774. let paraObj = {
  775. wordsList: paraArr,
  776. enwords: enwords,
  777. roleDetail: roleDetail,
  778. remarkDetail: remarkDetail,
  779. dhaspinyin: dhaspinyin
  780. };
  781. resArr.push(paraObj);
  782. });
  783. this.resArr = resArr;
  784. // 循环文章图片
  785. if (curQue.img_list) {
  786. curQue.img_list.forEach(item => {
  787. this.articleImg[item.imgNumber] = item.id;
  788. });
  789. }
  790. },
  791. findLightWord(wItem, startIndex, sentence, sItem) {
  792. let words = "",
  793. endIndex = 0;
  794. this.newWordList.forEach(item => {
  795. if (item.length == 1) {
  796. if (item == wItem.chs && !wItem.banLight) {
  797. words = wItem.chs;
  798. endIndex = startIndex + 1;
  799. }
  800. } else {
  801. if (item[0] == wItem.chs && sentence.indexOf(item) > -1) {
  802. let index = null;
  803. let chsStr = "";
  804. for (let i = startIndex; i < sItem.length + 1; i++) {
  805. index = i;
  806. if (chsStr.length == item.length) {
  807. break;
  808. } else {
  809. chsStr += sItem[i] ? sItem[i].chs : "";
  810. }
  811. }
  812. if (chsStr == item && !wItem.banLight) {
  813. words = item;
  814. endIndex = index;
  815. }
  816. } else if (
  817. wItem.new_word &&
  818. wItem.new_word == item &&
  819. !wItem.banLight
  820. ) {
  821. words = item;
  822. endIndex = startIndex + 1;
  823. }
  824. }
  825. });
  826. if (words) {
  827. this.highWords = { words: words, endIndex: endIndex };
  828. } else {
  829. this.highWords = null;
  830. }
  831. },
  832. //词和标点合一起
  833. mergeWordSymbol(wItem) {
  834. if (
  835. this.chsFhList.indexOf(wItem.chs) > -1 ||
  836. this.NumberList.indexOf(wItem.chs) > -1
  837. ) {
  838. wItem.isShow = false;
  839. } else {
  840. wItem.isShow = true;
  841. }
  842. },
  843. //获取角色
  844. getRole(dItem) {
  845. let roleIndex = dItem.roleIndex;
  846. let resObj = null;
  847. let roleList = JSON.parse(JSON.stringify(this.curQue.roleList));
  848. for (let i = 0; i < roleList.length; i++) {
  849. let item = roleList[i];
  850. if (item.id == roleIndex) {
  851. resObj = item;
  852. resObj.color = this.colorBox[i];
  853. break;
  854. }
  855. }
  856. return resObj;
  857. },
  858. //判断是否有padding
  859. judgePad(sItem, wItem, curIndex) {
  860. let leg = sItem.length;
  861. if (curIndex < leg - 1) {
  862. let nextIndex = curIndex + 1;
  863. let chs = sItem[nextIndex].chs;
  864. if (
  865. this.chsFhList.indexOf(chs) > -1 ||
  866. this.chsFhList.indexOf(wItem.chs) > -1
  867. ) {
  868. wItem.padding = false;
  869. } else {
  870. wItem.padding = true;
  871. }
  872. if (this.enFhList.indexOf(wItem.pinyin) > -1) {
  873. wItem.className = "textLeft";
  874. }
  875. }
  876. },
  877. //转化时间
  878. handleTimeList(list) {
  879. let listRes = [];
  880. list.forEach(item => {
  881. let res = timeStrToSen(item);
  882. listRes.push(res);
  883. });
  884. return listRes;
  885. },
  886. //点击播放某个句子
  887. handleChangeTime(time) {
  888. this.curTime = time;
  889. this.$refs.audioLine.onTimeupdateTime(time);
  890. },
  891. handleNewword() {
  892. let NewWordList = [];
  893. this.NNPENewWordList.forEach(item => {
  894. item.forEach(wItem => {
  895. if (wItem.new_word) {
  896. NewWordList.push(wItem.new_word);
  897. } else if (wItem.detail && wItem.detail.sentence) {
  898. NewWordList.push(wItem.detail.sentence);
  899. }
  900. });
  901. });
  902. this.newWordList = JSON.parse(JSON.stringify(NewWordList));
  903. },
  904. showWordDetail(e, word, words) {
  905. let _this = this;
  906. _this.highIndex = 0;
  907. _this.highWordsArr = [];
  908. if (word && this.newWordList.indexOf(word) > -1) {
  909. this.highWordsArr.push(word);
  910. }
  911. if (words && word != words && this.newWordList.indexOf(words) > -1) {
  912. this.highWordsArr.push(words);
  913. }
  914. if (
  915. this.newWordList.indexOf(word) > -1 ||
  916. this.newWordList.indexOf(words) > -1
  917. ) {
  918. if (word && this.newWordList.indexOf(word) > -1) {
  919. if (_this.oldHz != word) {
  920. this.isShow = false;
  921. setTimeout(() => {
  922. _this.hz = word;
  923. }, 50);
  924. }
  925. } else if (words && this.newWordList.indexOf(words) > -1) {
  926. if (_this.oldHz != words) {
  927. this.isShow = false;
  928. setTimeout(() => {
  929. _this.hz = words;
  930. }, 50);
  931. }
  932. }
  933. _this.clientY = e.clientY;
  934. let left = e.clientX;
  935. let width = 0;
  936. if (word.length == 1 || word.length == 2) {
  937. width = 304;
  938. } else if (word.length == 3 || word.length == 4) {
  939. width = 432;
  940. } else if (word.length > 3) {
  941. width = 560;
  942. }
  943. if (left - this.bodyLeft > this.contentWidth / 2) {
  944. _this.left = left - width + 10;
  945. } else {
  946. _this.left = left;
  947. }
  948. }
  949. },
  950. hideWordDetail() {
  951. this.isShow = false;
  952. },
  953. changeWordCard(isShow) {
  954. this.isShow = isShow;
  955. this.oldHz = "";
  956. this.hz = "";
  957. },
  958. // 处理分词数据
  959. handleNewWords(val, top, left) {
  960. this.isShow = true;
  961. this.word = null;
  962. for (let i = 0; i < this.NNPENewWordList.length; i++) {
  963. let pItem = this.NNPENewWordList[i];
  964. for (let j = 0; j < pItem.length; j++) {
  965. let item = pItem[j];
  966. if (item.new_word.trim() == val.trim()) {
  967. let wordlist = val.split("");
  968. this.word = JSON.parse(
  969. JSON.stringify({
  970. list: wordlist,
  971. detail: item,
  972. top: top,
  973. left: left
  974. })
  975. );
  976. break;
  977. }
  978. }
  979. }
  980. this.oldHz = val;
  981. },
  982. viewNotes(e, noteNum) {
  983. let _this = this;
  984. _this.clickType = "note";
  985. let noteIndex = "";
  986. _this.wordPlayMp3 = "";
  987. _this.NNPENewWordList.forEach(items => {
  988. items.forEach(itemn => {
  989. if (itemn.new_word === noteNum) {
  990. _this.wordbgs = itemn.bg;
  991. _this.wordeds = itemn.ed;
  992. _this.wordPlayMp3 = itemn.newWordMp3;
  993. }
  994. });
  995. });
  996. if (_this.NumberList.indexOf(noteNum) > -1) {
  997. for (let i = 0; i < _this.NumberList.length; i++) {
  998. if (_this.NumberList[i] == noteNum) {
  999. noteIndex = "" + i + "";
  1000. break;
  1001. }
  1002. }
  1003. this.showNoteDetail(e, noteIndex);
  1004. } else {
  1005. if (this.newWordList.indexOf(noteNum) > -1) {
  1006. if (_this.oldHz != noteNum) {
  1007. this.isShow = false;
  1008. setTimeout(() => {
  1009. _this.hz = noteNum;
  1010. }, 50);
  1011. }
  1012. _this.clientY = e.clientY;
  1013. let left = e.clientX;
  1014. let width = 0;
  1015. if (noteNum.length == 1 || noteNum.length == 2) {
  1016. width = 304;
  1017. } else if (noteNum.length == 3 || noteNum.length == 4) {
  1018. width = 432;
  1019. } else if (noteNum.length > 3) {
  1020. width = 560;
  1021. }
  1022. if (left - this.bodyLeft > this.contentWidth / 2) {
  1023. _this.left = left - width + 10;
  1024. } else {
  1025. _this.left = left;
  1026. }
  1027. }
  1028. }
  1029. },
  1030. showNoteDetail(e, noteNum) {
  1031. let _this = this;
  1032. if (_this.oldNoteNum != noteNum) {
  1033. this.isNoteShow = false;
  1034. setTimeout(() => {
  1035. _this.noteNum = noteNum;
  1036. }, 50);
  1037. }
  1038. _this.clientY = e.clientY;
  1039. let left = e.clientX;
  1040. let width = 642;
  1041. if (left - this.bodyLeft > this.contentWidth / 2) {
  1042. _this.left = left - width + 10;
  1043. } else {
  1044. _this.left = left - 200;
  1045. }
  1046. },
  1047. // 处理注释数据
  1048. handleNote(val) {
  1049. let _this = this;
  1050. _this.isNoteShow = true;
  1051. _this.oldNoteNum = val;
  1052. let noteIndex = Number(val);
  1053. if (_this.NNPEAnnotationList && _this.NNPEAnnotationList.length > 0) {
  1054. _this.curNoteCon = _this.NNPEAnnotationList[noteIndex]
  1055. ? _this.NNPEAnnotationList[noteIndex]
  1056. : null;
  1057. }
  1058. },
  1059. changeCard(isShow) {
  1060. let _this = this;
  1061. _this.isNoteShow = isShow;
  1062. _this.oldNoteNum = "";
  1063. _this.noteNum = "";
  1064. },
  1065. getScreenHeight() {
  1066. this.screenHeight = window.innerHeight;
  1067. },
  1068. changeCurQue(answer) {
  1069. if (answer) {
  1070. let writeModel = this.curQue.Bookanswer.writeModel;
  1071. let hz = answer.hz;
  1072. if (writeModel.hasOwnProperty(hz)) {
  1073. writeModel[hz].push(answer);
  1074. } else {
  1075. writeModel[hz] = [answer];
  1076. }
  1077. }
  1078. }
  1079. },
  1080. //生命周期 - 创建完成(可以访问当前this实例)
  1081. created() {},
  1082. //生命周期 - 挂载完成(可以访问DOM元素)
  1083. mounted() {
  1084. if (this.NNPENewWordList && this.NNPENewWordList.length > 0) {
  1085. this.handleNewword();
  1086. }
  1087. if (this.curQue) {
  1088. this.handleData();
  1089. }
  1090. $(window).resize(() => {
  1091. this.getScreenHeight();
  1092. });
  1093. this.getScreenHeight();
  1094. },
  1095. beforeCreate() {}, //生命周期 - 创建之前
  1096. beforeMount() {}, //生命周期 - 挂载之前
  1097. beforeUpdate() {}, //生命周期 - 更新之前
  1098. updated() {}, //生命周期 - 更新之后
  1099. beforeDestroy() {}, //生命周期 - 销毁之前
  1100. destroyed() {}, //生命周期 - 销毁完成
  1101. activated() {} //如果页面有keep-alive缓存功能,这个函数会触发
  1102. };
  1103. </script>
  1104. <style lang="scss" scoped>
  1105. //@import url(); 引入公共css类
  1106. .NNPE-ArticleView {
  1107. width: 100%;
  1108. .aduioLine-practice-npc {
  1109. display: flex;
  1110. justify-content: flex-start;
  1111. align-items: center;
  1112. .aduioLine-content {
  1113. flex: 1;
  1114. }
  1115. .aduioLine-right {
  1116. display: flex;
  1117. justify-content: space-between;
  1118. align-items: center;
  1119. width: 69px;
  1120. height: 40px;
  1121. box-sizing: border-box;
  1122. padding: 0 12px;
  1123. border-left: 1px solid rgba(0, 0, 0, 0.1);
  1124. > span {
  1125. width: 16px;
  1126. height: 16px;
  1127. cursor: pointer;
  1128. }
  1129. }
  1130. }
  1131. .NPC-sentences-list {
  1132. .NPC-article-empty {
  1133. display: flex;
  1134. justify-content: flex-start;
  1135. align-items: flex-start;
  1136. > div {
  1137. height: 24px;
  1138. &.empty-left {
  1139. width: 100%;
  1140. box-sizing: border-box;
  1141. &.hasRemark {
  1142. width: calc(100% - 120px);
  1143. box-sizing: border-box;
  1144. border-right: 1px rgba(0, 0, 0, 0.1) solid;
  1145. }
  1146. }
  1147. &.empty-right {
  1148. flex: 1;
  1149. }
  1150. }
  1151. &-bottom {
  1152. > div {
  1153. height: 40px;
  1154. }
  1155. }
  1156. }
  1157. .dia-article-record {
  1158. width: 100%;
  1159. border-top: 1px solid rgba(0, 0, 0, 0.1);
  1160. .luyin-box {
  1161. justify-content: start;
  1162. padding: 8px 12px;
  1163. height: 40px;
  1164. width: 280px;
  1165. justify-content: flex-start;
  1166. }
  1167. }
  1168. }
  1169. .NNPE-detail {
  1170. clear: both;
  1171. // overflow: hidden; // 为了不遮挡备注内容
  1172. display: flex;
  1173. justify-content: flex-start;
  1174. align-items: flex-start;
  1175. &.active {
  1176. background: rgba(0, 0, 0, 0.06);
  1177. }
  1178. .article-content {
  1179. width: 100%;
  1180. box-sizing: border-box;
  1181. padding: 8px 24px 8px 24px;
  1182. display: flex;
  1183. justify-content: flex-start;
  1184. align-items: flex-start;
  1185. &.hasRemark {
  1186. width: calc(100% - 120px);
  1187. border-right: 1px rgba(0, 0, 0, 0.1) solid;
  1188. padding: 8px 0px 8px 23px;
  1189. }
  1190. &.paraLast {
  1191. padding-bottom: 24px;
  1192. }
  1193. }
  1194. .enwords {
  1195. font-family: Helvetica;
  1196. font-weight: normal;
  1197. font-size: 14px;
  1198. line-height: 22px;
  1199. color: rgba(0, 0, 0, 0.85);
  1200. padding-left: 3px;
  1201. word-break: break-word;
  1202. }
  1203. .NNPE-words {
  1204. float: left;
  1205. &-box {
  1206. float: left;
  1207. > span {
  1208. display: block;
  1209. &.NNPE-pinyin {
  1210. font-family: "GB-PINYINOK-B";
  1211. font-weight: normal;
  1212. font-size: 14px;
  1213. line-height: 22px;
  1214. color: #000000;
  1215. height: 22px;
  1216. &.noFont {
  1217. font-family: initial;
  1218. }
  1219. &.textLeft {
  1220. text-align: left;
  1221. }
  1222. }
  1223. &.NNPE-chs {
  1224. font-family: "FZJCGFKTK";
  1225. font-size: 20px;
  1226. line-height: 28px;
  1227. color: #000000;
  1228. &.active {
  1229. background: rgba(60, 200, 99, 0.2);
  1230. }
  1231. &.wordActive {
  1232. color: #de4444;
  1233. }
  1234. &.newActive {
  1235. color: #de4444;
  1236. }
  1237. }
  1238. &.padding {
  1239. padding: 0 3px;
  1240. }
  1241. }
  1242. }
  1243. &.textLeft {
  1244. text-align: left;
  1245. }
  1246. &.textCenter {
  1247. text-align: center;
  1248. }
  1249. &.textRight {
  1250. text-align: right;
  1251. }
  1252. > span {
  1253. display: block;
  1254. &.NNPE-pinyin {
  1255. font-family: "GB-PINYINOK-B";
  1256. font-weight: normal;
  1257. font-size: 14px;
  1258. line-height: 22px;
  1259. color: #000000;
  1260. height: 22px;
  1261. &.noFont {
  1262. font-family: initial;
  1263. }
  1264. &.textLeft {
  1265. text-align: left;
  1266. }
  1267. }
  1268. &.NNPE-chs {
  1269. font-family: "FZJCGFKTK";
  1270. font-size: 20px;
  1271. line-height: 28px;
  1272. color: #000000;
  1273. &.active {
  1274. background: rgba(60, 200, 99, 0.2);
  1275. }
  1276. &.wordActive {
  1277. color: #de4444;
  1278. }
  1279. &.newActive {
  1280. color: #de4444;
  1281. }
  1282. }
  1283. &.padding {
  1284. padding: 0 3px;
  1285. }
  1286. }
  1287. }
  1288. &.NNPE-detail-title {
  1289. .wordsList-box {
  1290. > div {
  1291. display: flex;
  1292. justify-content: center;
  1293. flex-flow: wrap;
  1294. }
  1295. }
  1296. }
  1297. .index {
  1298. width: 48px;
  1299. box-sizing: border-box;
  1300. padding: 8px;
  1301. text-align: right;
  1302. border-right: 1px solid rgba(0, 0, 0, 0.1);
  1303. b {
  1304. font-weight: 400;
  1305. color: #000000;
  1306. line-height: 1.5;
  1307. }
  1308. }
  1309. .wordsList-box {
  1310. width: 100%;
  1311. padding: 0px 24px 0px 8px;
  1312. clear: both;
  1313. overflow: hidden;
  1314. .roleDetail {
  1315. min-height: 36px;
  1316. display: flex;
  1317. justify-content: flex-start;
  1318. align-items: center;
  1319. .pinyin {
  1320. font-family: "GB-PINYINOK-B";
  1321. font-size: 14px;
  1322. line-height: 22px;
  1323. color: rgba(0, 0, 0, 0.85);
  1324. margin-right: 4px;
  1325. }
  1326. .chs {
  1327. font-family: "FZJCGFKTK";
  1328. font-size: 16px;
  1329. line-height: 24px;
  1330. color: rgba(0, 0, 0, 0.85);
  1331. }
  1332. }
  1333. > .para-con {
  1334. float: left;
  1335. border: 1px solid rgba(0, 0, 0, 0.1);
  1336. box-sizing: border-box;
  1337. padding: 8px 12px 8px 12px;
  1338. border-radius: 8px;
  1339. }
  1340. > img {
  1341. width: 100%;
  1342. display: block;
  1343. }
  1344. }
  1345. }
  1346. .remarkBox {
  1347. flex: 1;
  1348. display: flex;
  1349. align-items: center;
  1350. justify-content: center;
  1351. position: relative;
  1352. &.remark72 {
  1353. padding-top: 72px;
  1354. }
  1355. &.remark-top {
  1356. padding-top: 44px;
  1357. }
  1358. }
  1359. .NNPE-wordDetail {
  1360. position: fixed;
  1361. z-index: 116;
  1362. top: 50%;
  1363. margin-top: -196px;
  1364. left: 50%;
  1365. max-width: 100%;
  1366. overflow: auto;
  1367. box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.15);
  1368. }
  1369. .NNPE-noteDetail {
  1370. margin-top: -130px;
  1371. padding: 8px;
  1372. box-shadow: none;
  1373. }
  1374. }
  1375. </style>