feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本
包含多个会话的累积代码变更: - backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔 - admin-web: ETL 状态页、任务管理、调度配置、登录优化 - miniprogram: 看板页面、聊天集成、UI 组件、导航更新 - etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强 - tenant-admin: 项目初始化 - db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8) - packages/shared: 枚举和工具函数更新 - tools: 数据库工具、报表生成、健康检查 - docs: PRD/架构/部署/合约文档更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
155
apps/tenant-admin/src/App.tsx
Normal file
155
apps/tenant-admin/src/App.tsx
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* 主布局与路由配置。
|
||||
*
|
||||
* - Ant Design Layout:Sider + Content
|
||||
* - react-router-dom v6 路由
|
||||
* - 未认证重定向到 /login
|
||||
* - 路由:/login, /applications, /users, /excel, /clues, / → /applications
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { Routes, Route, Navigate, useNavigate, useLocation } from "react-router-dom";
|
||||
import { Layout, Menu, Button, Tooltip } from "antd";
|
||||
import {
|
||||
AuditOutlined,
|
||||
TeamOutlined,
|
||||
FileExcelOutlined,
|
||||
SolutionOutlined,
|
||||
LogoutOutlined,
|
||||
UserSwitchOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import type { MenuProps } from "antd";
|
||||
import { AuthProvider, useAuth } from "./hooks/useAuth";
|
||||
import Login from "./pages/Login";
|
||||
import UserApproval from "./pages/UserApproval";
|
||||
import UserManagement from "./pages/UserManagement";
|
||||
import ExcelUpload from "./pages/ExcelUpload";
|
||||
import RetentionClues from "./pages/RetentionClues";
|
||||
import SiteAdmins from "./pages/SiteAdmins";
|
||||
|
||||
const { Sider, Content } = Layout;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 侧边栏导航配置 */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
function getNavItems(adminType: string): MenuProps["items"] {
|
||||
const items: MenuProps["items"] = [
|
||||
{ key: "/applications", icon: <AuditOutlined />, label: "用户审核" },
|
||||
{ key: "/users", icon: <TeamOutlined />, label: "用户管理" },
|
||||
{ key: "/excel", icon: <FileExcelOutlined />, label: "Excel 上传" },
|
||||
{ key: "/clues", icon: <SolutionOutlined />, label: "维客线索管理" },
|
||||
];
|
||||
// 仅租户管理员可见
|
||||
if (adminType === "tenant_admin") {
|
||||
items.push({ key: "/site-admins", icon: <UserSwitchOutlined />, label: "店铺管理员" });
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 路由守卫 */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
const PrivateRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const { isAuthenticated } = useAuth();
|
||||
return isAuthenticated ? <>{children}</> : <Navigate to="/login" replace />;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 主布局(含侧边栏) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
const AppLayout: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { logout, user } = useAuth();
|
||||
|
||||
const navItems = getNavItems(user?.adminType ?? "site_admin");
|
||||
|
||||
const onMenuClick: MenuProps["onClick"] = ({ key }) => {
|
||||
navigate(key);
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
<Sider collapsible style={{ display: "flex", flexDirection: "column" }}>
|
||||
<div
|
||||
style={{
|
||||
height: 48,
|
||||
margin: "12px 16px",
|
||||
color: "#fff",
|
||||
fontWeight: 700,
|
||||
fontSize: 16,
|
||||
textAlign: "center",
|
||||
lineHeight: "48px",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
租户管理后台
|
||||
</div>
|
||||
<Menu
|
||||
theme="dark"
|
||||
mode="inline"
|
||||
selectedKeys={[location.pathname]}
|
||||
items={navItems}
|
||||
onClick={onMenuClick}
|
||||
/>
|
||||
<div style={{ flex: 1 }} />
|
||||
<div style={{ padding: "12px 16px" }}>
|
||||
<Tooltip title="退出登录">
|
||||
<Button
|
||||
type="text"
|
||||
icon={<LogoutOutlined />}
|
||||
onClick={handleLogout}
|
||||
style={{ color: "rgba(255,255,255,0.65)", width: "100%" }}
|
||||
>
|
||||
退出
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Sider>
|
||||
<Layout>
|
||||
<Content style={{ margin: 16, minHeight: 280 }}>
|
||||
<Routes>
|
||||
<Route path="/applications" element={<UserApproval />} />
|
||||
<Route path="/users" element={<UserManagement />} />
|
||||
<Route path="/excel" element={<ExcelUpload />} />
|
||||
<Route path="/clues" element={<RetentionClues />} />
|
||||
<Route path="/site-admins" element={<SiteAdmins />} />
|
||||
<Route path="/" element={<Navigate to="/applications" replace />} />
|
||||
</Routes>
|
||||
</Content>
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 根组件 */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<Routes>
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route
|
||||
path="/*"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<AppLayout />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</AuthProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
Reference in New Issue
Block a user