v4.0.18版本更新

This commit is contained in:
2026-09-08 13:47:42 +08:00
parent 23ba639e9b
commit 253430b291
14 changed files with 136 additions and 25 deletions
+9
View File
@@ -175,3 +175,12 @@ export function storeLeafCategoryIds(store: {
const id = String(store.categoryId || store.category?.id || '');
return id ? [id] : [];
}
/** C 端是否渲染「核销N次」;开关关闭或次数为 0 时不展示 */
export function shouldShowStoreRedeemCount(
enabled: boolean | undefined,
count?: number | null,
): boolean {
if (enabled === false) return false;
return Number(count) > 0;
}
@@ -17,11 +17,13 @@ import StoreRedeemMarquee, { type StoreRedeemMarqueeItem } from '../../component
import BenefitIntroCard from '../../components/BenefitIntroCard';
import WechatShareReady from '../../components/WechatShareReady';
import { request, toast, isLoggedIn } from '../../lib/api';
import { fetchClientConfig } from '../../lib/pay-wechat';
import { toMoneyNumber } from '../../lib/money';
import { maskPhone, toDialablePhone } from '../../lib/phone';
import { track } from '../../lib/analytics';
import {
fullStoreAddress,
shouldShowStoreRedeemCount,
storeCategoryTags,
storeStarCount,
type StoreCategoryTreeNode,
@@ -190,6 +192,7 @@ export default function StoreDetailPage() {
const [loadError, setLoadError] = useState('');
const [headerSolid, setHeaderSolid] = useState(false);
const [pendingRatingId, setPendingRatingId] = useState<string | null>(null);
const [showStoreRedeemCount, setShowStoreRedeemCount] = useState(true);
const storeRef = useRef<Store | null>(null);
storeRef.current = store;
@@ -197,6 +200,12 @@ export default function StoreDetailPage() {
setHeaderSolid(scrollTop > 100);
});
useEffect(() => {
void fetchClientConfig()
.then((cfg) => setShowStoreRedeemCount(cfg.showStoreRedeemCount !== false))
.catch(() => undefined);
}, []);
const loadStore = useCallback(async (id: string) => {
if (!id) {
setLoading(false);
@@ -440,7 +449,7 @@ export default function StoreDetailPage() {
</Text>
))}
</View>
{Number(store.redeemCount) > 0 ? (
{shouldShowStoreRedeemCount(showStoreRedeemCount, store.redeemCount) ? (
<Text className="store-detail-redeem">{store.redeemCount}</Text>
) : null}
</View>
+31 -6
View File
@@ -28,6 +28,7 @@ import {
import { FALLBACK_CITY_CODE } from '../../lib/product-images';
import { formatDistanceMeters } from '../../lib/geo';
import { getToken, request, toast } from '../../lib/api';
import { fetchClientConfig } from '../../lib/pay-wechat';
import {
getStoresListCache,
isStoresSessionBootstrapped,
@@ -42,7 +43,7 @@ import {
toWeappShareTimeline,
} from '../../lib/wechat-share';
import BenefitSloganBar from '../../components/BenefitSloganBar';
import { fullStoreAddress, storeCategoryTags, storeLeafCategoryIds, storeStarCount } from '../../lib/store-display';
import { fullStoreAddress, shouldShowStoreRedeemCount, storeCategoryTags, storeLeafCategoryIds, storeStarCount } from '../../lib/store-display';
import openBadgeImg from '../../assets/icons/store-open-badge.png';
type Store = {
@@ -123,13 +124,21 @@ export default function StoresPage() {
const [categoryTree, setCategoryTree] = useState<StoreCategoryNode[]>([]);
const [sort, setSort] = useState<StoreSortKey>(() => cached?.sort ?? 'nearby');
const [sortOpen, setSortOpen] = useState(false);
const [showStoreRedeemCount, setShowStoreRedeemCount] = useState(true);
const fetchCityKeyRef = useRef<string | null>(cached?.cityKey ?? null);
const fetchSeqRef = useRef(0);
const regionRef = useRef(region);
regionRef.current = region;
const regionLabel = formatRegionLabel(region);
const categoryLabel = formatCategoryLabel(category);
const sortLabel = STORE_SORT_OPTIONS.find((o) => o.key === sort)?.label ?? '附近优先';
const sortOptions = useMemo(
() =>
showStoreRedeemCount
? STORE_SORT_OPTIONS
: STORE_SORT_OPTIONS.filter((o) => o.key !== 'redeem'),
[showStoreRedeemCount],
);
const sortLabel = sortOptions.find((o) => o.key === sort)?.label ?? '附近优先';
const showBootLoading = loading && stores.length === 0;
const childIdsByParent = useMemo(() => {
@@ -143,6 +152,22 @@ export default function StoresPage() {
return map;
}, [categoryTree]);
useEffect(() => {
void fetchClientConfig()
.then((cfg) => {
const enabled = cfg.showStoreRedeemCount !== false;
setShowStoreRedeemCount(enabled);
if (!enabled) {
setSort((prev) => {
if (prev !== 'redeem') return prev;
patchStoresFilterCache({ sort: 'nearby' });
return 'nearby';
});
}
})
.catch(() => undefined);
}, []);
async function fetchStores(
nextCode: string,
coords: UserCoords | null,
@@ -329,7 +354,7 @@ export default function StoresPage() {
if (sort === 'rating') {
const diff = storeStarCount(b.rating) - storeStarCount(a.rating);
if (diff !== 0) return diff;
} else if (sort === 'redeem') {
} else if (sort === 'redeem' && showStoreRedeemCount) {
const diff = (b.redeemCount ?? 0) - (a.redeemCount ?? 0);
if (diff !== 0) return diff;
}
@@ -338,7 +363,7 @@ export default function StoresPage() {
return da - db;
});
return next;
}, [stores, region, category, keyword, sort, childIdsByParent]);
}, [stores, region, category, keyword, sort, childIdsByParent, showStoreRedeemCount]);
function applySearch() {
const next = keywordInput.trim();
@@ -497,7 +522,7 @@ export default function StoresPage() {
</Text>
))}
</View>
{Number(s.redeemCount) > 0 ? (
{shouldShowStoreRedeemCount(showStoreRedeemCount, s.redeemCount) ? (
<Text className="store-card-redeem">{s.redeemCount}</Text>
) : null}
</View>
@@ -551,7 +576,7 @@ export default function StoresPage() {
</Text>
</View>
<View className="region-picker-list">
{STORE_SORT_OPTIONS.map((opt) => (
{sortOptions.map((opt) => (
<View
key={opt.key}
className={`region-picker-option${sort === opt.key ? ' selected' : ''}`}