You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

284 lines
8.4 KiB

<template>
<view class="placard">
<view class="placard-content">
<view class="img-box" :style="{ width: canvasW + 'px', height: canvasH + 'px' }">
<img v-show="tempFilePath" :style="{ width: canvasW + 'px', height: canvasH + 'px' }" :src="tempFilePath" alt="" />
</view>
<div class="qrcode" style="display: none;">
<vue-qrcode :value="qrCodeValue" :width="qrCodeSize"
:color="{ dark: qrCodeDarkColor, light: qrCodeLightColor }" :margin="margin"
type="image/png"></vue-qrcode>
</div>
<canvas :style="{ width: canvasW + 'px', height: canvasH + 'px' }"
canvas-id="myCanvas" id="myCanvas"></canvas>
<view class="add-btn">
<view class="btn">
长按图片保存到手机
</view>
</view>
</view>
</view>
</template>
<script>
import drawTextVertical from '@/utils/Canvas.js'
import VueQrcode from 'vue-qrcode'
export default {
name: 'Placard',
components : { VueQrcode },
data() {
return {
qrCodeValue: '',
// qrCodeValue: import.meta.env.VITE_REDIRECT_URI + `?vid=${this.getUserInfo()}`,
qrCodeSize: 180 * (window.innerWidth / 750),
qrCodeDarkColor: '#000',
qrCodeLightColor: '#fff',
margin: 0,
//画布信息
canvasW: 299,
canvasH: 403,
//设备信息
systemInfo: {},
//图片路径
tempFilePath: '',
_rpx: 0,
_center: 0
}
},
created(){
console.log(this.configList);
console.log(this.configList.user_url);
this.qrCodeValue = `${this.configList.user_url}?vid=${this.userInfo.id}`
},
methods: {
async draw() { //绘制海报
uni.showLoading({
title: '拼命绘画中...'
})
let self = this
//获取设备信息
self.systemInfo = await self.getSystemInfo();
//转换相对单位
let rpx = self.systemInfo.windowWidth / 750
self._rpx = rpx
//设置画布宽高
self.canvasW = 542 * rpx
self.canvasH = 731 * rpx
//海报背景
let bg = new Image();
bg.src = this.configList.qr_code_image
// bg.src = this.configList.user_url + '/static/placard/placard-bg.png'
//logo
let logo = new Image();
logo.src = this.configList.logo_image
// logo.src = import.meta.env.VITE_REDIRECT_URI + '/static/placard/logo.png'
console.log(this.configList.logo_image);
bg.onload = () => {
logo.onload = () => { //确保背景和logo加载完成(不然海报可能会少logo)
setTimeout(() => {
let ctx = document.querySelector('canvas').getContext('2d')
let img = document.querySelector('.qrcode img')
let center = self.canvasW / 2; //画布中心位置
self._center = center
//绘制图片
ctx.drawImage(bg, 0, 0, self.canvasW, self.canvasH)
ctx.drawImage(img, center - (self.qrCodeSize / 2), 295 * rpx, self.qrCodeSize, self
.qrCodeSize)
ctx.drawImage(logo, center - (100 * rpx / 2) , 60 * rpx , 100 * rpx, 100 * rpx)
//绘制文字
ctx.font = `bold ${40 * rpx}px 楷体`
ctx.textAlign = 'center'
ctx.fillStyle = "#59B495";
ctx.fillText('上门服务', center, 200 * rpx, 400)
ctx.fillStyle = "#0A543B";
ctx.font = `100 ${25 * rpx}px 楷体`
ctx.fillText(`一扫疲劳 舒服入眠`, center, 240 * rpx, 400)
ctx.font = `100 ${25 * rpx}px 宋体`
ctx.fillStyle = "#0A543B";
ctx.textAlign = 'center';
drawTextVertical(ctx, '微信扫码下单', 130 * rpx, 315 * rpx, self.qrCodeSize);
ctx.textAlign = 'center';
drawTextVertical(ctx, '在线选择技师', 400 * rpx, 315 * rpx, self.qrCodeSize);
ctx.font = `100 ${18 * rpx}px 宋体`
ctx.fillStyle = '#053323'
ctx.fillText(`长按扫一扫下单可领取`, center, 525 * rpx, 400)
ctx.font = `bold ${43 * rpx}px 宋体`
ctx.fillStyle = '#EC8D44'
ctx.fillText(`200元`, center, 580 * rpx, 400)
ctx.font = `100 ${18 * rpx}px 宋体`
ctx.fillText(`百万明星技师在线接单`, center, 625 * rpx, 400)
//画图形
this.paintingCapsule(ctx, center - (90 * rpx / 2), 250 * rpx, 90 * rpx, 25 * rpx,
13 * rpx, '#59B495', 'time')
this.paintingCapsule(ctx, center + (130 * rpx / 2), 530 * rpx, 25 * rpx, 70 * rpx,
13 * rpx, '#BCEED6', 'coupon')
////画海报最后的标签列表
this.drawList(ctx, 135 * rpx, 650 * rpx, 60 * rpx, 20 * rpx, 10 * rpx, '#59B495')
uni.canvasToTempFilePath({
x: 0, // 起点坐标
y: 0,
width: self.canvasW, // canvas 宽
height: self.canvasH, // canvas 高
canvasId: 'myCanvas', // canvas id
success(res) {
uni.hideLoading()
self.tempFilePath = res.tempFilePath //相对路径
}
})
})
}
}
},
// 获取设备信息
getSystemInfo() {
return new Promise((req, rej) => {
uni.getSystemInfo({
success: function(res) {
req(res)
}
});
})
},
paintingCapsule(ctx, x, y, width, height, radius, color, current) { //画椭圆(胶囊)
// 开始新的路径
ctx.beginPath();
// 绘制左上角圆角
ctx.moveTo(x + radius, y);
ctx.arcTo(x + width, y, x + width, y + height, radius);
// 绘制右上角圆角
ctx.arcTo(x + width, y + height, x, y + height, radius);
// 绘制右下角圆角
ctx.arcTo(x, y + height, x, y, radius);
// 绘制左下角圆角
ctx.arcTo(x, y, x + width, y, radius);
// 闭合路径(实际上在arcTo后已经是闭合的,但显式调用可以增加可读性)
ctx.closePath();
// 设置填充颜色
ctx.fillStyle = color;
// 填充路径
ctx.fill();
//下面是再写不同区域的内容
if (current == 'time') {
ctx.fillStyle = "#fff";
ctx.font = `100 ${17 * this._rpx}px 楷体`
ctx.fillText(`24小时`, this._center, 267 * this._rpx);
} else if (current == 'coupon') {
ctx.fillStyle = "#EC8D44";
ctx.font = `100 ${13 * this._rpx}px 楷体`
let offset = 13 * this._rpx
drawTextVertical(ctx, '优惠券', 349 * this._rpx, 555 * this._rpx, height - offset);
}
},
drawList(ctx, x, y, width, height, radius, color) { //画海报最后的标签列表
let list = ['安全', '正规', '健康', '便捷']
let offset = 15 //偏移量
let currentTagInfo = {
x
}
list.forEach(item => {
// 开始新的路径
ctx.beginPath();
// 绘制左上角圆角
ctx.moveTo(currentTagInfo.x + radius, y);
ctx.arcTo(currentTagInfo.x + width, y, currentTagInfo.x + width, y + height, radius);
// 绘制右上角圆角
ctx.arcTo(currentTagInfo.x + width, y + height, currentTagInfo.x, y + height, radius);
// 绘制右下角圆角
ctx.arcTo(currentTagInfo.x, y + height, currentTagInfo.x, y, radius);
// 绘制左下角圆角
ctx.arcTo(currentTagInfo.x, y, currentTagInfo.x + width, y, radius);
// 设置边框颜色
ctx.strokeStyle = color;
// 设置边框宽度(可选)
ctx.lineWidth = 1; // 或者你想要的任何宽度
// 闭合路径(实际上在arcTo后已经是闭合的,但显式调用可以增加可读性)
ctx.closePath();
// 绘制边框
ctx.stroke();
//圆点
ctx.beginPath();
ctx.fillStyle = color;
ctx.arc(currentTagInfo.x + (10 * this._rpx), y + (10 * this._rpx), 2, 0,360)
ctx.fill()
//绘制文本
ctx.font = `100 ${13 * this._rpx}px 楷体`
ctx.fillText(item, currentTagInfo.x + (33 * this._rpx), y + (15 * this._rpx), 400)
let next = currentTagInfo.x + width + offset; //下一个标签的位置
currentTagInfo = { x : next }
})
},
}
}
</script>
<style lang="scss" scoped>
.placard {
display: flex;
min-height: 100vh;
align-items: center;
justify-content: center;
.placard-content{
display: flex;
flex-direction: column;
align-items: center;
.add-btn {
display: flex;
justify-content: center;
align-items: center;
height: 100rpx;
width: 750rpx;
.btn {
display: flex;
align-items: center;
justify-content: center;
width: 72%;
height: 80rpx;
border-radius: 40rpx;
color: white;
font-size: 28rpx;
background: linear-gradient(180deg, #6FDFBE, #5AC796);
margin-top: 40rpx;
}
}
}
}
canvas{
opacity: 1;
position: fixed;
top: 100%;
left: 0;
}
</style>