Compare commits

...

2 Commits

Author SHA1 Message Date
李如威 5f138ec9df feat: 状态等待时间 2025-09-25 19:23:37 +08:00
李如威 9584f370ad feat: 耗时 2025-09-25 09:06:05 +08:00
6 changed files with 50 additions and 5 deletions

View File

@ -11,7 +11,7 @@ import nodes as F
from tool import format_content_uuid
from tortoise.transactions import in_transaction
from tortoise.functions import Max
from fastapi import FastAPI, Depends, HTTPException
from fastapi import FastAPI, Depends, HTTPException, Query
from models.schemas.system import InitStatusResponse, InitConfigRequest, BaseResponse, TableResponse
from models.schemas.user import LoginRequest, LoginResponse
from models.schemas.client import ClientRequest
@ -74,6 +74,10 @@ def get_current_user(token: str = Depends(oauth2_scheme)) -> DB.User | None:
return user
def pagination_query(page:int = Query(1), page_size:int = Query(20)):
return {"page": page, "page_size": page_size}
async def is_init():
init_config = await load_init_config()
init_status = init_config.get("is_init")
@ -207,6 +211,7 @@ def create_app():
)
await work_log.save()
try:
start_time = int(datetime.datetime.now().timestamp())
work_content = await DB.WorkContent.filter(work_id=work.id).first()
if not work_content:
logger.warning(f"没有找到对应的内容: {work.uuid}")
@ -251,7 +256,7 @@ def create_app():
await flow.run_async(shared)
app.state.tasks.pop(task_id, None)
app.state.task_nodes.pop(task_id, None)
end_time = int(datetime.datetime.now().timestamp())
# 更新日志
work_log_result = []
for x in nodes:
@ -269,7 +274,7 @@ def create_app():
"result": shared.get(id, {}),
"status": status
})
work_log.result = work_log_result
work_log.result = {"time": end_time - start_time, "logs": work_log_result}
if next((x for x in shared.values() if x.get("err")), None):
work_log.status = DB.WorkLogsStatus.FAILED
else:
@ -322,6 +327,7 @@ def create_app():
log: DB.WorkLogs = next((x for x in work_logs_list if x.work_id == work.id), DB.WorkLogs(user_id=-1))
log_user: DB.User = next((u for u in user_list if u.id == log.user_id), DB.User())
obj["last_user"] = log_user.username or ""
obj["last_use_time"] = log.result.get("time", 0)
obj["last_run_time"] = log.create_time.timestamp() if log.create_time else 0
obj["last_status"] = log.status or ""
obj["is_running"] = work.uuid in global_tasks
@ -451,6 +457,12 @@ def create_app():
await DB.Client.filter(id=id).delete()
return BaseResponse()
@app.get("/api/logs", tags=["Log"], description="日志列表", response_model=TableResponse)
async def log_list(p:dict = Depends(pagination_query), user: DB.User = Depends(get_current_user)):
page, page_size = p["page"], p["page_size"]
res = await DB.WorkLogs.all().order_by('-id').limit(page_size).offset((page - 1) * page_size)
return TableResponse(data=[x.json() for x in res], total=len(res))
return app

View File

@ -8,6 +8,7 @@ async def async_run_cmd(
password: str = None,
port: int = None,
sudo: bool = False,
wait: int = 0,
):
"""
异步执行命令
@ -15,6 +16,9 @@ async def async_run_cmd(
- 如果 host 不为空则通过 SSH 执行远程命令
"""
if wait > 0:
await asyncio.sleep(wait)
async def read_stream(stream, stream_type):
async for line in stream:
text = line

View File

@ -1,3 +1,4 @@
import asyncio
from fastapi import FastAPI
from core.pocket_flow import AsyncNode
from core.logger import logger
@ -36,6 +37,7 @@ class StatusNode(AsyncNode):
"password": self.params[self.id].get("password"),
"port": self.params[self.id].get("port"),
"sudo": self.params[self.id].get("sudo", False),
"wait": self.params[self.id].get("wait", 3),
"cmd": cmd_str,
}

6
frontend/src/api/log.js Normal file
View File

@ -0,0 +1,6 @@
import { request } from "./base";
export const tableList = async (data = {}) => {
return request("/api/logs?" + new URLSearchParams(data).toString(), "GET")
}

View File

@ -83,7 +83,12 @@ export default () => {
{
dataIndex: 'last_run_time',
title: '最后执行时间',
render: (_, record) => record?.last_run_time ? new Date(record?.last_run_time * 1000).toLocaleString() : ''
render: (_, record) => record?.last_run_time ? new Date(record?.last_run_time * 1000).toLocaleString() : '-'
},
{
dataIndex: 'last_use_time',
title: '最后执行耗时',
render: (_, record) => record?.last_use_time ? formatSeconds(record?.last_use_time) : '-',
},
{
dataIndex: 'last_status',
@ -190,4 +195,11 @@ export default () => {
</Card>
)
}
export const formatSeconds = (seconds = 0) => {
const h = String(Math.floor(seconds / 3600)).padStart(2, "0");
const m = String(Math.floor((seconds % 3600) / 60)).padStart(2, "0");
const s = String(seconds % 60).padStart(2, "0");
return h === "00" ? `${m}:${s}` : `${h}:${m}:${s}`;
}

View File

@ -1,6 +1,8 @@
import { ProTable } from "@ant-design/pro-components";
import { Card } from "antd";
import { useRef } from "react";
import { formatSeconds } from "../Flow";
import { tableList } from "../../api/log";
const LogPage = () => {
const actionRef = useRef(null);
@ -26,7 +28,12 @@ const LogPage = () => {
{
dataIndex: 'last_run_time',
title: '执行时间',
render: (_, record) => record?.last_run_time ? new Date(record?.last_run_time * 1000).toLocaleString() : ''
render: (_, record) => record?.last_run_time ? new Date(record?.last_run_time * 1000).toLocaleString() : '-'
},
{
dataIndex: 'time',
title: '执行耗时',
render: (_, record) => record?.time ? formatSeconds(record?.time) : '-',
},
{
dataIndex: 'last_status',
@ -51,6 +58,8 @@ const LogPage = () => {
}
];
const onRequest = async (params) => {
const res = await tableList(params)
console.log(res);
return {};
}
return <Card title="操作日志">