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.

363 lines
9.2 KiB

12 months ago
<template>
<view :style="viewColor">
<view class='poster-poster' v-if="posterStatus">
<view class='poster-pop'>
<image src='../../../static/images/poster-close.png' class='close' @click="posterImageClose"></image>
<view class="user-code">
<image class="canvas" :style="{width:wd+'px', height:hg+'px'}" :src="posterImage" v-if="posterImage"></image>
<canvas class="canvas" :style="{width:wd+'px',height:hg+'px'}" canvas-id="myCanvas" v-else></canvas>
</view>
<!-- #ifndef H5 -->
<view v-if="posterImage" class='save-poster' @click="savePosterPath(posterImage)">保存到手机</view>
<!-- #endif -->
<!-- #ifdef H5 -->
<view v-if="posterImage" class="keep">长按图片可以保存到手机</view>
<!-- #endif -->
</view>
</view>
<view class='mask' v-if="posterImage"></view>
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import { imgToBase } from '@/api/user.js';
import { mapGetters } from 'vuex';
export default {
computed: mapGetters(['viewColor']),
data() {
return {
wd: 225,
hg: 357,
posterImage: "",
posterBag: '../static/images/poster-bag.png',
}
},
props: {
picData: {
type: Object
},
posterStatus: {
type: Boolean,
default: false
}
},
watch: {
posterStatus(data) {
if (data) {
this.posterShow()
}
},
},
onLoad() {},
methods: {
async posterShow() {
let that = this;
uni.showLoading({
title: '海报生成中',
mask: true
});
let arr, bag_pic, goods_img, mp_code
goods_img = await that.imgToBase(that.picData.goodsPic)
mp_code = await that.imgToBase(that.picData.codePic)
// #ifdef H5
arr = [that.posterBag, goods_img, mp_code]
// #endif
// #ifdef MP || APP-PLUS
arr = [that.posterBag, await that.downloadFilestoreImage(that.picData.goodsPic), await that.downloadFilestoreImage(
that.picData.codePic)]
// #endif
that.bargainPosterCanvas(arr, that.picData.title, that.picData.label, that.picData.msg, that.picData.price,
that.wd,
that.hg,
(tempFilePath) => {
that.posterImage = tempFilePath
});
},
async imgToBase(url) {
let res = await imgToBase({
image: url
})
return res.data.image
},
savePosterPath(url) {
let that = this;
// #ifdef MP
uni.getSetting({
success(res) {
if (!res.authSetting['scope.writePhotosAlbum']) {
uni.authorize({
scope: 'scope.writePhotosAlbum',
success() {
uni.saveImageToPhotosAlbum({
filePath: url,
success: function(res) {
that.$util.Tips({
title: '保存成功',
icon: 'success'
});
},
fail: function(res) {
that.$util.Tips({
title: '保存失败'
});
}
});
}
});
} else {
uni.saveImageToPhotosAlbum({
filePath: url,
success: function(res) {
that.$util.Tips({
title: '保存成功',
icon: 'success'
});
},
fail: function(res) {
that.$util.Tips({
title: '保存失败'
});
}
});
}
}
});
// #endif
// #ifdef APP-PLUS
uni.saveImageToPhotosAlbum({
filePath: that.posterImage,
success: function(res) {
that.posterImageClose();
that.$util.Tips({
title: '保存成功',
icon: 'success'
});
},
fail: function(res) {
that.$util.Tips({
title: '保存失败'
});
},
})
// #endif
},
posterImageClose() {
this.$emit('update:posterStatus', false)
this.posterImage = ""
},
//图片转符合安全域名路径
downloadFilestoreImage(url) {
// #ifdef MP
let ishttps = url.split('//')[0] == 'https:'
if (!ishttps) {
url = 'https://'+url.split('//')[1]
}
// #endif
return new Promise((resolve, reject) => {
let that = this;
uni.downloadFile({
url: url,
success: function(res) {
resolve(res.tempFilePath);
},
fail: function() {
return that.$util.Tips({
title: ''
});
}
});
})
},
bargainPosterCanvas(arr2, title, label, msg, price, wd, hg, successFn) {
let that = this;
const ctx = uni.createCanvasContext('myCanvas', this);
ctx.clearRect(0, 0, 0, 0);
/**
* 只能获取合法域名下的图片信息,本地调试无法获取
*
*/
ctx.fillStyle = '#ccc';
ctx.fillRect(0, 0, wd, hg);
uni.getImageInfo({
src: arr2[0],
success: (res) => {
console.log(arr2)
const WIDTH = res.width;
const HEIGHT = res.height;
ctx.drawImage(arr2[0], 0, 0, wd, hg);
// 保证在不同机型对应坐标准确
let labelx = 0.6656 //标签x
let labely = 0.167 //标签y
let pricex = 0.1847 //价格x
let pricey = 0.175 //价格y
let codex = 0.385 //二维码
let codey = 0.77
let picturex = 0.1571 //商品图左上点
let picturey = 0.2916
let picturebx = 0.6857 //商品图右下点
let pictureby = 0.3916
let msgx = 0.1036 //msg
let msgy = 0.2306
ctx.drawImage(arr2[1], wd * picturex, hg * picturey, wd * picturebx, hg * pictureby);
ctx.save();
ctx.drawImage(arr2[2], wd * codex, hg * codey, 55, 55);
ctx.save();
//标题
const CONTENT_ROW_LENGTH = 25;
let [contentLeng, contentArray, contentRows] = that.textByteLength(title, CONTENT_ROW_LENGTH);
if (contentRows > 2) {
contentRows = 2;
let textArray = contentArray.slice(0, 2);
textArray[textArray.length - 1] += '…';
contentArray = textArray;
}
ctx.setTextAlign('left');
ctx.setFillStyle('#000');
if (contentArray.length < 2) {
ctx.setFontSize(16);
} else {
ctx.setFontSize(14);
}
let contentHh = 3;
for (let m = 0; m < contentArray.length; m++) {
if (m) {
ctx.fillText(contentArray[m], 20, 25 + contentHh * m + 13, 1100);
} else {
ctx.fillText(contentArray[m], 20, 25, 1100);
}
}
// 标签内容
ctx.setTextAlign('left')
ctx.setFontSize(10);
ctx.setFillStyle('#FFF');
ctx.fillText(label, wd * labelx, hg * labely);
ctx.save();
// 价格
ctx.setFillStyle('red');
// ctx.setFontSize(16);
ctx.font = "bold 18px Arial";
ctx.fillText(price, wd * pricex, hg * pricey);
ctx.save();
// msg
ctx.setFontSize(8);
ctx.setFillStyle('#3F3F3F');
ctx.fillText(msg, wd * msgx, hg * msgy);
ctx.save();
ctx.draw(true, () => {
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
fileType: 'png',
quality: 1,
success: (res) => {
console.log(res)
successFn && successFn(res.tempFilePath);
uni.hideLoading();
}
}, this)
});
},
fail: function(err) {
uni.hideLoading();
that.Tips({
title: '无法获取图片信息'
});
}
})
},
textByteLength(text, num) {
let strLength = 0;
let rows = 1;
let str = 0;
let arr = [];
for (let j = 0; j < text.length; j++) {
if (text.charCodeAt(j) > 255) {
strLength += 2;
if (strLength > rows * num) {
strLength++;
arr.push(text.slice(str, j));
str = j;
rows++;
}
} else {
strLength++;
if (strLength > rows * num) {
arr.push(text.slice(str, j));
str = j;
rows++;
}
}
}
arr.push(text.slice(str, text.length));
return [strLength, arr, rows] // [处理文字的总字节长度,每行显示内容的数组,行数]
},
}
}
</script>
<style>
.poster-poster {
width: 100%;
height: 100%;
width: 450rpx;
height: 714rpx;
}
.poster-pop {
position: fixed;
left: 50%;
transform: translateX(-50%);
top: 50%;
margin: 0 auto;
margin-top: -357rpx;
z-index: 999;
}
.poster-pop image {
width: 100%;
height: 100%;
display: block;
}
.poster-pop .close {
width: 46rpx;
height: 75rpx;
position: fixed;
right: 0;
top: -73rpx;
display: block;
z-index: 3999;
}
.poster-pop .save-poster {
background-color: var(--view-theme);
font-size: 22rpx;
color: #fff;
text-align: center;
height: 76rpx;
line-height: 76rpx;
width: 100%;
margin-top: 20rpx;
}
.poster-pop .keep {
color: #fff;
text-align: center;
font-size: 25rpx;
margin-top: 10rpx;
}
.mask {
z-index: 300 !important;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
z-index: 9;
}
</style>