Commit c0e9da66 by yuzhenWang

做到了生成图片

parent a428b359
<template>
<view class="generate-image-container">
<!-- 插槽用于放置需要生成图片的内容 -->
<view class="content-container" ref="captureElement" v-if="!generatedImage">
<slot></slot>
</view>
<!-- 生成的图片预览 -->
<view class="preview-container" v-if="generatedImage && showPreview">
<image :src="generatedImage" mode="widthFix" class="preview-image"></image>
</view>
</view>
</template>
<script>
import UQRCode from 'uqrcodejs';
import { elementToImage } from '@/util/htmlToImage';
export default {
name: 'GenerateImage',
props: {
// 是否显示预览
showPreview: {
type: Boolean,
default: true
},
// 二维码内容(如果不需要二维码可不传)
qrCodeContent: {
type: String,
default: ''
},
// 二维码大小
qrCodeSize: {
type: Number,
default: 110
},
// 二维码容器样式
qrCodeContainerStyle: {
type: Object,
default: () => ({
position: 'absolute',
bottom: '10rpx',
right: '10rpx',
background: '#fff',
padding: '10rpx',
borderRadius: '10rpx',
boxShadow: '0 0 10rpx rgba(0,0,0,0.1)'
})
},
// 存储的key,用于缓存
storageKey: {
type: String,
default: 'savedGeneratedImage'
},
// 最大重试次数
maxRetryCount: {
type: Number,
default: 3
},
// 是否启用缓存
enableCache: {
type: Boolean,
default: true
},
// 图片质量(0-1)
quality: {
type: Number,
default: 0.7
}
},
data() {
return {
generatedImage: '', // 生成的图片
isContentReady: false, // 内容是否准备就绪
retryCount: 0 // 重试次数
}
},
mounted() {
this.init();
},
methods: {
init() {
// 检查是否有缓存的图片
if (this.enableCache) {
const cachedImage = uni.getStorageSync(this.storageKey);
if (cachedImage) {
this.generatedImage = cachedImage;
this.$emit('success', cachedImage);
return;
}
}
// 重置状态
this.isContentReady = false;
this.retryCount = 0;
// 模拟内容加载完成
this.handleContentReady();
},
// 内容准备就绪
handleContentReady() {
this.isContentReady = true;
this.generateImage();
},
// 生成图片
async generateImage() {
try {
this.$emit('start');
// 如果有二维码内容,先生成二维码
if (this.qrCodeContent) {
await this.makeQrcode();
await new Promise(resolve => setTimeout(resolve, 500));
}
// 执行截图
await this.captureImage();
this.$emit('success', this.generatedImage);
} catch (error) {
console.error('生成图片失败:', error);
this.$emit('error', error);
this.retryGenerate();
}
},
// 重试机制
retryGenerate() {
if (this.retryCount < this.maxRetryCount) {
this.retryCount++;
const delay = 1000 * this.retryCount;
setTimeout(() => {
this.generateImage();
}, delay);
} else {
this.$emit('fail', '生成图片失败,请稍后再试');
}
},
// 生成二维码
makeQrcode() {
return new Promise((resolve, reject) => {
if (!this.qrCodeContent) {
resolve();
return;
}
// 创建实例
const qr = new UQRCode();
// 设置二维码内容
qr.data = this.qrCodeContent;
qr.size = this.qrCodeSize;
qr.foregroundColor = '#000000';
qr.backgroundColor = '#FFFFFF';
qr.margin = 10;
qr.errorCorrectLevel = UQRCode.errorCorrectLevel.H;
try {
// 调用制作二维码方法
qr.make();
// 获取canvas上下文
const ctx = uni.createCanvasContext('qrcode', this);
// 清空画布
ctx.clearRect(0, 0, this.qrCodeSize, this.qrCodeSize);
// 将二维码绘制到canvas上
qr.canvasContext = ctx;
qr.drawCanvas();
// 绘制完成
ctx.draw(true, () => {
resolve();
});
} catch (err) {
reject(err);
}
});
},
// 截图方法
async captureImage() {
try {
// 获取DOM元素
const element = this.$refs.captureElement.$el;
// 调用工具函数生成图片
const imageData = await elementToImage(element);
// 压缩图片
const compressedImage = await this.compressImage(imageData);
this.generatedImage = compressedImage;
// 缓存图片
if (this.enableCache) {
uni.setStorageSync(this.storageKey, compressedImage);
}
} catch (error) {
throw error;
}
},
// 压缩图片
compressImage(base64) {
return new Promise((resolve) => {
const img = new Image();
img.src = base64;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置压缩后的宽高
const maxWidth = 800;
const maxHeight = 1200;
let width = img.width;
let height = img.height;
if (width > maxWidth) {
height *= maxWidth / width;
width = maxWidth;
}
if (height > maxHeight) {
width *= maxHeight / height;
height = maxHeight;
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
// 降低质量
resolve(canvas.toDataURL('image/jpeg', this.quality));
};
});
},
// 保存图片到相册
saveImage() {
if (!this.generatedImage) {
this.$emit('error', '没有可保存的图片');
return;
}
if (uni.downloadFile) {
uni.downloadFile({
url: this.generatedImage,
success: (res) => {
if (res.statusCode === 200) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
this.$emit('save-success');
},
fail: (err) => {
this.$emit('save-error', err);
}
});
}
},
fail: (err) => {
this.$emit('save-error', err);
}
});
} else {
// H5环境下的处理方式
const link = document.createElement('a');
link.href = this.generatedImage;
link.download = 'generated-image.png';
link.click();
this.$emit('save-success');
}
},
// 重新生成图片
regenerate() {
if (this.enableCache) {
uni.removeStorageSync(this.storageKey);
}
this.generatedImage = '';
this.init();
},
// 获取生成的图片
getGeneratedImage() {
return this.generatedImage;
}
}
}
</script>
<style lang="scss" scoped>
.generate-image-container {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
position: relative;
.dropdown-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 100;
}
.content-container {
width: 100%;
height: auto;
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
border-radius: 16rpx 16rpx 0 0;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
z-index: 110;
transform: translateY(100%);
transition: transform 0.3s ease;
}
.preview-container {
flex: 1;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
.preview-image {
height: 100%;
width: auto;
object-fit: contain;
}
}
}
</style>
\ No newline at end of file
......@@ -31,7 +31,7 @@
import * as environment from "@/environments/environment";
import UQRCode from 'uqrcodejs';
import { elementToImage } from '@/util/htmlToImage';
import registerBg from '@/static/registerBg.png'
import { initJssdkShare, setWechatShare } from '@/util/fiveshare';
export default {
......@@ -133,11 +133,7 @@ export default {
const delay = 1000 * this.retryCount;
console.log(`第${this.retryCount}次重试,${delay}ms后重试...`);
// uni.showToast({
// title: `生成中,请稍候...(${this.retryCount}/${this.maxRetryCount})`,
// icon: 'none',
// duration: delay
// });
setTimeout(() => {
this.generateQrcodeAndCapture();
......
......@@ -82,6 +82,7 @@
></join-popup>
<!-- <tabBar :currentPage="currentPage"></tabBar> -->
</view>
<uni-popup ref="popup" type="top" background-color="#fff">
<view class="descriptionBox">
......@@ -259,7 +260,7 @@
loginType : uni.getStorageSync('loginType'),
userInfo:{} ,//用户信息,
productItem:{},
dataToken:''
dataToken:'',
}
},
components: {
......@@ -270,7 +271,7 @@
courseItem,
JoinPopup,
PartnerTipPopup,
restrictedTip
restrictedTip,
},
onShow() {
......@@ -291,10 +292,7 @@
},
onLoad(options) {
console.log('options',options);
// if(options.dataToken){
// this.dataToken = options.dataToken
// }
if(uni.getStorageSync('dataToken')){
this.dataToken = uni.getStorageSync('dataToken')
}
......@@ -453,7 +451,6 @@
this.reLogin()
return
}
console.log('1111');
let loginType = uni.getStorageSync('loginType')
if(loginType == 'codelogin'){
this.querySystemMessage()
......
......@@ -8,35 +8,7 @@ let userInfo = {name:''}
if(uni.getStorageSync('cffp_userInfo')){
userInfo = JSON.parse(uni.getStorageSync('cffp_userInfo'))
}
//初始化
// export function initJssdkShare(callback, url) {
// console.log('签名',url);
// var url = url
// //这一步需要调用后台接口,返回需要的签名 签名时间戳 随机串 和公众号appid
// //注意url:window.location.href.split('#')[0] //
// // request.post("", {
// // url // url是当前页面的url
// // },
// let WxConfigRequestVO = {
// url:url,
// systemType:uni.getStorageSync('addSystemType')?uni.getStorageSync('addSystemType'):'1'
// }
// // @ts-ignore
// api.Wxshare(WxConfigRequestVO).then(res => {
// jWeixin.config({
// debug: false,//调试的时候需要 在app上回弹出errmg:config ok 的时候就证明没问题了 这时候就可以改为false
// appId: res.data.appId,//appid
// timestamp: res.data.timestamp,//时间戳
// nonceStr: res.data.nonceStr,//随机串
// signature: res.data.signature,//签名
// jsApiList: res.data.jsApiList//必填 是下面需要用到的方法集合
// })
// if(callback){
// callback()
// }
// })
// }
// 初始化SDK
export function initJssdkShare(callback, url) {
const WxConfigRequestVO = {
......
import html2canvas from 'html2canvas';
import {baseURL,apiURL,cffpURL,sfpUrl,imgUrl,scrmUrl} from "../environments/environment";
/**
* 将DOM元素转换为图片
......@@ -13,14 +14,40 @@ export const elementToImage = async (element, options = {}) => {
backgroundColor: null, // 透明背景
scale: 2, // 提高缩放以获得更清晰的图片
useCORS: true, // 允许跨域图片
allowTaint: true, // 允许污染图片
logging: false // 关闭日志
allowTaint: false, // 允许污染图片
logging: false, // 关闭日志,
delay: 10000
};
const canvas = await html2canvas(element, { ...defaultOptions, ...options });
return canvas.toDataURL('image/png');
} catch (error) {
console.error('生成图片失败:', error);
throw error;
}
};
\ No newline at end of file
};
export function convertImageToBase64Frontend (url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous'; // 处理跨域问题
img.src = url;
console.log('img',img);
img.onload = () =>{
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.height = img.naturalHeight;
canvas.width = img.naturalWidth;
ctx.drawImage(img, 0, 0);
try {
const dataURL = canvas.toDataURL('image/png');
resolve(dataURL);
} catch (e) {
reject(e);
}
};
img.onerror = function() {
reject(new Error('图片加载失败'));
};
});
}
\ No newline at end of file
import {apiURL,cffpURL,sfpUrl} from "../environments/environment";
import api from "@/api/api";
// 白名单,不需要携带token就允许被访问的接口
const whiteApiList = [`${apiURL}/authorize/obtainToken`,
`${apiURL}/authorize/checkToken`,
`${cffpURL}/user/loginVerification`,
`${apiURL}/appVersion/checkIsUpdate`,
`${cffpURL}/accessLog/accessLogSave`,
`${cffpURL}/user/powerQuery`,`${cffpURL}/user/wxLogin`,
`${cffpURL}/certificate/officialWebsiteDetail`,
`${apiURL}/verificationCode`,
`${sfpUrl}/sfp/sfpMain/pocessTracking`,
`${cffpURL}/partner/queryById`,
];
export const interceptor = () => {
uni.addInterceptor('request', {
// 请求拦截器
invoke(args) {
// 当本地没有token,并且接口地址没在白名单内,需要重新获取token
if (!uni.getStorageSync('uni-token') && !whiteApiList.includes(args.url)) {
const params = {
ticket: 'uni-app',
loginId: null
}
let h5userId = uni.getStorageSync('cffp_userId');
if (h5userId) {
params.loginId = h5userId;
}
uni.request({
url: `${apiURL}/authorize/obtainToken`,
method: 'POST',
data: params,
success: (res) => {
if (res.statusCode === 200) {
uni.setStorageSync('uni-token', res.data['data']['token']);
let isHas = window.location.href.indexOf('?')==-1?'?':'&';
window.location.href = window.location.href + isHas + 't_reload=' + new Date().getTime();
}
}
})
}
//设置请求头及token
args.header = {
'content-type': args.method === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded',
'X-Authorization': uni.getStorageSync('uni-token') ? uni.getStorageSync('uni-token') : '',
// 'Access-Control-Allow-Headers': 'appId',
// 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
// 'Access-Control-Max-Age': 86400,
}
},
// 响应拦截器,可以对数据进行预处理
success(args) {
if(args && args.data && args.data.errorCode && "T001"==args.data.errorCode){
uni.removeStorageSync('isLogin');
uni.switchTab({
url:'/pages/index/index'
})
}
},
fail() {
// console.log('interceptor-fail', err)
},
complete() {
// uni.hideLoading()
}
})
}
// import {apiURL,cffpURL,sfpUrl} from "../environments/environment";
// import api from "@/api/api";
// // 白名单,不需要携带token就允许被访问的接口
// const whiteApiList = [
// `${apiURL}/authorize/obtainToken`,
// `${apiURL}/authorize/checkToken`,
// `${cffpURL}/user/loginVerification`,
// `${apiURL}/appVersion/checkIsUpdate`,
// `${cffpURL}/accessLog/accessLogSave`,
// `${cffpURL}/user/powerQuery`,
// `${cffpURL}/user/wxLogin`,
// `${cffpURL}/certificate/officialWebsiteDetail`,
// `${apiURL}/verificationCode`,
// `${sfpUrl}/sfp/sfpMain/pocessTracking`,
// `${cffpURL}/partner/queryById`,
// ];
// // 判断是否为资源请求(图片、字体等)
// const isResourceRequest = (url) => {
// const resourceExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.ttf', '.woff', '.woff2'];
// return resourceExtensions.some(ext => url.includes(ext));
// };
// export const interceptor = () => {
// uni.addInterceptor('request', {
// // 请求拦截器
// invoke(args) {
// // 资源请求不添加认证头,避免触发OPTIONS预检请求
// if (isResourceRequest(args.url)) {
// // 对于资源请求,使用更简单的请求头
// args.header = {
// 'content-type': 'application/x-www-form-urlencoded'
// };
// return;
// }
// // 当本地没有token,并且接口地址没在白名单内,需要重新获取token
// if (!uni.getStorageSync('uni-token') && !whiteApiList.includes(args.url)) {
// const params = {
// ticket: 'uni-app',
// loginId: null
// }
// let h5userId = uni.getStorageSync('cffp_userId');
// if (h5userId) {
// params.loginId = h5userId;
// }
// uni.request({
// url: `${apiURL}/authorize/obtainToken`,
// method: 'POST',
// data: params,
// success: (res) => {
// if (res.statusCode === 200) {
// uni.setStorageSync('uni-token', res.data['data']['token']);
// let isHas = window.location.href.indexOf('?')==-1?'?':'&';
// window.location.href = window.location.href + isHas + 't_reload=' + new Date().getTime();
// }
// }
// })
// }
// // 设置API请求头及token
// args.header = {
// 'content-type': args.method === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded',
// 'X-Authorization': uni.getStorageSync('uni-token') ? uni.getStorageSync('uni-token') : '',
// }
// },
// // 响应拦截器,可以对数据进行预处理
// success(args) {
// if(args && args.data && args.data.errorCode && "T001"==args.data.errorCode){
// uni.removeStorageSync('isLogin');
// uni.switchTab({
// url:'/pages/index/index'
// })
// }
// },
// fail(err) {
// console.log('interceptor-fail', err)
// },
// complete() {
// // uni.hideLoading()
// }
// })
// // 添加image拦截器,专门处理图片请求
// uni.addInterceptor('image', {
// invoke(args) {
// // 图片请求使用简单请求头
// args.header = {
// 'content-type': 'application/x-www-form-urlencoded'
// };
// }
// });
// }
// 旧版的拦截器
import {apiURL,cffpURL,sfpUrl} from "../environments/environment";
import api from "@/api/api";
// 白名单,不需要携带token就允许被访问的接口
const whiteApiList = [`${apiURL}/authorize/obtainToken`,
`${apiURL}/authorize/checkToken`,
`${cffpURL}/user/loginVerification`,
`${apiURL}/appVersion/checkIsUpdate`,
`${cffpURL}/accessLog/accessLogSave`,
`${cffpURL}/user/powerQuery`,`${cffpURL}/user/wxLogin`,
`${cffpURL}/certificate/officialWebsiteDetail`,
`${apiURL}/verificationCode`,
`${sfpUrl}/sfp/sfpMain/pocessTracking`,
`${cffpURL}/partner/queryById`,
];
export const interceptor = () => {
uni.addInterceptor('request', {
// 请求拦截器
invoke(args) {
// 当本地没有token,并且接口地址没在白名单内,需要重新获取token
if (!uni.getStorageSync('uni-token') && !whiteApiList.includes(args.url)) {
const params = {
ticket: 'uni-app',
loginId: null
}
let h5userId = uni.getStorageSync('cffp_userId');
if (h5userId) {
params.loginId = h5userId;
}
uni.request({
url: `${apiURL}/authorize/obtainToken`,
method: 'POST',
data: params,
success: (res) => {
if (res.statusCode === 200) {
uni.setStorageSync('uni-token', res.data['data']['token']);
let isHas = window.location.href.indexOf('?')==-1?'?':'&';
window.location.href = window.location.href + isHas + 't_reload=' + new Date().getTime();
}
}
})
}
//设置请求头及token
args.header = {
'content-type': args.method === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded',
'X-Authorization': uni.getStorageSync('uni-token') ? uni.getStorageSync('uni-token') : '',
// 'Access-Control-Allow-Headers': 'appId',
// 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
// 'Access-Control-Max-Age': 86400,
}
},
// 响应拦截器,可以对数据进行预处理
success(args) {
if(args && args.data && args.data.errorCode && "T001"==args.data.errorCode){
uni.removeStorageSync('isLogin');
uni.switchTab({
url:'/pages/index/index'
})
}
},
fail() {
// console.log('interceptor-fail', err)
},
complete() {
// uni.hideLoading()
}
})
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment