diff --git a/src/pages/index/Header.scss b/src/pages/index/Header.scss index e79ce78..d206e3b 100644 --- a/src/pages/index/Header.scss +++ b/src/pages/index/Header.scss @@ -14,10 +14,3 @@ position: absolute; z-index: 0; } - -/* 吸顶状态下的样式 */ -.nutui-sticky--fixed { - .header-bg { - height: 100%; - } -} \ No newline at end of file diff --git a/src/pages/index/Header.tsx b/src/pages/index/Header.tsx index a556a75..26e37ee 100644 --- a/src/pages/index/Header.tsx +++ b/src/pages/index/Header.tsx @@ -1,6 +1,6 @@ import {useEffect, useState} from "react"; import Taro from '@tarojs/taro'; -import {Button, Sticky, Popup, Cell, CellGroup} from '@nutui/nutui-react-taro' +import {Button, Popup, Cell, CellGroup} from '@nutui/nutui-react-taro' // import {TriangleDown} from '@nutui/icons-react-taro' import { NavBar} from '@nutui/nutui-react-taro' import {getUserInfo, getWxOpenId} from "@/api/layout"; @@ -25,7 +25,6 @@ const Header = (_: any) => { const [IsLogin, setIsLogin] = useState(true) const [statusBarHeight, setStatusBarHeight] = useState() - const [stickyStatus, setStickyStatus] = useState(false) const [userInfo] = useState() // 门店选择:用于首页展示“最近门店”,并在下单时写入订单 storeId @@ -291,12 +290,6 @@ const Header = (_: any) => { }) } - // 处理粘性布局状态变化 - const onStickyChange = (isSticky: boolean) => { - setStickyStatus(isSticky) - console.log('Header 粘性状态:', isSticky ? '已固定' : '取消固定') - } - // 获取小程序系统信息 // const getSystemInfo = () => { // const systemInfo = Taro.getSystemInfoSync() @@ -311,121 +304,114 @@ const Header = (_: any) => { return ( <> - - - {/* 只在非吸顶状态下显示搜索框 */} - {!stickyStatus && } - - { - }} - // left={ - // setStorePopupVisible(true)} - // > - // - // - // {selectedStore?.name || '请选择门店'} - // - // - // - // } - right={ - !IsLogin ? ( - - ) : null - } - > - {getTenantName()} - + + - setStorePopupVisible(false)} - > - - - 选择门店 - setStorePopupVisible(false)} - > - 关闭 - - + { + }} + // left={ + // setStorePopupVisible(true)} + // > + // + // + // {selectedStore?.name || '请选择门店'} + // + // + // + // } + right={ + !IsLogin ? ( + + ) : null + } + > + {getTenantName()} + - - {userLocation ? '已获取定位,按距离排序' : '未获取定位,可手动选择门店'} - - - - {[...stores] - .sort((a, b) => (getStoreDistance(a) ?? Number.POSITIVE_INFINITY) - (getStoreDistance(b) ?? Number.POSITIVE_INFINITY)) - .map((s) => { - const d = getStoreDistance(s) - const isActive = !!selectedStore?.id && selectedStore.id === s.id - return ( - - {s.name || `门店${s.id}`} - {d !== undefined && {formatDistance(d)}} - - } - description={s.address || ''} - onClick={async () => { - let storeToSave = s - if (s?.id) { - try { - const full = await getShopStore(s.id) - if (full) storeToSave = full - } catch (_e) { - // keep base item - } - } - setSelectedStore(storeToSave) - saveSelectedStoreToStorage(storeToSave) - setStorePopupVisible(false) - Taro.showToast({title: '门店已切换', icon: 'success'}) - }} - /> - ) - })} - + setStorePopupVisible(false)} + > + + + 选择门店 + setStorePopupVisible(false)} + > + 关闭 + - - + + + {userLocation ? '已获取定位,按距离排序' : '未获取定位,可手动选择门店'} + + + + {[...stores] + .sort((a, b) => (getStoreDistance(a) ?? Number.POSITIVE_INFINITY) - (getStoreDistance(b) ?? Number.POSITIVE_INFINITY)) + .map((s) => { + const d = getStoreDistance(s) + const isActive = !!selectedStore?.id && selectedStore.id === s.id + return ( + + {s.name || `门店${s.id}`} + {d !== undefined && {formatDistance(d)}} + + } + description={s.address || ''} + onClick={async () => { + let storeToSave = s + if (s?.id) { + try { + const full = await getShopStore(s.id) + if (full) storeToSave = full + } catch (_e) { + // keep base item + } + } + setSelectedStore(storeToSave) + saveSelectedStoreToStorage(storeToSave) + setStorePopupVisible(false) + Taro.showToast({title: '门店已切换', icon: 'success'}) + }} + /> + ) + })} + + + ) } diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index a80704e..435583a 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -234,7 +234,7 @@ function Home() { return ( <> - {/* Header区域 - 现在由Header组件内部处理吸顶逻辑 */} + {/* Header区域 */}
diff --git a/src/user/address/add.tsx b/src/user/address/add.tsx index 0f5c1e9..2b5234a 100644 --- a/src/user/address/add.tsx +++ b/src/user/address/add.tsx @@ -1,6 +1,6 @@ import {useEffect, useState, useRef} from "react"; import {useRouter} from '@tarojs/taro' -import {Button, Loading, CellGroup, Input, TextArea, Form} from '@nutui/nutui-react-taro' +import {Button, Loading, CellGroup, Cell, Input, TextArea, Form} from '@nutui/nutui-react-taro' import {Scan, ArrowRight} from '@nutui/icons-react-taro' import Taro from '@tarojs/taro' import {View} from '@tarojs/components' @@ -9,7 +9,24 @@ import {ShopUserAddress} from "@/api/shop/shopUserAddress/model"; import {getShopUserAddress, listShopUserAddress, updateShopUserAddress, addShopUserAddress} from "@/api/shop/shopUserAddress"; import RegionData from '@/api/json/regions-data.json'; import FixedButton from "@/components/FixedButton"; -import { getCurrentLngLat } from "@/utils/location"; + +type SelectedLocation = { lng: string; lat: string; name?: string; address?: string } + +const isLocationDenied = (e: any) => { + const msg = String(e?.errMsg || e?.message || e || '') + return ( + msg.includes('auth deny') || + msg.includes('authorize') || + msg.includes('permission') || + msg.includes('denied') || + msg.includes('scope.userLocation') + ) +} + +const isUserCancel = (e: any) => { + const msg = String(e?.errMsg || e?.message || e || '') + return msg.includes('cancel') +} const AddUserAddress = () => { const {params} = useRouter(); @@ -19,6 +36,7 @@ const AddUserAddress = () => { const [visible, setVisible] = useState(false) const [FormData, setFormData] = useState({}) const [inputText, setInputText] = useState('') + const [selectedLocation, setSelectedLocation] = useState(null) const formRef = useRef(null) // 判断是编辑还是新增模式 @@ -36,6 +54,10 @@ const AddUserAddress = () => { setFormData(address) // 设置所在地区 setText(`${address.province} ${address.city} ${address.region}`) + // 回显已保存的经纬度(编辑模式) + if (address?.lng && address?.lat) { + setSelectedLocation({ lng: String(address.lng), lat: String(address.lat) }) + } } catch (error) { console.error('加载地址失败:', error) Taro.showToast({ @@ -211,10 +233,111 @@ const AddUserAddress = () => { return null; }; + // 选择定位:打开地图让用户选点,保存经纬度到表单数据 + const chooseGeoLocation = async () => { + const applyChosenLocation = (res: any) => { + if (!res) return + if (res.latitude === undefined || res.longitude === undefined) { + Taro.showToast({ title: '定位信息获取失败', icon: 'none' }) + return + } + + const next: SelectedLocation = { + lng: String(res.longitude), + lat: String(res.latitude), + name: res.name, + address: res.address + } + setSelectedLocation(next) + + // 将地图选点的地址同步到“收货地址”,减少用户重复输入 + const nextDetailAddress = (() => { + const addr = String(res.address || '').trim() + const name = String(res.name || '').trim() + if (!addr && !name) return '' + if (!addr) return name + if (!name) return addr + return addr.includes(name) ? addr : `${addr} ${name}` + })() + + // 尝试从地图返回的 address 文本解析省市区(best-effort) + const regionResult = res?.provinceName || res?.cityName || res?.adName + ? { + province: String(res.provinceName || ''), + city: String(res.cityName || ''), + region: String(res.adName || '') + } + : parseRegion(String(res.address || '')) + + setFormData(prev => ({ + ...prev, + lng: next.lng, + lat: next.lat, + address: nextDetailAddress || prev.address, + province: regionResult?.province || prev.province, + city: regionResult?.city || prev.city, + region: regionResult?.region || prev.region + })) + + if (regionResult?.province && regionResult?.city && regionResult?.region) { + setText(`${regionResult.province} ${regionResult.city} ${regionResult.region}`) + } + + // 更新表单展示值(Form initialValues 不会跟随 FormData 变化) + if (formRef.current) { + const patch: any = {} + if (nextDetailAddress) patch.address = nextDetailAddress + if (regionResult?.region) patch.region = regionResult.region + formRef.current.setFieldsValue(patch) + } + } + + try { + const initLat = selectedLocation?.lat ? Number(selectedLocation.lat) : undefined + const initLng = selectedLocation?.lng ? Number(selectedLocation.lng) : undefined + const res = await Taro.chooseLocation({ + latitude: Number.isFinite(initLat as number) ? (initLat as number) : undefined, + longitude: Number.isFinite(initLng as number) ? (initLng as number) : undefined + }) + applyChosenLocation(res) + } catch (e: any) { + console.warn('选择定位失败:', e) + if (isUserCancel(e)) return + if (isLocationDenied(e)) { + try { + const modal = await Taro.showModal({ + title: '需要定位权限', + content: '选择定位需要开启定位权限,请在设置中开启后重试。', + confirmText: '去设置' + }) + if (modal.confirm) { + await Taro.openSetting() + // 权限可能刚被开启:重试一次 + const res = await Taro.chooseLocation({}) + applyChosenLocation(res) + } + } catch (_e) { + // ignore + } + return + } + try { + await Taro.showToast({ title: '打开地图失败,请重试', icon: 'none' }) + } catch (_e) { + // ignore + } + } + } + // 提交表单 const submitSucceed = async (values: any) => { - const loc = await getCurrentLngLat() - if (!loc) return + const loc = + selectedLocation || + (FormData?.lng && FormData?.lat ? { lng: String(FormData.lng), lat: String(FormData.lat) } : null) + if (!loc) { + Taro.showToast({ title: '请选择定位', icon: 'none' }) + return + } try { // 准备提交的数据 @@ -329,6 +452,28 @@ const AddUserAddress = () => { + + +
+ {selectedLocation?.name || (selectedLocation ? '已选择' : '请选择')} +
+ + + )} + onClick={chooseGeoLocation} + /> +
+ @@ -371,14 +516,14 @@ const AddUserAddress = () => { /> {/* 底部浮动按钮 */} - { // 触发表单提交 if (formRef.current) { formRef.current.submit(); } - }} + }} /> );