Practicechs.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. <!-- -->
  2. <template>
  3. <div class="NNPE-ArticleView" v-if="curQue">
  4. <div
  5. class="aduioLine-box aduioLine-practice"
  6. v-if="
  7. curQue.mp3_list && curQue.mp3_list.length > 0 && curQue.mp3_list[0].url
  8. "
  9. >
  10. <div class="aduioLine-content">
  11. <AudioLine
  12. :mp3="curQue.mp3_list[0].url"
  13. :getCurTime="getCurTime"
  14. ref="audioLine"
  15. :stopAudio="stopAudio"
  16. :width="555"
  17. :isRepeat="isRepeat"
  18. @handleChangeStopAudio="handleChangeStopAudio"
  19. />
  20. </div>
  21. <div class="aduioLine-right">
  22. <span
  23. :class="['Repeat-16', isRepeat ? '' : 'disabled']"
  24. @click="changeRepeat"
  25. ></span>
  26. <span
  27. :class="['pinyin-16', isShowPY ? '' : 'disabled']"
  28. @click="changePinyin"
  29. ></span>
  30. </div>
  31. </div>
  32. <template v-if="resObj">
  33. <p class="notice" v-if="curQue.notice">
  34. {{ curQue.notice }}
  35. </p>
  36. <div class="NPC-sentences-list">
  37. <div
  38. :class="['NNPE-detail-box', sentIndex == index ? 'active' : '']"
  39. v-for="(item, index) in resObj.sentList"
  40. :key="'detail' + index"
  41. >
  42. <div
  43. class="NNPE-detail"
  44. @click="
  45. handleChangeTime(
  46. curQue.wordTime &&
  47. curQue.wordTime[index] &&
  48. curQue.wordTime[index].bg,
  49. index
  50. )
  51. "
  52. >
  53. <template v-if="item.sentArr[0].sentIndex == 0">
  54. <RoleChs
  55. :curRole="item.roleDetail"
  56. :color="
  57. (curQue.wordTime &&
  58. curQue.wordTime[index] &&
  59. curTime >= curQue.wordTime[index].bg &&
  60. curTime <= curQue.wordTime[index].ed) ||
  61. sentIndex == index
  62. ? 'rgba(0,0,0,0.85)'
  63. : 'rgba(0,0,0,0.45)'
  64. "
  65. :type="1"
  66. />
  67. </template>
  68. <div v-else style="width: 36px; height: 36px"></div>
  69. <div class="sentence-box">
  70. <template v-if="item.sentArr[0].sentIndex == 0">
  71. <div
  72. class="roleDetail"
  73. v-if="item.roleDetail.detail.wordsList.length > 0"
  74. >
  75. <span
  76. :class="[
  77. 'pinyin',
  78. (curQue.wordTime &&
  79. curQue.wordTime[index] &&
  80. curTime >= curQue.wordTime[index].bg &&
  81. curTime <= curQue.wordTime[index].ed) ||
  82. sentIndex == index
  83. ? 'color85'
  84. : 'color45',
  85. ]"
  86. >{{ item.roleDetail.detail.wordsList | handlePinyin }}</span
  87. >
  88. <span
  89. :class="[
  90. 'chs',
  91. (curQue.wordTime &&
  92. curQue.wordTime[index] &&
  93. curTime >= curQue.wordTime[index].bg &&
  94. curTime <= curQue.wordTime[index].ed) ||
  95. sentIndex == index
  96. ? 'color85'
  97. : 'color45',
  98. ]"
  99. >{{ item.roleDetail.detail.wordsList | handleChs }}</span
  100. >
  101. </div>
  102. </template>
  103. <div
  104. class="sentence-box-inner"
  105. :style="{ background: item.roleDetail.color.bg }"
  106. >
  107. <div class="NNPE-words-box">
  108. <div
  109. class="NNPE-words"
  110. v-for="(pItem, pIndex) in item.sentArr"
  111. :key="'wordsList' + pIndex"
  112. :class="[pItem.wordIndex == 0 ? 'textLeft' : 'textCenter']"
  113. >
  114. <template v-if="!pItem.width">
  115. <template v-if="pItem.isShow">
  116. <template
  117. v-if="
  118. item.sentArr[pIndex + 1] &&
  119. item.sentArr[pIndex + 1].chs &&
  120. chsFhList.indexOf(item.sentArr[pIndex + 1].chs) > -1
  121. "
  122. >
  123. <span class="NNPE-words-box">
  124. <template v-if="curQue.pyPosition == 'top'">
  125. <span
  126. v-if="isShowPY"
  127. class="NNPE-pinyin"
  128. :class="[
  129. pItem.className ? pItem.className : '',
  130. sentIndex == index ? 'wordBlank' : '',
  131. ]"
  132. >{{ pItem.pinyin }}</span
  133. >
  134. </template>
  135. <span
  136. class="NNPE-chs"
  137. :class="[
  138. pItem.padding && isShowPY ? 'padding' : '',
  139. sentIndex == index ? 'wordBlank' : '',
  140. ]"
  141. >
  142. <template>
  143. <span
  144. v-for="(wItem, wIndex) in pItem.leg"
  145. :key="'ci' + wIndex + pIndex + index"
  146. :class="[
  147. pItem.timeList &&
  148. pItem.timeList[wIndex] &&
  149. curTime >= pItem.timeList[wIndex].wordBg &&
  150. curQue.wordTime &&
  151. curQue.wordTime[index] &&
  152. curTime <= curQue.wordTime[index].ed
  153. ? 'active'
  154. : '',
  155. sentIndex == index ? 'wordBlank' : '',
  156. ]"
  157. >{{ pItem.chs[wIndex] }}</span
  158. >
  159. </template>
  160. </span>
  161. <template v-if="curQue.pyPosition == 'bottom'">
  162. <span
  163. v-if="isShowPY"
  164. class="NNPE-pinyin"
  165. :class="[
  166. pItem.className ? pItem.className : '',
  167. sentIndex == index ? 'wordBlank' : '',
  168. ]"
  169. >{{ pItem.pinyin }}</span
  170. >
  171. </template>
  172. </span>
  173. <span class="NNPE-words-box">
  174. <template v-if="curQue.pyPosition == 'top'">
  175. <span
  176. v-if="isShowPY"
  177. :class="[
  178. 'NNPE-pinyin',
  179. sentIndex == index ? 'wordBlank' : '',
  180. ]"
  181. style="text-align: left"
  182. >{{ item.sentArr[pIndex + 1].pinyin }}</span
  183. >
  184. </template>
  185. <span class="NNPE-chs" style="text-align: left">
  186. <span
  187. :class="[
  188. pItem.timeList[pItem.leg - 1] &&
  189. curTime >=
  190. pItem.timeList[pItem.leg - 1].wordBg &&
  191. curQue.wordTime &&
  192. curQue.wordTime[index] &&
  193. curTime <= curQue.wordTime[index].ed
  194. ? 'active'
  195. : '',
  196. sentIndex == index ? 'wordBlank' : '',
  197. ]"
  198. >
  199. {{ item.sentArr[pIndex + 1].chs }}</span
  200. >
  201. </span>
  202. <template v-if="curQue.pyPosition == 'bottom'">
  203. <span
  204. v-if="isShowPY"
  205. :class="[
  206. 'NNPE-pinyin',
  207. sentIndex == index ? 'wordBlank' : '',
  208. ]"
  209. style="text-align: left"
  210. >{{ item.sentArr[pIndex + 1].pinyin }}</span
  211. >
  212. </template>
  213. </span>
  214. </template>
  215. <template v-else>
  216. <template v-if="curQue.pyPosition == 'top'">
  217. <template
  218. v-if="NumberList.indexOf(pItem.pinyin) < 0"
  219. >
  220. <span
  221. v-if="isShowPY"
  222. class="NNPE-pinyin"
  223. :class="[
  224. pItem.padding ? 'padding' : '',
  225. pItem.className ? pItem.className : '',
  226. sentIndex == index ? 'wordBlank' : '',
  227. ]"
  228. >{{ pItem.pinyin }}</span
  229. >
  230. </template>
  231. </template>
  232. <span
  233. v-if="pItem.chs != '#'"
  234. class="NNPE-chs"
  235. :class="[
  236. pItem.padding && isShowPY ? 'padding' : '',
  237. sentIndex == index ? 'wordBlank' : '',
  238. ]"
  239. >
  240. <template>
  241. <span
  242. v-for="(wItem, wIndex) in pItem.leg"
  243. :key="'ci' + wIndex + pIndex + index"
  244. :class="[
  245. pItem.timeList &&
  246. pItem.timeList[wIndex] &&
  247. curTime >= pItem.timeList[wIndex].wordBg &&
  248. curQue.wordTime &&
  249. curQue.wordTime[index] &&
  250. curTime <= curQue.wordTime[index].ed
  251. ? 'active'
  252. : '',
  253. ]"
  254. >{{ pItem.chs[wIndex] }}</span
  255. >
  256. </template>
  257. </span>
  258. <template v-if="curQue.pyPosition == 'bottom'">
  259. <template
  260. v-if="NumberList.indexOf(pItem.pinyin) < 0"
  261. >
  262. <span
  263. v-if="isShowPY"
  264. class="NNPE-pinyin"
  265. :class="[
  266. pItem.padding ? 'padding' : '',
  267. pItem.className ? pItem.className : '',
  268. sentIndex == index ? 'wordBlank' : '',
  269. ]"
  270. >{{ pItem.pinyin }}</span
  271. >
  272. </template>
  273. </template>
  274. </template>
  275. </template>
  276. </template>
  277. <template v-else>
  278. <span
  279. :style="{
  280. height: pItem.height + 'px',
  281. width: pItem.width + 'px',
  282. }"
  283. ></span>
  284. </template>
  285. </div>
  286. </div>
  287. <div
  288. v-if="item.enwords"
  289. :class="['enwords', sentIndex == index ? 'wordBlank' : '']"
  290. >
  291. {{ item.enwords }}
  292. </div>
  293. </div>
  294. </div>
  295. </div>
  296. <div v-show="sentIndex == index" class="Soundrecord-content">
  297. <Soundrecord
  298. @handleWav="handleWav"
  299. type="promax"
  300. class="luyin-box"
  301. @handleParentPlay="handleParentPlay"
  302. />
  303. </div>
  304. </div>
  305. </div>
  306. </template>
  307. </div>
  308. </template>
  309. <script>
  310. import { timeStrToSen } from "@/utils/index";
  311. import AudioLine from "../AudioLine.vue";
  312. import Soundrecord from "../../preview/Soundrecord.vue"; // 录音模板
  313. import RoleChs from "./RoleChs.vue";
  314. export default {
  315. name: "ArticleView",
  316. props: ["curQue", "colorBox"],
  317. components: {
  318. AudioLine,
  319. Soundrecord,
  320. RoleChs,
  321. },
  322. filters: {
  323. handlePinyin(wordsList) {
  324. let str = "";
  325. wordsList.forEach((item, index) => {
  326. if (index < wordsList.length - 1) {
  327. str += item.pinyin + " ";
  328. } else {
  329. str += item.pinyin;
  330. }
  331. });
  332. return str;
  333. },
  334. handleChs(wordsList) {
  335. let str = "";
  336. wordsList.forEach((item, index) => {
  337. if (index < wordsList.length - 1) {
  338. str += item.chs + " ";
  339. } else {
  340. str += item.chs;
  341. }
  342. });
  343. return str;
  344. },
  345. },
  346. data() {
  347. return {
  348. resObj: null,
  349. curTime: 0, //单位s
  350. chsFhList: [",", "。", "“", ":", "》", "《", "?", "!", ";"],
  351. enFhList: [",", ".", ";", "?", "!", ":", ">", "<"],
  352. NumberList: [
  353. "①",
  354. "②",
  355. "③",
  356. "④",
  357. "⑤",
  358. "⑥",
  359. "⑦",
  360. "⑧",
  361. "⑨",
  362. "⑩",
  363. "⑪",
  364. "⑫",
  365. "⑬",
  366. "⑭",
  367. "⑮",
  368. "⑯",
  369. "⑰",
  370. "⑱",
  371. "⑲",
  372. "⑳",
  373. ],
  374. stopAudio: false,
  375. sentIndex: 0,
  376. isShowPY: true,
  377. isRepeat: false,
  378. currSent: null, //当前句子的时间
  379. };
  380. },
  381. computed: {},
  382. watch: {},
  383. //方法集合
  384. methods: {
  385. getCurTime(curTime) {
  386. let _this = this;
  387. if (_this.isRepeat) {
  388. let time = curTime * 1000;
  389. console.log(time, _this.currSent.ed);
  390. if (time > _this.currSent.ed || time < _this.currSent.bg) {
  391. _this.curTime = _this.currSent.bg;
  392. this.$refs.audioLine.onTimeupdateTime(_this.currSent.bg / 1000);
  393. } else {
  394. _this.curTime = curTime * 1000;
  395. }
  396. } else {
  397. _this.curTime = curTime * 1000;
  398. _this.getSentIndex(_this.curTime);
  399. }
  400. },
  401. getSentIndex(curTime) {
  402. for (let i = 0; i < this.curQue.wordTime.length; i++) {
  403. let bg = this.curQue.wordTime[i].bg;
  404. let ed = this.curQue.wordTime[i].ed;
  405. if (curTime >= bg && curTime <= ed) {
  406. this.sentIndex = i;
  407. break;
  408. }
  409. }
  410. },
  411. handleData() {
  412. let resArr = [],
  413. timeArr = [],
  414. sentArrTotal = [],
  415. enList = [];
  416. let curQue = JSON.parse(JSON.stringify(this.curQue));
  417. let wordTimeList = curQue.wordTime;
  418. curQue.detail.forEach((dItem, dIndex) => {
  419. let roleDetail = this.getRole(dItem);
  420. dItem.wordsList.forEach((sItem, sIndex) => {
  421. let sentArr = [];
  422. sItem.forEach((wItem, wIndex) => {
  423. let startIndex =
  424. wIndex == 0
  425. ? 0
  426. : sentArr[wIndex - 1].startIndex +
  427. sentArr[wIndex - 1].chs.length;
  428. let endIndex =
  429. wIndex == 0
  430. ? wItem.chs.length
  431. : sentArr[wIndex - 1].endIndex + wItem.chs.length;
  432. // this.judgePad(sItem, wItem, wIndex);
  433. this.mergeWordSymbol(wItem);
  434. let obj = {
  435. paraIndex: dIndex, //段落索引
  436. sentIndex: sIndex, //在段落中句子索引
  437. wordIndex: wIndex, //单词的索引
  438. pinyin: wItem.pinyin,
  439. chs: wItem.chs,
  440. padding: true,
  441. className: wItem.className,
  442. isShow: wItem.isShow,
  443. startIndex: startIndex,
  444. endIndex: endIndex,
  445. leg: wItem.chs.length,
  446. timeList: [],
  447. };
  448. sentArr.push(obj);
  449. });
  450. let obj = {
  451. roleDetail: roleDetail,
  452. sentArr: sentArr,
  453. enwords: dItem.sentencesEn && dItem.sentencesEn[sIndex],
  454. };
  455. sentArrTotal.push(sentArr);
  456. resArr.push(obj);
  457. });
  458. timeArr.push(dItem.timeList);
  459. });
  460. if (wordTimeList && wordTimeList.length > 0) {
  461. this.mergeWordTime(sentArrTotal, wordTimeList);
  462. }
  463. let timeList = [];
  464. timeArr.forEach((item) => {
  465. item.forEach((aItem) => {
  466. if (timeList.indexOf(aItem) < 0) {
  467. timeList.push(aItem);
  468. }
  469. });
  470. });
  471. this.resObj = { sentList: resArr, timeList: timeList };
  472. console.log(this.resObj);
  473. },
  474. //获取角色
  475. getRole(dItem) {
  476. let roleIndex = dItem.roleIndex;
  477. let resObj = null;
  478. let roleList = JSON.parse(JSON.stringify(this.curQue.roleList));
  479. for (let i = 0; i < roleList.length; i++) {
  480. let item = roleList[i];
  481. if (item.id == roleIndex) {
  482. resObj = item;
  483. resObj.color = this.colorBox[i];
  484. break;
  485. }
  486. }
  487. return resObj;
  488. },
  489. mergeWordTime(resArr, wordTimeList) {
  490. resArr.forEach((item, index) => {
  491. let wordsResultList = wordTimeList[index].wordsResultList;
  492. item.forEach((wItem) => {
  493. let startIndex = wItem.startIndex;
  494. let endIndex = wItem.endIndex;
  495. wItem.timeList = wordsResultList.slice(startIndex, endIndex);
  496. });
  497. });
  498. },
  499. //词和标点合一起
  500. mergeWordSymbol(wItem) {
  501. if (this.chsFhList.indexOf(wItem.chs) > -1) {
  502. wItem.isShow = false;
  503. } else {
  504. wItem.isShow = true;
  505. }
  506. },
  507. handleData2() {
  508. let resArr = [],
  509. timeArr = [];
  510. let leg = this.curQue.detail.length;
  511. let curQue = JSON.parse(JSON.stringify(this.curQue));
  512. curQue.detail.forEach((dItem, dIndex) => {
  513. let endTime = 0;
  514. if (dIndex < leg - 1) {
  515. endTime = curQue.detail[dIndex + 1].timeList[0];
  516. dItem.timeList.push(endTime);
  517. dItem.timeList = this.handleTimeList(dItem.timeList);
  518. } else {
  519. dItem.timeList = this.handleTimeList(dItem.timeList);
  520. endTime = curQue.mp3_list[0].duration;
  521. dItem.timeList.push(endTime);
  522. }
  523. dItem.wordsList.forEach((sItem, sIndex) => {
  524. let time_diff = dItem.timeList[sIndex + 1] - dItem.timeList[sIndex];
  525. let wordsLeg = dItem.sentences[sIndex].length;
  526. let wordTime = time_diff / wordsLeg;
  527. // console.log(time_diff, wordsLeg, wordTime);
  528. let sentArr = [];
  529. sItem.forEach((wItem, wIndex) => {
  530. let preTotal = wIndex > 0 ? sentArr[wIndex - 1].endTime : 0;
  531. let endTime =
  532. wIndex > 0
  533. ? wordTime * wItem.chs.length + preTotal
  534. : dItem.timeList[sIndex] + wordTime * wItem.chs.length;
  535. //console.log("endTime" + endTime);
  536. let startTime =
  537. wIndex > 0 ? sentArr[wIndex - 1].endTime : dItem.timeList[sIndex];
  538. this.judgePad(sItem, wItem, wIndex);
  539. let obj = {
  540. paraIndex: dIndex, //段落索引
  541. sentIndex: sIndex, //在段落中句子索引
  542. wordIndex: wIndex, //单词的索引
  543. pinyin: wItem.pinyin,
  544. chs: wItem.chs,
  545. padding: wItem.padding,
  546. className: wItem.className,
  547. startTime: startTime,
  548. endTime: endTime,
  549. };
  550. sentArr.push(obj);
  551. });
  552. resArr.push(sentArr);
  553. });
  554. timeArr.push(dItem.timeList);
  555. });
  556. let timeList = [];
  557. timeArr.forEach((item) => {
  558. item.forEach((aItem) => {
  559. if (timeList.indexOf(aItem) < 0) {
  560. timeList.push(aItem);
  561. }
  562. });
  563. });
  564. this.resObj = { sentList: resArr, timeList: timeList, enList: enList };
  565. console.log(this.resObj);
  566. },
  567. //判断是否有padding
  568. judgePad(sItem, wItem, curIndex) {
  569. let leg = sItem.length;
  570. if (curIndex < leg - 1) {
  571. let nextIndex = curIndex + 1;
  572. let chs = sItem[nextIndex].chs;
  573. if (
  574. this.chsFhList.indexOf(chs) > -1 ||
  575. this.chsFhList.indexOf(wItem.chs) > -1
  576. ) {
  577. wItem.padding = false;
  578. } else {
  579. wItem.padding = true;
  580. }
  581. if (this.enFhList.indexOf(wItem.pinyin) > -1) {
  582. wItem.className = "textLeft";
  583. }
  584. }
  585. },
  586. //转化时间
  587. handleTimeList(list) {
  588. let listRes = [];
  589. list.forEach((item) => {
  590. let res = timeStrToSen(item);
  591. listRes.push(res);
  592. });
  593. return listRes;
  594. },
  595. //计算总时间
  596. countWordTime(sentArr) {
  597. let total = 0;
  598. sentArr.forEach((item) => {
  599. total += item.endTime;
  600. });
  601. return total;
  602. },
  603. //点击播放某个句子
  604. handleChangeTime(time, index) {
  605. let _this = this;
  606. if (_this.isRepeat) {
  607. _this.currSent = _this.curQue.wordTime[index];
  608. }
  609. _this.sentIndex = index;
  610. if (time) {
  611. _this.curTime = time;
  612. _this.$refs.audioLine.onTimeupdateTime(time / 1000);
  613. }
  614. },
  615. handleWav(data) {},
  616. // 录音时暂停音频播放
  617. handleParentPlay() {
  618. this.stopAudio = true;
  619. },
  620. // 音频播放时改变布尔值
  621. handleChangeStopAudio() {
  622. this.stopAudio = false;
  623. },
  624. //拼音的显示隐藏
  625. changePinyin() {
  626. this.isShowPY = !this.isShowPY;
  627. },
  628. // 单句是否重复播放
  629. changeRepeat() {
  630. let _this = this;
  631. _this.isRepeat = !_this.isRepeat;
  632. this.currSent = _this.curQue.wordTime[_this.sentIndex];
  633. },
  634. },
  635. //生命周期 - 创建完成(可以访问当前this实例)
  636. created() {},
  637. //生命周期 - 挂载完成(可以访问DOM元素)
  638. mounted() {
  639. console.log(this.curQue);
  640. if (this.curQue) {
  641. this.handleData();
  642. }
  643. },
  644. beforeCreate() {}, //生命周期 - 创建之前
  645. beforeMount() {}, //生命周期 - 挂载之前
  646. beforeUpdate() {}, //生命周期 - 更新之前
  647. updated() {}, //生命周期 - 更新之后
  648. beforeDestroy() {}, //生命周期 - 销毁之前
  649. destroyed() {}, //生命周期 - 销毁完成
  650. activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
  651. };
  652. </script>
  653. <style lang='scss' scoped>
  654. //@import url(); 引入公共css类
  655. .NNPE-ArticleView {
  656. width: 100%;
  657. padding-top: 24px;
  658. .NPC-sentences-list {
  659. padding: 0px 0 24px 0;
  660. }
  661. .aduioLine-content {
  662. flex: 1;
  663. }
  664. .aduioLine-practice {
  665. display: flex;
  666. justify-content: flex-start;
  667. align-items: center;
  668. .aduioLine-right {
  669. display: flex;
  670. justify-content: space-between;
  671. align-items: center;
  672. width: 72px;
  673. height: 40px;
  674. box-sizing: border-box;
  675. padding: 0 12px;
  676. border-left: 1px solid rgba(0, 0, 0, 0.1);
  677. > span {
  678. width: 16px;
  679. height: 16px;
  680. cursor: pointer;
  681. }
  682. }
  683. }
  684. .NNPE-detail-box {
  685. &.active {
  686. background: rgba(0, 0, 0, 0.06);
  687. }
  688. }
  689. .enwords {
  690. font-family: "robot";
  691. font-weight: normal;
  692. font-size: 14px;
  693. line-height: 22px;
  694. color: rgba(0, 0, 0, 0.45);
  695. &.wordBlank {
  696. color: rgba(0, 0, 0, 0.85);
  697. }
  698. }
  699. .NNPE-detail {
  700. display: flex;
  701. justify-content: flex-start;
  702. align-items: flex-start;
  703. clear: both;
  704. overflow: hidden;
  705. width: 100%;
  706. box-sizing: border-box;
  707. padding: 8px 24px 8px;
  708. color: rgba(0, 0, 0, 0.45);
  709. .sentence-box {
  710. padding-left: 8px;
  711. clear: both;
  712. overflow: hidden;
  713. &-inner {
  714. padding: 8px 12px;
  715. box-sizing: border-box;
  716. border-radius: 8px;
  717. border: 1px solid rgba(0, 0, 0, 0.1);
  718. float: left;
  719. }
  720. .roleDetail {
  721. height: 36px;
  722. display: flex;
  723. justify-content: flex-start;
  724. align-items: center;
  725. .pinyin {
  726. font-family: "GB-PINYINOK-B";
  727. font-size: 14px;
  728. line-height: 22px;
  729. color: rgba(0, 0, 0, 0.85);
  730. margin-right: 4px;
  731. }
  732. .chs {
  733. font-family: "FZJCGFKTK";
  734. font-size: 16px;
  735. line-height: 24px;
  736. color: rgba(0, 0, 0, 0.85);
  737. }
  738. .color85 {
  739. color: rgba(0, 0, 0, 0.85);
  740. }
  741. .color45 {
  742. color: rgba(0, 0, 0, 0.45);
  743. }
  744. }
  745. }
  746. .NNPE-words {
  747. float: left;
  748. &-box {
  749. float: left;
  750. > span {
  751. display: block;
  752. &.NNPE-pinyin {
  753. font-family: "GB-PINYINOK-B";
  754. font-weight: normal;
  755. font-size: 14px;
  756. line-height: 20px;
  757. height: 20px;
  758. &.textLeft {
  759. text-align: left;
  760. }
  761. &.wordBlank {
  762. color: rgba(0, 0, 0, 0.85);
  763. }
  764. }
  765. &.NNPE-chs {
  766. font-family: "FZJCGFKTK";
  767. font-size: 20px;
  768. line-height: 28px;
  769. .active {
  770. color: #de4444;
  771. }
  772. &.wordBlank {
  773. color: rgba(0, 0, 0, 0.85);
  774. }
  775. }
  776. // &.padding {
  777. // padding-right: 6px;
  778. // }
  779. }
  780. }
  781. &.textLeft {
  782. text-align: left;
  783. }
  784. &.textCenter {
  785. text-align: center;
  786. }
  787. > span {
  788. display: block;
  789. &.NNPE-pinyin {
  790. font-family: "GB-PINYINOK-B";
  791. font-weight: normal;
  792. font-size: 14px;
  793. line-height: 20px;
  794. height: 20px;
  795. &.textLeft {
  796. text-align: left;
  797. }
  798. &.wordBlank {
  799. color: rgba(0, 0, 0, 0.85);
  800. }
  801. }
  802. &.NNPE-chs {
  803. font-family: "FZJCGFKTK";
  804. font-size: 20px;
  805. line-height: 28px;
  806. .active {
  807. color: #de4444;
  808. }
  809. &.wordBlank {
  810. color: rgba(0, 0, 0, 0.85);
  811. }
  812. }
  813. &.padding {
  814. padding: 0 3px;
  815. }
  816. }
  817. }
  818. }
  819. .Soundrecord-content {
  820. padding: 0px 0px 8px 60px;
  821. .luyin-box {
  822. width: 280px;
  823. padding: 8px 12px;
  824. border: 1px solid rgba(0, 0, 0, 0.1);
  825. border-radius: 8px;
  826. background: #ffffff;
  827. }
  828. }
  829. }
  830. </style>