From 00f3954012290ffd7e9310318165db58a568f084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Mar 2026 12:11:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(ticket):=20=E5=AE=9E=E7=8E=B0=E5=9F=BA?= =?UTF-8?q?=E4=BA=8E=E6=A8=A1=E6=9D=BF=E9=85=8D=E7=BD=AE=E7=9A=84=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E8=B5=B7=E9=80=81=E6=95=B0=E9=87=8F=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入 gltTicketTemplate API 获取模板配置 - 将固定起送数量改为动态可配置的最小起送数量 - 添加基于商品ID或票据模板ID获取起送配置的功能 - 实现页面初始化时从票据模板加载起送数量配置 - 更新用户界面显示实际的动态起送数量要求 - 添加异步加载和取消请求的安全处理机制 --- src/user/ticket/use.tsx | 81 ++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/src/user/ticket/use.tsx b/src/user/ticket/use.tsx index 7f698dd..8a98f8f 100644 --- a/src/user/ticket/use.tsx +++ b/src/user/ticket/use.tsx @@ -26,6 +26,7 @@ import {getShopStore, listShopStore} from "@/api/shop/shopStore"; import {getSelectedStoreFromStorage, saveSelectedStoreToStorage} from "@/utils/storeSelection"; import type { GltUserTicket } from '@/api/glt/gltUserTicket/model' import { getGltUserTicket, listGltUserTicket } from '@/api/glt/gltUserTicket' +import { getGltTicketTemplate, getGltTicketTemplateByGoodsId } from '@/api/glt/gltTicketTemplate' import { addGltTicketOrder, getGltTicketOrder, updateGltTicketOrder } from '@/api/glt/gltTicketOrder' import { pageGltTicketOrder } from '@/api/glt/gltTicketOrder' import type { GltTicketOrder } from '@/api/glt/gltTicketOrder/model' @@ -35,13 +36,14 @@ import type { ShopStoreFence } from '@/api/shop/shopStoreFence/model' import { listShopStoreFence } from '@/api/shop/shopStoreFence' import { parseFencePoints, parseLngLatFromText, pointInAnyPolygon, pointInPolygon } from '@/utils/geofence' -const MIN_START_QTY = 10 +const DEFAULT_MIN_START_QTY = 10 const ADDRESS_CHANGE_COOLDOWN_DAYS = 30 const OrderConfirm = () => { const [goods, setGoods] = useState(null); const [address, setAddress] = useState() - const [quantity, setQuantity] = useState(MIN_START_QTY) + const [minStartQty, setMinStartQty] = useState(DEFAULT_MIN_START_QTY) + const [quantity, setQuantity] = useState(DEFAULT_MIN_START_QTY) const [orderRemark, setOrderRemark] = useState('') // Delivery date only (no hour/min selection). const [sendTime, setSendTime] = useState(() => dayjs().startOf('day').toDate()) @@ -325,13 +327,13 @@ const OrderConfirm = () => { }, [availableTicketTotal, editingOrder?.totalNum, editingOrder?.userTicketId, goods?.stock, isEditMode, tickets]) const canStartOrder = useMemo(() => { - return maxQuantity >= MIN_START_QTY - }, [maxQuantity]) + return maxQuantity >= minStartQty + }, [maxQuantity, minStartQty]) const displayQty = useMemo(() => { if (!canStartOrder) return 0 - return Math.max(MIN_START_QTY, Math.min(quantity, maxQuantity)) - }, [quantity, maxQuantity, canStartOrder]) + return Math.max(minStartQty, Math.min(quantity, maxQuantity)) + }, [quantity, maxQuantity, canStartOrder, minStartQty]) const sendTimeText = useMemo(() => { return dayjs(sendTime).format('YYYY-MM-DD') @@ -600,7 +602,7 @@ const OrderConfirm = () => { setQuantity(0) return } - setQuantity(Math.max(MIN_START_QTY, Math.min(newQuantity || MIN_START_QTY, upper))) + setQuantity(Math.max(minStartQty, Math.min(newQuantity || minStartQty, upper))) } const loadUserTickets = async () => { @@ -718,8 +720,8 @@ const OrderConfirm = () => { Taro.showToast({ title: '商品库存不足', icon: 'none' }) return } - if (finalQty < MIN_START_QTY) { - Taro.showToast({ title: `最低起送 ${MIN_START_QTY} 桶`, icon: 'none' }) + if (finalQty < minStartQty) { + Taro.showToast({ title: `最低起送 ${minStartQty} 桶`, icon: 'none' }) return } if (!sendTime) { @@ -863,8 +865,8 @@ const OrderConfirm = () => { return } - const initQty = Number(editingOrderRes.totalNum ?? MIN_START_QTY) - setQuantity(Number.isFinite(initQty) && initQty > 0 ? initQty : MIN_START_QTY) + const initQty = Number(editingOrderRes.totalNum ?? minStartQty) + setQuantity(Number.isFinite(initQty) && initQty > 0 ? initQty : minStartQty) setOrderRemark(String(editingOrderRes.buyerRemarks || '')) const st = parseTime(editingOrderRes.sendTime) if (st) setSendTime(st.startOf('day').toDate()) @@ -1000,11 +1002,54 @@ const OrderConfirm = () => { useEffect(() => { setQuantity(prev => { if (maxQuantity <= 0) return 0 - if (maxQuantity < MIN_START_QTY) return 0 - if (!prev || prev < MIN_START_QTY) return MIN_START_QTY + if (maxQuantity < minStartQty) return 0 + if (!prev || prev < minStartQty) return minStartQty return Math.min(prev, maxQuantity) }) - }, [maxQuantity]) + }, [maxQuantity, minStartQty]) + + const minStartQtyKey = useMemo(() => { + const gid = Number(goods?.goodsId) + if (Number.isFinite(gid) && gid > 0) return `g:${gid}` + + // If there is exactly one ticket template available, infer min start qty from it (covers "稍后再送" without goodsId). + const ids = Array.from( + new Set( + (usableTickets || []) + .map(t => Number(t?.templateId)) + .filter(id => Number.isFinite(id) && id > 0) + ) + ) + if (ids.length === 1) return `t:${ids[0]}` + return '' + }, [goods?.goodsId, usableTickets]) + + // Use configured min start-send qty from ticket template (by goodsId or by user's unique templateId). + useEffect(() => { + let cancelled = false + ;(async () => { + try { + if (!minStartQtyKey) { + setMinStartQty(DEFAULT_MIN_START_QTY) + return + } + const [kind, rawId] = minStartQtyKey.split(':') + const id = Number(rawId) + const tpl = + kind === 'g' + ? await getGltTicketTemplateByGoodsId(id) + : await getGltTicketTemplate(id) + const n = Number(tpl?.startSendQty) + const safe = Number.isFinite(n) && n > 0 ? n : DEFAULT_MIN_START_QTY + if (!cancelled) setMinStartQty(safe) + } catch (_e) { + if (!cancelled) setMinStartQty(DEFAULT_MIN_START_QTY) + } + })() + return () => { + cancelled = true + } + }, [minStartQtyKey]) // If user has no usable tickets, proactively guide them to purchase (only once per page lifecycle). useEffect(() => { @@ -1138,16 +1183,16 @@ const OrderConfirm = () => { title={'送水数量'} description={ canStartOrder - ? `最低起送 ${MIN_START_QTY} 桶` - : `最低起送 ${MIN_START_QTY} 桶(当前最多 ${maxQuantity} 桶)` + ? `最低起送 ${minStartQty} 桶` + : `最低起送 ${minStartQty} 桶(当前最多 ${maxQuantity} 桶)` } extra={( = 10 ? 10 : 1} readOnly disabled={!canStartOrder} onChange={handleQuantityChange}