import { create } from "zustand"; import dayjs from "dayjs"; import { getGamesList, getGamesIntegrateList, getSearchHistory, clearHistory, searchSuggestion, getGamesCount, getCities, getCityQrCode, getDistricts, } from "../services/listApi"; import { ListActions, IFilterOptions, ListState, IPayload, } from "../../types/list/types"; function translateCityData(dataTree) { return dataTree.map((item) => { const { children, ...rest } = item; // 只保留两级:国家和省份,去掉第三级(区域) const processedChildren = children?.length > 0 ? children.map(child => ({ ...child, text: child.name, label: child.name, value: child.name, children: null, // 去掉第三级 })) : null; return { ...rest, text: rest.name, label: rest.name, value: rest.name, children: processedChildren, }; }); } // 完整的 Store 类型 type TennisStore = ListState & ListActions; const defaultDateRange: [string, string] = [dayjs().format('YYYY-MM-DD'), dayjs().add(1, 'M').format('YYYY-MM-DD')] const defaultFilterOptions: IFilterOptions = { dateRange: defaultDateRange, // 日期区间 timeSlot: "", // 时间段 ntrp: [1, 5], // NTRP 水平区间 venueType: "", // 场地类型 playType: "", // 玩法 }; // const defaultDistance = "all"; // 默认距离 const defaultDistanceQuickFilter = { distanceFilter: "", order: "0", district: "", // 新增:行政区筛选 }; const defaultPageOption = { page: 1, pageSize: 20, }; // 页面状态默认值 const pageStateDefaultValue = { // 列表数据 data: [], // 推荐列表 recommendList: [], // 是否展示综合筛选弹窗 isShowFilterPopup: false, // 综合筛选项 filterOptions: defaultFilterOptions, // 距离筛选和快捷筛选 distanceQuickFilter: defaultDistanceQuickFilter, // 综合筛选 选择的筛选数量 filterCount: 0, // 分页 pageOption: defaultPageOption, // 球局数量 gamesNum: 0, // 是否还有更多数据 isHasMoreData: true, // 是否展示无数据 isShowNoData: false, } // 列表页状态 const listPageStateDefaultValue = { ...pageStateDefaultValue, // 列表页是否显示搜索框自定义导航 isShowInputCustomerNavBar: false, } // 搜索页状态 const searchPageStateDefaultValue = { ...pageStateDefaultValue, // 搜索结果数据 data: [], // 联想词 suggestionList: [], // 是否显示联想词 isShowSuggestion: false, // 搜索历史数据 searchHistory: [], // 搜索历史数据默认 Top 15 searchHistoryParams: { page: 1, pageSize: 15, }, } // const now = new Date(); // 公共属性 const commonStateDefaultValue = { // 是否是搜索结果页 isSearchResult: false, // 是否加载中 loading: false, // 错误信息 error: null, // 位置 location: { latitude: 0, longitude: 0, }, // 搜索的value searchValue: "", // 日期区间 // dateRange: [now, new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000)], // 距离筛选数据 distanceData: [ { id: 0, label: "全城", value: "" }, { id: 1, label: "3km", value: "3" }, { id: 2, label: "5km", value: "5" }, { id: 3, label: "10km", value: "10" }, ], // 快捷筛选数据 quickFilterData: [ { label: "智能排序", value: "0" }, { label: "距离更近", value: "distance" }, { label: "时间更近", value: "time" }, ], // 气泡日期范围 dateRangeOptions: [ { id: 1, label: "本周末", value: "1" }, { id: 2, label: "一周内", value: "2" }, { id: 3, label: "一月内", value: "3" }, ], // 时间气泡数据 timeBubbleData: [ { id: 1, label: "晨间 6:00-10:00", value: "6:00-10:00" }, { id: 2, label: "上午 10:00-12:00", value: "10:00-12:00" }, { id: 3, label: "中午 12:00-14:00", value: "12:00-14:00" }, { id: 4, label: "下午 14:00-18:00", value: "14:00-18:00" }, { id: 5, label: "晚上 18:00-22:00", value: "18:00-22:00" }, { id: 6, label: "夜间 22:00-24:00", value: "22:00-24:00" }, ], cities: [], cityQrCode: [], area: ['', ''] as [string, string], // 改为两级:国家、省份 districts: [], // 新增:行政区列表 } // 创建 store export const useListStore = create()((set, get) => ({ currentPage: "", // 列表页 listPageState: listPageStateDefaultValue, // 搜索及搜索结果页 searchPageState: searchPageStateDefaultValue, ...commonStateDefaultValue, gamesNum: 0, // 组装搜索数据 getSearchParams: () => { const state = get(); const currentPageState = state.isSearchResult ? state.searchPageState : state.listPageState; const filterOptions = currentPageState?.filterOptions || {}; // 全城和快捷筛选 const distanceQuickFilter = currentPageState?.distanceQuickFilter || {}; const { distanceFilter, order, district } = distanceQuickFilter || {}; // 从 area 中获取省份名称(area 格式: ["中国", 省份]) const province = state.area?.[1] || ""; // area[1] 是省份 // city 参数逻辑: // 1. 如果选择了行政区(district 有值),使用行政区的名称(label) // 2. 如果是"全城"(distanceFilter 为空),不传 city let city: string | undefined = undefined; if (district) { // 从 districts 数组中查找对应的行政区名称 const selectedDistrict = state.districts.find(item => item.value === district); if (selectedDistrict) { city = selectedDistrict.label; // 传递行政区名称,如"静安" } } // 如果是"全城"(distanceFilter 为空),city 保持 undefined,不会被传递 // 使用 filterOptions 中的 dateRange const dateRange: [string, string] = filterOptions?.dateRange || defaultDateRange; const searchOption: any = { ...filterOptions, title: state.searchValue, ntrpMin: filterOptions?.ntrp?.[0], ntrpMax: filterOptions?.ntrp?.[1], dateRange: dateRange, // 确保始终是两个值的数组 distanceFilter: distanceFilter, province: province, // 添加省份参数 }; // 只在有值时添加 city 参数 if (city) { searchOption.city = city; } const params = { pageOption: currentPageState?.pageOption, seachOption: searchOption, order: order, lat: state?.location?.latitude, lng: state?.location?.longitude, }; return params; }, // 设置列表结果 setListData: (payload: IPayload & { isAppend?: boolean }) => { const state = get(); const { error, data, loading, count, isAppend = false } = payload; const isHasMoreData = count > 0; const currentPageState = state.isSearchResult ? state.searchPageState : state.listPageState; const currentData = currentPageState?.data || []; const newData = isAppend ? [...currentData, ...(data || [])] : (data || []); state.updateCurrentPageState({ data: newData, isHasMoreData, isShowNoData: newData?.length === 0, }); set({ error, loading, }); }, // 获取列表数据(常规搜索) fetchMatches: async (params, isFirstLoad = false, isAppend = false) => { if (get().loading) { return; } set({ loading: true, error: null }); const { getSearchParams, setListData } = get(); try { const searchParams = getSearchParams() || {}; const reqParams = { ...(searchParams || {}), ...params, }; // 获取当前页面的距离筛选 const state = get(); const currentPageState = state.isSearchResult ? state.searchPageState : state.listPageState; const distanceQuickFilter = currentPageState?.distanceQuickFilter || {}; // 是否选择了智能排序 const isIntegrate = distanceQuickFilter?.order === "0"; let fetchFn = getGamesList; if (isIntegrate) { reqParams.order = ""; fetchFn = getGamesIntegrateList; // 第一次进入页面时传入 isRefresh 参数 if (isFirstLoad) { reqParams.seachOption.isRefresh = true; } } const resData = (await fetchFn(reqParams)) || {}; const { data = {}, code } = resData; if (code !== 0) { setListData({ error: "-1", data: [], loading: false, count: 0, isAppend, }); return Promise.reject(new Error('获取数据失败')); } const { count, rows } = data; setListData({ error: '', data: rows || [], loading: false, count, isAppend, }); return Promise.resolve(); } catch (error) { setListData({ error: "-1", data: [], loading: false, count: 0, isAppend, }); return Promise.reject(error); } }, // 获取列表数据 getMatchesData: async () => { const { fetchMatches } = get(); return await fetchMatches({}, true); // 第一次进入页面,传入 isFirstLoad = true }, // 同时更新两个列表接口(常规列表和智能排序列表) refreshBothLists: async () => { const state = get(); const { getSearchParams, setListData } = state; const { getGamesList, getGamesIntegrateList } = await import("../services/listApi"); try { const searchParams = getSearchParams() || {}; // 调用常规列表接口 const listParams = { ...searchParams, order: searchParams.order || "distance", }; const listRes = await getGamesList(listParams); // 调用智能排序列表接口 const integrateParams = { ...searchParams, order: "", seachOption: { ...searchParams.seachOption, isRefresh: true, }, }; const integrateRes = await getGamesIntegrateList(integrateParams); // 根据当前排序方式更新对应的数据 const currentPageState = state.isSearchResult ? state.searchPageState : state.listPageState; const distanceQuickFilter = currentPageState?.distanceQuickFilter || {}; const isIntegrate = distanceQuickFilter?.order === "0"; if (listRes?.code === 0 && listRes?.data) { const { count, rows } = listRes.data; if (!isIntegrate) { // 如果当前是常规排序,更新常规列表数据 setListData({ error: '', data: rows || [], loading: false, count, isAppend: false, }); } } if (integrateRes?.code === 0 && integrateRes?.data) { const { count, rows, recommendList } = integrateRes.data; if (isIntegrate) { // 如果当前是智能排序,更新智能排序列表数据 setListData({ error: '', data: rows || [], loading: false, count, isAppend: false, }); } // 无论当前排序方式如何,都更新推荐列表 state.updateCurrentPageState({ recommendList: recommendList || [], }); } return Promise.resolve(); } catch (error) { console.error("更新列表数据失败:", error); return Promise.reject(error); } }, // 获取球局数量 fetchGetGamesCount: async () => { const { getSearchParams } = get(); const params = getSearchParams() || {}; const resData = (await getGamesCount(params)) || {}; const gamesNum = resData?.data?.count || 0; set({ gamesNum }); }, // 获取历史搜索数据 getSearchHistory: async () => { try { const state = get(); const params = state.searchPageState?.searchHistoryParams || {}; const resData = (await getSearchHistory(params)) || {}; const searchHistory = resData?.data?.records || []; set({ searchPageState: { ...state.searchPageState, searchHistory, }, }); } catch (error) { } }, // 清空历史记录 clearHistory: async () => { try { const state = get(); const params = {}; const resData = (await clearHistory(params)) || {}; if (resData?.code === 0) { set({ searchPageState: { ...state.searchPageState, searchHistory: [], }, }); } } catch (error) { } }, // 获取联想 searchSuggestion: async (val: string) => { try { const state = get(); const resData = (await searchSuggestion({ keyword: val, limit: 10 })) || {}; const recommendations = resData?.data?.recommendations || []; const total = resData?.data?.total; set({ searchPageState: { ...state.searchPageState, suggestionList: recommendations, isShowSuggestion: total > 0, }, }); } catch (error) { const state = get(); set({ searchPageState: { ...state.searchPageState, suggestionList: [], isShowSuggestion: true, }, }); } }, // 清除错误信息 clearError: () => { set({ error: null }); }, getCurrentPageState: () => { const state = get(); return { currentPageState: state.isSearchResult ? state.searchPageState : state.listPageState, currentPageKey: state.isSearchResult ? "searchPageState" : "listPageState", }; }, // 更新当前页面状态 updateCurrentPageState: (payload: Record) => { const state = get(); const { currentPageState, currentPageKey } = state.getCurrentPageState(); set({ [currentPageKey]: { ...currentPageState, ...payload } }); }, // 更新综合筛选项 updateFilterOptions: (payload: Record) => { const state = get(); const { currentPageState } = state.getCurrentPageState(); const filterOptions = { ...currentPageState?.filterOptions, ...payload }; const filterCount = Object.values(filterOptions).filter(Boolean).length; // 先更新状态 state.updateCurrentPageState({ filterOptions, filterCount, pageOption: defaultPageOption, }); // 使用 Promise.resolve 确保状态更新后再调用接口 Promise.resolve().then(() => { const freshState = get(); // 重新获取最新状态 freshState.fetchGetGamesCount(); }); }, // 更新距离和快捷筛选 updateDistanceQuickFilter: (payload: Record) => { const state = get(); const { currentPageState } = state.getCurrentPageState(); const { distanceQuickFilter } = currentPageState || {}; const newDistanceQuickFilter = { ...distanceQuickFilter, ...payload }; // 先更新状态 state.updateCurrentPageState({ distanceQuickFilter: newDistanceQuickFilter, pageOption: defaultPageOption, }); // 使用 Promise.resolve 确保状态更新后再调用接口 Promise.resolve().then(() => { const freshState = get(); // 重新获取最新状态 freshState.getMatchesData(); freshState.fetchGetGamesCount(); }); }, // 清空综合筛选选项 clearFilterOptions: () => { const state = get(); const { getMatchesData, fetchGetGamesCount } = state; state.updateCurrentPageState({ filterOptions: defaultFilterOptions, filterCount: 0, pageOption: defaultPageOption, }); getMatchesData(); fetchGetGamesCount(); }, // 加载更多数据 loadMoreMatches: async () => { const state = get(); const currentPageState = state.isSearchResult ? state.searchPageState : state.listPageState; const { pageOption, isHasMoreData } = currentPageState || {}; if (!isHasMoreData) { return Promise.resolve(); } const newPageOption = { page: (pageOption?.page || 1) + 1, pageSize: 20, }; state.updateCurrentPageState({ pageOption: newPageOption, }); // 加载更多时追加数据到现有数组 return await state.fetchMatches({}, false, true); }, // 初始化搜索条件 重新搜索 initialFilterSearch: async (isSearchData = false) => { const state = get(); const { getMatchesData, fetchGetGamesCount } = state; if (state.isSearchResult) { set({ searchPageState: { ...searchPageStateDefaultValue }, // loading: true, }); } else { set({ listPageState: { ...listPageStateDefaultValue }, // loading: true, }); } if (!isSearchData) { return; } await fetchGetGamesCount(); await getMatchesData(); }, // 更新store数据 updateState: (payload: Record) => { set({ ...(payload || {}), }); }, // 更新列表页状态中的特定字段 updateListPageState: (payload: Record) => { console.log("===更新列表页状态:", payload); const state = get(); set({ listPageState: { ...state.listPageState, ...payload, }, }); }, // 更新搜索页状态中的特定字段 updateSearchPageState: (payload: Record) => { const state = get(); set({ searchPageState: { ...state.searchPageState, ...payload, }, }); console.log("===更新搜索页状态:", state); }, async getCities() { const res = await getCities(); const state = get(); set({ ...state, cities: translateCityData(res.data), }) }, async getCityQrCode() { const res = await getCityQrCode(); const state = get(); set({ ...state, cityQrCode: res.data, }) }, // 新增:获取行政区列表 async getDistricts() { try { const state = get(); // 从 area 中获取省份,area 格式: ["中国", 省份, 城市] const country = "中国"; const province = state.area?.at(1) || "上海"; // area[1] 是省份 const res = await getDistricts({ country, state: province }); if (res.code === 0 && res.data) { const districts = res.data.map((item) => ({ label: item.cn_city, value: item.id.toString(), id: item.id, })); set({ districts }); return districts; } return []; } catch (error) { console.error("获取行政区列表失败:", error); return []; } }, updateArea(payload: [string, string]) { const state = get(); set({ ...state, area: payload, }) }, })); // 导出便捷的 hooks export const useListState = () => useListStore((state) => state);