diff --git a/src/dealer/qrcode/index.config.ts b/src/dealer/qrcode/index.config.ts index 18e1216..8c86bc6 100644 --- a/src/dealer/qrcode/index.config.ts +++ b/src/dealer/qrcode/index.config.ts @@ -1,3 +1,6 @@ export default definePageConfig({ - navigationBarTitleText: '桂乐淘分享中心' + navigationBarTitleText: '桂乐淘分享中心', + // Enable "Share to friends" and "Share to Moments" (timeline) for this page. + enableShareAppMessage: true, + enableShareTimeline: true }) diff --git a/src/dealer/qrcode/index.tsx b/src/dealer/qrcode/index.tsx index 3c4aaa0..a721389 100644 --- a/src/dealer/qrcode/index.tsx +++ b/src/dealer/qrcode/index.tsx @@ -2,7 +2,7 @@ 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 Taro, {useShareAppMessage} from '@tarojs/taro' import {useDealerUser} from '@/hooks/useDealerUser' import {generateInviteCode} from '@/api/invite' // import type {InviteStats} from '@/api/invite' @@ -16,6 +16,39 @@ const DealerQrcode: React.FC = () => { // const [statsLoading, setStatsLoading] = useState(false) const {dealerUser, loading: dealerLoading, error, refresh} = useDealerUser() + // Enable "转发给朋友" + "分享到朋友圈" items in the share panel/menu. + useEffect(() => { + // Some clients require explicit call to show both share entries. + Taro.showShareMenu({ + withShareTicket: true, + showShareItems: ['shareAppMessage', 'shareTimeline'] + }).catch(() => {}) + }, []) + + // 转发给朋友(分享小程序链接) + useShareAppMessage(() => { + const inviterRaw = dealerUser?.userId ?? Taro.getStorageSync('UserId') + const inviter = Number(inviterRaw) + const hasInviter = Number.isFinite(inviter) && inviter > 0 + + const user = Taro.getStorageSync('User') || {} + const nickname = (user && (user.nickname || user.realName || user.username)) || '' + const title = hasInviter ? `${nickname || '我'}邀请你加入桂乐淘伙伴计划` : '桂乐淘伙伴计划' + + return { + title, + path: hasInviter + ? `/pages/index/index?inviter=${inviter}&source=dealer_qrcode&t=${Date.now()}` + : `/pages/index/index`, + success: function () { + Taro.showToast({title: '分享成功', icon: 'success', duration: 2000}) + }, + fail: function () { + Taro.showToast({title: '分享失败', icon: 'none', duration: 2000}) + } + } + }) + // 生成小程序码 const generateMiniProgramCode = async () => { if (!dealerUser?.userId) { @@ -376,29 +409,7 @@ const DealerQrcode: React.FC = () => { 保存小程序码到相册 - {/**/} - {/* }*/} - {/* onClick={copyInviteInfo}*/} - {/* disabled={!dealerUser?.userId || codeLoading}*/} - {/* >*/} - {/* 复制邀请信息*/} - {/* */} - {/**/} - {/**/} - {/* }*/} - {/* onClick={shareMiniProgramCode}*/} - {/* disabled={!dealerUser?.userId || codeLoading}*/} - {/* >*/} - {/* 分享给好友*/} - {/* */} - {/**/} + {/* 推广说明 */} diff --git a/src/shop/goodsDetail/index.tsx b/src/shop/goodsDetail/index.tsx index 80c04d4..4c4fa19 100644 --- a/src/shop/goodsDetail/index.tsx +++ b/src/shop/goodsDetail/index.tsx @@ -17,6 +17,8 @@ import {useCart} from "@/hooks/useCart"; import {useConfig} from "@/hooks/useConfig"; import {parseInviteParams, saveInviteParams, trackInviteSource} from "@/utils/invite"; import { ensureLoggedIn } from '@/utils/auth' +import {getGltTicketTemplateByGoodsId} from "@/api/glt/gltTicketTemplate"; +import type {GltTicketTemplate} from "@/api/glt/gltTicketTemplate/model"; const GoodsDetail = () => { const [statusBarHeight, setStatusBarHeight] = useState(44); @@ -32,6 +34,8 @@ const GoodsDetail = () => { title: '', content: '' }) + // 水票套票模板:存在时该商品不允许加入购物车(购物车无法支付此类商品) + const [ticketTemplate, setTicketTemplate] = useState(null) // const [selectedSku, setSelectedSku] = useState(null); const [loading, setLoading] = useState(false); const router = Taro.getCurrentInstance().router; @@ -60,9 +64,25 @@ const GoodsDetail = () => { }, [goodsId]) // 处理加入购物车 - const handleAddToCart = () => { + const handleAddToCart = async () => { if (!goods) return; + // 水票套票商品:不允许加入购物车(购物车无法支付) + // 优先使用已加载的 ticketTemplate;若尚未加载则补一次查询 + let tpl = ticketTemplate + if (!tpl && goods?.goodsId) { + try { + tpl = await getGltTicketTemplateByGoodsId(Number(goods.goodsId)) + setTicketTemplate(tpl) + } catch (_e) { + tpl = null + } + } + if (tpl) { + Taro.showToast({title: '该商品为水票套票商品,请点击“立即购买”下单', icon: 'none'}) + return + } + if (!ensureLoggedIn(`/shop/goodsDetail/index?id=${goods.goodsId}`)) return // 如果有规格,显示规格选择器 @@ -99,11 +119,26 @@ const GoodsDetail = () => { }; // 规格选择确认回调 - const handleSpecConfirm = (sku: ShopGoodsSku, quantity: number, action?: 'cart' | 'buy') => { + const handleSpecConfirm = async (sku: ShopGoodsSku, quantity: number, action?: 'cart' | 'buy') => { // setSelectedSku(sku); setShowSpecSelector(false); if (action === 'cart') { + // 水票套票商品:不允许加入购物车(购物车无法支付) + let tpl = ticketTemplate + if (!tpl && goods?.goodsId) { + try { + tpl = await getGltTicketTemplateByGoodsId(Number(goods.goodsId)) + setTicketTemplate(tpl) + } catch (_e) { + tpl = null + } + } + if (tpl) { + Taro.showToast({title: '该商品为水票套票商品,请点击“立即购买”下单', icon: 'none'}) + return + } + // 加入购物车 addToCart({ goodsId: goods!.goodsId!, @@ -143,14 +178,18 @@ const GoodsDetail = () => { } useEffect(() => { + let alive = true Taro.getSystemInfo({ success: (res) => { + if (!alive) return setWindowWidth(res.windowWidth) setStatusBarHeight(Number(res.statusBarHeight) + 5) }, }); if (goodsId) { setLoading(true); + // 切换商品时先重置套票模板,避免复用上一个商品状态 + setTicketTemplate(null) // 加载商品详情 getShopGoods(Number(goodsId)) @@ -159,6 +198,7 @@ const GoodsDetail = () => { if (res.content) { res.content = wxParse(res.content); } + if (!alive) return setGoods(res); if (res.files) { const arr = JSON.parse(res.files); @@ -169,12 +209,25 @@ const GoodsDetail = () => { console.error("Failed to fetch goods detail:", error); }) .finally(() => { + if (!alive) return setLoading(false); }); + // 查询商品是否绑定水票模板(失败/无数据时不影响正常浏览) + getGltTicketTemplateByGoodsId(Number(goodsId)) + .then((tpl) => { + if (!alive) return + setTicketTemplate(tpl) + }) + .catch((_e) => { + if (!alive) return + setTicketTemplate(null) + }) + // 加载商品规格 listShopGoodsSpec({goodsId: Number(goodsId)} as any) .then((data) => { + if (!alive) return setSpecs(data || []); }) .catch((error) => { @@ -184,12 +237,16 @@ const GoodsDetail = () => { // 加载商品SKU listShopGoodsSku({goodsId: Number(goodsId)} as any) .then((data) => { + if (!alive) return setSkus(data || []); }) .catch((error) => { console.error("Failed to fetch goods skus:", error); }); } + return () => { + alive = false + } }, [goodsId]); // 分享给好友