v3.5.3版本更新1
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-08-20 18:54:15 +08:00
parent ee493823bf
commit fc2e5b65de
65 changed files with 2297 additions and 875 deletions
+19 -9
View File
@@ -4,6 +4,7 @@ import Taro, { useDidShow, usePullDownRefresh, useShareAppMessage, useShareTimel
import PageShell from '../../components/PageShell';
import WechatShareReady from '../../components/WechatShareReady';
import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar';
import BenefitFigure from '../../components/BenefitFigure';
import { goLogin } from '../../lib/auth-nav';
import { isLoggedIn, request, toast } from '../../lib/api';
import { navBarStyle, tabNavContentStyle, useNavBarMetrics } from '../../lib/nav-bar';
@@ -150,10 +151,11 @@ export default function BenefitPage() {
<View>
<Text className="benefit-hero-label"></Text>
<View className="benefit-hero-amount">
<Text className="benefit-hero-symbol">¥</Text>
<Text className="benefit-hero-value">
{summary ? formatMoney(summary.totalBalance) : '--'}
</Text>
<BenefitFigure
value={summary ? formatMoney(summary.totalBalance) : '--'}
size="xl"
className="benefit-hero-value"
/>
</View>
</View>
<View className="benefit-hero-logo">
@@ -193,16 +195,19 @@ export default function BenefitPage() {
<View className="benefit-coupon-notch benefit-coupon-notch--right" />
<View className="benefit-coupon-head">
<Text className="benefit-coupon-name">{c.sourceProduct || '好客权益'}</Text>
<Text className="benefit-coupon-balance">¥{formatMoney(c.balance)}</Text>
<BenefitFigure value={formatMoney(c.balance)} size="md" className="benefit-coupon-balance" />
</View>
<Text className="benefit-coupon-no">NO. {c.couponNo}</Text>
<View className="benefit-progress">
<View className="benefit-progress-bar" style={{ width: `${usagePercent(c)}%` }} />
</View>
<View className="benefit-coupon-footer">
<Text className="benefit-coupon-meta">
¥{formatMoney(c.usedAmount)} / ¥{formatMoney(c.totalAmount)}
</Text>
<View className="benefit-coupon-meta">
<Text></Text>
<BenefitFigure value={formatMoney(c.usedAmount)} size="sm" />
<Text>/ </Text>
<BenefitFigure value={formatMoney(c.totalAmount)} size="sm" />
</View>
<Text
className="benefit-coupon-btn"
onClick={() =>
@@ -226,7 +231,12 @@ export default function BenefitPage() {
<View className="benefit-coupon-notch benefit-coupon-notch--right" />
<View className="benefit-coupon-head">
<Text className="benefit-coupon-name">{r.storeName || '门店核销'}</Text>
<Text className="benefit-coupon-balance">-¥{formatMoney(Number(r.amount))}</Text>
<BenefitFigure
prefix="-"
value={formatMoney(Number(r.amount))}
size="md"
className="benefit-coupon-balance"
/>
</View>
<Text className="benefit-coupon-no">NO. {r.redeemNo}</Text>
<View className="benefit-coupon-footer">
+2 -2
View File
@@ -9,6 +9,7 @@ import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader';
import WechatShareReady from '../../components/WechatShareReady';
import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar';
import BenefitFigure from '../../components/BenefitFigure';
import { goLogin } from '../../lib/auth-nav';
import { bindWechatForUser } from '../../lib/wechat-auth';
import {
@@ -447,8 +448,7 @@ export default function MinePage() {
<View>
<Text className="mine-asset-label"></Text>
<View className="mine-asset-amount">
<Text className="mine-asset-currency">¥</Text>
<Text className="mine-asset-value">{formatMoney(benefitBalance)}</Text>
<BenefitFigure value={formatMoney(benefitBalance)} size="lg" className="mine-asset-value" />
</View>
</View>
<Text
@@ -10,6 +10,7 @@ import { ensurePayReady } from '../../lib/pay-ready';
import { fetchUserProfile } from '../../lib/pay-wechat';
import { request, toast } from '../../lib/api';
import { getProductMainImage } from '../../lib/product-images';
import BenefitFigure from '../../components/BenefitFigure';
type PreviewProduct = {
id: string;
@@ -231,7 +232,11 @@ export default function OrderConfirmPickupPage() {
</View>
<View className="order-row">
<Text className="order-row-label"></Text>
<Text className="order-row-value--price">¥{Number(preview.benefitAmount).toFixed(2)}</Text>
<BenefitFigure
value={Number(preview.benefitAmount).toFixed(2)}
size="sm"
className="order-row-value--price"
/>
</View>
<View className="order-row">
<Text className="order-row-label"></Text>
@@ -13,6 +13,7 @@ import { fetchUserProfile } from '../../lib/pay-wechat';
import { request, toast } from '../../lib/api';
import { canCrossCity, isCrossCityAddress } from '../../lib/product-fulfillment';
import { getProductMainImage } from '../../lib/product-images';
import BenefitFigure from '../../components/BenefitFigure';
type Address = {
id: string;
@@ -384,7 +385,11 @@ export default function OrderConfirmPage() {
</View>
<View className="order-row">
<Text className="order-row-label"></Text>
<Text className="order-row-value--price">¥{preview.benefitAmount.toFixed(2)}</Text>
<BenefitFigure
value={preview.benefitAmount.toFixed(2)}
size="sm"
className="order-row-value--price"
/>
</View>
<View className="order-row">
<Text className="order-row-label"></Text>
@@ -13,6 +13,7 @@ import PageShell from '../../components/PageShell';
import PageNavBar from '../../components/PageNavBar';
import ProductCarousel from '../../components/ProductCarousel';
import WechatShareReady from '../../components/WechatShareReady';
import BenefitFigure from '../../components/BenefitFigure';
import { goLogin } from '../../lib/auth-nav';
import { ensurePayReady } from '../../lib/pay-ready';
import { isLoggedIn, request, toast } from '../../lib/api';
@@ -189,10 +190,10 @@ export default function ProductDetailPage() {
<View className="product-detail-promo-icon">
<Text className="product-detail-promo-icon-text"></Text>
</View>
<Text className="product-detail-promo-title">
·
<Text className="product-detail-promo-amount"> ¥{benefit}</Text>
</Text>
<View className="product-detail-promo-title">
<Text> · </Text>
<BenefitFigure value={String(benefit)} size="sm" className="product-detail-promo-amount" />
</View>
</View>
<Text className="product-detail-promo-desc">
@@ -8,6 +8,7 @@ import RedeemQrCode from '../../components/RedeemQrCode';
import SubPageHeader from '../../components/SubPageHeader';
import { request, toast } from '../../lib/api';
import { formatMoney } from '../../lib/money';
import BenefitFigure from '../../components/BenefitFigure';
const POLL_INTERVAL_MS = 2500;
const LAST_REDEEM_RECORD_KEY = 'lastRedeemRecordId';
@@ -154,7 +155,7 @@ export default function RedeemCodePage() {
<Text className="redeem-timer-label"></Text>
</View>
<Text className="u-muted"></Text>
<Text className="redeem-code-amount">¥ {formatMoney(amount)}</Text>
<BenefitFigure value={formatMoney(amount)} size="lg" className="redeem-code-amount" />
{token ? (
<View className="redeem-code-token-wrap" onClick={onTokenTap}>
<Text className="redeem-code-token-label"></Text>
@@ -6,7 +6,8 @@ import PageShell from '../../components/PageShell';
import SubPageHeader from '../../components/SubPageHeader';
import { request, toast } from '../../lib/api';
import { formatShanghaiDateTime } from '../../lib/datetime';
import { formatMoney } from '../../lib/money';
import { formatMoney, toMoneyNumber } from '../../lib/money';
import BenefitFigure from '../../components/BenefitFigure';
const LAST_REDEEM_RESULT_KEY = 'lastRedeemResult';
@@ -66,7 +67,7 @@ export default function RedeemSuccessPage() {
}
}, []);
const amount = Number(record?.amount ?? router.params.amount ?? 0);
const amount = toMoneyNumber(record?.amount ?? router.params.amount);
const storeName = record?.storeName || '门店';
const redeemNo = record?.redeemNo || '—';
const redeemedAt = formatChinaDateTime(record?.createdAt);
@@ -119,7 +120,7 @@ export default function RedeemSuccessPage() {
<Text></Text>
</View>
<Text className="redeem-success-title"></Text>
<Text className="redeem-success-amount">¥ {formatMoney(amount)}</Text>
<BenefitFigure value={formatMoney(amount)} size="lg" className="redeem-success-amount" />
<Text className="redeem-success-desc"> {storeName} </Text>
<View className="redeem-success-details">
+11 -7
View File
@@ -7,6 +7,7 @@ import SubPageHeader from '../../components/SubPageHeader';
import { goLogin } from '../../lib/auth-nav';
import { isLoggedIn, request, toast } from '../../lib/api';
import { formatMoney } from '../../lib/money';
import BenefitFigure from '../../components/BenefitFigure';
type BenefitSummary = {
totalBalance: number;
@@ -103,7 +104,7 @@ export default function RedeemPage() {
return;
}
if (value > redeemableMax) {
toast(couponId ? '核销金额不能超过该权益可用余额' : '超出可用余额');
toast(couponId ? '核销金额不能超过该权益可用余额' : '核销金额不能超过可用余额');
return;
}
@@ -134,9 +135,11 @@ export default function RedeemPage() {
<Text className="redeem-hero-label">
{couponId ? '当前权益可用余额' : '可用余额'}
</Text>
<Text className="redeem-hero-amount">
¥{redeemableMax > 0 ? formatMoney(redeemableMax) : '--'}
</Text>
<BenefitFigure
value={redeemableMax > 0 ? formatMoney(redeemableMax) : '--'}
size="xl"
className="redeem-hero-amount"
/>
</View>
<View className="redeem-input-wrap">
<Input
@@ -153,9 +156,10 @@ export default function RedeemPage() {
/>
</View>
<View className="redeem-amount-foot">
<Text className="redeem-amount-hint">
¥{formatMoney(redeemableMax)}
</Text>
<View className="redeem-amount-hint">
<Text></Text>
<BenefitFigure value={formatMoney(redeemableMax)} size="sm" />
</View>
<Text className="redeem-fill-max" onClick={fillMaxAmount}>
</Text>
@@ -16,6 +16,7 @@ import ShareNavButton from '../../components/ShareNavButton';
import StoreRedeemMarquee from '../../components/StoreRedeemMarquee';
import WechatShareReady from '../../components/WechatShareReady';
import { request, toast } from '../../lib/api';
import { toMoneyNumber } from '../../lib/money';
import { maskPhone, toDialablePhone } from '../../lib/phone';
import { track } from '../../lib/analytics';
import { formatShanghaiDateTime } from '../../lib/datetime';
@@ -116,9 +117,8 @@ function formatPackagePriceYuan(price: string | number) {
return n.toFixed(2).replace(/\.?0+$/, '');
}
function formatRedeemAmountYuan(amount: number | string) {
const n = typeof amount === 'number' ? amount : Number(amount);
if (!Number.isFinite(n)) return '0';
function formatRedeemAmountYuan(amount: unknown) {
const n = toMoneyNumber(amount);
if (Math.abs(n - Math.round(n)) < 1e-9) return String(Math.round(n));
return n.toFixed(2).replace(/\.?0+$/, '');
}
@@ -323,6 +323,8 @@ export default function StoreDetailPage() {
const envPhotos = envPhotoUrls(store);
const heroImages = uniqueUrls([store.coverUrl, ...(store.carouselUrls || [])]);
/** 预览相册:封面 + 环境图(去重),页面展示仍分开 */
const previewAlbum = uniqueUrls([store.coverUrl, ...envPhotos]);
const packages = store.packages ?? [];
const intro = store.intro?.trim() || '';
@@ -337,10 +339,12 @@ export default function StoreDetailPage() {
}
function previewEnv(index: number) {
if (!envPhotos.length) return;
const current = envPhotos[index];
if (!current) return;
const urls = previewAlbum.length ? previewAlbum : envPhotos;
Taro.previewImage({
current: envPhotos[index],
urls: envPhotos,
current,
urls,
}).catch(() => toast('无法预览图片'));
}
@@ -362,6 +366,7 @@ export default function StoreDetailPage() {
variant="store"
previewable
imageFit="contain"
previewUrls={previewAlbum}
/>
</View>