277 lines
7.4 KiB
Vue
Raw Permalink Normal View History

2025-05-08 09:16:37 +08:00
<template>
<!-- 分享海报 -->
<view class="share" @click="closeShow" catchtouchmove="preventD">
<view class="box" v-show="!showPrivacy">
<canvas class="canvas" id="myCanvas" canvas-id="myCanvas" @click.stop></canvas>
<view class="btn" @tap.stop="saveImage">保存图片</view>
</view>
</view>
<!-- 隐私协议弹窗 -->
<privacy-popup :show-dialog="showPrivacy" @close="showPrivacy = false" @agree.stop="showPrivacy = false" @refuse="showPrivacy = false" />
</template>
<script>
import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
import { getOldDay, saveImg, judgePrivacy, showToast } from '../common.js'
import { post } from '@/api/request.js'
import api from '@/api/index.js'
import privacyPopup from '../privacyPopup/index.vue'
export default {
components: {
privacyPopup
},
props: {
goods: Object
},
setup(props, context) {
const data = reactive({
canvasWidth: {},
ctx: null,
showImage: '',
avatar: '',
faceImg: '',
loading: false,
shareImg: '',
Color: uni.getStorageSync('theme_color'),
showPrivacy: false
})
// 关闭
function closeShow() {
context.emit('closeShow')
}
function draw1() {
data.ctx.setFontSize(20)
data.ctx.setFillStyle('white')
data.ctx.fillRect(0, 0, data.canvasWidth.width || 275, data.canvasWidth.height || 470)
data.ctx.drawImage(data.avatar, 15, 10, 30, 30)
data.ctx.setFontSize(12)
data.ctx.setFillStyle('#666666')
var nickname = uni.getStorageSync('nickname')
data.ctx.fillText(nickname, 50, 20)
data.ctx.setFontSize(11)
data.ctx.setFillStyle('#999999')
data.ctx.fillText(getOldDay(), 50, 40)
data.ctx.drawImage(data.faceImg, 15, 50, 245, 245)
data.ctx.font = 'warp bold 15px Arial,sans-serif '
data.ctx.setFillStyle('#111111')
toFormateStr(data.ctx, props.goods.title, 15, 315, 15, 230, 1)
data.ctx.setFontSize(12)
data.ctx.setFillStyle('#999999')
toFormateStr(data.ctx, props.goods.description.replace(/\s+/g, ''), 15, 335, 15, 230, 3)
data.ctx.setFontSize(12)
data.ctx.setFillStyle('#F14939')
let price = ''
if (props.goods.goods_size > 1) {
if (parseInt(props.goods.max_price) < parseInt(props.goods.min_price)) {
price = props.goods.max_price + '~' + props.goods.min_price
} else {
price = props.goods.min_price + '~' + props.goods.max_price
}
} else {
if (props.goods.group_goods[0].specs_type === 0) {
price = props.goods.group_goods[0].price
} else {
if (props.goods.group_goods[0].max_price === props.goods.group_goods[0].min_price) {
price = props.goods.group_goods[0].min_price
} else if (
parseInt(props.goods.group_goods[0].max_price) <
parseInt(props.goods.group_goods[0].min_price)
) {
price = props.goods.group_goods[0].max_price + '~' + props.goods.group_goods[0].min_price
} else {
price = props.goods.group_goods[0].min_price + '~' + props.goods.group_goods[0].max_price
}
}
}
data.ctx.fillText('¥', 15, 400)
data.ctx.setFontSize(15)
data.ctx.fillText(price, 27, 400)
data.ctx.setFillStyle('rgba(246, 246, 246, 0.9)')
data.ctx.fillRect(15, 410, 130, 55)
data.ctx.setFontSize(11)
data.ctx.setFillStyle('#999999')
data.ctx.fillText('长按识别图中小程序', 25, 430)
data.ctx.fillText('跟团购买>>', 25, 450)
data.ctx.drawImage(data.showImage, 165, 375, 90, 90)
data.ctx.draw()
}
// 文本换行
function toFormateStr(
ctx,
content,
drawX, // 15
drawY, // 335
lineHeight, // 15
lineMaxWidth, // 230
lineNum // 3
) {
var drawTxt = '' // 当前绘制的内容
var drawLine = 1 // 第几行开始绘制
var drawIndex = 0 // 当前绘制内容的索引
// 判断内容是否可以一行绘制完毕
if (ctx.measureText(content).width <= lineMaxWidth) {
ctx.fillText(content.substring(drawIndex, i), drawX, drawY)
} else {
for (var i = 0; i < content.length; i++) {
drawTxt += content[i]
if (ctx.measureText(drawTxt).width >= lineMaxWidth) {
if (drawLine >= lineNum) {
ctx.fillText(content.substring(drawIndex, i) + '..', drawX, drawY)
break
} else {
ctx.fillText(content.substring(drawIndex, i + 1), drawX, drawY)
drawIndex = i + 1
drawLine += 1
drawY += lineHeight
drawTxt = ''
}
} else {
// 内容绘制完毕但是剩下的内容宽度不到lineMaxWidth
if (i === content.length - 1) {
ctx.fillText(content.substring(drawIndex), drawX, drawY)
}
}
}
}
}
// 获取单张图片信息
const getImageInfo = async (imgSrc) => {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: imgSrc,
success: function(image) {
resolve(image.path)
},
fail(err) {
reject()
}
})
})
}
// 获取页面二维码
const getImg = () => {
return new Promise((resolve, reject) => {
uni.request({
url: api.url + '/api/v1/user/code',
method: 'POST',
data: {
page: 'pages/groups/index',
shop_goods_id: props.goods.id
},
header: {
Authorization: uni.getStorageSync('token') || '',
appid: api.appId
},
responseType: 'arraybuffer',
success: (res) => {
if (res.statusCode === 200) {
let base64 = ''
const bytes = new Uint8Array(res.data)
const len = bytes.byteLength
for (let i = 0; i < len; i++) {
base64 += String.fromCharCode(bytes[i])
}
base64 = `data:image/png;base64,${btoa(base64)}`
resolve(base64)
} else {
reject('')
}
},
})
})
}
onMounted(() => {
uni.showLoading({
mask: true,
title: '海报生成中...'
})
const instance = getCurrentInstance()
setTimeout(() => {
const query = uni.createSelectorQuery().in(instance)
query.select('#myCanvas').boundingClientRect(async (res) => {
console.log(res)
data.canvasWidth = res || {}
data.ctx = uni.createCanvasContext('myCanvas', instance)
data.avatar = await getImageInfo(uni.getStorageSync('avatar'))
data.faceImg = await getImageInfo(props.goods.face_img)
data.showImage = await getImg()
await draw1()
uni.hideLoading()
}).exec()
}, 200)
})
return {
...toRefs(data),
draw1,
closeShow,
getImg,
getImageInfo
}
},
methods: {
async saveImage() {
if(await judgePrivacy()) {
this.showPrivacy = true
return false
}
//保存到相册
const _this = this
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
success(res) {
saveImg(res.tempFilePath)
},
fail(err) {
}
}, _this)
}
}
}
</script>
<style lang="scss" scoped>
.share {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgba($color: #000000, $alpha: 0.7);
z-index: 202;
display: flex;
flex-direction: column;
justify-content: center;
.canvas {
width: 275px;
height: 470px;
box-sizing: border-box;
margin: 0 auto;
background-color: #fff;
}
.btn {
color: #fff;
background-color: v-bind('Color');
font-size: 30rpx;
width: 340rpx;
height: 76rpx;
line-height: 76rpx;
text-align: center;
margin: 60rpx auto 0;
border-radius: 76rpx;
}
}
</style>