onlineWrite.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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. "JPEG",
  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. {
  294. "title":"标题",
  295. "content":"内容"
  296. }`,
  297. },
  298. {
  299. type: "image_url",
  300. image_url: {
  301. url: url,
  302. },
  303. },
  304. ],
  305. },
  306. ],
  307. max_tokens: 4096,
  308. uid: "a77e9404-efec-11e9-96f9-028edca3b798",
  309. stream: false,
  310. };
  311. this.ajax.post("https://gpt4.cocorobo.cn/imageAnalyse", param).then(
  312. (res) => {
  313. if (
  314. res.data.FunctionResponse &&
  315. res.data.FunctionResponse.result &&
  316. res.data.FunctionResponse.result == "无效请求,请重新发起对话"
  317. ) {
  318. this.$message.error("你的作文内容太长,无法使用图片识别!");
  319. loading.close();
  320. return;
  321. }
  322. let aiImageNav = res.data.FunctionResponse.choices
  323. ? res.data.FunctionResponse.choices[0].message.content
  324. : "";
  325. try {
  326. aiImageNav = JSON.parse(aiImageNav);
  327. this.myAnswerList.engTitle = aiImageNav.title;
  328. this.myAnswerList.engText = aiImageNav.content;
  329. } catch (error) {
  330. // this.getImageNav();
  331. this.myAnswerList.engTitle = '';
  332. this.myAnswerList.engText = aiImageNav;
  333. }
  334. console.log(aiImageNav);
  335. // this.myAnswerList.engTitle = aiImageNav.title;
  336. // this.myAnswerList.engText = aiImageNav.content;
  337. this.type = 1;
  338. loading.close();
  339. },
  340. (err) => {
  341. console.log(err);
  342. loading.close();
  343. }
  344. );
  345. },
  346. },
  347. mounted() {
  348. if (
  349. !this.myAnswerList1.engTitle &&
  350. !this.myAnswerList1.engText &&
  351. !this.myAnswerList1.imgList.length
  352. ) {
  353. this.myAnswerList = {
  354. engTitle: "",
  355. engText: "",
  356. imgList: [],
  357. };
  358. this.type = 0;
  359. } else {
  360. this.myAnswerList = JSON.parse(JSON.stringify(this.myAnswerList1));
  361. this.type = 1;
  362. }
  363. },
  364. };
  365. </script>
  366. <style scoped>
  367. .engBox {
  368. width: 90%;
  369. margin: 0 auto;
  370. }
  371. .engTitle,
  372. .engText {
  373. display: flex;
  374. flex-direction: row;
  375. flex-wrap: nowrap;
  376. align-items: flex-start;
  377. margin-bottom: 20px;
  378. }
  379. .engTitle > .div:first-child,
  380. .engText > div:first-child {
  381. min-width: 75px;
  382. }
  383. .chooseUpload {
  384. width: 100%;
  385. height: 300px;
  386. text-align: center;
  387. line-height: 300px;
  388. border: 1px dashed #c4c4c4;
  389. border-radius: 5px;
  390. margin-bottom: 20px;
  391. cursor: pointer;
  392. }
  393. .ftypeBox {
  394. margin: 20px auto 0;
  395. }
  396. .ftypeTitle {
  397. display: flex;
  398. flex-direction: row;
  399. flex-wrap: nowrap;
  400. align-items: center;
  401. }
  402. .ftypeTitle > div:first-child {
  403. min-width: 42px;
  404. font-weight: bold;
  405. }
  406. .ftypeTitle > div:last-child {
  407. width: calc(100% - 42px);
  408. }
  409. .ftypeText {
  410. display: flex;
  411. flex-direction: row;
  412. flex-wrap: nowrap;
  413. align-items: flex-start;
  414. margin-top: 20px;
  415. }
  416. .ftypeText > div:first-child {
  417. min-width: 42px;
  418. margin-top: 10px;
  419. font-weight: bold;
  420. }
  421. .ftypeText > div:last-child {
  422. width: 100%;
  423. }
  424. .upImg {
  425. width: 30px;
  426. height: 30px;
  427. float: right;
  428. cursor: pointer;
  429. }
  430. .upImg > img,
  431. .isUpImg > img,
  432. .deleteImg > img,
  433. .itemImg > img,
  434. .itemDeleteImg > img {
  435. width: 100%;
  436. height: 100%;
  437. }
  438. .chapter_add {
  439. width: 180px;
  440. margin: 0 auto;
  441. position: relative;
  442. text-align: center;
  443. }
  444. .up_photo2 {
  445. width: 180px;
  446. box-sizing: border-box;
  447. min-width: 180px;
  448. height: 180px;
  449. max-height: 180px;
  450. min-height: 180px;
  451. cursor: pointer;
  452. display: flex;
  453. flex-direction: column;
  454. align-items: center;
  455. justify-content: center;
  456. background: rgb(242, 246, 255);
  457. /* padding: 25px; */
  458. margin-bottom: 10px;
  459. }
  460. .up_photo2 img {
  461. width: 50%;
  462. height: auto;
  463. }
  464. .up_photo2 span {
  465. color: #898989;
  466. }
  467. .isUpImg {
  468. width: 180px;
  469. min-width: 180px;
  470. height: 180px;
  471. max-height: 180px;
  472. min-height: 180px;
  473. }
  474. .deleteImg {
  475. width: 20px;
  476. height: 20px;
  477. cursor: pointer;
  478. position: absolute;
  479. top: 0;
  480. right: 0;
  481. }
  482. .imgListCss {
  483. margin: 10px 0;
  484. }
  485. .itemImg {
  486. width: 50px;
  487. height: 50px;
  488. position: relative;
  489. }
  490. .itemDeleteImg {
  491. width: 15px;
  492. height: 15px;
  493. cursor: pointer;
  494. position: absolute;
  495. top: -5px;
  496. right: -5px;
  497. }
  498. /* table 样式 */
  499. .cont >>> table {
  500. border-top: 1px solid #ccc;
  501. border-left: 1px solid #ccc;
  502. }
  503. .cont >>> table td,
  504. .cont >>> table th {
  505. border-bottom: 1px solid #ccc;
  506. border-right: 1px solid #ccc;
  507. /* padding: 20px 5px; */
  508. padding: 5px 10px;
  509. max-width: 0px;
  510. height: 30px;
  511. vertical-align: baseline;
  512. box-sizing: border-box;
  513. }
  514. .cont >>> table th {
  515. border-bottom: 2px solid #ccc;
  516. text-align: center;
  517. }
  518. /* blockquote 样式 */
  519. .cont >>> blockquote {
  520. display: block;
  521. border-left: 8px solid #d0e5f2;
  522. padding: 5px 10px;
  523. margin: 10px 0;
  524. line-height: 1.4;
  525. font-size: 100%;
  526. background-color: #f1f1f1;
  527. }
  528. /* code 样式 */
  529. .cont >>> code {
  530. display: inline-block;
  531. /* *display: inline; */
  532. zoom: 1;
  533. background-color: #f1f1f1;
  534. border-radius: 3px;
  535. padding: 3px 5px;
  536. margin: 0 3px;
  537. }
  538. .cont >>> pre code {
  539. display: block;
  540. }
  541. /* ul ol 样式 */
  542. .cont >>> ul,
  543. ol {
  544. margin: 10px 0 10px 20px;
  545. }
  546. /* code 样式 */
  547. .cont {
  548. /* -webkit-user-modify: read-write; */
  549. overflow-wrap: break-word;
  550. -webkit-line-break: after-white-space;
  551. }
  552. </style>