2022-12-14 11:06:28 +08:00

337 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Canvas, Image, Text, View } from '@tarojs/components'
import Taro, { useReady } from '@tarojs/taro'
import { useRef, useState } from 'react'
import styles from './index.module.scss'
import useLogin from '@/use/useLogin'
import { alert, goLink } from '@/common/common'
import { GenBarCodeOrQrCode, GetInvitationInfo, GetInvitationInfoApi, GetInviteCodeList, GetInviteeRecord } from '@/api/user'
import { getFilterData } from '@/common/util'
import LayoutBlock from '@/components/layoutBlock'
import { getCDNSource } from '@/common/constant'
import NormalButton from '@/components/normalButton'
import Dialog from '@/components/Dialog'
import IconText from '@/components/iconText'
import BindSalesManDialog from '@/components/bindSalesManDialog'
// 获取业务员信息
interface Param { inviter_id: number; inviter_name: string; phone: string }
const BindSalesman = () => {
useLogin()
const [inviteInfo, setInviteInfo] = useState<any>({})
const [salesMan, setSalesMan] = useState<Param | null>(null)
// const { fetchData: GetInvitationInfoFetchData } = GetInvitationInfoApi()
// const getInvitationInfo = async() => {
// const res = await GetInvitationInfoFetchData(getFilterData({ ...inviteInfo }))
// res.success ? setSalesMan(res.data) : setSalesMan(null)
// }
// 获取被邀请记录
const { fetchData: getInviteeRecordAPI } = GetInviteeRecord()
const getInviteeRecord = async() => {
const res = await getInviteeRecordAPI()
if (res.success) {
setSalesMan(res.data)
}
}
const { fetchData } = GetInvitationInfo()
// 获取邀请码
const getInviteCode = async() => {
const res = await fetchData()
if (res.success) {
setInviteInfo(res.data)
// getInvitationInfo()
}
}
const [invite, setInvite] = useState<number>(0)
const { fetchData: getInvitationListAPI } = GetInviteCodeList()
const getInvitationList = async() => {
const res = await getInvitationListAPI()
if (res.success) {
console.log('getInviteCode', res)
setInvite(res.data.total)
}
}
const canvasNode = useRef<Taro.Canvas | null>(null)
const ctx = useRef<Taro.RenderingContext | null>(null)
const [showPopup, setShowPopup] = useState(false)
const [loading, setLoading] = useState(false)
const { fetchData: genCode } = GenBarCodeOrQrCode()
// 生成二维码
const genQRcode = async() => {
const res = await genCode({ content: `InviteCode:${inviteInfo.invitation_code}` })
if (res.success) {
return res.data.qrcode_base64
}
else {
setLoading(false)
}
}
const inviteDialog = useRef<any>(null)
const getImageObject = (canvas: Taro.Canvas, src: string) => {
return new Promise<Taro.Image>((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)
}
})
}
const doublePick = (num, minus = false) => {
if (minus) {
return num / 2
}
else {
return num * 2
}
}
const [targetImageUrl, setTargetImageUrl] = useState('')
// canvas 生成 图片
const saveCanvasToImage = (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 [, setForceUpdate] = useState({})
// 初始化 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 [canvasStyle, setCanvasStyle] = useState<React.CSSProperties>({})
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 handleCopyInviteCode = () => {
Taro.setClipboardData({
data: inviteInfo.invitation_code,
})
}
const handleChange = (value: boolean) => {
setShowPopup(value)
}
useReady(() => {
getInviteCode()
getInvitationList()
getInviteeRecord()
setTimeout(() => {
initCanvas()
}, 200)
})
const handleQRcodeShare = async() => {
try {
const flag = await drawPictorial()
if (flag) {
setShowPopup(true)
}
}
catch (err) {
throw new Error('弹出二维码失败')
}
}
// 邀请记录
const handleInviteCord = () => {
goLink('/pages/inviteCode/inviteCord/index')
}
const handleBindSalesMan = () => {
inviteDialog.current.handleChange(true)
}
const handleBindSuccess = () => {
getInviteeRecord()
}
return (
<View className={styles.main}>
<View className={styles.content}>
<View className={styles.background}>
<View className={styles.left}>
<View className={styles.title}></View>
<View className={styles.description}></View>
</View>
<View className={styles.right}>
<View className={styles.iconContainer}>
<Image className={styles.icon} src={getCDNSource('/user/inviteCode.png')} mode="widthFix" />
</View>
</View>
</View>
<View className={styles.inviteCodeContent}>
<LayoutBlock circle>
<View className={styles.codeBar}>
<View className={styles.inviteCodeBar}>
<View className={styles.invite}>{inviteInfo.invitation_code ? inviteInfo.invitation_code : '暂无邀请码'}</View>
</View>
<View className={styles.codeTitle}></View>
</View>
</LayoutBlock>
<LayoutBlock circle>
<View className={styles.inviteCord}>
<View className={styles.inviteCordTitle}>
<Text className={styles.titleText}></Text>
{invite === 0 && <Text className={styles.noop}></Text>}
</View>
{invite !== 0 && <Text>{invite}</Text>}
<View className={styles.inviteCordMore} onClick={handleInviteCord}>
<IconText svg text="查看" direction="right" iconName="icon-rukou" textCustomStyle={{ color: '#337FFF' }} color="#337FFF"></IconText>
</View>
</View>
</LayoutBlock>
<LayoutBlock circle>
<View className={styles.inviteCord}>
<View className={styles.inviteCordTitle}>
<Text className={styles.titleText}></Text>
{!salesMan?.inviter_id && <Text className={styles.noop}></Text>}
</View>
{!!salesMan?.inviter_id && <View className={styles.inviteCordMore}>
{salesMan.inviter_name}{salesMan.phone}
</View>}
{!salesMan?.inviter_id
&& <View onClick={handleBindSalesMan}>
<IconText svg text="立即绑定" direction="right" iconName="icon-rukou" textCustomStyle={{ color: '#337FFF' }} color="#337FFF"></IconText>
</View>
}
</View>
</LayoutBlock>
<View className={styles.tips} style={{ justifyContent: 'flex-start' }}></View>
</View>
</View>
{/* 已踩坑这里必须设置canvas的style的width和height单单只设置canvas实例的width和height是不行的。会模糊 */}
<Canvas style={{ position: 'absolute', left: '-9999rpx', ...canvasStyle }} id="canvas" type="2d" />
<View className={styles.bottomBar}>
<NormalButton loading={loading} plain type="primary" customTextClassName={styles.bottomBar__text} customStyles={{ width: '45%' }} round onClick={handleQRcodeShare}>
</NormalButton>
<NormalButton type="primary" round customTextClassName={styles.bottomBar__text} customStyles={{ width: '45%' }} onClick={handleCopyInviteCode}>
</NormalButton>
</View>
<Dialog show={showPopup} onChange={handleChange}>
<View className={styles.codePreview}>
<View className={styles.imageContainer}>
{/* showMenuByLongpress 属性只对 小程序有效 */}
<Image className={styles.image} src={targetImageUrl} mode="widthFix" id="originImage" showMenuByLongpress />
</View>
<Text className={styles.previewTips}></Text>
</View>
</Dialog>
<BindSalesManDialog ref={inviteDialog} onSuccess={handleBindSuccess} />
</View>
)
}
export default BindSalesman