index.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
  8. <script type="text/javascript" async
  9. src="https://mingxuejingbang.oss-cn-beijing.aliyuncs.com/MathJaxFiles/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>
  10. <script type="text/javascript" async src="js/globalVariable.js"></script>
  11. <script type="text/javascript" async src="js/html2canvas.min.js"></script>
  12. <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  13. <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  14. <script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
  15. <title></title>
  16. <style>
  17. html,
  18. body {
  19. margin: 0;
  20. padding: 0
  21. }
  22. .el-radio--medium.is-bordered {
  23. height: auto;
  24. padding-bottom: 8px;
  25. }
  26. #title::after {
  27. display: table;
  28. content: "";
  29. clear: both;
  30. }
  31. </style>
  32. </head>
  33. <body>
  34. <div id="app">
  35. <div style="min-height:300px;">
  36. <div id="title" style="background:#fff;max-width:1024px">
  37. <div id="qs" style="padding-bottom: 15px" v-html="data.title"></div>
  38. <div id="ans" style="background:#fff">
  39. <template v-for="(itemOpt, idx) in data.options">
  40. <div :key="idx">
  41. <el-radio style="margin-bottom: 15px" :label="selectOpt[idx]" border size="medium">
  42. {{ selectOpt[idx] + ' 、 ' }}<span style="white-space: normal" v-html="itemOpt"></span>
  43. </el-radio>
  44. </div>
  45. </template>
  46. </div>
  47. </div>
  48. </div>
  49. <div style="margin-bottom:20px;padding: 15px;background: rgb(255, 255, 255); max-width: 1024px;">
  50. <el-input v-model="questionId" style="width: 150px;" placeholder="请输入题目编号"></el-input>
  51. <el-button type="primary" :disabled="isAuto" @click="search">搜索</el-button>
  52. <el-button type="primary" :disabled="isAuto" @click="upLoad">手动上传</el-button>
  53. <el-button type="primary" @click="auto">{{isAuto?'暂停':'自动运行'}}</el-button>
  54. </div>
  55. <div v-if="imgUri" style="margin-top:30px;padding: 15px;background: rgb(255, 255, 255); max-width: 1024px;">
  56. 图片展示:
  57. <img :src="imgUri" alt="" crossorigin="anonymous">
  58. </div>
  59. </div>
  60. <script>
  61. var exampleData = {
  62. selectOpt: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
  63. data: {},
  64. time: null,
  65. domain: '',
  66. isAuto: false,
  67. questionId: '52635',
  68. imgUri: '',
  69. times: 1,
  70. }
  71. // window.onload = function(){
  72. new Vue({
  73. el: '#app',
  74. data: exampleData,
  75. created() {
  76. // if(this.domain == 'localhost:9800'){
  77. this.domain = 'https://front.mingxuejinbang.com'
  78. // }
  79. // this.getData()
  80. },
  81. methods: {
  82. convertImgToBase64(img) {
  83. return new Promise((resolve, reject) => {
  84. let canvas = document.createElement('canvas');
  85. const ctx = canvas.getContext('2d');
  86. canvas.height = img.height;
  87. canvas.width = img.width;
  88. ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
  89. let ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();
  90. const base64 = canvas.toDataURL("image/" + ext);
  91. canvas = null;
  92. const holder = new Image();
  93. holder.setAttribute('crossOrigin', 'anonymous')
  94. holder.onload = (e) => {
  95. resolve(holder)
  96. }
  97. holder.src = base64;
  98. // return base64;
  99. });
  100. },
  101. hasImg(dom) {
  102. for (let i of dom?.children || []) {
  103. if (i.nodeName === 'IMG') {
  104. return true;
  105. }
  106. }
  107. return false;
  108. },
  109. getCanvasWrap(width, height) {
  110. const canvasWrap = document.createElement('canvas')
  111. canvasWrap.width = this.times * width
  112. canvasWrap.height = this.times * height
  113. canvasWrap.getContext('2d').scale(this.times, this.times)
  114. return canvasWrap;
  115. },
  116. getUnderline(num) {
  117. const underline = document.createElement('div');
  118. // 暂定于1个空格5像素
  119. underline.setAttribute('style', `width: ${num * 5}px;border-bottom: 1px solid #000000;display: inline-block;vertical-align: baseline;transform: translateY(2px);`);
  120. return underline;
  121. },
  122. // 遍历所有子元素
  123. findAllEle(promiseArr, parent) {
  124. for (let i of parent.childNodes) {
  125. if (i.nodeName === 'U') {
  126. parent.insertBefore(this.getUnderline(i.innerText.length), i);
  127. parent.removeChild(i);
  128. } else if (i.nodeName === 'IMG') {
  129. const promise = new Promise((resolve, reject) => {
  130. i.onload = async (e) => {
  131. // 如果图片存在浮动,需要手动设置容器的高度
  132. if (i.style.float) {
  133. const qs = document.querySelector('#qs');
  134. qs.style.height = Math.max(qs.getBoundingClientRect().height, i.height) + 'px'
  135. }
  136. const { width, height } = qs.getBoundingClientRect();
  137. html2canvas(qs, {
  138. canvas: this.getCanvasWrap(width, height),
  139. useCORS: true,
  140. }).then((canvas) => {
  141. resolve(canvas)
  142. })
  143. }
  144. });
  145. promiseArr.push(promise);
  146. }
  147. if (i.hasChildNodes()) {
  148. this.findAllEle(promiseArr, i);
  149. }
  150. }
  151. },
  152. waitingLoaingImg(cb) {
  153. let doms;
  154. let parent;
  155. const qs = document.querySelector('#qs');
  156. // 每次重置容器高度
  157. qs.style.height = 'auto';
  158. const promiseArr = [];
  159. this.findAllEle(promiseArr, qs);
  160. if (promiseArr.length === 0) {
  161. const { width, height } = qs.getBoundingClientRect();
  162. html2canvas(qs, {
  163. canvas: this.getCanvasWrap(width, height),
  164. useCORS: true,
  165. }).then((canvas) => {
  166. if (cb) {
  167. cb(canvas)
  168. }
  169. })
  170. } else {
  171. Promise.all(promiseArr).then(res => {
  172. // 虽然用了Promise.all,但实际假设只有一张图片
  173. if (cb) {
  174. cb(res[0])
  175. }
  176. });
  177. }
  178. },
  179. search() {
  180. if (this.questionId) {
  181. this.getData(this.questionId)
  182. } else {
  183. this.$message({
  184. message: '请输入题目编号',
  185. type: 'warning'
  186. });
  187. }
  188. },
  189. auto() {
  190. this.isAuto = !this.isAuto;
  191. if (this.isAuto) {
  192. this.getData()
  193. }
  194. },
  195. upLoad() {
  196. if (this.questionId && this.imgUri) {
  197. this.uploadQuestionImage(this.imgUri, 1)
  198. } else {
  199. this.$message({
  200. message: '请先搜索题目',
  201. type: 'warning'
  202. });
  203. }
  204. },
  205. getData(questionId) {
  206. axios.defaults.withCredentials = true;
  207. let str = ''
  208. if (questionId) {
  209. str = '?questionId=' + questionId
  210. }
  211. axios.get(this.domain + '/prod-api/front/questionCollection/getNextQuestionForImageGenerate' + str).then(response => {
  212. if (response.data.code == 200) {
  213. this.data = response.data.data
  214. this.$nextTick(() => {
  215. this.MathQueueTitle(str)
  216. })
  217. } else {
  218. this.isAuto = false
  219. this.$message({
  220. message: '获取题目信息失败',
  221. type: 'warning'
  222. });
  223. }
  224. }).catch(function (error) { // 请求失败处理
  225. this.isAuto = false
  226. this.$message.error('网络请求异常!');
  227. });
  228. },
  229. uploadQuestionImage(src, type) {
  230. axios.defaults.withCredentials = true;
  231. var formData = new FormData()
  232. formData.append('questionId', this.data.questionId)
  233. formData.append('imageBase64', src)
  234. if (this.isAuto == false) {
  235. formData.append('manual', true)
  236. }
  237. axios.post(this.domain + '/prod-api/front/questionCollection/uploadQuestionImage', formData).then(response => {
  238. console.log(response)
  239. if (response.data.code == 200) {
  240. if (this.isAuto) {
  241. setTimeout(() => {
  242. this.getData()
  243. }, 2000);
  244. }
  245. if (type) {
  246. this.$message({
  247. message: '上传题目信息成功!',
  248. type: 'success'
  249. });
  250. }
  251. } else {
  252. this.isAuto = false
  253. this.$message({
  254. message: '上传题目信息失败!',
  255. type: 'warning'
  256. });
  257. }
  258. }).catch(function (error) { // 请求失败处理
  259. this.isAuto = false
  260. this.$message.error('网络请求异常!');
  261. });
  262. },
  263. getCookie(str) {//获取cookie
  264. let cookie = document.cookie.split('; ');
  265. let cookies = {}
  266. cookie.forEach(item => {
  267. cookies[item.split('=')[0]] = item.split('=')[1]
  268. })
  269. return cookies[str]
  270. },
  271. MathQueueTitle(str) {//初始化公式
  272. if (MathQueue) {
  273. clearInterval(this.time)
  274. MathQueue('title')
  275. // setTimeout(() => {
  276. // this.$nextTick(() => {
  277. // this.downLoad(str)
  278. this.waitingLoaingImg((canvas) => { this.downLoad(str, canvas) });
  279. // })
  280. // }, 1000)
  281. } else {
  282. this.time = setInterval(() => {
  283. this.MathQueueTitle()
  284. }, 5)
  285. }
  286. },
  287. downLoad(type, canvas1) {
  288. if (!this.data.questionId) {
  289. this.$message({
  290. message: '请先搜索题目!',
  291. type: 'warning'
  292. });
  293. return
  294. }
  295. this.questionId=this.data.questionId
  296. const times = 2 // 图片放大倍数,能提升清晰度
  297. let _this = this
  298. _this.imgUri = ''
  299. document.getElementById('qs').style.display = 'none'
  300. let _canvas = document.getElementById('ans')
  301. const { width, height } = _canvas.getBoundingClientRect();
  302. html2canvas(_canvas, {
  303. canvas: this.getCanvasWrap(width, height),
  304. useCORS: true,
  305. }).then((canvas2) => {
  306. document.getElementById('qs').style.display = 'block'
  307. var canvas3 = document.createElement("canvas");
  308. canvas3.width = Math.max(canvas1?.width ?? 0, canvas2.width)
  309. canvas3.height = (canvas1?.height ?? 0) + (canvas2.width && canvas2.height ? canvas2.height : 0)
  310. var ctx = canvas3.getContext("2d");
  311. // 绘制题目
  312. canvas1 && ctx.drawImage(canvas1, 0, 0, canvas1.width, canvas1.height);
  313. if (canvas2.width && canvas2.height) {
  314. // 绘制答案
  315. ctx.drawImage(canvas2, 0, canvas1?.height ?? 0, canvas2.width, canvas2.height);
  316. }
  317. _this.imgUri = canvas3.toDataURL('image/png')
  318. canvas1 = null
  319. canvas2 = null
  320. canvas3 = null
  321. if (!type) {
  322. _this.uploadQuestionImage(_this.imgUri)
  323. }
  324. })
  325. },
  326. }
  327. });
  328. // }
  329. </script>
  330. </body>
  331. </html>