Files
danyang-match/miniapp/pages/activity/activity.ts
T

173 lines
5.0 KiB
TypeScript
Raw Normal View History

2026-09-09 22:05:00 +08:00
/**
* 公益活动列表页 U31
*
* 重构要点(遵循 AGENTS.md 不变量):
* - 数据:ActivityStore.fetchActivities / loadMoreActivities(游标分页)
* - 列表项:ui-activity-card 组件,"公益免费"为主视觉标识(AGENTS 第 1 条:用户永久免费)
* - 跳转:点击卡片 → activity-detail,不在列表页处理报名
* - 单向意向保密:本页不接入互选意向提交(仅在 activity-matches 页由用户主动操作,AGENTS 第 6 条)
* - 下拉刷新 + onReachBottom 加载更多
*/
import { activityStore, appStore, authStore } from '../../stores';
import { to } from '../../constants';
interface ActivityCategory {
code: string;
label: string;
}
/**
* 列表项。沿用共享 Activity 类型,并允许服务端附加分类字段用于本地筛选。
* 分类字段在共享类型中尚未收敛,此处显式声明,避免用 any 绕过类型检查。
*/
interface ActivityListItem {
activityId?: string;
id?: string;
activityType?: string;
category?: string;
[key: string]: unknown;
}
interface ActivityPageData {
activities: ActivityListItem[];
loading: boolean;
loadingMore: boolean;
hasMore: boolean;
firstLoaded: boolean;
activeCategory: string;
categories: ActivityCategory[];
emptyConfig: {
title: string;
description: string;
illustration: string;
actions: Array<{ text: string; event: string; variant: string }>;
};
}
2026-09-09 22:05:00 +08:00
Page({
data: {
activities: [] as ActivityListItem[],
2026-09-09 22:05:00 +08:00
loading: false,
loadingMore: false,
hasMore: true,
firstLoaded: false,
2026-09-14 07:05:20 +08:00
activeCategory: 'all',
categories: [
{ code: 'all', label: '全部' },
{ code: 'matchmaking', label: '公益联谊' },
{ code: 'classroom', label: '婚恋课堂' },
{ code: 'anti_fraud', label: '反诈宣传' },
],
2026-09-09 22:05:00 +08:00
/** @type {{title:string, description:string, illustration:string, actions:Array}} */
emptyConfig: {
title: '暂无进行中的活动',
description: '近期暂无报名中的公益活动,请稍后再来',
illustration: 'activity',
actions: [
{ text: '我的活动', event: 'my', variant: 'secondary' },
],
},
} as ActivityPageData,
2026-09-09 22:05:00 +08:00
onLoad() {
if (!authStore.state.isLoggedIn) return;
(this as any)._unsub = activityStore.bindToPage(this, {
2026-09-09 22:05:00 +08:00
activities: 'activities',
activitiesHasMore: 'activitiesHasMore',
});
this.fetchActivities(true);
},
onShow() {
if (!authStore.state.isLoggedIn) return;
// 从活动详情返回后,若列表为空则刷新(避免详情页报名后列表不同步)
if (this.data.firstLoaded && this.data.activities.length === 0) {
this.fetchActivities(true);
}
},
onUnload() {
if ((this as any)._unsub) (this as any)._unsub();
2026-09-09 22:05:00 +08:00
},
/** 首次或下拉刷新拉取活动列表 */
async fetchActivities(_first = false) {
2026-09-09 22:05:00 +08:00
if (this.data.loading) return;
this.setData({ loading: true });
try {
await activityStore.fetchActivities();
2026-09-14 07:05:20 +08:00
this.applyActivityFilter();
2026-09-09 22:05:00 +08:00
this.setData({
loading: false,
firstLoaded: true,
hasMore: activityStore.state.activitiesHasMore,
});
} catch (err) {
this.setData({ loading: false, firstLoaded: true });
appStore.toastError(err, '加载活动失败');
}
},
/** 加载更多(onReachBottom 触发) */
async loadMore() {
if (this.data.loadingMore || !this.data.hasMore) return;
this.setData({ loadingMore: true });
try {
await activityStore.loadMoreActivities();
2026-09-14 07:05:20 +08:00
this.applyActivityFilter();
2026-09-09 22:05:00 +08:00
this.setData({
loadingMore: false,
hasMore: activityStore.state.activitiesHasMore,
});
} catch (err) {
this.setData({ loadingMore: false });
appStore.toastError(err, '加载更多失败');
}
},
onPullDownRefresh() {
this.fetchActivities(true).then(() => {
wx.stopPullDownRefresh();
});
},
onReachBottom() {
this.loadMore();
},
onCategoryTap(e: WechatMiniprogram.TouchEvent) {
this.setData({ activeCategory: e.currentTarget.dataset.code as string });
2026-09-14 07:05:20 +08:00
this.applyActivityFilter();
},
applyActivityFilter() {
const source = (activityStore.state.activities || []) as ActivityListItem[];
2026-09-14 07:05:20 +08:00
const { activeCategory } = this.data;
this.setData({
activities: activeCategory === 'all'
? source
: source.filter((item) => (item.activityType || item.category) === activeCategory),
});
},
2026-09-09 22:05:00 +08:00
/** 点击活动卡片 → 跳转详情 */
onActivityTap(e: any) {
2026-09-09 22:05:00 +08:00
const activityId = e.detail.activityId;
if (!activityId) return;
wx.navigateTo({ url: to.activityDetail(activityId) });
},
/** 空状态:去我的活动 */
onEmptyAction(e: any) {
2026-09-09 22:05:00 +08:00
const { event } = e.detail;
if (event === 'my') {
wx.navigateTo({ url: '/pages/my-activities/my-activities' });
}
},
/** 顶部"我的活动"入口 */
onMyActivities() {
wx.navigateTo({ url: '/pages/my-activities/my-activities' });
},
});