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:
with CONFIG_PATH.open("r", encoding="utf-8") as f:
return json.load(f)
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
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):

View File

@ -95,12 +95,12 @@ async def lifespan(app: FastAPI):
init_config = await load_init_config()
await init_tortoise(init_config["db_type"], init_config, init_config.get("admin_password"))
logger.info("初始化数据库")
# 读取上一次登录状态
await load_session_from_file(app)
# 定时器
scheduler.add_job(clear_session, "interval", seconds=30, misfire_grace_time=10)
scheduler.start()
logger.info("初始化定时器")
# 读取上一次登录状态
await load_session_from_file(app)
yield
@ -173,6 +173,8 @@ def create_app():
@app.get("/api/current_user", tags=["User"], description="当前用户信息", response_model=LoginResponse)
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"]))
@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")
}
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 { login as loginToServer, currentUser } from "../api/user";
import { isInit } from '../api/system';
const AuthContext = createContext(null);
import { useNavigate } from 'react-router-dom';
export function AuthProvider({ children }) {
const navigate = useNavigate();
const token = localStorage.getItem('_token')
const [user, setUser] = useState(null);
const navigate = useNavigate();
const [loading, setLoading] = useState(token?.length > 0);
const [systemStatus, setSystemStatus] = useState(-1);
const getUserInfoFromToken = async () => {
try {
@ -24,6 +26,11 @@ export function AuthProvider({ children }) {
setLoading(false);
}
const checkSystemStatus = async () => {
const res = await isInit();
setSystemStatus(res?.data ? 1 : 0);
}
const login = async (username, password) => {
const res = await loginToServer(username, password);
if (res?.success) {
@ -42,11 +49,22 @@ export function AuthProvider({ children }) {
};
useEffect(() => {
token && getUserInfoFromToken();
}, [token])
systemStatus === 1 && token && getUserInfoFromToken();
if (systemStatus === 0) {
navigate("/init");
}
else if (!token) {
navigate("/login")
}
}, [token, systemStatus])
useEffect(() => {
checkSystemStatus();
}, [])
return (
<AuthContext.Provider value={{ user, login, logout, loading }}>
<AuthContext.Provider value={{ user, login, logout, loading, systemStatus }}>
{children}
</AuthContext.Provider>
);

View File

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

View File

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