| @ -0,0 +1,261 @@ | |||||
| <template> | |||||
| <view class="page__view"> | |||||
| <!-- 导航栏 --> | |||||
| <navbar leftClick @leftClick="$utils.navigateBack" bgColor="#4883F9" color="#FFFFFF" /> | |||||
| <view style="width: 750rpx; height: 1184rpx; overflow: hidden;"> | |||||
| <canvas id="myCanvas" canvas-id="firstCanvas1" type="2d" style="width: 100%; height: 100%;"></canvas> | |||||
| </view> | |||||
| <view class="flex bottom"> | |||||
| <view class="flex"> | |||||
| <button class="btn" @click="saveImg">保存到手机</button> | |||||
| </view> | |||||
| </view> | |||||
| </view> | |||||
| </template> | |||||
| <script> | |||||
| export default { | |||||
| data() { | |||||
| return { | |||||
| wxCodeImage: '', | |||||
| baseUrl: 'https://image.hhlm1688.com/', | |||||
| canvas: {}, | |||||
| details: {}, | |||||
| } | |||||
| }, | |||||
| async onLoad({ thesisId }) { | |||||
| uni.showLoading({ | |||||
| title: '加载中...' | |||||
| }); | |||||
| await this.getData(thesisId) | |||||
| await this.fetchQrCode(thesisId) | |||||
| uni.hideLoading(); | |||||
| this.draw() | |||||
| }, | |||||
| methods: { | |||||
| async getData(thesisId) { | |||||
| try { | |||||
| this.details = await this.$fetch('queryThesisById', { thesisId }) | |||||
| } catch (err) { | |||||
| } | |||||
| }, | |||||
| async fetchQrCode(thesisId) { | |||||
| try { | |||||
| const path = `pages_order/thesis/index?thesisId=${thesisId}` | |||||
| this.wxCodeImage = (await this.$fetch('getInviteCode', { path }))?.url | |||||
| } catch (err) { | |||||
| } | |||||
| }, | |||||
| drawTextWithManualLineBreaks(ctx, text, x, y, maxWidth, lineHeight) { | |||||
| let rows = 0 | |||||
| let size = 0 | |||||
| let lines = text.split('\n'); // 支持手动输入的换行符 | |||||
| for (let lIdx = 0; lIdx < lines.length; lIdx++) { | |||||
| let line = lines[lIdx] | |||||
| let row = '' | |||||
| for (let wIdx = 0; wIdx < line.length; wIdx++) { | |||||
| let word = line[wIdx] | |||||
| let metrics = ctx.measureText(row + word); | |||||
| if (metrics.width > maxWidth) { | |||||
| rows++ | |||||
| size += row.length | |||||
| console.log('--rows', rows, '--size', size) | |||||
| if (rows === 4 && size < text.length) { | |||||
| row = row.slice(0, -2) + '......' | |||||
| } | |||||
| ctx.fillText(row, x, y); | |||||
| row = '' | |||||
| y += lineHeight | |||||
| if (rows === 4) { | |||||
| break | |||||
| } | |||||
| } else { | |||||
| row += word | |||||
| } | |||||
| } | |||||
| if (rows === 4) { | |||||
| break | |||||
| } | |||||
| if (row) { | |||||
| rows++ | |||||
| size += row.length | |||||
| console.log('--rows', rows, '--size', size) | |||||
| if (rows === 4 && size < text.length) { | |||||
| row = row.slice(0, -2) + '......' | |||||
| } | |||||
| ctx.fillText(row, x, y); | |||||
| y += lineHeight | |||||
| if (rows === 4) { | |||||
| break | |||||
| } | |||||
| } | |||||
| } | |||||
| }, | |||||
| draw() { | |||||
| uni.showLoading({ | |||||
| title: "拼命绘画中..." | |||||
| }) | |||||
| wx.createSelectorQuery() | |||||
| .select('#myCanvas') // 绘制的canvas的id | |||||
| .fields({ | |||||
| node: true, | |||||
| size: true | |||||
| }) | |||||
| .exec(async (res) => { | |||||
| const canvas = res[0].node | |||||
| // 渲染上下文 | |||||
| const ctx = canvas.getContext('2d') | |||||
| // Canvas 画布的实际绘制宽高 | |||||
| const width = res[0].width | |||||
| const height = res[0].height | |||||
| // 初始化画布大小 | |||||
| const dpr = wx.getWindowInfo().pixelRatio | |||||
| //根据dpr调整 | |||||
| // dpr 2 4 | |||||
| // 3 6 | |||||
| console.log("--dpr", dpr) | |||||
| canvas.width = width * dpr | |||||
| canvas.height = height * dpr | |||||
| let Ratio = canvas.width / 750 | |||||
| this.canvas = canvas | |||||
| ctx.scale(dpr, dpr) | |||||
| ctx.clearRect(0, 0, width, height) | |||||
| ctx.fillStyle = '#fff' | |||||
| ctx.fillRect(0, 0, canvas.width, canvas.height) | |||||
| ctx.fillStyle = '#999999'; | |||||
| const fontSize = 28 * Ratio / dpr | |||||
| ctx.font = `${fontSize}px PingFangSC-regular`; | |||||
| const descX = 37 * Ratio / dpr | |||||
| const descY = 751 * Ratio / dpr | |||||
| const maxWidth = 677 * Ratio / dpr | |||||
| const lineHeight = 45 * Ratio / dpr | |||||
| const text = this.details.paperDesc || this.details.title | |||||
| this.drawTextWithManualLineBreaks(ctx, text, descX, descY, maxWidth, lineHeight) | |||||
| // 海报图片 | |||||
| const paperImage = canvas.createImage() | |||||
| paperImage.src = this.details.paperImage || this.details.image?.split?.(',')?.[0] | |||||
| paperImage.onload = () => { | |||||
| const x = 37 * Ratio / dpr | |||||
| const y = 21 * Ratio / dpr | |||||
| const w = 677 * Ratio / dpr | |||||
| const h = 687 * Ratio / dpr | |||||
| ctx.drawImage(paperImage, x, y, w, h) | |||||
| //二维码图片 | |||||
| const coderImage = canvas.createImage() | |||||
| coderImage.src = this.wxCodeImage | |||||
| coderImage.onload = () => { | |||||
| const x = 539 * Ratio / dpr | |||||
| const y = 987 * Ratio / dpr | |||||
| const size = 162 * Ratio / dpr | |||||
| ctx.drawImage(coderImage, x, y, size, size) | |||||
| uni.hideLoading() | |||||
| } | |||||
| } | |||||
| }) | |||||
| }, | |||||
| saveImg() { | |||||
| this.$authorize('scope.writePhotosAlbum').then((res) => { | |||||
| this.imgApi() | |||||
| }) | |||||
| }, | |||||
| imgApi() { | |||||
| uni.showLoading({ | |||||
| title: '保存中...' | |||||
| }); | |||||
| wx.canvasToTempFilePath({ | |||||
| x: 0, | |||||
| y: 0, | |||||
| width: this.canvas.width, | |||||
| height: this.canvas.height, | |||||
| canvas: this.canvas, | |||||
| success: (res) => { | |||||
| let tempFilePath = res.tempFilePath; | |||||
| this.saveImgToPhone(tempFilePath) | |||||
| }, | |||||
| fail: (err) => { | |||||
| console.log('--canvasToTempFilePath--fail', err) | |||||
| uni.hideLoading(); | |||||
| } | |||||
| }, this); | |||||
| }, | |||||
| saveImgToPhone(image) { | |||||
| /* 获取图片的信息 */ | |||||
| uni.getImageInfo({ | |||||
| src: image, | |||||
| success: function(image) { | |||||
| /* 保存图片到手机相册 */ | |||||
| uni.saveImageToPhotosAlbum({ | |||||
| filePath: image.path, | |||||
| success: function() { | |||||
| uni.showModal({ | |||||
| title: '保存成功', | |||||
| content: '图片已成功保存到相册', | |||||
| showCancel: false | |||||
| }); | |||||
| }, | |||||
| complete(res) { | |||||
| console.log(res); | |||||
| uni.hideLoading(); | |||||
| } | |||||
| }); | |||||
| } | |||||
| }); | |||||
| } | |||||
| }, | |||||
| } | |||||
| </script> | |||||
| <style scoped lang="scss"> | |||||
| .page__view { | |||||
| background: $uni-bg-color-grey; | |||||
| } | |||||
| .bottom { | |||||
| position: fixed; | |||||
| left: 0; | |||||
| bottom: 0; | |||||
| width: 100vw; | |||||
| height: 154rpx; | |||||
| padding-bottom: env(safe-area-inset-bottom); | |||||
| background: #FFFFFF; | |||||
| .btn { | |||||
| padding: 20rpx 77rpx; | |||||
| font-size: 28rpx; | |||||
| color: #FFFFFF; | |||||
| background: #4883F9; | |||||
| border-radius: 14rpx; | |||||
| } | |||||
| } | |||||
| </style> | |||||