CheckStyle.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. <template>
  2. <div class="check-article">
  3. <div class="main">
  4. <div class="main-top">
  5. <div style="display: flex">
  6. <b>校对样式</b>
  7. </div>
  8. <div class="btn-box">
  9. <el-button
  10. v-if="batch"
  11. @click="
  12. batch = false;
  13. batchList = [];
  14. "
  15. >取消批量选择</el-button
  16. >
  17. <el-button v-if="batch" type="primary" @click="sureBatch">批量选择完成</el-button>
  18. <el-button v-else type="primary" @click="batch = true">开始批量选择</el-button>
  19. </div>
  20. </div>
  21. <div class="article">
  22. <div v-for="(item, index) in indexArr" :key="index + 'paragraph'" class="paragraph">
  23. <div v-for="(items, indexs) in item" :key="indexs + 'words'" class="sentence-box">
  24. <div
  25. class="sentence"
  26. :style="{
  27. marginRight: items.marginRight ? '8px' : '',
  28. color:
  29. activeIndex === index + '_' + items.sentenceIndex + '_' + items.wordIndex ||
  30. batchList.findIndex((itemss) => itemss.saveIndex === items.saveIndex) > -1
  31. ? '#F2555A'
  32. : '',
  33. }"
  34. @click="selectItem(items, index)"
  35. >
  36. <span
  37. class="words"
  38. :class="[/^[0-9]*$/.test(items.text)] ? (/^[\u4e00-\u9fa5]/.test(items.text) ? 'hanzi' : 'en') : ''"
  39. :style="{
  40. fontFamily: items.fontFamily,
  41. color:
  42. batchList.findIndex((itemss) => itemss.saveIndex === items.saveIndex) > -1
  43. ? '#F2555A'
  44. : items.color,
  45. textDecoration: items.textDecoration,
  46. borderBottom: items.border === 'dotted' ? '1px dotted' : '',
  47. fontWeight: items.fontWeight,
  48. }"
  49. >
  50. {{ items.text }}
  51. </span>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. <el-dialog
  58. v-if="dialogFlag"
  59. :visible.sync="dialogFlag"
  60. :show-close="false"
  61. :close-on-click-modal="false"
  62. :modal-append-to-body="false"
  63. :modal="false"
  64. width="400px"
  65. class="login-dialog"
  66. >
  67. <div class="check-box">
  68. <div class="content">
  69. <div v-if="batchList.length < 2" class="words-box">
  70. <span
  71. class="words"
  72. :style="{
  73. fontFamily: itemActive.fontFamily,
  74. color: itemActive.color,
  75. textDecoration: itemActive.textDecoration,
  76. borderBottom: itemActive.border === 'dotted' ? '1px dotted' : '',
  77. fontWeight: itemActive.fontWeight,
  78. }"
  79. >
  80. {{ itemActive.text }}
  81. </span>
  82. </div>
  83. </div>
  84. <div ref="toolbarMenu" class="toolbar">
  85. <el-select v-model="itemActive.fontFamily" placeholder="请选择">
  86. <el-option v-for="font in fontList" :key="font.value" :label="font.label" :value="font.value" />
  87. </el-select>
  88. <span class="picker-area" :class="['tool-item', itemActive.color ? 'active' : '']">
  89. <el-color-picker
  90. ref="colorPicker"
  91. v-model="itemActive.color"
  92. @click="itemActive.color = itemActive.color"
  93. />
  94. <SvgIcon icon-class="fontcolor" title="字体颜色" size="18" />
  95. </span>
  96. <span :class="['tool-item', itemActive.textDecoration === 'underline' ? 'active' : '']">
  97. <SvgIcon icon-class="underline" title="下划线" size="18" @click="setActiveTextStyle('underline')" />
  98. </span>
  99. <span :class="['tool-item', itemActive.fontWeight === 'bold' ? 'active' : '']">
  100. <SvgIcon icon-class="bold" title="加粗" size="20" @click="setActiveTextStyle('bold')" />
  101. </span>
  102. <span :class="['tool-item', itemActive.textDecoration === 'line-through' ? 'active' : '']">
  103. <SvgIcon icon-class="strikethrough" title="删除线" size="20" @click="setActiveTextStyle('line-through')" />
  104. </span>
  105. <span :class="['tool-item', itemActive.border === 'dotted' ? 'active' : '']">
  106. <SvgIcon icon-class="borderDotted" title="下划虚线" size="16" @click="setActiveTextStyle('border')" />
  107. </span>
  108. </div>
  109. <div v-if="batchList.length < 2" class="match-info">
  110. <label>关联生词:</label>
  111. <el-input
  112. v-model="itemActive.matchWords"
  113. placeholder="请输入生词表的“生词/短语”"
  114. @blur="onBlur(itemActive, 'matchWords')"
  115. />
  116. </div>
  117. <!-- <div class="match-info" v-if="batchList.length < 2">
  118. <label>关联注释:</label>
  119. <el-input
  120. v-model="itemActive.matchNotes"
  121. placeholder="请输入注释表的“内容”"
  122. @blur="onBlur(itemActive, 'matchNotes')"
  123. ></el-input>
  124. <el-color-picker v-model="itemActive.notesColor"></el-color-picker>
  125. </div> -->
  126. <div class="btn-box">
  127. <el-button type="info" size="small" @click="cancleDialog">取消</el-button>
  128. <el-button type="primary" size="small" @click="surePinyin">保存</el-button>
  129. </div>
  130. </div>
  131. </el-dialog>
  132. </div>
  133. </template>
  134. <script>
  135. // import { publicMethods, reparse } from '@/api/api';
  136. import { fileUpload } from '@/api/app';
  137. import { fontList } from '@/common/data';
  138. export default {
  139. components: {},
  140. props: ['data'],
  141. data() {
  142. return {
  143. loading: false,
  144. id: '',
  145. ArticelData: null,
  146. indexArr: [], // 索引数组
  147. activeIndex: null,
  148. itemActive: null,
  149. dialogFlag: false,
  150. checkPinyinInput: '',
  151. oldInput: '',
  152. toneList: [' ', 'ˉ', 'ˊ', 'ˇ', 'ˋ'],
  153. fontFamilyList: [
  154. {
  155. value: '楷体,微软雅黑',
  156. name: '楷体',
  157. },
  158. {
  159. value: '黑体,微软雅黑',
  160. name: '黑体',
  161. },
  162. {
  163. value: '宋体,微软雅黑',
  164. name: '宋体',
  165. },
  166. {
  167. value: 'Arial,Helvetica,sans-serif',
  168. name: 'Arial',
  169. },
  170. {
  171. value: 'Times New Roman,times,serif',
  172. name: 'Times New Roman',
  173. },
  174. {
  175. value: 'League',
  176. name: '拼音',
  177. },
  178. // {
  179. // value: 'Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, sans-serif, alabo',
  180. // name: '系统字体',
  181. // },
  182. ],
  183. batch: false, // 批量选择flag
  184. batchList: [], // 批量选择列表
  185. fontList,
  186. };
  187. },
  188. // 生命周期 - 创建完成(可以访问当前this实例)
  189. created() {
  190. this.getArticleData();
  191. },
  192. methods: {
  193. onBlur(item, field) {
  194. item[field] = item[field] ? item[field].trim() : '';
  195. },
  196. // 获取分析结果
  197. getArticleData() {
  198. this.batchList = [];
  199. this.loading = true;
  200. let newdata = [];
  201. this.data.detail.forEach((item) => {
  202. if (item.wordsList.length !== 0 || (item.noticeWordList && item.noticeWordList.length !== 0)) {
  203. newdata.push(item);
  204. }
  205. });
  206. // this.ArticelData = JSON.parse(JSON.stringify(newdata));
  207. let saveArr = [];
  208. let arr = [];
  209. let saveIndex = 0;
  210. // 添加索引
  211. newdata.forEach((item, index) => {
  212. arr.push([]);
  213. if (item.wordsList.length > 0) {
  214. item.wordsList.forEach((items, indexs) => {
  215. items.forEach((itemss, indexss) => {
  216. let obj = {
  217. text: itemss.chs,
  218. paraIndex: item.paraIndex,
  219. sentenceIndex: indexs,
  220. wordIndex: indexss,
  221. marginRight: true,
  222. saveIndex,
  223. fontFamily: itemss.fontFamily,
  224. textDecoration: itemss.textDecoration,
  225. fontWeight: itemss.fontWeight,
  226. border: itemss.border,
  227. color: itemss.color,
  228. matchWords: itemss.matchWords,
  229. matchNotes: itemss.matchNotes,
  230. notesColor: itemss.notesColor,
  231. img: itemss.img,
  232. imgPosition: itemss.imgPosition,
  233. };
  234. arr[index].push(obj);
  235. let saveObj = {
  236. word: itemss.chs,
  237. // pinyin_lt: itemss.pinyin_lt?itemss.pinyin_lt:''
  238. };
  239. saveArr.push(saveObj);
  240. saveIndex++;
  241. });
  242. });
  243. } else {
  244. item.noticeWordList.forEach((items, indexs) => {
  245. items.forEach((itemss, indexss) => {
  246. let obj = {
  247. text: itemss.chs,
  248. paraIndex: item.paraIndex,
  249. sentenceIndex: indexs,
  250. wordIndex: indexss,
  251. marginRight: true,
  252. saveIndex,
  253. fontFamily: itemss.fontFamily,
  254. textDecoration: itemss.textDecoration,
  255. fontWeight: itemss.fontWeight,
  256. border: itemss.border,
  257. color: itemss.color,
  258. matchWords: itemss.matchWords,
  259. matchNotes: itemss.matchNotes,
  260. notesColor: itemss.notesColor,
  261. img: itemss.img,
  262. imgPosition: itemss.imgPosition,
  263. };
  264. arr[index].push(obj);
  265. let saveObj = {
  266. word: itemss.chs,
  267. // pinyin_lt: itemss.pinyin_lt?itemss.pinyin_lt:''
  268. };
  269. saveArr.push(saveObj);
  270. saveIndex++;
  271. });
  272. });
  273. }
  274. });
  275. this.indexArr = arr;
  276. this.ArticelData = saveArr;
  277. this.loading = false;
  278. },
  279. selectItem(item, index) {
  280. if (this.batch) {
  281. let isHas = this.batchList.findIndex((itemss) => itemss.saveIndex === item.saveIndex);
  282. if (isHas > -1) {
  283. this.batchList.splice(isHas, 1);
  284. } else {
  285. this.batchList.push(item);
  286. }
  287. this.itemActive = item;
  288. } else {
  289. this.batchList = [];
  290. this.activeIndex = `${index}_${item.sentenceIndex}_${item.wordIndex}`;
  291. this.itemActive = item;
  292. this.dialogFlag = true;
  293. this.checkPinyinInput = '';
  294. }
  295. },
  296. cancleDialog() {
  297. this.batchList = [];
  298. this.activeIndex = null;
  299. this.itemActive = null;
  300. this.checkPinyinInput = '';
  301. this.oldInput = '';
  302. this.dialogFlag = false;
  303. },
  304. surePinyin() {
  305. this.saveStyle();
  306. this.dialogFlag = false;
  307. },
  308. saveStyle() {
  309. if (this.batch) {
  310. this.batchList.forEach((item) => {
  311. this.$emit(
  312. 'saveStyle',
  313. item.paraIndex,
  314. item.sentenceIndex,
  315. item.wordIndex,
  316. this.itemActive.fontFamily,
  317. this.itemActive.textDecoration,
  318. this.itemActive.fontWeight,
  319. this.itemActive.border,
  320. this.itemActive.color,
  321. this.itemActive.matchWords,
  322. this.itemActive.matchNotes,
  323. this.itemActive.notesColor,
  324. this.itemActive.img,
  325. this.itemActive.imgPosition,
  326. );
  327. item.fontFamily = this.itemActive.fontFamily;
  328. item.textDecoration = this.itemActive.textDecoration;
  329. item.fontWeight = this.itemActive.fontWeight;
  330. item.border = this.itemActive.border;
  331. item.color = this.itemActive.color;
  332. item.matchWords = this.itemActive.matchWords;
  333. item.matchNotes = this.itemActive.matchNotes;
  334. item.notesColor = this.itemActive.notesColor;
  335. item.img = this.itemActive.img;
  336. item.imgPosition = this.itemActive.imgPosition;
  337. });
  338. } else {
  339. this.$emit(
  340. 'saveStyle',
  341. this.itemActive.paraIndex,
  342. this.itemActive.sentenceIndex,
  343. this.itemActive.wordIndex,
  344. this.itemActive.fontFamily,
  345. this.itemActive.textDecoration,
  346. this.itemActive.fontWeight,
  347. this.itemActive.border,
  348. this.itemActive.color,
  349. this.itemActive.matchWords,
  350. this.itemActive.matchNotes,
  351. this.itemActive.notesColor,
  352. this.itemActive.img,
  353. this.itemActive.imgPosition,
  354. );
  355. }
  356. this.$message.success('保存成功');
  357. this.activeIndex = null;
  358. // this.itemActive = null;
  359. this.dialogFlag = false;
  360. this.batch = false;
  361. this.batchList = [];
  362. },
  363. // 设置样式
  364. setActiveTextStyle(type) {
  365. let style = this.itemActive;
  366. if (type === 'line-through') {
  367. style.textDecoration = style.textDecoration === 'line-through' ? '' : 'line-through';
  368. this.$set(this.itemActive, 'textDecoration', style.textDecoration);
  369. } else if (type === 'bold') {
  370. style.fontWeight = style.fontWeight === 'bold' ? '' : 'bold';
  371. this.$set(this.itemActive, 'fontWeight', style.fontWeight);
  372. } else if (type === 'underline') {
  373. style.textDecoration = style.textDecoration === 'underline' ? '' : 'underline';
  374. this.$set(this.itemActive, 'textDecoration', style.textDecoration);
  375. } else if (type === 'border') {
  376. style.border = style.border === 'dotted' ? '' : 'dotted';
  377. this.$set(this.itemActive, 'border', style.border);
  378. }
  379. },
  380. // 处理超出图片个数操作
  381. handleExceed(files, fileList) {
  382. this.$message.warning(
  383. `当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`,
  384. );
  385. },
  386. // 图片上传前处理
  387. handleBeforeImage(file) {
  388. // 判断文件是否为图片
  389. if (!file.type.includes('image')) {
  390. this.$message.error('请选择图片文件');
  391. return false;
  392. }
  393. },
  394. // 图片上传
  395. handleImage(file) {
  396. fileUpload('Mid', file, { isGlobalprogress: true }).then(({ file_info_list }) => {
  397. if (file_info_list.length > 0) {
  398. this.itemActive.img = file_info_list;
  399. this.itemActive.img[0].name = file_info_list[0].file_name;
  400. }
  401. });
  402. },
  403. sureBatch() {
  404. if (this.batchList.length === 0) {
  405. this.$message.warning('请至少选择一个分词');
  406. return;
  407. }
  408. this.dialogFlag = true;
  409. },
  410. },
  411. };
  412. </script>
  413. <style lang="scss" scoped>
  414. .check-article {
  415. min-height: 100%;
  416. background: #f6f6f6;
  417. .wheader {
  418. background: #fff;
  419. }
  420. .el-button {
  421. padding: 5px 16px;
  422. font-size: 14px;
  423. font-weight: 400;
  424. line-height: 22px;
  425. color: #4e5969;
  426. background: #f2f3f5;
  427. border: 1px solid #f2f3f5;
  428. border-radius: 2px;
  429. &.el-button--primary {
  430. color: #fff;
  431. background: #165dff;
  432. border: 1px solid #165dff;
  433. }
  434. }
  435. .main {
  436. background: #fff;
  437. &-top {
  438. position: relative;
  439. display: flex;
  440. align-items: center;
  441. justify-content: space-between;
  442. margin-bottom: 24px;
  443. b {
  444. margin-left: 16px;
  445. font-size: 24px;
  446. font-weight: 500;
  447. line-height: 34px;
  448. color: #000;
  449. }
  450. }
  451. .go-back {
  452. display: flex;
  453. align-items: center;
  454. width: 60px;
  455. padding: 5px 8px;
  456. font-size: 14px;
  457. font-weight: 400;
  458. line-height: 22px;
  459. color: #333;
  460. cursor: pointer;
  461. background: #fff;
  462. border: 1px solid #d9d9d9;
  463. border-radius: 4px;
  464. box-shadow: 0 2px 0 0 rgba(0, 0, 0, 2%);
  465. .el-icon-arrow-left {
  466. margin-right: 8px;
  467. font-size: 16px;
  468. }
  469. }
  470. .article {
  471. padding: 8px;
  472. background: #fcfcfc;
  473. border: 1px solid rgba(0, 0, 0, 8%);
  474. border-radius: 2px;
  475. }
  476. .paragraph {
  477. display: flex;
  478. flex-flow: wrap;
  479. width: 100%;
  480. margin-bottom: 24px;
  481. text-align: center;
  482. .sentence-box {
  483. display: flex;
  484. flex-flow: wrap;
  485. float: left;
  486. .sentence {
  487. margin-top: 8px;
  488. color: #000;
  489. text-align: center;
  490. cursor: pointer;
  491. .words {
  492. display: block;
  493. font-size: 20px;
  494. font-weight: 400;
  495. line-height: 28px;
  496. }
  497. .pinyin {
  498. display: block;
  499. height: 14px;
  500. font-family: 'League';
  501. font-size: 14px;
  502. font-weight: 400;
  503. line-height: 1;
  504. }
  505. }
  506. }
  507. }
  508. }
  509. }
  510. .check-box {
  511. padding: 24px;
  512. background: #fff;
  513. border-radius: 4px;
  514. box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 25%);
  515. .content {
  516. display: flex;
  517. align-items: center;
  518. justify-content: center;
  519. .words-box {
  520. color: #000;
  521. text-align: center;
  522. .words {
  523. display: block;
  524. font-size: 28px;
  525. font-weight: 400;
  526. line-height: 40px;
  527. }
  528. .pinyin {
  529. display: block;
  530. height: 20px;
  531. font-family: 'League';
  532. font-size: 20px;
  533. font-weight: 400;
  534. line-height: 1;
  535. }
  536. }
  537. }
  538. .checkPinyinInput {
  539. margin: 16px 0 8px;
  540. }
  541. .tips {
  542. margin: 0 0 24px;
  543. font-size: 12px;
  544. font-weight: 400;
  545. line-height: 18px;
  546. color: #a0a0a0;
  547. }
  548. .btn-box {
  549. text-align: right;
  550. .el-button {
  551. padding: 2px 12px;
  552. font-size: 12px;
  553. line-height: 20px;
  554. }
  555. }
  556. }
  557. .toolbar {
  558. display: flex;
  559. column-gap: 10px;
  560. align-items: center;
  561. margin: 10px 0;
  562. cursor: pointer;
  563. .picker-area {
  564. position: relative;
  565. :deep .el-color-picker {
  566. position: absolute;
  567. &__trigger {
  568. border: none;
  569. }
  570. &__color {
  571. border: none !important;
  572. &-inner {
  573. background-color: rgba(0, 0, 0, 0%) !important;
  574. }
  575. }
  576. &__icon {
  577. display: none !important;
  578. }
  579. }
  580. }
  581. .tool-item {
  582. padding: 4px 6px;
  583. border-radius: 8px;
  584. &.active {
  585. background: #a6ccf7;
  586. }
  587. }
  588. }
  589. .match-info {
  590. display: flex;
  591. align-items: center;
  592. margin: 10px 0;
  593. label {
  594. width: 100px;
  595. }
  596. }
  597. .remark-box {
  598. display: flex;
  599. gap: 8px;
  600. align-items: center;
  601. justify-content: center;
  602. width: fit-content;
  603. height: 24px;
  604. padding: 2px 12px;
  605. font-size: 12px;
  606. font-weight: 400;
  607. line-height: 20px; /* 166.667% */
  608. color: #165dff;
  609. cursor: pointer;
  610. border: 1px solid #165dff;
  611. border-radius: 2px;
  612. }
  613. </style>
  614. <style lang="scss">
  615. .check-article {
  616. .login-dialog {
  617. .el-dialog__header {
  618. padding: 0;
  619. }
  620. .el-dialog__body {
  621. padding: 0;
  622. }
  623. .el-input__inner {
  624. text-align: center;
  625. background: #f3f3f3;
  626. }
  627. }
  628. .el-color-picker__empty {
  629. display: none;
  630. }
  631. }
  632. </style>