proofread.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. <template>
  2. <div class="edito_youmei">
  3. <header_local />
  4. <div class="onlineTextMain">
  5. <div class="flex1">
  6. <div class="btn-grounp">
  7. 文章内容
  8. <el-button
  9. type="primary"
  10. style="float: right; margin-top: 0.3em; margin-right: 0.5em"
  11. class="jiaoyan"
  12. @click="getServer"
  13. >
  14. 校验
  15. </el-button>
  16. <el-button
  17. class="clearError"
  18. type="primary"
  19. style="float: right; margin-top: 0.3em; margin-right: 0.5em"
  20. @click="clearError"
  21. :icon="Delete"
  22. >
  23. 清空
  24. </el-button>
  25. </div>
  26. <div class="Fle">
  27. <Editor v-model:rawText="rawText" />
  28. </div>
  29. </div>
  30. <div class="flex2">
  31. <div class="btn-grounp">
  32. 检索结果
  33. <div class="errTypes">
  34. <div
  35. @click="tabSelect[0] = !tabSelect[0]"
  36. :class="{ errType: true, checkboxLabel0: tabSelect[0] }"
  37. >
  38. 严重错误 {{ errorTotle.serious }}
  39. </div>
  40. <div
  41. @click="tabSelect[1] = !tabSelect[1]"
  42. :class="{ errType: true, checkboxLabel1: tabSelect[1] }"
  43. >
  44. 一般错误 {{ errorTotle.same }}
  45. </div>
  46. <div
  47. @click="tabSelect[2] = !tabSelect[2]"
  48. :class="{ errType: true, checkboxLabel2: tabSelect[2] }"
  49. >
  50. 疑错 {{ errorTotle.distrust }}
  51. </div>
  52. <div
  53. @click="tabSelect[3] = !tabSelect[3]"
  54. :class="{ errType: true, checkboxLabel3: tabSelect[3] }"
  55. >
  56. 自定义错误 {{ errorTotle.custom }}
  57. </div>
  58. </div>
  59. </div>
  60. <el-tabs tab-position="top" v-model="tabAct">
  61. <el-tab-pane :label="'未处理:' + untreatedError.length" :name="0">
  62. <proofread-errors
  63. listName="untreatedError"
  64. :lastAtom="lastAtom"
  65. :list="untreatedError"
  66. :tabSelect="tabSelect"
  67. @selectErrorFunc="selectErrorFunc"
  68. @replaceText="replaceText"
  69. @ignoreText="ignoreText"
  70. @deleteText="deleteText"
  71. ></proofread-errors>
  72. </el-tab-pane>
  73. <el-tab-pane :label="'已忽略:' + ignoreError.length" :name="1">
  74. <proofread-errors
  75. listName="ignoreError"
  76. :list="ignoreError"
  77. :tabSelect="tabSelect"
  78. @resumeText="resumeText"
  79. ></proofread-errors>
  80. </el-tab-pane>
  81. <el-tab-pane :label="'已替换:' + replaceError.length" :name="2">
  82. <proofread-errors
  83. listName="replaceError"
  84. :list="replaceError"
  85. :tabSelect="tabSelect"
  86. @resumeText="resumeText"
  87. ></proofread-errors>
  88. </el-tab-pane>
  89. <el-tab-pane :label="'已删除:' + deleteError.length" :name="3">
  90. <proofread-errors
  91. listName="deleteError"
  92. :list="deleteError"
  93. :tabSelect="tabSelect"
  94. @resumeText="resumeText"
  95. ></proofread-errors>
  96. </el-tab-pane>
  97. </el-tabs>
  98. </div>
  99. </div>
  100. </div>
  101. </template>
  102. <script setup>
  103. import header_local from "./components/header.vue";
  104. import Editor from '@/components/editor.vue';
  105. import { Delete } from '@element-plus/icons-vue';
  106. import { ref } from 'vue';
  107. import errType from '../../../config/errtype';
  108. import { check } from '../../api/index';
  109. import proofreadErrors from './components/proofread_errors.vue';
  110. const rawText = ref(
  111. '<p style="margin: 10px auto; font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; font-size: 16px; line-height: 34.2px; font-family: &quot;Microsoft Yahei&quot; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255);">作为一名记者,自己相继参加了党的十八大、十九大、二十大采访报道工作,既是难得的职业经历,也在我心中刻印下3个难忘的场景。</p><p style="margin: 10px auto; font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; font-size: 16px; line-height: 34.2px; font-family: &quot;Microsoft Yahei&quot; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255);">五年前,党的十九大中一位代表自问自答道:“党长期执政的最大威胁是什么?是腐败。党的十八大以来,党中央抓党的建设的鲜明主题是什么?全面从严治党。”以习近平同志为核心的党中央开展了史无前例的反腐败斗争,以“得罪千百人、不负十四亿”的使命担当祛疴治乱,坚定不移“打虎”“拍蝇”“猎狐”,雷霆万钧惩治腐败。“反腐败斗争压倒性态势已经形成并巩固发展”,党的十九大报告作出的这一重大判断,让那位曾经忧心忡忡的党的十八大代表倍感欣慰。</p><p style="margin: 10px auto; font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; font-size: 16px; line-height: 34.2px; font-family: &quot;Microsoft Yahei&quot; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255);">怎能不欣慰?从腐败和反腐败“呈胶着状态”,到反腐败斗争“压倒性态势已经形成”,再到“取得压倒性胜利并全面巩固”,十年磨一剑,党在革命性锻造中更加坚强有力,找到了自我革命这一跳出治乱兴衰历史周期率的第二个答案。</p><p style="margin: 10px auto; font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; font-size: 16px; line-height: 34.2px; font-family: &quot;Microsoft Yahei&quot; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255);">更难忘、更受触动的场景发生在党的二十大开幕之日。习近平总主席在党的二十大报告墙调:“全党必须牢记,从严治党永远在路上,党的自我革命永远在路上”。话语铿锵,响鼓重槌:只要存在腐败问题产生的土壤和条件,反腐败斗争就一刻不能停,必须永远吹冲锋号。</p><p style="margin: 10px auto; font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; font-size: 16px; line-height: 34.2px; font-family: &quot;Microsoft Yahei&quot; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255);">十年时光,三个场景,一个方向:打铁必须自身硬。为党永葆生机活力、走好新的赶考之路,全面从严治党是必由之路。要兴党强党,保证党的先进性和纯洁性,就必须实事求是认识和把握自己,以勇于自我革命的精神打造和锤炼自己。</p><p style="margin: 10px auto; font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; font-size: 16px; line-height: 34.2px; font-family: &quot;Microsoft Yahei&quot; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255);">在我国云南边境地带,还残存着对越战争时期遗留的雷场,给当地的人民群众造成了生命财产安全威胁。雷场中地雷种类复杂,除了常规军用地雷外还有相当一部分游击队的自制地雷等,也给排雷作业造成了巨大影响。</p>'
  112. );
  113. const tabSelect = ref([true, true, true, true]);
  114. const untreatedError = ref([]);
  115. const ignoreError = ref([]);
  116. const replaceError = ref([]);
  117. const deleteError = ref([]);
  118. const errorTotle = ref({
  119. serious: 0,
  120. same: 0,
  121. distrust: 0,
  122. custom: 0,
  123. });
  124. const tabAct = ref(0);
  125. let lastAtom = ref(-1);
  126. // 清理数据
  127. function clearError() {
  128. rawText.value = '';
  129. untreatedError.value = [];
  130. ignoreError.value = [];
  131. replaceError.value = [];
  132. deleteError.value = [];
  133. }
  134. // 获取数据
  135. function getServer() {
  136. if (!window.fetch || !rawText.value) return;
  137. errorTotle.value = {
  138. serious: 0,
  139. same: 0,
  140. distrust: 0,
  141. custom: 0,
  142. };
  143. untreatedError.value = [];
  144. ignoreError.value = [];
  145. replaceError.value = [];
  146. deleteError.value = [];
  147. check({
  148. data: {
  149. text: rawText.value,
  150. },
  151. }).then(res => {
  152. const list = res.checklist || [];
  153. let rawTextF = res.rawText || '';
  154. console.log(list);
  155. for (let i = 0; i < list.length; i++) {
  156. const v = list[i];
  157. const r = new RegExp(`data-umpos="${v.colorPosition}"`, 'g');
  158. let rText = `data-umpos="${
  159. v.colorPosition
  160. }" style="border-bottom: 3px solid rgb(${errType[v.um_error_level]});`;
  161. if (i == 0) {
  162. rText += `background-color: rgba(${errType[v.um_error_level]}, 0.5)`;
  163. lastAtom.value = v.colorPosition;
  164. }
  165. rText += `"`;
  166. rawTextF = rawTextF.replace(r, rText);
  167. if (v.um_error_level == 1) errorTotle.value.serious++;
  168. if (v.um_error_level == 2) errorTotle.value.same++;
  169. if (v.um_error_level == 3) errorTotle.value.distrust++;
  170. if (v.um_error_level == 4) errorTotle.value.custom++;
  171. }
  172. rawText.value = rawTextF;
  173. untreatedError.value = list;
  174. ignoreError.value = [];
  175. replaceError.value = [];
  176. deleteError.value = [];
  177. });
  178. }
  179. // 选中的文案
  180. function selectErrorFunc(data) {
  181. const newele = getEle(data.colorPosition);
  182. if (newele === null) return;
  183. let oldele = null;
  184. if (lastAtom.value != -1) {
  185. oldele = document.querySelector(`[data-umpos='${lastAtom.value}']`);
  186. oldele.style.backgroundColor = '';
  187. }
  188. newele.style.backgroundColor = `rgba(${errType[data.um_error_level]}, 0.5)`;
  189. lastAtom.value = data.colorPosition;
  190. }
  191. // 替换文案
  192. function replaceText(data) {
  193. const newele = getEle(data.item.colorPosition);
  194. if (newele === null) return;
  195. const fDoc = document.querySelector('.Fle .text');
  196. const outerHTML = newele.outerHTML || '';
  197. newele.outerHTML = `<span data-umpos="${data.item.colorPosition}">${
  198. data.item.suggest[data.index]
  199. }</span>`;
  200. rawText.value = fDoc.innerHTML;
  201. removeList(data.name, data.pindex, data.item);
  202. replaceError.value.push({ ...data.item, outerHTML });
  203. }
  204. // 忽略
  205. function ignoreText(data) {
  206. const newele = getEle(data.item.colorPosition);
  207. if (newele === null) return;
  208. const fDoc = document.querySelector('.Fle .text');
  209. const outerHTML = newele.outerHTML || '';
  210. newele.outerHTML = `<span data-umpos="${data.item.colorPosition}">${newele.innerHTML}</span>`;
  211. rawText.value = fDoc.innerHTML;
  212. removeList(data.name, data.pindex, data.item);
  213. ignoreError.value.push({ ...data.item, outerHTML });
  214. }
  215. // 删除
  216. function deleteText(data) {
  217. const newele = getEle(data.item.colorPosition);
  218. if (newele === null) return;
  219. const fDoc = document.querySelector('.Fle .text');
  220. const outerHTML = newele.outerHTML || '';
  221. newele.outerHTML = `<span data-umpos="${data.item.colorPosition}"></span>`;
  222. rawText.value = fDoc.innerHTML;
  223. removeList(data.name, data.pindex, data.item);
  224. deleteError.value.push({ ...data.item, outerHTML });
  225. }
  226. // 恢复
  227. function resumeText(data) {
  228. const newele = getEle(data.item.colorPosition);
  229. if (newele === null) return;
  230. const fDoc = document.querySelector('.Fle .text');
  231. newele.outerHTML = data.item.outerHTML;
  232. rawText.value = fDoc.innerHTML;
  233. removeList(data.name, data.pindex, data.item);
  234. untreatedError.value.push(data.item);
  235. }
  236. // remove list
  237. function removeList(key, index, item) {
  238. const C = lastAtom.value !== item.colorPosition;
  239. if (key === 'deleteError') {
  240. deleteError.value.splice(index, 1);
  241. if (C) return;
  242. deleteError.value[0] && selectErrorFunc(deleteError.value[0]);
  243. return;
  244. }
  245. if (key === 'ignoreError') {
  246. ignoreError.value.splice(index, 1);
  247. if (C) return;
  248. ignoreError.value[0] && selectErrorFunc(ignoreError.value[0]);
  249. return;
  250. }
  251. if (key === 'replaceError') {
  252. replaceError.value.splice(index, 1);
  253. if (C) return;
  254. replaceError.value[0] && selectErrorFunc(replaceError.value[0]);
  255. return;
  256. }
  257. if (key === 'untreatedError') {
  258. untreatedError.value.splice(index, 1);
  259. if (C) return;
  260. untreatedError.value[0] && selectErrorFunc(untreatedError.value[0]);
  261. return;
  262. }
  263. }
  264. // 获得选中的元素
  265. function getEle(colorPosition) {
  266. const newele = document.querySelector(`[data-umpos='${colorPosition}']`);
  267. if (!newele) return null;
  268. return newele;
  269. }
  270. </script>
  271. <style scoped>
  272. .onlineTextMain {
  273. padding: 1em;
  274. display: flex;
  275. }
  276. .onlineTextMain > div {
  277. flex: 3;
  278. margin-right: 0.5em;
  279. border: 1px solid #eee;
  280. height: calc(100vh - 106px);
  281. }
  282. .onlineTextMain .flex2 {
  283. flex: 2;
  284. overflow: hidden;
  285. }
  286. .onlineTextMain > div:last-child {
  287. margin-right: 0;
  288. }
  289. .btn-grounp {
  290. color: #666;
  291. background-color: #f9fafc;
  292. line-height: 2.8em;
  293. padding-left: 0.5em;
  294. border-bottom: 1px solid #eee;
  295. }
  296. .flex1 {
  297. line-height: 1.5em;
  298. min-height: 1.5em;
  299. }
  300. .flex1 span {
  301. display: inline-block;
  302. }
  303. .Fle {
  304. height: calc(100vh-226px);
  305. }
  306. .clearError {
  307. float: right;
  308. }
  309. .errTypes {
  310. display: flex;
  311. padding: 0 0 1em 0;
  312. }
  313. .errType {
  314. flex: 1;
  315. font-size: 12px;
  316. margin-right: 3px;
  317. border: 1px solid;
  318. padding: 0 0.5em;
  319. text-align: center;
  320. border-radius: 5px;
  321. line-height: 2.5em;
  322. cursor: pointer;
  323. color: #909090;
  324. background-color: hsla(0, 0%, 56.5%, 0.1);
  325. }
  326. .errTypes .checkboxLabel0 {
  327. color: rgb(255, 68, 99);
  328. border-color: rgb(255, 68, 99);
  329. background-color: rgba(255, 68, 99, 0.1);
  330. }
  331. .errTypes .checkboxLabel1 {
  332. color: rgb(145, 155, 218);
  333. border-color: rgb(145, 155, 218);
  334. background-color: rgba(145, 155, 218, 0.1);
  335. }
  336. .errTypes .checkboxLabel2 {
  337. color: rgb(255, 152, 0);
  338. border-color: rgb(255, 152, 0);
  339. background-color: rgba(255, 152, 0, 0.1);
  340. }
  341. .errTypes .checkboxLabel3 {
  342. color: rgb(156, 133, 255);
  343. border-color: rgb(156, 133, 255);
  344. background-color: rgba(156, 133, 255, 0.1);
  345. }
  346. </style>
  347. <style>
  348. .edito_youmei .el-popper.is-light,
  349. .edito_youmei .el-popper .el-popper__arrow::before {
  350. background-color: #2974ff !important;
  351. color: #fff;
  352. border-color: #2974ff !important;
  353. }
  354. .el-poper .selectSpan {
  355. border-bottom: 3px solid #fff;
  356. }
  357. </style>