onlineWrite.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. <template>
  2. <div class="engBox">
  3. <div class="engTitle">
  4. <div>作文题目:</div>
  5. <div>{{ englishList.engTitle }}</div>
  6. </div>
  7. <div class="engText">
  8. <div>作文内容:</div>
  9. <div class="cont" v-html="englishList.englishText"></div>
  10. </div>
  11. <div
  12. v-for="(item, index) in myAnswerList.imgList"
  13. :key="index"
  14. class="imgListCss"
  15. >
  16. <div class="itemImg">
  17. <img :src="item.url" alt="" />
  18. <div class="itemDeleteImg" @click="deleteImgList">
  19. <img src="../../../assets/icon/english/delete.png" alt="" />
  20. </div>
  21. </div>
  22. </div>
  23. <div class="chooseUpload" @click="type = 1" v-if="type == 0">+在线编写</div>
  24. <div
  25. class="chooseUpload"
  26. @click="uploadDialogVisible = true"
  27. v-if="type == 0"
  28. >
  29. +图片上传
  30. </div>
  31. <div class="loadingImageText" v-if="type == 1">
  32. <div class="ftypeBox">
  33. <div class="ftypeTitle">
  34. <div>标题:</div>
  35. <div>
  36. <el-input
  37. v-model="myAnswerList.engTitle"
  38. placeholder="请填写你的作文题目"
  39. ></el-input>
  40. </div>
  41. </div>
  42. <div class="ftypeText">
  43. <div>正文:</div>
  44. <div>
  45. <el-input
  46. type="textarea"
  47. :rows="20"
  48. resize="none"
  49. v-model="myAnswerList.engText"
  50. ></el-input>
  51. </div>
  52. </div>
  53. <div class="upImg" @click="uploadDialogVisible = true">
  54. <img src="../../../assets/icon/english/uploadImg.png" alt="" />
  55. </div>
  56. </div>
  57. </div>
  58. <el-dialog
  59. title="图片上传"
  60. :visible.sync="uploadDialogVisible"
  61. :append-to-body="true"
  62. width="30%"
  63. :before-close="handleClose"
  64. class="dialog_diy"
  65. >
  66. <div
  67. class="chapter_add"
  68. @click="addImg($event)"
  69. v-if="myAnswerList.imgList.length == 0"
  70. >
  71. <div class="up_photo2">
  72. <img src="../../../assets/icon/plwork1.png" alt />
  73. <span>点击上传文件</span>
  74. </div>
  75. <input
  76. type="file"
  77. accept="video/mp4, video/quicktime, video/x-msvideo,application/pdf, application/.ppt, .pptx, .xlsx, .xls, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, image/*"
  78. multiple="multiple"
  79. style="display: none"
  80. @change="beforeUpload($event)"
  81. />
  82. </div>
  83. <div class="chapter_add" v-else>
  84. <div class="isUpImg">
  85. <img :src="myAnswerList.imgList[0].url" alt="" />
  86. </div>
  87. <div class="deleteImg" @click="deleteImgList">
  88. <img src="../../../assets/icon/english/delete.png" alt="" />
  89. </div>
  90. </div>
  91. <div style="text-align: center">如已进行填写,确认后讲清空内容噢。</div>
  92. <span slot="footer" class="dialog-footer">
  93. <el-button @click="checkImage">取 消</el-button>
  94. <el-button type="primary" @click="uploadIsType">确定</el-button>
  95. </span>
  96. </el-dialog>
  97. </div>
  98. </template>
  99. <script>
  100. export default {
  101. props: ["englishList", "myAnswerList1", "userid"],
  102. data() {
  103. return {
  104. type: 0,
  105. myAnswerList: {
  106. engTitle: "",
  107. engText: "",
  108. imgList: [],
  109. },
  110. uploadDialogVisible: false,
  111. noneBtnImg: false,
  112. baseFile: "",
  113. };
  114. },
  115. watch: {
  116. myAnswerList1: {
  117. handler(newVal) {
  118. if (
  119. !this.myAnswerList1.engTitle &&
  120. !this.myAnswerList1.engText &&
  121. !this.myAnswerList1.imgList.length
  122. ) {
  123. this.myAnswerList = {
  124. engTitle: "",
  125. engText: "",
  126. imgList: [],
  127. };
  128. this.type = 0;
  129. } else {
  130. this.myAnswerList = newVal;
  131. this.type = 1;
  132. }
  133. },
  134. deep: true,
  135. },
  136. },
  137. methods: {
  138. handleClose(done) {
  139. done();
  140. },
  141. imgChange() {
  142. var _tmp = this.myAnswerList.imgList;
  143. this.noneBtnImg = _tmp.length >= 1;
  144. },
  145. addImg(e) {
  146. var el = e.currentTarget;
  147. el.getElementsByTagName("input")[0].click();
  148. e.target.value = "";
  149. },
  150. deleteImgList() {
  151. this.myAnswerList.imgList = [];
  152. },
  153. uploadIsType() {
  154. this.type = 1;
  155. this.uploadDialogVisible = false;
  156. this.getImageNav();
  157. },
  158. checkImage() {
  159. if (
  160. this.myAnswerList.imgList.length > 0 &&
  161. this.myAnswerList.imgList[0].url
  162. ) {
  163. this.getImageNav();
  164. } else {
  165. this.uploadDialogVisible = false;
  166. }
  167. this.uploadDialogVisible = false;
  168. },
  169. async beforeUpload(event) {
  170. // this.$message.success('进入上传')
  171. var file = event.target.files[0];
  172. var credentials = {
  173. accessKeyId: "AKIATLPEDU37QV5CHLMH",
  174. secretAccessKey: "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",
  175. }; //秘钥形式的登录上传
  176. window.AWS.config.update(credentials);
  177. window.AWS.config.region = "cn-northwest-1"; //设置区域
  178. var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
  179. var _this = this;
  180. // _this.progress = 0;
  181. var photoA = [
  182. "BMP",
  183. "GIF",
  184. "PNG",
  185. "JPGE",
  186. "JPG",
  187. "TIF",
  188. "PCX",
  189. "TGA",
  190. "EXIF",
  191. "FPX",
  192. "SVG",
  193. "APNG",
  194. ];
  195. if (
  196. photoA.indexOf(
  197. file.name
  198. .split(".")
  199. [file.name.split(".").length - 1].toLocaleUpperCase()
  200. ) == -1
  201. ) {
  202. _this.$message.error("请上传图片!");
  203. return;
  204. }
  205. if (file) {
  206. var params = {
  207. Key:
  208. file.name.split(".")[0] +
  209. new Date().getTime() +
  210. "." +
  211. file.name.split(".")[file.name.split(".").length - 1],
  212. ContentType: file.type,
  213. Body: file,
  214. "Access-Control-Allow-Credentials": "*",
  215. ACL: "public-read",
  216. }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
  217. var options = {
  218. // partSize: 2048 * 1024 * 1024,
  219. partSize: 1024 * 1024 * 1024,
  220. queueSize: 2,
  221. leavePartsOnError: true,
  222. };
  223. bucket
  224. .upload(params, options)
  225. .on("httpUploadProgress", function (evt) {
  226. //这里可以写进度条
  227. // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
  228. // _this.progress = parseInt((evt.loaded * 80) / evt.total);
  229. })
  230. .send(function (err, data) {
  231. // _this.progress = 100;
  232. if (err) {
  233. var a = _this.$refs.upload1.uploadFiles;
  234. a.splice(a.length - 1, a.length);
  235. _this.$message.error("上传失败");
  236. } else {
  237. // _this.$message.success('上传成功')
  238. _this.myAnswerList.imgList.push({
  239. name: file.name,
  240. url: data.Location,
  241. });
  242. _this.pngToWhiteBg(file);
  243. _this.imgChange();
  244. console.log(data.Location);
  245. // _this.$message.success('上传成功'+data.Location)
  246. }
  247. });
  248. }
  249. },
  250. pngToWhiteBg(file) {
  251. const _file = file;
  252. let read = new FileReader();
  253. read.readAsDataURL(file); // 文件转base64
  254. return new Promise((resolve, reject) => {
  255. read.onload = (e) => {
  256. let img = new Image();
  257. img.src = e.target.result;
  258. img.onload = async () => {
  259. // 生成canvas
  260. let canvas = document.createElement("canvas");
  261. let context = canvas.getContext("2d");
  262. // 绘制图片到canvas上
  263. canvas.width = img.width;
  264. canvas.height = img.height;
  265. // 在canvas绘制前填充白色背景
  266. context.fillStyle = "#fff";
  267. context.fillRect(0, 0, canvas.width, canvas.height);
  268. context.drawImage(img, 0, 0);
  269. let base64 = canvas.toDataURL(file["type"], 1);
  270. this.baseFile = base64;
  271. };
  272. };
  273. });
  274. },
  275. getImageNav() {
  276. let url = this.baseFile;
  277. const loading = this.$loading.service({
  278. background: "rgba(255, 255, 255)",
  279. target: document.querySelectorAll(".loadingImageText")[0],
  280. });
  281. let param = {
  282. messages: [
  283. {
  284. role: "user",
  285. content: [
  286. {
  287. type: "text",
  288. text: `NOTICE
  289. Role: 你是一个专门解读图片的大师,你可以把图片里面的文字全部提取出来,然后根据Format example的要求返回
  290. ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
  291. -----
  292. ## Format example
  293. javascirpt
  294. {
  295. "title":"标题",
  296. "content":"内容"
  297. }`,
  298. },
  299. {
  300. type: "image_url",
  301. image_url: {
  302. url: url,
  303. },
  304. },
  305. ],
  306. },
  307. ],
  308. max_tokens: 4096,
  309. uid: "a77e9404-efec-11e9-96f9-028edca3b798",
  310. stream: false,
  311. };
  312. this.ajax.post("https://gpt4.cocorobo.cn/imageAnalyse", param).then(
  313. (res) => {
  314. if (
  315. res.data.FunctionResponse &&
  316. res.data.FunctionResponse.result &&
  317. res.data.FunctionResponse.result == "无效请求,请重新发起对话"
  318. ) {
  319. this.$message.error("你的作文内容太长,无法使用图片识别!");
  320. loading.close();
  321. return;
  322. }
  323. let aiImageNav = res.data.FunctionResponse.choices
  324. ? res.data.FunctionResponse.choices[0].message.content
  325. : "";
  326. try {
  327. aiImageNav = JSON.parse(aiImageNav);
  328. this.myAnswerList.engTitle = aiImageNav.title;
  329. this.myAnswerList.engText = aiImageNav.content;
  330. } catch (error) {
  331. // this.getImageNav();
  332. this.myAnswerList.engTitle = '';
  333. this.myAnswerList.engText = aiImageNav;
  334. }
  335. console.log(aiImageNav);
  336. // this.myAnswerList.engTitle = aiImageNav.title;
  337. // this.myAnswerList.engText = aiImageNav.content;
  338. this.type = 1;
  339. loading.close();
  340. },
  341. (err) => {
  342. console.log(err);
  343. loading.close();
  344. }
  345. );
  346. },
  347. },
  348. mounted() {
  349. if (
  350. !this.myAnswerList1.engTitle &&
  351. !this.myAnswerList1.engText &&
  352. !this.myAnswerList1.imgList.length
  353. ) {
  354. this.myAnswerList = {
  355. engTitle: "",
  356. engText: "",
  357. imgList: [],
  358. };
  359. this.type = 0;
  360. } else {
  361. this.myAnswerList = JSON.parse(JSON.stringify(this.myAnswerList1));
  362. this.type = 1;
  363. }
  364. },
  365. };
  366. </script>
  367. <style scoped>
  368. .engBox {
  369. width: 90%;
  370. margin: 0 auto;
  371. }
  372. .engTitle,
  373. .engText {
  374. display: flex;
  375. flex-direction: row;
  376. flex-wrap: nowrap;
  377. align-items: flex-start;
  378. margin-bottom: 20px;
  379. }
  380. .engTitle > .div:first-child,
  381. .engText > div:first-child {
  382. min-width: 75px;
  383. }
  384. .chooseUpload {
  385. width: 100%;
  386. height: 300px;
  387. text-align: center;
  388. line-height: 300px;
  389. border: 1px dashed #c4c4c4;
  390. border-radius: 5px;
  391. margin-bottom: 20px;
  392. cursor: pointer;
  393. }
  394. .ftypeBox {
  395. margin: 20px auto 0;
  396. }
  397. .ftypeTitle {
  398. display: flex;
  399. flex-direction: row;
  400. flex-wrap: nowrap;
  401. align-items: center;
  402. }
  403. .ftypeTitle > div:first-child {
  404. min-width: 42px;
  405. font-weight: bold;
  406. }
  407. .ftypeTitle > div:last-child {
  408. width: calc(100% - 42px);
  409. }
  410. .ftypeText {
  411. display: flex;
  412. flex-direction: row;
  413. flex-wrap: nowrap;
  414. align-items: flex-start;
  415. margin-top: 20px;
  416. }
  417. .ftypeText > div:first-child {
  418. min-width: 42px;
  419. margin-top: 10px;
  420. font-weight: bold;
  421. }
  422. .ftypeText > div:last-child {
  423. width: 100%;
  424. }
  425. .upImg {
  426. width: 30px;
  427. height: 30px;
  428. float: right;
  429. cursor: pointer;
  430. }
  431. .upImg > img,
  432. .isUpImg > img,
  433. .deleteImg > img,
  434. .itemImg > img,
  435. .itemDeleteImg > img {
  436. width: 100%;
  437. height: 100%;
  438. }
  439. .chapter_add {
  440. width: 180px;
  441. margin: 0 auto;
  442. position: relative;
  443. text-align: center;
  444. }
  445. .up_photo2 {
  446. width: 180px;
  447. box-sizing: border-box;
  448. min-width: 180px;
  449. height: 180px;
  450. max-height: 180px;
  451. min-height: 180px;
  452. cursor: pointer;
  453. display: flex;
  454. flex-direction: column;
  455. align-items: center;
  456. justify-content: center;
  457. background: rgb(242, 246, 255);
  458. /* padding: 25px; */
  459. margin-bottom: 10px;
  460. }
  461. .up_photo2 img {
  462. width: 50%;
  463. height: auto;
  464. }
  465. .up_photo2 span {
  466. color: #898989;
  467. }
  468. .isUpImg {
  469. width: 180px;
  470. min-width: 180px;
  471. height: 180px;
  472. max-height: 180px;
  473. min-height: 180px;
  474. }
  475. .deleteImg {
  476. width: 20px;
  477. height: 20px;
  478. cursor: pointer;
  479. position: absolute;
  480. top: 0;
  481. right: 0;
  482. }
  483. .imgListCss {
  484. margin: 10px 0;
  485. }
  486. .itemImg {
  487. width: 50px;
  488. height: 50px;
  489. position: relative;
  490. }
  491. .itemDeleteImg {
  492. width: 15px;
  493. height: 15px;
  494. cursor: pointer;
  495. position: absolute;
  496. top: -5px;
  497. right: -5px;
  498. }
  499. /* table 样式 */
  500. .cont >>> table {
  501. border-top: 1px solid #ccc;
  502. border-left: 1px solid #ccc;
  503. }
  504. .cont >>> table td,
  505. .cont >>> table th {
  506. border-bottom: 1px solid #ccc;
  507. border-right: 1px solid #ccc;
  508. /* padding: 20px 5px; */
  509. padding: 5px 10px;
  510. max-width: 0px;
  511. height: 30px;
  512. vertical-align: baseline;
  513. box-sizing: border-box;
  514. }
  515. .cont >>> table th {
  516. border-bottom: 2px solid #ccc;
  517. text-align: center;
  518. }
  519. /* blockquote 样式 */
  520. .cont >>> blockquote {
  521. display: block;
  522. border-left: 8px solid #d0e5f2;
  523. padding: 5px 10px;
  524. margin: 10px 0;
  525. line-height: 1.4;
  526. font-size: 100%;
  527. background-color: #f1f1f1;
  528. }
  529. /* code 样式 */
  530. .cont >>> code {
  531. display: inline-block;
  532. /* *display: inline; */
  533. zoom: 1;
  534. background-color: #f1f1f1;
  535. border-radius: 3px;
  536. padding: 3px 5px;
  537. margin: 0 3px;
  538. }
  539. .cont >>> pre code {
  540. display: block;
  541. }
  542. /* ul ol 样式 */
  543. .cont >>> ul,
  544. ol {
  545. margin: 10px 0 10px 20px;
  546. }
  547. /* code 样式 */
  548. .cont {
  549. /* -webkit-user-modify: read-write; */
  550. overflow-wrap: break-word;
  551. -webkit-line-break: after-white-space;
  552. }
  553. </style>