Article.vue 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453
  1. <template>
  2. <ModuleBase ref="base" :type="data.type">
  3. <template #content>
  4. <!-- eslint-disable max-len -->
  5. <div v-loading="loading" class="article-wrapper">
  6. <div class="table-rich-toolbar" v-if="articleAttrib">
  7. <el-select
  8. v-model="articleAttrib.font"
  9. placeholder="请选择"
  10. style="width: 130px"
  11. @change="handleChangeStyles"
  12. >
  13. <el-option v-for="{ value, label } in fontFamilyList" :key="value" :label="label" :value="value" />
  14. </el-select>
  15. <el-select v-model="articleAttrib.font_size" placeholder="请选择" style="width: 130px">
  16. <el-option
  17. v-for="(value, index) in 16"
  18. :key="index"
  19. :label="6 + value * 2 + 'pt'"
  20. :value="6 + value * 2 + 'pt'"
  21. />
  22. </el-select>
  23. <el-form :model="articleAttrib" inline>
  24. <el-form-item label="文字颜色">
  25. <el-color-picker v-model="articleAttrib.text_color" @change="handleChangeStyles" />
  26. </el-form-item>
  27. </el-form>
  28. <span :class="[data.other_attrib.isUnderline ? 'active' : '']" @click="setActiveTextStyle('underline')">
  29. <SvgIcon icon-class="underline" size="20" />
  30. </span>
  31. <span :class="[data.other_attrib.isBold ? 'active' : '']" @click="setActiveTextStyle('bold')">
  32. <SvgIcon icon-class="font-bold" size="20" />
  33. </span>
  34. <!-- <span
  35. :class="[data.other_attrib.isItalic ? 'active' : '']"
  36. @click="data.other_attrib.isItalic = !data.other_attrib.isItalic"
  37. >
  38. <SvgIcon icon-class="font-italic" size="20" />
  39. </span> -->
  40. <span
  41. :class="[data.other_attrib.isStrikethrough ? 'active' : '']"
  42. @click="setActiveTextStyle('line-through')"
  43. >
  44. <SvgIcon icon-class="strikethrough" size="20" />
  45. </span>
  46. <span :class="[data.other_attrib.border === 'dotted' ? 'active' : '']">
  47. <SvgIcon icon-class="borderDotted" title="下划虚线" size="16" @click="setActiveTextStyle('border')" />
  48. </span>
  49. <span :class="[articleAttrib.align === 'LEFT' ? 'active' : '']" @click="setActiveTextStyle('align', 'LEFT')">
  50. <SvgIcon icon-class="align-left" size="20" />
  51. </span>
  52. <span
  53. :class="[articleAttrib.align === 'MIDDLE' ? 'active' : '']"
  54. @click="setActiveTextStyle('align', 'MIDDLE')"
  55. >
  56. <SvgIcon icon-class="align-center" size="20" />
  57. </span>
  58. <span
  59. :class="[articleAttrib.align === 'RIGHT' ? 'active' : '']"
  60. @click="setActiveTextStyle('align', 'RIGHT')"
  61. >
  62. <SvgIcon icon-class="align-right" size="20" />
  63. </span>
  64. </div>
  65. <el-input v-model="data.content" placeholder="输入" type="textarea" />
  66. <div class="btn-box">
  67. <SelectUpload label="课文音频" type="audio" @uploadSuccess="uploadAudioSuccess" />
  68. <el-button :loading="autoLoading" @click="handleAutoAudio">自动生成音频</el-button>
  69. </div>
  70. <div v-if="data.mp3_list.length > 0" class="upload-file">
  71. <div class="file-name">
  72. <span>
  73. <SvgIcon icon-class="note" size="12" />
  74. <span>{{ data.mp3_list[0].name }}</span>
  75. </span>
  76. </div>
  77. <SvgIcon icon-class="delete-black" size="12" @click="removeFile" />
  78. <ResourcesOperate :data="data.mp3_list[0]" />
  79. </div>
  80. <span v-if="data.content" class="tips">说明:需先点击“生成分词”按钮后,再进行文章校对或生成字幕节点</span>
  81. <div v-if="data.content" class="btn-box">
  82. <a @click="handleChangeContent">生成分词</a>
  83. <a @click="checkArticle">文章校对</a>
  84. <a @click="picArticle">添加图片</a>
  85. <a @click="editWordsFlag = !editWordsFlag">编辑生词短语注释</a>
  86. <template v-if="data.wordTime && data.wordTime.length > 0">
  87. <!-- <span>已有字幕时间节点</span> -->
  88. <a type="text" @click="againWordTime">重新生成字幕时间</a>
  89. <a size="medium" @click="openCheckSubtitles('句子')">校对句子字幕时间</a>
  90. <!-- <a size="medium" @click="compareTime('句子')">校对句子字幕时间</a> -->
  91. <a size="medium" @click="compareTime('文字')">校对文字字幕时间</a>
  92. </template>
  93. <template v-else>
  94. <a v-if="!isWordTime" size="medium" @click="createWordTimes">自动生成字幕节点</a>
  95. <p v-else>字幕节点生成中...请等待</p>
  96. </template>
  97. <el-button @click="handleMultilingual">课文多语言</el-button>
  98. <MultilingualFill
  99. :visible.sync="multilingualVisible"
  100. :text="multilingualText"
  101. :translations="data.multilingual"
  102. @SubmitTranslation="handleMultilingualTranslation"
  103. />
  104. </div>
  105. </div>
  106. <el-dialog
  107. v-if="dialogFlag"
  108. :visible.sync="dialogFlag"
  109. :show-close="false"
  110. :close-on-click-modal="false"
  111. :modal-append-to-body="false"
  112. :modal="false"
  113. width="250px"
  114. class="article-checkpinyin-dialog"
  115. >
  116. <div class="check-box">
  117. <div class="content">
  118. <div class="words-box">
  119. <span class="pinyin">
  120. {{ itemActive.pinyin }}
  121. </span>
  122. <span class="words">
  123. {{ itemActive.chs }}
  124. </span>
  125. </div>
  126. </div>
  127. <!-- <el-input v-model="checkPinyinInput" type="text" class="checkPinyinInput" /> -->
  128. <el-select
  129. v-model="checkPinyinInput"
  130. placeholder="请选择"
  131. filterable
  132. allow-create
  133. default-first-option
  134. class="checkPinyinInput"
  135. >
  136. <el-option v-for="item in pinyinList" :key="item.pinyin" :value="item.pinyin.replace(/,/g, '')">
  137. <span style="float: left">{{ item.pinyin.replace(/,/g, '') }}</span>
  138. <span style="float: right; font-size: 13px; color: #8492a6">{{
  139. item.storage_type === 1 ? '机构库' : item.storage_type === 2 ? '全域库' : '个人库'
  140. }}</span>
  141. </el-option>
  142. </el-select>
  143. <p class="tips">
  144. 一到四声分别用数字1-4表示。拼音间用空格隔开,儿化音用_代替空格,如“骨朵儿”输入“gu1 duo3_er”。
  145. </p>
  146. <div class="btn-box">
  147. <el-button type="info" size="small" @click="cancleDialog">取消</el-button>
  148. <el-button type="primary" size="small" @click="surePinyin">保存</el-button>
  149. </div>
  150. </div>
  151. </el-dialog>
  152. <el-dialog
  153. v-if="showArticleFlag"
  154. :visible.sync="showArticleFlag"
  155. :show-close="true"
  156. :close-on-click-modal="true"
  157. :modal-append-to-body="true"
  158. :append-to-body="true"
  159. :lock-scroll="true"
  160. width="80%"
  161. class="practiceBox"
  162. >
  163. <CheckArticle
  164. ref="CheckArticle"
  165. :data="data"
  166. @saveWord="saveWord"
  167. @savePinyin="savePinyin"
  168. @saveStyle="saveStyle"
  169. />
  170. </el-dialog>
  171. <el-dialog title="校对字幕时间" :visible.sync="compareShow" width="50%" :before-close="handleClose" top="0">
  172. <CompareTime
  173. :data="compareData"
  174. :type="compareType"
  175. :changewords-result-list="changewordsResultList"
  176. :open-check-subtitles="openCheckSubtitles"
  177. />
  178. <span slot="footer" class="dialog-footer">
  179. <el-button @click="handleClose">取 消</el-button>
  180. <el-button :loading="compareloading" type="primary" @click="saveCompare">确 定</el-button>
  181. </span>
  182. </el-dialog>
  183. <!-- <el-dialog title="" :visible.sync="editWordsFlag" width="80%" :close-on-click-modal="true" top="0"> -->
  184. <template v-if="editWordsFlag">
  185. <div class="tabs-box">
  186. <a :class="[editWordIndex === 0 ? 'active' : '']" @click="editWordIndex = 0">生词</a>
  187. <a :class="[editWordIndex === 2 ? 'active' : '']" @click="editWordIndex = 2">其他词汇</a>
  188. <a :class="[editWordIndex === 1 ? 'active' : '']" @click="editWordIndex = 1">注释</a>
  189. </div>
  190. <NewWord
  191. v-if="editWordIndex === 0"
  192. key="new_word"
  193. :data-new-word="data.new_word_list"
  194. :unified-attrib="data.unified_attrib ? data.unified_attrib : null"
  195. @sureNewWords="sureNewWords"
  196. />
  197. <Notes
  198. v-if="editWordIndex === 1"
  199. key="notes"
  200. :data-notes="data.notes_list"
  201. :unified-attrib="data.unified_attrib ? data.unified_attrib : null"
  202. @sureNotes="sureNotes"
  203. />
  204. <NewWord
  205. v-if="editWordIndex === 2"
  206. :data-new-word="data.other_word_list"
  207. :unified-attrib="data.unified_attrib ? data.unified_attrib : null"
  208. @sureNewWords="sureOtherNewWords"
  209. />
  210. </template>
  211. <template v-if="isEnable(data.property.view_pinyin)">
  212. <el-divider content-position="left"
  213. >拼音效果<el-button
  214. v-show="isEnable(data.property.view_pinyin)"
  215. type="text"
  216. icon="el-icon-refresh"
  217. title="刷新"
  218. class="refresh-pinyin-btn"
  219. @click.native="handleChangeContent"
  220. /></el-divider>
  221. <div v-for="(item, index) in data.detail" :key="index" class="text">
  222. <template v-for="(witem, windex) in item.wordsList">
  223. <div
  224. v-for="(wItem, wIndex) in witem"
  225. :key="windex + '-' + wIndex"
  226. class="text-item"
  227. :style="{
  228. textAlign: windex === 0 && wIndex === 0 ? 'left' : '',
  229. }"
  230. @click="selectItem(wItem)"
  231. >
  232. <span class="pinyin">{{
  233. windex === 0 &&
  234. wIndex === 0 &&
  235. data.property.is_first_sentence_first_hz_pinyin_first_char_upper_case === 'true'
  236. ? wItem.pinyin_up
  237. : wItem.pinyin
  238. }}</span>
  239. <span
  240. class="word"
  241. :style="{
  242. fontFamily: wItem.fontFamily,
  243. textDecoration: wItem.textDecoration,
  244. borderBottom: wItem.border === 'dotted' ? '1px dotted' : '',
  245. fontWeight: wItem.fontWeight,
  246. color: wItem.color,
  247. }"
  248. >{{ wItem.chs }}</span
  249. >
  250. </div>
  251. </template>
  252. </div>
  253. </template>
  254. <!-- </el-dialog> -->
  255. <!-- 添加图片 -->
  256. <el-dialog
  257. v-if="showPicArticleFlag"
  258. :visible.sync="showPicArticleFlag"
  259. :show-close="true"
  260. :close-on-click-modal="true"
  261. :modal-append-to-body="true"
  262. :append-to-body="true"
  263. :lock-scroll="true"
  264. width="80%"
  265. class="practiceBox"
  266. >
  267. <CheckPic :data="data" />
  268. </el-dialog>
  269. <CheckSubtitles
  270. v-if="visible"
  271. :visible.sync="visible"
  272. :audio-id="data.mp3_list[0] && data.mp3_list[0].file_id ? data.mp3_list[0].file_id : ''"
  273. :option-list="subtitleList"
  274. @saveSubtitles="saveSubtitles"
  275. />
  276. </template>
  277. </ModuleBase>
  278. </template>
  279. <script>
  280. import ModuleMixin from '../../common/ModuleMixin';
  281. import SelectUpload from '@/views/book/courseware/create/components/common/SelectUpload.vue';
  282. import CheckArticle from './CheckArticle.vue';
  283. import CompareTime from './CompareTime.vue';
  284. import NewWord from './NewWord.vue';
  285. import Notes from './Notes.vue';
  286. import CheckPic from './CheckPic.vue';
  287. import CheckSubtitles from '@/views/book/courseware/create/components/question/voice_matrix/CheckSubtitles.vue';
  288. import ResourcesOperate from '../../common/ResourcesOperate.vue';
  289. import { getArticleData } from '@/views/book/courseware/data/article';
  290. import { fontFamilyList } from '@/views/book/courseware/data/table';
  291. import { TextToAudioFile } from '@/api/app';
  292. import { isEnable } from '@/views/book/courseware/data/common';
  293. import {
  294. segSentences,
  295. BatchSegContent,
  296. getWordTime,
  297. prepareTranscribe,
  298. fileToBase64Text,
  299. getWordTimes,
  300. } from '@/api/article';
  301. const Base64 = require('js-base64').Base64;
  302. import cnchar from 'cnchar';
  303. import { toolGetWordPinyinCorrectionList } from '@/api/pinyinCorrection';
  304. export default {
  305. name: 'ArticlePage',
  306. components: {
  307. SelectUpload,
  308. CheckArticle,
  309. CompareTime,
  310. NewWord,
  311. Notes,
  312. CheckPic,
  313. CheckSubtitles,
  314. ResourcesOperate,
  315. },
  316. mixins: [ModuleMixin],
  317. data() {
  318. return {
  319. fontFamilyList,
  320. isEnable,
  321. data: getArticleData(),
  322. showArticleFlag: false, // 校对文章
  323. showPicArticleFlag: false, // 添加图片
  324. toneList: [' ', 'ˉ', 'ˊ', 'ˇ', 'ˋ'],
  325. loading: false,
  326. isWordTime: false,
  327. compareType: '', // 校对类型
  328. compareIndex: null, // 校对句子索引
  329. compareShow: false,
  330. compareData: null,
  331. compareloading: false,
  332. editWordsFlag: false,
  333. editWordIndex: 0,
  334. multilingualText: '',
  335. autoLoading: false,
  336. visible: false,
  337. subtitleList: [],
  338. itemActive: null,
  339. dialogFlag: false,
  340. checkPinyinInput: '',
  341. oldInput: '',
  342. tableData: [
  343. ['ā', 'á', 'ǎ', 'à', 'a'],
  344. ['ō', 'ó', 'ǒ', 'ò', 'o'],
  345. ['ē', 'é', 'ě', 'è', 'e'],
  346. ['ī', 'í', 'ǐ', 'ì', 'i'],
  347. ['ū', 'ú', 'ǔ', 'ù', 'u'],
  348. ['ǖ', 'ǘ', 'ǚ', 'ǜ', 'ü'],
  349. ['Ā', 'Á', 'Â', 'À', 'A'],
  350. ['Ō', 'Ó', 'Ô', 'Ò', 'O'],
  351. ['Ē', 'É', 'Ê', 'È', 'E'],
  352. ['Ī', 'Í', 'Î', 'Ì', 'I'],
  353. ['Ū', 'Ú', 'Û', 'Ù', 'U'],
  354. ['n', 'ń', 'ň', 'ǹ', 'n'],
  355. ['m̄', 'ḿ', 'm', 'm̀', 'm'],
  356. ],
  357. pinyinList: [], // 拼音校正列表
  358. articleAttrib: null,
  359. };
  360. },
  361. watch: {
  362. 'data.content': 'handleMindMap',
  363. 'data.unified_attrib': {
  364. handler(val) {
  365. if (val) {
  366. this.articleAttrib = JSON.parse(JSON.stringify(val));
  367. this.handleChangeStyles();
  368. }
  369. },
  370. deep: true,
  371. immediate: true,
  372. },
  373. // 'data.unified_attrib.font': {
  374. // handler(val) {
  375. // if (val) {
  376. // this.handleChangeStyles();
  377. // }
  378. // },
  379. // deep: true,
  380. // immediate: true,
  381. // },
  382. // 'data.unified_attrib.text_color': {
  383. // handler(val) {
  384. // if (val) {
  385. // this.handleChangeStyles();
  386. // }
  387. // },
  388. // deep: true,
  389. // immediate: true,
  390. // },
  391. // 'data.unified_attrib.align': {
  392. // handler(val) {
  393. // if (val) {
  394. // this.handleChangeStyles();
  395. // }
  396. // },
  397. // deep: true,
  398. // immediate: true,
  399. // },
  400. },
  401. created() {},
  402. methods: {
  403. // 全局样式变化
  404. handleChangeStyles() {
  405. if (this.articleAttrib.font !== this.data.other_attrib.oldFont) {
  406. this.data.other_attrib.oldFont = this.articleAttrib.font;
  407. this.data.detail.forEach((item) => {
  408. item.wordsList.forEach((items) => {
  409. items.forEach((itemss) => {
  410. itemss.fontFamily = this.articleAttrib.font;
  411. });
  412. });
  413. });
  414. } else if (this.articleAttrib.text_color !== this.data.other_attrib.oldColor) {
  415. this.data.other_attrib.oldColor = this.articleAttrib.text_color;
  416. this.data.detail.forEach((item) => {
  417. item.wordsList.forEach((items) => {
  418. items.forEach((itemss) => {
  419. itemss.color = this.articleAttrib.text_color;
  420. });
  421. });
  422. });
  423. } else if (this.articleAttrib.align !== this.data.other_attrib.oldAlign) {
  424. this.data.other_attrib.oldAlign = this.articleAttrib.align;
  425. this.data.detail.forEach((item) => {
  426. item.paraAlign =
  427. this.articleAttrib.align === 'RIGHT' ? 'right' : this.articleAttrib.align === 'MIDDLE' ? 'center' : 'left';
  428. });
  429. }
  430. },
  431. // 解析输入内容
  432. handleChangeContent() {
  433. this.loading = true;
  434. this.data.detail = [];
  435. if (this.data.content.trim()) {
  436. let contentArr = this.data.content.split('\n');
  437. let textList = [];
  438. let detailItem = {
  439. paraIndex: 0,
  440. para: '',
  441. sentences: [],
  442. segList: [],
  443. seg_words: [],
  444. wordsList: [],
  445. timeList: [],
  446. isTitle: false,
  447. sentencesEn: [],
  448. paraAlign: this.articleAttrib
  449. ? this.articleAttrib.align === 'RIGHT'
  450. ? 'right'
  451. : this.articleAttrib.align === 'MIDDLE'
  452. ? 'center'
  453. : 'left'
  454. : 'left',
  455. remark: {
  456. chs: '',
  457. en: '',
  458. heightNumber: null,
  459. img_list: [],
  460. widthNumber: null,
  461. chsBg: '#988ed6',
  462. enBg: '#fff',
  463. },
  464. sourceList: [],
  465. sourcePosition: 'after',
  466. heightNumber: null,
  467. widthNumber: null,
  468. };
  469. // 分段
  470. contentArr.forEach((item, index) => {
  471. if (item.trim()) {
  472. detailItem.para = item;
  473. detailItem.paraIndex = index;
  474. this.data.detail.push(JSON.parse(JSON.stringify(detailItem)));
  475. let str = Base64.encode(item);
  476. textList.push(str);
  477. }
  478. });
  479. BatchSegContent({
  480. text: this.data.content,
  481. is_build_pinyin: 'true',
  482. is_custom_fc: 'false',
  483. is_vocabulary_pinyin_lt: 'true',
  484. is_fill_punctuation_mark: 'true',
  485. })
  486. .then((res) => {
  487. this.loading = false;
  488. if (res.status === 1) {
  489. res.paragraph_list.forEach((item, index) => {
  490. let sentenceList = []; // 句子按段数组
  491. let segList = []; // 句子分词结果
  492. item.forEach((items) => {
  493. let sentence = items.reduce((acc, itemss) => `${acc + itemss.text}`, '');
  494. let seg = items.map((itemss) => itemss.text);
  495. sentenceList.push(sentence);
  496. segList.push(seg);
  497. });
  498. this.data.detail[index].sentences = sentenceList;
  499. this.data.detail[index].segList = segList;
  500. this.setWordsList(item, index);
  501. });
  502. this.handleSenWord();
  503. }
  504. })
  505. .catch(() => {
  506. this.loading = false;
  507. });
  508. // 分句
  509. // let sentenceList = []; // 句子按段数组
  510. // let data = {
  511. // textList,
  512. // };
  513. // segSentences(data)
  514. // .then((res) => {
  515. // let result = res.data.result;
  516. // sentenceList = JSON.parse(JSON.stringify(res.data.result));
  517. // result.forEach((item, index) => {
  518. // let sentenceListBase64 = [];
  519. // this.data.detail[index].sentences = item;
  520. // item.forEach((items) => {
  521. // sentenceListBase64.push(Base64.encode(items));
  522. // });
  523. // // 分词
  524. // BatchSegContent({ textList: sentenceListBase64 })
  525. // .then((res) => {
  526. // let list = res.data.result.list;
  527. // this.data.detail[index].segList = list;
  528. // this.setWordsList(list, index);
  529. // if (index === result.length - 1) {
  530. // this.handleSenWord();
  531. // this.loading = false;
  532. // }
  533. // })
  534. // .catch(() => {
  535. // this.loading = false;
  536. // });
  537. // });
  538. // })
  539. // .catch(() => {
  540. // this.loading = false;
  541. // });
  542. }
  543. },
  544. // 处理句子和词的关系
  545. handleSenWord() {
  546. this.data.sentence_list_mp = [];
  547. this.data.detail.forEach((item) => {
  548. item.sentences.forEach((items, indexs) => {
  549. let word_list = [];
  550. item.segList[indexs].forEach((itemw) => {
  551. word_list.push({
  552. word: itemw,
  553. });
  554. });
  555. let obj = {
  556. sentence: items,
  557. word_list,
  558. };
  559. this.data.sentence_list_mp.push(obj);
  560. });
  561. });
  562. },
  563. setWordsList(list, paraIndex) {
  564. let wordsList = [];
  565. list.forEach((item, index) => {
  566. let sentArr = [];
  567. item.map((sItem) => {
  568. // let toneStr = [];
  569. // for (let i = 0; i < sItem.length; i++) {
  570. // const pattern = /[\u4e00-\u9fa5]/;
  571. // if (cnchar.isCnChar(sItem[i]) && !pattern.test(cnchar.spell(sItem[i], 'low', 'tone'))) {
  572. // toneStr.push(this.toneList[cnchar.spellInfo(cnchar.spell(sItem[i], 'low', 'tone')).tone]);
  573. // } else {
  574. // toneStr.push(' ');
  575. // }
  576. // }
  577. let obj = {
  578. chs: sItem.text,
  579. pinyin: sItem.pinyin,
  580. pinyin_up: sItem.pinyin_up,
  581. pinyin_tone: sItem.pinyin_tone,
  582. fontFamily: this.articleAttrib ? this.articleAttrib.font : '楷体',
  583. textDecoration: this.data.other_attrib
  584. ? this.data.other_attrib.isUnderline
  585. ? this.data.other_attrib.isUnderline
  586. : this.data.other_attrib.isStrikethrough
  587. ? this.data.other_attrib.isStrikethrough
  588. : ''
  589. : '',
  590. fontWeight: this.data.other_attrib ? this.data.other_attrib.isBold : '',
  591. border: this.data.other_attrib ? this.data.other_attrib.border : '',
  592. color: this.articleAttrib ? this.articleAttrib.text_color : '',
  593. matchWords: '',
  594. matchNotes: '',
  595. notesColor: '',
  596. img: [],
  597. imgPosition: 'after',
  598. };
  599. sentArr.push(obj);
  600. });
  601. wordsList.push(sentArr);
  602. });
  603. this.data.detail[paraIndex].wordsList = wordsList;
  604. },
  605. uploadAudioSuccess(fileList) {
  606. if (fileList.length > 0) {
  607. const { file_name: name, file_url: temporary_url, file_id, media_duration } = fileList[0];
  608. this.data.mp3_list = [
  609. {
  610. name,
  611. media_duration,
  612. temporary_url,
  613. url: file_id,
  614. file_id,
  615. },
  616. ];
  617. this.data.file_id_list = [file_id];
  618. }
  619. },
  620. removeFile() {
  621. this.$confirm('是否删除当前文件?', '提示', {
  622. confirmButtonText: '确定',
  623. cancelButtonText: '取消',
  624. type: 'warning',
  625. })
  626. .then(() => {
  627. this.data.mp3_list = [];
  628. this.data.file_id_list = [];
  629. })
  630. .catch(() => {});
  631. },
  632. // 校对文章
  633. checkArticle() {
  634. let verseList = [];
  635. this.data.detail.forEach((item) => {
  636. verseList = verseList.concat(item.sentences);
  637. });
  638. if (verseList.length > 0) {
  639. this.showArticleFlag = true;
  640. } else {
  641. this.$message.warning('请先生成分词');
  642. }
  643. },
  644. saveWord(saveArr) {
  645. BatchSegContent({
  646. text: this.data.content,
  647. is_build_pinyin: 'true',
  648. is_custom_fc: 'true',
  649. is_vocabulary_pinyin_lt: 'true',
  650. is_fill_punctuation_mark: 'true',
  651. fc_paragraph_list: saveArr,
  652. }).then((res) => {
  653. if (res.status === 1) {
  654. res.paragraph_list.forEach((item, index) => {
  655. let sentenceList = []; // 句子按段数组
  656. let segList = []; // 句子分词结果
  657. let sentenceStr = [];
  658. let para = '';
  659. let wordsList = [];
  660. item.forEach((items) => {
  661. let sentence = items.reduce((acc, itemss) => `${acc + itemss.text}`, '');
  662. let sentenceS = items.reduce((acc, itemss) => `${acc + itemss.text}&nbsp;&nbsp;`, '');
  663. let seg = items.map((itemss) => itemss.text);
  664. para += items.map((itemss) => itemss.text);
  665. sentenceList.push(sentence);
  666. sentenceStr.push(sentenceS);
  667. segList.push(seg);
  668. let sentArr = [];
  669. items.forEach((sItem) => {
  670. let obj = {
  671. chs: sItem.text,
  672. pinyin: sItem.pinyin,
  673. pinyin_up: sItem.pinyin_up,
  674. pinyin_tone: sItem.pinyin_tone,
  675. fontFamily: this.articleAttrib ? this.articleAttrib.font : '楷体',
  676. textDecoration: this.data.other_attrib
  677. ? this.data.other_attrib.isUnderline
  678. ? this.data.other_attrib.isUnderline
  679. : this.data.other_attrib.isStrikethrough
  680. ? this.data.other_attrib.isStrikethrough
  681. : ''
  682. : '',
  683. fontWeight: this.data.other_attrib ? this.data.other_attrib.isBold : '',
  684. border: this.data.other_attrib ? this.data.other_attrib.border : '',
  685. color: this.articleAttrib ? this.articleAttrib.text_color : '',
  686. matchWords: '',
  687. matchNotes: '',
  688. notesColor: '',
  689. img: [],
  690. imgPosition: 'after',
  691. };
  692. sentArr.push(obj);
  693. });
  694. wordsList.push(sentArr);
  695. });
  696. if (this.data.detail[index]) {
  697. this.data.detail[index].segList = segList;
  698. this.data.detail[index].para = para;
  699. this.data.detail[index].sentenceStr = sentenceStr;
  700. this.data.detail[index].sentences = sentenceList;
  701. this.data.detail[index].wordsList = wordsList;
  702. } else {
  703. let obj = {
  704. paraIndex: index,
  705. para,
  706. sentences: sentenceList,
  707. segList: item,
  708. seg_words: [],
  709. wordsList,
  710. timeList: [],
  711. isTitle: false,
  712. sentencesEn: [],
  713. sentenceStr,
  714. paraAlign: this.articleAttrib
  715. ? this.articleAttrib.align === 'RIGHT'
  716. ? 'right'
  717. : this.articleAttrib.align === 'MIDDLE'
  718. ? 'center'
  719. : 'left'
  720. : 'left',
  721. remark: {
  722. chs: '',
  723. en: '',
  724. heightNumber: null,
  725. img_list: [],
  726. widthNumber: null,
  727. chsBg: '#988ed6',
  728. enBg: '#fff',
  729. },
  730. sourceList: [],
  731. sourcePosition: 'after',
  732. heightNumber: null,
  733. widthNumber: null,
  734. };
  735. this.data.detail.push(obj);
  736. }
  737. });
  738. this.$refs.CheckArticle.refreshData();
  739. }
  740. });
  741. this.$message.success('保存成功,请校对拼音');
  742. this.handleSenWord();
  743. },
  744. // 保存拼音
  745. savePinyin(paraIndex, sentenceIndex, wordIndex, pinyin) {
  746. if (this.data.pinyin_type === 'tone') {
  747. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].pinyin_tone = pinyin;
  748. } else if (wordIndex === 0) {
  749. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].pinyin_up = pinyin;
  750. } else {
  751. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].pinyin = pinyin;
  752. }
  753. },
  754. saveStyle(
  755. paraIndex,
  756. sentenceIndex,
  757. wordIndex,
  758. fontFamily,
  759. textDecoration,
  760. fontWeight,
  761. border,
  762. color,
  763. matchWords,
  764. matchNotes,
  765. notesColor,
  766. img,
  767. imgPosition,
  768. ) {
  769. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].fontFamily = fontFamily;
  770. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].textDecoration = textDecoration;
  771. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].fontWeight = fontWeight;
  772. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].border = border;
  773. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].color = color;
  774. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].matchWords = matchWords;
  775. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].matchNotes = matchNotes;
  776. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].notesColor = notesColor;
  777. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].img = img;
  778. this.data.detail[paraIndex].wordsList[sentenceIndex][wordIndex].imgPosition = imgPosition;
  779. },
  780. // 保存校对
  781. saveCompare() {
  782. this.compareloading = false;
  783. this.data.wordTime = this.compareData;
  784. this.handleClose();
  785. // this.compareloading = true;
  786. // compareSenTenceTime({ matchList: JSON.stringify(this.compareData) })
  787. // .then((res) => {
  788. // this.compareloading = false;
  789. // this.data.wordTime = res.data.result;
  790. // })
  791. // .catch(() => {
  792. // this.compareloading = false;
  793. // });
  794. },
  795. // 校对时间
  796. compareTime(type) {
  797. this.compareType = type;
  798. this.compareData = JSON.parse(JSON.stringify(this.data.wordTime));
  799. this.compareShow = true;
  800. },
  801. handleClose() {
  802. this.compareShow = false;
  803. this.compareData = null;
  804. this.compareType = '';
  805. },
  806. // 校对每个字的时间
  807. changewordsResultList(index, item) {
  808. this.data.wordTime[index].wordsResultList = JSON.parse(JSON.stringify(item));
  809. },
  810. againWordTime() {
  811. this.isWordTime = false;
  812. this.data.wordTime = [];
  813. },
  814. createWordTimes() {
  815. let _this = this;
  816. let verseList = [];
  817. if (_this.data.mp3_list && _this.data.mp3_list.length > 0 && _this.data.mp3_list[0].file_id) {
  818. if (_this.data.content) {
  819. _this.data.detail.forEach((item) => {
  820. verseList = verseList.concat(item.sentences);
  821. });
  822. if (verseList.length > 0) {
  823. _this.isWordTime = true;
  824. let data = {
  825. audio_file_id: _this.data.mp3_list[0].file_id,
  826. text: _this.data.content,
  827. text_type: 'line_text_list',
  828. line_text_list: verseList,
  829. };
  830. getWordTimes(data).then((res) => {
  831. _this.data.wordTime = res.data.result;
  832. _this.isWordTime = false;
  833. });
  834. } else {
  835. this.$message.warning('请先生成分词');
  836. }
  837. }
  838. } else {
  839. _this.$message.warning('请先上传音频');
  840. _this.loading = false;
  841. }
  842. },
  843. createWordTime() {
  844. let _this = this;
  845. this.getfillLiu().then(() => {
  846. if (_this.data.taskId) {
  847. let verseList = [];
  848. _this.data.detail.forEach((item) => {
  849. verseList = verseList.concat(item.sentences);
  850. });
  851. if (verseList.length > 0) {
  852. _this.isWordTime = true;
  853. let data = {
  854. taskId: _this.data.taskId,
  855. verseList: JSON.stringify(verseList),
  856. matchType: 'chinese',
  857. language: 'ch',
  858. };
  859. getWordTime(data).then((res) => {
  860. _this.data.wordTime = res.data.result;
  861. _this.isWordTime = false;
  862. });
  863. }
  864. } else {
  865. _this.$message.warning('请先上传音频');
  866. _this.loading = false;
  867. }
  868. });
  869. },
  870. // 得到文件流
  871. getfillLiu() {
  872. this.loading = true;
  873. let _this = this;
  874. return new Promise(function (resolve, reject) {
  875. if (_this.data.mp3_list && _this.data.mp3_list.length > 0 && _this.data.mp3_list[0].file_id) {
  876. let id = _this.data.mp3_list[0].file_id;
  877. let data = {
  878. file_id: id,
  879. };
  880. fileToBase64Text(data).then((res) => {
  881. let taskIddata = {
  882. fileName: _this.data.mp3_list[0].name,
  883. speechBase64: res.base64_text,
  884. language: 'ch',
  885. };
  886. prepareTranscribe(taskIddata)
  887. .then((ress) => {
  888. _this.$set(_this.data, 'taskId', ress.data.taskId);
  889. _this.loading = false;
  890. resolve();
  891. })
  892. .catch(() => {
  893. _this.loading = false;
  894. });
  895. });
  896. } else {
  897. _this.$message.warning('请先上传音频');
  898. _this.loading = false;
  899. }
  900. });
  901. },
  902. sureNewWords(data) {
  903. this.data.new_word_list = data;
  904. },
  905. sureOtherNewWords(data) {
  906. this.data.other_word_list = data;
  907. },
  908. sureNotes(data) {
  909. this.data.notes_list = data;
  910. },
  911. handleMindMap() {
  912. // 思维导图数据
  913. let node_list = [];
  914. node_list.push({
  915. name: this.data.content,
  916. id: Math.random().toString(36).substring(2, 12),
  917. });
  918. this.data.mind_map.node_list = node_list;
  919. },
  920. handleMultilingual() {
  921. this.multilingualText = '';
  922. let flag = false;
  923. this.data.detail.forEach((item) => {
  924. if (item.para) {
  925. if (item.sentences && item.sentences.length > 0) {
  926. flag = true;
  927. }
  928. item.sentences.forEach((items) => {
  929. this.multilingualText += `<p>${items}<p>`;
  930. });
  931. } else {
  932. this.multilingualText += '<p>&nbsp;</p>';
  933. }
  934. // this.multilingualText += item.para ? '<p>' + item.para + '<p>' : '<p>&nbsp;</p>';
  935. });
  936. if (flag) {
  937. this.multilingualVisible = true;
  938. } else {
  939. this.$message.warning('请先生成分词');
  940. }
  941. },
  942. // 点击插入图片按钮
  943. picArticle() {
  944. let verseList = [];
  945. this.data.detail.forEach((item) => {
  946. verseList = verseList.concat(item.sentences);
  947. });
  948. if (verseList.length > 0) {
  949. this.showPicArticleFlag = true;
  950. } else {
  951. this.$message.warning('请先生成分词');
  952. }
  953. },
  954. // 自动生成音频
  955. handleAutoAudio() {
  956. this.autoLoading = true;
  957. TextToAudioFile({
  958. text: this.data.content,
  959. voice_type: this.data.property.voice_type,
  960. emotion: this.data.property.emotion,
  961. speed_ratio: this.data.property.speed_ratio,
  962. })
  963. .then(({ status, file_id, file_url }) => {
  964. this.autoLoading = false;
  965. if (status === 1) {
  966. this.data.mp3_list = [
  967. {
  968. name: '自动生成课文音频.mp3',
  969. media_duration: 0,
  970. temporary_url: file_url,
  971. url: file_id,
  972. file_id,
  973. },
  974. ];
  975. this.data.file_id_list = [file_id];
  976. }
  977. })
  978. .catch(() => {
  979. this.autoLoading = false;
  980. });
  981. },
  982. /**
  983. * 打开校对字幕
  984. */
  985. openCheckSubtitles(type, index) {
  986. this.compareType = type;
  987. // this.compareData = JSON.parse(JSON.stringify(this.data.wordTime));
  988. // this.compareShow = true;
  989. if (this.data.mp3_list.length === 0) {
  990. return this.$message.warning('请先上传音频文件');
  991. }
  992. this.subtitleList = [];
  993. if (this.compareType === '句子') {
  994. this.data.wordTime.forEach((item, index) => {
  995. let obj = {
  996. content: item.onebest,
  997. lrc_data: {
  998. begin_time: item.bg,
  999. end_time: item.ed,
  1000. },
  1001. };
  1002. this.subtitleList.push(obj);
  1003. });
  1004. } else {
  1005. this.compareIndex = index;
  1006. this.data.wordTime[index].wordsResultList.forEach((item, index) => {
  1007. let obj = {
  1008. content: item.wordsName,
  1009. lrc_data: {
  1010. begin_time: item.wordBg,
  1011. end_time: item.wordEd,
  1012. },
  1013. };
  1014. this.subtitleList.push(obj);
  1015. });
  1016. }
  1017. this.visible = true;
  1018. },
  1019. /**
  1020. * 保存字幕
  1021. * @param {Array} dataList
  1022. */
  1023. saveSubtitles(dataList) {
  1024. if (this.compareType === '句子') {
  1025. this.data.wordTime.forEach((item, index) => {
  1026. item.bg = dataList[index] ? dataList[index].lrc_data.begin_time : 0;
  1027. item.ed = dataList[index] ? dataList[index].lrc_data.end_time : 0;
  1028. });
  1029. } else {
  1030. this.data.wordTime[this.compareIndex].wordsResultList.forEach((item, index) => {
  1031. item.wordBg = dataList[index] ? dataList[index].lrc_data.begin_time : 0;
  1032. item.wordEd = dataList[index] ? dataList[index].lrc_data.end_time : 0;
  1033. });
  1034. }
  1035. },
  1036. selectItem(item) {
  1037. this.itemActive = item;
  1038. this.pinyinList = [];
  1039. toolGetWordPinyinCorrectionList({
  1040. word: item.chs,
  1041. })
  1042. .then((res) => {
  1043. if (res.status === 1) {
  1044. this.pinyinList = res.pinyin_correction_list;
  1045. }
  1046. this.dialogFlag = true;
  1047. })
  1048. .catch(() => {
  1049. this.dialogFlag = true;
  1050. });
  1051. this.checkPinyinInput = '';
  1052. },
  1053. cancleDialog() {
  1054. this.itemActive = null;
  1055. this.checkPinyinInput = '';
  1056. this.oldInput = '';
  1057. this.dialogFlag = false;
  1058. },
  1059. surePinyin() {
  1060. this.oldInput = JSON.parse(JSON.stringify(this.checkPinyinInput.trim()));
  1061. this.handleReplaceTone(this.checkPinyinInput.trim());
  1062. },
  1063. handleReplaceTone(e) {
  1064. let _this = this;
  1065. _this.$nextTick(() => {
  1066. let value = e;
  1067. _this.resArr = [];
  1068. if (value) {
  1069. let valueArr = [];
  1070. value.replace(/\s+/g, ' ');
  1071. valueArr = value.split(' ');
  1072. // let reg = /\s+/g;
  1073. // valueArr = value.split(reg);
  1074. valueArr.forEach((item, index) => {
  1075. if (this.data.pinyin_type === 'tone') {
  1076. this.resArr.push([
  1077. {
  1078. con: this.toneList[Number(item)],
  1079. },
  1080. ]);
  1081. } else {
  1082. this.handleValue(item);
  1083. }
  1084. });
  1085. let str = '';
  1086. setTimeout(() => {
  1087. _this.resArr.forEach((item) => {
  1088. str += ' ';
  1089. item.forEach((sItem) => {
  1090. if (sItem.number && sItem.con) {
  1091. let number = Number(sItem.number);
  1092. let con = sItem.con;
  1093. let word = _this.addTone(number, con);
  1094. str += word;
  1095. } else if (sItem.number) {
  1096. str += sItem.number;
  1097. } else if (sItem.con) {
  1098. str += ` ${sItem.con} `;
  1099. }
  1100. });
  1101. });
  1102. this.checkPinyinInput = str.trim();
  1103. this.itemActive.pinyin = this.checkPinyinInput.replace(/\s+/g, '');
  1104. this.$message.success('保存成功');
  1105. // this.itemActive = null;
  1106. this.checkPinyinInput = '';
  1107. this.oldInput = '';
  1108. this.dialogFlag = false;
  1109. }, 10);
  1110. }
  1111. });
  1112. },
  1113. handleValue(valItem) {
  1114. let reg = /\d/;
  1115. let reg2 = /[A-Za-z]+\d/g;
  1116. let numList = [];
  1117. let valArr = valItem.split('');
  1118. if (reg2.test(valItem)) {
  1119. for (let i = 0; i < valArr.length; i++) {
  1120. let item = valItem[i];
  1121. if (reg.test(item)) {
  1122. let numIndex = numList.length === 0 ? 0 : numList[numList.length - 1].index;
  1123. let con = valItem.substring(numIndex, i);
  1124. con = con.replace(/\d/g, '');
  1125. let obj = {
  1126. index: i,
  1127. number: item,
  1128. con,
  1129. isTran: true,
  1130. };
  1131. numList.push(obj);
  1132. }
  1133. }
  1134. } else {
  1135. numList = [];
  1136. }
  1137. if (numList.length === 0) {
  1138. this.resArr.push([{ con: valItem }]);
  1139. } else {
  1140. this.resArr.push(numList);
  1141. }
  1142. },
  1143. addTone(number, con) {
  1144. let _this = this;
  1145. let zmList = ['a', 'o', 'e', 'i', 'u', 'v', 'A', 'O', 'E', 'I', 'U', 'n', 'm'];
  1146. if (number) {
  1147. for (let i = 0; i < zmList.length; i++) {
  1148. let zm = zmList[i];
  1149. if (con.indexOf(zm) > -1) {
  1150. let zm2 = _this.tableData[i][number - 1];
  1151. if (con.indexOf('iu') > -1) {
  1152. zm2 = _this.tableData[4][number - 1];
  1153. con = con.replace('u', zm2);
  1154. } else if (con.indexOf('ui') > -1) {
  1155. zm2 = _this.tableData[3][number - 1];
  1156. con = con.replace('i', zm2);
  1157. } else if (
  1158. con.indexOf('yv') > -1 ||
  1159. con.indexOf('jv') > -1 ||
  1160. con.indexOf('qv') > -1 ||
  1161. con.indexOf('xv') > -1
  1162. ) {
  1163. zm2 = _this.tableData[4][number - 1];
  1164. con = con.replace('v', zm2);
  1165. } else {
  1166. con = con.replace(zm, zm2);
  1167. }
  1168. break;
  1169. }
  1170. }
  1171. }
  1172. return con;
  1173. },
  1174. // 设置样式
  1175. setActiveTextStyle(type, val) {
  1176. let style = this.data.other_attrib;
  1177. if (type === 'underline') {
  1178. style.isUnderline = style.isUnderline === 'underline' ? '' : 'underline';
  1179. if (style.isUnderline === 'underline') {
  1180. style.isStrikethrough = '';
  1181. }
  1182. this.data.detail.forEach((item) => {
  1183. item.wordsList.forEach((items) => {
  1184. items.forEach((itemss) => {
  1185. itemss.textDecoration = style.isUnderline;
  1186. });
  1187. });
  1188. });
  1189. } else if (type === 'bold') {
  1190. style.isBold = style.isBold === 'bold' ? '' : 'bold';
  1191. this.data.detail.forEach((item) => {
  1192. item.wordsList.forEach((items) => {
  1193. items.forEach((itemss) => {
  1194. itemss.fontWeight = style.isBold;
  1195. });
  1196. });
  1197. });
  1198. } else if (type === 'line-through') {
  1199. style.isStrikethrough = style.isStrikethrough === 'line-through' ? '' : 'line-through';
  1200. if (style.isStrikethrough === 'line-through') {
  1201. style.isUnderline = '';
  1202. }
  1203. this.data.detail.forEach((item) => {
  1204. item.wordsList.forEach((items) => {
  1205. items.forEach((itemss) => {
  1206. itemss.textDecoration = style.isStrikethrough;
  1207. });
  1208. });
  1209. });
  1210. } else if (type === 'border') {
  1211. style.border = style.border === 'dotted' ? '' : 'dotted';
  1212. this.data.detail.forEach((item) => {
  1213. item.wordsList.forEach((items) => {
  1214. items.forEach((itemss) => {
  1215. itemss.border = style.border;
  1216. });
  1217. });
  1218. });
  1219. } else if (type === 'align') {
  1220. style.align = val;
  1221. this.articleAttrib.align = val;
  1222. this.data.detail.forEach((item) => {
  1223. item.paraAlign =
  1224. this.articleAttrib.align === 'RIGHT' ? 'right' : this.articleAttrib.align === 'MIDDLE' ? 'center' : 'left';
  1225. });
  1226. }
  1227. },
  1228. },
  1229. };
  1230. </script>
  1231. <style lang="scss" scoped>
  1232. .article-wrapper {
  1233. display: flex;
  1234. flex-direction: column;
  1235. row-gap: 16px;
  1236. align-items: flex-start;
  1237. }
  1238. .upload-file {
  1239. display: flex;
  1240. column-gap: 12px;
  1241. align-items: center;
  1242. margin: 8px 0;
  1243. .file-name {
  1244. display: flex;
  1245. column-gap: 14px;
  1246. align-items: center;
  1247. justify-content: space-between;
  1248. max-width: 360px;
  1249. padding: 8px 12px;
  1250. font-size: 14px;
  1251. color: #1d2129;
  1252. background-color: #f7f8fa;
  1253. span {
  1254. display: flex;
  1255. column-gap: 14px;
  1256. align-items: center;
  1257. }
  1258. }
  1259. .svg-icon {
  1260. cursor: pointer;
  1261. }
  1262. }
  1263. .btn-box {
  1264. display: flex;
  1265. flex-flow: wrap;
  1266. gap: 10px;
  1267. a {
  1268. padding: 5px 16px;
  1269. font-size: 14px;
  1270. line-height: 22px;
  1271. color: #4e5969;
  1272. cursor: pointer;
  1273. background: #f2f3f5;
  1274. border-radius: 2px;
  1275. }
  1276. p {
  1277. margin: 0;
  1278. }
  1279. }
  1280. .tips {
  1281. margin: 0;
  1282. font-size: 12px;
  1283. color: #e82d2d;
  1284. }
  1285. .tabs-box {
  1286. display: flex;
  1287. column-gap: 12px;
  1288. margin: 12px 0;
  1289. a {
  1290. padding: 5px 16px;
  1291. font-size: 14px;
  1292. font-weight: 400;
  1293. line-height: 22px; /* 157.143% */
  1294. color: #4e5969;
  1295. cursor: pointer;
  1296. border-radius: 100px;
  1297. &.active {
  1298. color: #165dff;
  1299. background: #f2f3f5;
  1300. }
  1301. }
  1302. }
  1303. .text {
  1304. display: flex;
  1305. flex-flow: wrap;
  1306. .text-item {
  1307. padding: 0 1px;
  1308. text-align: center;
  1309. }
  1310. .pinyin {
  1311. display: block;
  1312. font-family: 'PINYIN-B';
  1313. }
  1314. .word {
  1315. display: block;
  1316. }
  1317. }
  1318. .table-rich-toolbar {
  1319. display: flex;
  1320. gap: 5px;
  1321. padding: 5px 0;
  1322. /* align-items: center; */
  1323. :deep .el-form-item--small.el-form-item {
  1324. margin: 0 5px 0 0;
  1325. }
  1326. :deep .el-form-item__label {
  1327. padding-right: 3px;
  1328. }
  1329. > span {
  1330. height: 30px;
  1331. padding: 5px 6px;
  1332. color: #222f3e;
  1333. cursor: pointer;
  1334. border-radius: 5px;
  1335. &:hover {
  1336. background: #cce2fa;
  1337. }
  1338. &.active {
  1339. background: #a6ccf7;
  1340. }
  1341. }
  1342. }
  1343. </style>
  1344. <style lang="scss">
  1345. .article-checkpinyin-dialog {
  1346. .el-dialog__header {
  1347. padding: 0;
  1348. }
  1349. .el-dialog__body {
  1350. padding: 0;
  1351. }
  1352. .el-input__inner {
  1353. text-align: center;
  1354. background: #f3f3f3;
  1355. }
  1356. .check-box {
  1357. padding: 24px;
  1358. background: #fff;
  1359. border-radius: 4px;
  1360. box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 25%);
  1361. .content {
  1362. display: flex;
  1363. align-items: center;
  1364. justify-content: center;
  1365. .words-box {
  1366. color: #000;
  1367. text-align: center;
  1368. .words {
  1369. display: block;
  1370. font-size: 28px;
  1371. font-weight: 400;
  1372. line-height: 40px;
  1373. }
  1374. .pinyin {
  1375. display: block;
  1376. height: 20px;
  1377. font-family: 'League';
  1378. font-size: 20px;
  1379. font-weight: 400;
  1380. line-height: 1;
  1381. }
  1382. }
  1383. }
  1384. .checkPinyinInput {
  1385. margin: 16px 0 8px;
  1386. }
  1387. .tips {
  1388. margin: 0 0 24px;
  1389. font-size: 12px;
  1390. font-weight: 400;
  1391. line-height: 18px;
  1392. color: #a0a0a0;
  1393. }
  1394. .btn-box {
  1395. display: block;
  1396. text-align: right;
  1397. .el-button {
  1398. padding: 2px 12px;
  1399. font-size: 12px;
  1400. line-height: 20px;
  1401. }
  1402. }
  1403. }
  1404. }
  1405. </style>