CheckArticle.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. <template>
  2. <div class="check-article">
  3. <div class="main">
  4. <div class="main-top">
  5. <b>校对</b>
  6. <div class="btn-box">
  7. <el-button @click="showWordFlag = true">校对分词</el-button>
  8. <el-button @click="showPinyinFlag = true">校对拼音</el-button>
  9. <el-button @click="showStyleFlag = true">校对样式</el-button>
  10. </div>
  11. </div>
  12. <div v-for="(item, index) in data.detail" :key="index + 'paragraph'" class="paragraph">
  13. <label>段 {{ index + 1 }}</label>
  14. <template v-if="data.type === 'article'">
  15. <div class="set-para">
  16. <span>对齐方式:</span>
  17. <el-radio-group v-model="item.paraAlign">
  18. <el-radio label="left">左对齐</el-radio>
  19. <el-radio label="center">居中对齐</el-radio>
  20. <el-radio label="right">右对齐</el-radio>
  21. </el-radio-group>
  22. </div>
  23. <div class="remark-box" @click="showRemark(index)"><SvgIcon icon-class="edit-line" />添加备注</div>
  24. <el-upload
  25. action="no"
  26. accept="image/*,video/*"
  27. :file-list="item.sourceList"
  28. :http-request="handleImage"
  29. :before-upload="handleBeforeImage"
  30. :on-exceed="handleExceed"
  31. :limit="1"
  32. :key="index"
  33. @click.native="handleItem(index)"
  34. class="upload-resource"
  35. >
  36. <div class="remark-box"><i class="el-icon-upload"></i>上传图片/视频</div>
  37. </el-upload>
  38. <div class="set-para">
  39. <span>图片/视频位置:</span>
  40. <el-radio-group v-model="item.sourcePosition">
  41. <el-radio label="before">段落前</el-radio>
  42. <el-radio label="after">段落后</el-radio>
  43. </el-radio-group>
  44. </div>
  45. <div class="set-para">
  46. <span class="adult-book-lable">图片宽度:</span>
  47. <el-input
  48. v-model="item.widthNumber"
  49. class="adult-book-input"
  50. placeholder="请输入宽度值"
  51. maxlength="200"
  52. style="width: 150px"
  53. @blur="onBlur(item, 'widthNumber')"
  54. />
  55. <span class="adult-book-lable">图片高度:</span>
  56. <el-input
  57. v-model="item.heightNumber"
  58. class="adult-book-input"
  59. placeholder="请输入高度值"
  60. maxlength="200"
  61. style="width: 150px"
  62. @blur="onBlur(item, 'heightNumber')"
  63. />
  64. </div>
  65. </template>
  66. <div v-for="(items, indexs) in item.sentenceStr" :key="indexs + 'words'" class="sentence-box">
  67. <div class="sentence">
  68. <b>{{ indexs + 1 }}.</b>
  69. <div class="sentence" v-html="items"></div>
  70. </div>
  71. </div>
  72. </div>
  73. </div>
  74. <el-dialog
  75. v-if="showWordFlag"
  76. :visible.sync="showWordFlag"
  77. :show-close="true"
  78. :close-on-click-modal="true"
  79. :modal-append-to-body="true"
  80. :append-to-body="true"
  81. :lock-scroll="true"
  82. width="80%"
  83. class="practiceBox"
  84. >
  85. <CheckWord :data="data" @saveWord="saveWord" />
  86. </el-dialog>
  87. <el-dialog
  88. v-if="showPinyinFlag"
  89. :visible.sync="showPinyinFlag"
  90. :show-close="true"
  91. :close-on-click-modal="true"
  92. :modal-append-to-body="true"
  93. :append-to-body="true"
  94. :lock-scroll="true"
  95. width="80%"
  96. class="practiceBox"
  97. >
  98. <CheckPinyin :data="data" @savePinyin="savePinyin" />
  99. </el-dialog>
  100. <el-dialog
  101. v-if="showStyleFlag"
  102. :visible.sync="showStyleFlag"
  103. :show-close="true"
  104. :close-on-click-modal="true"
  105. :modal-append-to-body="true"
  106. :append-to-body="true"
  107. :lock-scroll="true"
  108. width="80%"
  109. class="practiceBox"
  110. >
  111. <CheckStyle :data="data" @saveStyle="saveStyle" />
  112. </el-dialog>
  113. <el-dialog title="标注" :visible.sync="remarkVisible" width="50%" :close-on-click-modal="false" append-to-body>
  114. <div v-if="remark" class="remark">
  115. <div class="adult-book-input-item">
  116. <span class="adult-book-lable">中文:</span>
  117. <!-- <el-input
  118. v-model="remark.chs"
  119. class="adult-book-input"
  120. type="textarea"
  121. :autosize="{ minRows: 2 }"
  122. placeholder="请输入中文"
  123. maxlength="200"
  124. show-word-limit
  125. @blur="onBlur(remark, 'chs')"
  126. /> -->
  127. <RichText
  128. ref="richText"
  129. v-model="remark.chs"
  130. toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
  131. :wordlimit-num="200"
  132. :font-size="data?.unified_attrib?.font_size"
  133. :font-family="data?.unified_attrib?.font"
  134. />
  135. </div>
  136. <div class="adult-book-input-item">
  137. <span class="adult-book-lable">英文:</span>
  138. <!-- <el-input
  139. class="adult-book-input"
  140. type="textarea"
  141. :autosize="{ minRows: 2 }"
  142. placeholder="请输入英文"
  143. v-model="remark.en"
  144. @blur="onBlur(remark, 'en')"
  145. maxlength="200"
  146. show-word-limit
  147. ></el-input> -->
  148. <RichText
  149. ref="richText"
  150. v-model="remark.en"
  151. toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
  152. :wordlimit-num="200"
  153. :font-size="data?.unified_attrib?.font_size"
  154. :font-family="data?.unified_attrib?.font"
  155. />
  156. </div>
  157. <div v-if="remark.img_list && remark.img_list.length == 0" class="adult-book-input-item">
  158. <el-upload action="no" accept="image/*" :show-file-list="false" :http-request="changeImage">
  159. <el-button>上传图片</el-button>
  160. </el-upload>
  161. </div>
  162. <ul v-if="remark.img_list && remark.img_list.length > 0" class="uploadArt_list">
  163. <li v-for="(artItem, artIndex) in remark.img_list" :key="'articleImgList' + artIndex">
  164. <img :src="artItem.url" style="width: 26px; margin-right: 5px" />
  165. <span class="art_name">{{ artItem.name }}</span>
  166. <SvgIcon icon-class="delete-black" size="14" @click="delImage(artIndex)" />
  167. </li>
  168. </ul>
  169. <div class="adult-book-input-item">
  170. <span class="adult-book-lable">图片宽度:</span>
  171. <el-input
  172. v-model="remark.widthNumber"
  173. class="adult-book-input"
  174. placeholder="请输入宽度值"
  175. maxlength="200"
  176. style="width: 150px"
  177. @blur="onBlur(remark, 'widthNumber')"
  178. />
  179. <span class="adult-book-lable">图片高度:</span>
  180. <el-input
  181. v-model="remark.heightNumber"
  182. class="adult-book-input"
  183. placeholder="请输入高度值"
  184. maxlength="200"
  185. style="width: 150px"
  186. @blur="onBlur(remark, 'heightNumber')"
  187. />
  188. </div>
  189. </div>
  190. <span slot="footer" class="dialog-footer">
  191. <el-button @click="remarkVisible = false">取 消</el-button>
  192. <el-button type="primary" @click="saveRemark">保 存</el-button>
  193. </span>
  194. </el-dialog>
  195. </div>
  196. </template>
  197. <script>
  198. import CheckWord from './CheckWord.vue';
  199. import CheckPinyin from './CheckPinyin.vue';
  200. import CheckStyle from './CheckStyle.vue';
  201. import RichText from '@/components/RichText.vue';
  202. import { fileUpload } from '@/api/app';
  203. export default {
  204. components: {
  205. CheckWord,
  206. CheckPinyin,
  207. CheckStyle,
  208. RichText,
  209. },
  210. props: ['data'],
  211. data() {
  212. return {
  213. // ArticelData: JSON.parse(JSON.stringify(this.data)),
  214. showWordFlag: false,
  215. showPinyinFlag: false,
  216. showStyleFlag: false,
  217. remarkVisible: false,
  218. remark: null,
  219. activeItem: null,
  220. };
  221. },
  222. // 生命周期 - 创建完成(可以访问当前this实例)
  223. created() {
  224. this.getArticleData();
  225. },
  226. methods: {
  227. // 获取分析结果
  228. getArticleData() {
  229. this.data.detail.forEach((item) => {
  230. if (item.segList && item.segList.length > 0) {
  231. item.sentenceStr = [];
  232. item.segList.forEach((items, indexs) => {
  233. let str = '';
  234. items.forEach((itemss, indexss) => {
  235. str += itemss;
  236. if (indexss !== items.length - 1) str += '&nbsp;&nbsp;';
  237. });
  238. item.sentenceStr.push(str);
  239. });
  240. }
  241. });
  242. },
  243. // 保存分词分段
  244. saveWord(saveArr) {
  245. this.$emit('saveWord', saveArr);
  246. },
  247. savePinyin(paraIndex, sentenceIndex, wordIndex, pinyin) {
  248. this.$emit('savePinyin', paraIndex, sentenceIndex, wordIndex, pinyin);
  249. },
  250. saveStyle(
  251. paraIndex,
  252. sentenceIndex,
  253. wordIndex,
  254. fontFamily,
  255. textDecoration,
  256. fontWeight,
  257. border,
  258. color,
  259. matchWords,
  260. matchNotes,
  261. img,
  262. imgPosition,
  263. ) {
  264. this.$emit(
  265. 'saveStyle',
  266. paraIndex,
  267. sentenceIndex,
  268. wordIndex,
  269. fontFamily,
  270. textDecoration,
  271. fontWeight,
  272. border,
  273. color,
  274. matchWords,
  275. matchNotes,
  276. img,
  277. imgPosition,
  278. );
  279. },
  280. changeImage(file) {
  281. fileUpload('Mid', file, { isGlobalprogress: true }).then(({ file_info_list }) => {
  282. if (file_info_list.length > 0) {
  283. const { file_id, file_url_open, file_name } = file_info_list[0];
  284. this.remark.img_list.push({
  285. name: file_name,
  286. url: file_url_open,
  287. id: file_id,
  288. imgNumber: 0,
  289. });
  290. }
  291. });
  292. },
  293. delImage(index) {
  294. this.remark.img_list.splice(index, 1);
  295. },
  296. showRemark(index) {
  297. this.remark = this.data.detail[index].remark;
  298. this.paraIndex = index;
  299. this.remarkVisible = true;
  300. },
  301. saveRemark() {
  302. this.data.detail[this.paraIndex].remark = JSON.parse(JSON.stringify(this.remark));
  303. this.remarkVisible = false;
  304. },
  305. onBlur(item, field) {
  306. item[field] = item[field] ? item[field].trim() : '';
  307. },
  308. // 处理超出图片个数操作
  309. handleExceed(files, fileList) {
  310. this.$message.warning(
  311. `当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`,
  312. );
  313. },
  314. // 记录段落
  315. handleItem(index) {
  316. this.activeItem = this.data.detail[index];
  317. },
  318. // 图片上传前处理
  319. handleBeforeImage(file) {
  320. // 判断文件是否为图片
  321. if (!file.type.includes('image') && !file.type.includes('video')) {
  322. this.$message.error('请选择图片或视频文件');
  323. return false;
  324. }
  325. },
  326. // 图片上传
  327. handleImage(file) {
  328. fileUpload('Mid', file, { isGlobalprogress: true }).then(({ file_info_list }) => {
  329. if (file_info_list.length > 0) {
  330. this.activeItem.sourceList = file_info_list;
  331. this.activeItem.sourceList[0].name = file_info_list[0].file_name;
  332. this.activeItem.sourceList[0].type = file.file.type.includes('image') > -1 ? 'image' : 'video';
  333. }
  334. });
  335. },
  336. },
  337. };
  338. </script>
  339. <style lang="scss" scoped>
  340. .check-article {
  341. min-height: 100%;
  342. background: #f6f6f6;
  343. .wheader {
  344. background: #fff;
  345. }
  346. .main {
  347. background: #fff;
  348. &-top {
  349. position: relative;
  350. display: flex;
  351. align-items: center;
  352. justify-content: flex-end;
  353. margin-bottom: 24px;
  354. b {
  355. position: absolute;
  356. top: 0;
  357. left: 50%;
  358. width: 50px;
  359. margin-left: -25px;
  360. font-size: 24px;
  361. font-weight: 500;
  362. line-height: 34px;
  363. color: #000;
  364. text-align: center;
  365. }
  366. .el-button {
  367. padding: 5px 16px;
  368. font-size: 14px;
  369. font-weight: 400;
  370. line-height: 22px;
  371. color: #165dff;
  372. border: 1px solid #165dff;
  373. border-radius: 2px;
  374. &.el-button--primary {
  375. color: #fff;
  376. background: #165dff;
  377. }
  378. }
  379. }
  380. .go-back {
  381. display: flex;
  382. align-items: center;
  383. width: 60px;
  384. padding: 5px 8px;
  385. font-size: 14px;
  386. font-weight: 400;
  387. line-height: 22px;
  388. color: #333;
  389. cursor: pointer;
  390. background: #fff;
  391. border: 1px solid #d9d9d9;
  392. border-radius: 4px;
  393. box-shadow: 0 2px 0 0 rgba(0, 0, 0, 2%);
  394. .el-icon-arrow-left {
  395. margin-right: 8px;
  396. font-size: 16px;
  397. }
  398. }
  399. .paragraph {
  400. margin-bottom: 8px;
  401. text-align: center;
  402. > label {
  403. padding: 1px 8px;
  404. font-size: 14px;
  405. font-weight: 400;
  406. line-height: 22px;
  407. color: var(--blue-05, #175dff);
  408. background: #e7eeff;
  409. border: 1px solid #175dff;
  410. border-radius: 2px;
  411. }
  412. .sentence-box {
  413. .sentence {
  414. display: flex;
  415. margin-top: 8px;
  416. b {
  417. flex-shrink: 0;
  418. width: 32px;
  419. margin-top: 16px;
  420. font-size: 16px;
  421. font-weight: 400;
  422. line-height: 24px;
  423. color: #000;
  424. }
  425. .sentence {
  426. flex: 1;
  427. padding: 8px;
  428. font-size: 16px;
  429. font-weight: 400;
  430. line-height: 24px;
  431. color: #000;
  432. text-align: left;
  433. background: #f7f7f7;
  434. }
  435. }
  436. }
  437. }
  438. }
  439. .set-para {
  440. margin-top: 8px;
  441. text-align: left;
  442. }
  443. }
  444. .remark-box {
  445. display: flex;
  446. gap: 8px;
  447. align-items: center;
  448. justify-content: center;
  449. width: fit-content;
  450. height: 24px;
  451. padding: 2px 12px;
  452. margin: 16px 0 0;
  453. font-size: 12px;
  454. font-weight: 400;
  455. line-height: 20px; /* 166.667% */
  456. color: #165dff;
  457. cursor: pointer;
  458. border: 1px solid #165dff;
  459. border-radius: 2px;
  460. }
  461. .upload-resource {
  462. text-align: left;
  463. }
  464. </style>