onlineWrite.vue 14 KB

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