Merge branch 'feat/liujie'
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
@use '~@/scss/themeColor.scss' as theme;
|
@use "~@/scss/themeColor.scss" as theme;
|
||||||
|
|
||||||
.common-popup {
|
.common-popup {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
background-color: rgba(22, 24, 35, 0.20);
|
background-color: rgba(22, 24, 35, 0.2);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -48,13 +48,18 @@
|
|||||||
padding: 8px 10px 0 10px;
|
padding: 8px 10px 0 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
background: #FFF;
|
background: #fff;
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.common-popup__btn {
|
.common-popup__btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
font-feature-settings: "liga" off, "clig" off;
|
||||||
|
font-family: "PingFang SC";
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.common-popup__btn-cancel {
|
.common-popup__btn-cancel {
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 999;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
z-index: 999;
|
z-index: 9991;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
72
src/components/Picker/CityPicker.tsx
Normal file
72
src/components/Picker/CityPicker.tsx
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import CommonPopup from "@/components/CommonPopup";
|
||||||
|
import Picker from "./Picker";
|
||||||
|
interface PickerOption {
|
||||||
|
text: string | number;
|
||||||
|
value: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PickerProps {
|
||||||
|
visible: boolean;
|
||||||
|
setvisible: (visible: boolean) => void;
|
||||||
|
options?: PickerOption[][] | PickerOption[];
|
||||||
|
value?: (string | number)[];
|
||||||
|
type?: "month" | "day" | "hour" | "ntrp" | null;
|
||||||
|
img?: string;
|
||||||
|
onConfirm?: (options: PickerOption[], values: (string | number)[]) => void;
|
||||||
|
onChange?: (value: (string | number)[]) => void;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PopupPicker = ({
|
||||||
|
visible,
|
||||||
|
setvisible,
|
||||||
|
value = [],
|
||||||
|
onConfirm,
|
||||||
|
onChange,
|
||||||
|
options = [],
|
||||||
|
style,
|
||||||
|
}: PickerProps) => {
|
||||||
|
const [defaultValue, setDefaultValue] = useState<(string | number)[]>(value);
|
||||||
|
const changePicker = (_options: any[], values: any, _columnIndex: number) => {
|
||||||
|
setDefaultValue(values);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirm = () => {
|
||||||
|
console.log(defaultValue, "defaultValue");
|
||||||
|
onChange?.(defaultValue);
|
||||||
|
setvisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dialogClose = () => {
|
||||||
|
setvisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CommonPopup
|
||||||
|
visible={visible}
|
||||||
|
onClose={dialogClose}
|
||||||
|
showHeader={false}
|
||||||
|
title={null}
|
||||||
|
hideFooter={false}
|
||||||
|
cancelText="取消"
|
||||||
|
confirmText="完成"
|
||||||
|
onConfirm={handleConfirm}
|
||||||
|
position="bottom"
|
||||||
|
round
|
||||||
|
zIndex={1000}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<Picker
|
||||||
|
visible={visible}
|
||||||
|
options={options}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
onChange={changePicker}
|
||||||
|
/>
|
||||||
|
</CommonPopup>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PopupPicker;
|
||||||
@@ -4,3 +4,4 @@ export { default as PickerCommon } from './PickerCommon'
|
|||||||
export type { PickerCommonRef } from './PickerCommon'
|
export type { PickerCommonRef } from './PickerCommon'
|
||||||
export { default as CalendarUI } from './CalendarUI/CalendarUI'
|
export { default as CalendarUI } from './CalendarUI/CalendarUI'
|
||||||
export { default as DialogCalendarCard } from './CalendarDialog/DialogCalendarCard'
|
export { default as DialogCalendarCard } from './CalendarDialog/DialogCalendarCard'
|
||||||
|
export { default as CityPicker } from './CityPicker'
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
import { View, Text, Image } from "@tarojs/components";
|
import { View, Text, Image } from "@tarojs/components";
|
||||||
import img from "@/config/images";
|
import img from "@/config/images";
|
||||||
import { useGlobalState } from "@/store/global";
|
import { useGlobalState } from "@/store/global";
|
||||||
import { useUserInfo, } from '@/store/userStore'
|
import { useUserInfo } from "@/store/userStore";
|
||||||
import { useListState } from "@/store/listStore";
|
import { useListState } from "@/store/listStore";
|
||||||
import CustomNavbar from "@/components/CustomNavbar";
|
import CustomNavbar from "@/components/CustomNavbar";
|
||||||
import { Input } from "@nutui/nutui-react-taro";
|
import { Input } from "@nutui/nutui-react-taro";
|
||||||
import Taro from "@tarojs/taro";
|
import Taro from "@tarojs/taro";
|
||||||
import "./index.scss";
|
import "./index.scss";
|
||||||
import { getCurrentFullPath } from "@/utils";
|
import { getCurrentFullPath } from "@/utils";
|
||||||
|
import { CityPicker as PopupPicker } from "@/components/Picker";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
config?: {
|
config?: {
|
||||||
@@ -18,30 +20,60 @@ interface IProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CityPicker(props) {
|
||||||
|
const { visible, setVisible, cities, area, setArea } = props;
|
||||||
|
console.log(cities, "cities");
|
||||||
|
const [index, setIndex] = useState(0);
|
||||||
|
const [value, setValue] = useState(area);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (visible) {
|
||||||
|
setIndex(index + 1);
|
||||||
|
}
|
||||||
|
}, [visible]);
|
||||||
|
|
||||||
|
function onChange(value: any) {
|
||||||
|
console.log(value, "value");
|
||||||
|
setValue(value);
|
||||||
|
setArea(value);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
visible && (
|
||||||
|
<PopupPicker
|
||||||
|
key={index}
|
||||||
|
options={cities}
|
||||||
|
visible={visible}
|
||||||
|
setvisible={setVisible}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
style={{ zIndex: 9991 }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const ListHeader = (props: IProps) => {
|
const ListHeader = (props: IProps) => {
|
||||||
const { config } = props;
|
const { config } = props;
|
||||||
const {
|
const { showInput = false, inputLeftIcon, leftIconClick } = config || {};
|
||||||
showInput = false,
|
const { getLocationLoading, statusNavbarHeightInfo } = useGlobalState();
|
||||||
inputLeftIcon,
|
const { gamesNum, searchValue, cities, area, updateArea } = useListState();
|
||||||
leftIconClick,
|
|
||||||
} = config || {};
|
|
||||||
const {
|
|
||||||
getLocationLoading,
|
|
||||||
statusNavbarHeightInfo,
|
|
||||||
} = useGlobalState();
|
|
||||||
const { gamesNum, searchValue } = useListState();
|
|
||||||
const { navBarHeight } = statusNavbarHeightInfo;
|
const { navBarHeight } = statusNavbarHeightInfo;
|
||||||
|
|
||||||
const userInfo = useUserInfo()
|
const [cityPopupVisible, setCityPopupVisible] = useState(false);
|
||||||
const city = (userInfo as any)?.city || ''
|
|
||||||
const district = (userInfo as any)?.district || ''
|
|
||||||
|
|
||||||
console.log("useUserInfo",city,district )
|
const userInfo = useUserInfo();
|
||||||
|
const province = (userInfo as any)?.province || "";
|
||||||
|
const city = (userInfo as any)?.city || "";
|
||||||
|
// const district = (userInfo as any)?.district || "";
|
||||||
|
|
||||||
const currentAddress = city + district
|
useEffect(() => {
|
||||||
|
updateArea(["中国", province, city]);
|
||||||
|
}, [province, city]);
|
||||||
|
|
||||||
|
// const currentAddress = city + district;
|
||||||
|
|
||||||
const handleInputClick = () => {
|
const handleInputClick = () => {
|
||||||
const currentPagePath = getCurrentFullPath()
|
const currentPagePath = getCurrentFullPath();
|
||||||
if (currentPagePath === "/game_pages/searchResult/index") {
|
if (currentPagePath === "/game_pages/searchResult/index") {
|
||||||
Taro.navigateBack();
|
Taro.navigateBack();
|
||||||
} else {
|
} else {
|
||||||
@@ -77,6 +109,11 @@ const ListHeader = (props: IProps) => {
|
|||||||
height: `${navBarHeight}px`,
|
height: `${navBarHeight}px`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function handleToggleCity() {
|
||||||
|
setCityPopupVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const area_city = area.at(-1);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomNavbar>
|
<CustomNavbar>
|
||||||
@@ -96,10 +133,10 @@ const ListHeader = (props: IProps) => {
|
|||||||
/>
|
/>
|
||||||
<View className="listNavLine" />
|
<View className="listNavLine" />
|
||||||
<View className="listNavContent">
|
<View className="listNavContent">
|
||||||
<View className="listNavCityWrapper">
|
<View className="listNavCityWrapper" onClick={handleToggleCity}>
|
||||||
{/* 位置 */}
|
{/* 位置 */}
|
||||||
<Text className="listNavCity">{currentAddress}</Text>
|
<Text className="listNavCity">{area_city}</Text>
|
||||||
{!getLocationLoading && currentAddress && (
|
{!getLocationLoading && area_city && (
|
||||||
<Image src={img.ICON_CHANGE} className="listNavChange" />
|
<Image src={img.ICON_CHANGE} className="listNavChange" />
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
@@ -111,7 +148,8 @@ const ListHeader = (props: IProps) => {
|
|||||||
</View>
|
</View>
|
||||||
{/* 搜索导航 */}
|
{/* 搜索导航 */}
|
||||||
<View
|
<View
|
||||||
className={`inputCustomerNavbarContainer toggleElement secondElement hidden ${showInput && "visible"
|
className={`inputCustomerNavbarContainer toggleElement secondElement hidden ${
|
||||||
|
showInput && "visible"
|
||||||
} ${showInput ? "inputCustomerNavbarShowInput" : ""}`}
|
} ${showInput ? "inputCustomerNavbarShowInput" : ""}`}
|
||||||
style={navbarStyle}
|
style={navbarStyle}
|
||||||
>
|
>
|
||||||
@@ -139,6 +177,13 @@ const ListHeader = (props: IProps) => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
<CityPicker
|
||||||
|
visible={cityPopupVisible}
|
||||||
|
setVisible={setCityPopupVisible}
|
||||||
|
cities={cities}
|
||||||
|
area={area}
|
||||||
|
setArea={updateArea}
|
||||||
|
/>
|
||||||
</CustomNavbar>
|
</CustomNavbar>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,79 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cqContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
// gap: 24px;
|
||||||
|
|
||||||
|
.tips {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.tip1 {
|
||||||
|
color: #000;
|
||||||
|
text-align: center;
|
||||||
|
font-family: "PingFang SC";
|
||||||
|
font-size: 18px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip2 {
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
text-align: center;
|
||||||
|
font-family: "PingFang SC";
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcodeWrappper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.qrcode {
|
||||||
|
width: 180px;
|
||||||
|
height: 180px;
|
||||||
|
// border-radius: 12px;
|
||||||
|
// border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
// background: lightgray 50% / cover no-repeat;
|
||||||
|
// box-shadow: 0 4px 36px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcodeTip {
|
||||||
|
color: rgba(0, 0, 0, 0.65);
|
||||||
|
text-align: center;
|
||||||
|
font-family: "PingFang SC";
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: normal;
|
||||||
|
margin-top: -30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.listPage {
|
.listPage {
|
||||||
background-color: #fefefe;
|
background-color: #fefefe;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import Taro, {
|
|||||||
} from "@tarojs/taro";
|
} from "@tarojs/taro";
|
||||||
import { useListStore } from "@/store/listStore";
|
import { useListStore } from "@/store/listStore";
|
||||||
import { useGlobalState } from "@/store/global";
|
import { useGlobalState } from "@/store/global";
|
||||||
import { View } from "@tarojs/components";
|
import { View, Image, Text } from "@tarojs/components";
|
||||||
import CustomerNavBar from "@/container/listCustomNavbar";
|
import CustomerNavBar from "@/container/listCustomNavbar";
|
||||||
import GuideBar from "@/components/GuideBar";
|
import GuideBar from "@/components/GuideBar";
|
||||||
import ListContainer from "@/container/listContainer";
|
import ListContainer from "@/container/listContainer";
|
||||||
@@ -19,7 +19,7 @@ import { updateUserLocation } from "@/services/userService";
|
|||||||
// import ShareCardCanvas from "@/components/ShareCardCanvas";
|
// import ShareCardCanvas from "@/components/ShareCardCanvas";
|
||||||
import { useUserActions } from "@/store/userStore";
|
import { useUserActions } from "@/store/userStore";
|
||||||
import { useDictionaryStore } from "@/store/dictionaryStore";
|
import { useDictionaryStore } from "@/store/dictionaryStore";
|
||||||
// import generateShareImage from '@/utils/share'
|
import { saveImage } from "@/utils";
|
||||||
|
|
||||||
const ListPage = () => {
|
const ListPage = () => {
|
||||||
// 从 store 获取数据和方法
|
// 从 store 获取数据和方法
|
||||||
@@ -47,6 +47,10 @@ const ListPage = () => {
|
|||||||
loadMoreMatches,
|
loadMoreMatches,
|
||||||
fetchGetGamesCount,
|
fetchGetGamesCount,
|
||||||
updateDistanceQuickFilter,
|
updateDistanceQuickFilter,
|
||||||
|
getCities,
|
||||||
|
getCityQrCode,
|
||||||
|
area,
|
||||||
|
cityQrCode,
|
||||||
} = store;
|
} = store;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -104,6 +108,8 @@ const ListPage = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getLocation();
|
getLocation();
|
||||||
fetchUserInfo();
|
fetchUserInfo();
|
||||||
|
getCities();
|
||||||
|
getCityQrCode();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 监听数据变化,如果是第一页就滚动到顶部
|
// 监听数据变化,如果是第一页就滚动到顶部
|
||||||
@@ -317,6 +323,44 @@ const ListPage = () => {
|
|||||||
// })
|
// })
|
||||||
// }, [])
|
// }, [])
|
||||||
|
|
||||||
|
const area_city = area.at(-2);
|
||||||
|
|
||||||
|
function renderCityQrcode() {
|
||||||
|
let item = cityQrCode.find((item) => item.city_name === area_city);
|
||||||
|
if (!item) item = cityQrCode.find((item) => item.city_name === "其他");
|
||||||
|
return (
|
||||||
|
<View className={styles.cqContainer}>
|
||||||
|
{item ? (
|
||||||
|
<View className={styles.wrapper}>
|
||||||
|
<View className={styles.tips}>
|
||||||
|
<Text className={styles.tip1}>当前城市暂无球局</Text>
|
||||||
|
<Text className={styles.tip2}>
|
||||||
|
加入城市球友群,获得最新球局消息
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View className={styles.qrcodeWrappper}>
|
||||||
|
<Image
|
||||||
|
className={styles.qrcode}
|
||||||
|
src={item.qr_code_url}
|
||||||
|
mode="widthFix"
|
||||||
|
onClick={() => {
|
||||||
|
saveImage(item.qr_code_url);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Text className={styles.qrcodeTip}>
|
||||||
|
点击图片保存,使用微信扫码加入群聊
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View>
|
||||||
|
<Text>当前城市暂无球局, 敬请期待</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* 自定义导航 */}
|
{/* 自定义导航 */}
|
||||||
@@ -325,6 +369,9 @@ const ListPage = () => {
|
|||||||
showInput: isShowInputCustomerNavBar,
|
showInput: isShowInputCustomerNavBar,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{area_city !== "上海" ? (
|
||||||
|
renderCityQrcode()
|
||||||
|
) : (
|
||||||
<View ref={scrollContextRef}>
|
<View ref={scrollContextRef}>
|
||||||
{/* 列表内容 */}
|
{/* 列表内容 */}
|
||||||
<View className={styles.listPage} style={{ paddingTop: totalHeight }}>
|
<View className={styles.listPage} style={{ paddingTop: totalHeight }}>
|
||||||
@@ -384,23 +431,7 @@ const ListPage = () => {
|
|||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{/* 测试分享功能 */}
|
)}
|
||||||
{/* <ShareCardCanvas data={
|
|
||||||
{
|
|
||||||
userAvatar: "https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/63f62c80-ac44-4f3b-bb6c-d7f6e8ebf76d.jpg",
|
|
||||||
userNickname: "华巴抡卡",
|
|
||||||
gameType: "单打",
|
|
||||||
skillLevel: "NTRP 2.5 - 3.0",
|
|
||||||
gameDate: "6月20日(周五)",
|
|
||||||
gameTime: "下午5点 2小时",
|
|
||||||
venueName: "因乐驰网球俱乐部(嘉定江桥万达店)",
|
|
||||||
venueImages: ["https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/63f62c80-ac44-4f3b-bb6c-d7f6e8ebf76d.jpg",
|
|
||||||
"https://bimwe.oss-cn-shanghai.aliyuncs.com/front/ball/images/63f62c80-ac44-4f3b-bb6c-d7f6e8ebf76d.jpg"
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onGenerated={handleShare}
|
|
||||||
/> */}
|
|
||||||
<GuideBar currentPage="list" />
|
<GuideBar currentPage="list" />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -553,8 +553,13 @@ function Result() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
const url = await genCardImage();
|
const url = await genCardImage();
|
||||||
Taro.saveImageToPhotosAlbum({ filePath: url });
|
Taro.saveImageToPhotosAlbum({ filePath: url });
|
||||||
|
Taro.showToast({ title: "保存成功" });
|
||||||
|
} catch (e) {
|
||||||
|
Taro.showToast({ title: "图片保存失败", icon: "none" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,3 +109,26 @@ export const searchSuggestion = async (params) => {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getCities = async () => {
|
||||||
|
try {
|
||||||
|
// 调用HTTP服务获取城市列表
|
||||||
|
return httpService.post('/cities/tree', {})
|
||||||
|
} catch (error) {
|
||||||
|
// 捕获并打印错误信息
|
||||||
|
console.error("城市列表获取失败:", error);
|
||||||
|
// 抛出错误以便上层处理
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export const getCityQrCode = async () => {
|
||||||
|
try {
|
||||||
|
// 调用HTTP服务获取城市二维码
|
||||||
|
return httpService.post('/hot_city_qr/list', {})
|
||||||
|
} catch (error) {
|
||||||
|
// 捕获并打印错误信息
|
||||||
|
console.error("城市二维码获取失败:", error);
|
||||||
|
// 抛出错误以便上层处理
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
clearHistory,
|
clearHistory,
|
||||||
searchSuggestion,
|
searchSuggestion,
|
||||||
getGamesCount,
|
getGamesCount,
|
||||||
|
getCities,
|
||||||
|
getCityQrCode,
|
||||||
} from "../services/listApi";
|
} from "../services/listApi";
|
||||||
import {
|
import {
|
||||||
ListActions,
|
ListActions,
|
||||||
@@ -15,6 +17,19 @@ import {
|
|||||||
IPayload,
|
IPayload,
|
||||||
} from "../../types/list/types";
|
} from "../../types/list/types";
|
||||||
|
|
||||||
|
function translateCityData(dataTree) {
|
||||||
|
return dataTree.map((item) => {
|
||||||
|
const { children, ...rest } = item;
|
||||||
|
return {
|
||||||
|
...rest,
|
||||||
|
text: rest.name,
|
||||||
|
label: rest.name,
|
||||||
|
value: rest.name,
|
||||||
|
children: children?.length > 0 ? translateCityData(children) : null,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 完整的 Store 类型
|
// 完整的 Store 类型
|
||||||
type TennisStore = ListState & ListActions;
|
type TennisStore = ListState & ListActions;
|
||||||
@@ -138,6 +153,9 @@ const commonStateDefaultValue = {
|
|||||||
{ id: 5, label: "晚上 18:00-22:00", value: "18:00-22: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" },
|
{ id: 6, label: "夜间 22:00-24:00", value: "22:00-24:00" },
|
||||||
],
|
],
|
||||||
|
cities: [],
|
||||||
|
cityQrCode: [],
|
||||||
|
area: ['', '', ''] as [string, string, string],
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 store
|
// 创建 store
|
||||||
@@ -486,6 +504,32 @@ export const useListStore = create<TennisStore>()((set, get) => ({
|
|||||||
});
|
});
|
||||||
console.log("===更新搜索页状态:", state);
|
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,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
updateArea(payload: [string, string, string]) {
|
||||||
|
const state = get();
|
||||||
|
set({
|
||||||
|
...state,
|
||||||
|
area: payload,
|
||||||
|
})
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// 导出便捷的 hooks
|
// 导出便捷的 hooks
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ export * from './orderActions';
|
|||||||
export * from './routeUtil';
|
export * from './routeUtil';
|
||||||
export * from './share'
|
export * from './share'
|
||||||
export * from './genPoster'
|
export * from './genPoster'
|
||||||
|
export * from './wx_helper'
|
||||||
|
|||||||
35
src/utils/wx_helper.ts
Normal file
35
src/utils/wx_helper.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import Taro from "@tarojs/taro";
|
||||||
|
|
||||||
|
export function saveImage(url) {
|
||||||
|
Taro.getSetting().then(async (res) => {
|
||||||
|
if (!res.authSetting["scope.writePhotosAlbum"]) {
|
||||||
|
Taro.authorize({
|
||||||
|
scope: "scope.writePhotosAlbum",
|
||||||
|
success: async () => {
|
||||||
|
try {
|
||||||
|
Taro.saveImageToPhotosAlbum({ filePath: url });
|
||||||
|
Taro.showToast({ title: "保存成功" });
|
||||||
|
} catch (e) {
|
||||||
|
Taro.showToast({ title: "图片保存失败", icon: "none" });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
Taro.showModal({
|
||||||
|
title: "提示",
|
||||||
|
content: "需要开启相册权限才能保存图片",
|
||||||
|
success: (r) => {
|
||||||
|
if (r.confirm) Taro.openSetting();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Taro.saveImageToPhotosAlbum({ filePath: url });
|
||||||
|
Taro.showToast({ title: "保存成功" });
|
||||||
|
} catch (e) {
|
||||||
|
Taro.showToast({ title: "图片保存失败", icon: "none" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -55,6 +55,20 @@ export interface SearchPageState extends PageState {
|
|||||||
searchHistoryParams: Record<string, any>
|
searchHistoryParams: Record<string, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CityTree {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
children: CityTree[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CityQrCodeItem {
|
||||||
|
id: number,
|
||||||
|
city_name: string,
|
||||||
|
qr_code_url: string,
|
||||||
|
description: string,
|
||||||
|
sort_order: number
|
||||||
|
}
|
||||||
|
|
||||||
// 主状态接口
|
// 主状态接口
|
||||||
export interface ListState {
|
export interface ListState {
|
||||||
currentPage: string
|
currentPage: string
|
||||||
@@ -73,6 +87,9 @@ export interface ListState {
|
|||||||
timeBubbleData: BubbleOption[]
|
timeBubbleData: BubbleOption[]
|
||||||
dateRangeOptions: BubbleOption[]
|
dateRangeOptions: BubbleOption[]
|
||||||
gamesNum: number
|
gamesNum: number
|
||||||
|
cities: CityTree[]
|
||||||
|
cityQrCode: CityQrCodeItem[]
|
||||||
|
area: [string, string, string]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListActions {
|
export interface ListActions {
|
||||||
@@ -96,6 +113,9 @@ export interface ListActions {
|
|||||||
getCurrentPageState: () => { currentPageState: any; currentPageKey: string }
|
getCurrentPageState: () => { currentPageState: any; currentPageKey: string }
|
||||||
updateCurrentPageState: (payload: Record<string, any>) => void
|
updateCurrentPageState: (payload: Record<string, any>) => void
|
||||||
updateDistanceQuickFilter: (payload: Record<string, any>) => void
|
updateDistanceQuickFilter: (payload: Record<string, any>) => void
|
||||||
|
getCities: () => Promise<void>
|
||||||
|
getCityQrCode: () => Promise<void>
|
||||||
|
updateArea: (payload: [string, string, string]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPayload {
|
export interface IPayload {
|
||||||
|
|||||||
Reference in New Issue
Block a user