feat(h5): add pull-to-refresh on user partner and shop pages
CI / verify (pull_request) Has been cancelled

Share PullToRefresh for partner/shop H5; enable Taro pull-down on mini-user lists.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-22 11:19:42 +08:00
parent 270cebc79a
commit ae7c63c08d
29 changed files with 443 additions and 121 deletions
@@ -1,4 +1,6 @@
export default definePageConfig({
navigationStyle: 'custom',
navigationBarTitleText: '地址管理',
enablePullDownRefresh: true,
backgroundTextStyle: 'dark',
});
+5 -1
View File
@@ -1,6 +1,6 @@
import { useCallback, useState } from 'react';
import { View, Text } from '@tarojs/components';
import Taro, { useDidShow, useRouter } from '@tarojs/taro';
import Taro, { useDidShow, usePullDownRefresh, useRouter } from '@tarojs/taro';
import PageShell from '../../components/PageShell';
import SubPageHeader from '../../components/SubPageHeader';
import {
@@ -44,6 +44,10 @@ export default function AddressesPage() {
loadList();
});
usePullDownRefresh(() => {
void Promise.resolve(loadList()).finally(() => Taro.stopPullDownRefresh());
});
function selectAddress(addr: Address) {
if (!selectMode) return;
Taro.redirectTo({
@@ -1,4 +1,6 @@
export default definePageConfig({
navigationStyle: 'custom',
navigationBarTitleText: '好客权益',
enablePullDownRefresh: true,
backgroundTextStyle: 'dark',
});
+13 -5
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { View, Text } from '@tarojs/components';
import Taro, { useDidShow } from '@tarojs/taro';
import Taro, { useDidShow, usePullDownRefresh } from '@tarojs/taro';
import PageShell from '../../components/PageShell';
import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar';
import { goLogin } from '../../lib/auth-nav';
@@ -44,9 +44,9 @@ export default function BenefitPage() {
syncTabBarSelected(2);
});
useEffect(() => {
if (!loggedIn) return;
Promise.all([
const loadBenefit = useCallback(() => {
if (!loggedIn) return Promise.resolve();
return Promise.all([
request<BenefitSummary>('/benefit/summary'),
request<CouponItem[]>('/benefit/coupons'),
])
@@ -57,6 +57,14 @@ export default function BenefitPage() {
.catch((e) => toast(e instanceof Error ? e.message : '加载失败'));
}, [loggedIn]);
useEffect(() => {
void loadBenefit();
}, [loadBenefit]);
usePullDownRefresh(() => {
void loadBenefit().finally(() => Taro.stopPullDownRefresh());
});
const available = coupons.filter((c) => c.status === 'ACTIVE' && c.balance > 0);
const history = coupons.filter((c) => c.status === 'USED_UP' || c.status === 'VOID');
const visible = tab === 'available' ? available : history;
@@ -1,3 +1,5 @@
export default definePageConfig({
navigationBarTitleText: '杜康好客',
enablePullDownRefresh: true,
backgroundTextStyle: 'dark',
});
+29 -4
View File
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { View, Text } from '@tarojs/components';
import Taro, { useDidShow } from '@tarojs/taro';
import Taro, { useDidShow, usePullDownRefresh } from '@tarojs/taro';
import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader';
import CouponBadge from '../../components/CouponBadge';
@@ -41,14 +41,39 @@ export default function HomePage() {
});
});
useEffect(() => {
const loadProducts = useCallback(() => {
setLoading(true);
request<Product[]>(`/catalog/products?cityCode=${encodeURIComponent(cityCode)}`)
return request<Product[]>(`/catalog/products?cityCode=${encodeURIComponent(cityCode)}`)
.then((list) => setProducts(Array.isArray(list) ? list : []))
.catch((e) => toast(e instanceof Error ? e.message : '加载失败'))
.finally(() => setLoading(false));
}, [cityCode]);
useEffect(() => {
void loadProducts();
}, [loadProducts]);
usePullDownRefresh(() => {
void (async () => {
try {
const resolved = await resolveUserCity();
setDisplayCity(resolved.displayCity);
const nextCode = getCityCodeForCatalog(resolved);
setCityCode(nextCode);
setLoading(true);
const list = await request<Product[]>(
`/catalog/products?cityCode=${encodeURIComponent(nextCode)}`,
);
setProducts(Array.isArray(list) ? list : []);
} catch (e) {
toast(e instanceof Error ? e.message : '加载失败');
} finally {
setLoading(false);
Taro.stopPullDownRefresh();
}
})();
});
const availableAromas = useMemo(
() =>
AROMA_TABS.filter((item) =>
@@ -1,3 +1,5 @@
export default definePageConfig({
navigationBarTitleText: '我的',
enablePullDownRefresh: true,
backgroundTextStyle: 'dark',
});
+14 -3
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { View, Text, Image, Button, Input } from '@tarojs/components';
import Taro, { useDidShow } from '@tarojs/taro';
import Taro, { useDidShow, usePullDownRefresh } from '@tarojs/taro';
import { isWxAuthorizeEnabled, type ClientRuntimeConfig } from '@dukang/shared-types';
import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader';
@@ -64,9 +64,9 @@ export default function MinePage() {
}
function loadProfile() {
if (!isLoggedIn()) return;
if (!isLoggedIn()) return Promise.resolve();
setProfileLoadError('');
Promise.all([
return Promise.all([
request<UserProfile>('/auth/me'),
request<Array<Record<string, unknown>>>('/benefit/coupons').catch(() => []),
...ORDER_SHORTCUTS.map((s) =>
@@ -109,6 +109,17 @@ export default function MinePage() {
}
});
usePullDownRefresh(() => {
const loggedInNow = isLoggedIn();
setAuthed(loggedInNow);
if (!loggedInNow) {
resetGuestState();
Taro.stopPullDownRefresh();
return;
}
void loadProfile().finally(() => Taro.stopPullDownRefresh());
});
useEffect(() => {
request<ClientRuntimeConfig>('/common/client-config')
.then((config) => setWxAuthorize(isWxAuthorizeEnabled(config)))
@@ -1,4 +1,6 @@
export default definePageConfig({
navigationStyle: 'custom',
navigationBarTitleText: '我的订单',
enablePullDownRefresh: true,
backgroundTextStyle: 'dark',
});
+12 -4
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { View, Text } from '@tarojs/components';
import Taro, { useRouter } from '@tarojs/taro';
import Taro, { usePullDownRefresh, useRouter } from '@tarojs/taro';
import PageShell from '../../components/PageShell';
import SubPageHeader from '../../components/SubPageHeader';
import { request, toast } from '../../lib/api';
@@ -47,9 +47,9 @@ export default function OrdersPage() {
const [orders, setOrders] = useState<OrderRow[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadOrders = useCallback(() => {
setLoading(true);
request<{ list?: OrderRow[]; items?: OrderRow[]; total?: number } | OrderRow[]>(
return request<{ list?: OrderRow[]; items?: OrderRow[]; total?: number } | OrderRow[]>(
`/trade/orders?tab=${encodeURIComponent(tab)}&pageSize=20`,
)
.then((data) => {
@@ -63,6 +63,14 @@ export default function OrdersPage() {
.finally(() => setLoading(false));
}, [tab]);
useEffect(() => {
void loadOrders();
}, [loadOrders]);
usePullDownRefresh(() => {
void loadOrders().finally(() => Taro.stopPullDownRefresh());
});
return (
<PageShell variant="sub" className="orders-page">
<SubPageHeader title="我的订单" />
@@ -1,3 +1,5 @@
export default definePageConfig({
navigationBarTitleText: '门店',
enablePullDownRefresh: true,
backgroundTextStyle: 'dark',
});
+28 -4
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { View, Text, Image, Input } from '@tarojs/components';
import Taro, { useDidShow } from '@tarojs/taro';
import Taro, { useDidShow, usePullDownRefresh } from '@tarojs/taro';
import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader';
import RegionPicker from '../../components/RegionPicker';
@@ -49,15 +49,39 @@ export default function StoresPage() {
});
});
useEffect(() => {
const loadStores = useCallback(() => {
setLoading(true);
const path = cityCode ? `/stores?cityCode=${encodeURIComponent(cityCode)}` : '/stores';
request<Store[]>(path)
return request<Store[]>(path)
.then((list) => setStores(Array.isArray(list) ? list : []))
.catch((e) => toast(e instanceof Error ? e.message : '加载失败'))
.finally(() => setLoading(false));
}, [cityCode]);
useEffect(() => {
void loadStores();
}, [loadStores]);
usePullDownRefresh(() => {
void (async () => {
try {
const resolved = await resolveUserCity();
setRegion(resolved.region);
const nextCode = getCityCodeForCatalog(resolved);
setCityCode(nextCode);
setLoading(true);
const path = nextCode ? `/stores?cityCode=${encodeURIComponent(nextCode)}` : '/stores';
const list = await request<Store[]>(path);
setStores(Array.isArray(list) ? list : []);
} catch (e) {
toast(e instanceof Error ? e.message : '加载失败');
} finally {
setLoading(false);
Taro.stopPullDownRefresh();
}
})();
});
const filtered = stores.filter((s) => {
if (!matchesRegionFilter(s, region)) return false;
if (!keyword.trim()) return true;