4 Commits

Author SHA1 Message Date
李瑞
99c8026f61 数据为空时允许展示banner 2026-02-11 23:13:49 +08:00
05966b2acb 优化ntrp和性别picker偶尔选不上值 2026-02-10 18:00:26 +08:00
张成
4cf2b959b5 1 2026-02-10 12:42:42 +08:00
张成
43610dcf99 修复首页数据少的问题 2026-02-10 11:46:39 +08:00
5 changed files with 83 additions and 49 deletions

View File

@@ -52,7 +52,7 @@ const PopupPicker = ({
ntrpTested, ntrpTested,
}: PickerProps) => { }: PickerProps) => {
const [defaultValue, setDefaultValue] = useState<(string | number)[]>([]); const [defaultValue, setDefaultValue] = useState<(string | number)[]>([]);
const [defaultOptions, setDefaultOptions] = useState<PickerOption[][]>([]); const [defaultOptions, setDefaultOptions] = useState<PickerOption[][]>([...options]);
const [pickerCurrentValue, setPickerCurrentValue] = const [pickerCurrentValue, setPickerCurrentValue] =
useState<(string | number)[]>(value); useState<(string | number)[]>(value);

View File

@@ -10,6 +10,7 @@ import {
useUserActions, useUserActions,
useNicknameChangeStatus, useNicknameChangeStatus,
useLastTestResult, useLastTestResult,
useUserInfo,
} from "@/store/userStore"; } from "@/store/userStore";
import { UserInfoType } from "@/services/userService"; import { UserInfoType } from "@/services/userService";
import { import {
@@ -73,7 +74,6 @@ const on_edit = () => {
// 用户信息卡片组件 // 用户信息卡片组件
const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
editable = true, editable = true,
user_info,
is_current_user, is_current_user,
is_following = false, is_following = false,
collapseProfile, collapseProfile,
@@ -84,6 +84,8 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
set_user_info, set_user_info,
onTab, onTab,
}) => { }) => {
const user_info = useUserInfo();
const nickname_change_status = useNicknameChangeStatus(); const nickname_change_status = useNicknameChangeStatus();
const { setShowGuideBar } = useGlobalState(); const { setShowGuideBar } = useGlobalState();
const { updateUserInfo, updateNickname, fetchLastTestResult } = const { updateUserInfo, updateNickname, fetchLastTestResult } =
@@ -122,11 +124,15 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
useState(false); useState(false);
// 表单状态 // 表单状态
const [form_data, set_form_data] = useState<Partial<UserInfoType>>({}); const [form_data, set_form_data] = useState<Partial<UserInfoType>>({ ...user_info });
useDidShow(() => { // useDidShow(() => {
// set_form_data({ ...user_info });
// });
useEffect(() => {
set_form_data({ ...user_info }); set_form_data({ ...user_info });
}); }, [user_info])
useEffect(() => { useEffect(() => {
const visibles = [ const visibles = [
@@ -372,7 +378,6 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
urls: [url], urls: [url],
}); });
}; };
return ( return (
<View className="user_info_card"> <View className="user_info_card">
{/* 头像和基本信息 */} {/* 头像和基本信息 */}
@@ -650,16 +655,16 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
<PopupPicker <PopupPicker
showHeader={true} showHeader={true}
title="选择性别" title="选择性别"
options={[ options={
[ [
{ text: "男", value: "0" }, { text: "男", value: "0" },
{ text: "女", value: "1" }, { text: "女", value: "1" },
{ text: "保密", value: "2" }, { text: "保密", value: "2" },
], ]
]} }
visible={gender_picker_visible} visible={gender_picker_visible}
setvisible={setGenderPickerVisible} setvisible={setGenderPickerVisible}
value={form_data.gender === "" ? ["0"] : [form_data.gender]} value={!form_data.gender ? ["0"] : [form_data.gender]}
onChange={handle_gender_change} onChange={handle_gender_change}
/> />
)} )}
@@ -868,8 +873,7 @@ export const GameTabs: React.FC<GameTabsProps> = ({
<Text className="tab_text">{hosted_text}</Text> <Text className="tab_text">{hosted_text}</Text>
</View> </View>
<View <View
className={`tab_item ${ className={`tab_item ${active_tab === "participated" ? "active" : ""
active_tab === "participated" ? "active" : ""
}`} }`}
onClick={() => on_tab_change("participated")} onClick={() => on_tab_change("participated")}
> >

View File

@@ -132,40 +132,39 @@ const ListContainer = (props) => {
); );
}; };
// 插入 banner 卡片 // showNumber 为 0 表示尚未同步,不参与截断;截断时只限制「数据条数」,插卡不占数据条数
const shouldLimitByShowNumber = showNumber > 0;
// 插入 banner 卡片(在 bannerListIndex 位置插入,不替换数据)
function insertBannerCard(list) { function insertBannerCard(list) {
if (!bannerListImage) return list; if (!bannerListImage) return list;
if (!list || !Array.isArray(list)) return list ?? []; if (!list || !Array.isArray(list)) {
list = [];
}
const idx = Number(bannerListIndex);
return [ return [
...list.slice(0, Number(bannerListIndex)), ...list.slice(0, idx),
{ type: "banner", banner_image_url: bannerListImage, banner_detail_url: bannerDetailImage }, { type: "banner", banner_image_url: bannerListImage, banner_detail_url: bannerDetailImage },
...list.slice(Number(bannerListIndex)) ...list.slice(idx),
]; ];
} }
// 对于没有ntrp等级的用户每个月展示一次, 插在第二个位置后面 // 对于没有 ntrp 等级的用户每个月展示一次插在第 2 条数据后面;插卡是插入不替换,保留全部 showNumber 条数据
// insertBannerCard 需在最后统一执行,否则前面分支直接 return 时 banner 不会被插入
function insertEvaluateCard(list) { function insertEvaluateCard(list) {
let result: any[]; if (!list || !Array.isArray(list)) return insertBannerCard(list ?? []);
if (!evaluateFlag) { const limitedList = shouldLimitByShowNumber ? list.slice(0, showNumber) : list;
result = showNumber !== undefined ? list.slice(0, showNumber) : list;
} else if (!list || list.length === 0) { if (!evaluateFlag || hasTestInLastMonth) {
result = list; return insertBannerCard(limitedList);
} else if (hasTestInLastMonth) {
result = showNumber !== undefined ? list.slice(0, showNumber) : list;
} else if (list.length <= 2) {
result = [...list, { type: "evaluateCard" }];
} else {
const [item1, item2, ...rest] = list;
result = [
item1,
item2,
{ type: "evaluateCard" },
...(showNumber !== undefined ? rest.slice(0, showNumber - 3) : rest),
];
} }
if (limitedList.length <= 2) {
return insertBannerCard([...limitedList, { type: "evaluateCard" }]);
}
const [item1, item2, ...rest] = limitedList;
const result = [item1, item2, { type: "evaluateCard" }, ...rest];
return insertBannerCard(result); return insertBannerCard(result);
} }
@@ -204,10 +203,12 @@ const ListContainer = (props) => {
); );
}; };
const showNoData = isShowNoData && !loading && memoizedList?.length === 0;
// 渲染列表 // 渲染列表
const renderList = () => { const renderList = () => {
// 请求数据为空 // 请求数据为空
if (isShowNoData) { if (showNoData) {
return ( return (
<ListLoadError <ListLoadError
reload={reload} reload={reload}

View File

@@ -1,6 +1,7 @@
export default definePageConfig({ export default definePageConfig({
navigationBarTitleText: '首页', navigationBarTitleText: '首页',
navigationStyle: 'custom', navigationStyle: 'custom',
navigationBarBackgroundColor: '#FAFAFA' navigationBarBackgroundColor: '#FAFAFA',
}) enableShareAppMessage: true,
})

View File

@@ -1,6 +1,7 @@
import React, { useState, useEffect, useCallback } from "react"; import React, { useState, useEffect, useCallback } from "react";
import { View } from "@tarojs/components"; import { View } from "@tarojs/components";
import Taro from "@tarojs/taro"; import Taro, { useRouter, useShareAppMessage } from "@tarojs/taro";
import { OSS_BASE } from "@/config/api";
import { wechat_auth_login, save_login_state } from "@/services/loginService"; import { wechat_auth_login, save_login_state } from "@/services/loginService";
import { useUserActions } from "@/store/userStore"; import { useUserActions } from "@/store/userStore";
import { useGlobalState } from "@/store/global"; import { useGlobalState } from "@/store/global";
@@ -18,7 +19,11 @@ import { useDictionaryStore } from "@/store/dictionaryStore";
type TabType = "list" | "message" | "personal"; type TabType = "list" | "message" | "personal";
const MainPage: React.FC = () => { const MainPage: React.FC = () => {
const [currentTab, setCurrentTab] = useState<TabType>("list"); const { params } = useRouter();
const [currentTab, setCurrentTab] = useState<TabType>(() => {
const tab = params?.tab as TabType | undefined;
return tab === "list" || tab === "message" || tab === "personal" ? tab : "list";
});
const [isPublishMenuVisible, setIsPublishMenuVisible] = useState(false); const [isPublishMenuVisible, setIsPublishMenuVisible] = useState(false);
const [isDistanceFilterVisible, setIsDistanceFilterVisible] = useState(false); const [isDistanceFilterVisible, setIsDistanceFilterVisible] = useState(false);
const [isCityPickerVisible, setIsCityPickerVisible] = useState(false); const [isCityPickerVisible, setIsCityPickerVisible] = useState(false);
@@ -35,6 +40,14 @@ const MainPage: React.FC = () => {
const { showGuideBar, guideBarZIndex, setShowGuideBar, setGuideBarZIndex } = const { showGuideBar, guideBarZIndex, setShowGuideBar, setGuideBarZIndex } =
useGlobalState(); useGlobalState();
// 从分享链接进入时根据 ?tab= 定位到对应 tab
useEffect(() => {
const tab = params?.tab as TabType | undefined;
if (tab === "list" || tab === "message" || tab === "personal") {
setCurrentTab(tab);
}
}, [params?.tab]);
// 初始化:自动微信授权并获取用户信息 // 初始化:自动微信授权并获取用户信息
useEffect(() => { useEffect(() => {
const init = async () => { const init = async () => {
@@ -153,6 +166,21 @@ const MainPage: React.FC = () => {
[] []
); );
// 分享:首页、个人页均支持转发
// 分享图:配置 OSS 地址 + 路径(不含 ? 后参数),首页用 share_home.png个人页用 share_self.png
useShareAppMessage(() => {
const isList = currentTab === "list";
const isPersonal = currentTab === "personal";
const title = isList ? "约球 - 发现身边的球局" : isPersonal ? "约球 - 我的约球" : "约球";
const image_path = isPersonal ? "system/share_self.png" : "system/share_home.png";
const imageUrl = OSS_BASE ? `${OSS_BASE.replace(/\/$/, "")}/${image_path}` : "";
return {
title,
path: "/main_pages/index" + (isList ? "?tab=list" : isPersonal ? "?tab=personal" : ""),
imageUrl: imageUrl,
};
});
// 滚动到顶部 // 滚动到顶部
const scrollToTop = useCallback(() => { const scrollToTop = useCallback(() => {
// 如果当前是列表页,触发列表页内部滚动 // 如果当前是列表页,触发列表页内部滚动