mirror of
https://github.com/tnb-labs/panel.git
synced 2026-08-29 02:10:58 +08:00
5391911a97
- 首屏加载后不贴底:改由 useResizeObserver 把"跟随时保持贴底"维持成不变式, 覆盖弹窗入场、横向滚动条、字体度量、tab 由隐藏转可见等后续布局变化 - 向上翻页内容重复:文件日志改用首屏 size 作为反向分页锚点, 不再受跟踪期间写入的新日志影响 - 首屏到建连之间的日志丢失:follow 支持从锚点字节位置续读(tail -c +N), 重连仍只跟新增以免整段重放 - 断线重连残留的半行与新流拼接会拼出错行 - 点"跳到顶部"被翻页的位置补偿拽回原处 - 实时裁剪未退还翻页游标,导致下次上翻跳过被裁掉的那一段 - 搜索跳转改按相对位置计算,不再连带滚动外层页面 - 首屏日志不足一页时凭空出现"没有更多日志" 性能: - ws 帧合并到 rAF 统一落盘,繁忙日志下渲染次数从帧数级降到 60/秒级 - 反向读取按字节切分,只把返回的那页转 string;首块按预估行长一次读足 - 日志行 markRaw 并移除小写副本字段 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
110 lines
4.2 KiB
Go
110 lines
4.2 KiB
Go
package request
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/spf13/cast"
|
|
)
|
|
|
|
type FileList struct {
|
|
Path string `json:"path" form:"path" validate:"required && unix_path"`
|
|
Sort string `json:"sort" form:"sort"`
|
|
Keyword string `form:"keyword" json:"keyword"`
|
|
Sub bool `form:"sub" json:"sub"`
|
|
}
|
|
|
|
func (r *FileList) Prepare(req *http.Request) error {
|
|
r.Sub = cast.ToBool(req.FormValue("sub"))
|
|
return nil
|
|
}
|
|
|
|
type FilePath struct {
|
|
Path string `json:"path" form:"path" validate:"required && unix_path"`
|
|
}
|
|
|
|
type FileTail struct {
|
|
Path string `json:"path" form:"path"`
|
|
Service string `json:"service" form:"service"`
|
|
Container string `json:"container" form:"container"`
|
|
Offset int `json:"offset" form:"offset"`
|
|
Limit int `json:"limit" form:"limit"`
|
|
Cursor string `json:"cursor" form:"cursor"`
|
|
// Size 为首屏返回的文件大小,翻页时回传作为反向分页锚点,避免日志持续写入导致错位
|
|
Size int64 `json:"size" form:"size"`
|
|
}
|
|
|
|
type FileFollow struct {
|
|
Path string `json:"path" form:"path"`
|
|
Service string `json:"service" form:"service"`
|
|
Container string `json:"container" form:"container"`
|
|
// Offset 为首屏锚点字节位置,从该处开始跟踪以衔接首屏与实时流,避免中间写入的日志丢失
|
|
Offset int64 `json:"offset" form:"offset"`
|
|
}
|
|
|
|
type FileCreate struct {
|
|
Dir bool `json:"dir" form:"dir"`
|
|
Path string `json:"path" form:"path" validate:"required && unix_path"`
|
|
}
|
|
|
|
type FileSave struct {
|
|
Path string `form:"path" json:"path" validate:"required && unix_path"`
|
|
Content string `form:"content" json:"content"`
|
|
}
|
|
|
|
type FileControl struct {
|
|
Source string `form:"source" json:"source" validate:"required && unix_path"`
|
|
Target string `form:"target" json:"target" validate:"required && unix_path"`
|
|
Force bool `form:"force" json:"force"`
|
|
}
|
|
|
|
type FileRemoteDownload struct {
|
|
Path string `form:"path" json:"path" validate:"required && unix_path"`
|
|
URL string `form:"url" json:"url" validate:"required && url"`
|
|
}
|
|
|
|
type FilePermission struct {
|
|
Path string `form:"path" json:"path" validate:"required && unix_path"`
|
|
Mode string `form:"mode" json:"mode" validate:"required"`
|
|
Owner string `form:"owner" json:"owner" validate:"required"`
|
|
Group string `form:"group" json:"group" validate:"required"`
|
|
}
|
|
|
|
type FileCompress struct {
|
|
Dir string `form:"dir" json:"dir" validate:"required && unix_path"`
|
|
Paths []string `form:"paths" json:"paths" validate:"required && unique && dive && required"`
|
|
File string `form:"file" json:"file" validate:"required && unix_path"`
|
|
}
|
|
|
|
type FileUnCompress struct {
|
|
File string `form:"file" json:"file" validate:"required && unix_path"`
|
|
Path string `form:"path" json:"path" validate:"required && unix_path"`
|
|
}
|
|
|
|
type FileShareCreate struct {
|
|
Path string `form:"path" json:"path" validate:"required && unix_path"`
|
|
MaxDownloads uint `form:"max_downloads" json:"max_downloads"` // 最大下载次数(0 不限)
|
|
ExpireHours uint `form:"expire_hours" json:"expire_hours" validate:"required && min:1 && max:8760"` // 有效期(小时)
|
|
}
|
|
|
|
type FileShareToken struct {
|
|
Token string `json:"token" form:"token" uri:"token" validate:"required"`
|
|
}
|
|
|
|
// ChunkUploadStart 分块上传开始请求
|
|
type ChunkUploadStart struct {
|
|
Path string `json:"path" validate:"required && unix_path"` // 目标目录
|
|
FileName string `json:"file_name" validate:"required"` // 文件名
|
|
FileHash string `json:"file_hash" validate:"required && len:64"` // 文件SHA256
|
|
ChunkCount int `json:"chunk_count" validate:"required && min:1"` // 分块总数
|
|
Force bool `json:"force"` // 是否覆盖已存在文件
|
|
}
|
|
|
|
// ChunkUploadFinish 分块上传完成请求
|
|
type ChunkUploadFinish struct {
|
|
Path string `json:"path" validate:"required && unix_path"` // 目标目录
|
|
FileName string `json:"file_name" validate:"required"` // 文件名
|
|
FileHash string `json:"file_hash" validate:"required && len:64"` // 文件SHA256
|
|
ChunkCount int `json:"chunk_count" validate:"required && min:1"` // 分块总数
|
|
Force bool `json:"force"` // 是否覆盖已存在文件
|
|
}
|