From 969066591c1952f68497b6a333dcabee4863da46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Thu, 5 Feb 2026 23:23:21 +0800 Subject: [PATCH 01/11] 1 --- .../DistanceQuickFilterV2/index.scss | 4 + .../DistanceQuickFilterV2/index.tsx | 78 ++++++++++++++++++- src/components/PublishMenu/PublishMenu.tsx | 2 +- src/components/SearchBar/index.tsx | 2 +- src/config/images.js | 1 + src/game_pages/search/index.tsx | 2 +- src/game_pages/sharePoster/index.tsx | 1 + src/main_pages/components/ListPageContent.tsx | 14 +++- src/services/userService.ts | 6 +- src/static/list/icon-relocate.svg | 10 +++ src/store/listStore.ts | 8 +- src/store/userStore.ts | 35 ++++++--- 12 files changed, 137 insertions(+), 26 deletions(-) create mode 100644 src/static/list/icon-relocate.svg diff --git a/src/components/DistanceQuickFilterV2/index.scss b/src/components/DistanceQuickFilterV2/index.scss index eb926ee..e6342fb 100644 --- a/src/components/DistanceQuickFilterV2/index.scss +++ b/src/components/DistanceQuickFilterV2/index.scss @@ -85,6 +85,10 @@ font-size: 13px; font-weight: 400; color: #3c3c43; + display: flex; + flex-direction: row; + align-items: center; + gap:4px; } .distanceWrap { diff --git a/src/components/DistanceQuickFilterV2/index.tsx b/src/components/DistanceQuickFilterV2/index.tsx index 3411faf..2989a64 100644 --- a/src/components/DistanceQuickFilterV2/index.tsx +++ b/src/components/DistanceQuickFilterV2/index.tsx @@ -1,9 +1,14 @@ import { useRef, useState, useEffect } from "react"; import { Menu } from "@nutui/nutui-react-taro"; import { Image, View, ScrollView } from "@tarojs/components"; +import Taro from "@tarojs/taro"; import img from "@/config/images"; import Bubble from "../Bubble"; -import { useListState } from "@/store/listStore"; +import { useListState, useListStore } from "@/store/listStore"; +import { getCurrentLocation } from "@/utils/locationUtils"; +import { updateUserLocation } from "@/services/userService"; +import { useGlobalState } from "@/store/global"; +import { useUserActions } from "@/store/userStore"; import "./index.scss"; const DistanceQuickFilterV2 = (props) => { @@ -19,15 +24,19 @@ const DistanceQuickFilterV2 = (props) => { quickValue, districtValue, // 新增:行政区选中值 onMenuVisibleChange, // 菜单展开/收起回调 + onRelocate, // 重新定位回调 } = props; const cityRef = useRef(null); const quickRef = useRef(null); const [changePosition, setChangePosition] = useState([]); const [isMenuOpen, setIsMenuOpen] = useState(false); - const [keys, setKeys] = useState(0); + const [keys, setKeys] = useState(0); + const [isRelocating, setIsRelocating] = useState(false); // 从 store 获取当前城市信息 const { area } = useListState(); const currentCity = area?.at(-1) || ""; // 获取省份/城市名称 + const { updateState } = useGlobalState() || {}; + const { fetchUserInfo, updateCache } = useUserActions(); // 全城筛选显示的标题 - 如果选择了行政区,显示行政区名称 const getCityTitle = () => { @@ -79,6 +88,64 @@ const DistanceQuickFilterV2 = (props) => { index === 1 && (quickRef.current as any)?.toggle(false); }; + + // 重新获取当前位置,调用接口把位置传递后端 + const handleRelocate = async () => { + if (isRelocating) return; + + setIsRelocating(true); + (Taro as any).showLoading({ title: '定位中...', mask: true }); + + try { + // 获取当前位置 + const location = await getCurrentLocation(); + + if (location && location.latitude && location.longitude) { + // 更新 store 中的位置信息 + updateState?.({ location }); + + // 调用接口把位置传递给后端,传递一个值代表强制更新 + const response = await updateUserLocation(location.latitude, location.longitude, true); + + // 如果接口返回成功,重新调用用户信息接口来更新 USER_SELECTED_CITY + if (response?.code === 0) { + + // 删除 缓存 + (Taro as any).removeStorageSync("USER_SELECTED_CITY"); + + // 延时一下 + await new Promise(resolve => setTimeout(resolve, 600)); + // 先清除缓存和 area,确保使用最新的用户信息 + await updateCache( ["中国", response.data.last_location_province]); + + } + + (Taro as any).showToast({ + title: '定位成功', + icon: 'success', + duration: 1500, + }); + + // 通知父组件位置已更新,可以刷新列表 + if (onRelocate) { + onRelocate(location); + } + } else { + throw new Error('获取位置信息失败'); + } + } catch (error: any) { + console.error('重新定位失败:', error); + (Taro as any).showToast({ + title: error?.message || '定位失败,请检查定位权限', + icon: 'none', + duration: 2000, + }); + } finally { + setIsRelocating(false); + (Taro as any).hideLoading(); + } + }; + // 监听菜单状态变化,通知父组件 useEffect(() => { onMenuVisibleChange?.(isMenuOpen); @@ -103,8 +170,11 @@ const DistanceQuickFilterV2 = (props) => { icon={} >
-

当前位置

-

{currentCity}

+

{currentCity}

+

+ + 重新定位 +

= (props) => { }; const handleMenuItemClick = (type: "individual" | "group" | "ai") => { const [_, address] = area; - if (address !== '上海') { + if (address !== '上海市') { (Taro as any).showModal({ title: '提示', content: '仅上海地区开放,您可加入社群或切换城市', diff --git a/src/components/SearchBar/index.tsx b/src/components/SearchBar/index.tsx index f18e8f7..a77974c 100644 --- a/src/components/SearchBar/index.tsx +++ b/src/components/SearchBar/index.tsx @@ -45,7 +45,7 @@ const SearchBarComponent = (props: IProps) => { } className={styles.searchBar} - placeholder="搜索上海的球局和场地" + placeholder="搜索球局和场地" onChange={handleChange} value={value} onInputClick={onInputClick} diff --git a/src/config/images.js b/src/config/images.js index 57e03c6..62eaddb 100644 --- a/src/config/images.js +++ b/src/config/images.js @@ -70,4 +70,5 @@ export default { ICON_LIST_NTPR: require('@/static/list/ntpr.svg'), ICON_LIST_CHANGDA: require('@/static/list/icon-changda.svg'), ICON_LIST_CHANGDA_QIuju: require('@/static/list/changdaqiuju.png'), + ICON_RELOCATE: require('@/static/list/icon-relocate.svg'), } diff --git a/src/game_pages/search/index.tsx b/src/game_pages/search/index.tsx index 6668a8a..f4a3022 100644 --- a/src/game_pages/search/index.tsx +++ b/src/game_pages/search/index.tsx @@ -131,7 +131,7 @@ const ListSearch = () => { = ({ }); }; + // 处理重新定位 + const handleRelocate = async (location) => { + try { + // 位置已更新到后端,刷新列表数据 + await getMatchesData(); + await fetchGetGamesCount(); + } catch (error) { + console.error("刷新列表失败:", error); + } + }; + const handleSearchClick = () => { navigateTo({ url: "/game_pages/search/index", @@ -508,7 +519,7 @@ const ListPageContent: React.FC = ({ // 判定是否显示"暂无球局"页面 // 条件:省份不是上海 或 (已加载完成且球局数量为0) - const shouldShowNoGames = province !== "上海"; + const shouldShowNoGames = province !== "上海市"; return ( <> @@ -559,6 +570,7 @@ const ListPageContent: React.FC = ({ quickValue={distanceQuickFilter?.order} districtValue={distanceQuickFilter?.district} onMenuVisibleChange={handleDistanceFilterVisibleChange} + onRelocate={handleRelocate} /> diff --git a/src/services/userService.ts b/src/services/userService.ts index 2309e80..e1bc150 100644 --- a/src/services/userService.ts +++ b/src/services/userService.ts @@ -2,7 +2,7 @@ import { UserInfo } from "@/components/UserInfo"; import { API_CONFIG } from "@/config/api"; import httpService, { ApiResponse } from "./httpService"; import uploadFiles from "./uploadFiles"; -import Taro from "@tarojs/taro"; +import * as Taro from "@tarojs/taro"; import getCurrentConfig from "@/config/env"; import { clear_login_state } from "@/services/loginService"; @@ -740,12 +740,14 @@ export const updateUserProfile = async (payload: Partial) => { // 更新用户坐标位置 export const updateUserLocation = async ( latitude: number, - longitude: number + longitude: number, + force: boolean = false ) => { try { const response = await httpService.post("/user/update_location", { latitude, longitude, + force }); return response; } catch (error) { diff --git a/src/static/list/icon-relocate.svg b/src/static/list/icon-relocate.svg new file mode 100644 index 0000000..8100302 --- /dev/null +++ b/src/static/list/icon-relocate.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/store/listStore.ts b/src/store/listStore.ts index 128589e..a09c7d5 100644 --- a/src/store/listStore.ts +++ b/src/store/listStore.ts @@ -731,16 +731,16 @@ export const useListStore = create()((set, get) => ({ const state = get(); // 从 area 中获取省份,area 格式: ["中国", 省份, 城市] const country = "中国"; - const province = state.area?.at(1) || "上海"; // area[1] 是省份 - + const cn_city = state.area?.at(1) || "上海市"; // area[1] 是省份 + const res = await getDistricts({ country, - state: province + state: cn_city }); if (res.code === 0 && res.data) { const districts = res.data.map((item) => ({ - label: item.cn_city, + label: item.cn_county, value: item.id.toString(), id: item.id, })); diff --git a/src/store/userStore.ts b/src/store/userStore.ts index 1b35edd..f1d4550 100644 --- a/src/store/userStore.ts +++ b/src/store/userStore.ts @@ -36,6 +36,7 @@ const getTimeNextDate = (time: string) => { // 请求锁,避免重复调用 let isFetchingLastTestResult = false; let isCheckingNicknameStatus = false; +const CITY_CACHE_KEY = "USER_SELECTED_CITY"; export const useUser = create()((set) => ({ user: {}, @@ -44,41 +45,50 @@ export const useUser = create()((set) => ({ const res = await fetchUserProfile(); const userData = res.data; set({ user: userData }); - + // 优先使用缓存中的城市,不使用用户信息中的位置 // 检查是否有缓存的城市 - const CITY_CACHE_KEY = "USER_SELECTED_CITY"; + const cachedCity = (Taro as any).getStorageSync?.(CITY_CACHE_KEY); - + + + if (cachedCity && Array.isArray(cachedCity) && cachedCity.length === 2) { // 如果有缓存的城市,使用缓存,不更新 area console.log("[userStore] 检测到缓存的城市,使用缓存,不更新 area"); return userData; } - + // 只有当没有缓存时,才使用用户信息中的位置 if (userData?.last_location_province) { const listStore = useListStore.getState(); const currentArea = listStore.area; + // 只有当 area 不存在时才使用用户信息中的位置 if (!currentArea) { const newArea: [string, string] = ["中国", userData.last_location_province]; listStore.updateArea(newArea); // 保存到缓存 - try { - (Taro as any).setStorageSync?.(CITY_CACHE_KEY, newArea); - } catch (error) { - console.error("保存城市缓存失败:", error); - } + useUser.getState().updateCache(newArea); } } - + return userData; } catch (error) { console.error("获取用户信息失败:", error); return undefined; } }, + + // 更新缓存 + updateCache: async (newArea: [string, string]) => { + try { + (Taro as any).setStorageSync?.(CITY_CACHE_KEY, newArea); + } catch (error) { + console.error("保存城市缓存失败:", error); + } + }, + updateUserInfo: async (userInfo: Partial) => { try { // 先更新后端 @@ -86,7 +96,7 @@ export const useUser = create()((set) => ({ // 然后立即更新本地状态(乐观更新) set((state) => { const newUser = { ...state.user, ...userInfo }; - + // 当 userLastLocationProvince 更新时,同步更新 area if (userInfo.last_location_province) { const listStore = useListStore.getState(); @@ -97,7 +107,7 @@ export const useUser = create()((set) => ({ listStore.updateArea(newArea); } } - + return { user: newUser }; }); // 不再每次都重新获取完整用户信息,减少请求次数 @@ -195,6 +205,7 @@ export const useNicknameChangeStatus = () => export const useUserActions = () => useUser((state) => ({ fetchUserInfo: state.fetchUserInfo, + updateCache: state.updateCache, updateUserInfo: state.updateUserInfo, checkNicknameChangeStatus: state.checkNicknameChangeStatus, updateNickname: state.updateNickname, From d149de1f421de412380eb81bab2e7cccee9cbd77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Fri, 6 Feb 2026 00:26:31 +0800 Subject: [PATCH 02/11] 1 --- README.md | 6 +- project.config.json | 3 +- .../DistanceQuickFilterV2/index.tsx | 2 +- src/components/HomeNavbar/index.tsx | 51 ++++++++------- src/main_pages/components/ListPageContent.tsx | 19 ++++-- src/services/listApi.ts | 2 +- src/store/dictionaryStore.ts | 7 +- src/store/listStore.ts | 64 +++++++++---------- src/store/userStore.ts | 10 +-- 9 files changed, 91 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index f6aa878..e8e5643 100644 --- a/README.md +++ b/README.md @@ -148,4 +148,8 @@ src/ ## License -MIT \ No newline at end of file +MIT + +"appid": "wx915ecf6c01bea4ec", + + "appid": "wx815b533167eb7b53", \ No newline at end of file diff --git a/project.config.json b/project.config.json index fcd025f..3812516 100644 --- a/project.config.json +++ b/project.config.json @@ -2,7 +2,8 @@ "miniprogramRoot": "dist/", "projectname": "playBallTogether", "description": "playBallTogether", - "appid": "wx915ecf6c01bea4ec", + "appid": "wx815b533167eb7b53", + "setting": { "urlCheck": true, "es6": true, diff --git a/src/components/DistanceQuickFilterV2/index.tsx b/src/components/DistanceQuickFilterV2/index.tsx index 2989a64..c6aa7a0 100644 --- a/src/components/DistanceQuickFilterV2/index.tsx +++ b/src/components/DistanceQuickFilterV2/index.tsx @@ -116,7 +116,7 @@ const DistanceQuickFilterV2 = (props) => { // 延时一下 await new Promise(resolve => setTimeout(resolve, 600)); // 先清除缓存和 area,确保使用最新的用户信息 - await updateCache( ["中国", response.data.last_location_province]); + await updateCache( [ response.data.last_location_province, response.data.last_location_city ]); } diff --git a/src/components/HomeNavbar/index.tsx b/src/components/HomeNavbar/index.tsx index 019eea6..361369b 100644 --- a/src/components/HomeNavbar/index.tsx +++ b/src/components/HomeNavbar/index.tsx @@ -105,15 +105,15 @@ const HomeNavbar = (props: IProps) => { const userInfo = useUserInfo(); // 使用用户详情接口中的 last_location 字段 // USER_SELECTED_CITY 第二个值应该是省份/直辖市,不能是区 - const lastLocationProvince = (userInfo as any)?.last_location_province || ""; + const lastLocationCity = (userInfo as any)?.last_location_city || ""; // 只使用省份/直辖市,不使用城市(城市可能是区) - const detectedLocation = lastLocationProvince; + const detectedLocation = lastLocationCity; // 检查是否应该显示定位确认弹窗 const should_show_location_dialog = (): boolean => { try { const current_time = Date.now(); - + // 检查是否在2小时内切换过城市 const city_change_time = (Taro as any).getStorageSync(CITY_CHANGE_TIME_KEY); if (city_change_time) { @@ -127,13 +127,13 @@ const HomeNavbar = (props: IProps) => { (Taro as any).removeStorageSync(CITY_CHANGE_TIME_KEY); } } - + // 检查是否在2小时内已选择"继续浏览" const dismiss_time = (Taro as any).getStorageSync(LOCATION_DIALOG_DISMISS_TIME_KEY); if (!dismiss_time) { return true; // 没有记录,可以显示 } - + const time_diff = current_time - dismiss_time; // 如果距离上次选择"继续浏览"已超过2小时,可以再次显示 if (time_diff >= TWO_HOURS_MS) { @@ -141,7 +141,7 @@ const HomeNavbar = (props: IProps) => { (Taro as any).removeStorageSync(LOCATION_DIALOG_DISMISS_TIME_KEY); return true; } - + // 在2小时内,不显示弹窗 console.log(`[HomeNavbar] 距离上次选择"继续浏览"还不到2小时,剩余时间: ${Math.ceil((TWO_HOURS_MS - time_diff) / 1000 / 60)}分钟`); return false; @@ -158,7 +158,7 @@ const HomeNavbar = (props: IProps) => { console.log('[HomeNavbar] 用户在2小时内已选择"继续浏览"或切换过城市,不显示弹窗'); return; } - + console.log('[HomeNavbar] 准备显示定位确认弹窗,隐藏 GuideBar'); setLocationDialogData({ detectedProvince: detectedLocation, cachedCity }); setLocationDialogVisible(true); @@ -172,13 +172,13 @@ const HomeNavbar = (props: IProps) => { useEffect(() => { // 1. 优先尝试从缓存中读取上次的定位信息 const cachedCity = (Taro as any).getStorageSync(CITY_CACHE_KEY); - + if (cachedCity && Array.isArray(cachedCity) && cachedCity.length === 2) { // 如果有缓存的定位信息,使用缓存 const cachedCityArray = cachedCity as [string, string]; console.log("[HomeNavbar] 使用缓存的定位城市:", cachedCityArray); updateArea(cachedCityArray); - + // 如果用户详情中有位置信息,且与缓存不一致,检查是否需要弹窗 if (detectedLocation && cachedCityArray[1] !== detectedLocation) { // 检查时间缓存,如果没有或过期,则弹出选择框 @@ -192,7 +192,7 @@ const HomeNavbar = (props: IProps) => { } else if (detectedLocation) { // 只有在完全没有缓存的情况下,才使用用户详情中的位置信息 console.log("[HomeNavbar] 没有缓存,使用用户详情中的位置信息:", detectedLocation); - const newArea: [string, string] = ["中国", detectedLocation]; + const newArea: [string, string] = [(userInfo as any)?.last_location_province || "", detectedLocation]; updateArea(newArea); // 保存定位信息到缓存 (Taro as any).setStorageSync(CITY_CACHE_KEY, newArea); @@ -263,10 +263,10 @@ const HomeNavbar = (props: IProps) => { // 处理定位弹窗确认 const handleLocationDialogConfirm = () => { if (!locationDialogData) return; - + const { detectedProvince } = locationDialogData; // 用户选择"切换到",使用用户详情中的位置信息 - const newArea: [string, string] = ["中国", detectedProvince]; + const newArea: [string, string] = [(userInfo as any)?.last_location_province || "", detectedProvince]; updateArea(newArea); // 更新缓存为新的定位信息 (Taro as any).setStorageSync(CITY_CACHE_KEY, newArea); @@ -279,13 +279,13 @@ const HomeNavbar = (props: IProps) => { console.error('保存城市切换时间失败:', error); } console.log("切换到用户详情中的位置信息并更新缓存:", detectedProvince); - + // 关闭弹窗 setLocationDialogVisible(false); setLocationDialogData(null); // 关闭弹窗时显示 GuideBar setShowGuideBar(true); - + // 刷新数据 handleCityChangeWithoutCache(); }; @@ -293,11 +293,11 @@ const HomeNavbar = (props: IProps) => { // 处理定位弹窗取消(用户选择"继续浏览") const handleLocationDialogCancel = () => { if (!locationDialogData) return; - + const { cachedCity } = locationDialogData; // 用户选择"继续浏览",保持缓存的定位城市 console.log("保持缓存的定位城市:", cachedCity[1]); - + // 记录用户选择"继续浏览"的时间戳,2小时内不再提示 try { const current_time = Date.now(); @@ -306,7 +306,7 @@ const HomeNavbar = (props: IProps) => { } catch (error) { console.error('保存定位弹窗关闭时间失败:', error); } - + // 关闭弹窗 setLocationDialogVisible(false); setLocationDialogData(null); @@ -321,7 +321,7 @@ const HomeNavbar = (props: IProps) => { if (cityPopupVisible) { setCityPopupVisible(false); } - + const currentPagePath = getCurrentFullPath(); if (currentPagePath === "/game_pages/searchResult/index") { (Taro as any).navigateBack(); @@ -338,7 +338,7 @@ const HomeNavbar = (props: IProps) => { if (cityPopupVisible) { setCityPopupVisible(false); } - + // 如果当前在列表页,点击后页面回到顶部 if (getCurrentFullPath() === "/main_pages/index") { // 使用父组件传递的滚动方法(适配 ScrollView) @@ -363,7 +363,7 @@ const HomeNavbar = (props: IProps) => { if (cityPopupVisible) { setCityPopupVisible(false); } - + if (leftIconClick) { leftIconClick(); } else { @@ -397,10 +397,10 @@ const HomeNavbar = (props: IProps) => { const handleCityChange = async (_newArea: any) => { // 用户手动选择的城市保存到缓存 console.log("用户手动选择城市,更新缓存:", _newArea); - + // 先更新 area 状态(用于界面显示和接口参数) updateArea(_newArea); - + // 保存城市到缓存 try { (Taro as any).setStorageSync(CITY_CACHE_KEY, _newArea); @@ -411,7 +411,7 @@ const HomeNavbar = (props: IProps) => { } catch (error) { console.error("保存城市缓存失败:", error); } - + // 先调用列表接口(会使用更新后的 state.area) if (refreshBothLists) { await refreshBothLists(); @@ -481,9 +481,8 @@ const HomeNavbar = (props: IProps) => { {/* 搜索导航 */} {!showTitle && ( - 手机号验证码登录 + 手机号快捷登录 {/* 用户协议复选框 */} diff --git a/src/login_pages/terms/README.md b/src/login_pages/terms/README.md index 298b20c..30ba148 100644 --- a/src/login_pages/terms/README.md +++ b/src/login_pages/terms/README.md @@ -1,8 +1,8 @@ -# 条款页面 - 开场的条款和条件 +# 条款页面 - 有场的条款和条件 ## 功能概述 -条款页面展示完整的《开场的条款和条件》内容,用户需要仔细阅读并同意后才能继续使用平台服务。 +条款页面展示完整的《有场的条款和条件》内容,用户需要仔细阅读并同意后才能继续使用平台服务。 ## 🎨 设计特点 @@ -54,7 +54,7 @@ TermsPage ## 📋 条款内容 -本页面包含完整的《开场的条款和条件》,涵盖以下十个主要部分: +本页面包含完整的《有场的条款和条件》,涵盖以下十个主要部分: ### 1. 服务内容 - 活动发布、报名、聊天室沟通、活动提醒等服务 diff --git a/src/login_pages/terms/index.tsx b/src/login_pages/terms/index.tsx index 01f9634..928263c 100644 --- a/src/login_pages/terms/index.tsx +++ b/src/login_pages/terms/index.tsx @@ -7,7 +7,7 @@ const TermsPage: React.FC = () => { // 获取页面参数 const [termsType, setTermsType] = React.useState('terms'); const [pageTitle, setPageTitle] = React.useState('条款和条件'); - const [termsTitle, setTermsTitle] = React.useState('《开场的条款和条件》'); + const [termsTitle, setTermsTitle] = React.useState('《有场的条款和条件》'); const [termsContent, setTermsContent] = React.useState(''); // 返回上一页 @@ -23,7 +23,7 @@ const TermsPage: React.FC = () => { switch (type) { case 'terms': setPageTitle('条款和条件'); - setTermsTitle('《开场的条款和条件》'); + setTermsTitle('《有场的条款和条件》'); setTermsContent(`欢迎使用本平台(以下简称"本平台")发布与参与网球活动。为保障您的权益,请您务必仔细阅读并理解以下服务条款。 一、服务内容 @@ -69,7 +69,7 @@ const TermsPage: React.FC = () => { break; case 'binding': setPageTitle('微信号绑定协议'); - setTermsTitle('《开场与微信号绑定协议》'); + setTermsTitle('《有场与微信号绑定协议》'); setTermsContent(`欢迎使用本平台(以下简称"本平台")的微信绑定服务。为保障您的权益,请您务必仔细阅读并理解以下协议内容。 一、绑定服务说明 @@ -171,7 +171,7 @@ const TermsPage: React.FC = () => { break; default: setPageTitle('条款和条件'); - setTermsTitle('《开场的条款和条件》'); + setTermsTitle('《有场的条款和条件》'); setTermsContent('条款内容加载中...'); } }, []); diff --git a/src/login_pages/verification/README.md b/src/login_pages/verification/README.md index 24d9dd6..69cd099 100644 --- a/src/login_pages/verification/README.md +++ b/src/login_pages/verification/README.md @@ -64,7 +64,7 @@ VerificationPage - **页面跳转**:登录成功后跳转到首页 ### 协议支持 -- **条款链接**:《开场的条款和条件》 +- **条款链接**:《有场的条款和条件》 - **隐私政策**:《隐私权政策》 - **动态跳转**:支持通过 URL 参数指定协议类型 From ce0a299b59cd2f9abbdea6049271f6b0500b1a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Fri, 6 Feb 2026 10:38:24 +0800 Subject: [PATCH 05/11] 1 --- src/login_pages/index/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/login_pages/index/index.tsx b/src/login_pages/index/index.tsx index ce37fce..c0d653e 100644 --- a/src/login_pages/index/index.tsx +++ b/src/login_pages/index/index.tsx @@ -224,13 +224,13 @@ const LoginPage: React.FC = () => { className="terms_link" onClick={() => handle_view_terms("terms")} > - 《开场的条款和条件》 + 《有场的条款和条件》 handle_view_terms("binding")} > - 《开场与微信号绑定协议》 + 《有场与微信号绑定协议》 { className="terms_item" onClick={() => handle_view_terms("terms")} > - 《开场的条款和条件》 + 《有场的条款和条件》 handle_view_terms("binding")} > - 《开场与微信号绑定协议》 + 《有场与微信号绑定协议》 Date: Fri, 6 Feb 2026 17:58:38 +0800 Subject: [PATCH 06/11] 1 --- package.json | 1 + project.private.config.json | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f5238d4..5143872 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "@tarojs/shared": "4.1.5", "@tarojs/taro": "4.1.5", "babel-plugin-transform-remove-console": "^6.9.4", + "classnames": "^2.5.1", "dayjs": "^1.11.13", "qweather-icons": "^1.8.0", "react": "^18.0.0", diff --git a/project.private.config.json b/project.private.config.json index 0602fbc..ac01ff4 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -15,9 +15,10 @@ "useStaticServer": false, "useLanDebug": false, "showES6CompileOption": false, - "compileHotReLoad": false, + "compileHotReLoad": true, "checkInvalidKey": true, "ignoreDevUnusedFiles": true, - "bigPackageSizeSupport": true + "bigPackageSizeSupport": true, + "useIsolateContext": true } } \ No newline at end of file From 8d729a0132fb9e9d23526b4d1855789fda2e6722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Sat, 7 Feb 2026 00:51:30 +0800 Subject: [PATCH 07/11] 1 --- src/container/listContainer/index.tsx | 25 +++++++------------ src/login_pages/index/index.tsx | 2 +- src/main_pages/components/ListPageContent.tsx | 10 +++++--- src/main_pages/index.scss | 10 +++----- src/other_pages/bannerDetail/index.scss | 10 +++++--- .../enable_notification/index.scss | 3 +-- 6 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/container/listContainer/index.tsx b/src/container/listContainer/index.tsx index a75bf0e..fb1cb72 100644 --- a/src/container/listContainer/index.tsx +++ b/src/container/listContainer/index.tsx @@ -161,29 +161,22 @@ const ListContainer = (props) => { // 渲染 banner 卡片 const renderBanner = (item, index) => { - if (!item?.banner_image_url) return null; + if (!item?.banner_image_url) { + return null; + } return ( - { - const target = item.banner_detail_url; - if (target) { - (Taro as any).navigateTo({ - url: `/other_pages/bannerDetail/index?img=${encodeURIComponent(target)}`, - }); - } - }} - /> ); }; @@ -216,7 +209,7 @@ const ListContainer = (props) => { } if (match.type === "evaluateCard") { return ( - + ); } return ; diff --git a/src/login_pages/index/index.tsx b/src/login_pages/index/index.tsx index c0d653e..ef2eda6 100644 --- a/src/login_pages/index/index.tsx +++ b/src/login_pages/index/index.tsx @@ -193,7 +193,7 @@ const LoginPage: React.FC = () => { /> - {is_loading ? "登录中..." : "授权登录"} + {is_loading ? "登录中..." : "一键登录"} diff --git a/src/main_pages/components/ListPageContent.tsx b/src/main_pages/components/ListPageContent.tsx index b35ff52..8bf6a79 100644 --- a/src/main_pages/components/ListPageContent.tsx +++ b/src/main_pages/components/ListPageContent.tsx @@ -293,9 +293,9 @@ const ListPageContent: React.FC = ({ currentProvince, }); - // 地址发生变化或不一致,重新加载数据和球局数量 - // 先调用列表接口,然后在列表接口完成后调用数量接口 - (async () => { + // 延迟刷新,等 tab 切换动画完成后再加载,避免切换时列表重渲染导致抖动 + const delayMs = 280; + const timer = setTimeout(async () => { try { if (refreshBothLists) { await refreshBothLists(); @@ -311,7 +311,9 @@ const ListPageContent: React.FC = ({ } catch (error) { console.error("重新加载数据失败:", error); } - })(); + }, delayMs); + prevIsActiveRef.current = isActive; + return () => clearTimeout(timer); } } diff --git a/src/main_pages/index.scss b/src/main_pages/index.scss index 2e8d1a1..dc19c1e 100644 --- a/src/main_pages/index.scss +++ b/src/main_pages/index.scss @@ -21,21 +21,17 @@ top: 0; left: 0; opacity: 0; - transform: scale(0.98); - transition: opacity 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94), - transform 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94); + transition: opacity 0.25s ease-out; overflow-y: auto; -webkit-overflow-scrolling: touch; pointer-events: none; - will-change: opacity, transform; - backface-visibility: hidden; - -webkit-backface-visibility: hidden; + visibility: hidden; &.active { opacity: 1; - transform: scale(1); z-index: 1; pointer-events: auto; + visibility: visible; } } diff --git a/src/other_pages/bannerDetail/index.scss b/src/other_pages/bannerDetail/index.scss index e29887d..79a4b85 100644 --- a/src/other_pages/bannerDetail/index.scss +++ b/src/other_pages/bannerDetail/index.scss @@ -1,16 +1,20 @@ .banner_detail_page { min-height: 100vh; background: #ffffff; + display: flex; + flex-direction: column; } .banner_detail_content { padding: 12px; + display: flex; + align-items: center; + justify-content: center; + flex: 1; } .banner_detail_image { width: 100%; border-radius: 12px; display: block; -} - - +} \ No newline at end of file diff --git a/src/other_pages/enable_notification/index.scss b/src/other_pages/enable_notification/index.scss index 4eada00..b18b4dc 100644 --- a/src/other_pages/enable_notification/index.scss +++ b/src/other_pages/enable_notification/index.scss @@ -10,7 +10,7 @@ display: flex; flex-direction: column; align-items: center; - height: calc(100vh - 98px); + flex: 1; position: relative; overflow: hidden; } @@ -163,7 +163,6 @@ &__qr_image { width: 100%; - height: 100%; } &__qr_placeholder { From 9dca489aba74435668eb3f5dcf3d914e59edf7ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=91=9E?= Date: Sat, 7 Feb 2026 00:53:40 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E5=A4=84=E7=90=86banner=E6=8F=92?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/container/listContainer/index.tsx | 35 ++++++++++++++++++--------- src/store/listStore.ts | 29 ++-------------------- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/container/listContainer/index.tsx b/src/container/listContainer/index.tsx index a75bf0e..a2c62de 100644 --- a/src/container/listContainer/index.tsx +++ b/src/container/listContainer/index.tsx @@ -10,6 +10,7 @@ import { EvaluateScene } from "@/store/evaluateStore"; import { waitForAuthInit } from "@/utils/authInit"; import "./index.scss"; import { useRef, useEffect, useState, useMemo } from "react"; +import { useDictionaryStore } from "@/store/dictionaryStore"; const ListContainer = (props) => { const { @@ -44,7 +45,7 @@ const ListContainer = (props) => { const { fetchUserInfo, fetchLastTestResult } = useUserActions(); // 使用全局状态中的测试结果,避免重复调用接口 const lastTestResult = useLastTestResult(); - + const { bannerListImage, bannerDetailImage, bannerListIndex = 0 } = useDictionaryStore((s) => s.bannerDict) || {}; useReachBottom(() => { // 加载更多方法 if (loading) { @@ -130,6 +131,16 @@ const ListContainer = (props) => { ); }; + // 插入 banner 卡片 + function insertBannerCard(list) { + if (!bannerListImage) return list; + return [ + ...list.slice(0, Number(bannerListIndex)), + { type: "banner", banner_image_url: bannerListImage, banner_detail_url: bannerDetailImage }, + ...list.slice(Number(bannerListIndex)) + ]; + } + // 对于没有ntrp等级的用户每个月展示一次, 插在第二个位置后面 function insertEvaluateCard(list) { if (!evaluateFlag) @@ -146,17 +157,23 @@ const ListContainer = (props) => { return [...list, { type: "evaluateCard" }]; } const [item1, item2, ...rest] = list; - return [ + + let result = [ item1, item2, { type: "evaluateCard" }, ...(showNumber !== undefined ? rest.slice(0, showNumber - 3) : rest), ]; + + if (bannerListImage) { + return insertBannerCard(result); + } + return result; } const memoizedList = useMemo( () => insertEvaluateCard(data), - [evaluateFlag, data, hasTestInLastMonth, showNumber] + [evaluateFlag, data, hasTestInLastMonth, showNumber, bannerListImage, bannerDetailImage, bannerListIndex] ); // 渲染 banner 卡片 @@ -165,16 +182,12 @@ const ListContainer = (props) => { return ( { const target = item.banner_detail_url; if (target) { @@ -211,10 +224,10 @@ const ListContainer = (props) => { return ( <> {memoizedList.map((match, index) => { - if (match.type === "banner") { + if (match?.type === "banner") { return renderBanner(match, index); } - if (match.type === "evaluateCard") { + if (match?.type === "evaluateCard") { return ( ); diff --git a/src/store/listStore.ts b/src/store/listStore.ts index c17dd80..d5d2392 100644 --- a/src/store/listStore.ts +++ b/src/store/listStore.ts @@ -11,8 +11,6 @@ import { getCityQrCode, getDistricts, } from "../services/listApi"; -// 不再在这里请求 banner 字典,统一由 dictionaryStore 启动时获取 -import { useDictionaryStore } from "./dictionaryStore"; import { ListActions, IFilterOptions, @@ -20,26 +18,6 @@ import { IPayload, } from "../../types/list/types"; -// 将 banner 按索引插入到列表的工具方法(0基;长度不足则插末尾;先移除已存在的 banner) -function insertBannersToRows(rows: any[], dictData: any) { - if (!Array.isArray(rows) || !dictData) return rows; - const img = (dictData?.bannerListImage || "").trim(); - const indexRaw = (dictData?.bannerListIndex || "").toString().trim(); - if (!img) return rows; - const parsed = parseInt(indexRaw, 10); - const normalized = Number.isFinite(parsed) ? parsed : 0; - // 先移除已有的 banner,确保列表中仅一条 banner - const resultRows = rows?.filter((item) => item?.type !== "banner") || []; - const target = Math.max(0, Math.min(normalized, resultRows.length)); - resultRows.splice(target, 0, { - type: "banner", - id: `banner-${target}`, - banner_image_url: img, - banner_detail_url: (dictData?.bannerDetailImage || "").trim(), - } as any); - return resultRows; -} - function translateCityData(dataTree) { return dataTree.map((item) => { const { children, ...rest } = item; @@ -272,14 +250,11 @@ export const useListStore = create()((set, get) => ({ const currentPageState = state.isSearchResult ? state.searchPageState : state.listPageState; const currentData = currentPageState?.data || []; const newData = isAppend ? [...currentData, ...(data || [])] : (data || []); - // 从字典缓存获取 banner,并将其插入到最终列表指定位置(全局索引) - const dictData = useDictionaryStore.getState().bannerDict; - const processedData = dictData ? insertBannersToRows(newData, dictData) : newData; state.updateCurrentPageState({ - data: processedData, + data: newData, isHasMoreData, // 使用插入后的最终数据判断是否显示空状态,避免有 banner 时仍显示空 - isShowNoData: processedData?.length === 0, + isShowNoData: newData?.length === 0, }); set({ From b417b3a4c22a9ae52531078e67115d4a89da2c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Sat, 7 Feb 2026 00:58:57 +0800 Subject: [PATCH 09/11] 1 --- src/container/listContainer/index.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/container/listContainer/index.tsx b/src/container/listContainer/index.tsx index fb1cb72..0c0d906 100644 --- a/src/container/listContainer/index.tsx +++ b/src/container/listContainer/index.tsx @@ -167,12 +167,20 @@ const ListContainer = (props) => { return ( { + const target = item.banner_detail_url; + if (target) { + (Taro as any).navigateTo({ + url: `/other_pages/bannerDetail/index?img=${encodeURIComponent(target)}`, + }); + } + }} style={{ height: "122px", overflow: "hidden", borderRadius: "12px", backgroundImage: `url(${item.banner_image_url})`, - backgroundSize: "contain", + backgroundSize: "cover", backgroundPosition: "center", backgroundRepeat: "no-repeat", }} From 5a10c73adf50e02e92659484499137b88b8afaaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Sat, 7 Feb 2026 11:56:43 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E5=A0=86?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ListCard/index.tsx | 2 +- src/components/Radar/index.tsx | 20 +++------ src/components/Radar/indexV2.tsx | 21 +++------ src/container/listContainer/index.tsx | 45 +++++++++---------- src/main_pages/index.tsx | 6 --- .../enable_notification/index.scss | 1 - src/other_pages/new_follow/index.tsx | 2 +- src/other_pages/ntrp-evaluate/index.tsx | 39 ++++++++-------- src/services/evaluateService.ts | 1 + src/store/dictionaryStore.ts | 33 +++++--------- 10 files changed, 65 insertions(+), 105 deletions(-) diff --git a/src/components/ListCard/index.tsx b/src/components/ListCard/index.tsx index c865790..c4b65c2 100644 --- a/src/components/ListCard/index.tsx +++ b/src/components/ListCard/index.tsx @@ -45,7 +45,7 @@ const ListCard: React.FC = ({ className="image" mode="aspectFill" lazyLoad - defaultSource="https://images.unsplash.com/photo-1554068865-24cecd4e34b8?w=200&h=200&fit=crop&crop=center" + defaultSource={require("@/static/emptyStatus/publish-empty-card.png")} /> ); }; diff --git a/src/components/Radar/index.tsx b/src/components/Radar/index.tsx index ca71305..c4a9fd9 100644 --- a/src/components/Radar/index.tsx +++ b/src/components/Radar/index.tsx @@ -89,25 +89,15 @@ const RadarChart: React.FC = forwardRef((props, ref) => { ctx.lineWidth = 1; ctx.stroke(); - // 标签 - const offset = 10; - const textX = center.x + (radius + offset) * Math.cos(angle); - const textY = center.y + (radius + offset) * Math.sin(angle); + // 标签:沿轴线外侧延伸,文字中心对齐轴线端点 + const labelOffset = 28; + const textX = center.x + (radius + labelOffset) * Math.cos(angle); + const textY = center.y + (radius + labelOffset) * Math.sin(angle); ctx.font = "12px sans-serif"; ctx.fillStyle = "#333"; ctx.textBaseline = "middle"; - - if ( - Math.abs(angle) < 0.01 || - Math.abs(Math.abs(angle) - Math.PI) < 0.01 - ) { - ctx.textAlign = "center"; - } else if (angle > -Math.PI / 2 && angle < Math.PI / 2) { - ctx.textAlign = "left"; - } else { - ctx.textAlign = "right"; - } + ctx.textAlign = "center"; ctx.fillText(label, textX, textY); }); diff --git a/src/components/Radar/indexV2.tsx b/src/components/Radar/indexV2.tsx index 9db6076..ab1e276 100644 --- a/src/components/Radar/indexV2.tsx +++ b/src/components/Radar/indexV2.tsx @@ -102,26 +102,15 @@ const RadarChartV2 = forwardRef((props, ref) ctx.lineWidth = 1 * (radarSize / 200); // 根据2倍图调整线宽 ctx.stroke(); - // 标签 - 文字显示在圆圈外面 - const offset = 10 * (radarSize / 200); // 文字距离圆圈的偏移量(2倍图) - const textX = center.x + (radius + offset) * Math.cos(angle); - const textY = center.y + (radius + offset) * Math.sin(angle); + // 标签:沿轴线外侧延伸,文字中心对齐轴线端点(与 index.tsx 一致) + const labelOffset = 28 * (radarSize / 200); // 文字距离圆圈的偏移量(2倍图) + const textX = center.x + (radius + labelOffset) * Math.cos(angle); + const textY = center.y + (radius + labelOffset) * Math.sin(angle); ctx.font = `${12 * (radarSize / 200)}px sans-serif`; // 根据2倍图调整字体大小 ctx.fillStyle = "#333"; ctx.textBaseline = "middle"; - - // 调整文字对齐方式 - if ( - Math.abs(angle) < 0.01 || - Math.abs(Math.abs(angle) - Math.PI) < 0.01 - ) { - ctx.textAlign = "center"; - } else if (angle > -Math.PI / 2 && angle < Math.PI / 2) { - ctx.textAlign = "left"; - } else { - ctx.textAlign = "right"; - } + ctx.textAlign = "center"; ctx.fillText(label, textX, textY); }); diff --git a/src/container/listContainer/index.tsx b/src/container/listContainer/index.tsx index 40b89b4..23b2647 100644 --- a/src/container/listContainer/index.tsx +++ b/src/container/listContainer/index.tsx @@ -134,6 +134,7 @@ const ListContainer = (props) => { // 插入 banner 卡片 function insertBannerCard(list) { if (!bannerListImage) return list; + if (!list || !Array.isArray(list)) return list ?? []; return [ ...list.slice(0, Number(bannerListIndex)), { type: "banner", banner_image_url: bannerListImage, banner_detail_url: bannerDetailImage }, @@ -142,33 +143,29 @@ const ListContainer = (props) => { } // 对于没有ntrp等级的用户每个月展示一次, 插在第二个位置后面 + // insertBannerCard 需在最后统一执行,否则前面分支直接 return 时 banner 不会被插入 function insertEvaluateCard(list) { - if (!evaluateFlag) - return showNumber !== undefined ? list.slice(0, showNumber) : list; - if (!list || list.length === 0) { - return list; - } - // 如果最近一个月有测试记录,则不插入 card - if (hasTestInLastMonth) { - return showNumber !== undefined ? list.slice(0, showNumber) : list; + let result: any[]; + + if (!evaluateFlag) { + result = showNumber !== undefined ? list.slice(0, showNumber) : list; + } else if (!list || list.length === 0) { + result = list; + } 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 (list.length <= 2) { - return [...list, { type: "evaluateCard" }]; - } - const [item1, item2, ...rest] = list; - - let result = [ - item1, - item2, - { type: "evaluateCard" }, - ...(showNumber !== undefined ? rest.slice(0, showNumber - 3) : rest), - ]; - - if (bannerListImage) { - return insertBannerCard(result); - } - return result; + return insertBannerCard(result); } const memoizedList = useMemo( diff --git a/src/main_pages/index.tsx b/src/main_pages/index.tsx index b71b954..114d516 100644 --- a/src/main_pages/index.tsx +++ b/src/main_pages/index.tsx @@ -67,12 +67,6 @@ const MainPage: React.FC = () => { try { await fetchUserInfo(); await checkNicknameChangeStatus(); - // 启动时预取 Banner 字典(与业务无强依赖,失败不影响主流程) - try { - await useDictionaryStore.getState().fetchBannerDictionary(); - } catch (e) { - console.error("预取 Banner 字典失败:", e); - } } catch (error) { console.error("获取用户信息失败:", error); } diff --git a/src/other_pages/enable_notification/index.scss b/src/other_pages/enable_notification/index.scss index b18b4dc..b2e1ca5 100644 --- a/src/other_pages/enable_notification/index.scss +++ b/src/other_pages/enable_notification/index.scss @@ -12,7 +12,6 @@ align-items: center; flex: 1; position: relative; - overflow: hidden; } // 示例消息卡片区域 diff --git a/src/other_pages/new_follow/index.tsx b/src/other_pages/new_follow/index.tsx index 61eec71..c1932f9 100644 --- a/src/other_pages/new_follow/index.tsx +++ b/src/other_pages/new_follow/index.tsx @@ -193,7 +193,7 @@ const NewFollow = () => { handleUserClick(item.user_id)}> diff --git a/src/other_pages/ntrp-evaluate/index.tsx b/src/other_pages/ntrp-evaluate/index.tsx index 38cde35..33303e9 100644 --- a/src/other_pages/ntrp-evaluate/index.tsx +++ b/src/other_pages/ntrp-evaluate/index.tsx @@ -216,9 +216,8 @@ function Intro() { }); } Taro.redirectTo({ - url: `/other_pages/ntrp-evaluate/index?stage=${type}${ - type === StageType.RESULT ? `&id=${id}` : "" - }`, + url: `/other_pages/ntrp-evaluate/index?stage=${type}${type === StageType.RESULT ? `&id=${id}` : "" + }`, }); } @@ -539,18 +538,21 @@ function Result() { const res = await evaluateService.getTestResult({ record_id: Number(id) }); if (res.code === 0) { setResult(res.data); - // delay(1000); - setRadarData( - adjustRadarLabels( - Object.entries(res.data.radar_data.abilities).map(([key, value]) => [ - key, - Math.min( - 100, - Math.floor((value.current_score / value.max_score) * 100) - ), - ]) - ) - ); + + const sortOrder = res.data.sort || []; + const abilities = res.data.radar_data.abilities; + const sortedKeys = sortOrder.filter((k) => k in abilities); + const remainingKeys = Object.keys(abilities).filter((k) => !sortOrder.includes(k)); + const allKeys = [...sortedKeys, ...remainingKeys]; + let radarData: [string, number][] = allKeys.map((key) => [ + key, + Math.min( + 100, + Math.floor((abilities[key].current_score / abilities[key].max_score) * 100) + ), + ]); + // 直接使用接口 sort 顺序,不经过 adjustRadarLabels 重新排序 + setRadarData(radarData); updateUserLevel(res.data.record_id, res.data.ntrp_level); } } @@ -698,13 +700,12 @@ function Result() { } const currentPage = getCurrentFullPath(); Taro.redirectTo({ - url: `/login_pages/index/index${ - currentPage ? `?redirect=${encodeURIComponent(currentPage)}` : "" - }`, + url: `/login_pages/index/index${currentPage ? `?redirect=${encodeURIComponent(currentPage)}` : "" + }`, }); } - function handleGo() {} + function handleGo() { } return ( diff --git a/src/services/evaluateService.ts b/src/services/evaluateService.ts index dab032d..d7c3778 100644 --- a/src/services/evaluateService.ts +++ b/src/services/evaluateService.ts @@ -58,6 +58,7 @@ export interface TestResultData { level_img?: string; // 等级图片URL radar_data: RadarData; answers: Answer[]; + sort?: string[]; // 雷达图能力项排序,如 ["正手球质", "正手控制", ...] } // 单条测试记录 diff --git a/src/store/dictionaryStore.ts b/src/store/dictionaryStore.ts index 47a5e28..8f361d2 100644 --- a/src/store/dictionaryStore.ts +++ b/src/store/dictionaryStore.ts @@ -20,7 +20,6 @@ interface DictionaryState { bannerDetailImage: string bannerListIndex: string } | null - fetchBannerDictionary: () => Promise } // 创建字典Store @@ -36,7 +35,7 @@ export const useDictionaryStore = create()((set, get) => ({ set({ isLoading: true, error: null }) try { - const keys = 'publishing_requirements,court_type,court_surface,supplementary_information,game_play,fabu_tip,supported_cities'; + const keys = 'publishing_requirements,court_type,court_surface,supplementary_information,game_play,fabu_tip,supported_cities,bannerListImage,bannerDetailImage,bannerListIndex'; const response = await commonApi.getDictionaryManyKey(keys) if (response.code === 0 && response.data) { @@ -53,6 +52,15 @@ export const useDictionaryStore = create()((set, get) => ({ dictionaryData: dictionaryData || {}, isLoading: false }) + + set({ + bannerDict: { + bannerListImage: response.data.bannerListImage || '', + bannerDetailImage: response.data.bannerDetailImage || '', + bannerListIndex: (response.data.bannerListIndex ?? '').toString(), + } + }) + console.log('字典数据获取成功:', response.data) } else { throw new Error(response.message || '获取字典数据失败') @@ -67,26 +75,7 @@ export const useDictionaryStore = create()((set, get) => ({ } }, - // 获取 Banner 字典(启动时或手动调用) - fetchBannerDictionary: async () => { - try { - const keys = 'bannerListImage,bannerDetailImage,bannerListIndex'; - const response = await commonApi.getDictionaryManyKey(keys) - if (response.code === 0 && response.data) { - const data = response.data || {}; - set({ - bannerDict: { - bannerListImage: data.bannerListImage || '', - bannerDetailImage: data.bannerDetailImage || '', - bannerListIndex: (data.bannerListIndex ?? '').toString(), - } - }) - } - } catch (error) { - // 保持静默,避免影响启动流程 - console.error('获取 Banner 字典失败:', error) - } - }, + // 获取字典值 getDictionaryValue: (key: string, defaultValue?: any) => { From 536619ebfcbd4f1ce6ce09a1f3e1ab8e347c815a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Sat, 7 Feb 2026 13:08:28 +0800 Subject: [PATCH 11/11] 1 --- src/container/listContainer/index.tsx | 15 ++++---- .../detail/components/SharePopup/index.tsx | 5 ++- src/main_pages/components/ListPageContent.tsx | 1 + src/other_pages/favorites/index.tsx | 12 +++--- src/services/commonApi.ts | 1 - src/services/detailService.ts | 2 +- src/services/httpService.ts | 37 +++++++++++-------- src/utils/share.ts | 34 ++++++++--------- 8 files changed, 58 insertions(+), 49 deletions(-) diff --git a/src/container/listContainer/index.tsx b/src/container/listContainer/index.tsx index 23b2647..7e5861e 100644 --- a/src/container/listContainer/index.tsx +++ b/src/container/listContainer/index.tsx @@ -29,6 +29,7 @@ const ListContainer = (props) => { collapse = false, defaultShowNum, evaluateFlag, + enableHomeCards = false, // 仅首页需要 banner 和 NTRP 测评卡片 listLoadErrorWrapperHeight, listLoadErrorWidth, listLoadErrorHeight, @@ -94,10 +95,10 @@ const ListContainer = (props) => { }; }, []); - // 获取测试结果,判断最近一个月是否有测试记录 + // 获取测试结果,判断最近一个月是否有测试记录(仅首页需要) useEffect(() => { const init = async () => { - if (!evaluateFlag) return; + if (!evaluateFlag || !enableHomeCards) return; // 先等待静默登录完成 await waitForAuthInit(); // 然后再获取用户信息 @@ -112,7 +113,7 @@ const ListContainer = (props) => { } }; init(); - }, [evaluateFlag, userInfo, lastTestResult, fetchLastTestResult]); + }, [evaluateFlag, enableHomeCards, userInfo, lastTestResult, fetchLastTestResult]); // 从全局状态中获取测试状态 const hasTestInLastMonth = lastTestResult?.has_test_in_last_month || false; @@ -169,8 +170,8 @@ const ListContainer = (props) => { } const memoizedList = useMemo( - () => insertEvaluateCard(data), - [evaluateFlag, data, hasTestInLastMonth, showNumber, bannerListImage, bannerDetailImage, bannerListIndex] + () => (enableHomeCards ? insertEvaluateCard(data) : data), + [enableHomeCards, evaluateFlag, data, hasTestInLastMonth, showNumber, bannerListImage, bannerDetailImage, bannerListIndex] ); // 渲染 banner 卡片 @@ -226,10 +227,10 @@ const ListContainer = (props) => { return ( <> {memoizedList.map((match, index) => { - if (match?.type === "banner") { + if (enableHomeCards && match?.type === "banner") { return renderBanner(match, index); } - if (match?.type === "evaluateCard") { + if (enableHomeCards && match?.type === "evaluateCard") { return ( ); diff --git a/src/game_pages/detail/components/SharePopup/index.tsx b/src/game_pages/detail/components/SharePopup/index.tsx index be2af80..ea181b2 100644 --- a/src/game_pages/detail/components/SharePopup/index.tsx +++ b/src/game_pages/detail/components/SharePopup/index.tsx @@ -128,7 +128,7 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => { const endTime = dayjs(end_time); const dayofWeek = DayOfWeekMap.get(startTime.day()); const gameLength = `${endTime.diff(startTime, "hour")}小时`; - Taro.showLoading({ title: "生成中..." }); + // Taro.showLoading({ title: "生成中..." }); const qrCodeUrlRes = await DetailService.getQrCodeUrl({ page: "game_pages/detail/index", scene: `id=${id}`, @@ -137,6 +137,7 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => { qrCodeUrlRes.data.qr_code_base64 ); await delay(100); + // Taro.showLoading({ title: "生成中..." }); const url = await generatePosterImage({ playType: play_type, ntrp: `NTRP ${genNTRPRequirementText(skill_level_min, skill_level_max)}`, @@ -152,7 +153,7 @@ export default forwardRef(({ id, from, detail, userInfo }, ref) => { time: `${startTime.format("ah")}点 ${gameLength}`, qrCodeUrl, }); - Taro.hideLoading(); + // Taro.hideLoading(); Taro.showShareImageMenu({ path: url, }); diff --git a/src/main_pages/components/ListPageContent.tsx b/src/main_pages/components/ListPageContent.tsx index 8bf6a79..641fa63 100644 --- a/src/main_pages/components/ListPageContent.tsx +++ b/src/main_pages/components/ListPageContent.tsx @@ -627,6 +627,7 @@ const ListPageContent: React.FC = ({ reload={refreshMatches} loadMoreMatches={loadMoreMatches} evaluateFlag + enableHomeCards /> diff --git a/src/other_pages/favorites/index.tsx b/src/other_pages/favorites/index.tsx index 94c8903..db08552 100644 --- a/src/other_pages/favorites/index.tsx +++ b/src/other_pages/favorites/index.tsx @@ -21,10 +21,10 @@ const OrderCheck = () => { //TODO: get order msg from id const handlePay = async () => { - Taro.showLoading({ - title: '支付中...', - mask: true - }) + // Taro.showLoading({ + // title: '支付中...', + // mask: true + // }) const res = await orderService.createOrder(Number(gameId)) if (res.code === 0) { const { payment_required, payment_params } = res.data @@ -37,7 +37,7 @@ const OrderCheck = () => { signType, paySign, success: async () => { - Taro.hideLoading() + // Taro.hideLoading() Taro.showToast({ title: '支付成功', icon: 'success' @@ -48,7 +48,7 @@ const OrderCheck = () => { }) }, fail: () => { - Taro.hideLoading() + // Taro.hideLoading() Taro.showToast({ title: '支付失败', icon: 'none' diff --git a/src/services/commonApi.ts b/src/services/commonApi.ts index d0b4e73..135264c 100644 --- a/src/services/commonApi.ts +++ b/src/services/commonApi.ts @@ -51,7 +51,6 @@ class CommonApiService { data: results.map(result => result.data) } } catch (error) { - throw error } finally { Taro.hideLoading() } diff --git a/src/services/detailService.ts b/src/services/detailService.ts index b5cdd9c..6c5fd6c 100644 --- a/src/services/detailService.ts +++ b/src/services/detailService.ts @@ -163,7 +163,7 @@ class GameDetailService { width: number }>> { return httpService.post('/user/generate_qrcode', req, { - showLoading: false + showLoading: true }) } } diff --git a/src/services/httpService.ts b/src/services/httpService.ts index 664f331..d86885d 100644 --- a/src/services/httpService.ts +++ b/src/services/httpService.ts @@ -129,23 +129,30 @@ class HttpService { // 隐藏loading(支持多个并发请求) private hideLoading(): void { - this.loadingCount = Math.max(0, this.loadingCount - 1) + try { + this.loadingCount = Math.max(0, this.loadingCount - 1) - // 只有所有请求都完成时才隐藏loading - if (this.loadingCount === 0) { - // 清除之前的延时器 - if (this.hideLoadingTimer) { - clearTimeout(this.hideLoadingTimer) - this.hideLoadingTimer = null + // 只有所有请求都完成时才隐藏loading + if (this.loadingCount === 0) { + // 清除之前的延时器 + if (this.hideLoadingTimer) { + clearTimeout(this.hideLoadingTimer) + this.hideLoadingTimer = null + } + + // 延时300ms后隐藏loading,避免频繁切换 + this.hideLoadingTimer = setTimeout(() => { + Taro.hideLoading() + this.currentLoadingText = '' + this.hideLoadingTimer = null + }, 800) } - // 延时300ms后隐藏loading,避免频繁切换 - this.hideLoadingTimer = setTimeout(() => { - Taro.hideLoading() - this.currentLoadingText = '' - this.hideLoadingTimer = null - }, 800) } + catch (e) { + console.warn(e) + } + } // 处理响应 @@ -175,7 +182,7 @@ class HttpService { url: '/login_pages/index/index' }) reject(new Error('用户不存在')) - return response.data + return response.data } @@ -187,7 +194,7 @@ class HttpService { } else { reject(response.data) } - return response.data + return response.data } } diff --git a/src/utils/share.ts b/src/utils/share.ts index 1f2cb87..8e60115 100644 --- a/src/utils/share.ts +++ b/src/utils/share.ts @@ -534,23 +534,23 @@ const drawShareCard = async (ctx: any, data: ShareCardData, offscreen: any): Pro ctx.drawImage(locationPath, iconX, locationInfoY, iconSize, iconSize) drawBoldText(ctx, data.venueName, danDaX, locationInfoY + 10, locationFontSize, '#000000') - try { - const wxAny: any = (typeof (globalThis as any) !== 'undefined' && (globalThis as any).wx) ? (globalThis as any).wx : null - if (wxAny && typeof wxAny.canvasToTempFilePath === 'function') { - wxAny.canvasToTempFilePath({ - canvas: offscreen, - fileType: 'png', - quality: 1, - success: (res: any) => { - console.log('===res666', res) - resolve(res.tempFilePath) - }, - fail: reject - }) - return - } - } catch { } - reject(new Error('无法导出图片(OffscreenCanvas 转文件失败)')) + try { + const wxAny: any = (typeof (globalThis as any) !== 'undefined' && (globalThis as any).wx) ? (globalThis as any).wx : null + if (wxAny && typeof wxAny.canvasToTempFilePath === 'function') { + wxAny.canvasToTempFilePath({ + canvas: offscreen, + fileType: 'png', + quality: 1, + success: (res: any) => { + console.log('===res666', res) + resolve(res.tempFilePath) + }, + fail: reject + }) + return + } + } catch { } + reject(new Error('无法导出图片(OffscreenCanvas 转文件失败)')) console.log('Canvas绘制命令已发送') } catch (error) {