- 新增 react-simple-maps 地图库 - 实现中国省级行政区划地图(34 个省份) - 首页集成地图组件,点击省份跳转城市列表 - 悬停显示省份名称,热力图颜色表示内容丰富度 - 重构 stores 导出方式,支持 hooks 模式
178 lines
5.0 KiB
JavaScript
178 lines
5.0 KiB
JavaScript
import React from 'react';
|
|
import { Routes, Route, useParams, useNavigate } from 'react-router-dom';
|
|
import { observer } from 'mobx-react-lite';
|
|
import styled from 'styled-components';
|
|
import { useAuthStore } from './stores/AuthStore';
|
|
import { useUserStore } from './stores/UserStore';
|
|
import { useRegionStore } from './stores/RegionStore';
|
|
import Layout from './components/common/Layout';
|
|
import Loading from './components/common/Loading';
|
|
import ChinaMap from './components/common/ChinaMap';
|
|
import CitiesPage from './components/region/CitiesPage';
|
|
import CityDetailPage from './components/region/CityDetailPage';
|
|
import ArticleDetailPage from './components/article/ArticleDetailPage';
|
|
import ServiceDetailPage from './components/service/ServiceDetailPage';
|
|
import LoginPage from './components/auth/LoginPage';
|
|
import RegisterPage from './components/auth/RegisterPage';
|
|
|
|
const Container = styled.div`
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
`;
|
|
|
|
const Header = styled.header`
|
|
margin-bottom: 30px;
|
|
padding-bottom: 20px;
|
|
border-bottom: 2px solid #eee;
|
|
`;
|
|
|
|
const Title = styled.h1`
|
|
margin: 0;
|
|
font-size: 28px;
|
|
`;
|
|
|
|
function App() {
|
|
const authStore = useAuthStore();
|
|
|
|
// Fetch current user on app load
|
|
React.useEffect(() => {
|
|
if (authStore.isAuthenticated) {
|
|
authStore.fetchCurrentUser();
|
|
}
|
|
}, [authStore]);
|
|
|
|
return (
|
|
<Layout title="城市手册" subtitle="地方志兼本地生活服务平台">
|
|
<Routes>
|
|
<Route path="/" element={<HomePage />} />
|
|
<Route path="/cities" element={<CitiesPage />} />
|
|
<Route path="/cities/:regionId" element={<CityDetailPage />} />
|
|
<Route path="/articles/:articleId" element={<ArticleDetailPageWrapper />} />
|
|
<Route path="/services/:serviceId" element={<ServiceDetailPageWrapper />} />
|
|
<Route path="/login" element={<LoginPage />} />
|
|
<Route path="/register" element={<RegisterPage />} />
|
|
<Route path="/user/profile" element={<UserProfilePage />} />
|
|
<Route path="*" element={<NotFoundPage />} />
|
|
</Routes>
|
|
</Layout>
|
|
);
|
|
}
|
|
|
|
const ArticleDetailPageWrapper = observer(() => {
|
|
const { articleId } = useParams();
|
|
return <ArticleDetailPage articleId={articleId} />;
|
|
});
|
|
|
|
const ServiceDetailPageWrapper = observer(() => {
|
|
const { serviceId } = useParams();
|
|
return <ServiceDetailPage serviceId={serviceId} />;
|
|
});
|
|
|
|
const HomePage = observer(() => {
|
|
const navigate = useNavigate();
|
|
const regionStore = useRegionStore();
|
|
const [loading, setLoading] = React.useState(false);
|
|
|
|
const handleProvinceClick = async (geo) => {
|
|
const provinceName = geo.properties.name;
|
|
const provinceCode = geo.properties.code;
|
|
|
|
setLoading(true);
|
|
try {
|
|
// 先获取所有省份列表,找到对应的 region ID
|
|
await regionStore.fetchProvinces();
|
|
const province = regionStore.regions.find(
|
|
r => r.name === provinceName || r.code === provinceCode
|
|
);
|
|
|
|
if (province) {
|
|
navigate(`/cities/${province.id}`);
|
|
} else {
|
|
// 如果没有找到,跳转到城市列表页并带上省份名称
|
|
navigate(`/cities?province=${encodeURIComponent(provinceName)}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to navigate to province:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Container>
|
|
<Header>
|
|
<Title>欢迎来到城市手册</Title>
|
|
<p>探索每个城市的故事与特色</p>
|
|
</Header>
|
|
|
|
{loading ? (
|
|
<Loading message="加载中..." />
|
|
) : (
|
|
<ChinaMap onProvinceClick={handleProvinceClick} />
|
|
)}
|
|
|
|
<div style={{ marginTop: '40px' }}>
|
|
<h2>📚 最新文章</h2>
|
|
<p>即将推出...</p>
|
|
</div>
|
|
</Container>
|
|
);
|
|
});
|
|
|
|
const UserProfilePage = observer(() => {
|
|
const authStore = useAuthStore();
|
|
const userStore = useUserStore();
|
|
|
|
React.useEffect(() => {
|
|
if (authStore.isAuthenticated) {
|
|
userStore.fetchCurrentUser();
|
|
}
|
|
}, [authStore, userStore]);
|
|
|
|
if (!authStore.isAuthenticated) {
|
|
return (
|
|
<Container>
|
|
<p>请先登录</p>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
if (userStore.loading) {
|
|
return <Loading message="加载用户信息..." />;
|
|
}
|
|
|
|
return (
|
|
<Container>
|
|
<Header>
|
|
<Title>个人中心</Title>
|
|
</Header>
|
|
{userStore.user && (
|
|
<div>
|
|
<h3>用户信息</h3>
|
|
<p>用户名: {userStore.user.username}</p>
|
|
<p>邮箱: {userStore.user.email}</p>
|
|
<p>角色: {userStore.user.role_display}</p>
|
|
|
|
<h3>统计</h3>
|
|
<p>文章数: {userStore.user.articles_count}</p>
|
|
<p>服务数: {userStore.user.services_count}</p>
|
|
<p>评论数: {userStore.user.comments_count}</p>
|
|
<p>点赞数: {userStore.user.likes_count}</p>
|
|
<p>收藏数: {userStore.user.favorites_count}</p>
|
|
</div>
|
|
)}
|
|
</Container>
|
|
);
|
|
});
|
|
|
|
const NotFoundPage = () => (
|
|
<Container>
|
|
<Header>
|
|
<Title>404</Title>
|
|
</Header>
|
|
<p>页面未找到</p>
|
|
</Container>
|
|
);
|
|
|
|
export default App; |