diff --git a/src/components/CityFilter/index.module.scss b/src/components/CityFilter/index.module.scss index aa8442f..ef6d454 100644 --- a/src/components/CityFilter/index.module.scss +++ b/src/components/CityFilter/index.module.scss @@ -1,6 +1,7 @@ .menuWrap { padding: 5px 20px 10px; .menuItem { + width: 100vw; left: 0; border-bottom-left-radius: 30px; border-bottom-right-radius: 30px; diff --git a/src/components/CityFilter/index.tsx b/src/components/CityFilter/index.tsx index db40f86..b50c8ca 100644 --- a/src/components/CityFilter/index.tsx +++ b/src/components/CityFilter/index.tsx @@ -12,7 +12,7 @@ interface IProps { } const MenuComponent = (props: IProps) => { - const { value, onChange, wrapperClassName, itemClassName } = props; + const { value, onChange, wrapperClassName, itemClassName, options } = props; const [isChange, setIsChange] = useState(false); const itemRef = useRef(null); @@ -22,12 +22,7 @@ const MenuComponent = (props: IProps) => { onChange && onChange(value); }; - const options: BubbleOption[] = [ - { id: 0, label: "全城", value: "0" }, - { id: 1, label: "3km", value: "3" }, - { id: 2, label: "5km", value: "5" }, - { id: 3, label: "10km", value: "10" }, - ]; + return ( { >
diff --git a/src/components/Menu/index.module.scss b/src/components/Menu/index.module.scss index 0867087..4bebabb 100644 --- a/src/components/Menu/index.module.scss +++ b/src/components/Menu/index.module.scss @@ -1,6 +1,8 @@ .menuWrap { + position: static; padding: 5px 20px 10px; .menuItem { + width: 100vw; left: 0; border-bottom-left-radius: 30px; border-bottom-right-radius: 30px; diff --git a/src/components/SearchBar/index.module.scss b/src/components/SearchBar/index.module.scss index b376efc..632fe92 100644 --- a/src/components/SearchBar/index.module.scss +++ b/src/components/SearchBar/index.module.scss @@ -6,7 +6,6 @@ --nutui-searchbar-input-text-color: #000000; --nutui-searchbar-input-padding: 0 0 0 10px; --nutui-searchbar-padding:0 15px; - // --nutui-searchbar-background: #ffffff; :global(.nut-searchbar-content) { box-shadow: 0 4px 48px #00000014; } diff --git a/src/components/SearchBar/index.tsx b/src/components/SearchBar/index.tsx index 60fd06f..9456d55 100644 --- a/src/components/SearchBar/index.tsx +++ b/src/components/SearchBar/index.tsx @@ -1,22 +1,26 @@ +import { SearchBar } from "@nutui/nutui-react-taro"; +// import {ICON_FILTER} from '../../config/images.js' +import styles from "./index.module.scss"; -import { SearchBar } from '@nutui/nutui-react-taro' -import styles from './index.module.scss' - -const SearchBarComponent = () => { +const SearchBarComponent = (props: IProps) => { + // console.log('===', ICON_FILTER) + const { handleFilterIcon } = props; return ( <> - 123
// } right={ -
+
+ 筛 +
} className={styles.searchBar} - placeholder='搜索上海的球局和场地' + placeholder="搜索上海的球局和场地" /> - ) -} + ); +}; -export default SearchBarComponent \ No newline at end of file +export default SearchBarComponent; diff --git a/src/config/images.js b/src/config/images.js index ab20192..2f42a82 100644 --- a/src/config/images.js +++ b/src/config/images.js @@ -8,4 +8,5 @@ export default { ICON_COST: require('@/static/publishBall/icon-cost.svg'), ICON_TIPS: require('@/static/publishBall/icon-tips.svg'), ICON_ARROW_RIGHT: require('@/static/publishBall/icon-arrow-right.svg'), + ICON_FILTER: require('@/static/list/icon-filter.svg'), } \ No newline at end of file diff --git a/src/pages/list/FilterPopup.tsx b/src/pages/list/FilterPopup.tsx index 1e31276..a4c19f3 100644 --- a/src/pages/list/FilterPopup.tsx +++ b/src/pages/list/FilterPopup.tsx @@ -3,6 +3,8 @@ import Range from "../../components/Range"; import Bubble, { BubbleOption } from "../../components/Bubble"; import styles from "./filterPopup.module.scss"; import TitleComponent from "src/components/Title"; +import { Button } from "@nutui/nutui-react-taro"; +import { useListStore } from "../../store/listStore"; const timeOptions: BubbleOption[] = [ { id: 1, label: "晨间 6:00-10:00", value: "morning" }, @@ -19,7 +21,14 @@ const locationOptions: BubbleOption[] = [ { id: 3, label: "半室外", value: "3" }, ]; -const FilterPopup = () => { +interface IProps { + onCancel: () => void; + onConfirm: () => void; + loading: boolean; +} + +const FilterPopup = (props: IProps) => { + const { loading, onCancel, onConfirm } = props; return ( <> { position="top" round closeOnOverlayClick={false} - onClose={() => { - // setShowTop(false) - }} >
{/* 时间气泡选项 */} @@ -63,6 +69,15 @@ const FilterPopup = () => { columns={3} />
+ {/* 按钮 */} +
+ + +
diff --git a/src/pages/list/filterPopup.module.scss b/src/pages/list/filterPopup.module.scss index c1e834a..9305f21 100644 --- a/src/pages/list/filterPopup.module.scss +++ b/src/pages/list/filterPopup.module.scss @@ -1,8 +1,35 @@ .filterPopupWrapper { + position: relative; $m18: 18px; padding: $m18; + .filterPopupRange { margin-top: $m18; margin-bottom: $m18; } + + .filterPopupBtnWrapper { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + position: sticky; + bottom: 0; + background-color: #ffffff; + padding: 8px 0; + + .btn { + flex: 1; + } + + --nutui-button-border-width: 0.5px; + --nutui-button-default-border-color: #0000000F; + --nutui-button-border-radius: 16px; + --nutui-button-default-height: 44px; + --nutui-button-default-color: #000000; + .confirm { + --nutui-button-default-color: #ffffff; + --nutui-button-default-background-color: #000000; + } + } } \ No newline at end of file diff --git a/src/pages/list/index.module.scss b/src/pages/list/index.module.scss new file mode 100644 index 0000000..1aa4c24 --- /dev/null +++ b/src/pages/list/index.module.scss @@ -0,0 +1,15 @@ +.listPage { + background-color: #fafafa; + padding: 0 15px; + + .listTopFilterWrapper { + display: flex; + align-items: center; + padding: 5px 0 10px; + gap: 5px; + } + + .menuFilter { + padding: 0; + } +} diff --git a/src/pages/list/index.scss b/src/pages/list/index.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/pages/list/index.tsx b/src/pages/list/index.tsx index 7587ed3..525fddc 100644 --- a/src/pages/list/index.tsx +++ b/src/pages/list/index.tsx @@ -1,29 +1,26 @@ import ListItem from "../../components/ListItem"; import List from "../../components/List"; -import Bubble from "../../components/Bubble/example"; -import Range from "../../components/Range/example"; -import Menu from "../../components/Menu/example"; -import CityFilter from "../../components/CityFilter/example"; +import Menu from "../../components/Menu"; +import CityFilter from "../../components/CityFilter"; import SearchBar from "../../components/SearchBar"; import FilterPopup from "./FilterPopup"; -import "./index.scss"; +import styles from "./index.module.scss"; import { useEffect } from "react"; import Taro from "@tarojs/taro"; -import { - useTennisMatches, - useTennisLoading, - useTennisError, - useTennisLastRefresh, - useTennisActions, -} from "../../store/listStore"; +import { useListStore } from "../../store/listStore"; const ListPage = () => { // 从 store 获取数据和方法 - const matches = useTennisMatches(); - const loading = useTennisLoading(); - const error = useTennisError(); - const lastRefreshTime = useTennisLastRefresh(); - const { fetchMatches, refreshMatches, clearError } = useTennisActions(); + const { + isShowFilterPopup, + error, + matches, + loading, + fetchMatches, + refreshMatches, + clearError, + updateState, + } = useListStore() || {}; useEffect(() => { // 页面加载时获取数据 @@ -146,22 +143,43 @@ const ListPage = () => { ); } - return ( -
- - {/* 综合筛选 */} -
- -
- {/* 筛选 */} -
- {/* 全城筛选 */} - - {/* 智能排序 */} - -
+ const toggleShowPopup = () => { + updateState({ isShowFilterPopup: !isShowFilterPopup }); + }; - + const cityOptions: BubbleOption[] = [ + { id: 0, label: "全城", value: "0" }, + { id: 1, label: "3km", value: "3" }, + { id: 2, label: "5km", value: "5" }, + { id: 3, label: "10km", value: "10" }, + ]; + + const options = [ + { text: "默认排序", value: "a" }, + { text: "好评排序", value: "b" }, + { text: "销量排序", value: "c" }, + ]; + + return ( +
+ + {/* 综合筛选 */} + {isShowFilterPopup && ( +
+ +
+ )} + {/* 筛选 */} +
+ {/* 全城筛选 */} + { }} wrapperClassName={styles.menuFilter} /> + {/* 智能排序 */} + { }} wrapperClassName={styles.menuFilter} /> +
{/* 列表内容 */} diff --git a/src/static/list/icon-filter.svg b/src/static/list/icon-filter.svg new file mode 100644 index 0000000..dd5b39a --- /dev/null +++ b/src/static/list/icon-filter.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/store/listStore.ts b/src/store/listStore.ts index d64d49e..3a61d67 100644 --- a/src/store/listStore.ts +++ b/src/store/listStore.ts @@ -16,15 +16,16 @@ export interface TennisMatch { } // Store 状态接口 -interface TennisState { +interface ListState { matches: TennisMatch[] loading: boolean error: string | null lastRefreshTime: string | null + isShowFilterPopup: boolean } // Store Actions 接口 -interface TennisActions { +interface ListActions { fetchMatches: (params?: { page?: number pageSize?: number @@ -33,36 +34,39 @@ interface TennisActions { }) => Promise refreshMatches: () => Promise clearError: () => void + updateState: (payload: Record) => void } // 完整的 Store 类型 -type TennisStore = TennisState & TennisActions +type TennisStore = ListState & ListActions // 创建 store -export const useTennisStore = create()((set, get) => ({ +export const useListStore = create()((set, get) => ({ // 初始状态 matches: [], loading: false, error: null, lastRefreshTime: null, + // 是否展示综合筛选弹窗 + isShowFilterPopup: false, // 获取比赛数据 fetchMatches: async (params) => { set({ loading: true, error: null }) - + try { const matches = await getTennisMatches(params) - set({ - matches, - loading: false, - lastRefreshTime: new Date().toISOString() + set({ + matches, + loading: false, + lastRefreshTime: new Date().toISOString() }) console.log('Store: 成功获取网球比赛数据:', matches.length, '条') } catch (error) { const errorMessage = error instanceof Error ? error.message : '未知错误' - set({ - error: errorMessage, - loading: false + set({ + error: errorMessage, + loading: false }) console.error('Store: 获取网球比赛数据失败:', errorMessage) } @@ -71,20 +75,20 @@ export const useTennisStore = create()((set, get) => ({ // 刷新比赛数据 refreshMatches: async () => { set({ loading: true, error: null }) - + try { const matches = await getTennisMatches() - set({ - matches, - loading: false, - lastRefreshTime: new Date().toISOString() + set({ + matches, + loading: false, + lastRefreshTime: new Date().toISOString() }) console.log('Store: 成功刷新网球比赛数据:', matches.length, '条') } catch (error) { const errorMessage = error instanceof Error ? error.message : '未知错误' - set({ - error: errorMessage, - loading: false + set({ + error: errorMessage, + loading: false }) console.error('Store: 刷新网球比赛数据失败:', errorMessage) } @@ -93,16 +97,14 @@ export const useTennisStore = create()((set, get) => ({ // 清除错误信息 clearError: () => { set({ error: null }) + }, + // 更新store数据 + updateState: (payload: Record) => { + set({ + ...(payload || {}) + }) } })) // 导出便捷的 hooks -export const useTennisMatches = () => useTennisStore((state) => state.matches) -export const useTennisLoading = () => useTennisStore((state) => state.loading) -export const useTennisError = () => useTennisStore((state) => state.error) -export const useTennisLastRefresh = () => useTennisStore((state) => state.lastRefreshTime) -export const useTennisActions = () => useTennisStore((state) => ({ - fetchMatches: state.fetchMatches, - refreshMatches: state.refreshMatches, - clearError: state.clearError -})) +export const useListState = () => useListStore((state) => state)