Article.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. <template>
  2. <ModuleBase :type="data.type">
  3. <template #content>
  4. <!-- eslint-disable max-len -->
  5. <div v-loading="loading" class="article-wrapper">
  6. <el-input v-model="data.content" placeholder="输入" type="textarea" />
  7. <SelectUpload label="课文音频" type="audio" width="500px" @uploadSuccess="uploadAudioSuccess" />
  8. <div v-if="data.mp3_list.length > 0" class="upload-file">
  9. <div class="file-name">
  10. <span>
  11. <SvgIcon icon-class="note" size="12" />
  12. <span>{{ data.mp3_list[0].name }}</span>
  13. </span>
  14. </div>
  15. <SvgIcon icon-class="delete-black" size="12" @click="removeFile" />
  16. </div>
  17. <div v-if="data.content" class="btn-box">
  18. <a @click="handleChangeContent">生成分词</a>
  19. <a @click="checkArticle">文章校对</a>
  20. <a @click="picArticle">添加图片</a>
  21. <a @click="editWordsFlag = !editWordsFlag">编辑生词短语注释</a>
  22. <template v-if="data.wordTime && data.wordTime.length > 0">
  23. <!-- <span>已有字幕时间节点</span> -->
  24. <a type="text" @click="againWordTime">重新生成字幕时间</a>
  25. <a size="medium" @click="compareTime('句子')">校对句子字幕时间</a>
  26. <a size="medium" @click="compareTime('文字')">校对文字字幕时间</a>
  27. </template>
  28. <template v-else>
  29. <a v-if="!isWordTime" size="medium" @click="createWordTimes">自动生成字幕节点</a>
  30. <p v-else>字幕节点生成中...请等待</p>
  31. </template>
  32. <el-button @click="handleMultilingual">课文多语言</el-button>
  33. <MultilingualFill
  34. :visible.sync="multilingualVisible"
  35. :text="multilingualText"
  36. :translations="data.multilingual"
  37. @SubmitTranslation="handleMultilingualTranslation"
  38. />
  39. </div>
  40. </div>
  41. <el-dialog
  42. v-if="showArticleFlag"
  43. :visible.sync="showArticleFlag"
  44. :show-close="true"
  45. :close-on-click-modal="true"
  46. :modal-append-to-body="true"
  47. :append-to-body="true"
  48. :lock-scroll="true"
  49. width="80%"
  50. class="practiceBox"
  51. >
  52. <CheckArticle :data="data" @saveWord="saveWord" @savePinyin="savePinyin" @saveStyle="saveStyle" />
  53. </el-dialog>
  54. <el-dialog title="校对字幕时间" :visible.sync="compareShow" width="50%" :before-close="handleClose" top="0">
  55. <CompareTime :data="compareData" :type="compareType" :changewords-result-list="changewordsResultList" />
  56. <span slot="footer" class="dialog-footer">
  57. <el-button @click="handleClose">取 消</el-button>
  58. <el-button :loading="compareloading" type="primary" @click="saveCompare">确 定</el-button>
  59. </span>
  60. </el-dialog>
  61. <!-- <el-dialog title="" :visible.sync="editWordsFlag" width="80%" :close-on-click-modal="true" top="0"> -->
  62. <template v-if="editWordsFlag">
  63. <div class="tabs-box">
  64. <a :class="[editWordIndex === 0 ? 'active' : '']" @click="editWordIndex = 0">生词</a>
  65. <a :class="[editWordIndex === 2 ? 'active' : '']" @click="editWordIndex = 2">其他词汇</a>
  66. <a :class="[editWordIndex === 1 ? 'active' : '']" @click="editWordIndex = 1">注释</a>
  67. </div>
  68. <NewWord
  69. v-if="editWordIndex === 0"
  70. key="new_word"
  71. :data-new-word="data.new_word_list"
  72. @sureNewWords="sureNewWords"
  73. />
  74. <Notes v-if="editWordIndex === 1" key="notes" :data-notes="data.notes_list" @sureNotes="sureNotes" />
  75. <NewWord v-if="editWordIndex === 2" :data-new-word="data.other_word_list" @sureNewWords="sureOtherNewWords" />
  76. </template>
  77. <!-- </el-dialog> -->
  78. <!-- 添加图片 -->
  79. <el-dialog
  80. v-if="showPicArticleFlag"
  81. :visible.sync="showPicArticleFlag"
  82. :show-close="true"
  83. :close-on-click-modal="true"
  84. :modal-append-to-body="true"
  85. :append-to-body="true"
  86. :lock-scroll="true"
  87. width="80%"
  88. class="practiceBox"
  89. >
  90. <CheckPic :data="data" />
  91. </el-dialog>
  92. </template>
  93. </ModuleBase>
  94. </template>
  95. <script>
  96. import ModuleMixin from '../../common/ModuleMixin';
  97. import SelectUpload from '@/views/book/courseware/create/components/common/SelectUpload.vue';
  98. import CheckArticle from './CheckArticle.vue';
  99. import CompareTime from './CompareTime.vue';
  100. import NewWord from './NewWord.vue';
  101. import Notes from './Notes.vue';
  102. import CheckPic from './CheckPic.vue';
  103. import { getArticleData } from '@/views/book/courseware/data/article';
  104. import {
  105. segSentences,
  106. BatchSegContent,
  107. getWordTime,
  108. prepareTranscribe,
  109. fileToBase64Text,
  110. getWordTimes,
  111. } from '@/api/article';
  112. const Base64 = require('js-base64').Base64;
  113. import cnchar from 'cnchar';
  114. export default {
  115. name: 'ArticlePage',
  116. components: {
  117. SelectUpload,
  118. CheckArticle,
  119. CompareTime,
  120. NewWord,
  121. Notes,
  122. CheckPic,
  123. },
  124. mixins: [ModuleMixin],
  125. data() {
  126. return {
  127. data: getArticleData(),
  128. showArticleFlag: false, // 校对文章
  129. showPicArticleFlag: false, // 添加图片
  130. toneList: [' ', 'ˉ', 'ˊ', 'ˇ', 'ˋ'],
  131. loading: false,
  132. isWordTime: false,
  133. compareType: '', // 校对类型
  134. compareShow: false,
  135. compareData: null,
  136. compareloading: false,
  137. editWordsFlag: false,
  138. editWordIndex: 0,
  139. multilingualText: '',
  140. };
  141. },
  142. watch: {
  143. 'data.content': 'handleMindMap',
  144. },
  145. created() {},
  146. methods: {
  147. // 解析输入内容
  148. handleChangeContent() {
  149. this.loading = true;
  150. this.data.detail = [];
  151. if (this.data.content.trim()) {
  152. let contentArr = this.data.content.split('\n');
  153. let textList = [];
  154. let detailItem = {
  155. paraIndex: 0,
  156. para: '',
  157. sentences: [],
  158. segList: [],
  159. seg_words: [],
  160. wordsList: [],
  161. timeList: [],
  162. isTitle: false,
  163. sentencesEn: [],
  164. paraAlign: 'left',
  165. remark: {
  166. chs: '',
  167. en: '',
  168. heightNumber: null,
  169. img_list: [],
  170. widthNumber: null,
  171. },
  172. sourceList: [],
  173. sourcePosition: 'after',
  174. heightNumber: null,
  175. widthNumber: null,
  176. };
  177. // 分段
  178. contentArr.forEach((item, index) => {
  179. if (item.trim()) {
  180. detailItem.para = item;
  181. detailItem.paraIndex = index;
  182. this.data.detail.push(JSON.parse(JSON.stringify(detailItem)));
  183. let str = Base64.encode(item);
  184. textList.push(str);
  185. }
  186. });
  187. // 分句
  188. let sentenceList = []; // 句子按段数组
  189. let data = {
  190. textList,
  191. };
  192. segSentences(data)
  193. .then((res) => {
  194. let result = res.data.result;
  195. sentenceList = JSON.parse(JSON.stringify(res.data.result));
  196. result.forEach((item, index) => {
  197. let sentenceListBase64 = [];
  198. this.data.detail[index].sentences = item;
  199. item.forEach((items) => {
  200. sentenceListBase64.push(Base64.encode(items));
  201. });
  202. // 分词
  203. BatchSegContent({ textList: sentenceListBase64 })
  204. .then((res) => {
  205. let list = res.data.result.list;
  206. this.data.detail[index].segList = list;
  207. this.setWordsList(list, index);
  208. if (index === result.length - 1) {
  209. this.handleSenWord();
  210. this.loading = false;
  211. }
  212. })
  213. .catch(() => {
  214. this.loading = false;
  215. });
  216. });
  217. })
  218. .catch(() => {
  219. this.loading = false;
  220. });
  221. }
  222. },
  223. // 处理句子和词的关系
  224. handleSenWord() {
  225. this.data.sentence_list_mp = [];
  226. this.data.detail.forEach((item) => {
  227. item.sentences.forEach((items, indexs) => {
  228. let word_list = [];
  229. item.segList[indexs].forEach((itemw) => {
  230. word_list.push({
  231. word: itemw,
  232. });
  233. });
  234. let obj = {
  235. sentence: items,
  236. word_list,
  237. };
  238. this.data.sentence_list_mp.push(obj);
  239. });
  240. });
  241. },
  242. setWordsList(list, paraIndex) {
  243. let wordsList = [];
  244. list.forEach((item, index) => {
  245. let sentArr = [];
  246. item.map((sItem) => {
  247. let toneStr = [];
  248. for (let i = 0; i < sItem.length; i++) {
  249. const pattern = /[\u4e00-\u9fa5]/;
  250. if (cnchar.isCnChar(sItem[i]) && !pattern.test(cnchar.spell(sItem[i], 'low', 'tone'))) {
  251. toneStr.push(this.toneList[cnchar.spellInfo(cnchar.spell(sItem[i], 'low', 'tone')).tone]);
  252. } else {
  253. toneStr.push(' ');
  254. }
  255. }
  256. let obj = {
  257. chs: sItem,
  258. pinyin: cnchar.spell(sItem, 'low', 'tone'),
  259. pinyin_up:
  260. cnchar.spell(sItem, 'low', 'tone').charAt(0).toUpperCase() + cnchar.spell(sItem, 'low', 'tone').slice(1),
  261. pinyin_tone: toneStr.join(' '),
  262. fontFamily: '楷体',
  263. textDecoration: '',
  264. fontWeight: '',
  265. border: '',
  266. color: '',
  267. matchWords: '',
  268. matchNotes: '',
  269. img: [],
  270. imgPosition: 'after',
  271. };
  272. sentArr.push(obj);
  273. });
  274. wordsList.push(sentArr);
  275. });
  276. this.data.detail[paraIndex].wordsList = wordsList;
  277. },
  278. uploadAudioSuccess(fileList) {
  279. if (fileList.length > 0) {
  280. const { file_name: name, file_url: temporary_url, file_id, media_duration } = fileList[0];
  281. this.data.mp3_list = [
  282. {
  283. name,
  284. media_duration,
  285. temporary_url,
  286. url: file_id,
  287. file_id,
  288. },
  289. ];
  290. this.data.file_id_list = [file_id];
  291. }
  292. },
  293. removeFile() {
  294. this.data.mp3_list = [];
  295. this.data.file_id_list = [];
  296. },
  297. // 校对文章
  298. checkArticle() {
  299. let verseList = [];
  300. this.data.detail.forEach((item) => {
  301. verseList = verseList.concat(item.sentences);
  302. });
  303. if (verseList.length > 0) {
  304. this.showArticleFlag = true;
  305. } else {
  306. this.$message.warning('请先生成分词');
  307. }
  308. },
  309. saveWord(saveArr) {
  310. saveArr.forEach((item, index) => {
  311. let para = '';
  312. let sentenceStr = [];
  313. let sentences = [];
  314. let wordsList = [];
  315. item.forEach((items) => {
  316. para += items.join('');
  317. sentenceStr.push(items.join('&nbsp;&nbsp;'));
  318. sentences.push(items.join(''));
  319. let sentArr = [];
  320. items.forEach((sItem) => {
  321. let toneStr = [];
  322. for (let i = 0; i < sItem.length; i++) {
  323. const pattern = /[\u4e00-\u9fa5]/;
  324. if (cnchar.isCnChar(sItem[i]) && !pattern.test(cnchar.spell(sItem[i], 'low', 'tone'))) {
  325. toneStr.push(this.toneList[cnchar.spellInfo(cnchar.spell(sItem[i], 'low', 'tone')).tone]);
  326. } else {
  327. toneStr.push(' ');
  328. }
  329. }
  330. let obj = {
  331. chs: sItem,
  332. pinyin: cnchar.spell(sItem, 'low', 'tone'),
  333. pinyin_up:
  334. cnchar.spell(sItem, 'low', 'tone').charAt(0).toUpperCase() +
  335. cnchar.spell(sItem, 'low', 'tone').slice(1),
  336. pinyin_tone: toneStr.join(' '),
  337. fontFamily: '楷体',
  338. textDecoration: '',
  339. fontWeight: '',
  340. border: '',
  341. color: '',
  342. matchWords: '',
  343. matchNotes: '',
  344. img: [],
  345. imgPosition: 'after',
  346. };
  347. sentArr.push(obj);
  348. });
  349. wordsList.push(sentArr);
  350. });
  351. if (this.data.detail[index]) {
  352. this.data.detail[index].segList = item;
  353. this.data.detail[index].para = para;
  354. this.data.detail[index].sentenceStr = sentenceStr;
  355. this.data.detail[index].sentences = sentences;
  356. this.data.detail[index].wordsList = wordsList;
  357. } else {
  358. let obj = {
  359. paraIndex: index,
  360. para,
  361. sentences,
  362. segList: item,
  363. seg_words: [],
  364. wordsList,
  365. timeList: [],
  366. isTitle: false,
  367. sentencesEn: [],
  368. sentenceStr,
  369. paraAlign: 'left',
  370. remark: {
  371. chs: '',
  372. en: '',
  373. heightNumber: null,
  374. img_list: [],
  375. widthNumber: null,
  376. },
  377. sourceList: [],
  378. sourcePosition: 'after',
  379. heightNumber: null,
  380. widthNumber: null,
  381. };
  382. this.data.detail.push(obj);
  383. }
  384. });
  385. this.$message.success('保存成功,请校对拼音');
  386. this.handleSenWord();
  387. },
  388. // 保存拼音
  389. savePinyin(paraIndex, sentenceIndex, wordIndex, pinyin) {
  390. if (this.data.pinyin_type === 'tone') {
  391. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].pinyin_tone = pinyin;
  392. } else if (wordIndex === 0) {
  393. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].pinyin_up = pinyin;
  394. } else {
  395. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].pinyin = pinyin;
  396. }
  397. },
  398. saveStyle(
  399. paraIndex,
  400. sentenceIndex,
  401. wordIndex,
  402. fontFamily,
  403. textDecoration,
  404. fontWeight,
  405. border,
  406. color,
  407. matchWords,
  408. matchNotes,
  409. img,
  410. imgPosition,
  411. ) {
  412. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].fontFamily = fontFamily;
  413. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].textDecoration = textDecoration;
  414. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].fontWeight = fontWeight;
  415. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].border = border;
  416. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].color = color;
  417. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].matchWords = matchWords;
  418. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].matchNotes = matchNotes;
  419. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].img = img;
  420. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].imgPosition = imgPosition;
  421. },
  422. // 保存校对
  423. saveCompare() {
  424. this.compareloading = false;
  425. this.data.wordTime = this.compareData;
  426. this.handleClose();
  427. // this.compareloading = true;
  428. // compareSenTenceTime({ matchList: JSON.stringify(this.compareData) })
  429. // .then((res) => {
  430. // this.compareloading = false;
  431. // this.data.wordTime = res.data.result;
  432. // })
  433. // .catch(() => {
  434. // this.compareloading = false;
  435. // });
  436. },
  437. // 校对时间
  438. compareTime(type) {
  439. this.compareType = type;
  440. this.compareData = JSON.parse(JSON.stringify(this.data.wordTime));
  441. this.compareShow = true;
  442. },
  443. handleClose() {
  444. this.compareShow = false;
  445. this.compareData = null;
  446. this.compareType = '';
  447. },
  448. // 校对每个字的时间
  449. changewordsResultList(index, item) {
  450. this.data.wordTime[index].wordsResultList = JSON.parse(JSON.stringify(item));
  451. },
  452. againWordTime() {
  453. this.isWordTime = false;
  454. this.data.wordTime = [];
  455. },
  456. createWordTimes() {
  457. let _this = this;
  458. let verseList = [];
  459. if (_this.data.mp3_list && _this.data.mp3_list.length > 0 && _this.data.mp3_list[0].file_id) {
  460. if (_this.data.content) {
  461. _this.data.detail.forEach((item) => {
  462. verseList = verseList.concat(item.sentences);
  463. });
  464. if (verseList.length > 0) {
  465. _this.isWordTime = true;
  466. let data = {
  467. audio_file_id: _this.data.mp3_list[0].file_id,
  468. text: _this.data.content,
  469. text_type: 'line_text_list',
  470. line_text_list: verseList,
  471. };
  472. getWordTimes(data).then((res) => {
  473. _this.data.wordTime = res.data.result;
  474. _this.isWordTime = false;
  475. });
  476. } else {
  477. this.$message.warning('请先生成分词');
  478. }
  479. }
  480. } else {
  481. _this.$message.warning('请先上传音频');
  482. _this.loading = false;
  483. }
  484. },
  485. createWordTime() {
  486. let _this = this;
  487. this.getfillLiu().then(() => {
  488. if (_this.data.taskId) {
  489. let verseList = [];
  490. _this.data.detail.forEach((item) => {
  491. verseList = verseList.concat(item.sentences);
  492. });
  493. if (verseList.length > 0) {
  494. _this.isWordTime = true;
  495. let data = {
  496. taskId: _this.data.taskId,
  497. verseList: JSON.stringify(verseList),
  498. matchType: 'chinese',
  499. language: 'ch',
  500. };
  501. getWordTime(data).then((res) => {
  502. _this.data.wordTime = res.data.result;
  503. _this.isWordTime = false;
  504. });
  505. }
  506. } else {
  507. _this.$message.warning('请先上传音频');
  508. _this.loading = false;
  509. }
  510. });
  511. },
  512. // 得到文件流
  513. getfillLiu() {
  514. this.loading = true;
  515. let _this = this;
  516. return new Promise(function (resolve, reject) {
  517. if (_this.data.mp3_list && _this.data.mp3_list.length > 0 && _this.data.mp3_list[0].file_id) {
  518. let id = _this.data.mp3_list[0].file_id;
  519. let data = {
  520. file_id: id,
  521. };
  522. fileToBase64Text(data).then((res) => {
  523. let taskIddata = {
  524. fileName: _this.data.mp3_list[0].name,
  525. speechBase64: res.base64_text,
  526. language: 'ch',
  527. };
  528. prepareTranscribe(taskIddata)
  529. .then((ress) => {
  530. _this.$set(_this.data, 'taskId', ress.data.taskId);
  531. _this.loading = false;
  532. resolve();
  533. })
  534. .catch(() => {
  535. _this.loading = false;
  536. });
  537. });
  538. } else {
  539. _this.$message.warning('请先上传音频');
  540. _this.loading = false;
  541. }
  542. });
  543. },
  544. sureNewWords(data) {
  545. this.data.new_word_list = data;
  546. },
  547. sureOtherNewWords(data) {
  548. this.data.other_word_list = data;
  549. },
  550. sureNotes(data) {
  551. this.data.notes_list = data;
  552. },
  553. handleMindMap() {
  554. // 思维导图数据
  555. let node_list = [];
  556. node_list.push({
  557. name: this.data.content,
  558. id: Math.random().toString(36).substring(2, 12),
  559. });
  560. this.data.mind_map.node_list = node_list;
  561. },
  562. handleMultilingual() {
  563. this.multilingualText = '';
  564. let flag = false;
  565. this.data.detail.forEach((item) => {
  566. if (item.para) {
  567. if (item.sentences && item.sentences.length > 0) {
  568. flag = true;
  569. }
  570. item.sentences.forEach((items) => {
  571. this.multilingualText += `<p>${items}<p>`;
  572. });
  573. } else {
  574. this.multilingualText += '<p>&nbsp;</p>';
  575. }
  576. // this.multilingualText += item.para ? '<p>' + item.para + '<p>' : '<p>&nbsp;</p>';
  577. });
  578. if (flag) {
  579. this.multilingualVisible = true;
  580. } else {
  581. this.$message.warning('请先生成分词');
  582. }
  583. },
  584. // 点击插入图片按钮
  585. picArticle() {
  586. let verseList = [];
  587. this.data.detail.forEach((item) => {
  588. verseList = verseList.concat(item.sentences);
  589. });
  590. if (verseList.length > 0) {
  591. this.showPicArticleFlag = true;
  592. } else {
  593. this.$message.warning('请先生成分词');
  594. }
  595. },
  596. },
  597. };
  598. </script>
  599. <style lang="scss" scoped>
  600. .article-wrapper {
  601. display: flex;
  602. flex-direction: column;
  603. row-gap: 16px;
  604. align-items: flex-start;
  605. }
  606. .upload-file {
  607. display: flex;
  608. column-gap: 12px;
  609. align-items: center;
  610. margin: 8px 0;
  611. .file-name {
  612. display: flex;
  613. column-gap: 14px;
  614. align-items: center;
  615. justify-content: space-between;
  616. max-width: 360px;
  617. padding: 8px 12px;
  618. font-size: 14px;
  619. color: #1d2129;
  620. background-color: #f7f8fa;
  621. span {
  622. display: flex;
  623. column-gap: 14px;
  624. align-items: center;
  625. }
  626. }
  627. .svg-icon {
  628. cursor: pointer;
  629. }
  630. }
  631. .btn-box {
  632. display: flex;
  633. flex-flow: wrap;
  634. gap: 16px;
  635. a {
  636. padding: 5px 16px;
  637. font-size: 14px;
  638. line-height: 22px;
  639. color: #4e5969;
  640. cursor: pointer;
  641. background: #f2f3f5;
  642. border-radius: 2px;
  643. }
  644. p {
  645. margin: 0;
  646. }
  647. }
  648. .tabs-box {
  649. display: flex;
  650. column-gap: 12px;
  651. margin: 12px 0;
  652. a {
  653. padding: 5px 16px;
  654. font-size: 14px;
  655. font-weight: 400;
  656. line-height: 22px; /* 157.143% */
  657. color: #4e5969;
  658. cursor: pointer;
  659. border-radius: 100px;
  660. &.active {
  661. color: #165dff;
  662. background: #f2f3f5;
  663. }
  664. }
  665. }
  666. </style>