Practicechs.vue 45 KB

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