Practicechs.vue 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591
  1. <!-- -->
  2. <template>
  3. <div v-if="curQue" class="NNPE-ArticleView">
  4. <!-- <a class="ArticleView-full" @click="fullScreen">黑板模式</a> -->
  5. <div
  6. v-if="
  7. ((curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url) ||
  8. config.isHasPY ||
  9. config.isHasEN) &&
  10. curQue.property.mp3_position === 'top'
  11. "
  12. class="aduioLine-box aduioLine-practice-npc"
  13. >
  14. <div class="aduioLine-content">
  15. <template v-if="curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url">
  16. <AudioLine
  17. ref="audioLine"
  18. audio-id="diaPraAudio"
  19. :mp3="curQue.mp3_list[0].url"
  20. :get-cur-time="getCurTime"
  21. :stop-audio="stopAudio"
  22. :width="colLength == 2 ? 175 : isPhone ? 200 : 750"
  23. :is-repeat="isRepeat"
  24. :mp3-source="curQue.mp3_list[0].source"
  25. :ed="ed"
  26. type="audioLine"
  27. :attrib="attrib"
  28. @handleChangeStopAudio="handleChangeStopAudio"
  29. @emptyEd="emptyEd"
  30. />
  31. </template>
  32. </div>
  33. <div class="aduioLine-right">
  34. <!-- <span :class="['Repeat-16', isRepeat ? '' : 'disabled']" @click="changeRepeat"></span> -->
  35. <SvgIcon
  36. v-if="config.isHasPY"
  37. icon-class="repeat-1"
  38. size="16"
  39. :class="['Repeat-16', isRepeat ? '' : 'disabled']"
  40. :style="{ color: isRepeat ? (attrib ? attrib.topic_color : '') : '#DCDFE6', cursor: 'pointer' }"
  41. @click="changeRepeat"
  42. />
  43. <!-- <span
  44. :class="['pinyin-16', config.isShowPY ? '' : 'disabled']"
  45. @click="changePinyin"
  46. v-if="config.isHasPY"
  47. ></span>
  48. <span :class="['EN-16', config.isShowEN ? '' : 'disabled']" @click="changeEN" v-if="config.isHasEN"></span> -->
  49. <SvgIcon
  50. v-if="config.isHasPY"
  51. icon-class="pin-btn"
  52. size="16"
  53. :class="['pinyin-16', config.isShowPY ? '' : 'disabled']"
  54. :style="{ color: config.isShowPY ? (attrib ? attrib.topic_color : '') : '#DCDFE6' }"
  55. @click="changePinyin"
  56. />
  57. <!-- <span :class="['EN-16', config.isShowEN ? '' : 'disabled']" @click="changeEN" v-if="config.isHasEN"></span> -->
  58. <SvgIcon
  59. v-if="config.isHasEN"
  60. icon-class="en-btn"
  61. size="16"
  62. :class="['EN-16', config.isShowEN ? '' : 'disabled']"
  63. :style="{ color: config.isShowEN ? (attrib ? attrib.topic_color : '') : '#DCDFE6' }"
  64. @click="changeEN"
  65. />
  66. </div>
  67. </div>
  68. <div
  69. :style="{
  70. height: curQue.property.content_height ? curQue.property.content_height + 'px' : '',
  71. overflow: 'auto',
  72. }"
  73. >
  74. <template v-if="resObj">
  75. <p
  76. v-if="curQue.notice"
  77. class="notice"
  78. style="padding-top: 24px"
  79. :style="{
  80. fontSize: curQue.property.notice_size ? curQue.property.notice_size + 'px' : '',
  81. color: curQue.property.notice_color ? curQue.property.notice_color : '',
  82. }"
  83. >
  84. {{ convertText(curQue.notice) }}
  85. </p>
  86. <div class="NPC-sentences-list">
  87. <div
  88. v-for="(item, index) in resObj.sentList"
  89. :key="'detail' + index"
  90. :class="['NNPE-detail-box', sentIndex == index ? 'active' : '']"
  91. :style="{
  92. backgroundColor: sentIndex == index && attrib ? attrib.assist_color : '',
  93. }"
  94. >
  95. <div
  96. class="NNPE-detail"
  97. @click="
  98. handleChangeTime(
  99. curQue.wordTime && curQue.wordTime[index] && curQue.wordTime[index].bg,
  100. index,
  101. curQue.wordTime && curQue.wordTime[index] && curQue.wordTime[index].ed,
  102. )
  103. "
  104. >
  105. <template v-if="item.sentArr[0].sentIndex == 0">
  106. <RoleChs
  107. :cur-role="item.roleDetail"
  108. :color="
  109. (curQue.wordTime &&
  110. curQue.wordTime[index] &&
  111. curTime >= curQue.wordTime[index].bg &&
  112. curTime <= curQue.wordTime[index].ed) ||
  113. sentIndex == index
  114. ? 'rgba(0,0,0,0.85)'
  115. : 'rgba(0,0,0,0.45)'
  116. "
  117. :type="curQue.property.role_img_type"
  118. />
  119. </template>
  120. <div v-else style="width: 36px; height: 36px"></div>
  121. <div class="sentence-box">
  122. <template v-if="item.sentArr[0].sentIndex == 0">
  123. <!-- <div class="roleDetail" v-if="item.roleDetail.detail && item.roleDetail.detail.wordsList.length > 0">
  124. <span
  125. :class="[
  126. 'pinyin',
  127. (curQue.wordTime &&
  128. curQue.wordTime[index] &&
  129. curTime >= curQue.wordTime[index].bg &&
  130. curTime <= curQue.wordTime[index].ed) ||
  131. sentIndex == index
  132. ? 'color85'
  133. : 'color45',
  134. ]"
  135. >{{ item.roleDetail.detail.wordsList | handlePinyin }}</span
  136. >
  137. <span
  138. :class="[
  139. 'chs',
  140. (curQue.wordTime &&
  141. curQue.wordTime[index] &&
  142. curTime >= curQue.wordTime[index].bg &&
  143. curTime <= curQue.wordTime[index].ed) ||
  144. sentIndex == index
  145. ? 'color85'
  146. : 'color45',
  147. ]"
  148. >{{ item.roleDetail.detail.wordsList | handleChs }}</span
  149. >
  150. </div> -->
  151. <div v-if="item.roleDetail.fullName || item.roleDetail.fullPinyin" class="roleDetail">
  152. <span
  153. :class="[
  154. 'chs',
  155. (curQue.wordTime &&
  156. curQue.wordTime[index] &&
  157. curTime >= curQue.wordTime[index].bg &&
  158. curTime <= curQue.wordTime[index].ed) ||
  159. sentIndex == index
  160. ? 'color85'
  161. : 'color45',
  162. ]"
  163. >{{ convertText(item.roleDetail.fullName) }}</span
  164. >
  165. <span
  166. :class="[
  167. 'pinyin',
  168. (curQue.wordTime &&
  169. curQue.wordTime[index] &&
  170. curTime >= curQue.wordTime[index].bg &&
  171. curTime <= curQue.wordTime[index].ed) ||
  172. sentIndex == index
  173. ? 'color85'
  174. : 'color45',
  175. ]"
  176. >{{ item.roleDetail.fullPinyin }}</span
  177. >
  178. </div>
  179. </template>
  180. <div class="sentence-box-inner" :style="{ background: item.roleDetail.color.bg }">
  181. <div
  182. v-if="item.enwords && config.isShowEN && curQue.enPosition && curQue.enPosition == 'top'"
  183. :class="['enwords', sentIndex == index ? 'wordBlank' : '']"
  184. >
  185. {{ convertText(item.enwords) }}
  186. </div>
  187. <div style="overflow: hidden; clear: both"></div>
  188. <div class="NNPE-words-box">
  189. <div
  190. v-for="(pItem, pIndex) in item.sentArr"
  191. :key="'wordsList' + pIndex"
  192. class="NNPE-words"
  193. :class="[
  194. pItem.chs != '“' && pItem.wordIndex == 0 ? 'textLeft' : 'textCenter',
  195. pItem.chs == '“' ? 'textRight' : '',
  196. ]"
  197. >
  198. <template v-if="!pItem.width">
  199. <template v-if="pItem.isShow">
  200. <template
  201. v-if="
  202. (item.sentArr[pIndex + 1] &&
  203. item.sentArr[pIndex + 1].chs &&
  204. chsFhList.indexOf(item.sentArr[pIndex + 1].chs) > -1) ||
  205. (item.sentArr[pIndex + 1] &&
  206. item.sentArr[pIndex + 1].chs &&
  207. item.sentArr[pIndex + 1].chs == '#')
  208. "
  209. >
  210. <span class="NNPE-words-box">
  211. <template v-if="curQue.property.pinyin_position == 'top'">
  212. <span
  213. v-if="config.isShowPY && item.dhaspinyin"
  214. class="NNPE-pinyin"
  215. :class="[
  216. pItem.className ? pItem.className : '',
  217. sentIndex == index ? 'wordBlank' : '',
  218. noFont.indexOf(pItem.pinyin) > -1 ? 'noFont' : '',
  219. ]"
  220. :style="{
  221. fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
  222. height:
  223. attrib && attrib.pinyin_size
  224. ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
  225. : '22px',
  226. }"
  227. >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
  228. >
  229. </template>
  230. <span
  231. class="NNPE-chs"
  232. :class="[
  233. pItem.padding && config.isShowPY && item.dhaspinyin ? 'padding' : '',
  234. sentIndex == index ? 'wordBlank' : '',
  235. ]"
  236. >
  237. <template>
  238. <span
  239. v-for="(wItem, wIndex) in pItem.leg"
  240. :key="'ci' + wIndex + pIndex + index"
  241. :class="[
  242. isPlaying &&
  243. pItem.timeList &&
  244. pItem.timeList[wIndex] &&
  245. curTime >= pItem.timeList[wIndex].wordBg &&
  246. curQue.wordTime &&
  247. curQue.wordTime[index] &&
  248. curTime <= curQue.wordTime[index].ed
  249. ? 'active'
  250. : '',
  251. sentIndex == index ? 'wordBlank' : '',
  252. ]"
  253. :style="{
  254. fontFamily: pItem.config.fontFamily,
  255. textDecoration: pItem.config.textDecoration,
  256. borderBottom: pItem.config.border === 'dotted' ? '1px dotted' : '',
  257. fontWeight: pItem.config.fontWeight,
  258. height:
  259. attrib && attrib.font_size
  260. ? attrib.font_size.replace('pt', '') * 1.4 + 'pt'
  261. : '28px',
  262. fontSize: attrib && attrib.font_size ? attrib.font_size : '20px',
  263. lineHeight:
  264. attrib && attrib.font_size
  265. ? attrib.font_size.replace('pt', '') * 1.4 + 'pt'
  266. : '28px',
  267. display: 'inline-block',
  268. color:
  269. isPlaying &&
  270. pItem.timeList &&
  271. pItem.timeList[wIndex] &&
  272. curTime >= pItem.timeList[wIndex].wordBg &&
  273. curQue.wordTime &&
  274. curQue.wordTime[index] &&
  275. curTime <= curQue.wordTime[index].ed &&
  276. attrib
  277. ? attrib.topic_color
  278. : pItem.config.color,
  279. }"
  280. >{{
  281. NumberList.indexOf(pItem.pinyin) == -1 ? convertText(pItem.chs[wIndex]) : ''
  282. }}</span
  283. >
  284. </template>
  285. </span>
  286. <template v-if="curQue.property.pinyin_position == 'bottom'">
  287. <span
  288. v-if="config.isShowPY && item.dhaspinyin"
  289. class="NNPE-pinyin"
  290. :class="[
  291. pItem.className ? pItem.className : '',
  292. sentIndex == index ? 'wordBlank' : '',
  293. noFont.indexOf(pItem.pinyin) > -1 ? 'noFont' : '',
  294. ]"
  295. :style="{
  296. fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
  297. height:
  298. attrib && attrib.pinyin_size
  299. ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
  300. : '22px',
  301. }"
  302. >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
  303. >
  304. </template>
  305. </span>
  306. <span class="NNPE-words-box">
  307. <template v-if="curQue.property.pinyin_position == 'top'">
  308. <span
  309. v-if="config.isShowPY && item.dhaspinyin"
  310. :class="[
  311. 'NNPE-pinyin',
  312. sentIndex == index ? 'wordBlank' : '',
  313. noFont.indexOf(item.sentArr[pIndex + 1].pinyin) > -1 ? 'noFont' : '',
  314. ]"
  315. style="text-align: left"
  316. :style="{
  317. fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
  318. height:
  319. attrib && attrib.pinyin_size
  320. ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
  321. : '22px',
  322. }"
  323. >{{
  324. NumberList.indexOf(item.sentArr[pIndex + 1].pinyin) == -1
  325. ? item.sentArr[pIndex + 1].pinyin
  326. : ''
  327. }}</span
  328. >
  329. </template>
  330. <span class="NNPE-chs" style="text-align: left">
  331. <span
  332. :class="[
  333. isPlaying &&
  334. pItem.timeList[pItem.leg - 1] &&
  335. curTime >= pItem.timeList[pItem.leg - 1].wordBg &&
  336. curQue.wordTime &&
  337. curQue.wordTime[index] &&
  338. curTime <= curQue.wordTime[index].ed
  339. ? 'active'
  340. : '',
  341. sentIndex == index ? 'wordBlank' : '',
  342. ]"
  343. :style="{
  344. fontFamily: item.sentArr[pIndex + 1].config.fontFamily,
  345. textDecoration: item.sentArr[pIndex + 1].config.textDecoration,
  346. borderBottom:
  347. item.sentArr[pIndex + 1].config.border === 'dotted' ? '1px dotted' : '',
  348. fontWeight: item.sentArr[pIndex + 1].config.fontWeight,
  349. height:
  350. attrib && attrib.font_size
  351. ? attrib.font_size.replace('pt', '') * 1.4 + 'pt'
  352. : '28px',
  353. fontSize: attrib && attrib.font_size ? attrib.font_size : '20px',
  354. lineHeight:
  355. attrib && attrib.font_size
  356. ? attrib.font_size.replace('pt', '') * 1.4 + 'pt'
  357. : '28px',
  358. display: 'inline-block',
  359. color:
  360. isPlaying &&
  361. pItem.timeList[pItem.leg - 1] &&
  362. curTime >= pItem.timeList[pItem.leg - 1].wordBg &&
  363. curQue.wordTime &&
  364. curQue.wordTime[index] &&
  365. curTime <= curQue.wordTime[index].ed &&
  366. attrib
  367. ? attrib.topic_color
  368. : item.sentArr[pIndex + 1].config.color,
  369. }"
  370. >
  371. {{
  372. NumberList.indexOf(item.sentArr[pIndex + 1].pinyin) == -1
  373. ? convertText(item.sentArr[pIndex + 1].chs)
  374. : ''
  375. }}</span
  376. >
  377. </span>
  378. <template v-if="curQue.property.pinyin_position == 'bottom'">
  379. <span
  380. v-if="config.isShowPY && item.dhaspinyin"
  381. :class="[
  382. 'NNPE-pinyin',
  383. sentIndex == index ? 'wordBlank' : '',
  384. noFont.indexOf(item.sentArr[pIndex + 1].pinyin) > -1 ? 'noFont' : '',
  385. ]"
  386. style="text-align: left"
  387. :style="{
  388. fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
  389. height:
  390. attrib && attrib.pinyin_size
  391. ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
  392. : '22px',
  393. }"
  394. >{{
  395. NumberList.indexOf(item.sentArr[pIndex + 1].pinyin) == -1
  396. ? item.sentArr[pIndex + 1].pinyin
  397. : ''
  398. }}</span
  399. >
  400. </template>
  401. </span>
  402. <span
  403. v-if="
  404. item.sentArr[pIndex + 2] &&
  405. item.sentArr[pIndex + 2].chs &&
  406. chsFhList.indexOf(item.sentArr[pIndex + 2].chs) > -1
  407. "
  408. class="NNPE-words-box"
  409. >
  410. <template v-if="curQue.property.pinyin_position == 'top'">
  411. <span
  412. v-if="config.isShowPY && item.dhaspinyin"
  413. :class="[
  414. 'NNPE-pinyin',
  415. sentIndex == index ? 'wordBlank' : '',
  416. noFont.indexOf(item.sentArr[pIndex + 2].pinyin) > -1 ? 'noFont' : '',
  417. ]"
  418. style="text-align: left"
  419. :style="{
  420. fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
  421. height:
  422. attrib && attrib.pinyin_size
  423. ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
  424. : '22px',
  425. }"
  426. >{{
  427. NumberList.indexOf(item.sentArr[pIndex + 2].pinyin) == -1
  428. ? item.sentArr[pIndex + 2].pinyin
  429. : ''
  430. }}</span
  431. >
  432. </template>
  433. <span class="NNPE-chs" style="text-align: left">
  434. <span
  435. :class="[
  436. isPlaying &&
  437. pItem.timeList[pItem.leg - 1] &&
  438. curTime >= pItem.timeList[pItem.leg - 1].wordBg &&
  439. curQue.wordTime &&
  440. curQue.wordTime[index] &&
  441. curTime <= curQue.wordTime[index].ed
  442. ? 'active'
  443. : '',
  444. sentIndex == index ? 'wordBlank' : '',
  445. ]"
  446. :style="{
  447. fontFamily: item.sentArr[pIndex + 2].config.fontFamily,
  448. textDecoration: item.sentArr[pIndex + 2].config.textDecoration,
  449. borderBottom:
  450. item.sentArr[pIndex + 2].config.border === 'dotted' ? '1px dotted' : '',
  451. fontWeight: item.sentArr[pIndex + 2].config.fontWeight,
  452. height:
  453. attrib && attrib.font_size
  454. ? attrib.font_size.replace('pt', '') * 1.4 + 'pt'
  455. : '28px',
  456. fontSize: attrib && attrib.font_size ? attrib.font_size : '20px',
  457. lineHeight:
  458. attrib && attrib.font_size
  459. ? attrib.font_size.replace('pt', '') * 1.4 + 'pt'
  460. : '28px',
  461. display: 'inline-block',
  462. color:
  463. isPlaying &&
  464. pItem.timeList[pItem.leg - 1] &&
  465. curTime >= pItem.timeList[pItem.leg - 1].wordBg &&
  466. curQue.wordTime &&
  467. curQue.wordTime[index] &&
  468. curTime <= curQue.wordTime[index].ed &&
  469. attrib
  470. ? attrib.topic_color
  471. : item.sentArr[pIndex + 2].config.color,
  472. }"
  473. >
  474. {{
  475. NumberList.indexOf(item.sentArr[pIndex + 2].pinyin) == -1
  476. ? convertText(item.sentArr[pIndex + 2].chs)
  477. : ''
  478. }}</span
  479. >
  480. </span>
  481. <template v-if="curQue.property.pinyin_position == 'bottom'">
  482. <span
  483. v-if="config.isShowPY && item.dhaspinyin"
  484. :class="[
  485. 'NNPE-pinyin',
  486. sentIndex == index ? 'wordBlank' : '',
  487. noFont.indexOf(item.sentArr[pIndex + 2].pinyin) > -1 ? 'noFont' : '',
  488. ]"
  489. style="text-align: left"
  490. :style="{
  491. fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
  492. height:
  493. attrib && attrib.pinyin_size
  494. ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
  495. : '22px',
  496. }"
  497. >{{
  498. NumberList.indexOf(item.sentArr[pIndex + 2].pinyin) == -1
  499. ? item.sentArr[pIndex + 2].pinyin
  500. : ''
  501. }}</span
  502. >
  503. </template>
  504. </span>
  505. </template>
  506. <template v-else>
  507. <template v-if="curQue.property.pinyin_position == 'top'">
  508. <span
  509. v-if="config.isShowPY && item.dhaspinyin"
  510. class="NNPE-pinyin"
  511. :class="[
  512. pItem.chs != '“' && pItem.padding ? 'padding' : '',
  513. pItem.className ? pItem.className : '',
  514. sentIndex == index ? 'wordBlank' : '',
  515. noFont.indexOf(item.pinyin) > -1 ? 'noFont' : '',
  516. ]"
  517. :style="{
  518. fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
  519. height:
  520. attrib && attrib.pinyin_size
  521. ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
  522. : '22px',
  523. }"
  524. >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
  525. >
  526. </template>
  527. <span
  528. v-if="pItem.chs != '#'"
  529. class="NNPE-chs"
  530. :class="[
  531. pItem.chs != '“' && pItem.padding && config.isShowPY && item.dhaspinyin
  532. ? 'padding'
  533. : '',
  534. sentIndex == index ? 'wordBlank' : '',
  535. ]"
  536. >
  537. <template>
  538. <span
  539. v-for="(wItem, wIndex) in pItem.leg"
  540. :key="'ci' + wIndex + pIndex + index"
  541. :class="[
  542. isPlaying &&
  543. pItem.timeList &&
  544. pItem.timeList[wIndex] &&
  545. curTime >= pItem.timeList[wIndex].wordBg &&
  546. curQue.wordTime &&
  547. curQue.wordTime[index] &&
  548. curTime <= curQue.wordTime[index].ed
  549. ? 'active'
  550. : '',
  551. ]"
  552. :style="{
  553. fontFamily: pItem.config.fontFamily,
  554. textDecoration: pItem.config.textDecoration,
  555. borderBottom: pItem.config.border === 'dotted' ? '1px dotted' : '',
  556. fontWeight: pItem.config.fontWeight,
  557. height:
  558. attrib && attrib.font_size
  559. ? attrib.font_size.replace('pt', '') * 1.4 + 'pt'
  560. : '28px',
  561. fontSize: attrib && attrib.font_size ? attrib.font_size : '20px',
  562. lineHeight:
  563. attrib && attrib.font_size
  564. ? attrib.font_size.replace('pt', '') * 1.4 + 'pt'
  565. : '28px',
  566. display: 'inline-block',
  567. color:
  568. isPlaying &&
  569. pItem.timeList &&
  570. pItem.timeList[wIndex] &&
  571. curTime >= pItem.timeList[wIndex].wordBg &&
  572. curQue.wordTime &&
  573. curQue.wordTime[index] &&
  574. curTime <= curQue.wordTime[index].ed &&
  575. attrib
  576. ? attrib.topic_color
  577. : pItem.config.color,
  578. }"
  579. >{{
  580. NumberList.indexOf(pItem.chs[wIndex]) == -1 ? convertText(pItem.chs[wIndex]) : ''
  581. }}</span
  582. >
  583. </template>
  584. </span>
  585. <template v-if="curQue.property.pinyin_position == 'bottom'">
  586. <span
  587. v-if="config.isShowPY && item.dhaspinyin"
  588. class="NNPE-pinyin"
  589. :class="[
  590. pItem.chs != '“' && pItem.padding ? 'padding' : '',
  591. pItem.className ? pItem.className : '',
  592. sentIndex == index ? 'wordBlank' : '',
  593. ]"
  594. :style="{
  595. fontSize: attrib && attrib.pinyin_size ? attrib.pinyin_size : '14px',
  596. height:
  597. attrib && attrib.pinyin_size
  598. ? attrib.pinyin_size.replace('pt', '') * 1.5 + 'pt'
  599. : '22px',
  600. }"
  601. >{{ NumberList.indexOf(pItem.pinyin) == -1 ? pItem.pinyin : '' }}</span
  602. >
  603. </template>
  604. </template>
  605. </template>
  606. </template>
  607. <template v-else>
  608. <span
  609. :style="{
  610. height: pItem.height + 'px',
  611. width: pItem.width + 'px',
  612. }"
  613. ></span>
  614. </template>
  615. </div>
  616. </div>
  617. <div style="overflow: hidden; clear: both"></div>
  618. <div
  619. v-if="
  620. item.enwords &&
  621. config.isShowEN &&
  622. (!curQue.enPosition || (curQue.enPosition && curQue.enPosition == 'bottom'))
  623. "
  624. :class="['enwords', sentIndex == index ? 'wordBlank' : '']"
  625. >
  626. {{ convertText(item.enwords) }}
  627. </div>
  628. <div
  629. v-if="curQue.property.multilingual_position === 'para'"
  630. class="multilingual-para"
  631. :class="[item.isTitle ? 'multilingual-para-center' : '']"
  632. >
  633. {{
  634. multilingualTextList[multilingual] && multilingualTextList[multilingual][index]
  635. ? multilingualTextList[multilingual][index]
  636. : ''
  637. }}
  638. </div>
  639. </div>
  640. </div>
  641. </div>
  642. <div v-show="sentIndex == index" class="Soundrecord-content">
  643. <div class="Soundrecord-content-inner">
  644. <Soundrecord
  645. v-if="refresh"
  646. type="promax"
  647. class="luyin-box"
  648. :TaskModel="TaskModel"
  649. :answer-record-list="
  650. curQue.Bookanswer.practiceModel[index] && curQue.Bookanswer.practiceModel[index].recordList
  651. "
  652. :tm-index="index"
  653. :sent-index="sentIndex"
  654. :attrib="attrib"
  655. @getWavblob="getWavblob"
  656. @handleParentPlay="handleParentPlay"
  657. @sentPause="sentPause"
  658. @handleWav="handleWav"
  659. />
  660. <!-- <div v-if="curQue.mp3_list && curQue.mp3_list.length > 0" class="compare-box">
  661. <Audio-compare
  662. :theme-color="attrib ? attrib.topic_color : '#e35454'"
  663. :index="index"
  664. :sent-index="sentIndex"
  665. :url="curQue.mp3_list[0].id"
  666. :bg="curQue.wordTime[index].bg"
  667. :ed="curQue.wordTime[index].ed"
  668. :wavblob="wavblob"
  669. :get-cur-time="getCurTime"
  670. :sent-pause="sentPause"
  671. :is-record="isRecord"
  672. :handle-change-stop-audio="handleChangeStopAudio"
  673. :get-play-status="getPlayStatus"
  674. :attrib="attrib"
  675. />
  676. </div> -->
  677. </div>
  678. <span class="full-screen-icon" @click="fullScreen">
  679. <svg-icon
  680. icon-class="icon-full"
  681. size="24"
  682. :style="{
  683. color: attrib && attrib.topic_color ? attrib.topic_color : '',
  684. }"
  685. />
  686. </span>
  687. </div>
  688. </div>
  689. <!-- <div class="multilingual" v-for="(items, indexs) in multilingualTextList" :key="indexs">
  690. {{ items }}
  691. </div> -->
  692. </div>
  693. </template>
  694. <template v-for="(items, indexs) in curQue.detail">
  695. <div
  696. v-if="
  697. curQue.property.multilingual_position === 'all' &&
  698. items.multilingualTextList &&
  699. items.multilingualTextList[multilingual] &&
  700. items.multilingualTextList[multilingual].length > 0
  701. "
  702. :key="indexs"
  703. class="multilingual"
  704. >
  705. <div class="multilingual-para" :class="[items.isTitle ? 'multilingual-para-center' : '']">
  706. {{
  707. items.multilingualTextList && items.multilingualTextList[multilingual]
  708. ? items.multilingualTextList[multilingual].join(' ')
  709. : ''
  710. }}
  711. </div>
  712. </div>
  713. </template>
  714. </div>
  715. <div
  716. v-if="
  717. ((curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url) ||
  718. config.isHasPY ||
  719. config.isHasEN) &&
  720. curQue.property.mp3_position === 'bottom'
  721. "
  722. class="aduioLine-box aduioLine-practice-npc aduioLine-box-bottom"
  723. >
  724. <div class="aduioLine-content">
  725. <template v-if="curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url">
  726. <AudioLine
  727. ref="audioLine"
  728. audio-id="diaPraAudio"
  729. :mp3="curQue.mp3_list[0].url"
  730. :get-cur-time="getCurTime"
  731. :stop-audio="stopAudio"
  732. :width="colLength == 2 ? 175 : isPhone ? 200 : 750"
  733. :is-repeat="isRepeat"
  734. :mp3-source="curQue.mp3_list[0].source"
  735. :ed="ed"
  736. type="audioLine"
  737. :attrib="attrib"
  738. @handleChangeStopAudio="handleChangeStopAudio"
  739. @emptyEd="emptyEd"
  740. />
  741. </template>
  742. </div>
  743. <div class="aduioLine-right">
  744. <SvgIcon
  745. v-if="config.isHasPY"
  746. icon-class="repeat-1"
  747. size="16"
  748. :class="['Repeat-16', isRepeat ? '' : 'disabled']"
  749. :style="{ color: isRepeat ? (attrib ? attrib.topic_color : '') : '#DCDFE6', cursor: 'pointer' }"
  750. @click="changeRepeat"
  751. />
  752. <!-- <span
  753. :class="['pinyin-16', config.isShowPY ? '' : 'disabled']"
  754. @click="changePinyin"
  755. v-if="config.isHasPY"
  756. ></span>
  757. <span :class="['EN-16', config.isShowEN ? '' : 'disabled']" @click="changeEN" v-if="config.isHasEN"></span> -->
  758. <SvgIcon
  759. v-if="config.isHasPY"
  760. icon-class="pin-btn"
  761. size="16"
  762. :class="['pinyin-16', config.isShowPY ? '' : 'disabled']"
  763. :style="{ color: config.isShowPY ? (attrib ? attrib.topic_color : '') : '#DCDFE6' }"
  764. @click="changePinyin"
  765. />
  766. <!-- <span :class="['EN-16', config.isShowEN ? '' : 'disabled']" @click="changeEN" v-if="config.isHasEN"></span> -->
  767. <SvgIcon
  768. v-if="config.isHasEN"
  769. icon-class="en-btn"
  770. size="16"
  771. :class="['EN-16', config.isShowEN ? '' : 'disabled']"
  772. :style="{ color: config.isShowEN ? (attrib ? attrib.topic_color : '') : '#DCDFE6' }"
  773. @click="changeEN"
  774. />
  775. </div>
  776. </div>
  777. <div :id="'screen-' + mathNum" class="voice-full-screen">
  778. <Voicefullscreen
  779. v-if="isFull && resObj"
  780. :theme-color="attrib ? attrib.topic_color : '#e35454'"
  781. :cur-que="curQue"
  782. :sent-list="resObj.sentList"
  783. :sent-index="sentIndex"
  784. :mp3="curQue.mp3_list && curQue.mp3_list[0] ? curQue.mp3_list[0].id : ''"
  785. :no-font="noFont"
  786. :NNPENewWordList="NNPENewWordList"
  787. :NNPEAnnotationList="NNPEAnnotationList"
  788. :current-tree-i-d="currentTreeID"
  789. :is-full="isFull"
  790. :config="config"
  791. :TaskModel="TaskModel"
  792. :NpcNewWordMp3="NpcNewWordMp3"
  793. :attrib="attrib"
  794. @handleWav="handleWav"
  795. @changePinyin="changePinyin"
  796. @changeEN="changeEN"
  797. @exitFullscreen="exitFullscreen"
  798. @changeIsFull="changeIsFull"
  799. />
  800. </div>
  801. </div>
  802. </template>
  803. <script>
  804. import { timeStrToSen } from '@/utils/transform';
  805. import AudioLine from '../voice_matrix/components/AudioLine.vue';
  806. import Soundrecord from '../../common/SoundRecord.vue'; // 录音模板
  807. import RoleChs from './RoleChs.vue';
  808. import AudioCompare from '../article/components/AudioCompare.vue';
  809. import Voicefullscreen from '../article/Voicefullscreen.vue';
  810. export default {
  811. name: 'ArticleView',
  812. components: {
  813. AudioLine,
  814. Soundrecord,
  815. RoleChs,
  816. AudioCompare,
  817. Voicefullscreen,
  818. },
  819. filters: {
  820. handlePinyin(wordsList) {
  821. let str = '';
  822. wordsList.forEach((item, index) => {
  823. if (index < wordsList.length - 1) {
  824. str += `${item.pinyin} `;
  825. } else {
  826. str += item.pinyin;
  827. }
  828. });
  829. return str;
  830. },
  831. handleChs(wordsList) {
  832. let str = '';
  833. wordsList.forEach((item, index) => {
  834. if (index < wordsList.length - 1) {
  835. str += `${item.chs} `;
  836. } else {
  837. str += item.chs;
  838. }
  839. });
  840. return str;
  841. },
  842. },
  843. props: [
  844. 'curQue',
  845. 'colorBox',
  846. 'noFont',
  847. 'attrib',
  848. 'config',
  849. 'NNPENewWordList',
  850. 'NNPEAnnotationList',
  851. 'currentTreeID',
  852. 'TaskModel',
  853. 'colLength',
  854. 'NpcNewWordMp3',
  855. 'isPhone',
  856. 'multilingual',
  857. ],
  858. inject: ['convertText'],
  859. data() {
  860. return {
  861. wavblob: null,
  862. resObj: null,
  863. curTime: 0, // 单位s
  864. chsFhList: [',', '。', '”', ':', '》', '?', '!', ';', '、'],
  865. enFhList: [',', '.', ';', '?', '!', ':', '>', '<'],
  866. NumberList: ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩', '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳'],
  867. stopAudio: false,
  868. sentIndex: 0,
  869. isRepeat: false,
  870. currSent: null, // 当前句子的时间
  871. isRecord: false,
  872. isFull: false,
  873. mathNum: Math.random().toString(36).substr(2),
  874. ed: undefined,
  875. refresh: true,
  876. highWords: null,
  877. highWordsArr: [],
  878. highIndex: 0,
  879. newWordList: [],
  880. multilingualTextList: {},
  881. };
  882. },
  883. computed: {
  884. isPlaying() {
  885. let playing = false;
  886. if (this.$refs.audioLine) {
  887. playing = this.$refs.audioLine.audio.isPlaying;
  888. }
  889. return playing;
  890. },
  891. },
  892. watch: {
  893. sentIndex: {
  894. handler(newVal, oldVal) {
  895. let _this = this;
  896. if (newVal !== oldVal) {
  897. let Bookanswer = _this.curQue.Bookanswer;
  898. if (
  899. Bookanswer &&
  900. Bookanswer.practiceModel &&
  901. Bookanswer.practiceModel[newVal] &&
  902. Bookanswer.practiceModel[newVal].recordList &&
  903. Bookanswer.practiceModel[newVal].recordList.length > 0
  904. ) {
  905. _this.wavblob = Bookanswer.practiceModel[newVal].recordList[0].wavData;
  906. } else {
  907. _this.wavblob = '';
  908. }
  909. }
  910. },
  911. deep: true,
  912. },
  913. isFull: {
  914. handler(newVal, oldVal) {
  915. let _this = this;
  916. _this.refresh = false;
  917. if (!newVal) {
  918. _this.$nextTick(() => {
  919. // 重新渲染组件
  920. _this.refresh = true;
  921. });
  922. }
  923. },
  924. deep: true,
  925. },
  926. },
  927. // 生命周期 - 创建完成(可以访问当前this实例)
  928. created() {},
  929. // 生命周期 - 挂载完成(可以访问DOM元素)
  930. mounted() {
  931. if (this.curQue) {
  932. this.handleData();
  933. }
  934. },
  935. beforeCreate() {}, // 生命周期 - 创建之前
  936. beforeMount() {}, // 生命周期 - 挂载之前
  937. beforeUpdate() {}, // 生命周期 - 更新之前
  938. updated() {}, // 生命周期 - 更新之后
  939. beforeDestroy() {}, // 生命周期 - 销毁之前
  940. destroyed() {}, // 生命周期 - 销毁完成
  941. activated() {},
  942. // 方法集合
  943. methods: {
  944. getPlayStatus(val) {
  945. // this.isPlaying = val;
  946. },
  947. pauseAudio() {
  948. let audio = document.getElementsByTagName('audio');
  949. if (audio && audio.length > 0 && window.location.href.indexOf('GCLS-Learn') === -1) {
  950. audio.forEach((item) => {
  951. item.pause();
  952. });
  953. }
  954. },
  955. pauseVideo() {
  956. let video = document.getElementsByTagName('video');
  957. if (video && video.length > 0 && window.location.href.indexOf('GCLS-Learn') === -1) {
  958. video.forEach((item) => {
  959. item.pause();
  960. });
  961. }
  962. },
  963. // 语音全屏
  964. fullScreen() {
  965. this.pauseAudio();
  966. this.pauseVideo();
  967. this.isFull = true;
  968. this.goFullscreen();
  969. },
  970. goFullscreen() {
  971. let id = `screen-${this.mathNum}`;
  972. let element = document.getElementById(id);
  973. if (element.requestFullscreen) {
  974. element.requestFullscreen();
  975. } else if (element.msRequestFullscreen) {
  976. element.msRequestFullscreen();
  977. } else if (element.mozRequestFullScreen) {
  978. element.mozRequestFullScreen();
  979. } else if (element.webkitRequestFullscreen) {
  980. element.webkitRequestFullscreen();
  981. }
  982. },
  983. exitFullscreen() {
  984. this.isFull = false;
  985. if (document.exitFullscreen) {
  986. document.exitFullscreen();
  987. } else if (document.msExitFullscreen) {
  988. document.msExitFullscreen();
  989. } else if (document.mozCancelFullScreen) {
  990. document.mozCancelFullScreen();
  991. } else if (document.webkitExitFullscreen) {
  992. document.webkitExitFullscreen();
  993. }
  994. },
  995. changeIsFull() {
  996. this.isFull = false;
  997. },
  998. getWavblob(wavblob) {
  999. this.wavblob = wavblob;
  1000. },
  1001. sentPause(isRecord) {
  1002. this.isRecord = isRecord;
  1003. },
  1004. getCurTime(curTime) {
  1005. let _this = this;
  1006. if (_this.isRepeat) {
  1007. let time = curTime * 1000;
  1008. if (time >= _this.currSent.ed || time <= _this.currSent.bg) {
  1009. _this.curTime = _this.currSent.bg;
  1010. this.$refs.audioLine.onTimeupdateTime(_this.currSent.bg / 1000, true);
  1011. } else {
  1012. _this.curTime = curTime * 1000;
  1013. }
  1014. } else {
  1015. _this.curTime = curTime * 1000;
  1016. _this.getSentIndex(_this.curTime);
  1017. }
  1018. },
  1019. getSentIndex(curTime) {
  1020. for (let i = 0; i < this.curQue.wordTime.length; i++) {
  1021. let bg = this.curQue.wordTime[i].bg;
  1022. let ed = this.curQue.wordTime[i].ed;
  1023. if (curTime >= bg && curTime <= ed) {
  1024. this.sentIndex = i;
  1025. break;
  1026. }
  1027. }
  1028. },
  1029. handleData() {
  1030. this.curQue.multilingual.forEach((item) => {
  1031. let trans_arr = item.translation.split('\n');
  1032. this.$set(this.multilingualTextList, item.type, trans_arr);
  1033. });
  1034. let resArr = [];
  1035. let sentArrTotal = [];
  1036. let curQue = JSON.parse(JSON.stringify(this.curQue));
  1037. let wordTimeList = curQue.wordTime;
  1038. let dhaspinyin = false; // 每段是否有拼音
  1039. curQue.detail.forEach((dItem, dIndex) => {
  1040. dhaspinyin = false;
  1041. let roleDetail = this.getRole(dItem);
  1042. dItem.wordsList.forEach((sItem, sIndex) => {
  1043. let sentArr = [];
  1044. let sentence = dItem.sentences[sIndex];
  1045. sItem.forEach((wItem, wIndex) => {
  1046. let startIndex = wIndex === 0 ? 0 : sentArr[wIndex - 1].startIndex + sentArr[wIndex - 1].chs.length;
  1047. let endIndex = wIndex === 0 ? wItem.chs.length : sentArr[wIndex - 1].endIndex + wItem.chs.length;
  1048. // this.judgePad(sItem, wItem, wIndex);
  1049. this.mergeWordSymbol(wItem);
  1050. let words = '';
  1051. if (this.newWordList.length > 0) {
  1052. if (!this.highWords) {
  1053. this.findLightWord(wItem, wIndex, sentence, sItem);
  1054. words = this.highWords ? this.highWords.words : '';
  1055. } else if (wIndex > this.highWords.endIndex - 1) {
  1056. this.highWords = null;
  1057. this.findLightWord(wItem, wIndex, sentence, sItem);
  1058. words = this.highWords ? this.highWords.words : '';
  1059. } else {
  1060. words = this.highWords ? this.highWords.words : '';
  1061. }
  1062. }
  1063. let obj = {
  1064. paraIndex: dIndex, // 段落索引
  1065. sentIndex: sIndex, // 在段落中句子索引
  1066. wordIndex: wIndex, // 单词的索引
  1067. pinyin:
  1068. curQue.pinyin_type === 'pinyin'
  1069. ? curQue.property.is_first_sentence_first_hz_pinyin_first_char_upper_case === 'true' && wIndex === 0
  1070. ? wItem.pinyin_up
  1071. : wItem.pinyin
  1072. : wItem.pinyin_tone,
  1073. chs: wItem.chs,
  1074. padding: true,
  1075. className: wItem.className,
  1076. isShow: wItem.isShow,
  1077. startIndex,
  1078. endIndex,
  1079. leg: wItem.chs.length,
  1080. timeList: [],
  1081. words,
  1082. config: {
  1083. fontFamily: wItem.fontFamily,
  1084. color: wItem.color,
  1085. textDecoration: wItem.textDecoration,
  1086. border: wItem.border,
  1087. fontWeight: wItem.fontWeight,
  1088. },
  1089. matchWords: wItem.matchWords,
  1090. matchNotes: wItem.matchNotes,
  1091. notesColor: wItem.notesColor,
  1092. img: wItem.img,
  1093. imgPosition: wItem.imgPosition,
  1094. };
  1095. sentArr.push(obj);
  1096. if (wItem.pinyin) dhaspinyin = true;
  1097. });
  1098. let objs = {
  1099. roleDetail,
  1100. sentArr,
  1101. enwords: dItem.sentencesEn && dItem.sentencesEn[sIndex] && dItem.sentencesEn[sIndex].replace(/'/g, '’'),
  1102. dhaspinyin,
  1103. type: dItem.type,
  1104. notice: dItem.notice,
  1105. noticeWordList: dItem.noticeWordList,
  1106. notice_size: dItem.notice_size,
  1107. notice_color: dItem.notice_color,
  1108. file_url_open: dItem.file_url_open,
  1109. };
  1110. sentArrTotal.push(sentArr);
  1111. resArr.push(objs);
  1112. });
  1113. });
  1114. if (wordTimeList && wordTimeList.length > 0) {
  1115. this.mergeWordTime(sentArrTotal, wordTimeList);
  1116. }
  1117. this.resObj = { sentList: resArr };
  1118. },
  1119. // 获取角色
  1120. getRole(dItem) {
  1121. let roleIndex = dItem.roleIndex;
  1122. let resObj = null;
  1123. let roleList = JSON.parse(JSON.stringify(this.curQue.property.role_list));
  1124. for (let i = 0; i < roleList.length; i++) {
  1125. let item = roleList[i];
  1126. if (item.id === roleIndex) {
  1127. resObj = item;
  1128. // resObj.color = this.colorBox[i];
  1129. break;
  1130. }
  1131. }
  1132. return resObj;
  1133. },
  1134. mergeWordTime(resArr, wordTimeList) {
  1135. resArr.forEach((item, index) => {
  1136. let wordsResultList = wordTimeList[index].wordsResultList;
  1137. item.forEach((wItem) => {
  1138. let startIndex = wItem.startIndex;
  1139. let endIndex = wItem.endIndex;
  1140. wItem.timeList = wordsResultList.slice(startIndex, endIndex);
  1141. });
  1142. });
  1143. },
  1144. // 词和标点合一起
  1145. mergeWordSymbol(wItem) {
  1146. if (this.chsFhList.indexOf(wItem.chs) > -1) {
  1147. wItem.isShow = false;
  1148. } else {
  1149. wItem.isShow = true;
  1150. }
  1151. },
  1152. findLightWord(wItem, startIndex, sentence, sItem) {
  1153. let endIndex = 0;
  1154. let words = '';
  1155. this.newWordList.forEach((item) => {
  1156. if (item.length === 1) {
  1157. if (item === wItem.chs && !wItem.banLight) {
  1158. words = wItem.chs;
  1159. endIndex = startIndex + 1;
  1160. }
  1161. } else if (item[0] === wItem.chs && sentence.indexOf(item) > -1) {
  1162. let index = null;
  1163. let chsStr = '';
  1164. for (let i = startIndex; i < sItem.length + 1; i++) {
  1165. index = i;
  1166. if (chsStr.length === item.length) {
  1167. break;
  1168. } else {
  1169. chsStr += sItem[i] ? sItem[i].chs : '';
  1170. }
  1171. }
  1172. if (chsStr === item && !wItem.banLight) {
  1173. words = item;
  1174. endIndex = index;
  1175. }
  1176. } else if (wItem.new_word && wItem.new_word === item && !wItem.banLight) {
  1177. words = item;
  1178. endIndex = startIndex + 1;
  1179. }
  1180. });
  1181. if (words) {
  1182. this.highWords = { words, endIndex };
  1183. } else {
  1184. this.highWords = null;
  1185. }
  1186. },
  1187. // 判断是否有padding
  1188. judgePad(sItem, wItem, curIndex) {
  1189. let leg = sItem.length;
  1190. if (curIndex < leg - 1) {
  1191. let nextIndex = curIndex + 1;
  1192. let chs = sItem[nextIndex].chs;
  1193. if (this.chsFhList.indexOf(chs) > -1 || this.chsFhList.indexOf(wItem.chs) > -1) {
  1194. wItem.padding = false;
  1195. } else {
  1196. wItem.padding = true;
  1197. }
  1198. if (this.enFhList.indexOf(wItem.pinyin) > -1) {
  1199. wItem.className = 'textLeft';
  1200. }
  1201. }
  1202. },
  1203. // 转化时间
  1204. handleTimeList(list) {
  1205. let listRes = [];
  1206. list.forEach((item) => {
  1207. let res = timeStrToSen(item);
  1208. listRes.push(res);
  1209. });
  1210. return listRes;
  1211. },
  1212. // 计算总时间
  1213. countWordTime(sentArr) {
  1214. let total = 0;
  1215. sentArr.forEach((item) => {
  1216. total += item.endTime;
  1217. });
  1218. return total;
  1219. },
  1220. // 点击播放某个句子
  1221. handleChangeTime(time, index, ed) {
  1222. let _this = this;
  1223. if (_this.isRepeat) {
  1224. _this.currSent = _this.curQue.wordTime[index];
  1225. }
  1226. _this.sentIndex = index;
  1227. _this.ed = ed;
  1228. if (time) {
  1229. _this.curTime = time;
  1230. _this.$refs.audioLine.onTimeupdateTime(time / 1000, true);
  1231. }
  1232. },
  1233. emptyEd() {
  1234. this.ed = undefined;
  1235. },
  1236. handleWav(list, tmIndex) {
  1237. let _tmIndex = tmIndex || 0;
  1238. this.curQue.Bookanswer.practiceModel[_tmIndex] = {
  1239. recordList: [],
  1240. };
  1241. this.$set(this.curQue.Bookanswer.practiceModel[_tmIndex], 'recordList', list);
  1242. },
  1243. // 录音时暂停音频播放
  1244. handleParentPlay() {
  1245. this.stopAudio = true;
  1246. },
  1247. // 音频播放时改变布尔值
  1248. handleChangeStopAudio() {
  1249. this.stopAudio = false;
  1250. },
  1251. // 拼音的显示和隐藏
  1252. changePinyin() {
  1253. if (this.config.isHasPY) {
  1254. this.$emit('changeConfig', 'isShowPY');
  1255. }
  1256. },
  1257. // 英文的显示和隐藏
  1258. changeEN() {
  1259. if (this.config.isHasEN) {
  1260. this.$emit('changeConfig', 'isShowEN');
  1261. }
  1262. },
  1263. // 单句是否重复播放
  1264. changeRepeat() {
  1265. let _this = this;
  1266. _this.isRepeat = !_this.isRepeat;
  1267. this.currSent = _this.curQue.wordTime[_this.sentIndex];
  1268. },
  1269. handleNewword() {
  1270. let NewWordList = [];
  1271. this.NNPENewWordList.forEach((wItem) => {
  1272. // item.forEach((wItem) => {
  1273. if (wItem.new_word) {
  1274. NewWordList.push(wItem.new_word);
  1275. } else if (wItem.detail && wItem.detail.sentence) {
  1276. NewWordList.push(wItem.detail.sentence);
  1277. }
  1278. // });
  1279. });
  1280. this.newWordList = JSON.parse(JSON.stringify(NewWordList));
  1281. },
  1282. }, // 如果页面有keep-alive缓存功能,这个函数会触发
  1283. };
  1284. </script>
  1285. <style lang="scss" scoped>
  1286. //@import url(); 引入公共css类
  1287. .NNPE-ArticleView {
  1288. position: relative;
  1289. width: 100%;
  1290. .ArticleView-full {
  1291. position: absolute;
  1292. top: -44px;
  1293. left: 0;
  1294. z-index: 99999;
  1295. padding-left: 24px;
  1296. font-size: 14px;
  1297. font-weight: bold;
  1298. line-height: 24px;
  1299. color: #000;
  1300. background: url('@/assets/full-screen-red.png') left center no-repeat;
  1301. background-size: 16px 16px;
  1302. }
  1303. .NPC-sentences-list {
  1304. padding: 0 0 24px;
  1305. overflow: auto;
  1306. }
  1307. .multilingual {
  1308. padding: 6px 24px 12px;
  1309. word-break: break-word;
  1310. }
  1311. .aduioLine-content {
  1312. flex: 1;
  1313. }
  1314. .aduioLine-practice-npc {
  1315. display: flex;
  1316. align-items: center;
  1317. justify-content: flex-start;
  1318. .aduioLine-right {
  1319. box-sizing: border-box;
  1320. display: flex;
  1321. align-items: center;
  1322. justify-content: space-between;
  1323. width: 92px;
  1324. height: 40px;
  1325. padding: 0 12px;
  1326. border-left: 1px solid rgba(0, 0, 0, 10%);
  1327. > span {
  1328. width: 16px;
  1329. height: 16px;
  1330. cursor: pointer;
  1331. }
  1332. }
  1333. }
  1334. .NNPE-detail-box {
  1335. &.active {
  1336. background: rgba(0, 0, 0, 6%);
  1337. }
  1338. }
  1339. .enwords {
  1340. padding-left: 3px;
  1341. font-family: 'Helvetica';
  1342. font-size: 14px;
  1343. font-weight: normal;
  1344. line-height: 22px;
  1345. color: rgba(0, 0, 0, 45%);
  1346. word-break: break-word;
  1347. &.wordBlank {
  1348. color: rgba(0, 0, 0, 85%);
  1349. }
  1350. }
  1351. .NNPE-detail {
  1352. box-sizing: border-box;
  1353. display: flex;
  1354. align-items: flex-start;
  1355. justify-content: flex-start;
  1356. width: 100%;
  1357. padding: 8px 24px;
  1358. overflow: hidden;
  1359. clear: both;
  1360. color: rgba(0, 0, 0, 45%);
  1361. .sentence-box {
  1362. padding-left: 8px;
  1363. overflow: hidden;
  1364. clear: both;
  1365. &-inner {
  1366. box-sizing: border-box;
  1367. float: left;
  1368. padding: 8px 12px;
  1369. border: 1px solid rgba(0, 0, 0, 10%);
  1370. border-radius: 8px;
  1371. }
  1372. .roleDetail {
  1373. display: flex;
  1374. align-items: center;
  1375. justify-content: flex-start;
  1376. height: 36px;
  1377. .pinyin {
  1378. margin-left: 4px;
  1379. font-family: 'League';
  1380. font-size: 14px;
  1381. line-height: 22px;
  1382. color: rgba(0, 0, 0, 85%);
  1383. &.noFont {
  1384. font-family: initial;
  1385. }
  1386. }
  1387. .chs {
  1388. font-family: '楷体';
  1389. font-size: 16px;
  1390. line-height: 24px;
  1391. color: rgba(0, 0, 0, 85%);
  1392. }
  1393. .color85 {
  1394. color: rgba(0, 0, 0, 85%);
  1395. }
  1396. .color45 {
  1397. color: rgba(0, 0, 0, 45%);
  1398. }
  1399. }
  1400. }
  1401. .NNPE-words {
  1402. float: left;
  1403. padding-bottom: 5px;
  1404. &-box {
  1405. float: left;
  1406. > span {
  1407. display: block;
  1408. &.NNPE-pinyin {
  1409. height: 20px;
  1410. font-family: 'League';
  1411. font-size: 14px;
  1412. font-weight: normal;
  1413. line-height: 1.5;
  1414. &.noFont {
  1415. font-family: initial;
  1416. }
  1417. &.textLeft {
  1418. text-align: left;
  1419. }
  1420. &.wordBlank {
  1421. color: rgba(0, 0, 0, 85%);
  1422. }
  1423. }
  1424. &.NNPE-chs {
  1425. font-family: '楷体';
  1426. font-size: 20px;
  1427. line-height: 1.4;
  1428. .active {
  1429. color: #de4444;
  1430. }
  1431. &.wordBlank {
  1432. color: rgba(0, 0, 0, 85%);
  1433. }
  1434. }
  1435. // &.padding {
  1436. // padding-right: 6px;
  1437. // }
  1438. }
  1439. }
  1440. &.textLeft {
  1441. text-align: left;
  1442. }
  1443. &.textCenter {
  1444. text-align: center;
  1445. }
  1446. &.textRight {
  1447. text-align: right;
  1448. }
  1449. > span {
  1450. display: block;
  1451. &.NNPE-pinyin {
  1452. height: 20px;
  1453. font-family: 'League';
  1454. font-size: 14px;
  1455. font-weight: normal;
  1456. line-height: 1.5;
  1457. &.noFont {
  1458. font-family: initial;
  1459. }
  1460. &.textLeft {
  1461. text-align: left;
  1462. }
  1463. &.wordBlank {
  1464. color: rgba(0, 0, 0, 85%);
  1465. }
  1466. }
  1467. &.NNPE-chs {
  1468. font-family: '楷体';
  1469. font-size: 20px;
  1470. line-height: 1.4;
  1471. .active {
  1472. color: #de4444;
  1473. }
  1474. &.wordBlank {
  1475. color: rgba(0, 0, 0, 85%);
  1476. }
  1477. }
  1478. &.padding {
  1479. padding: 0 3px;
  1480. }
  1481. }
  1482. }
  1483. }
  1484. .Soundrecord-content {
  1485. display: flex;
  1486. align-items: center;
  1487. justify-content: space-between;
  1488. padding: 0 10px 8px 68px;
  1489. &-inner {
  1490. display: flex;
  1491. align-items: center;
  1492. justify-content: flex-start;
  1493. // width: 304px;
  1494. padding: 4px 12px;
  1495. background: #fff;
  1496. border: 1px solid rgba(0, 0, 0, 10%);
  1497. border-radius: 8px;
  1498. .luyin-box {
  1499. width: 280px;
  1500. }
  1501. .compare-box {
  1502. display: flex;
  1503. align-items: center;
  1504. justify-content: center;
  1505. height: 32px;
  1506. }
  1507. }
  1508. .full-screen-icon {
  1509. width: 24px;
  1510. height: 24px;
  1511. cursor: pointer;
  1512. // background: url('@/assets/full-screen-red.png') no-repeat left top;
  1513. // background-size: 100% 100%;
  1514. }
  1515. }
  1516. .voice-full-screen {
  1517. // position: fixed;
  1518. // top: 0;
  1519. // left: 0;
  1520. // z-index: 9999;
  1521. }
  1522. .notice {
  1523. margin: 0;
  1524. font-size: 14px;
  1525. font-weight: 400;
  1526. line-height: 150%;
  1527. color: #000;
  1528. word-break: break-word;
  1529. }
  1530. img {
  1531. max-width: 100%;
  1532. }
  1533. }
  1534. </style>