feat: 初始化

This commit is contained in:
李如威 2025-09-30 14:12:54 +08:00
parent d94f215467
commit 98c937e079
7 changed files with 99 additions and 17 deletions

View File

@ -0,0 +1,10 @@
{
"is_init": true,
"db_type": "sqlite",
"db_host": "localhost",
"db_port": 3306,
"db_user": "root",
"db_password": "12345",
"db_name": "your_workflow",
"admin_password": "12345"
}

View File

@ -6,8 +6,14 @@ CONFIG_PATH = Path(__file__).parent.parent / "config" / "init.json"
def _sync_load_config() -> dict: def _sync_load_config() -> dict:
with CONFIG_PATH.open("r", encoding="utf-8") as f: CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
return json.load(f) try:
with CONFIG_PATH.open("r", encoding="utf-8") as f:
return json.load(f)
except FileNotFoundError:
default_config = {"is_init": False}
_sync_save_config(default_config)
return default_config
def _sync_save_config(config_data: dict): def _sync_save_config(config_data: dict):

View File

@ -95,12 +95,12 @@ async def lifespan(app: FastAPI):
init_config = await load_init_config() init_config = await load_init_config()
await init_tortoise(init_config["db_type"], init_config, init_config.get("admin_password")) await init_tortoise(init_config["db_type"], init_config, init_config.get("admin_password"))
logger.info("初始化数据库") logger.info("初始化数据库")
# 读取上一次登录状态
await load_session_from_file(app)
# 定时器 # 定时器
scheduler.add_job(clear_session, "interval", seconds=30, misfire_grace_time=10) scheduler.add_job(clear_session, "interval", seconds=30, misfire_grace_time=10)
scheduler.start() scheduler.start()
logger.info("初始化定时器") logger.info("初始化定时器")
# 读取上一次登录状态
await load_session_from_file(app)
yield yield
@ -173,6 +173,8 @@ def create_app():
@app.get("/api/current_user", tags=["User"], description="当前用户信息", response_model=LoginResponse) @app.get("/api/current_user", tags=["User"], description="当前用户信息", response_model=LoginResponse)
async def current_user(user: DB.User = Depends(get_current_user)): async def current_user(user: DB.User = Depends(get_current_user)):
if not await is_init():
return LoginResponse(success=False)
return LoginResponse(data=user.json(del_columns=["password"])) return LoginResponse(data=user.json(del_columns=["password"]))
@app.post("/api/run", tags=["Flow"], description="执行任务", response_model=BaseResponse) @app.post("/api/run", tags=["Flow"], description="执行任务", response_model=BaseResponse)

View File

@ -4,3 +4,6 @@ export const isInit = async () => {
return request("/api/check_init", "GET") return request("/api/check_init", "GET")
} }
export const initSystem = async (data) => {
return request("/api/init_system", "POST", data)
}

View File

@ -1,13 +1,15 @@
import { createContext, useContext, useEffect, useState } from "react"; import { createContext, useContext, useEffect, useState } from "react";
import { login as loginToServer, currentUser } from "../api/user"; import { login as loginToServer, currentUser } from "../api/user";
import { isInit } from '../api/system';
const AuthContext = createContext(null); const AuthContext = createContext(null);
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
export function AuthProvider({ children }) { export function AuthProvider({ children }) {
const navigate = useNavigate();
const token = localStorage.getItem('_token') const token = localStorage.getItem('_token')
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const navigate = useNavigate();
const [loading, setLoading] = useState(token?.length > 0); const [loading, setLoading] = useState(token?.length > 0);
const [systemStatus, setSystemStatus] = useState(-1);
const getUserInfoFromToken = async () => { const getUserInfoFromToken = async () => {
try { try {
@ -24,6 +26,11 @@ export function AuthProvider({ children }) {
setLoading(false); setLoading(false);
} }
const checkSystemStatus = async () => {
const res = await isInit();
setSystemStatus(res?.data ? 1 : 0);
}
const login = async (username, password) => { const login = async (username, password) => {
const res = await loginToServer(username, password); const res = await loginToServer(username, password);
if (res?.success) { if (res?.success) {
@ -42,11 +49,22 @@ export function AuthProvider({ children }) {
}; };
useEffect(() => { useEffect(() => {
token && getUserInfoFromToken(); systemStatus === 1 && token && getUserInfoFromToken();
}, [token])
if (systemStatus === 0) {
navigate("/init");
}
else if (!token) {
navigate("/login")
}
}, [token, systemStatus])
useEffect(() => {
checkSystemStatus();
}, [])
return ( return (
<AuthContext.Provider value={{ user, login, logout, loading }}> <AuthContext.Provider value={{ user, login, logout, loading, systemStatus }}>
{children} {children}
</AuthContext.Provider> </AuthContext.Provider>
); );

View File

@ -1,12 +1,32 @@
import { ProForm, ProFormSelect, ProFormText } from "@ant-design/pro-components"; import { ProForm, ProFormDependency, ProFormDigit, ProFormGroup, ProFormSelect, ProFormText } from "@ant-design/pro-components";
import { Card, Divider } from "antd"; import { App, Card, Divider } from "antd";
import { useNavigate } from "react-router-dom";
import { initSystem } from "../api/system";
import { useAuth } from "../context/AuthContext";
import { useEffect } from "react";
const rules = [{required: true}] const rules = [{required: true}]
const InitPage = () => { const InitPage = () => {
const { systemStatus } = useAuth();
const navigate = useNavigate();
const { message } = App.useApp();
useEffect(() => {
if (systemStatus === 1) {
navigate("/login");
}
}, [systemStatus])
return ( return (
<div style={{ width: '100vw', height: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f2f3f5' }}> <div style={{ width: '100vw', height: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f2f3f5' }}>
<Card title='初始化' style={{ width: 400}}> <Card style={{ width: 600}} title="系统初始化">
<ProForm layout='horizontal'> <ProForm onFinish={async values => {
<Divider orientation="left">超级帐号</Divider> const res = await initSystem(values);
if (res?.success) {
message.success("初始化成功");
navigate("/login");
} else {
message.error(res.message);
}
}}>
<Divider orientation="left" plain>超级帐号</Divider>
<ProFormText <ProFormText
name="account" name="account"
label="帐号" label="帐号"
@ -17,14 +37,29 @@ const InitPage = () => {
label="密码" label="密码"
rules={rules} rules={rules}
/> />
<Divider orientation="left">数据库配置</Divider> <Divider orientation="left" plain>数据库配置</Divider>
<ProFormSelect <ProFormSelect
name="db_type" name="db_type"
options={[{ label: 'SQLite', value: 'sqlite' }, { label: 'MySql', value: 'mysql' }]} options={[{ label: 'SQLite', value: 'sqlite' }, { label: 'MySql', value: 'mysql' }]}
label="数据库" label="数据库"
rules={rules} rules={rules}
/> />
<ProFormDependency name={['db_type']}>
{({ db_type }) => {
if (db_type === 'mysql') return <>
<ProFormGroup>
<ProFormText name="db_host" label="地址" rules={rules} />
<ProFormDigit name="db_port" label="端口" rules={rules} />
<ProFormText name="db_name" label="数据库" rules={rules} />
<ProFormText name="db_user" label="用户" rules={rules} />
<ProFormText.Password name="db_password" label="密码" rules={rules} />
</ProFormGroup>
</>
return null;
}}
</ProFormDependency>
</ProForm> </ProForm>
</Card> </Card>
</div> </div>

View File

@ -10,17 +10,25 @@ import FlowDetail from "./pages/Flow/Detail";
import LayoutPage from "./pages/Layout"; import LayoutPage from "./pages/Layout";
import ClientPage from "./pages/Client"; import ClientPage from "./pages/Client";
import LogPage from "./pages/Log"; import LogPage from "./pages/Log";
import InitPage from "./pages/InitPage";
// //
function PrivateRoute() { function PrivateRoute() {
const { user, loading } = useAuth(); const { user, loading, systemStatus } = useAuth();
return (user || loading) ? <Outlet /> : <Navigate to="/login" replace />; if (systemStatus === 0) {
return <Navigate to="/init" replace />
}
if (user || loading || systemStatus != 0) {
return <Outlet />;
}
return <Navigate to="/login" replace />;
} }
const routes = [ const routes = [
// 访 // 访
{ path: "/", element: <Loading /> }, { path: "/", element: <Loading /> },
{ path: "/login", element: <Login /> }, { path: "/login", element: <Login /> },
{ path: "/init", element: <InitPage /> },
// 访 // 访
{ {