Files
citywalk-stamp/packages/web/src/App.tsx
YANG JIANKUAN ae63cb1d85 feat: 新增音乐播放模块
- 新增 Music 数据模型 + 迁移(title/subtitle/audioFile)
- 后端:公共 /api/music 查询接口 + 管理端 CRUD
  (音频上传专用 multer,限制 20MB)
- 移动端 /music/:id 播放页:
  - 金色印章式唱片 + 旋转虚线环 + 三重金色涟漪
  - preload=auto + HTTP Range 流式加载
  - 浏览器禁止 autoplay 时显示「轻点聆听」overlay
  - 自定义进度条与时间显示
- Admin:新增音乐管理三页(列表/表单/二维码)与侧栏入口
- 导入示例音乐:朝天宫之歌
- Dockerfile + entrypoint 增加 music 资产回灌

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 18:37:44 +08:00

67 lines
2.9 KiB
TypeScript

import { Routes, Route, Navigate, useParams } from "react-router-dom";
import { AuthProvider } from "./lib/auth";
import LandingPage from "./pages/LandingPage";
import AlbumPage from "./pages/AlbumPage";
import ArticlePage from "./pages/ArticlePage";
import MusicPage from "./pages/MusicPage";
import AdminLogin from "./admin/AdminLogin";
import AdminGuard from "./admin/AdminGuard";
import AdminLayout from "./admin/AdminLayout";
import StampList from "./admin/StampList";
import StampForm from "./admin/StampForm";
import StampQRCode from "./admin/StampQRCode";
import ArticleList from "./admin/ArticleList";
import ArticleForm from "./admin/ArticleForm";
import ArticleQRCode from "./admin/ArticleQRCode";
import MusicList from "./admin/MusicList";
import MusicForm from "./admin/MusicForm";
import MusicQRCode from "./admin/MusicQRCode";
import RuleList from "./admin/RuleList";
import RuleForm from "./admin/RuleForm";
import RedemptionLog from "./admin/RedemptionLog";
function CollectRedirect() {
const { stampId } = useParams();
return <Navigate to={`/?stamp=${stampId}`} replace />;
}
export default function App() {
return (
<AuthProvider>
<Routes>
{/* User-facing mobile H5 */}
<Route path="/" element={<LandingPage />} />
<Route path="/album" element={<AlbumPage />} />
<Route path="/collect/:stampId" element={<CollectRedirect />} />
<Route path="/article/:id" element={<ArticlePage />} />
<Route path="/music/:id" element={<MusicPage />} />
{/* Admin panel */}
<Route path="/admin" element={<AdminLogin />} />
<Route element={<AdminGuard />}>
<Route element={<AdminLayout />}>
<Route path="/admin/stamps" element={<StampList />} />
<Route path="/admin/stamps/new" element={<StampForm />} />
<Route path="/admin/stamps/:id/edit" element={<StampForm />} />
<Route path="/admin/stamps/:id/qrcode" element={<StampQRCode />} />
<Route path="/admin/articles" element={<ArticleList />} />
<Route path="/admin/articles/new" element={<ArticleForm />} />
<Route path="/admin/articles/:id/edit" element={<ArticleForm />} />
<Route path="/admin/articles/:id/qrcode" element={<ArticleQRCode />} />
<Route path="/admin/music" element={<MusicList />} />
<Route path="/admin/music/new" element={<MusicForm />} />
<Route path="/admin/music/:id/edit" element={<MusicForm />} />
<Route path="/admin/music/:id/qrcode" element={<MusicQRCode />} />
<Route path="/admin/rules" element={<RuleList />} />
<Route path="/admin/rules/new" element={<RuleForm />} />
<Route path="/admin/rules/:id/edit" element={<RuleForm />} />
<Route path="/admin/redemptions" element={<RedemptionLog />} />
</Route>
</Route>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</AuthProvider>
);
}