Pdf2Word.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. <template>
  2. <!-- <el-dialog v-model="isOpen" title="文字识别" width="55%"> -->
  3. <div class="container">
  4. <div v-if="thisStep === 'start'" class="up_box">
  5. <div class="left_box">
  6. <div class="upimg_box boder_box">
  7. <!-- <el-upload
  8. v-if="!showImg"
  9. class="avatar-uploader"
  10. :drag="true"
  11. :action="actionUrl"
  12. :headers="headersObj"
  13. accept=".pdf, .PDF"
  14. :show-file-list="false"
  15. :on-success="handleAvatarSuccess"
  16. :before-upload="beforeUp"
  17. >
  18. <img src="@/assets/images/Frame427319159.png" class="avatar" />
  19. <span>将文件拖入框内/点击按钮上传文件</span>
  20. </el-upload> -->
  21. <el-upload
  22. v-if="!showImg"
  23. class="avatar-uploader"
  24. :drag="true"
  25. :http-request="test"
  26. accept=".pdf, .PDF"
  27. :show-file-list="false"
  28. :before-upload="beforeUp"
  29. >
  30. <img src="@/assets/images/pdf2word.png" class="avatar" />
  31. <span>将文件拖入框内/点击按钮上传文件</span>
  32. </el-upload>
  33. <div v-else class="img_show">
  34. <img :src="toRaw(showImg)" class="avatar" />
  35. </div>
  36. </div>
  37. <div class="sunmit_btn">
  38. <el-upload
  39. class="avatar-uploader"
  40. :http-request="test"
  41. accept=".pdf, .PDF"
  42. :show-file-list="false"
  43. :before-upload="beforeUp"
  44. >
  45. <span>选择本地文件</span>
  46. </el-upload>
  47. </div>
  48. </div>
  49. <div class="right_box">
  50. <div class="upimg_box boder_box">
  51. <el-upload
  52. disabled
  53. class="avatar-uploader"
  54. :action="actionUrl"
  55. :show-file-list="false"
  56. :on-success="handleAvatarSuccess"
  57. >
  58. <img @click="addlibraryImg" src="@/assets/images/cloudp2w.png" class="avatar" />
  59. <span>点击按钮选择文件</span>
  60. </el-upload>
  61. </div>
  62. <div class="sunmit_btn hand" @click="addlibraryImg">添加文库文件</div>
  63. </div>
  64. <!-- <el-button @click="test">测试</el-button> -->
  65. </div>
  66. <div v-if="thisStep === 'loading'" class="load-box">
  67. <div class="light_box">
  68. <img :src="toRaw(showImg)" class="avatar" />
  69. <div class="light"></div>
  70. </div>
  71. <div class="text_box">
  72. <span>请耐心等待扫描完成</span>
  73. <Loading :small="true"></Loading>
  74. </div>
  75. </div>
  76. <div v-if="thisStep === 'end'" class="end_box">
  77. <div class="left_box">
  78. <div class="boder_box">
  79. <div class="title">原始图片</div>
  80. <div class="upimg_box">
  81. <div class="img_show">
  82. <img :src="toRaw(showImg)" class="avatar" />
  83. </div>
  84. </div>
  85. </div>
  86. <div class="sunmit_btn">
  87. <!-- <el-upload
  88. class="avatar-uploader"
  89. action="http://192.168.1.28:8080/api/upload"
  90. :show-file-list="false"
  91. :on-success="handleAvatarSuccess"
  92. :before-upload="beforeUp"
  93. > -->
  94. <span @click="reClick" class="hand">重新选择</span>
  95. <!-- </el-upload> -->
  96. </div>
  97. </div>
  98. <div class="right_box">
  99. <div class="boder_box">
  100. <div class="title" >识别结果</div>
  101. <div class="upimg_box">
  102. <el-scrollbar>
  103. <div class="text_box">
  104. {{ textData }}
  105. </div>
  106. </el-scrollbar>
  107. </div>
  108. </div>
  109. <div class="sunmit_btn copy-qb hand" @click="copyQbUrl()">复制结果</div>
  110. </div>
  111. </div>
  112. </div>
  113. <!-- </el-dialog> -->
  114. <PicTree
  115. :openFile="openFile"
  116. @close="openFile = false"
  117. :fileUserTreeData="treeData"
  118. @fileChangeMsg="fileChangeMsg"
  119. ></PicTree>
  120. <div
  121. v-loading.fullscreen="loadingPreview"
  122. v-if="loadingPreview"
  123. class="lodingBox"
  124. ></div>
  125. </template>
  126. <script setup>
  127. import { onMounted, ref, toRaw, watch, inject } from "vue";
  128. import { ElMessage } from "element-plus";
  129. import Clipboard from "clipboard";
  130. import Loading from "@/components/Loading/Loading.vue";
  131. import PicTree from "@/components/PicTree/PicTree.vue"; //选择文件发送的列表
  132. import { picTree, pdfTree } from "@/api/search/search.js";
  133. import { ocrRemark, preview } from "@/api/common/common.js";
  134. import { getInfo } from "@/api/biz/info.js";
  135. import Cookies from "js-cookie";
  136. import axios from "axios";
  137. const textData = ref(""); //解析出来的文字
  138. const showImg = ref(); //上传的图片
  139. const isOpen = ref(props.openFile);
  140. const thisStep = ref("start"); //解析进度 start,loading,end,
  141. const openFile = ref(false); //控制tree显示
  142. const treeData = ref(); //树节点数据
  143. const actionUrl = ref(
  144. `${window.location.origin}${
  145. import.meta.env.VITE_APP_BASE_API
  146. }/biz/info/pdf2word`
  147. );
  148. const headersObj = ref({
  149. Authorization: Cookies.get("Admin-Token"),
  150. });
  151. // const actionUrl = ref(`${window.location.origin}/upload`);
  152. const loadingPreview = ref(false);
  153. const addFolderAdd = inject("addFolderAdd");
  154. const props = defineProps({
  155. openFile: {
  156. type: Boolean,
  157. default: false,
  158. },
  159. });
  160. watch(
  161. () => props.openFile,
  162. (newValue) => {
  163. // console.log(111);
  164. isOpen.value = newValue;
  165. }
  166. );
  167. const test = function (file) {
  168. // console.log("file", file);
  169. const url = `${window.location.origin}${
  170. import.meta.env.VITE_APP_BASE_API
  171. }/biz/info/pdf2word`;
  172. return axios({
  173. method: "post",
  174. url: url,
  175. responseType: "blob",
  176. data: file,
  177. headers: {
  178. Authorization: Cookies.get("Admin-Token"),
  179. "Content-Type": "multipart/form-data",
  180. },
  181. }).then(function (res) {
  182. // console.log("testres", res);
  183. if (res.headers["content-disposition"] !== undefined) {
  184. let blob = new Blob([res.data], {
  185. type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  186. });
  187. let fileName = decodeURI(res.headers["content-disposition"]);
  188. if (fileName) {
  189. fileName = fileName.substring(fileName.indexOf("=") + 1);
  190. fileName = fileName.substring(0, fileName.lastIndexOf("."));
  191. // alert(fileName)
  192. }
  193. const elink = document.createElement("a");
  194. // console.log("fileName", fileName);
  195. elink.download = fileName.replace(new RegExp('"', "g"), "") + ".docx";
  196. elink.style.display = "none";
  197. elink.href = URL.createObjectURL(blob);
  198. document.body.appendChild(elink);
  199. elink.click();
  200. URL.revokeObjectURL(elink.href);
  201. document.body.removeChild(elink);
  202. loadingPreview.value = false;
  203. }
  204. });
  205. };
  206. const fileId2Word = function (fileId) {
  207. // console.log("fileId", fileId);
  208. const url = `${window.location.origin}${
  209. import.meta.env.VITE_APP_BASE_API
  210. }/biz/info/pdf2word/${fileId}`;
  211. return axios({
  212. method: "get",
  213. url: url,
  214. responseType: "blob",
  215. headers: {
  216. Authorization: Cookies.get("Admin-Token"),
  217. "Content-Type": "multipart/form-data",
  218. },
  219. }).then(function (res) {
  220. // console.log("testres", res);
  221. if (res.headers["content-disposition"] !== undefined) {
  222. let blob = new Blob([res.data], {
  223. type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  224. });
  225. let fileName = decodeURI(res.headers["content-disposition"]);
  226. if (fileName) {
  227. fileName = fileName.substring(fileName.indexOf("=") + 1);
  228. fileName = fileName.substring(0, fileName.lastIndexOf("."));
  229. // alert(fileName)
  230. }
  231. const elink = document.createElement("a");
  232. // console.log("fileName", fileName);
  233. elink.download = fileName.replace(new RegExp('"', "g"), "") + ".docx";
  234. elink.style.display = "none";
  235. elink.href = URL.createObjectURL(blob);
  236. document.body.appendChild(elink);
  237. elink.click();
  238. URL.revokeObjectURL(elink.href);
  239. document.body.removeChild(elink);
  240. loadingPreview.value = false;
  241. }
  242. });
  243. };
  244. onMounted(async () => {});
  245. const handleAvatarSuccess = (msg, file) => {
  246. // console.log('re', msg)
  247. const flieData = toRaw(file);
  248. // console.log('file', flieData)
  249. // setTimeout(() => {
  250. // downLoadfile(flieData.raw,file);
  251. // }, 500);
  252. const blob = new Blob([msg]); //excel,pdf等
  253. const href = URL.createObjectURL(blob); //创建新的URL表示指定的blob对象
  254. const a = document.createElement("a"); //创建a标签
  255. a.style.display = "none";
  256. a.href = href; // 指定下载链接
  257. a.download = file.name + ".docx"; //指定下载文件名
  258. a.click(); //触发下载
  259. URL.revokeObjectURL(a.href); //释放URL对象
  260. ElMessage({ message: "转换成功,已下载到本地", type: "success" });
  261. loadingPreview.value = false;
  262. };
  263. //文件上传前的钩子
  264. const beforeUp = (raw) => {
  265. // console.log('raw',raw);
  266. // showImg.value = URL.createObjectURL(raw);
  267. loadingPreview.value = true;
  268. // thisStep.value = "loading";
  269. };
  270. // 复制功能调用的方法
  271. const copyQbUrl = () => {
  272. let clipboard = new Clipboard(".copy-qb", {
  273. text: () => {
  274. return textData.value;
  275. },
  276. });
  277. clipboard.on("success", () => {
  278. // console.log('success');
  279. ElMessage({ message: "复制成功", type: "success" });
  280. clipboard.destroy();
  281. });
  282. clipboard.on("error", () => {
  283. // console.log('err');
  284. clipboard.destroy();
  285. });
  286. };
  287. // 选取文库图片
  288. const addlibraryImg = async () => {
  289. const res = await pdfTree();
  290. // console.log("res", res);
  291. treeData.value = res;
  292. openFile.value = true;
  293. };
  294. //确定选中图片
  295. const fileChangeMsg = async (val) => {
  296. // console.log("val", toRaw(val));
  297. loadingPreview.value = true;
  298. fileId2Word(val.remark);
  299. // const res = await getInfo(val.id)
  300. // const data = toRaw(val)
  301. // const imgRes = await preview(data.id)
  302. // thisStep.value = 'loading'
  303. // showImg.value = URL.createObjectURL(imgRes)
  304. // const res = await ocrRemark(data.remark)
  305. // thisStep.value = 'end'
  306. // textData.value = res.msg
  307. // console.log("res", res);
  308. // console.log("imgRes", imgRes);
  309. };
  310. const reClick = () => {
  311. thisStep.value = "start";
  312. textData.value = null;
  313. showImg.value = null;
  314. };
  315. // 文件下载
  316. const downLoadfile = (res, file) => {
  317. // console.log('downLoadfileres',res);
  318. var reader = new FileReader();
  319. reader.onloadend = function (event) {
  320. //event 就是你要的返回内容
  321. //因为返回的报错格式是字符串,手动转换成对象,转换成功表示请求失败
  322. //转换失败就意味着你拿到的result是文件流,那么直接手动下载就好
  323. try {
  324. let data = JSON.parse(event.target.result);
  325. } catch (err) {
  326. const time = Date.now();
  327. // console.log('time',time);
  328. const link = document.createElement("a"); // 创建a标签
  329. let blob = new Blob([res]);
  330. link.style.display = "none";
  331. link.href = URL.createObjectURL(blob); // 创建下载的链接
  332. // link.setAttribute("download", clickRow.value.fileName); // 给下载后的文件命名
  333. link.setAttribute("download", file.name + ".docx"); // 给下载后的文件命名
  334. document.body.appendChild(link);
  335. link.click(); // 点击下载
  336. document.body.removeChild(link); // 完成移除元素
  337. window.URL.revokeObjectURL(link.href); // 释放blob对象
  338. }
  339. };
  340. // console.log('downLoadfileres',res);
  341. reader.readAsText(res);
  342. };
  343. </script>
  344. <style lang="scss" scoped>
  345. .lodingBox {
  346. position: absolute;
  347. top: 0;
  348. left: 0;
  349. width: 100vh;
  350. height: 100vh;
  351. z-index: 10000000;
  352. }
  353. .container {
  354. width: 100%;
  355. height: 87vh;
  356. background-color: #fff;
  357. display: flex;
  358. align-items: center;
  359. justify-content: center;
  360. .up_box {
  361. display: flex;
  362. width: 100%;
  363. justify-content: center;
  364. }
  365. .left_box {
  366. width: 45%;
  367. display: flex;
  368. flex-direction: column;
  369. align-items: center;
  370. margin-right: 48px;
  371. .boder_box {
  372. width: 100%;
  373. border: 1px solid #c1cce3;
  374. }
  375. .title {
  376. width: 100%;
  377. height: 40px;
  378. background: #ebeff6;
  379. line-height: 40px;
  380. font-size: 16px;
  381. font-weight: 400;
  382. text-align: center;
  383. }
  384. .img_show {
  385. width: 100%;
  386. height: calc(100% - 40px);
  387. display: flex;
  388. align-items: center;
  389. justify-content: center;
  390. img {
  391. width: 100%;
  392. max-height: 100%;
  393. // opacity: 0;
  394. // object-fit:cover; // 保持原比例缩小
  395. object-fit: contain; // 保持原比例缩小
  396. }
  397. }
  398. .upimg_box {
  399. width: 100%;
  400. height: 500px;
  401. display: flex;
  402. align-items: center;
  403. justify-content: center;
  404. }
  405. .sunmit_btn {
  406. margin-top: 24px;
  407. width: 120px;
  408. height: 32px;
  409. background: #2e6bc8;
  410. border-radius: 4px 4px 4px 4px;
  411. color: #fff;
  412. font-size: 14px;
  413. line-height: 32px;
  414. font-weight: 400;
  415. text-align: center;
  416. }
  417. }
  418. .right_box {
  419. width: 45%;
  420. display: flex;
  421. flex-direction: column;
  422. align-items: center;
  423. .boder_box {
  424. width: 100%;
  425. border: 1px solid #c1cce3;
  426. }
  427. .title {
  428. width: 100%;
  429. height: 40px;
  430. background: #ebeff6;
  431. line-height: 40px;
  432. font-size: 16px;
  433. font-weight: 400;
  434. text-align: center;
  435. }
  436. .upimg_box {
  437. width: 100%;
  438. height: 500px;
  439. // border: 1px solid #c1cce3;
  440. display: flex;
  441. align-items: center;
  442. justify-content: center;
  443. }
  444. .sunmit_btn {
  445. margin-top: 24px;
  446. width: 120px;
  447. height: 32px;
  448. background: #2e6bc8;
  449. border-radius: 4px 4px 4px 4px;
  450. color: #fff;
  451. font-size: 14px;
  452. line-height: 32px;
  453. font-weight: 400;
  454. text-align: center;
  455. }
  456. .text_box {
  457. padding: 16px;
  458. font-size: 14px;
  459. font-weight: 500;
  460. color: #000000;
  461. line-height: 22px;
  462. }
  463. }
  464. .load-box {
  465. display: flex;
  466. align-items: center;
  467. // justify-content: center;
  468. flex-direction: column;
  469. .text_box {
  470. width: 100%;
  471. margin-top: 20px;
  472. color: #06286c;
  473. display: flex;
  474. justify-content: center;
  475. align-items: center;
  476. span {
  477. margin-right: 15px;
  478. }
  479. }
  480. .light_box {
  481. width: 500px;
  482. height: 500px;
  483. background-image: url("@/assets/images/light_boder.png");
  484. background-repeat: no-repeat;
  485. background-size: contain;
  486. position: relative;
  487. display: flex;
  488. align-items: center;
  489. justify-content: center;
  490. padding: 0 15px;
  491. img {
  492. width: 100%;
  493. height: 100%;
  494. object-fit: contain; // 保持原比例缩小
  495. }
  496. .light {
  497. width: calc(100% - 30px);
  498. height: 1px;
  499. position: absolute;
  500. top: 0;
  501. left: 15px;
  502. right: 0;
  503. bottom: 0;
  504. background-color: rgba(0, 255, 255, 0.7);
  505. box-shadow: 0px 2px 10px 5px rgba(0, 255, 255, 0.3);
  506. animation: move 2s infinite linear;
  507. }
  508. @keyframes move {
  509. from {
  510. top: 0px;
  511. }
  512. /*网格移动到显示区域的外面*/
  513. to {
  514. top: 100%;
  515. }
  516. }
  517. }
  518. }
  519. .end_box {
  520. display: flex;
  521. justify-content: center;
  522. width: 100%;
  523. }
  524. }
  525. :deep(.el-dialog__header) {
  526. background-color: #eceff7;
  527. margin-right: 0px;
  528. }
  529. .avatar-uploader .el-upload {
  530. border: 1px dashed var(--el-border-color);
  531. border-radius: 6px;
  532. cursor: pointer;
  533. position: relative;
  534. overflow: hidden;
  535. transition: var(--el-transition-duration-fast);
  536. }
  537. ::v-deep .avatar-uploader .el-upload {
  538. display: flex;
  539. flex-direction: column;
  540. img {
  541. width: 220;
  542. height: 220px;
  543. margin-bottom: 16px;
  544. }
  545. span {
  546. font-size: 12px;
  547. font-weight: 400;
  548. color: #06286c;
  549. }
  550. }
  551. ::v-deep .sunmit_btn .avatar-uploader .el-upload {
  552. span {
  553. font-size: 14px;
  554. font-weight: 400;
  555. color: #fff;
  556. }
  557. }
  558. ::v-deep .avatar-uploader .el-upload .el-upload-dragger {
  559. display: flex;
  560. flex-direction: column;
  561. align-items: center;
  562. border: none;
  563. }
  564. .avatar-uploader .el-upload:hover {
  565. border-color: var(--el-color-primary);
  566. }
  567. .el-icon.avatar-uploader-icon {
  568. font-size: 28px;
  569. color: #8c939d;
  570. width: 178px;
  571. height: 178px;
  572. text-align: center;
  573. }
  574. .hand{
  575. cursor: pointer;
  576. }
  577. </style>