Article.vue 22 KB

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