<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="./js/vue.js"></script> <script src="./js/html2canvas.min.js"></script> <script src="./js/axios.min.js"></script> <script src="./js/base.js"></script> <link rel="stylesheet" href="./css/style.css" /> </head> <body> <div id="app"> <div class="operate flexacenter"> <input placeholder="请输入" v-model="inputText" @keyup.enter="confirm()" /> <div class="btn" @click="confirm()">确定</div> <div class="btn" :class="{ disabled: !isClickable }" :disabled="!isClickable" @click="saveimage()">生成图片</div> </div> <div class="main"> <template v-if="tab == 'offer' && JSON.stringify(offerinfo) !== '{}'"> <div class="box"> <div class="head"> <div class="left"> <img class="index" crossorigin="anonymous" :src="base01" /> <img class="arrow" crossorigin="anonymous" :src="arrowyellow" /> <img class="arrow" crossorigin="anonymous" :src="arrowlightyellow" /> </div> <div class="right"> <div class="right-text">Offer详情</div> </div> <div class="strip"></div> </div> <div class="content offer-details"> <div class="details-header flexacenter"> <img class="icon" ref="offerImage" crossorigin="anonymous" :src="offerinfo?.school?.base64 || offerinfo?.school?.image" @load="getBase64ImageFromURL('offer')" /> <div class="school flex1 flexcolumn"> <div class="name">{{ offerinfo?.school?.name }}</div> <div class="brief"> {{ offerinfo?.school?.enname }} <template v-if="offerinfo?.school?.countries">| {{ offerinfo?.school?.countries }}</template> </div> </div> </div> <div class="info"> <div class="item" v-if="offerinfo.degree"> <div class="name">学位</div> <div class="value">{{ offerinfo.degree }}</div> </div> <div class="item" v-if="offerinfo.professional"> <div class="name">专业</div> <div class="value">{{ offerinfo.professional }}</div> </div> <div class="item" v-if="offerinfo.project"> <div class="name">项目</div> <div class="value">{{ offerinfo.project }}</div> </div> <div class="item" v-if="offerinfo.apply_results"> <div class="name">申请结果</div> <div class="value">{{ offerinfo.apply_results }}</div> </div> <div class="item" v-if="offerinfo.semester"> <div class="name">入学</div> <div class="value">{{ offerinfo.semester }}</div> </div> <div class="item"> <div class="name">通知时间</div> <div class="value">{{ offerinfo.noticedate }}</div> </div> <div class="item" v-if="offerinfo?.useperformance?.length"> <div class="name">使用成绩</div> <div class="value"><template v-for="(it, i) in offerinfo?.useperformance">{{ it.toLocaleUpperCase() }} {{ i + 1 == offerinfo.useperformance.length ? '' : '、' }}</template></div> </div> </div> </div> </div> <div class="box"> <div class="head"> <div class="left"> <img class="index" crossorigin="anonymous" :src="base02" /> <img class="arrow" crossorigin="anonymous" :src="arrowyellow" /> <img class="arrow" crossorigin="anonymous" :src="arrowlightyellow" /> </div> <div class="right"> <div class="right-text">个人背景</div> </div> <div class="strip"></div> </div> <div class="content bj"> <div class="bj-title flexacenter flexcenter" v-if="personalBgResults.length != 0"> <div>-</div> 考试成绩 <div>-</div> </div> <div class="grade-box flexcolumn" v-if="personalBgResults.length != 0"> <div class="grade-item" v-for="(item, index) in personalBgResults" :key="index"> <div class="background-item-title">{{ item.name }}</div> <div v-if="item.isarr == 'table'" class="offer-background-content flexacenter"> <div class="grade-content-item flex1 flexcolumn" v-for="(it, index) in item.value" :key="index"> <div class="grade-content-key flexcenter">{{ it.name }}</div> <div class="grade-content-value flexcenter">{{ it.value }}</div> </div> </div> <div v-else-if="item.isarr == 'sub'" class="offer-background-content offer-background-content2 flexcolumn"> <div class="offer-background-content-top flexcenter">{{ item.value.name }}</div> <div class="offer-background-content-bottom flexacenter"> <div class="offer-background-content-left flexcenter">总分</div> <div class="offer-background-content-text flex1 flexcenter">{{ item.value.value }}</div> </div> </div> <div v-else-if="item.isarr == 'strip'" class="offer-background-content offer-background-content1 flexacenter"> <div class="offer-background-content-left flexcenter">总分</div> <div class="offer-background-content-text flex1 flexcenter">{{ item.value }}</div> </div> <div v-else class="offer-background-content offer-background-content-text flexcenter">{{ item.value }}</div> </div> </div> <div v-if="personalBgUndergraduate.length != 0" class="background-box"> <div class="bj-title flexacenter flexcenter"> <div>-</div> 本科背景 <div>-</div> </div> <div class="background-content offer-background-content flexcolumn"> <div class="offer-background-item flexflex" v-for="(item, index) in personalBgUndergraduate" :key="index"> <div class="offer-background-key">{{ item.name }}</div> <div class="offer-background-value">{{ item.value }}</div> </div> </div> </div> <div v-if="personalBgGraduate.length != 0" class="background-box"> <div class="bj-title flexacenter flexcenter"> <div>-</div> 研究生背景 <div>-</div> </div> <div class="background-content offer-background-content flexcolumn"> <div class="offer-background-item flexflex" v-for="(item, index) in personalBgGraduate" :key="index"> <div class="offer-background-key">{{ item.name }}</div> <div class="offer-background-value">{{ item.value }}</div> </div> </div> </div> <div v-if="personalBgBackgroundList.length != 0" class="background-box"> <div class="bj-title flexacenter flexcenter"> <div>-</div> 软件背景 <div>-</div> </div> <div class="grade-item" v-for="(item, index) in personalBgBackgroundList" :key="index"> <div class="background-item-title">{{ item.name }}</div> <span class="offer-background-content offer-background-content-text flexacenter">{{ item.value }}</span> </div> </div> </div> </div> <div class="box" v-if="moodmessage && moodmessage.length != 0"> <div class="head"> <div class="left"> <img class="index" crossorigin="anonymous" :src="base03" /> <img class="arrow" crossorigin="anonymous" :src="arrowyellow" /> <img class="arrow" crossorigin="anonymous" :src="arrowlightyellow" /> </div> <div class="right"> <div class="right-text"> <div class="right-text">心情与小结</div> </div> </div> <div class="strip"></div> </div> <div class="content mood"> <div class="offer-mood-item flexcolumn" v-for="(item, index) in moodmessage" :key="index"> <div class="offer-mood-time" v-if="index != 0">以下内容于 {{ item.timestamp }} 补充</div> <div class="offer-mood-text">{{ item.message }}</div> </div> </div> </div> <div class="more flexcenter"> more <img class="more-icon" crossorigin="anonymous" :src="arrowround" /> </div> </template> <template v-if="tab == 'summary' && JSON.stringify(info) !== '{}'"> <div class="box" v-for="(item,index) in offercollege" :key="index" style="margin-bottom: 30px;"> <div class="head" v-if="index == 0"> <div class="left"> <img class="index" crossorigin="anonymous" :src="base01" /> <img class="arrow" crossorigin="anonymous" :src="arrowblue" /> <img class="arrow" crossorigin="anonymous" :src="arrowlightblue" /> </div> <div class="right summary"> <div class="right-text">收录{{ offercollege.length }}个Offer</div> </div> <div class="strip"></div> </div> <div class="head" style="height: 0;" v-else> <div class="strip"></div> </div> <div class="content summaryInclude-item flexcolumn"> <!-- 半圆 --> <div class="semicircle flexcenter"> {{ index + 1 }} <img class="semicircle-bj" crossorigin="anonymous" :src="semicircleicon" /> </div> <div class="header flexacenter"> <img :ref="'schoolimg' + index" @load="getBase64ImageFromURL('summary', index)" class="schoolimg" crossorigin="anonymous" :src="item.base64 || item.schoolimage" /> <div class="schoolname">{{ item.schoolname }}</div> </div> <div class="summaryInclude-content flex1 flexcolumn"> <div class="item flexacenter" v-if="item.professional"> <div class="key">专业</div> <div class="value">{{ item.professional }}</div> </div> <div class="item flexacenter" v-if="item.project"> <div class="key">项目</div> <div class="value">{{ item.project }}</div> </div> <div class="item flexacenter"> <div class="key">学位</div> <div class="value flexacenter" style="white-space: nowrap; flex-wrap: wrap;"> {{ item.degree }} <template v-if="item.semester"> <div class="vertical-line"></div> {{ item.semester }} </template> <template v-if="item.noticedate"> <div class="vertical-line"></div> {{ item.noticedate }}通知 </template> <template v-if="item.apply_results"> <div class="vertical-line"></div> <div v-if="item.apply_results" class="normal" :class="'results' + item.apply_results_status">{{ item.apply_results }}</div> </template> </div> </div> <div v-if="item.useperformance.length != 0" class="item flexacenter"> <div class="key">使用成绩</div> <div class="value"> <template v-for="(it, i) in item.useperformance">{{ it.toLocaleUpperCase() }} {{ i + 1 == item.useperformance.length ? '' : '、' }}</template> </div> </div> <div class="more-btn flexcenter"> 详情 <img class="more-btn-icom" crossorigin="anonymous" :src="arrowsgray" /> </div> </div> </div> </div> <div class="box" v-if="info.content"> <div class="head"> <div class="left"> <img class="index" crossorigin="anonymous" :src="base02" /> <img class="arrow" crossorigin="anonymous" :src="arrowblue" /> <img class="arrow" crossorigin="anonymous" :src="arrowlightblue" /> </div> <div class="right summary"> <div class="right-text">申请总结</div> </div> <div class="strip"></div> </div> <div class="content summary-text">{{ info.content }}</div> </div> <div class="box" v-if="info.message"> <div class="head"> <div class="left"> <img class="index" crossorigin="anonymous" :src="info.content ? base03 : base02" /> <img class="arrow" crossorigin="anonymous" :src="arrowblue" /> <img class="arrow" crossorigin="anonymous" :src="arrowlightblue" /> </div> <div class="right summary"> <div class="right-text">给学弟学妹的留言</div> </div> <div class="strip"></div> </div> <div class="content summary-text">{{ info.message }}</div> </div> <div class="more flexcenter"> more <img class="more-icon" crossorigin="anonymous" :src="arrow1round" /> </div> </template> <div v-if="selectState" class="pop-up flexcenter" @click="closeState"> <div class="select flexflex" @click.stop="aaa"> <div class="title">生成成功</div> <div class="img-box flexcenter"> <img class="img" :src="selectBase64" /> </div> <a class="btn" :href="selectBase64" :download="inputId + '.png'">另存为</a> </div> </div> </div> </div> <script> let app = new Vue({ el: "#app", data: { tab: "offer", // offer summary inputText: "", // "XS9W80qnj5G1", inputId: "", // "XS9W80qnj5G1", personalBgGraduate: [], personalBgUndergraduate: [], personalBackground: {}, personalBgBackgrounddictionaries: [ // 个人背景的软件背景字典 { key: "scientificresearch", name: "科研相关", }, { key: "recommendationletter", name: "推荐信", }, { key: "workexperience", name: "实习/工作经历", }, { key: "awards", name: "竞赛/奖项", }, { key: "scientificachievement", name: "科学成就", }, { key: "exchangeprogram", name: "交换项目", }, { key: "backgroundpromotionplan", name: "背景提升计划", }, { key: "other", name: "软件说明/其他", }, ], personalBgBackgroundList: [], // 处理好的软件背景数据 resultsSubjectsDictionaries: ["toefl", "ielts", "ptea", "gre", "gmat", "lsat", "sub", "duolingo", "otherlanguage"], // 成绩顺序字典 resultsSubjectsGreValue: [ { key: "verbal", name: "语文-V", }, { key: "quantitative", name: "数学-Q", }, { key: "analyticalwriting", name: "写作-W", }, { key: "total", name: "总分", }, ], resultsSubjectsToeflValue: [ { key: "reading", name: "阅读-R", }, { key: "listening", name: "听力-L", }, { key: "speaking", name: "口试-S", }, { key: "writing", name: "写作-W", }, { key: "total", name: "总分", }, ], personalBgResults: [], // 处理好的考试成绩数据 personalBgEducationdictionaries: [ // 个人背景的学校背景字典 { key: "school", name: "学校/档次", }, { key: "graduationtime", name: "毕业时间", }, { key: "major", name: "专业", }, { key: "majortype", name: "专业分类1", }, { key: "alternativemajors", name: "专业分类2", }, { key: "gpa", name: "GPA成绩", }, { key: "majorrank", name: "专业排名", }, ], offerinfo: {}, moodmessage: [], info: {}, offercollege: [], base01: "", arrow1round: "", selectState: false, selectBase64: "", }, mounted() { // 本地跳转 登录的 if (["localhost", "127.0.0.1"].includes(location.hostname)) axios.defaults.headers.common["Authorization"] = "ld9bk0gpdkqkydoyhdiqkvlm68cgxmjc" this.base01 = base01 this.base02 = base02 this.base03 = base03 this.arrow1round = arrow1round this.arrowblue = arrowblue this.arrowlightblue = arrowlightblue this.arrowround = arrowround this.semicircleicon = semicircleicon this.arrowlightyellow = arrowlightyellow this.arrowyellow = arrowyellow this.arrowsgray = arrowsgray }, computed: { isClickable() { return JSON.stringify(this.offerinfo) !== "{}" || JSON.stringify(this.info) !== "{}" }, }, methods: { getBase64ImageFromURL(type, index) { if (type == "offer") { const img = this.$refs.offerImage const canvas = document.createElement("canvas") canvas.width = img.naturalWidth canvas.height = img.naturalHeight const ctx = canvas.getContext("2d") // 设置背景色为透明或白色 ctx.fillStyle = "#ffffff" // 设置为白色 ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.drawImage(img, 0, 0) this.offerinfo.school["base64"] = canvas.toDataURL("image/jpeg") } else { const img = this.$refs["schoolimg" + index][0] const canvas = document.createElement("canvas") canvas.width = img.naturalWidth canvas.height = img.naturalHeight const ctx = canvas.getContext("2d") ctx.fillStyle = "#ffffff" // 设置为白色 ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.drawImage(img, 0, 0) this.offercollege[index]["base64"] = canvas.toDataURL("image/jpeg") this.$forceUpdate() } }, // 获取 offer 详情 getOfferDetails() { axios .post("https://offer.gter.net/api/details", { uniqid: this.inputId, }) .then(res => { res = res.data if (res.code != 200) { alert(res.message) return } const data = res.data const offerinfo = data.offerinfo || {} this.offerinfo = offerinfo this.moodmessage = data.moodmessage this.getPersonalBackground(data.backgroundid) }) }, // 获取总结详情 getSummaryDetails() { axios .post("https://offer.gter.net/api/details/summary", { token: this.inputId, }) .then(res => { res = res.data if (res.code != 200) { alert(res.message) return } const data = res.data while (data.info.message && data.info.message.indexOf("\n\n\n\n") >= 0) { data.info.message = data.info.message.replace("\n\n\n\n", "\n\n\n") } if (data.info.message && (data.info.message == "\n\n\n" || data.info.message == "\n\n" || data.info.message == "\n")) data.info.message = "" // 留言只有 回车 // 删除前后的空格 if (data.info.content) data.info.content = data.info.content.trim() if (data.info.message) data.info.message = data.info.message.trim() const offercollege = data.offercollege || [] this.offercollege = offercollege this.info = data.info }) }, getPersonalBackground(backgroundid) { axios .get("https://offer.gter.net/api/details/background", { params: { backgroundid, }, }) .then(res => { res = res.data this.personalBackground = { ...res.data } this.handlelSoftwareBackground() this.handlelTsestScore() this.handleEducationdictionaries() }) }, // 处理个人背景-考试成绩 handlelTsestScore() { let achievement = this.personalBackground.achievement let resultsSubjectsDictionaries = this.resultsSubjectsDictionaries let resultsSubjectsGreValue = this.resultsSubjectsGreValue let resultsSubjectsToeflValue = this.resultsSubjectsToeflValue let personalBgResults = [] resultsSubjectsDictionaries.forEach((element, index) => { let name = "" let value let isarr = "" if (["toefl", "ielts"].includes(element)) { name = element.toLocaleUpperCase() value = [] resultsSubjectsToeflValue.forEach(el => { let value1 = achievement && achievement[element] && achievement[element][el.key] if (value1 == undefined) return isarr = "table" value.push({ name: el.name, value: value1, }) }) } else if (["gre", "gmat"].includes(element)) { name = element.toLocaleUpperCase() value = [] resultsSubjectsGreValue.forEach(el => { let value1 = achievement[element] && achievement[element][el.key] if (value1 == undefined) return isarr = "table" value.push({ name: el.name, value: value1, }) }) } else if (element == "ptea") { name = "PTE A" value = achievement[element] && achievement[element].total isarr = "strip" } else if (element == "lsat") { name = element.toLocaleUpperCase() value = achievement[element] isarr = "strip" } else if (element == "sub") { name = element.toLocaleUpperCase() isarr = "sub" value = { name: achievement[element] && achievement[element].profession, value: achievement[element] && achievement[element].total, } } else if (element == "duolingo") { name = "多邻国" value = achievement[element] isarr = "strip" } else if (element == "otherlanguage") { if (achievement[element] && !achievement[element].trim()) return name = "其他语言/暂无" value = achievement[element] isarr = "text" } if (name == "" || value == undefined || value.length == 0) return if (name == "SUB" && value.name == undefined) return personalBgResults.push({ name, value, isarr, }) }) this.personalBgResults = personalBgResults }, // 处理个人背景-软件背景 handlelSoftwareBackground() { let background = this.personalBackground.background let personalBgBackgrounddictionaries = this.personalBgBackgrounddictionaries let personalBgBackgroundList = [] personalBgBackgrounddictionaries.forEach((element, index) => { let value = (background && background[element.key]) || "" value = value.trim() if (value != null && value != undefined && value != "") { value = value.replaceAll(/\r\n|\n|\r/g, "<br />") value = value.replaceAll("<br /><br />", "\n") value = value.replaceAll("<br/><br />", "\n") value = value.replaceAll("<br /><br/>", "\n") while (value.indexOf("<br/>") != -1 || value.indexOf("<br />") != -1 || value.indexOf("<br>") != -1) { value = value.replaceAll("<br/>", "\n") value = value.replaceAll("<br />", "\n") value = value.replaceAll("<br>", "\n") } personalBgBackgroundList.push({ name: element.name, value, }) } }) this.personalBgBackgroundList = personalBgBackgroundList }, // 处理个人背景- 本科背景和研究生背景 handleEducationdictionaries() { let personalBgUndergraduate = [] // 本科 let personalBgGraduate = [] // 研究生 let bjUndergraduate = this.personalBackground.undergraduate let graduate = this.personalBackground.graduate this.personalBgEducationdictionaries.forEach((element, index) => { let undergraduateValue = bjUndergraduate[element.key] let name = element.name if (element.key == "gpa") { undergraduateValue = [] if (`${bjUndergraduate["gpascore"]}` || `${bjUndergraduate["gpawes"]}` || `${bjUndergraduate["gpaotherscore"]}`) { undergraduateValue = [] if (bjUndergraduate["gpascore"]) undergraduateValue.push(`${bjUndergraduate["gpascore"]}/100 百分制`) if (bjUndergraduate["gpaoriginaldata"]) undergraduateValue.push(`${bjUndergraduate["gpaoriginaldata"]}`) else if (bjUndergraduate["gpawes"]) undergraduateValue.push(`${bjUndergraduate["gpawes"]}/4 WES算法`) if (bjUndergraduate["gpaotherscore"]) undergraduateValue.push(`${bjUndergraduate["gpaotherscore"]}/${bjUndergraduate["gpaotherfullscore"]} 其他算法`) if (undergraduateValue.length > 0) { undergraduateValue = undergraduateValue.join("、") } } } if ((element.key == "majortype" || element.key == "alternativemajors") && undergraduateValue == "其他") undergraduateValue = bjUndergraduate["majorother"] if (undergraduateValue != undefined && undergraduateValue.length != 0) { personalBgUndergraduate.push({ key: element.key, name, value: undergraduateValue, }) } }) this.personalBgEducationdictionaries.forEach((element, index) => { let graduateValue = graduate[element.key] let name = element.name if (element.key == "gpa") { if (`${graduate["gpascore"]}` || `${graduate["gpawes"]}` || `${graduate["gpaotherscore"]}`) { graduateValue = [] if (graduate["gpascore"]) graduateValue.push(`${graduate["gpascore"]}/100 百分制`) if (graduate["gpaoriginaldata"]) graduateValue.push(`${graduate["gpaoriginaldata"]}`) else if (graduate["gpawes"]) graduateValue.push(`${graduate["gpawes"]}/4 WES算法`) if (graduate["gpaotherscore"]) graduateValue.push(`${graduate["gpaotherscore"]}/${graduate["gpaotherfullscore"]} 其他算法`) if (graduateValue.length > 0) { graduateValue = graduateValue.join("、") } } } if ((element.key == "majortype" || element.key == "alternativemajors") && graduateValue == "其他") graduateValue = graduate["majorother"] if (graduateValue != undefined && graduateValue.length != 0) { personalBgGraduate.push({ key: element.key, name, value: graduateValue, }) } }) this.personalBgUndergraduate = personalBgUndergraduate this.personalBgGraduate = personalBgGraduate }, // 确定 confirm() { if (!this.inputText) return if (this.inputText.indexOf("/details/") > 0) this.tab = "offer" else this.tab = "summary" if (this.inputText.indexOf("http") != -1) this.inputId = this.inputText.substring(this.inputText.lastIndexOf("/") + 1) else this.inputId = this.inputText if (this.tab == "offer") this.getOfferDetails() else this.getSummaryDetails() }, // 保存图片 saveimage() { html2canvas(document.querySelector(".main")).then(canvas => { // 你现在可以对canvas做任何事情,比如将其添加到文档中 // document.body.appendChild(canvas) // 或者你可以将canvas转换为图片数据 let img = canvas.toDataURL("image/png") // 创建一个新的图片元素 // let newImg = document.createElement("img") // newImg.src = img // 将新图片添加到文档中 // document.body.appendChild(newImg) this.selectBase64 = img this.selectState = true // 创建一个链接元素用于下载 // var downloadLink = document.createElement("a") // downloadLink.href = img // // 为下载的文件命名 // downloadLink.download = this.inputId + ".png" // // 触发下载 // downloadLink.click() }) }, // 关闭 closeState() { this.selectState = false }, aaa() {}, }, }) </script> </body> </html>