OcrTest.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. <template>
  2. <el-dialog
  3. class="page-dialog"
  4. custom-class="ocr-test-dialog"
  5. :visible.sync="modalIsShow"
  6. :close-on-click-modal="false"
  7. :close-on-press-escape="false"
  8. append-to-body
  9. fullscreen
  10. @closed="visibleChange()"
  11. :title="'OCR测试 - ' + curRow.name"
  12. >
  13. <div class="body">
  14. <div class="left" v-loading="loading" ref="dragOuter">
  15. <div
  16. class="drag-wrap"
  17. ref="wrapper"
  18. v-if="imageUrl"
  19. @wheel.prevent="scaleHandle($event)"
  20. >
  21. <el-upload
  22. class="reset"
  23. ref="uploadButton"
  24. action=""
  25. :show-file-list="false"
  26. :on-success="handleSuccess"
  27. :before-upload="beforeUpload"
  28. accept="image/*"
  29. :auto-upload="false"
  30. :multiple="false"
  31. :on-change="onChange"
  32. :http-request="customSubmit"
  33. >
  34. <el-button type="primary" size="mini">重新上传</el-button>
  35. </el-upload>
  36. <div class="box" ref="centerBox" @mousedown="dragstart($event)">
  37. <img
  38. :src="imageUrl"
  39. class="avatar"
  40. @load="initImgSize"
  41. :style="{
  42. maxWidth: maxWidth + 'px',
  43. maxHeight: maxHeight + 'px',
  44. }"
  45. />
  46. </div>
  47. </div>
  48. <el-upload
  49. v-else
  50. ref="upload"
  51. action=""
  52. class="avatar-uploader"
  53. :show-file-list="false"
  54. :on-success="handleSuccess"
  55. :before-upload="beforeUpload"
  56. accept="image/*"
  57. :auto-upload="false"
  58. :multiple="false"
  59. :on-change="onChange"
  60. :http-request="customSubmit"
  61. drag
  62. >
  63. <!-- <img
  64. v-if="imageUrl"
  65. :src="imageUrl"
  66. class="avatar animate__animated animate__backInLeft"
  67. /> -->
  68. <i class="el-icon-plus avatar-uploader-icon"></i>
  69. </el-upload>
  70. </div>
  71. <div class="right">
  72. <div>
  73. <el-select v-model="type" :disabled="loading">
  74. <el-option value="GENERAL" label="通用"></el-option>
  75. <el-option value="HANDWRITING" label="手写"></el-option>
  76. </el-select>
  77. <el-button
  78. type="primary"
  79. style="margin-left: 10px"
  80. :disabled="!file || loading"
  81. @click="submit"
  82. >开始识别</el-button
  83. >
  84. </div>
  85. <div style="height: calc(100% - 32px)">
  86. <el-link
  87. :underline="false"
  88. type="success"
  89. style="margin-top: 20px; margin-bottom: 5px"
  90. >识别结果:</el-link
  91. >
  92. <div v-html="resultText" class="result-text"></div>
  93. </div>
  94. </div>
  95. </div>
  96. </el-dialog>
  97. </template>
  98. <script>
  99. import { orgTestApi } from "../api";
  100. export default {
  101. name: "ocr-test",
  102. props: {
  103. curRow: {
  104. type: Object,
  105. default() {
  106. return {};
  107. },
  108. },
  109. },
  110. data() {
  111. return {
  112. modalIsShow: false,
  113. file: null,
  114. imageUrl: "",
  115. type: "GENERAL",
  116. resultText: "",
  117. loading: false,
  118. key: "",
  119. timer: null,
  120. index: 0,
  121. scale: 1,
  122. scaleNum: 0.25, // 缩放比例
  123. scaleMax: 10, // 最大缩放比例
  124. scaleMin: 0.1, // 最小缩放比例
  125. dragData: {
  126. x: 0, // 拖拽初始化时的x坐标
  127. y: 0, // 拖拽初始化时的y坐标
  128. left: 0, // 拖拽结束时的x偏移量
  129. top: 0, // 拖拽结束时的y偏移量
  130. },
  131. maxWidth: 0,
  132. maxHeight: 0,
  133. };
  134. },
  135. computed: {
  136. title() {
  137. return `应用nginx配置-${this.app.name}`;
  138. },
  139. },
  140. mounted() {},
  141. methods: {
  142. initImgSize() {
  143. this.maxWidth = this.$refs.dragOuter.offsetWidth - 40;
  144. this.maxHeight = this.$refs.dragOuter.offsetHeight - 40;
  145. },
  146. scaleDom() {
  147. this.$refs.centerBox.style.transform = `translate(-50%, -50%) scale(${this.scale})`;
  148. },
  149. scaleHandle(e) {
  150. let dy = -e.deltaY || e.wheelDeltaY;
  151. if (dy < 0) {
  152. this.scale -= this.scaleNum;
  153. } else {
  154. this.scale += this.scaleNum;
  155. }
  156. if (this.scale >= this.scaleMax) {
  157. this.scale = this.scaleMax;
  158. return;
  159. }
  160. if (this.scale <= this.scaleMin) {
  161. this.scale = this.scaleMin;
  162. return;
  163. }
  164. this.$refs.centerBox.style.transition = "none";
  165. this.scaleDom();
  166. return false;
  167. },
  168. dragstart(e) {
  169. this.$refs.centerBox.style.transition = "none";
  170. e.preventDefault();
  171. this.dragData.x = e.pageX - this.$refs.centerBox.offsetLeft;
  172. this.dragData.y = e.pageY - this.$refs.centerBox.offsetTop;
  173. // 给 document 添加鼠标移动事件
  174. document.addEventListener("mousemove", move);
  175. const _this = this;
  176. function move(event) {
  177. // 计算元素的位置
  178. _this.dragData.left = event.pageX - _this.dragData.x;
  179. _this.dragData.top = event.pageY - _this.dragData.y;
  180. // 边界判断可以在这里添加 ↓
  181. // 设置元素的位置
  182. _this.$refs.centerBox.style.left = _this.dragData.left + "px";
  183. _this.$refs.centerBox.style.top = _this.dragData.top + "px";
  184. }
  185. // 添加鼠标抬起事件,鼠标抬起,将事件移除
  186. document.addEventListener("mouseup", function () {
  187. document.removeEventListener("mousemove", move);
  188. });
  189. // 鼠标离开父级元素,把事件移除
  190. document.addEventListener("mouseout", function () {
  191. document.removeEventListener("mousemove", move);
  192. });
  193. },
  194. async visibleChange(visible) {
  195. this.file = null;
  196. this.imageUrl = "";
  197. this.type = "GENERAL";
  198. this.resultText = "";
  199. this.clear();
  200. this.key = "";
  201. },
  202. cancel() {
  203. this.modalIsShow = false;
  204. },
  205. open() {
  206. this.modalIsShow = true;
  207. },
  208. handleSuccess(res, file) {
  209. console.log("handleSuccess", file);
  210. },
  211. beforeUpload(file) {
  212. const isLt20M = file.size / 1024 / 1024 < 20;
  213. if (!isLt20M) {
  214. this.$message.error("上传头像图片大小不能超过 20MB!");
  215. }
  216. return isLt20M;
  217. },
  218. submit() {
  219. // this.$refs.upload.submit();
  220. this.resultText = "";
  221. this.key = Math.random() + "";
  222. this.loading = true;
  223. orgTestApi({
  224. id: this.curRow.id,
  225. type: this.type,
  226. image: this.file,
  227. })
  228. .then((res) => {
  229. if (res && res.text) {
  230. let initText = (res.text || "").replaceAll(/\n/g, "<br />");
  231. this.writing(initText, this.key);
  232. }
  233. })
  234. .finally(() => {
  235. this.loading = false;
  236. });
  237. },
  238. customSubmit(option) {
  239. this.resultText = "";
  240. this.key = Math.random() + "";
  241. this.loading = true;
  242. orgTestApi({
  243. id: this.curRow.id,
  244. type: this.type,
  245. image: option.file,
  246. })
  247. .then((res) => {
  248. if (res && res.text) {
  249. let initText = (res.text || "").replaceAll(/\n/g, "<br />");
  250. this.writing(initText, this.key);
  251. }
  252. })
  253. .finally(() => {
  254. this.loading = false;
  255. });
  256. },
  257. onChange(file, fileList) {
  258. this.imageUrl = "";
  259. console.log("file", file);
  260. this.file = file.raw;
  261. this.$nextTick(() => {
  262. this.imageUrl = URL.createObjectURL(file.raw);
  263. });
  264. },
  265. clear() {
  266. if (this.timer) {
  267. clearInterval(this.timer);
  268. this.timer = null;
  269. }
  270. },
  271. writing(data, key) {
  272. // if (index < data.length && !this.reset) {
  273. // this.resultText = this.resultText + data.slice(index, index + 10);
  274. // setTimeout(() => {
  275. // this.writing(index + 10, data);
  276. // }, 20);
  277. // }
  278. this.clear();
  279. this.index = 0;
  280. this.timer = setInterval(() => {
  281. if (key !== this.key) {
  282. this.clear();
  283. return;
  284. }
  285. this.resultText =
  286. this.resultText + data.slice(this.index, this.index + 20);
  287. this.index = this.index + 20;
  288. }, 50);
  289. },
  290. },
  291. beforeDestroy() {
  292. this.clear();
  293. this.key = "";
  294. },
  295. };
  296. </script>
  297. <style lang="scss">
  298. .ocr-test-dialog {
  299. .el-dialog__title {
  300. font-size: 16px;
  301. }
  302. .el-dialog__body {
  303. height: calc(100vh - 2px);
  304. .body {
  305. height: 100%;
  306. display: flex;
  307. .left,
  308. .right {
  309. width: calc(50% - 10px);
  310. background-color: #fff;
  311. border-radius: 8px;
  312. }
  313. .right {
  314. margin-left: 20px;
  315. padding: 20px;
  316. .result-text {
  317. height: calc(100% - 44px);
  318. overflow: auto;
  319. font-size: 16px;
  320. line-height: 1.5;
  321. }
  322. }
  323. .left {
  324. padding: 20px;
  325. .drag-wrap {
  326. width: 100%;
  327. height: 100%;
  328. position: relative;
  329. overflow: hidden;
  330. &:hover {
  331. .reset {
  332. // display: block;
  333. opacity: 1;
  334. }
  335. }
  336. .reset {
  337. position: absolute;
  338. right: 10px;
  339. top: 10px;
  340. z-index: 10000;
  341. // display: none;
  342. transition: all 0.3s;
  343. opacity: 0;
  344. }
  345. .box {
  346. user-select: none; /* 不可选中,为了拖拽时不让文字高亮 */
  347. position: absolute;
  348. cursor: move;
  349. top: 50%;
  350. left: 50%;
  351. transform: translate(-50%, -50%);
  352. & > img {
  353. // max-width: none;
  354. // max-height: none;
  355. }
  356. }
  357. }
  358. .avatar-uploader {
  359. width: 100%;
  360. height: 100%;
  361. }
  362. .avatar-uploader .el-upload {
  363. // border: 1px dashed #d9d9d9;
  364. border-radius: 6px;
  365. cursor: pointer;
  366. position: relative;
  367. overflow: hidden;
  368. height: 100%;
  369. .el-upload-dragger {
  370. height: 100%;
  371. display: flex;
  372. justify-content: center;
  373. align-items: center;
  374. }
  375. & .avatar {
  376. // max-width: 100%;
  377. // max-height: 100%;
  378. user-select: none;
  379. width: 100%;
  380. height: 100%;
  381. display: block;
  382. }
  383. }
  384. .avatar-uploader .el-upload:hover {
  385. border-color: #409eff;
  386. }
  387. .avatar-uploader-icon {
  388. font-size: 50px;
  389. color: #8c939d;
  390. width: 178px;
  391. height: 178px;
  392. line-height: 178px;
  393. text-align: center;
  394. }
  395. }
  396. }
  397. }
  398. }
  399. </style>
  400. <style scoped lang="scss"></style>