feat: client
This commit is contained in:
parent
25fa8a043a
commit
03885d5a52
|
|
@ -1,4 +1,5 @@
|
|||
import asyncio
|
||||
import datetime
|
||||
import json
|
||||
import uvicorn
|
||||
import uuid
|
||||
|
|
@ -11,6 +12,7 @@ from tortoise.functions import Max
|
|||
from fastapi import FastAPI, Depends, HTTPException
|
||||
from models.schemas.system import InitStatusResponse, InitConfigRequest, BaseResponse, TableResponse
|
||||
from models.schemas.user import LoginRequest, LoginResponse
|
||||
from models.schemas.client import ClientRequest
|
||||
from core.config import load_init_config, save_init_config
|
||||
from core.db import init_tortoise, close_tortoise
|
||||
from core.logger import logger
|
||||
|
|
@ -413,6 +415,35 @@ def create_app():
|
|||
|
||||
return StreamingResponse(_event(), media_type="text/event-stream")
|
||||
|
||||
@app.get("/api/clients", tags=["Client"], description="终端列表", response_model=TableResponse)
|
||||
async def clients_list(user: DB.User = Depends(get_current_user)):
|
||||
res = await DB.Client.filter(user_id=user.id).all()
|
||||
return TableResponse(data=[x.json() for x in res], total=len(res))
|
||||
|
||||
@app.post("/api/clients", tags=["Client"], description="终端创建", response_model=BaseResponse)
|
||||
async def create_client(body: ClientRequest, user: DB.User = Depends(get_current_user)):
|
||||
await DB.Client(**body, user_id=user.id).save()
|
||||
return BaseResponse()
|
||||
|
||||
@app.post("/api/clients", tags=["Client"], description="终端创建", response_model=BaseResponse)
|
||||
async def create_client(body: ClientRequest, user: DB.User = Depends(get_current_user)):
|
||||
await DB.Client(**body, user_id=user.id).save()
|
||||
return BaseResponse()
|
||||
|
||||
@app.put("/api/clients", tags=["Client"], description="终端修改", response_model=BaseResponse)
|
||||
async def update_client(client_id:int, body: ClientRequest, user: DB.User = Depends(get_current_user)):
|
||||
obj = await DB.Client.filter(id=client_id).first()
|
||||
if obj:
|
||||
obj.update_from_dict(body.model_dump())
|
||||
obj.update_time = datetime.datetime.now()
|
||||
await obj.save()
|
||||
return BaseResponse()
|
||||
|
||||
@app.delete("/api/clients", tags=["Client"], description="终端删除", response_model=BaseResponse)
|
||||
async def del_client(client_id: int, user: DB.User = Depends(get_current_user)):
|
||||
await DB.Client.filter(id=client_id).delete()
|
||||
return BaseResponse()
|
||||
|
||||
return app
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from .system import *
|
||||
from .user import *
|
||||
from .work import *
|
||||
from .work import *
|
||||
from .client import *
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
from tortoise import fields
|
||||
from .system import BaseModel
|
||||
|
||||
|
||||
class Client(BaseModel):
|
||||
name = fields.CharField(max_length=50, null=True)
|
||||
host = fields.CharField(max_length=50, null=True)
|
||||
port = fields.IntField(default=22, null=True)
|
||||
user = fields.CharField(max_length=50, null=True)
|
||||
password = fields.CharField(max_length=50, null=True)
|
||||
user_id = fields.IntField(null=True)
|
||||
|
||||
class Meta:
|
||||
table = "tb_client"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
from pydantic import BaseModel
|
||||
from .system import BaseResponse
|
||||
import hashlib
|
||||
|
||||
|
||||
class ClientRequest(BaseModel):
|
||||
port: int
|
||||
host: str
|
||||
password: str
|
||||
user: str
|
||||
name: str
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { request } from "./base";
|
||||
|
||||
export const tableList = async (data = {}) => {
|
||||
return request("/api/clients?" + new URLSearchParams(data).toString(), "GET")
|
||||
}
|
||||
|
||||
export const create = async (data = {}) => {
|
||||
return request("/api/clients", "POST", data)
|
||||
}
|
||||
|
||||
export const update = async (id, data = {}) => {
|
||||
return request("/api/clients?id=" + id, "PUT", data)
|
||||
}
|
||||
|
||||
export const del = async (id) => {
|
||||
return request("/api/clients?id=" + id, "DELETE")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { ModalForm, ProForm } from "@ant-design/pro-components";
|
||||
import { Button } from "antd";
|
||||
import { PlusOutlined } from "@ant-design/icons";
|
||||
|
||||
const Create = ({ onFinish }) => {
|
||||
return <ModalForm
|
||||
trigger={<Button icon={<PlusOutlined />} type='primary'>创建</Button>}
|
||||
></ModalForm>
|
||||
}
|
||||
|
||||
export default Create;
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
import { ProTable } from "@ant-design/pro-components"
|
||||
import { Card } from "antd"
|
||||
import { useRef } from "react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { tableList } from "../../api/client"
|
||||
import Create from "./components/Create"
|
||||
|
||||
const ClientPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const actionRef = useRef(null);
|
||||
const onRequest = async () => {
|
||||
const res = await tableList();
|
||||
return res;
|
||||
}
|
||||
const columns = [
|
||||
{
|
||||
title: '#ID',
|
||||
dataIndex: "id",
|
||||
},
|
||||
{
|
||||
title: '名字',
|
||||
dataIndex: "name",
|
||||
},
|
||||
{
|
||||
title: '地址',
|
||||
dataIndex: "host",
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: "update_time",
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
key: 'option',
|
||||
with: 100,
|
||||
fixed: 'right',
|
||||
render: (_, record) => [
|
||||
<Button key='2' type="link" style={{ padding: '0 0', border: 'none' }} onClick={() => {
|
||||
navigate("/flow/detail/" + record.uuid);
|
||||
}}>编辑</Button>,
|
||||
<Button key='3' type="link" danger style={{ padding: '0 0', border: 'none' }}>删除</Button>,
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
return <Card title="节点管理">
|
||||
<ProTable
|
||||
toolBarRender={() => <Create />}
|
||||
actionRef={actionRef}
|
||||
rowKey='id'
|
||||
search={false}
|
||||
scroll={{ x: 'max-content' }}
|
||||
options={false}
|
||||
columns={columns}
|
||||
request={onRequest}
|
||||
/>
|
||||
|
||||
</Card>
|
||||
}
|
||||
|
||||
export default ClientPage
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState } from "react";
|
||||
import { Outlet, useNavigate, useLocation } from "react-router-dom";
|
||||
import { Layout, Menu, Button, Flex, Dropdown, Steps } from "antd";
|
||||
import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LoginOutlined, ProfileOutlined, NodeExpandOutlined } from "@ant-design/icons";
|
||||
import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LoginOutlined, ProfileOutlined, NodeExpandOutlined, LaptopOutlined } from "@ant-design/icons";
|
||||
import { useAuth } from "../context/AuthContext";
|
||||
import './Layout.css';
|
||||
|
||||
|
|
@ -15,6 +15,7 @@ export default function LayoutPage() {
|
|||
|
||||
const menuItems = [
|
||||
{ key: "1", icon: <NodeExpandOutlined />, label: "工作台", path: "/flow" },
|
||||
{ key: "2", icon: <LaptopOutlined />, label: "节点管理", path: "/client" },
|
||||
];
|
||||
|
||||
const selectedKey = menuItems.find(item => location.pathname.startsWith(item.path))?.key || "";
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import Profile from "./pages/User/Profile";
|
|||
import Flow from "./pages/Flow";
|
||||
import FlowDetail from "./pages/Flow/Detail";
|
||||
import LayoutPage from "./pages/Layout";
|
||||
import ClientPage from "./pages/Client";
|
||||
|
||||
|
||||
// 受保护的路由:没登录就跳转到登录页
|
||||
|
|
@ -29,6 +30,7 @@ const routes = [
|
|||
element: <LayoutPage />,
|
||||
children: [
|
||||
{ path: "/flow", element: <Flow /> },
|
||||
{ path: "/client", element: <ClientPage /> },
|
||||
{ path: "/flow/detail/:work_uuid", element: <FlowDetail /> },
|
||||
{ path: "/user", element: <User /> },
|
||||
{ path: "/user/detail", element: <Profile /> }
|
||||
|
|
|
|||
Loading…
Reference in New Issue