feat(user): 使用微信原生 Picker 替换所在地选择弹层
- 删除 NutUI Address 相关导入、状态及地区数据转换逻辑 - 新增派生 regionValue 用于绑定微信原生 Picker 的 value - 将 handleRegionChange 调整为处理微信 Picker 的事件 - 将所在地选择 UI 修改为微信原生 Picker 包裹的视图结构 - 地图定位失败使用弹窗提示,引导用户手动选择或重试 - 移除手动打开地区选择器的函数及 NutUI 组件 - 保留 RegionData 用于文本智能识别解析 - 编译通过,提升在无地图或无权限环境下的地区选择稳定性
This commit is contained in:
10
.workbuddy/memory/2026-07-13.md
Normal file
10
.workbuddy/memory/2026-07-13.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# 2026-07-13 工作日志
|
||||||
|
|
||||||
|
## 小程序分享 / 朋友圈能力全量接入
|
||||||
|
- 新增 `src/hooks/useShare.ts`:统一注册 `useShareAppMessage` + `useShareTimeline`,自动追加 `inviter=${user.id}` 裂变参数;导出 `isTimelineSinglePage()`(scene===1154)。
|
||||||
|
- 新增 `src/components/SharePoster/index.tsx`:Canvas 2D 生成「封面+标题+价格+小程序码」海报,返回临时图路径作 imageUrl。
|
||||||
|
- 新增 `src/api/share.ts`:`generateShareCode(page, inviterId)`,复用 `generateMiniProgramCode`(scene=uid_${id},page 透传)。
|
||||||
|
- 扩展 `src/api/shop/shopInvite/index.ts` 的 `generateMiniProgramCode`,URL 透传 `page` 参数(后端需读取转发)。
|
||||||
|
- 接入 10 个页面:商品/积分/拼团/秒杀/活动/赛事详情(带 canvas 海报);邀请下级/分销推广/升级VIP/分享赚佣金(仅 enableShare + useShare)。
|
||||||
|
- 类型检查:本次改动零错误,仅余 1 个历史既有错误(TS2688 @tarojs/taro 类型解析,非本次引入)。
|
||||||
|
- 待办/注意:朋友圈分享必须真机测试;后端需支持按 page 生成指定落地页小程序码;单页模式降级(避免强制登录跳转)可调用 `isTimelineSinglePage()`。
|
||||||
@@ -31,3 +31,11 @@
|
|||||||
- 字段:订单号(`character_string1`)、商品名称(`thing4`)、联系人(`thing10`)、联系电话(`phone_number7`)、送货地址(`thing8`)
|
- 字段:订单号(`character_string1`)、商品名称(`thing4`)、联系人(`thing10`)、联系电话(`phone_number7`)、送货地址(`thing8`)
|
||||||
- 场景说明:下单提醒
|
- 场景说明:下单提醒
|
||||||
- 新订单检测 Hook:`src/hooks/useNewOrderDetector.ts`(30秒轮询,页面隐藏暂停)
|
- 新订单检测 Hook:`src/hooks/useNewOrderDetector.ts`(30秒轮询,页面隐藏暂停)
|
||||||
|
|
||||||
|
## 分享 / 朋友圈能力(2026-07-13 接入)
|
||||||
|
- 统一封装:`src/hooks/useShare.ts`(`useShare({title, path?, query?, imageUrl?})`,内部一次注册 `useShareAppMessage` + `useShareTimeline`,并自动在 path/query 追加 `inviter=${当前用户id}` 做裂变归因;`isTimelineSinglePage()` 判断朋友圈单页模式 scene===1154)
|
||||||
|
- 海报组件:`src/components/SharePoster/index.tsx`(Canvas 2D 绘制封面+标题+价格+小程序码,返回临时图路径作 imageUrl)
|
||||||
|
- 小程序码接口:`src/api/share.ts` `generateShareCode(page, inviterId)` 复用 `generateMiniProgramCode`(scene 用 `uid_${inviterId}`,page 透传但后端需读取转发才生效)
|
||||||
|
- 裂变约定:分享链接 query 用 `inviter`,与 `src/utils/invite.ts` 的 `parseInviteParams` 读取字段一致
|
||||||
|
- 已接入页面:商品详情、积分商品、拼团、秒杀、活动、赛事(带 canvas 海报);邀请下级、分销推广、升级VIP、分享赚佣金(仅 enableShare + useShare,无海报)
|
||||||
|
- 注意:tabBar 4 页(首页/分类/订单/我的)不支持朋友圈分享;朋友圈分享必须真机测试(开发者工具无预览)
|
||||||
|
|||||||
23
src/api/share.ts
Normal file
23
src/api/share.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { generateMiniProgramCode } from '@/api/shop/shopInvite'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成「分享海报」用的小程序码(二维码)图片地址。
|
||||||
|
*
|
||||||
|
* - scene 复用现有 uid_${inviterId} 约定,与邀请裂变逻辑一致;
|
||||||
|
* - page 指向被分享的页面(小程序码扫码后落地页)。
|
||||||
|
*
|
||||||
|
* 注意:当前后端 /wx-login/getOrderQRCodeUnlimited/{scene} 仅消费 scene,
|
||||||
|
* 若希望扫码后直达指定页面而非默认页,需后端读取并转发 page 参数。
|
||||||
|
*
|
||||||
|
* @param page 被分享页路径,如 pages/shop/product-detail
|
||||||
|
* @param inviterId 当前登录用户 id(用于裂变归因),未登录可省略
|
||||||
|
*/
|
||||||
|
export function generateShareCode(page: string, inviterId?: number | string) {
|
||||||
|
const scene = inviterId ? `uid_${inviterId}` : 'share'
|
||||||
|
return generateMiniProgramCode({
|
||||||
|
page,
|
||||||
|
scene,
|
||||||
|
width: 200,
|
||||||
|
envVersion: 'release',
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -111,7 +111,12 @@ export interface InviteRecordParam {
|
|||||||
*/
|
*/
|
||||||
export async function generateMiniProgramCode(data: MiniProgramCodeParam) {
|
export async function generateMiniProgramCode(data: MiniProgramCodeParam) {
|
||||||
try {
|
try {
|
||||||
const url = '/wx-login/getOrderQRCodeUnlimited/' + data.scene;
|
let url = '/wx-login/getOrderQRCodeUnlimited/' + data.scene;
|
||||||
|
// 透传 page,便于后端按要求生成指向指定页的小程序码
|
||||||
|
// (当前后端仅使用 scene,若需扫码直达指定页,后端需读取并转发 page 到微信 getwxacodeunlimit)
|
||||||
|
if (data.page) {
|
||||||
|
url += `?page=${encodeURIComponent(data.page)}`;
|
||||||
|
}
|
||||||
// 由于接口直接返回图片buffer,我们直接构建完整的URL
|
// 由于接口直接返回图片buffer,我们直接构建完整的URL
|
||||||
return `${BaseUrl}${url}`;
|
return `${BaseUrl}${url}`;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
204
src/components/SharePoster/index.tsx
Normal file
204
src/components/SharePoster/index.tsx
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
import React, { forwardRef, useImperativeHandle, useRef } from 'react'
|
||||||
|
import { Canvas, View } from '@tarojs/components'
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import { useUser } from '@/hooks/useUser'
|
||||||
|
import { generateShareCode } from '@/api/share'
|
||||||
|
|
||||||
|
export interface PosterOptions {
|
||||||
|
/** 封面图(网络地址或本地路径) */
|
||||||
|
cover?: string
|
||||||
|
/** 主标题 */
|
||||||
|
title: string
|
||||||
|
/** 副标题 / 描述 */
|
||||||
|
subtitle?: string
|
||||||
|
/** 价格(仅展示用) */
|
||||||
|
price?: string | number
|
||||||
|
/** 小程序码落地页,如 pages/shop/product-detail */
|
||||||
|
page?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SharePosterHandle {
|
||||||
|
/** 生成海报,返回临时图片路径,可直接作为分享 imageUrl */
|
||||||
|
generate: (opts: PosterOptions) => Promise<string>
|
||||||
|
}
|
||||||
|
|
||||||
|
// 逻辑尺寸(CSS px),实际位图按 dpr 放大
|
||||||
|
const W = 300
|
||||||
|
const H = 420
|
||||||
|
const CANVAS_ID = 'sharePosterCanvas'
|
||||||
|
|
||||||
|
const SharePoster = forwardRef<SharePosterHandle>((_, ref) => {
|
||||||
|
const { user } = useUser()
|
||||||
|
const inviterId = user?.id ?? user?.userId
|
||||||
|
|
||||||
|
const getCanvasNode = (): Promise<any> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Taro.createSelectorQuery()
|
||||||
|
.select('#' + CANVAS_ID)
|
||||||
|
.fields({ node: true, size: true })
|
||||||
|
.exec((res) => {
|
||||||
|
const node = res && res[0] && res[0].node
|
||||||
|
if (node) resolve(node)
|
||||||
|
else reject(new Error('未找到 canvas 节点'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadImage = (canvas: any, src: string): Promise<any> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!src) return reject(new Error('空图片地址'))
|
||||||
|
const img = canvas.createImage()
|
||||||
|
img.onload = () => resolve(img)
|
||||||
|
img.onerror = (e: any) => reject(e)
|
||||||
|
img.src = src
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const drawRoundRect = (
|
||||||
|
ctx: any,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
w: number,
|
||||||
|
h: number,
|
||||||
|
r: number
|
||||||
|
) => {
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(x + r, y)
|
||||||
|
ctx.arcTo(x + w, y, x + w, y + h, r)
|
||||||
|
ctx.arcTo(x + w, y + h, x, y + h, r)
|
||||||
|
ctx.arcTo(x, y + h, x, y, r)
|
||||||
|
ctx.arcTo(x, y, x + w, y, r)
|
||||||
|
ctx.closePath()
|
||||||
|
}
|
||||||
|
|
||||||
|
const drawRoundImage = (
|
||||||
|
ctx: any,
|
||||||
|
img: any,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
w: number,
|
||||||
|
h: number,
|
||||||
|
r: number
|
||||||
|
) => {
|
||||||
|
ctx.save()
|
||||||
|
drawRoundRect(ctx, x, y, w, h, r)
|
||||||
|
ctx.clip()
|
||||||
|
ctx.drawImage(img, x, y, w, h)
|
||||||
|
ctx.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 文本按宽度换行,最多 maxLines 行 */
|
||||||
|
const wrapText = (ctx: any, text: string, maxWidth: number, maxLines: number): string[] => {
|
||||||
|
const chars = (text || '').split('')
|
||||||
|
const lines: string[] = []
|
||||||
|
let line = ''
|
||||||
|
for (let i = 0; i < chars.length; i++) {
|
||||||
|
const ch = chars[i]
|
||||||
|
if (ctx.measureText(line + ch).width > maxWidth && line) {
|
||||||
|
lines.push(line)
|
||||||
|
line = ch
|
||||||
|
if (lines.length === maxLines - 1) break
|
||||||
|
} else {
|
||||||
|
line += ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lines.length < maxLines) lines.push(line)
|
||||||
|
else if (line) lines[maxLines - 1] = lines[maxLines - 1] + '…'
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
const generate = async (opts: PosterOptions): Promise<string> => {
|
||||||
|
const canvas = await getCanvasNode()
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
const dpr = Taro.getSystemInfoSync().pixelRatio || 2
|
||||||
|
canvas.width = W * dpr
|
||||||
|
canvas.height = H * dpr
|
||||||
|
ctx.scale(dpr, dpr)
|
||||||
|
|
||||||
|
// 背景
|
||||||
|
ctx.fillStyle = '#ffffff'
|
||||||
|
ctx.fillRect(0, 0, W, H)
|
||||||
|
|
||||||
|
// 封面图
|
||||||
|
const coverX = 16
|
||||||
|
const coverY = 16
|
||||||
|
const coverW = W - 32
|
||||||
|
const coverH = 200
|
||||||
|
if (opts.cover) {
|
||||||
|
try {
|
||||||
|
const coverImg = await loadImage(canvas, opts.cover)
|
||||||
|
drawRoundImage(ctx, coverImg, coverX, coverY, coverW, coverH, 12)
|
||||||
|
} catch {
|
||||||
|
ctx.fillStyle = '#f2f2f2'
|
||||||
|
ctx.fillRect(coverX, coverY, coverW, coverH)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.fillStyle = '#f2f2f2'
|
||||||
|
ctx.fillRect(coverX, coverY, coverW, coverH)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主标题
|
||||||
|
ctx.fillStyle = '#222222'
|
||||||
|
ctx.font = 'bold 16px sans-serif'
|
||||||
|
const titleLines = wrapText(ctx, opts.title || '', coverW - 8, 2)
|
||||||
|
let ty = coverY + coverH + 30
|
||||||
|
titleLines.forEach((ln) => {
|
||||||
|
ctx.fillText(ln, coverX, ty)
|
||||||
|
ty += 22
|
||||||
|
})
|
||||||
|
|
||||||
|
// 价格
|
||||||
|
let py = ty + 6
|
||||||
|
if (opts.price !== undefined && opts.price !== '' && opts.price !== null) {
|
||||||
|
ctx.fillStyle = '#ee0a24'
|
||||||
|
ctx.font = 'bold 20px sans-serif'
|
||||||
|
ctx.fillText('¥' + opts.price, coverX, py)
|
||||||
|
py += 28
|
||||||
|
}
|
||||||
|
|
||||||
|
// 副标题
|
||||||
|
if (opts.subtitle) {
|
||||||
|
ctx.fillStyle = '#999999'
|
||||||
|
ctx.font = '12px sans-serif'
|
||||||
|
const subLines = wrapText(ctx, opts.subtitle, coverW, 2)
|
||||||
|
let sy = py
|
||||||
|
subLines.forEach((ln) => {
|
||||||
|
ctx.fillText(ln, coverX, sy)
|
||||||
|
sy += 16
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小程序码
|
||||||
|
const codeSize = 86
|
||||||
|
const codeX = W - codeSize - 16
|
||||||
|
const codeY = H - codeSize - 16
|
||||||
|
try {
|
||||||
|
const codeUrl = generateShareCode(opts.page || 'pages/index/index', inviterId)
|
||||||
|
const dl = await Taro.downloadFile({ url: codeUrl })
|
||||||
|
if (dl.statusCode === 200) {
|
||||||
|
const codeImg = await loadImage(canvas, dl.tempFilePath)
|
||||||
|
drawRoundImage(ctx, codeImg, codeX, codeY, codeSize, codeSize, 8)
|
||||||
|
ctx.fillStyle = '#999999'
|
||||||
|
ctx.font = '11px sans-serif'
|
||||||
|
ctx.fillText('长按识别', codeX, codeY - 6)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 小程序码生成失败不影响主海报
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await Taro.canvasToTempFilePath({ canvas })
|
||||||
|
return res.tempFilePath
|
||||||
|
}
|
||||||
|
|
||||||
|
useImperativeHandle(ref, () => ({ generate }))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{ position: 'fixed', left: -9999, top: 0, zIndex: -1 }}>
|
||||||
|
<Canvas type='2d' id={CANVAS_ID} style={{ width: W + 'px', height: H + 'px' }} />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
SharePoster.displayName = 'SharePoster'
|
||||||
|
|
||||||
|
export default SharePoster
|
||||||
69
src/hooks/useShare.ts
Normal file
69
src/hooks/useShare.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { useRef } from 'react'
|
||||||
|
import Taro, { useShareAppMessage, useShareTimeline } from '@tarojs/taro'
|
||||||
|
import { useUser } from './useUser'
|
||||||
|
|
||||||
|
export interface UseShareOptions {
|
||||||
|
/** 分享标题 */
|
||||||
|
title: string
|
||||||
|
/** 分享给好友的完整 path(含或不含 query),如 /pages/shop/product-detail?id=123 */
|
||||||
|
path?: string
|
||||||
|
/** 朋友圈的 query(不含 page 与 ?),如 id=123,会被拼到当前页 path 之后 */
|
||||||
|
query?: string
|
||||||
|
/** 封面图(海报临时路径或网络图地址),不传则微信截取页面 */
|
||||||
|
imageUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 当前是否处于朋友圈单页模式(scene=1154) */
|
||||||
|
export function isTimelineSinglePage(): boolean {
|
||||||
|
try {
|
||||||
|
const options = Taro.getEnterOptionsSync()
|
||||||
|
return options?.scene === 1154
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPath(path: string | undefined, inviterId?: number | string): string {
|
||||||
|
if (!path) return ''
|
||||||
|
if (!inviterId) return path
|
||||||
|
const sep = path.includes('?') ? '&' : '?'
|
||||||
|
return `${path}${sep}inviter=${inviterId}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildQuery(query: string | undefined, inviterId?: number | string): string {
|
||||||
|
const parts: string[] = []
|
||||||
|
if (query) parts.push(query)
|
||||||
|
if (inviterId) parts.push(`inviter=${inviterId}`)
|
||||||
|
return parts.join('&')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一注册「分享给好友」与「分享到朋友圈」回调。
|
||||||
|
* 自动在 path/query 中追加 inviter(当前登录用户 id),用于分销裂变。
|
||||||
|
* 注意:朋友圈分享仅对非 tabBar 页生效,需在页面 config 中设置 enableShareTimeline: true。
|
||||||
|
*/
|
||||||
|
export function useShare(options: UseShareOptions) {
|
||||||
|
const { user } = useUser()
|
||||||
|
const inviterId = user?.id ?? user?.userId
|
||||||
|
// 用 ref 保证分享触发时读取到最新 options(含异步生成的海报图)
|
||||||
|
const optionsRef = useRef(options)
|
||||||
|
optionsRef.current = options
|
||||||
|
|
||||||
|
useShareAppMessage(() => {
|
||||||
|
const o = optionsRef.current
|
||||||
|
return {
|
||||||
|
title: o.title,
|
||||||
|
path: buildPath(o.path, inviterId),
|
||||||
|
imageUrl: o.imageUrl,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
useShareTimeline(() => {
|
||||||
|
const o = optionsRef.current
|
||||||
|
return {
|
||||||
|
title: o.title,
|
||||||
|
query: buildQuery(o.query, inviterId),
|
||||||
|
imageUrl: o.imageUrl,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect, useRef } from 'react'
|
||||||
import { View, Text, ScrollView, Image } from '@tarojs/components'
|
import { View, Text, ScrollView, Image } from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import { getShopActivity, signUpActivity, cancelSignUpActivity, getSignUpStatus } from '@/api/shop/shopActivity'
|
import { getShopActivity, signUpActivity, cancelSignUpActivity, getSignUpStatus } from '@/api/shop/shopActivity'
|
||||||
import type { ShopActivity, ActivityStatus } from '@/api/shop/shopActivity/model'
|
import type { ShopActivity, ActivityStatus } from '@/api/shop/shopActivity/model'
|
||||||
import { getCompressedImageUrl } from '@/utils/image'
|
import { getCompressedImageUrl } from '@/utils/image'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
|
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
|
||||||
|
|
||||||
definePageConfig({
|
definePageConfig({
|
||||||
navigationBarTitleText: '活动详情',
|
navigationBarTitleText: '活动详情',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const ActivityDetailPage: React.FC = () => {
|
const ActivityDetailPage: React.FC = () => {
|
||||||
@@ -16,6 +20,30 @@ const ActivityDetailPage: React.FC = () => {
|
|||||||
const [signedUp, setSignedUp] = useState(false)
|
const [signedUp, setSignedUp] = useState(false)
|
||||||
const [submitting, setSubmitting] = useState(false)
|
const [submitting, setSubmitting] = useState(false)
|
||||||
|
|
||||||
|
// 分享 / 朋友圈
|
||||||
|
const posterRef = useRef<SharePosterHandle>(null)
|
||||||
|
const [posterPath, setPosterPath] = useState('')
|
||||||
|
useShare({
|
||||||
|
title: activity?.name || '精彩活动推荐',
|
||||||
|
path: `/pages/activity/detail?id=${id}`,
|
||||||
|
query: `id=${id}`,
|
||||||
|
imageUrl: posterPath || activity?.image || undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 数据加载完成后异步生成分享海报(带小程序码)
|
||||||
|
useEffect(() => {
|
||||||
|
if (activity) {
|
||||||
|
posterRef.current
|
||||||
|
?.generate({
|
||||||
|
cover: activity.image,
|
||||||
|
title: activity.name || '精彩活动',
|
||||||
|
page: 'pages/activity/detail',
|
||||||
|
})
|
||||||
|
.then(setPosterPath)
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
}, [activity])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id) {
|
if (id) {
|
||||||
fetchDetail(Number(id))
|
fetchDetail(Number(id))
|
||||||
@@ -239,6 +267,8 @@ const ActivityDetailPage: React.FC = () => {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
|
||||||
|
<SharePoster ref={posterRef} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect, useRef } from 'react'
|
||||||
import { View, Text, ScrollView, Image } from '@tarojs/components'
|
import { View, Text, ScrollView, Image } from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import { getShopEvent, getRegistrationStatus, getEventStatusLabel } from '@/api/shop/shopEvent'
|
import { getShopEvent, getRegistrationStatus, getEventStatusLabel } from '@/api/shop/shopEvent'
|
||||||
import type { ShopEvent, RegistrationStatus, EventFormField } from '@/api/shop/shopEvent'
|
import type { ShopEvent, RegistrationStatus, EventFormField } from '@/api/shop/shopEvent'
|
||||||
import { getCompressedImageUrl } from '@/utils/image'
|
import { getCompressedImageUrl } from '@/utils/image'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
|
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
|
||||||
|
|
||||||
definePageConfig({ navigationBarTitleText: '赛事详情' })
|
definePageConfig({
|
||||||
|
navigationBarTitleText: '赛事详情',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
|
})
|
||||||
|
|
||||||
const EventDetailPage: React.FC = () => {
|
const EventDetailPage: React.FC = () => {
|
||||||
const { id } = Taro.getCurrentInstance().router?.params || {}
|
const { id } = Taro.getCurrentInstance().router?.params || {}
|
||||||
@@ -13,6 +19,30 @@ const EventDetailPage: React.FC = () => {
|
|||||||
const [regStatus, setRegStatus] = useState<RegistrationStatus | null>(null)
|
const [regStatus, setRegStatus] = useState<RegistrationStatus | null>(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
|
// 分享 / 朋友圈
|
||||||
|
const posterRef = useRef<SharePosterHandle>(null)
|
||||||
|
const [posterPath, setPosterPath] = useState('')
|
||||||
|
useShare({
|
||||||
|
title: event?.name || '精彩赛事推荐',
|
||||||
|
path: `/pages/event/detail?id=${id}`,
|
||||||
|
query: `id=${id}`,
|
||||||
|
imageUrl: posterPath || event?.image || undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 数据加载完成后异步生成分享海报(带小程序码)
|
||||||
|
useEffect(() => {
|
||||||
|
if (event) {
|
||||||
|
posterRef.current
|
||||||
|
?.generate({
|
||||||
|
cover: event.image,
|
||||||
|
title: event.name || '精彩赛事',
|
||||||
|
page: 'pages/event/detail',
|
||||||
|
})
|
||||||
|
.then(setPosterPath)
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
}, [event])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id) {
|
if (id) {
|
||||||
fetchDetail(Number(id))
|
fetchDetail(Number(id))
|
||||||
@@ -189,6 +219,8 @@ const EventDetailPage: React.FC = () => {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
|
||||||
|
<SharePoster ref={posterRef} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect, useRef } from 'react'
|
||||||
import { View, Text, Image, ScrollView, RichText } from '@tarojs/components'
|
import { View, Text, Image, ScrollView, RichText } from '@tarojs/components'
|
||||||
import Taro, { useRouter, useShareAppMessage } from '@tarojs/taro'
|
import Taro, { useRouter } from '@tarojs/taro'
|
||||||
import { getShopPointsProduct } from '@/api/shop/shopPointsProduct'
|
import { getShopPointsProduct } from '@/api/shop/shopPointsProduct'
|
||||||
import type { ShopPointsProduct } from '@/api/shop/shopPointsProduct/model'
|
import type { ShopPointsProduct } from '@/api/shop/shopPointsProduct/model'
|
||||||
import EmptyState from '@/components/common/EmptyState'
|
import EmptyState from '@/components/common/EmptyState'
|
||||||
import { getCompressedImageUrl } from '@/utils/image'
|
import { getCompressedImageUrl } from '@/utils/image'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
|
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
|
||||||
|
|
||||||
definePageConfig({
|
definePageConfig({
|
||||||
navigationBarTitleText: '积分商品',
|
navigationBarTitleText: '积分商品',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const PointsProductDetail: React.FC = () => {
|
const PointsProductDetail: React.FC = () => {
|
||||||
@@ -16,13 +20,14 @@ const PointsProductDetail: React.FC = () => {
|
|||||||
const [product, setProduct] = useState<ShopPointsProduct | null>(null)
|
const [product, setProduct] = useState<ShopPointsProduct | null>(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
||||||
// 微信分享
|
// 分享 / 朋友圈
|
||||||
useShareAppMessage(() => {
|
const posterRef = useRef<SharePosterHandle>(null)
|
||||||
return {
|
const [posterPath, setPosterPath] = useState('')
|
||||||
title: product?.productName || '积分商品推荐',
|
useShare({
|
||||||
path: `/pages/points/product-detail?id=${id}`,
|
title: product?.productName || '积分商品推荐',
|
||||||
imageUrl: product?.productImage || ''
|
path: `/pages/points/product-detail?id=${id}`,
|
||||||
}
|
query: `id=${id}`,
|
||||||
|
imageUrl: posterPath || product?.productImage || undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -31,6 +36,21 @@ const PointsProductDetail: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [id])
|
}, [id])
|
||||||
|
|
||||||
|
// 数据加载完成后异步生成分享海报(带小程序码)
|
||||||
|
useEffect(() => {
|
||||||
|
if (product) {
|
||||||
|
posterRef.current
|
||||||
|
?.generate({
|
||||||
|
cover: product.productImage,
|
||||||
|
title: product.productName || '积分商品',
|
||||||
|
subtitle: product.pointsPrice ? `仅需 ${product.pointsPrice} 积分` : undefined,
|
||||||
|
page: 'pages/points/product-detail',
|
||||||
|
})
|
||||||
|
.then(setPosterPath)
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
}, [product])
|
||||||
|
|
||||||
const loadProduct = async () => {
|
const loadProduct = async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
@@ -171,6 +191,9 @@ const PointsProductDetail: React.FC = () => {
|
|||||||
<Text className='text-sm'>{isSoldOut ? '已售罄' : '立即兑换'}</Text>
|
<Text className='text-sm'>{isSoldOut ? '已售罄' : '立即兑换'}</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
|
||||||
|
<SharePoster ref={posterRef} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,25 @@
|
|||||||
import { View, Text, Image } from '@tarojs/components';
|
import { View, Text, Image } from '@tarojs/components';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
|
import { useShare } from '@/hooks/useShare';
|
||||||
import NavBar from '@/components/NavBar';
|
import NavBar from '@/components/NavBar';
|
||||||
|
|
||||||
|
definePageConfig({
|
||||||
|
navigationBarTitleText: '分享赚佣金',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
|
});
|
||||||
|
|
||||||
export default function SharePage() {
|
export default function SharePage() {
|
||||||
const [shareLink, setShareLink] = useState('https://paopao.com/ref/abc123');
|
const [shareLink, setShareLink] = useState('https://paopao.com/ref/abc123');
|
||||||
const [qrCodeUrl, setQrCodeUrl] = useState('');
|
const [qrCodeUrl, setQrCodeUrl] = useState('');
|
||||||
|
|
||||||
|
// 分享 / 朋友圈
|
||||||
|
useShare({
|
||||||
|
title: '分享赚佣金,邀请好友一起来',
|
||||||
|
path: '/pages/share/index',
|
||||||
|
});
|
||||||
|
|
||||||
const handleCopyLink = () => {
|
const handleCopyLink = () => {
|
||||||
Taro.setClipboardData({ data: shareLink })
|
Taro.setClipboardData({ data: shareLink })
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState, useRef } from 'react'
|
||||||
import { View, Text, Image, ScrollView } from '@tarojs/components'
|
import { View, Text, Image, ScrollView } from '@tarojs/components'
|
||||||
import Taro, { useRouter } from '@tarojs/taro'
|
import Taro, { useRouter } from '@tarojs/taro'
|
||||||
import { getShopGroupBuy, listShopGroupBuyRecords, joinGroupBuy, createGroupBuy } from '@/api/shop/shopGroupBuy'
|
import { getShopGroupBuy, listShopGroupBuyRecords, joinGroupBuy, createGroupBuy } from '@/api/shop/shopGroupBuy'
|
||||||
@@ -8,9 +8,13 @@ import type { ShopGoods } from '@/api/shop/shopGoods/model'
|
|||||||
import type { ShopGoodsSku } from '@/api/shop/shopGoodsSku/model'
|
import type { ShopGoodsSku } from '@/api/shop/shopGoodsSku/model'
|
||||||
import SkuSelector from '@/components/business/SkuSelector'
|
import SkuSelector from '@/components/business/SkuSelector'
|
||||||
import { getCompressedImageUrl } from '@/utils/image'
|
import { getCompressedImageUrl } from '@/utils/image'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
|
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
|
||||||
|
|
||||||
definePageConfig({
|
definePageConfig({
|
||||||
navigationBarTitleText: '拼团详情',
|
navigationBarTitleText: '拼团详情',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const GroupBuyDetailPage: React.FC = () => {
|
const GroupBuyDetailPage: React.FC = () => {
|
||||||
@@ -25,6 +29,31 @@ const GroupBuyDetailPage: React.FC = () => {
|
|||||||
const [skuVisible, setSkuVisible] = useState(false)
|
const [skuVisible, setSkuVisible] = useState(false)
|
||||||
const [pendingRecordId, setPendingRecordId] = useState<number | null>(null)
|
const [pendingRecordId, setPendingRecordId] = useState<number | null>(null)
|
||||||
|
|
||||||
|
// 分享 / 朋友圈
|
||||||
|
const posterRef = useRef<SharePosterHandle>(null)
|
||||||
|
const [posterPath, setPosterPath] = useState('')
|
||||||
|
useShare({
|
||||||
|
title: groupBuy?.goodsName || groupBuy?.product?.name || '拼团商品推荐',
|
||||||
|
path: `/pages/shop/group-buy-detail?groupBuyId=${groupBuyId}`,
|
||||||
|
query: `groupBuyId=${groupBuyId}`,
|
||||||
|
imageUrl: posterPath || groupBuy?.goodsImage || groupBuy?.product?.image || undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 数据加载完成后异步生成分享海报(带小程序码)
|
||||||
|
useEffect(() => {
|
||||||
|
if (groupBuy) {
|
||||||
|
posterRef.current
|
||||||
|
?.generate({
|
||||||
|
cover: groupBuy.goodsImage || groupBuy.product?.image,
|
||||||
|
title: groupBuy.goodsName || groupBuy.product?.name || '拼团商品',
|
||||||
|
price: groupBuy.groupPrice,
|
||||||
|
page: 'pages/shop/group-buy-detail',
|
||||||
|
})
|
||||||
|
.then(setPosterPath)
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
}, [groupBuy])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (groupBuyId) {
|
if (groupBuyId) {
|
||||||
fetchData()
|
fetchData()
|
||||||
@@ -317,6 +346,8 @@ const GroupBuyDetailPage: React.FC = () => {
|
|||||||
onClose={() => setSkuVisible(false)}
|
onClose={() => setSkuVisible(false)}
|
||||||
onConfirm={handleSkuConfirm}
|
onConfirm={handleSkuConfirm}
|
||||||
/>
|
/>
|
||||||
|
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
|
||||||
|
<SharePoster ref={posterRef} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect, useRef } from 'react'
|
||||||
import { View, Text, Image, ScrollView, Swiper, SwiperItem, RichText } from '@tarojs/components'
|
import { View, Text, Image, ScrollView, Swiper, SwiperItem, RichText } from '@tarojs/components'
|
||||||
import { Tag } from '@nutui/nutui-react-taro'
|
import { Tag } from '@nutui/nutui-react-taro'
|
||||||
import Taro, { useRouter, useShareAppMessage } from '@tarojs/taro'
|
import Taro, { useRouter } from '@tarojs/taro'
|
||||||
import { getShopGoods } from '@/api/shop/shopGoods'
|
import { getShopGoods } from '@/api/shop/shopGoods'
|
||||||
import {
|
import {
|
||||||
addShopGoodsFavorite,
|
addShopGoodsFavorite,
|
||||||
@@ -14,12 +14,16 @@ import SkuSelector from '@/components/business/SkuSelector'
|
|||||||
import { useCartContext } from '@/contexts/CartContext'
|
import { useCartContext } from '@/contexts/CartContext'
|
||||||
import { useUserContext } from '@/contexts/UserContext'
|
import { useUserContext } from '@/contexts/UserContext'
|
||||||
import { useScrollHeight } from '@/hooks/useScrollHeight'
|
import { useScrollHeight } from '@/hooks/useScrollHeight'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
|
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
|
||||||
import { isGuest } from '@/utils/auth'
|
import { isGuest } from '@/utils/auth'
|
||||||
import { requireLogin } from '@/utils/login-guard'
|
import { requireLogin } from '@/utils/login-guard'
|
||||||
import { isVipMember } from '@/utils/vip'
|
import { isVipMember } from '@/utils/vip'
|
||||||
|
|
||||||
definePageConfig({
|
definePageConfig({
|
||||||
navigationBarTitleText: '商品详情',
|
navigationBarTitleText: '商品详情',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const ProductDetailPage: React.FC = () => {
|
const ProductDetailPage: React.FC = () => {
|
||||||
@@ -35,13 +39,14 @@ const ProductDetailPage: React.FC = () => {
|
|||||||
// 底部操作栏高度约 90px(含按钮 + 安全区),动态计算 ScrollView 可用高度
|
// 底部操作栏高度约 90px(含按钮 + 安全区),动态计算 ScrollView 可用高度
|
||||||
const scrollHeight = useScrollHeight(44)
|
const scrollHeight = useScrollHeight(44)
|
||||||
|
|
||||||
// 微信分享配置
|
// 分享 / 朋友圈
|
||||||
useShareAppMessage(() => {
|
const posterRef = useRef<SharePosterHandle>(null)
|
||||||
return {
|
const [posterPath, setPosterPath] = useState('')
|
||||||
title: product?.name || product?.goodsName || '优质商品推荐',
|
useShare({
|
||||||
path: `/pages/shop/product-detail?id=${id}`,
|
title: product?.name || product?.goodsName || '优质商品推荐',
|
||||||
imageUrl: product?.image || ''
|
path: `/pages/shop/product-detail?id=${id}`,
|
||||||
}
|
query: `id=${id}`,
|
||||||
|
imageUrl: posterPath || product?.image || undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -53,10 +58,20 @@ const ProductDetailPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [id, isLoggedIn])
|
}, [id, isLoggedIn])
|
||||||
|
|
||||||
// 监听 product 变化后再添加到历史记录
|
// 监听 product 变化后再添加到历史记录,并异步生成分享海报
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (product) {
|
if (product) {
|
||||||
addToHistory()
|
addToHistory()
|
||||||
|
posterRef.current
|
||||||
|
?.generate({
|
||||||
|
cover: product.image,
|
||||||
|
title: product.name || product.goodsName || '优质商品推荐',
|
||||||
|
price:
|
||||||
|
product.dealerPrice && isVipMember() ? product.dealerPrice : product.price,
|
||||||
|
page: 'pages/shop/product-detail',
|
||||||
|
})
|
||||||
|
.then(setPosterPath)
|
||||||
|
.catch(() => {})
|
||||||
}
|
}
|
||||||
}, [product])
|
}, [product])
|
||||||
|
|
||||||
@@ -444,6 +459,9 @@ const ProductDetailPage: React.FC = () => {
|
|||||||
onClose={() => setSkuVisible(false)}
|
onClose={() => setSkuVisible(false)}
|
||||||
onConfirm={handleSkuConfirm}
|
onConfirm={handleSkuConfirm}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
|
||||||
|
<SharePoster ref={posterRef} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState, useRef } from 'react'
|
||||||
import { View, Text, Image, ScrollView } from '@tarojs/components'
|
import { View, Text, Image, ScrollView } from '@tarojs/components'
|
||||||
import Taro, { useRouter } from '@tarojs/taro'
|
import Taro, { useRouter } from '@tarojs/taro'
|
||||||
import { getShopSeckill, createSeckillOrder } from '@/api/shop/shopSeckill'
|
import { getShopSeckill, createSeckillOrder } from '@/api/shop/shopSeckill'
|
||||||
@@ -7,9 +7,13 @@ import type { ShopSeckill } from '@/api/shop/shopSeckill/model'
|
|||||||
import type { ShopGoods } from '@/api/shop/shopGoods/model'
|
import type { ShopGoods } from '@/api/shop/shopGoods/model'
|
||||||
import type { ShopGoodsSku } from '@/api/shop/shopGoodsSku/model'
|
import type { ShopGoodsSku } from '@/api/shop/shopGoodsSku/model'
|
||||||
import SkuSelector from '@/components/business/SkuSelector'
|
import SkuSelector from '@/components/business/SkuSelector'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
|
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
|
||||||
|
|
||||||
definePageConfig({
|
definePageConfig({
|
||||||
navigationBarTitleText: '秒杀详情',
|
navigationBarTitleText: '秒杀详情',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const SeckillDetailPage: React.FC = () => {
|
const SeckillDetailPage: React.FC = () => {
|
||||||
@@ -24,6 +28,31 @@ const SeckillDetailPage: React.FC = () => {
|
|||||||
const [countdown, setCountdown] = useState('')
|
const [countdown, setCountdown] = useState('')
|
||||||
const [skuVisible, setSkuVisible] = useState(false)
|
const [skuVisible, setSkuVisible] = useState(false)
|
||||||
|
|
||||||
|
// 分享 / 朋友圈
|
||||||
|
const posterRef = useRef<SharePosterHandle>(null)
|
||||||
|
const [posterPath, setPosterPath] = useState('')
|
||||||
|
useShare({
|
||||||
|
title: seckill?.goodsName || seckill?.product?.name || '秒杀商品推荐',
|
||||||
|
path: `/pages/shop/seckill-detail?seckillId=${seckillId}`,
|
||||||
|
query: `seckillId=${seckillId}`,
|
||||||
|
imageUrl: posterPath || seckill?.goodsImage || seckill?.product?.image || undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 数据加载完成后异步生成分享海报(带小程序码)
|
||||||
|
useEffect(() => {
|
||||||
|
if (seckill) {
|
||||||
|
posterRef.current
|
||||||
|
?.generate({
|
||||||
|
cover: seckill.goodsImage || seckill.product?.image,
|
||||||
|
title: seckill.goodsName || seckill.product?.name || '秒杀商品',
|
||||||
|
price: seckill.seckillPrice,
|
||||||
|
page: 'pages/shop/seckill-detail',
|
||||||
|
})
|
||||||
|
.then(setPosterPath)
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
}, [seckill])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (seckillId) {
|
if (seckillId) {
|
||||||
fetchData()
|
fetchData()
|
||||||
@@ -272,6 +301,8 @@ const SeckillDetailPage: React.FC = () => {
|
|||||||
onClose={() => setSkuVisible(false)}
|
onClose={() => setSkuVisible(false)}
|
||||||
onConfirm={handleSkuConfirm}
|
onConfirm={handleSkuConfirm}
|
||||||
/>
|
/>
|
||||||
|
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
|
||||||
|
<SharePoster ref={posterRef} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,24 @@ import { View, Text, ScrollView, Input, Button, Image } from '@tarojs/components
|
|||||||
import Taro, { useRouter } from '@tarojs/taro'
|
import Taro, { useRouter } from '@tarojs/taro'
|
||||||
import { useUser } from '@/hooks/useUser'
|
import { useUser } from '@/hooks/useUser'
|
||||||
import { useScrollHeight } from '@/hooks/useScrollHeight'
|
import { useScrollHeight } from '@/hooks/useScrollHeight'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
import { getMyRegisterList, addSubordinate, updateSubordinate, MemberRegister } from '@/api/shop/shopMemberRegister'
|
import { getMyRegisterList, addSubordinate, updateSubordinate, MemberRegister } from '@/api/shop/shopMemberRegister'
|
||||||
import EmptyState from '@/components/common/EmptyState'
|
import EmptyState from '@/components/common/EmptyState'
|
||||||
|
|
||||||
definePageConfig({
|
definePageConfig({
|
||||||
navigationBarTitleText: '录入下级',
|
navigationBarTitleText: '录入下级',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const InviteSubordinatePage: React.FC = () => {
|
const InviteSubordinatePage: React.FC = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { user, isLoggedIn } = useUser()
|
const { user, isLoggedIn } = useUser()
|
||||||
|
// 分享 / 朋友圈:带当前用户 id 作为邀请归因
|
||||||
|
useShare({
|
||||||
|
title: '邀请下级会员,一起拓客赚钱',
|
||||||
|
path: '/pages/user/invite-subordinate',
|
||||||
|
})
|
||||||
const scrollHeight = useScrollHeight()
|
const scrollHeight = useScrollHeight()
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [submitting, setSubmitting] = useState(false)
|
const [submitting, setSubmitting] = useState(false)
|
||||||
|
|||||||
@@ -2,14 +2,22 @@ import React, { useState, useEffect } from 'react'
|
|||||||
import { View, Text, ScrollView, Button, Image } from '@tarojs/components'
|
import { View, Text, ScrollView, Button, Image } from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import { useUser } from '@/hooks/useUser'
|
import { useUser } from '@/hooks/useUser'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
import { useScrollHeight } from '@/hooks/useScrollHeight'
|
import { useScrollHeight } from '@/hooks/useScrollHeight'
|
||||||
|
|
||||||
definePageConfig({
|
definePageConfig({
|
||||||
navigationBarTitleText: '分销推广',
|
navigationBarTitleText: '分销推广',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const PromotionPage: React.FC = () => {
|
const PromotionPage: React.FC = () => {
|
||||||
const { user, isLoggedIn } = useUser()
|
const { user, isLoggedIn } = useUser()
|
||||||
|
// 分享 / 朋友圈:分销推广页,带当前用户 id 作为邀请归因
|
||||||
|
useShare({
|
||||||
|
title: '邀请好友,一起赚佣金',
|
||||||
|
path: '/pages/user/promotion',
|
||||||
|
})
|
||||||
const [inviteCode, setInviteCode] = useState('')
|
const [inviteCode, setInviteCode] = useState('')
|
||||||
const [inviteLink, setInviteLink] = useState('')
|
const [inviteLink, setInviteLink] = useState('')
|
||||||
const [qrCodeUrl, setQrCodeUrl] = useState('')
|
const [qrCodeUrl, setQrCodeUrl] = useState('')
|
||||||
|
|||||||
@@ -2,15 +2,23 @@ import React, { useState, useEffect } from 'react'
|
|||||||
import { View, Text, Input } from '@tarojs/components'
|
import { View, Text, Input } from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import { useUser } from '@/hooks/useUser'
|
import { useUser } from '@/hooks/useUser'
|
||||||
|
import { useShare } from '@/hooks/useShare'
|
||||||
import { addShopDealerApply, listShopDealerApply } from '@/api/shop/shopDealerApply'
|
import { addShopDealerApply, listShopDealerApply } from '@/api/shop/shopDealerApply'
|
||||||
import type { ShopDealerApply } from '@/api/shop/shopDealerApply/model'
|
import type { ShopDealerApply } from '@/api/shop/shopDealerApply/model'
|
||||||
|
|
||||||
definePageConfig({
|
definePageConfig({
|
||||||
navigationBarTitleText: '升级VIP会员',
|
navigationBarTitleText: '升级VIP会员',
|
||||||
|
enableShareAppMessage: true,
|
||||||
|
enableShareTimeline: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const VipUpgradePage: React.FC = () => {
|
const VipUpgradePage: React.FC = () => {
|
||||||
const { user, isLoggedIn } = useUser()
|
const { user, isLoggedIn } = useUser()
|
||||||
|
// 分享 / 朋友圈
|
||||||
|
useShare({
|
||||||
|
title: '升级VIP会员,享专属优惠价',
|
||||||
|
path: '/pages/user/vip-upgrade',
|
||||||
|
})
|
||||||
const [realName, setRealName] = useState('')
|
const [realName, setRealName] = useState('')
|
||||||
const [address, setAddress] = useState('')
|
const [address, setAddress] = useState('')
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
|||||||
Reference in New Issue
Block a user