import React, {useState, useEffect} from 'react' import {View, Text, Image} from '@tarojs/components' import {Button, Loading} from '@nutui/nutui-react-taro' import {Download, QrCode} from '@nutui/icons-react-taro' import Taro from '@tarojs/taro' import {useDealerUser} from '@/hooks/useDealerUser' import {generateInviteCode} from '@/api/invite' // import type {InviteStats} from '@/api/invite' import {businessGradients} from '@/styles/gradients' const DealerQrcode: React.FC = () => { const [miniProgramCodeUrl, setMiniProgramCodeUrl] = useState('') const [loading, setLoading] = useState(false) const [saving, setSaving] = useState(false) // const [inviteStats, setInviteStats] = useState(null) // const [statsLoading, setStatsLoading] = useState(false) const {dealerUser} = useDealerUser() // 生成小程序码 const generateMiniProgramCode = async () => { if (!dealerUser?.userId) { return } try { setLoading(true) // 生成邀请小程序码 const codeUrl = await generateInviteCode(dealerUser.userId) if (codeUrl) { setMiniProgramCodeUrl(codeUrl) } else { throw new Error('返回的小程序码URL为空') } } catch (error: any) { Taro.showToast({ title: error.message || '生成小程序码失败', icon: 'error' }) // 清空之前的二维码 setMiniProgramCodeUrl('') } finally { setLoading(false) } } // 获取邀请统计数据 // const fetchInviteStats = async () => { // if (!dealerUser?.userId) return // // try { // setStatsLoading(true) // const stats = await getInviteStats(dealerUser.userId) // stats && setInviteStats(stats) // } catch (error) { // // 静默处理错误,不影响用户体验 // } finally { // setStatsLoading(false) // } // } // 初始化生成小程序码和获取统计数据 useEffect(() => { if (dealerUser?.userId) { generateMiniProgramCode() // fetchInviteStats() } }, [dealerUser?.userId]) const isAlbumAuthError = (errMsg?: string) => { if (!errMsg) return false // WeChat uses variants like: "saveImageToPhotosAlbum:fail auth deny", // "saveImageToPhotosAlbum:fail auth denied", "authorize:fail auth deny" return ( errMsg.includes('auth deny') || errMsg.includes('auth denied') || errMsg.includes('authorize') || errMsg.includes('scope.writePhotosAlbum') ) } const ensureWriteAlbumPermission = async (): Promise => { try { const setting = await Taro.getSetting() if (setting?.authSetting?.['scope.writePhotosAlbum']) return true await Taro.authorize({scope: 'scope.writePhotosAlbum'}) return true } catch (error: any) { const modal = await Taro.showModal({ title: '提示', content: '需要您授权保存图片到相册,请在设置中开启相册权限', confirmText: '去设置' }) if (modal.confirm) { await Taro.openSetting() } return false } } const downloadImageToLocalPath = async (url: string): Promise => { // saveImageToPhotosAlbum must receive a local temp path (e.g. `http://tmp/...` or `wxfile://...`). // Some environments may return a non-existing temp path from getImageInfo, so we verify. if (url.startsWith('http://tmp/') || url.startsWith('wxfile://')) { return url } const token = Taro.getStorageSync('access_token') const tenantId = Taro.getStorageSync('TenantId') const header: Record = {} if (token) header.Authorization = token if (tenantId) header.TenantId = tenantId // 先下载到本地临时文件再保存到相册 const res = await Taro.downloadFile({url, header}) if (res.statusCode !== 200 || !res.tempFilePath) { throw new Error(`图片下载失败(${res.statusCode || 'unknown'})`) } // Double-check file exists to avoid: saveImageToPhotosAlbum:fail no such file or directory try { await Taro.getFileInfo({filePath: res.tempFilePath}) } catch (_) { throw new Error('图片临时文件不存在,请重试') } return res.tempFilePath } // 保存小程序码到相册 const saveMiniProgramCode = async () => { if (!miniProgramCodeUrl) { Taro.showToast({ title: '小程序码未生成', icon: 'error' }) return } try { if (saving) return setSaving(true) Taro.showLoading({title: '保存中...'}) const hasPermission = await ensureWriteAlbumPermission() if (!hasPermission) return let filePath = await downloadImageToLocalPath(miniProgramCodeUrl) try { await Taro.saveImageToPhotosAlbum({filePath}) } catch (e: any) { const msg = e?.errMsg || e?.message || '' // Fallback: some devices/clients may fail to save directly from a temp path. if ( msg.includes('no such file or directory') && (filePath.startsWith('http://tmp/') || filePath.startsWith('wxfile://')) ) { const saved = (await Taro.saveFile({tempFilePath: filePath})) as unknown as { savedFilePath?: string } if (saved?.savedFilePath) { filePath = saved.savedFilePath } await Taro.saveImageToPhotosAlbum({filePath}) } else { throw e } } Taro.showToast({ title: '保存成功', icon: 'success' }) } catch (error: any) { const errMsg = error?.errMsg || error?.message if (errMsg?.includes('cancel')) { Taro.showToast({title: '已取消', icon: 'none'}) return } if (isAlbumAuthError(errMsg)) { const modal = await Taro.showModal({ title: '提示', content: '需要您授权保存图片到相册', confirmText: '去设置' }) if (modal.confirm) { await Taro.openSetting() } } else { // Prefer a modal so we can show the real reason (e.g. domain whitelist / network error). await Taro.showModal({ title: '保存失败', content: errMsg || '保存失败,请稍后重试', showCancel: false }) } } finally { Taro.hideLoading() setSaving(false) } } // 复制邀请信息 // const copyInviteInfo = () => { // if (!dealerUser?.userId) { // Taro.showToast({ // title: '用户信息未加载', // icon: 'error' // }) // return // } // // const inviteText = `🎉 邀请您加入我的团队! // // 扫描小程序码或搜索"网宿软件"小程序,即可享受优质商品和服务! // // 💰 成为我的团队成员,一起赚取丰厚佣金 // 🎁 新用户专享优惠等你来拿 // // 邀请码:${dealerUser.userId} // 快来加入我们吧!` // // Taro.setClipboardData({ // data: inviteText, // success: () => { // Taro.showToast({ // title: '邀请信息已复制', // icon: 'success' // }) // } // }) // } // 分享小程序码 // const shareMiniProgramCode = () => { // if (!dealerUser?.userId) { // Taro.showToast({ // title: '用户信息未加载', // icon: 'error' // }) // return // } // // // 小程序分享 // Taro.showShareMenu({ // withShareTicket: true, // showShareItems: ['shareAppMessage'] // }) // } if (!dealerUser) { return ( 加载中... ) } return ( {/* 头部卡片 */} {/* 装饰背景 */} 我的邀请小程序码 分享小程序码邀请好友,获得丰厚佣金奖励 {/* 小程序码展示区 */} {loading ? ( 生成中... ) : miniProgramCodeUrl ? ( { Taro.showModal({ title: '二维码加载失败', content: '请检查网络连接或联系管理员', showCancel: true, confirmText: '重新生成', success: (res) => { if (res.confirm) { generateMiniProgramCode(); } } }); }} /> ) : ( 小程序码生成失败 )} 扫码加入我的团队 好友扫描小程序码即可直接进入小程序并建立邀请关系 {/* 操作按钮 */} {/**/} {/* }*/} {/* onClick={copyInviteInfo}*/} {/* disabled={!dealerUser?.userId || loading}*/} {/* >*/} {/* 复制邀请信息*/} {/* */} {/**/} {/**/} {/* }*/} {/* onClick={shareMiniProgramCode}*/} {/* disabled={!dealerUser?.userId || loading}*/} {/* >*/} {/* 分享给好友*/} {/* */} {/**/} {/* 推广说明 */} 推广说明 好友通过您的二维码或链接注册成为您的团队成员 好友购买商品时,您可获得相应层级的分销佣金 支持三级分销,团队越大收益越多 {/* 邀请统计数据 */} {/**/} {/* 我的邀请数据*/} {/* {statsLoading ? (*/} {/* */} {/* */} {/* 加载中...*/} {/* */} {/* ) : inviteStats ? (*/} {/* */} {/* */} {/* */} {/* */} {/* {inviteStats.totalInvites || 0}*/} {/* */} {/* 总邀请数*/} {/* */} {/* */} {/* */} {/* {inviteStats.successfulRegistrations || 0}*/} {/* */} {/* 成功注册*/} {/* */} {/* */} {/* */} {/* */} {/* */} {/* {inviteStats.conversionRate ? `${(inviteStats.conversionRate * 100).toFixed(1)}%` : '0%'}*/} {/* */} {/* 转化率*/} {/* */} {/* */} {/* */} {/* {inviteStats.todayInvites || 0}*/} {/* */} {/* 今日邀请*/} {/* */} {/* */} {/* /!* 邀请来源统计 *!/*/} {/* {inviteStats.sourceStats && inviteStats.sourceStats.length > 0 && (*/} {/* */} {/* 邀请来源分布*/} {/* */} {/* {inviteStats.sourceStats.map((source, index) => (*/} {/* */} {/* */} {/* */} {/* {source.source}*/} {/* */} {/* */} {/* {source.count}*/} {/* */} {/* {source.conversionRate ? `${(source.conversionRate * 100).toFixed(1)}%` : '0%'}*/} {/* */} {/* */} {/* */} {/* ))}*/} {/* */} {/* */} {/* )}*/} {/* */} {/* ) : (*/} {/* */} {/* 暂无邀请数据*/} {/* */} {/* 刷新数据*/} {/* */} {/* */} {/* )}*/} {/**/} ) } export default DealerQrcode