import { Canvas, Image, Text, View } from '@tarojs/components' import Taro, { useReady } from '@tarojs/taro' import React, { useCallback, useRef, useState } from 'react' import style from './index.module.scss' import Dialog from '@/components/Dialog' import LayoutBlock from '@/components/layoutBlock' import Divider from '@/components/divider' import type { TablePropsType } from '@/components/table' import Table from '@/components/table' import NormalButton from '@/components/normalButton' import { alert } from '@/common/common' import { GenBarCodeOrQrCode, GetInvitationInfo } from '@/api' import { getCDNSource } from '@/common/constant' import Painter from '@/components/painter' const SystemInfo = Taro.getSystemInfoSync() let screenK = 5 /** * 是否支持负数 * @param {Boolean} minus 是否支持负数 */ const toPx = (num: string, minus = false) => { let reg if (minus) { reg = /^-?[0-9]+([.]{1}[0-9]+){0,1}(rpx|px)$/g } else { reg = /^[0-9]+([.]{1}[0-9]+){0,1}(rpx|px)$/g } const results = reg.exec(num) console.log('results', results) if (!num || !results) { console.log(`The size: ${num} is illegal`) return 0 } const unit = results[2] const value = parseFloat(num) let res = 0 if (unit === 'rpx') { res = Math.round(value * screenK) } else if (unit === 'px') { res = value } return res } // 需要传进来的表头数据示例 const inviteColumns = [ { key: 'invitee', title: '被邀请人', dataIndex: 'invitee', width: '50%', }, { key: 'InviteResults', title: '邀请进度', dataIndex: 'InviteResults', width: '50%', }, ] // 邀请码 const InviteCode = () => { screenK = SystemInfo.screenWidth / 750 const { fetchData } = GetInvitationInfo() const { fetchData: genCode } = GenBarCodeOrQrCode() const [inviteInfo, setInviteInfo] = useState({}) const [currentTable, setCurrentTable] = useState({ columns: inviteColumns, dataSource: { list: [], total: 0 }, }) const [loading, setLoading] = useState(false) // 获取邀请码 const getInviteCode = async() => { const res = await fetchData() if (res.success) { console.log('getInviteCode', res) setCurrentTable((prev: any) => ({ ...prev, dataSource: { list: res.data.invitation_record.map((item, index: number) => ({ key: index, index: index + 1, invitee: item.name || '--', InviteResults: '已邀请', })), total: res.data.invitation_record.length, }, })) setInviteInfo(res.data) } } // 生成二维码 const genQRcode = async() => { const res = await genCode({ content: `InviteCode:${inviteInfo.invitation_code}` }) if (res.success) { return res.data.qrcode_base64 } else { setLoading(false) } } const [, setForceUpdate] = useState({}) const canvasNode = useRef(null) const ctx = useRef(null) const [showPopup, setShowPopup] = useState(false) const [targetImageUrl, setTargetImageUrl] = useState('') const getImageObject = (canvas: Taro.Canvas, src: string) => { return new Promise((resolve, reject) => { console.log('getImageObject param', canvas, src) const img = canvas.createImage() img.src = src img.onload = () => { console.log('image===>', img) resolve(img) } img.onerror = (err) => { console.log('image error===>', err) alert.error('图片加载失败') reject(err) } }) } // canvas 生成 图片 const saveCanvasToImage = (canvas) => { console.log('pixelRatio', SystemInfo.pixelRatio, canvas) Taro.canvasToTempFilePath({ canvas, fileType: 'png', success: (res) => { console.log('tempFilePath', res.tempFilePath) setTargetImageUrl(res.tempFilePath) }, fail: (error) => { console.log('error', error) }, complete: () => { setLoading(false) }, }) } const getImageInfo = (filePath) => { Taro.getImageInfo({ src: filePath, success: (infoRes) => { console.log('', infoRes) }, }) } // 初始化 canvas const initCanvas = async() => { return new Promise((resolve, reject) => { Taro.nextTick(() => { const query = Taro.createSelectorQuery() query.select('#canvas').node(({ node: canvas }: { node: Taro.Canvas }) => { console.log('canvas==>', canvas) const context = canvas.getContext('2d') console.log('ctx', context) canvasNode.current = canvas ctx.current = context console.log('canvas', canvas) setForceUpdate({}) resolve(true) }).exec() }) }) } const doublePick = (num, minus = false) => { if (minus) { return num / 2 } else { return num * 2 } } const [canvasStyle, setCanvasStyle] = useState({}) const painter = useRef(null) const startPaint = async(ctx: Taro.RenderingContext, canvas: Taro.Canvas, image: Taro.Image) => { // 开始绘制 const { width, height } = canvas console.log('startPaint param', ctx, canvas, image) const cCanvasCtx = ctx as any cCanvasCtx.clearRect(0, 0, width, height) cCanvasCtx.drawImage(image, 0, 0, width, height) cCanvasCtx.save() cCanvasCtx.font = `${doublePick(40)}px 微软雅黑` cCanvasCtx.fillStyle = '#000000' cCanvasCtx.fillText('蜘蛛管家', doublePick(40), doublePick(80)) // text up above canvas cCanvasCtx.save() cCanvasCtx.font = `${doublePick(26)}px 微软雅黑` cCanvasCtx.fillStyle = '#8f9398' cCanvasCtx.fillText('真挚邀请您建立合作关系', doublePick(40), doublePick(130)) // text up above canvas cCanvasCtx.save() cCanvasCtx.font = `${doublePick(24)}px 微软雅黑` cCanvasCtx.fillStyle = '#a6a6a6' cCanvasCtx.fillText('请前往邀请码页面,进行扫描邀请', doublePick(100), doublePick(630)) // text up above canvas cCanvasCtx.save() cCanvasCtx.font = `${doublePick(36)}px 微软雅黑` cCanvasCtx.fillStyle = '#7f7f7f' cCanvasCtx.fillText('邀 请 码', doublePick(72), doublePick(730)) // text up above canvas cCanvasCtx.save() cCanvasCtx.font = `${doublePick(24)}px 微软雅黑` cCanvasCtx.fillStyle = '#cccccc' cCanvasCtx.fillText('|', doublePick(258), doublePick(724)) // text up above canvas cCanvasCtx.save() cCanvasCtx.font = `${doublePick(36)}px 微软雅黑` cCanvasCtx.fillStyle = '#7f7f7f' cCanvasCtx.fillText(`${inviteInfo.invitation_code}`, doublePick(311), doublePick(730)) // text up above canvas cCanvasCtx.save() const codeUrl = await genQRcode() try { const code = await getImageObject(canvas, codeUrl) cCanvasCtx.drawImage(code, doublePick(110), doublePick(213), doublePick(342), doublePick(342)) } catch (err) { console.error('合成二维邀请码失败', err) setLoading(false) throw new Error('合成二维邀请码失败') } saveCanvasToImage(canvas) } // 绘制最终的海报,图片使用两倍大小,canvas大小是图片的二分之一 就能让canvas生成出来的图片清晰了 const drawPictorial = async() => { // eslint-disable-next-line no-async-promise-executor return new Promise(async(resolve, reject) => { setLoading(true) if (!ctx.current) { // 重新初始化canvas await initCanvas() } const canvas = canvasNode.current! Taro.getImageInfo({ src: getCDNSource('/user/inviteCodePopup.png'), success: (res) => { console.log('res==>', res) canvas.width = res.width canvas.height = res.height setCanvasStyle({ width: `${doublePick(canvas.width, true)}px`, height: `${doublePick(canvas.height, true)}px`, }) getImageObject(canvas, `${res.path}`).then(async(image) => { try { // 开始绘制 await startPaint(ctx.current!, canvas, image) resolve(true) } catch (err) { console.log(err) setLoading(false) reject(new Error('绘制失败')) } }).catch((error) => { setLoading(false) throw new Error(error) }) }, }) }) } // 加载更多 const handleLoadMore = () => { } const handleQRcodeShare = async() => { try { // painter.current.startPaint() const flag = await drawPictorial() if (flag) { setShowPopup(true) } } catch (err) { throw new Error('弹出二维码失败') } } // 复制二维码 const handleCopyInviteCode = () => { Taro.setClipboardData({ data: inviteInfo.invitation_code, }) } const handleChange = (value: boolean) => { setShowPopup(value) } useReady(() => { getInviteCode() setTimeout(() => { initCanvas() }, 200) }) const onImgErr = (e) => { Taro.hideLoading() console.error('onImgErr', e.error) Taro.showToast({ title: '生成分享图失败,请刷新页面重试', }) } const onImgOK = (e) => { console.log('onImgOK', e.path) setTargetImageUrl(e.path) setShowPopup(true) Taro.hideLoading() } return 蜘蛛管家 真挚邀请您建立合作关系 邀请码 {inviteInfo.invitation_code} 填写邀请码,即可在蜘蛛管家下单购物 成功邀请
温馨提示:邀请码确定绑定后,不支持解绑。
{/* */} {/* 已踩坑,这里必须设置canvas的style的width和height,单单只设置canvas实例的width和height是不行的。会模糊! */} 二维码分享 复制邀请码 {/* showMenuByLongpress 属性只对 小程序有效 */} 长按图片保存到手机
} export default InviteCode