VoiceMatrixFullscreen.vue 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801
  1. <template>
  2. <div :class="['voicefull', bgIndex === 0 ? 'bg1' : 'bg2']">
  3. <div class="voicefull-top">
  4. <div :class="['voicefull-top-show']">
  5. <div class="top-left">
  6. <div :class="['select-bg', bgIndex === 1 ? 'select-bg-blue' : '']">
  7. <div :class="['bg-green-box', bgIndex === 1 ? 'active' : '']">
  8. <span
  9. :class="['bg-green', bgIndex === 1 ? 'active' : '']"
  10. @click="changeBg(1)"
  11. />
  12. </div>
  13. <div :class="['bg-white-box', bgIndex === 0 ? 'active' : '']">
  14. <span
  15. :class="['bg-white', bgIndex === 0 ? 'active' : '']"
  16. @click="changeBg(0)"
  17. />
  18. </div>
  19. </div>
  20. <div
  21. :class="['set-fontSize', bgIndex === 1 ? 'set-fontSize-green' : '']"
  22. >
  23. <template v-if="hzSize >= 34">
  24. <span
  25. :class="[
  26. 'font-jian-black',
  27. bgIndex === 1 ? 'font-jian-yellow' : ''
  28. ]"
  29. @click="setFontSize('-')"
  30. />
  31. </template>
  32. <template v-else>
  33. <span
  34. :class="[
  35. 'font-jian-black',
  36. bgIndex === 1
  37. ? 'font-jian-yellow-disabled'
  38. : 'font-jian-white-disabled'
  39. ]"
  40. />
  41. </template>
  42. <span
  43. :class="[
  44. 'font-img-black',
  45. bgIndex === 1 ? 'font-img-yellow' : ''
  46. ]"
  47. />
  48. <template v-if="hzSize <= 76">
  49. <span
  50. :class="[
  51. 'font-jia-black',
  52. bgIndex === 1 ? 'font-jia-yellow' : ''
  53. ]"
  54. @click="setFontSize('+')"
  55. />
  56. </template>
  57. <template v-else>
  58. <span
  59. :class="[
  60. 'font-jia-black',
  61. bgIndex === 1
  62. ? 'font-jia-yellow-disabled'
  63. : 'font-jia-white-disabled'
  64. ]"
  65. />
  66. </template>
  67. </div>
  68. </div>
  69. <div class="top-middle">
  70. <template v-if="mp3">
  71. <voice-matrix-fullscreen-audio
  72. ref="audioLine"
  73. audio-id="voiceMatrixFullscreenAudio"
  74. :is-repeat="isRepeat"
  75. :bg-index="bgIndex"
  76. :mp3="mp3"
  77. :get-cur-time="getCurTime"
  78. :stop-audio="stopAudio"
  79. :has-selected-cell="hasSelectedCell"
  80. @playChange="playChange"
  81. @parentPlayAudio="playAudio"
  82. @handleChangeStopAudio="handleChangeStopAudio"
  83. />
  84. </template>
  85. <div
  86. :class="['op-btn', bgIndex === 1 ? 'op-btn-green' : '']"
  87. @click="changeLoopState"
  88. >
  89. <span
  90. :class="[
  91. 'repeat-icon',
  92. !isRepeat ? 'disabled' : 'auto-icon',
  93. isRepeat && bgIndex === 1 ? 'auto-icon-yellow' : ''
  94. ]"
  95. />
  96. </div>
  97. <div
  98. :class="['op-btn', bgIndex === 1 ? 'op-btn-green' : '']"
  99. @click="changePinyin"
  100. >
  101. <span
  102. :class="[
  103. 'pinyin-icon',
  104. !isShowPY || !isHasPY ? 'disabled' : '',
  105. isShowPY && isHasPY && bgIndex === 1 ? 'pinyin-icon-yellow' : ''
  106. ]"
  107. />
  108. </div>
  109. <div
  110. :class="['op-btn', bgIndex === 1 ? 'op-btn-green' : '']"
  111. @click="changeEN"
  112. >
  113. <span
  114. :class="[
  115. 'en-icon',
  116. !isShowEN || !isHasEN ? 'disabled' : '',
  117. isShowEN && bgIndex === 1 && isHasEN ? 'en-icon-yellow' : ''
  118. ]"
  119. />
  120. </div>
  121. </div>
  122. <div
  123. :class="['op-btn', bgIndex === 1 ? 'op-btn-green' : '']"
  124. @click="exitFullScreen"
  125. >
  126. <span
  127. :class="['close-icon', bgIndex === 1 ? 'close-icon-white' : '']"
  128. />
  129. </div>
  130. </div>
  131. </div>
  132. <div class="voicefull-content">
  133. <div
  134. v-if="curQue.voiceMatrix.matrix.length > 0"
  135. class="matrix"
  136. :style="{
  137. 'grid-template': `96px repeat(${curQue.voiceMatrix.matrix.length}, auto) minmax(1.5em, 1fr) / 112px repeat(${curQue.voiceMatrix.matrix[0].length}, auto) minmax(124px, 1fr)`,
  138. 'font-size': `${hzSize}px`
  139. }"
  140. @mouseleave="clearSelectCell"
  141. >
  142. <!-- 顶部单元格 -->
  143. <div class="matrix-top" @mouseenter="clearSelectCell" />
  144. <template v-for="(row, i) in curQue.voiceMatrix.matrix[0]">
  145. <div
  146. :key="`top-${i}`"
  147. :class="['matrix-top']"
  148. @mouseenter="checkboxMouseenter(selectColumn === i, 'column')"
  149. >
  150. <span
  151. v-if="
  152. row.type !== 'connection' && curQue.voiceMatrix.columnSelection
  153. "
  154. v-show="
  155. selectColumn === i ||
  156. (selectedLine.type === 'column' && selectedLine.index === i)
  157. "
  158. :class="[
  159. `matrix-checkbox-row-${themeColor}`,
  160. selectedLine.type === 'column' && selectedLine.index === i
  161. ? 'active'
  162. : ''
  163. ]"
  164. @click="selectRowOrColumn(i, 'column')"
  165. />
  166. </div>
  167. </template>
  168. <div class="matrix-top" @mouseenter="clearSelectCell" />
  169. <!-- 主矩阵 -->
  170. <template v-for="(row, i) in curQue.voiceMatrix.matrix">
  171. <div
  172. :key="`start-${i}`"
  173. :class="['column-wrapper']"
  174. @mouseenter="checkboxMouseenter(selectRow === i, 'row')"
  175. >
  176. <span
  177. v-if="curQue.voiceMatrix.rowSelection"
  178. v-show="
  179. selectRow === i ||
  180. (selectedLine.type === 'row' && selectedLine.index === i)
  181. "
  182. :class="[
  183. `matrix-checkbox-column-${themeColor}`,
  184. selectedLine.type === 'row' && selectedLine.index === i
  185. ? 'active'
  186. : ''
  187. ]"
  188. @click="selectRowOrColumn(i, 'row')"
  189. />
  190. </div>
  191. <!-- 单元格 -->
  192. <template v-for="(column, j) in row">
  193. <div
  194. :key="`wrapper-${i}-${j}`"
  195. :class="[
  196. 'column-wrapper',
  197. (i === 0 && curQue.voiceMatrix.firstLineHighlight) ||
  198. (j === row.length - 1 && curQue.voiceMatrix.lastColumnHighlight)
  199. ? `highlight-${themeColor}`
  200. : ''
  201. ]"
  202. @mouseenter="matrixCellMouseenter(i, j, column.type)"
  203. >
  204. <!-- 文本 -->
  205. <div
  206. v-if="column.type === 'text'"
  207. :key="`column-${i}-${j}`"
  208. :class="[
  209. column.text.length === 0 ? 'space' : `column-${themeColor}`,
  210. (selectCell.row === i && selectCell.column === j) ||
  211. (selectedLine.type === 'column' &&
  212. selectedLine.index === j) ||
  213. (selectedLine.type === 'row' && selectedLine.index === i)
  214. ? 'selected'
  215. : '',
  216. playing &&
  217. column.lrc_data.begin_time / 1000 <= curTime &&
  218. (curTime < column.lrc_data.end_time / 1000 ||
  219. column.lrc_data.end_time === -1)
  220. ? 'playing'
  221. : '',
  222. column.isTitle ? 'title' : ''
  223. ]"
  224. @click="matrixCellClick(i, j)"
  225. >
  226. <span>{{ column.text }}</span>
  227. </div>
  228. <!-- 连接线 -->
  229. <div
  230. v-else-if="column.type === 'connection'"
  231. :key="`column-${i}-${j}`"
  232. :class="[
  233. 'connection',
  234. i === 0 && curQue.voiceMatrix.firstLineHighlight
  235. ? `highlight-bc-${themeColor}`
  236. : ''
  237. ]"
  238. />
  239. <!-- 分词 -->
  240. <div
  241. v-else-if="column.type === 'SentenceSegwordChs'"
  242. :key="`column-${i}-${j}`"
  243. :class="[
  244. `sentence-${themeColor}`,
  245. (selectCell.row === i && selectCell.column === j) ||
  246. (selectedLine.type === 'column' &&
  247. selectedLine.index === j) ||
  248. (selectedLine.type === 'row' && selectedLine.index === i)
  249. ? 'selected'
  250. : '',
  251. playing &&
  252. column.lrc_data.begin_time / 1000 <= curTime &&
  253. (curTime < column.lrc_data.end_time / 1000 ||
  254. column.lrc_data.end_time === -1)
  255. ? 'playing'
  256. : '',
  257. column.isTitle ? 'title' : ''
  258. ]"
  259. :style="{
  260. 'grid-template-columns': `repeat(${column.sentence_data.wordsList.length}, auto)`
  261. }"
  262. @click="matrixCellClick(i, j)"
  263. >
  264. <template
  265. v-for="({ chs, pinyin }, w) in column.sentence_data.wordsList"
  266. >
  267. <span
  268. :key="
  269. `${
  270. column.sentence_data.pyPosition === 'top'
  271. ? 'pinyin'
  272. : 'chs'
  273. }-${w}`
  274. "
  275. :style="{
  276. visibility:
  277. column.sentence_data.pyPosition === 'top' && isShowPY
  278. ? 'visible'
  279. : 'hidden'
  280. }"
  281. :class="
  282. column.sentence_data.pyPosition === 'top'
  283. ? 'pinyin'
  284. : 'chs'
  285. "
  286. >
  287. {{
  288. column.sentence_data.pyPosition === "top" ? pinyin : chs
  289. }}
  290. </span>
  291. </template>
  292. <template
  293. v-for="({ chs, pinyin }, w) in column.sentence_data.wordsList"
  294. >
  295. <span
  296. :key="
  297. `${
  298. column.sentence_data.pyPosition === 'top'
  299. ? 'chs'
  300. : 'pinyin'
  301. }-${w}`
  302. "
  303. :style="{
  304. visibility:
  305. column.sentence_data.pyPosition !== 'top' && isShowPY
  306. ? 'hidden'
  307. : 'visible'
  308. }"
  309. :class="
  310. column.sentence_data.pyPosition === 'top'
  311. ? 'chs'
  312. : 'pinyin'
  313. "
  314. >
  315. {{
  316. column.sentence_data.pyPosition === "top" ? chs : pinyin
  317. }}
  318. </span>
  319. </template>
  320. </div>
  321. <!-- 拼音 + 英文 -->
  322. <div
  323. v-else-if="column.type === 'PinyinEnglish'"
  324. :key="`column-${i}-${j}`"
  325. :class="[
  326. `pinyinEnglish-${themeColor}`,
  327. (selectCell.row === i && selectCell.column === j) ||
  328. (selectedLine.type === 'column' &&
  329. selectedLine.index === j) ||
  330. (selectedLine.type === 'row' && selectedLine.index === i)
  331. ? 'selected'
  332. : '',
  333. playing &&
  334. column.lrc_data.begin_time / 1000 <= curTime &&
  335. (curTime < column.lrc_data.end_time / 1000 ||
  336. column.lrc_data.end_time === -1)
  337. ? 'playing'
  338. : '',
  339. column.isTitle ? 'title' : ''
  340. ]"
  341. @click="matrixCellClick(i, j)"
  342. >
  343. <div class="inside-wrapper">
  344. <div class="pinyin">
  345. {{ column.pinyin_english_data.pinyin }}
  346. </div>
  347. <div
  348. class="english"
  349. :style="{ visibility: isShowEN ? 'visible' : 'hidden' }"
  350. >
  351. {{ column.pinyin_english_data.english }}
  352. </div>
  353. </div>
  354. </div>
  355. <!-- 文本中有括号 -->
  356. <div
  357. v-else-if="column.type === 'textBrackets'"
  358. :key="`column-${i}-${j}`"
  359. :class="[
  360. `textBrackets-${themeColor}`,
  361. (selectCell.row === i && selectCell.column === j) ||
  362. (selectedLine.type === 'column' &&
  363. selectedLine.index === j) ||
  364. (selectedLine.type === 'row' && selectedLine.index === i)
  365. ? 'selected'
  366. : '',
  367. playing &&
  368. column.lrc_data.begin_time / 1000 <= curTime &&
  369. (curTime < column.lrc_data.end_time / 1000 ||
  370. column.lrc_data.end_time === -1)
  371. ? 'playing'
  372. : '',
  373. column.isTitle ? 'title' : ''
  374. ]"
  375. @click="matrixCellClick(i, j)"
  376. >
  377. <span>
  378. <span class="brackets-text">{{
  379. column.text_brackets.brackets_outer
  380. }}</span>
  381. <span class="brackets">&nbsp;[&nbsp;</span>
  382. <span class="brackets-text">{{
  383. column.text_brackets.brackets_inner
  384. }}</span>
  385. <span class="brackets">&nbsp;]</span>
  386. </span>
  387. </div>
  388. </div>
  389. </template>
  390. <div :key="`end-${i}`" @mouseenter="clearSelectCell" />
  391. </template>
  392. <!-- 底部格子 -->
  393. <div class="matrix-bottom" @mouseenter="clearSelectCell" />
  394. <template v-for="(row, i) in curQue.voiceMatrix.matrix[0]">
  395. <div :key="`bottom-${i}`" @mouseenter="clearSelectCell" />
  396. </template>
  397. <div class="matrix-bottom" @mouseenter="clearSelectCell" />
  398. </div>
  399. </div>
  400. <div class="voicefull-bottom">
  401. <div :class="['voicefull-bottom-show']">
  402. <div class="bottom-left">
  403. <soundrecorddiff
  404. ref="Soundrecorddiff"
  405. :bg-index="bgIndex"
  406. :file-name="fileName"
  407. :select-data="selectData"
  408. :answer-record-list="recordList"
  409. @getSelectData="getSelectData"
  410. @getWavblob="getWavblob"
  411. @handleParentPlay="handleParentPlay"
  412. @sentPause="sentPause"
  413. @getRerordStatus="getRerordStatus"
  414. @getMicrophoneStatus="getMicrophoneStatus"
  415. @getPlayStatus="getPlayStatus"
  416. @handleWav="handleWav"
  417. />
  418. <div
  419. v-if="isShowCompare"
  420. :class="['compare-box', bgIndex === 1 ? 'compare-box-white' : '']"
  421. >
  422. <audio-compare
  423. type="full"
  424. :theme-color="themeColor"
  425. :url="mp3"
  426. :wavblob="wavblob"
  427. :sent-pause="sentPause"
  428. :is-record="isRecord"
  429. :handle-change-stop-audio="handleChangeStopAudio"
  430. :get-play-status="getPlayStatus"
  431. :matrix-select-lrc="matrixSelectLrc"
  432. :get-cur-time="getCurTime"
  433. :cur-time="curTime"
  434. />
  435. </div>
  436. </div>
  437. </div>
  438. </div>
  439. </div>
  440. </template>
  441. <script>
  442. import VoiceMatrixFullscreenAudio from "./VoiceMatrixFullscreenAudio.vue";
  443. import Soundrecorddiff from "./Soundrecorddiff.vue";
  444. import AudioCompare from "./AudioCompareMatrix.vue";
  445. import Wordcard from "./components/Wordcard.vue";
  446. export default {
  447. components: {
  448. VoiceMatrixFullscreenAudio,
  449. Soundrecorddiff,
  450. AudioCompare,
  451. Wordcard
  452. },
  453. props: ["mp3", "curQue", "themeColor", "recordList"],
  454. data() {
  455. return {
  456. hzSize: 48,
  457. bgIndex: 1,
  458. item: null,
  459. curTime: 0,
  460. stopAudio: false,
  461. isShowCompare: false,
  462. clientY: 0,
  463. top: 0,
  464. left: 0,
  465. isShow: false,
  466. curWordTime: 0,
  467. playing: false,
  468. key: "isRepeat",
  469. isKeyboard: true,
  470. isTopShow: false,
  471. isBottomShow: false,
  472. isRecording: false,
  473. recordPlaying: false,
  474. fileName: "",
  475. // 底色行、列
  476. selectRow: -1,
  477. selectColumn: -1,
  478. // 行、列选中
  479. selectedLine: {
  480. type: "",
  481. index: 0
  482. },
  483. // 点击选中
  484. selectCell: {
  485. row: -1,
  486. column: -1
  487. },
  488. isRepeat: false,
  489. // 跟读所需属性
  490. wavblob: null,
  491. isRecord: false,
  492. matrixSelectLrc: null,
  493. unWatch: null,
  494. lrcArray: [],
  495. cellTimer: null,
  496. // 拼音、英文显隐判断
  497. isShowPY: true,
  498. isShowEN: true
  499. };
  500. },
  501. computed: {
  502. isHasPY() {
  503. let matrix = this.curQue.voiceMatrix.matrix;
  504. for (let i = 0; i < matrix.length; i++) {
  505. if (matrix[i].some(({ type }) => type === "SentenceSegwordChs")) {
  506. return true;
  507. }
  508. }
  509. return false;
  510. },
  511. isHasEN() {
  512. let matrix = this.curQue.voiceMatrix.matrix;
  513. for (let i = 0; i < matrix.length; i++) {
  514. if (matrix[i].some(({ type }) => type === "PinyinEnglish")) return true;
  515. }
  516. return false;
  517. },
  518. hasSelectedCell() {
  519. let { type, index } = this.selectedLine;
  520. let { row, column } = this.selectCell;
  521. return (type.length > 0 && index >= 0) || (row >= 0 && column >= 0);
  522. },
  523. selectData() {
  524. let { type, index } = this.selectedLine;
  525. let { row, column } = this.selectCell;
  526. return {
  527. type: type.length > 0 && index >= 0 ? type : "cell",
  528. index,
  529. row,
  530. column
  531. };
  532. },
  533. // 矩阵的行、列数从 0 开始
  534. matrix() {
  535. const matrixArr = this.curQue.voiceMatrix.matrix;
  536. return {
  537. rows: matrixArr.length - 1,
  538. columns: matrixArr.length > 0 ? matrixArr[0].length - 1 : -1
  539. };
  540. }
  541. },
  542. watch: {
  543. isRecording(newVal) {
  544. if (newVal) {
  545. this.isBottomShow = newVal;
  546. }
  547. },
  548. recordPlaying(newVal) {
  549. if (newVal) {
  550. this.isBottomShow = newVal;
  551. }
  552. },
  553. isShow(val) {
  554. if (val) {
  555. setTimeout(() => {
  556. this.cardHeight = this.$refs.wordcard.offsetHeight;
  557. if (this.screenHeight - this.clientY > this.cardHeight) {
  558. this.top = this.clientY + 20;
  559. } else {
  560. this.top = this.clientY - this.cardHeight - 30;
  561. }
  562. }, 50);
  563. }
  564. }
  565. },
  566. created() {
  567. document.addEventListener("keyup", this.handleKeyup);
  568. [
  569. "fullscreenchange",
  570. "mozfullscreenchange",
  571. "webkitfullscreenchange",
  572. "msfullscreenchange"
  573. ].forEach(event => {
  574. document.addEventListener(event, this.handleFullscreen);
  575. });
  576. },
  577. beforeDestroy() {
  578. document.removeEventListener("keyup", this.handleKeyup);
  579. [
  580. "fullscreenchange",
  581. "mozfullscreenchange",
  582. "webkitfullscreenchange",
  583. "msfullscreenchange"
  584. ].forEach(event => {
  585. document.removeEventListener(event, this.handleFullscreen);
  586. });
  587. },
  588. // 方法集合
  589. methods: {
  590. // #region
  591. /** 语音矩阵方法开始 **/
  592. // 鼠标移入移出
  593. matrixCellMouseenter(i, j, type) {
  594. if (type === "connection") {
  595. this.selectRow = -1;
  596. this.selectColumn = -1;
  597. } else {
  598. this.selectRow = i;
  599. this.selectColumn = j;
  600. }
  601. },
  602. clearSelectCell() {
  603. this.selectRow = -1;
  604. this.selectColumn = -1;
  605. },
  606. // 单击单元格
  607. matrixCellClick(row, column) {
  608. if (this.playing) this.handleParentPlay();
  609. if (this.unWatch) this.unWatch();
  610. this.lrcArray = [];
  611. if (row === this.selectCell.row && column === this.selectCell.column) {
  612. this.selectCell = { row: -1, column: -1 };
  613. return;
  614. }
  615. this.selectedLine = { type: "", index: -1 };
  616. this.selectCell = { row, column };
  617. this.handleChangeTime(
  618. this.curQue.voiceMatrix.matrix[row][column].lrc_data
  619. );
  620. // 设置录音文件名
  621. this.setRecordingFileName(row, column);
  622. },
  623. setRecordingFileName(row, column) {
  624. let {
  625. type,
  626. text,
  627. sentence_data,
  628. pinyin_english_data,
  629. text_brackets
  630. } = this.curQue.voiceMatrix.matrix[row][column];
  631. if (type === "text") this.fileName = text;
  632. if (type === "SentenceSegwordChs") this.fileName = sentence_data.sentence;
  633. if (type === "PinyinEnglish") this.fileName = pinyin_english_data.pinyin;
  634. if (type === "textBrackets") {
  635. this.fileName = `${text_brackets.brackets_outer}[${text_brackets.brackets_inner}]`;
  636. }
  637. },
  638. checkboxMouseenter(isSelected, type) {
  639. if (!isSelected) return this.clearSelectCell();
  640. if (type === "row") this.selectColumn = -1;
  641. if (type === "column") this.selectRow = -1;
  642. },
  643. // 选中行、列
  644. selectRowOrColumn(index, type) {
  645. this.handleParentPlay();
  646. this.lrcArray = [];
  647. this.selectCell = { row: -1, column: -1 };
  648. if (this.unWatch) this.unWatch();
  649. if (
  650. this.selectedLine.type === type &&
  651. this.selectedLine.index === index
  652. ) {
  653. this.selectedLine = { type: "", index: -1 };
  654. return;
  655. }
  656. this.selectedLine = { type, index };
  657. let number = index;
  658. if (type === "column") {
  659. this.curQue.voiceMatrix.matrix[index].forEach(({ type }, i) => {
  660. if (i >= index) return;
  661. if (type === "connection") number -= 1;
  662. });
  663. }
  664. this.fileName = `第 ${number + 1} ${type === "row" ? "行" : "列"}`;
  665. },
  666. playAudio() {
  667. console.log(this.hasSelectedCell);
  668. if (!this.hasSelectedCell) return;
  669. if (this.playing) return this.handleParentPlay();
  670. if (this.lrcArray.length > 0) return this.$refs.audioLine.PlayAudio();
  671. if (this.unWatch) this.unWatch();
  672. this.lrcArray = [];
  673. let { type, index } = this.selectedLine;
  674. if (type.length > 0 && index >= 0 && type === "row") {
  675. this.curQue.voiceMatrix.matrix[index].forEach(item => {
  676. let data = this.getLrcData(item);
  677. if (data) this.lrcArray.push(data);
  678. });
  679. if (this.lrcArray.length > 0) this.lrcPlay(this.lrcArray[0], 0);
  680. return;
  681. }
  682. if (type.length > 0 && index >= 0 && type === "column") {
  683. this.curQue.voiceMatrix.matrix.forEach(item => {
  684. let data = this.getLrcData(item[index]);
  685. if (data) this.lrcArray.push(data);
  686. });
  687. if (this.lrcArray.length > 0) this.lrcPlay(this.lrcArray[0], 0);
  688. return;
  689. }
  690. let { row, column } = this.selectCell;
  691. if (row >= 0 && column >= 0) {
  692. this.handleChangeTime(
  693. this.curQue.voiceMatrix.matrix[row][column].lrc_data
  694. );
  695. }
  696. },
  697. lrcPlay({ begin_time, end_time }, index) {
  698. this.handleParentPlay();
  699. this.$nextTick(() => {
  700. this.$refs.audioLine.onTimeupdateTime(begin_time / 1000);
  701. this.$refs.audioLine.PlayAudio();
  702. if (end_time === -1) return;
  703. let end = end_time / 1000 - 0.01;
  704. this.unWatch = this.$watch("curTime", val => {
  705. if (val >= end) {
  706. if (!this.hasSelectedCell) return this.unWatch();
  707. this.handleParentPlay();
  708. this.$refs.audioLine.onTimeupdateTime(end);
  709. this.unWatch();
  710. let i = index + 1;
  711. if (i < this.lrcArray.length) {
  712. return this.lrcPlay(this.lrcArray[i], i);
  713. }
  714. // 多次循环
  715. if (this.isRepeat) {
  716. return this.lrcPlay(this.lrcArray[0], 0);
  717. }
  718. this.lrcArray = [];
  719. }
  720. });
  721. });
  722. },
  723. // 暂停音频播放
  724. handleParentPlay() {
  725. this.stopAudio = true;
  726. },
  727. // 音频播放时改变布尔值
  728. handleChangeStopAudio() {
  729. this.stopAudio = false;
  730. },
  731. getCurTime(curTime) {
  732. this.curTime = curTime;
  733. },
  734. getWavblob(wavblob) {
  735. this.wavblob = wavblob;
  736. },
  737. handleWav(list, tmIndex = 0) {
  738. this.$emit("handleWav", list, tmIndex);
  739. },
  740. getSelectData({ type, index, row, column }) {
  741. if (type === "") return;
  742. if (index === 0 && row === -1 && column === -1) {
  743. this.matrixSelectLrc = null;
  744. return;
  745. }
  746. let arr = [];
  747. if (type.length > 0 && index >= 0 && type === "row") {
  748. this.curQue.voiceMatrix.matrix[index].forEach(item => {
  749. let data = this.getLrcData(item);
  750. if (data) arr.push(data);
  751. });
  752. this.matrixSelectLrc = arr;
  753. return;
  754. }
  755. if (type.length > 0 && index >= 0 && type === "column") {
  756. this.curQue.voiceMatrix.matrix.forEach(item => {
  757. let data = this.getLrcData(item[index]);
  758. if (data) arr.push(data);
  759. });
  760. this.matrixSelectLrc = arr;
  761. return;
  762. }
  763. if (type === "cell" && row >= 0 && column >= 0) {
  764. let lrcData = this.curQue.voiceMatrix.matrix[row][column].lrc_data;
  765. if (lrcData.end_time === -1) lrcData.end_time = this.mp3Duration;
  766. this.matrixSelectLrc = [lrcData];
  767. }
  768. },
  769. getLrcData({ type, text, lrc_data }) {
  770. if (
  771. type === "SentenceSegwordChs" ||
  772. type === "PinyinEnglish" ||
  773. type === "textBrackets" ||
  774. (type === "text" && text.length > 0)
  775. ) {
  776. if (lrc_data.end_time === -1) {
  777. return {
  778. begin_time: lrc_data.begin_time,
  779. end_time: this.mp3Duration,
  780. text: lrc_data.text
  781. };
  782. }
  783. return lrc_data;
  784. }
  785. return false;
  786. },
  787. sentPause(isRecord) {
  788. this.isRecord = isRecord;
  789. },
  790. handleChangeTime({ begin_time, end_time }) {
  791. if (this.unWatch) this.unWatch();
  792. this.handleParentPlay();
  793. this.$nextTick(() => {
  794. this.$refs.audioLine.onTimeupdateTime(begin_time / 1000);
  795. this.$refs.audioLine.PlayAudio();
  796. // 监听是否已到结束时间,为了选中效果 - 0.01
  797. if (end_time === -1) return;
  798. let end = end_time / 1000 - 0.01;
  799. this.unWatch = this.$watch("curTime", val => {
  800. if (val >= end) {
  801. this.handleParentPlay();
  802. this.$refs.audioLine.onTimeupdateTime(end);
  803. this.unWatch();
  804. this.unWatch = null;
  805. if (this.isRepeat) {
  806. this.handleChangeTime({ begin_time, end_time });
  807. }
  808. }
  809. });
  810. });
  811. },
  812. /** 语音矩阵方法结束 **/
  813. // #endregion
  814. /* 全局事件处理 */
  815. handleKeyup({ key }) {
  816. if (!this.isKeyboard) return;
  817. if (key === "Enter") {
  818. this.$refs.Soundrecorddiff.microphone();
  819. }
  820. if (key === " ") {
  821. this.hasSelectedCell
  822. ? this.playAudio()
  823. : this.$refs.audioLine.PlayAudio();
  824. }
  825. if (!this.hasSelectedCell) return;
  826. if (key === "ArrowUp") {
  827. let { type, index, row, column } = this.selectData;
  828. if (type === "cell" && row > 0) {
  829. return this.matrixCellClick(row - 1, column);
  830. }
  831. if ((type === "column" || type === "row") && index > 0) {
  832. return this.selectRowOrColumn(index - 1, type);
  833. }
  834. }
  835. if (key === "ArrowDown") {
  836. let { type, index, row, column } = this.selectData;
  837. let { rows } = this.matrix;
  838. if (type === "cell" && row < rows) {
  839. return this.matrixCellClick(row + 1, column);
  840. }
  841. if ((type === "column" || type === "row") && index < rows) {
  842. return this.selectRowOrColumn(index + 1, type);
  843. }
  844. }
  845. if (key === "ArrowLeft") {
  846. let { type, row, column } = this.selectData;
  847. if (type !== "cell") return;
  848. if (column > 0) {
  849. return this.matrixCellClick(row, column - 1);
  850. }
  851. }
  852. if (key === "ArrowRight") {
  853. let { columns } = this.matrix;
  854. let { type, row, column } = this.selectData;
  855. if (type !== "cell") return;
  856. if (column < columns) {
  857. return this.matrixCellClick(row, column + 1);
  858. }
  859. }
  860. },
  861. handleFullscreen() {
  862. let isFullscreen = Boolean(
  863. document.fullScreen ||
  864. document.mozFullScreen ||
  865. document.webkitIsFullScreen ||
  866. document.webkitFullScreen ||
  867. document.msFullScreen
  868. );
  869. if (!isFullscreen) this.changeFullScreen();
  870. },
  871. setTopShow(bool) {
  872. this.isTopShow = bool;
  873. },
  874. setBottomShow(bool) {
  875. if (!this.recordPlaying && !this.isRecording) {
  876. this.isBottomShow = bool;
  877. }
  878. },
  879. getPlayStatus(bool) {
  880. this.recordPlaying = bool;
  881. },
  882. setFontSize(type) {
  883. if (this.hzSize >= 34 || this.hzSize <= 76) {
  884. type === "+" ? (this.hzSize += 4) : (this.hzSize -= 4);
  885. }
  886. },
  887. playChange(bool) {
  888. this.playing = bool;
  889. },
  890. changeStatus(key) {
  891. this[key] = !this[key];
  892. },
  893. changeLoopState() {
  894. this.isRepeat = !this.isRepeat;
  895. },
  896. getRerordStatus(bool) {
  897. this.isShowCompare = bool;
  898. },
  899. getMicrophoneStatus(bool) {
  900. this.isRecording = bool;
  901. },
  902. getCurCompareTime(curTime) {
  903. this.curTime = curTime * 1000;
  904. },
  905. getCurWordTime(curTime) {
  906. this.curWordTime = curTime * 1000;
  907. },
  908. changePinyin() {
  909. if (!this.isHasPY) return;
  910. this.isShowPY = !this.isShowPY;
  911. },
  912. changeEN() {
  913. if (!this.isHasEN) return;
  914. this.isShowEN = !this.isShowEN;
  915. },
  916. changeBg(bgIndex) {
  917. this.bgIndex = bgIndex;
  918. },
  919. pauseAudio() {
  920. let audio = document.getElementsByTagName("audio");
  921. if (
  922. audio &&
  923. audio.length > 0 &&
  924. window.location.href.indexOf("GCLS-Learn") == -1
  925. ) {
  926. audio.forEach(item => {
  927. item.pause();
  928. });
  929. }
  930. },
  931. exitFullScreen() {
  932. this.pauseAudio();
  933. this.$emit("exitFullscreen");
  934. },
  935. changeFullScreen() {
  936. this.pauseAudio();
  937. this.$emit("changeIsFull");
  938. }
  939. }
  940. };
  941. </script>
  942. <style lang="scss" scoped>
  943. $select-color: #de4444;
  944. $border-color: #e6e6e6;
  945. $select-color-green: #24b99e;
  946. $select-color-green-bc: rgba(36, 185, 158, 0.25);
  947. $select-color-green-hover: #3dd4b8;
  948. $select-color-green-active: #1fa189;
  949. $select-color-brown: #bd8865;
  950. $select-color-brown-bc: rgba(189, 136, 101, 0.25);
  951. $select-color-brown-hover: #d6a687;
  952. $select-color-brown-active: #a37557;
  953. $dark-color: #ffc600;
  954. $dark-color-play: #fff2c6;
  955. .voicefull {
  956. width: 100vh;
  957. height: 100vw;
  958. overflow: hidden;
  959. display: flex;
  960. flex-direction: column;
  961. transform: rotate(90deg);
  962. transform-origin: 0% 0%;
  963. margin-left: 100vw;
  964. position: fixed;
  965. left: 0;
  966. top: 0;
  967. z-index: 99999;
  968. &.bg1 {
  969. background: #fff;
  970. color: #062211;
  971. .playing {
  972. color: $select-color !important;
  973. }
  974. }
  975. // 黑暗模式 强制替换颜色
  976. &.bg2 {
  977. background: linear-gradient(180deg, #274533 0%, #385f45 100%);
  978. color: #fff;
  979. .column-wrapper {
  980. &:hover {
  981. color: $dark-color !important;
  982. }
  983. .selected {
  984. color: $dark-color !important;
  985. }
  986. .playing {
  987. color: $dark-color-play;
  988. text-shadow: 0 0 0.1em, 0 0 0.3em;
  989. }
  990. &.highlight-,
  991. &.highlight-red,
  992. &.highlight-brown,
  993. &.highlight-green {
  994. color: $dark-color !important;
  995. }
  996. .matrix-checkbox-column-,
  997. .matrix-checkbox-column-red,
  998. .matrix-checkbox-column-brown,
  999. .matrix-checkbox-column-green {
  1000. &.active {
  1001. border-color: $dark-color !important;
  1002. &::after {
  1003. border-color: $dark-color !important;
  1004. }
  1005. }
  1006. }
  1007. .connection {
  1008. background-color: #fff !important;
  1009. &.highlight-bc-,
  1010. &.highlight-bc-red,
  1011. &.highlight-bc-brown,
  1012. &.highlight-bc-green {
  1013. background-color: $dark-color !important;
  1014. }
  1015. }
  1016. }
  1017. .matrix-top {
  1018. .matrix-checkbox-row-,
  1019. .matrix-checkbox-row-green,
  1020. .matrix-checkbox-row-brown,
  1021. .matrix-checkbox-row-red {
  1022. &.active {
  1023. border-color: $dark-color !important;
  1024. &::after {
  1025. border-color: $dark-color !important;
  1026. }
  1027. }
  1028. }
  1029. }
  1030. }
  1031. &-top {
  1032. height: 66px;
  1033. width: 100%;
  1034. padding: 0 15px;
  1035. .voicefull-top-hidden {
  1036. width: 100%;
  1037. height: 66px;
  1038. visibility: hidden;
  1039. display: flex;
  1040. justify-content: space-between;
  1041. align-items: end;
  1042. }
  1043. .voicefull-top-show {
  1044. width: 100%;
  1045. height: 66px;
  1046. visibility: visible;
  1047. display: flex;
  1048. justify-content: space-between;
  1049. align-items: center;
  1050. }
  1051. .top-left {
  1052. display: flex;
  1053. justify-content: flex-start;
  1054. align-items: center;
  1055. }
  1056. .select-bg {
  1057. display: flex;
  1058. justify-content: space-between;
  1059. align-items: center;
  1060. width: 84px;
  1061. height: 48px;
  1062. border: 1px solid rgba(0, 0, 0, 0.1);
  1063. border-radius: 40px;
  1064. display: flex;
  1065. justify-content: center;
  1066. align-items: center;
  1067. margin-right: 15px;
  1068. &.select-bg-blue {
  1069. background: rgba(255, 255, 255, 0.1);
  1070. border: 1px solid rgba(0, 0, 0, 0.1);
  1071. }
  1072. > div {
  1073. width: 36px;
  1074. height: 36px;
  1075. border-radius: 100%;
  1076. display: flex;
  1077. justify-content: center;
  1078. align-items: center;
  1079. &.bg-white-box {
  1080. background: 0 0;
  1081. margin-right: 4px;
  1082. &.active {
  1083. background: #de4444;
  1084. }
  1085. }
  1086. &.bg-green-box {
  1087. background: #fff;
  1088. &.active {
  1089. background: #ffc600;
  1090. }
  1091. }
  1092. > span {
  1093. width: 24px;
  1094. height: 24px;
  1095. border-radius: 100%;
  1096. cursor: pointer;
  1097. &.bg-white {
  1098. background: #fff;
  1099. }
  1100. &.bg-green {
  1101. background: linear-gradient(180deg, #274533 0%, #385f45 100%);
  1102. }
  1103. }
  1104. }
  1105. }
  1106. .set-fontSize {
  1107. padding: 0 10px;
  1108. height: 48px;
  1109. background: #ffffff;
  1110. border: 1px solid rgba(0, 0, 0, 0.1);
  1111. border-radius: 40px;
  1112. display: flex;
  1113. justify-content: center;
  1114. align-items: center;
  1115. &-green {
  1116. background: rgba(255, 255, 255, 0.1);
  1117. border: 1px solid rgba(0, 0, 0, 0.1);
  1118. }
  1119. > span {
  1120. width: 24px;
  1121. height: 24px;
  1122. margin: 0 4px;
  1123. &.font-jian {
  1124. &-black {
  1125. background: url("../../../assets/NPC/jian-black.png") no-repeat left
  1126. top;
  1127. background-size: 100% 100%;
  1128. cursor: pointer;
  1129. }
  1130. &-yellow {
  1131. background: url("../../../assets/NPC/jian-white.png") no-repeat left
  1132. top;
  1133. background-size: 100% 100%;
  1134. cursor: pointer;
  1135. }
  1136. &-white-disabled {
  1137. background: url("../../../assets/NPC/jian-white-disabled.png")
  1138. no-repeat left top;
  1139. background-size: 100% 100%;
  1140. cursor: pointer;
  1141. }
  1142. &-yellow-disabled {
  1143. background: url("../../../assets/NPC/jian-yellow-disabled.png")
  1144. no-repeat left top;
  1145. background-size: 100% 100%;
  1146. cursor: pointer;
  1147. }
  1148. }
  1149. &.font-img {
  1150. &-black {
  1151. background: url("../../../assets/NPC/fontSize-black.png") no-repeat
  1152. left top;
  1153. background-size: 100% 100%;
  1154. }
  1155. &-yellow {
  1156. background: url("../../../assets/NPC/fontSize-white.png") no-repeat
  1157. left top;
  1158. background-size: 100% 100%;
  1159. }
  1160. }
  1161. &.font-jia {
  1162. &-black {
  1163. background: url("../../../assets/NPC/jia-black.png") no-repeat left
  1164. top;
  1165. background-size: 100% 100%;
  1166. cursor: pointer;
  1167. }
  1168. &-yellow {
  1169. background: url("../../../assets/NPC/jia-white.png") no-repeat left
  1170. top;
  1171. background-size: 100% 100%;
  1172. cursor: pointer;
  1173. }
  1174. &-white-disabled {
  1175. background: url("../../../assets/NPC/jia-white-disabled.png")
  1176. no-repeat left top;
  1177. background-size: 100% 100%;
  1178. cursor: pointer;
  1179. }
  1180. &-yellow-disabled {
  1181. background: url("../../../assets/NPC/jia-yellow-disabled.png")
  1182. no-repeat left top;
  1183. background-size: 100% 100%;
  1184. cursor: pointer;
  1185. }
  1186. }
  1187. }
  1188. }
  1189. .top-middle {
  1190. display: flex;
  1191. justify-content: center;
  1192. align-items: center;
  1193. .audio-box {
  1194. width: 48px;
  1195. height: 48px;
  1196. background: #ffffff;
  1197. border: 1px solid rgba(0, 0, 0, 0.1);
  1198. border-radius: 40px;
  1199. display: flex;
  1200. justify-content: center;
  1201. align-items: center;
  1202. &-green {
  1203. background: rgba(255, 255, 255, 0.1);
  1204. border: 1px solid rgba(0, 0, 0, 0.1);
  1205. }
  1206. }
  1207. }
  1208. }
  1209. .op-btn {
  1210. width: 48px;
  1211. height: 48px;
  1212. border-radius: 100%;
  1213. display: flex;
  1214. justify-content: center;
  1215. align-items: center;
  1216. flex-shrink: 0;
  1217. cursor: pointer;
  1218. margin-left: 32px;
  1219. background: #ffffff;
  1220. border: 1px solid rgba(0, 0, 0, 0.1);
  1221. &-green {
  1222. background: rgba(255, 255, 255, 0.1);
  1223. border: 1px solid rgba(0, 0, 0, 0.1);
  1224. }
  1225. &.close-btn {
  1226. background: #274533;
  1227. border: 1px solid rgba(0, 0, 0, 0.1);
  1228. }
  1229. > span {
  1230. width: 24px;
  1231. height: 24px;
  1232. &.close-icon {
  1233. background: url("../../../assets/icon/cross-24-normal-black.png")
  1234. no-repeat left top;
  1235. background-size: 100% 100%;
  1236. &-white {
  1237. background: url("../../../assets/icon/cross-24-normal-white.png")
  1238. no-repeat left top;
  1239. background-size: 100% 100%;
  1240. }
  1241. }
  1242. }
  1243. }
  1244. .repeat-icon {
  1245. background: url("../../../assets/icon/Repeat-24-normal-red.png") no-repeat
  1246. left top;
  1247. background-size: 100% 100%;
  1248. &.disabled {
  1249. background: url("../../../assets/icon/auto-24-disable-black.png")
  1250. no-repeat left top;
  1251. background-size: 100% 100%;
  1252. }
  1253. &-yellow {
  1254. background: url("../../../assets/icon/Repeat-24-normal-yellow.png")
  1255. no-repeat left top;
  1256. background-size: 100% 100%;
  1257. }
  1258. &.auto-icon {
  1259. background: url("../../../assets/icon/Auto-24-next-red.png") no-repeat
  1260. left top;
  1261. background-size: 100% 100%;
  1262. &-yellow {
  1263. background: url("../../../assets/icon/Auto-24-next-yellow.png")
  1264. no-repeat left top;
  1265. background-size: 100% 100%;
  1266. }
  1267. }
  1268. }
  1269. .pinyin-icon {
  1270. background: url("../../../assets/icon/pinyin-24-normal-red.png") no-repeat
  1271. left top;
  1272. background-size: 100% 100%;
  1273. &.disabled {
  1274. background: url("../../../assets/icon/pinyin-24-disable-Black.png")
  1275. no-repeat left top;
  1276. background-size: 100% 100%;
  1277. }
  1278. &-yellow {
  1279. background: url("../../../assets/icon/pinyin-24-normal-yellow.png")
  1280. no-repeat left top;
  1281. background-size: 100% 100%;
  1282. }
  1283. }
  1284. .en-icon {
  1285. background: url("../../../assets/icon/EN-24-normal-Red.png") no-repeat left
  1286. top;
  1287. background-size: 100% 100%;
  1288. &.disabled {
  1289. background: url("../../../assets/icon/EN-24-disable-Black.png") no-repeat
  1290. left top;
  1291. background-size: 100% 100%;
  1292. }
  1293. &-yellow {
  1294. background: url("../../../assets/icon/EN-24-normal-yellow.png") no-repeat
  1295. left top;
  1296. background-size: 100% 100%;
  1297. }
  1298. }
  1299. .keyboard-icon {
  1300. background: url("../../../assets/icon/enter-24-keyboard-red.png") no-repeat
  1301. left top;
  1302. background-size: 100% 100%;
  1303. &.disabled {
  1304. background: url("../../../assets/icon/enter-24-keyboard-disable-Black.png")
  1305. no-repeat left top;
  1306. background-size: 100% 100%;
  1307. }
  1308. &-yellow {
  1309. background: url("../../../assets/icon/enter-24-keyboard-yellow.png")
  1310. no-repeat left top;
  1311. background-size: 100% 100%;
  1312. }
  1313. }
  1314. &-content {
  1315. flex: 1;
  1316. width: 100%;
  1317. display: flex;
  1318. align-items: center;
  1319. justify-content: center;
  1320. height: calc(100vw - 272px);
  1321. overflow: auto;
  1322. // 语音矩阵
  1323. .matrix {
  1324. display: inline-grid;
  1325. gap: 20px 48px;
  1326. height: 100%;
  1327. word-break: break-word;
  1328. %matrix-checkbox {
  1329. position: relative;
  1330. top: calc(50% - 0.25em);
  1331. display: block;
  1332. width: 0.5em;
  1333. height: 0.5em;
  1334. border: 1.5px solid #b0b0b0;
  1335. border-radius: 4px;
  1336. margin: 0 auto;
  1337. cursor: pointer;
  1338. &.active {
  1339. border-color: $select-color;
  1340. &::after {
  1341. box-sizing: content-box;
  1342. content: "";
  1343. border: 1px solid $select-color;
  1344. border-left: 0;
  1345. border-top: 0;
  1346. width: 0.1em;
  1347. height: 0.25em;
  1348. top: 18%;
  1349. left: 37%;
  1350. position: absolute;
  1351. transform: rotate(45deg) scaleY(1);
  1352. transition: transform 0.15s ease-in 0.05s;
  1353. transform-origin: center;
  1354. }
  1355. }
  1356. }
  1357. .matrix-checkbox-row-,
  1358. .matrix-checkbox-row-red {
  1359. @extend %matrix-checkbox;
  1360. }
  1361. .matrix-checkbox-row-green {
  1362. @extend %matrix-checkbox;
  1363. &.active {
  1364. border-color: $select-color-green-active;
  1365. &::after {
  1366. border-color: $select-color-green-active;
  1367. }
  1368. }
  1369. }
  1370. .matrix-checkbox-row-brown {
  1371. @extend %matrix-checkbox;
  1372. &.active {
  1373. border-color: $select-color-brown-active;
  1374. &::after {
  1375. border-color: $select-color-brown-active;
  1376. }
  1377. }
  1378. }
  1379. %matrix-checkbox-column,
  1380. .matrix-checkbox-column-,
  1381. .matrix-checkbox-column-red {
  1382. @extend %matrix-checkbox;
  1383. top: calc(50% - 0.25em);
  1384. right: -48px;
  1385. }
  1386. .matrix-checkbox-column-green {
  1387. @extend %matrix-checkbox-column;
  1388. &.active {
  1389. border-color: $select-color-green-active;
  1390. &::after {
  1391. border-color: $select-color-green-active;
  1392. }
  1393. }
  1394. }
  1395. .matrix-checkbox-column-brown {
  1396. @extend %matrix-checkbox-column;
  1397. &.active {
  1398. border-color: $select-color-brown-active;
  1399. &::after {
  1400. border-color: $select-color-brown-active;
  1401. }
  1402. }
  1403. }
  1404. .read {
  1405. background-color: #eaeaea;
  1406. }
  1407. .highlight-,
  1408. .highlight-red {
  1409. color: $select-color;
  1410. }
  1411. .highlight-green {
  1412. color: $select-color-green;
  1413. }
  1414. .highlight-brown {
  1415. color: $select-color-brown;
  1416. }
  1417. .column-wrapper {
  1418. padding: 4px;
  1419. %column {
  1420. width: 100%;
  1421. height: 100%;
  1422. min-height: 32px;
  1423. border-radius: 8px;
  1424. transition: 0.2s;
  1425. cursor: pointer;
  1426. user-select: none;
  1427. &:hover {
  1428. border-color: #8c8c8c;
  1429. }
  1430. &.selected {
  1431. color: $select-color;
  1432. border-color: $select-color;
  1433. }
  1434. &.title {
  1435. background-color: transparent;
  1436. border-color: transparent;
  1437. }
  1438. > span {
  1439. display: inline-block;
  1440. padding: 4px 12px;
  1441. word-break: keep-all;
  1442. white-space: nowrap;
  1443. }
  1444. }
  1445. %column-red,
  1446. .column-,
  1447. .column-red {
  1448. @extend %column;
  1449. position: relative;
  1450. font-family: "GB-PINYINOK-B", "FZJCGFKTK";
  1451. &::before {
  1452. display: inline-block;
  1453. content: "";
  1454. vertical-align: middle;
  1455. }
  1456. }
  1457. .column-green {
  1458. @extend %column-red;
  1459. &.selected {
  1460. color: $select-color-green;
  1461. border-color: $select-color-green;
  1462. }
  1463. }
  1464. .column-brown {
  1465. @extend %column-red;
  1466. &.selected {
  1467. color: $select-color-brown;
  1468. border-color: $select-color-brown;
  1469. }
  1470. }
  1471. %sentence,
  1472. .sentence-,
  1473. .sentence-red {
  1474. @extend %column;
  1475. display: inline-grid;
  1476. padding: 4px 12px;
  1477. column-gap: 8px;
  1478. justify-items: center;
  1479. justify-content: start;
  1480. > span {
  1481. padding: 0;
  1482. }
  1483. .pinyin {
  1484. font-family: "GB-PINYINOK-B";
  1485. opacity: 0.45;
  1486. font-size: 0.75em;
  1487. }
  1488. .chs {
  1489. font-family: "FZJCGFKTK";
  1490. font-size: 1em;
  1491. }
  1492. }
  1493. .sentence-green {
  1494. @extend %sentence;
  1495. &.selected {
  1496. color: $select-color-green;
  1497. border-color: $select-color-green;
  1498. }
  1499. }
  1500. .sentence-brown {
  1501. @extend %sentence;
  1502. &.selected {
  1503. color: $select-color-brown;
  1504. border-color: $select-color-brown;
  1505. }
  1506. }
  1507. .connection {
  1508. position: relative;
  1509. top: calc(50% - 1px);
  1510. height: 2px;
  1511. width: 16px;
  1512. margin: 0 -4px;
  1513. border-radius: 4px;
  1514. background-color: #252525;
  1515. &.highlight-bc-,
  1516. &.highlight-bc-red {
  1517. background-color: $select-color;
  1518. }
  1519. &.highlight-bc-green {
  1520. background-color: $select-color-green;
  1521. }
  1522. &.highlight-bc-brown {
  1523. background-color: $select-color-brown;
  1524. }
  1525. }
  1526. // 拼音 + 文字
  1527. %pinyinEnglish,
  1528. .pinyinEnglish-,
  1529. .pinyinEnglish-red {
  1530. @extend %column;
  1531. .inside-wrapper {
  1532. padding: 4px 12px;
  1533. .pinyin {
  1534. font-family: "GB-PINYINOK-B";
  1535. font-size: 1em;
  1536. }
  1537. .english {
  1538. font-family: "robot";
  1539. opacity: 0.45;
  1540. font-size: 0.75em;
  1541. }
  1542. }
  1543. }
  1544. .pinyinEnglish-green {
  1545. @extend %pinyinEnglish;
  1546. &.selected {
  1547. color: $select-color-green;
  1548. border-color: $select-color-green;
  1549. }
  1550. }
  1551. .pinyinEnglish-brown {
  1552. @extend %pinyinEnglish;
  1553. &.selected {
  1554. color: $select-color-brown;
  1555. border-color: $select-color-brown;
  1556. }
  1557. }
  1558. %textBrackets,
  1559. .textBrackets-,
  1560. .textBrackets-red {
  1561. @extend %column;
  1562. .brackets-text {
  1563. font-family: "GB-PINYINOK-B";
  1564. }
  1565. .brackets {
  1566. font-size: 1em;
  1567. font-family: "FZJCGFKTK";
  1568. }
  1569. }
  1570. .textBrackets-green {
  1571. @extend %textBrackets;
  1572. &.selected {
  1573. color: $select-color-green;
  1574. border-color: $select-color-green;
  1575. }
  1576. }
  1577. .textBrackets-brown {
  1578. @extend %textBrackets;
  1579. &.selected {
  1580. color: $select-color-brown;
  1581. border-color: $select-color-brown;
  1582. }
  1583. }
  1584. }
  1585. }
  1586. }
  1587. &-bottom {
  1588. height: 66px;
  1589. width: 100%;
  1590. display: flex;
  1591. justify-content: space-between;
  1592. align-items: center;
  1593. padding-right: 40px;
  1594. .voicefull-bottom-show {
  1595. height: 66px;
  1596. width: 100%;
  1597. display: flex;
  1598. justify-content: space-between;
  1599. align-items: start;
  1600. visibility: visible;
  1601. &.hidden {
  1602. visibility: hidden;
  1603. }
  1604. }
  1605. .bottom-left {
  1606. display: flex;
  1607. justify-content: flex-start;
  1608. align-items: center;
  1609. .compare-box {
  1610. height: 56px;
  1611. padding: 16px 16px;
  1612. border: 1px solid rgba(0, 0, 0, 0.1);
  1613. border-radius: 0 40px 40px 0;
  1614. border-left: 0px solid rgba(0, 0, 0, 0.1);
  1615. &-white {
  1616. background: rgba(255, 255, 255, 0.1);
  1617. border: 1px solid rgba(0, 0, 0, 0.1);
  1618. border-left: 0;
  1619. }
  1620. }
  1621. }
  1622. }
  1623. }
  1624. </style>
  1625. <style lang="scss">
  1626. .NPC-Big-Book-preview-green {
  1627. .bg1 {
  1628. .repeat-icon {
  1629. background: url("../../../assets/icon/Repeat-24-normal-Green.png")
  1630. no-repeat left top;
  1631. background-size: 100% 100%;
  1632. }
  1633. .pinyin-icon {
  1634. background: url("../../../assets/icon/pinyin-24-normal-green.png")
  1635. no-repeat left top;
  1636. background-size: 100% 100%;
  1637. }
  1638. .en-icon {
  1639. background: url("../../../assets/icon/EN-24-normal-Green.png") no-repeat
  1640. left top;
  1641. background-size: 100% 100%;
  1642. }
  1643. }
  1644. }
  1645. .NPC-Big-Book-preview-brown {
  1646. .bg1 {
  1647. .repeat-icon {
  1648. background: url("../../../assets/icon/Repeat-24-normal-Brown.png")
  1649. no-repeat left top;
  1650. background-size: 100% 100%;
  1651. }
  1652. .en-icon {
  1653. background: url("../../../assets/icon/EN-24-normal-Brown.png") no-repeat
  1654. left top;
  1655. background-size: 100% 100%;
  1656. }
  1657. .coll-icon {
  1658. background: url("../../../assets/icon/bookmarkfill-24-normal-brown.png")
  1659. no-repeat left top;
  1660. background-size: 100% 100%;
  1661. }
  1662. }
  1663. }
  1664. </style>