feat: 初始化
This commit is contained in:
parent
d94f215467
commit
98c937e079
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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 /> },
|
||||||
|
|
||||||
// 需要登录才能访问的路由
|
// 需要登录才能访问的路由
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue