refactor(front-end): switch to web-based map navigation and update layouts

- Update `openMapDirection` to `openWebMapRaw` in `utils/front.ts` to open
  maps in a new browser tab (`_blank`) using raw WGS-84 coordinates.
- Adjust URL schemes for Google, AMap, Baidu, Tencent, and Apple Maps to
  support direct web navigation with `coordinate` parameters.
- Update `ClubSummary.tsx` to use `openWebMapRaw` and change the map button
  label from "Navigation" to "View Location" with a new icon.
- Add `padding-bottom` to `AppBar.tsx` in `AppBarLayout.tsx` to accommodate
  the increased bottom padding required by the updated AppBar styling.
- Remove the "Home" FloatButton from `ProfilePage.tsx` and update `routes.tsx`
  to remove the unused `ActionButtonLayout` import.
- Update navigation handlers in `AppBar.tsx` to use `replace: true` for smoother
  state management without creating new browser history entries.
This commit is contained in:
kyuuseiryuu 2026-03-16 02:04:06 +09:00
parent 2f8ce1711f
commit 4b69ed3b84
7 changed files with 67 additions and 33 deletions

View File

@ -1,4 +1,4 @@
import { CalendarOutlined, HeartOutlined, ScheduleOutlined, SearchOutlined, UserOutlined } from "@ant-design/icons"; import { HeartOutlined, ScheduleOutlined, SearchOutlined, UserOutlined } from "@ant-design/icons";
import { Button, Flex } from "antd"; import { Button, Flex } from "antd";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import styled from "styled-components"; import styled from "styled-components";
@ -12,6 +12,7 @@ const StyledContainer = styled.div`
background: #181818; background: #181818;
font-size: 16px; font-size: 16px;
padding: 8px; padding: 8px;
padding-bottom: 34px;
box-sizing: border-box; box-sizing: border-box;
.ant-btn { .ant-btn {
padding: 24px; padding: 24px;
@ -25,22 +26,22 @@ export const AppBar = () => {
<Button <Button
type="text" type="text"
icon={<ScheduleOutlined size={64} />} icon={<ScheduleOutlined size={64} />}
onClick={() => navigate('/')} onClick={() => navigate('/', { replace: true })}
/> />
<Button <Button
type="text" type="text"
icon={<HeartOutlined />} icon={<HeartOutlined />}
onClick={() => navigate('/fav-players')} onClick={() => navigate('/fav-players', { replace: true })}
/> />
<Button <Button
type="text" type="text"
icon={<SearchOutlined />} icon={<SearchOutlined />}
onClick={() => navigate('/find')} onClick={() => navigate('/find', { replace: true })}
/> />
<Button <Button
type="text" type="text"
icon={<UserOutlined />} icon={<UserOutlined />}
onClick={() => navigate('/user-center')} onClick={() => navigate('/user-center', { replace: true })}
/> />
</Flex> </Flex>
</StyledContainer> </StyledContainer>

View File

@ -3,9 +3,9 @@ import { ChangeBackground } from "./ChangeBackground";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { useRequest } from "ahooks"; import { useRequest } from "ahooks";
import type { ClubDetail } from "../types"; import type { ClubDetail } from "../types";
import { isMobile, MapType, openMapDirection } from "../utils/front"; import { isMobile, MapType, openWebMapRaw } from "../utils/front";
import type { ItemType } from "antd/es/menu/interface"; import type { ItemType } from "antd/es/menu/interface";
import { CarOutlined, NotificationOutlined } from "@ant-design/icons"; import { NotificationOutlined, PushpinOutlined } from "@ant-design/icons";
interface Props { interface Props {
clubId: string; clubId: string;
@ -33,17 +33,14 @@ export const ClubSummary = (props: Props) => {
{ {
label: '高德地图', label: '高德地图',
key: MapType.AMAP, key: MapType.AMAP,
disabled: !isMobileDevice,
}, },
{ {
label: '腾讯地图', label: '腾讯地图',
key: MapType.TENCENT, key: MapType.TENCENT,
disabled: !isMobileDevice,
}, },
{ {
label: '百度地图', label: '百度地图',
key: MapType.BAIDU, key: MapType.BAIDU,
disabled: !isMobileDevice,
}, },
] ]
}, [info]); }, [info]);
@ -65,11 +62,11 @@ export const ClubSummary = (props: Props) => {
trigger={['click']} trigger={['click']}
menu={{ menu={{
items: mapMenu, items: mapMenu,
onClick: (e) => openMapDirection(e.key as MapType, info.geo!), onClick: (e) => openWebMapRaw(e.key as MapType, info.geo!),
}} }}
> >
<Button icon={<CarOutlined />}> <Button icon={<PushpinOutlined />}>
</Button> </Button>
</Dropdown> </Dropdown>
)} )}

View File

@ -4,7 +4,7 @@ import { AppBar } from "../AppBar";
import styled from "styled-components"; import styled from "styled-components";
const StyledContainer = styled.div` const StyledContainer = styled.div`
padding-bottom: 54px; padding-bottom: 90px;
box-sizing: border-box; box-sizing: border-box;
`; `;
export const AppBarLayout = () => { export const AppBarLayout = () => {

View File

@ -1,7 +1,6 @@
import React, { useEffect, useMemo } from "react"; import React, { useEffect, useMemo } from "react";
import { Link, useLoaderData, useNavigate } from "react-router"; import { Link, useLoaderData, useNavigate } from "react-router";
import { Avatar, Divider, Flex, FloatButton, Image, Typography } from "antd"; import { Avatar, Divider, Flex, Image, Typography } from "antd";
import { HomeOutlined } from "@ant-design/icons";
import { useTitle } from "ahooks"; import { useTitle } from "ahooks";
import type { XCXProfile } from "../types/profile"; import type { XCXProfile } from "../types/profile";
import User from "../components/User"; import User from "../components/User";
@ -108,7 +107,6 @@ export default function ProfilePage() {
return ( return (
<> <>
<ChangeBackground url={profile?.realpic} /> <ChangeBackground url={profile?.realpic} />
<FloatButton icon={<HomeOutlined />} onClick={() => navigate('/')} />
<Flex vertical align="center" style={{ padding: 24 }}> <Flex vertical align="center" style={{ padding: 24 }}>
<Avatar src={profile?.realpic} size={128} /> <Avatar src={profile?.realpic} size={128} />
<Typography.Title level={2}> <Typography.Title level={2}>

View File

@ -9,7 +9,7 @@ import { CallbackPage } from "./page/Logto/Callback";
import App from "./App"; import App from "./App";
import { ClubEventsPage } from "./page/ClubEvents"; import { ClubEventsPage } from "./page/ClubEvents";
import { HydrateFallback } from "./components/HydrateFallback"; import { HydrateFallback } from "./components/HydrateFallback";
import { ActionButtonLayout, AppBarLayout } from './components/Layout'; import { AppBarLayout } from './components/Layout';
export const route = createBrowserRouter([ export const route = createBrowserRouter([
{ {

View File

@ -23,44 +23,59 @@ export const isMobile = (): boolean => {
}; };
/** /**
* * Web (使)
* @param type
* @param location ( GCJ-02 )
*/ */
export const openMapDirection = (type: MapType, location: MapLocation): void => { export const openWebMapRaw = (type: MapType, location: MapLocation): void => {
const { lat, lng, name = '目的地' } = location; const { lat, lng, name = 'Location' } = location;
const encodedName = encodeURIComponent(name); const encodedName = encodeURIComponent(name);
let url = ''; let url = '';
switch (type) { switch (type) {
case MapType.GOOGLE: case MapType.GOOGLE:
/** /**
* Google Maps Scheme * Google Maps Web API
* saddr: 起点 () * 使 query
* daddr: 终点经纬度
* directionsmode: 导航模式 (driving, walking, bicycling, transit)
*/ */
url = `https://www.google.com/maps/dir/?api=1&destination=${lat},${lng}`; url = `https://www.google.com/maps/search/?api=1&query=${lat},${lng}`;
break; break;
case MapType.AMAP: case MapType.AMAP:
url = `iosamap://path?sourceApplication=appName&dlat=${lat}&dlon=${lng}&dname=${encodedName}&dev=0&t=0`; /**
* Web
* coordinate=wgs84 GPS
* position [, ]
*/
url = `https://uri.amap.com/marker?position=${lng},${lat}&name=${encodedName}&coordinate=wgs84&callnative=0`;
break; break;
case MapType.BAIDU: case MapType.BAIDU:
url = `baidumap://map/direction?destination=name:${encodedName}|latlng:${lat},${lng}&mode=driving&coord_type=gcj02`; /**
* Web
* coord_type=wgs84 GPS
*/
url = `http://api.map.baidu.com/marker?location=${lat},${lng}&title=${encodedName}&content=${encodedName}&coord_type=wgs84&output=html&src=webapp`;
break; break;
case MapType.TENCENT: case MapType.TENCENT:
url = `qqmap://map/routeplan?type=drive&to=${encodedName}&tocoord=${lat},${lng}&referer=myapp`; /**
* Web
* Web API wgs84 gcj02
* Web
*/
url = `https://apis.map.qq.com/uri/v1/marker?marker=coord:${lat},${lng};title:${encodedName}&referer=myapp`;
break; break;
case MapType.APPLE: case MapType.APPLE:
url = `http://maps.apple.com/?daddr=${lat},${lng}&q=${encodedName}`; /**
* Apple Maps Web
* ll: 经纬度, q: 标注点名称
*/
url = `https://maps.apple.com/?ll=${lat},${lng}&q=${encodedName}`;
break; break;
} }
if (url) { if (url) {
window.open(url); window.open(url, '_blank');
} }
}; };

23
src/utils/mapUtils.ts Normal file
View File

@ -0,0 +1,23 @@
import gcoord, { CRSTypes } from 'gcoord';
/**
*
*/
export const getCorrectCoords = (lng: number, lat: number) => {
// gcoord.transform 会自动判断:
// 如果输入坐标在海外,它通常会返回原值(或根据算法处理)
// 但我们可以手动配合它的边界逻辑
// 更加显式的判断方法:
// gcoord 内部其实维护了一个边界多边形,你可以直接进行转换测试
const result = gcoord.transform(
[lng, lat], // 目标坐标
gcoord.WGS84, // 当前坐标系
gcoord.GCJ02 // 目标坐标系
);
return {
lng: result[0],
lat: result[1]
};
};