feat(user): 使用微信原生 Picker 替换所在地选择弹层

- 删除 NutUI Address 相关导入、状态及地区数据转换逻辑
- 新增派生 regionValue 用于绑定微信原生 Picker 的 value
- 将 handleRegionChange 调整为处理微信 Picker 的事件
- 将所在地选择 UI 修改为微信原生 Picker 包裹的视图结构
- 地图定位失败使用弹窗提示,引导用户手动选择或重试
- 移除手动打开地区选择器的函数及 NutUI 组件
- 保留 RegionData 用于文本智能识别解析
- 编译通过,提升在无地图或无权限环境下的地区选择稳定性
This commit is contained in:
2026-07-13 08:16:17 +08:00
parent 70ad1d030f
commit d6d6b1f5a7
16 changed files with 546 additions and 25 deletions

View File

@@ -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 Taro from '@tarojs/taro'
import { getShopActivity, signUpActivity, cancelSignUpActivity, getSignUpStatus } from '@/api/shop/shopActivity'
import type { ShopActivity, ActivityStatus } from '@/api/shop/shopActivity/model'
import { getCompressedImageUrl } from '@/utils/image'
import { useShare } from '@/hooks/useShare'
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
definePageConfig({
navigationBarTitleText: '活动详情',
enableShareAppMessage: true,
enableShareTimeline: true,
})
const ActivityDetailPage: React.FC = () => {
@@ -16,6 +20,30 @@ const ActivityDetailPage: React.FC = () => {
const [signedUp, setSignedUp] = 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(() => {
if (id) {
fetchDetail(Number(id))
@@ -239,6 +267,8 @@ const ActivityDetailPage: React.FC = () => {
</View>
)}
</View>
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
<SharePoster ref={posterRef} />
</View>
)
}

View File

@@ -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 Taro from '@tarojs/taro'
import { getShopEvent, getRegistrationStatus, getEventStatusLabel } from '@/api/shop/shopEvent'
import type { ShopEvent, RegistrationStatus, EventFormField } from '@/api/shop/shopEvent'
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 { id } = Taro.getCurrentInstance().router?.params || {}
@@ -13,6 +19,30 @@ const EventDetailPage: React.FC = () => {
const [regStatus, setRegStatus] = useState<RegistrationStatus | null>(null)
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(() => {
if (id) {
fetchDetail(Number(id))
@@ -189,6 +219,8 @@ const EventDetailPage: React.FC = () => {
</View>
)}
</View>
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
<SharePoster ref={posterRef} />
</View>
)
}

View File

@@ -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 Taro, { useRouter, useShareAppMessage } from '@tarojs/taro'
import Taro, { useRouter } from '@tarojs/taro'
import { getShopPointsProduct } from '@/api/shop/shopPointsProduct'
import type { ShopPointsProduct } from '@/api/shop/shopPointsProduct/model'
import EmptyState from '@/components/common/EmptyState'
import { getCompressedImageUrl } from '@/utils/image'
import { useShare } from '@/hooks/useShare'
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
definePageConfig({
navigationBarTitleText: '积分商品',
enableShareAppMessage: true,
enableShareTimeline: true,
})
const PointsProductDetail: React.FC = () => {
@@ -16,13 +20,14 @@ const PointsProductDetail: React.FC = () => {
const [product, setProduct] = useState<ShopPointsProduct | null>(null)
const [loading, setLoading] = useState(true)
// 微信分享
useShareAppMessage(() => {
return {
title: product?.productName || '积分商品推荐',
path: `/pages/points/product-detail?id=${id}`,
imageUrl: product?.productImage || ''
}
// 分享 / 朋友圈
const posterRef = useRef<SharePosterHandle>(null)
const [posterPath, setPosterPath] = useState('')
useShare({
title: product?.productName || '积分商品推荐',
path: `/pages/points/product-detail?id=${id}`,
query: `id=${id}`,
imageUrl: posterPath || product?.productImage || undefined,
})
useEffect(() => {
@@ -31,6 +36,21 @@ const PointsProductDetail: React.FC = () => {
}
}, [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 () => {
setLoading(true)
try {
@@ -171,6 +191,9 @@ const PointsProductDetail: React.FC = () => {
<Text className='text-sm'>{isSoldOut ? '已售罄' : '立即兑换'}</Text>
</View>
</View>
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
<SharePoster ref={posterRef} />
</View>
)
}

View File

@@ -1,12 +1,25 @@
import { View, Text, Image } from '@tarojs/components';
import { useState } from 'react';
import Taro from '@tarojs/taro';
import { useShare } from '@/hooks/useShare';
import NavBar from '@/components/NavBar';
definePageConfig({
navigationBarTitleText: '分享赚佣金',
enableShareAppMessage: true,
enableShareTimeline: true,
});
export default function SharePage() {
const [shareLink, setShareLink] = useState('https://paopao.com/ref/abc123');
const [qrCodeUrl, setQrCodeUrl] = useState('');
// 分享 / 朋友圈
useShare({
title: '分享赚佣金,邀请好友一起来',
path: '/pages/share/index',
});
const handleCopyLink = () => {
Taro.setClipboardData({ data: shareLink })
};

View File

@@ -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 Taro, { useRouter } from '@tarojs/taro'
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 SkuSelector from '@/components/business/SkuSelector'
import { getCompressedImageUrl } from '@/utils/image'
import { useShare } from '@/hooks/useShare'
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
definePageConfig({
navigationBarTitleText: '拼团详情',
enableShareAppMessage: true,
enableShareTimeline: true,
})
const GroupBuyDetailPage: React.FC = () => {
@@ -25,6 +29,31 @@ const GroupBuyDetailPage: React.FC = () => {
const [skuVisible, setSkuVisible] = useState(false)
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(() => {
if (groupBuyId) {
fetchData()
@@ -317,6 +346,8 @@ const GroupBuyDetailPage: React.FC = () => {
onClose={() => setSkuVisible(false)}
onConfirm={handleSkuConfirm}
/>
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
<SharePoster ref={posterRef} />
</View>
)
}

View File

@@ -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 { 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 {
addShopGoodsFavorite,
@@ -14,12 +14,16 @@ import SkuSelector from '@/components/business/SkuSelector'
import { useCartContext } from '@/contexts/CartContext'
import { useUserContext } from '@/contexts/UserContext'
import { useScrollHeight } from '@/hooks/useScrollHeight'
import { useShare } from '@/hooks/useShare'
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
import { isGuest } from '@/utils/auth'
import { requireLogin } from '@/utils/login-guard'
import { isVipMember } from '@/utils/vip'
definePageConfig({
navigationBarTitleText: '商品详情',
enableShareAppMessage: true,
enableShareTimeline: true,
})
const ProductDetailPage: React.FC = () => {
@@ -35,13 +39,14 @@ const ProductDetailPage: React.FC = () => {
// 底部操作栏高度约 90px含按钮 + 安全区),动态计算 ScrollView 可用高度
const scrollHeight = useScrollHeight(44)
// 微信分享配置
useShareAppMessage(() => {
return {
title: product?.name || product?.goodsName || '优质商品推荐',
path: `/pages/shop/product-detail?id=${id}`,
imageUrl: product?.image || ''
}
// 分享 / 朋友圈
const posterRef = useRef<SharePosterHandle>(null)
const [posterPath, setPosterPath] = useState('')
useShare({
title: product?.name || product?.goodsName || '优质商品推荐',
path: `/pages/shop/product-detail?id=${id}`,
query: `id=${id}`,
imageUrl: posterPath || product?.image || undefined,
})
useEffect(() => {
@@ -53,10 +58,20 @@ const ProductDetailPage: React.FC = () => {
}
}, [id, isLoggedIn])
// 监听 product 变化后再添加到历史记录
// 监听 product 变化后再添加到历史记录,并异步生成分享海报
useEffect(() => {
if (product) {
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])
@@ -444,6 +459,9 @@ const ProductDetailPage: React.FC = () => {
onClose={() => setSkuVisible(false)}
onConfirm={handleSkuConfirm}
/>
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
<SharePoster ref={posterRef} />
</View>
)
}

View File

@@ -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 Taro, { useRouter } from '@tarojs/taro'
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 { ShopGoodsSku } from '@/api/shop/shopGoodsSku/model'
import SkuSelector from '@/components/business/SkuSelector'
import { useShare } from '@/hooks/useShare'
import SharePoster, { SharePosterHandle } from '@/components/SharePoster'
definePageConfig({
navigationBarTitleText: '秒杀详情',
enableShareAppMessage: true,
enableShareTimeline: true,
})
const SeckillDetailPage: React.FC = () => {
@@ -24,6 +28,31 @@ const SeckillDetailPage: React.FC = () => {
const [countdown, setCountdown] = useState('')
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(() => {
if (seckillId) {
fetchData()
@@ -272,6 +301,8 @@ const SeckillDetailPage: React.FC = () => {
onClose={() => setSkuVisible(false)}
onConfirm={handleSkuConfirm}
/>
{/* 分享海报画布(离屏,用于生成带小程序码的海报图) */}
<SharePoster ref={posterRef} />
</View>
)
}

View File

@@ -3,16 +3,24 @@ import { View, Text, ScrollView, Input, Button, Image } from '@tarojs/components
import Taro, { useRouter } from '@tarojs/taro'
import { useUser } from '@/hooks/useUser'
import { useScrollHeight } from '@/hooks/useScrollHeight'
import { useShare } from '@/hooks/useShare'
import { getMyRegisterList, addSubordinate, updateSubordinate, MemberRegister } from '@/api/shop/shopMemberRegister'
import EmptyState from '@/components/common/EmptyState'
definePageConfig({
navigationBarTitleText: '录入下级',
enableShareAppMessage: true,
enableShareTimeline: true,
})
const InviteSubordinatePage: React.FC = () => {
const router = useRouter()
const { user, isLoggedIn } = useUser()
// 分享 / 朋友圈:带当前用户 id 作为邀请归因
useShare({
title: '邀请下级会员,一起拓客赚钱',
path: '/pages/user/invite-subordinate',
})
const scrollHeight = useScrollHeight()
const [loading, setLoading] = useState(true)
const [submitting, setSubmitting] = useState(false)

View File

@@ -2,14 +2,22 @@ import React, { useState, useEffect } from 'react'
import { View, Text, ScrollView, Button, Image } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useUser } from '@/hooks/useUser'
import { useShare } from '@/hooks/useShare'
import { useScrollHeight } from '@/hooks/useScrollHeight'
definePageConfig({
navigationBarTitleText: '分销推广',
enableShareAppMessage: true,
enableShareTimeline: true,
})
const PromotionPage: React.FC = () => {
const { user, isLoggedIn } = useUser()
// 分享 / 朋友圈:分销推广页,带当前用户 id 作为邀请归因
useShare({
title: '邀请好友,一起赚佣金',
path: '/pages/user/promotion',
})
const [inviteCode, setInviteCode] = useState('')
const [inviteLink, setInviteLink] = useState('')
const [qrCodeUrl, setQrCodeUrl] = useState('')

View File

@@ -2,15 +2,23 @@ import React, { useState, useEffect } from 'react'
import { View, Text, Input } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useUser } from '@/hooks/useUser'
import { useShare } from '@/hooks/useShare'
import { addShopDealerApply, listShopDealerApply } from '@/api/shop/shopDealerApply'
import type { ShopDealerApply } from '@/api/shop/shopDealerApply/model'
definePageConfig({
navigationBarTitleText: '升级VIP会员',
enableShareAppMessage: true,
enableShareTimeline: true,
})
const VipUpgradePage: React.FC = () => {
const { user, isLoggedIn } = useUser()
// 分享 / 朋友圈
useShare({
title: '升级VIP会员享专属优惠价',
path: '/pages/user/vip-upgrade',
})
const [realName, setRealName] = useState('')
const [address, setAddress] = useState('')
const [loading, setLoading] = useState(false)