diff --git a/agent/app/api/v2/file.go b/agent/app/api/v2/file.go index f00bb5486..ce1f14367 100644 --- a/agent/app/api/v2/file.go +++ b/agent/app/api/v2/file.go @@ -628,6 +628,28 @@ func (b *BaseApi) Size(c *gin.Context) { helper.SuccessWithData(c, res) } +// @Tags File +// @Summary Multi file size +// @Accept json +// @Param request body request.DirSizeReq true "request" +// @Success 200 {array} response.DepthDirSizeRes +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /files/depth/size [post] +// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"获取目录及其第一层子目录文件夹大小 [path]","formatEN":"Multi file size [path]"} +func (b *BaseApi) DepthDirSize(c *gin.Context) { + var req request.DirSizeReq + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + res, err := fileService.DepthDirSize(req) + if err != nil { + helper.InternalServer(c, err) + return + } + helper.SuccessWithData(c, res) +} + func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int, overwrite bool) error { defer func() { _ = os.RemoveAll(fileDir) diff --git a/agent/app/dto/response/file.go b/agent/app/dto/response/file.go index 887037245..1f4c0e9d7 100644 --- a/agent/app/dto/response/file.go +++ b/agent/app/dto/response/file.go @@ -64,3 +64,8 @@ type UserGroupResponse struct { Users []UserInfo `json:"users"` Groups []string `json:"groups"` } + +type DepthDirSizeRes struct { + Path string `json:"path"` + Size int64 `json:"size"` +} diff --git a/agent/app/service/file.go b/agent/app/service/file.go index 74bf5d399..4339726bf 100644 --- a/agent/app/service/file.go +++ b/agent/app/service/file.go @@ -4,6 +4,7 @@ import ( "bufio" "context" "fmt" + "github.com/jinzhu/copier" "io" "io/fs" "os" @@ -51,6 +52,7 @@ type IFileService interface { SaveContent(edit request.FileEdit) error FileDownload(d request.FileDownload) (string, error) DirSize(req request.DirSizeReq) (response.DirSizeRes, error) + DepthDirSize(req request.DirSizeReq) ([]response.DepthDirSizeRes, error) ChangeName(req request.FileRename) error Wget(w request.FileWget) (string, error) MvFile(m request.FileMove) error @@ -443,6 +445,22 @@ func (f *FileService) DirSize(req request.DirSizeReq) (response.DirSizeRes, erro return res, nil } +func (f *FileService) DepthDirSize(req request.DirSizeReq) ([]response.DepthDirSizeRes, error) { + var ( + res []response.DepthDirSizeRes + ) + if req.Path == "/proc" { + return res, nil + } + fo := files.NewFileOp() + dirSizes, err := fo.GetDepthDirSize(req.Path) + _ = copier.Copy(&res, &dirSizes) + if err != nil { + return res, err + } + return res, nil +} + func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error) { logFilePath := "" switch req.Type { diff --git a/agent/router/ro_file.go b/agent/router/ro_file.go index 1c5a8e1a2..0f6e8de02 100644 --- a/agent/router/ro_file.go +++ b/agent/router/ro_file.go @@ -34,6 +34,7 @@ func (f *FileRouter) InitRouter(Router *gin.RouterGroup) { fileRouter.GET("/download", baseApi.Download) fileRouter.POST("/chunkdownload", baseApi.DownloadChunkFiles) fileRouter.POST("/size", baseApi.Size) + fileRouter.POST("/depth/size", baseApi.DepthDirSize) fileRouter.GET("/wget/process", baseApi.WgetProcess) fileRouter.GET("/wget/process/keys", baseApi.ProcessKeys) fileRouter.POST("/read", baseApi.ReadFileByLine) diff --git a/agent/utils/files/file_op.go b/agent/utils/files/file_op.go index 38b460491..dd96e5534 100644 --- a/agent/utils/files/file_op.go +++ b/agent/utils/files/file_op.go @@ -512,6 +512,71 @@ func (f FileOp) GetDirSize(path string) (int64, error) { return size, nil } +type DirSize struct { + Path string `json:"path"` + Size int64 `json:"size"` +} + +func (f FileOp) GetDepthDirSize(path string) ([]DirSize, error) { + var result []DirSize + sizeMap := make(map[string]int64) + duCmd := exec.Command("du", "-k", "--max-depth=1", "--exclude=proc", path) + output, err := duCmd.Output() + if err == nil { + parseDUOutput(output, sizeMap) + } else { + calculateDirSizeFallback(path, sizeMap) + } + + for dir, size := range sizeMap { + result = append(result, DirSize{ + Path: dir, + Size: size, + }) + } + + return result, nil +} + +func parseDUOutput(output []byte, sizeMap map[string]int64) { + lines := strings.Split(string(output), "\n") + for _, line := range lines { + if strings.TrimSpace(line) == "" { + continue + } + fields := strings.Fields(line) + if len(fields) == 2 { + if sizeKB, err := strconv.ParseInt(fields[0], 10, 64); err == nil { + dir := fields[1] + sizeMap[dir] = sizeKB * 1024 + } + } + } +} + +func calculateDirSizeFallback(path string, sizeMap map[string]int64) { + _ = filepath.Walk(path, func(p string, info os.FileInfo, err error) error { + if err != nil { + return nil + } + if !info.IsDir() { + rel, err := filepath.Rel(path, p) + if err != nil { + return nil + } + parts := strings.Split(rel, string(os.PathSeparator)) + var topLevel string + if len(parts) == 0 || parts[0] == "." { + topLevel = path + } else { + topLevel = filepath.Join(path, parts[0]) + } + sizeMap[topLevel] += info.Size() + } + return nil + }) +} + func getFormat(cType CompressType) archiver.CompressedArchive { format := archiver.CompressedArchive{} switch cType { diff --git a/frontend/src/api/interface/file.ts b/frontend/src/api/interface/file.ts index f7c0cc5f8..7bbf9d2f5 100644 --- a/frontend/src/api/interface/file.ts +++ b/frontend/src/api/interface/file.ts @@ -152,6 +152,11 @@ export namespace File { size: number; } + export interface DepthDirSizeRes { + size: number; + path: string; + } + export interface FilePath { path: string; } diff --git a/frontend/src/api/modules/files.ts b/frontend/src/api/modules/files.ts index a3e6eed11..bb0c13331 100644 --- a/frontend/src/api/modules/files.ts +++ b/frontend/src/api/modules/files.ts @@ -98,6 +98,10 @@ export const computeDirSize = (params: File.DirSizeReq) => { return http.post('files/size', params, TimeoutEnum.T_5M); }; +export const computeDepthDirSize = (params: File.DirSizeReq) => { + return http.post('files/depth/size', params, TimeoutEnum.T_5M); +}; + export const fileWgetKeys = () => { return http.get('files/wget/process/keys'); }; diff --git a/frontend/src/components/complex-table/index.vue b/frontend/src/components/complex-table/index.vue index b8d3fb253..d57008628 100644 --- a/frontend/src/components/complex-table/index.vue +++ b/frontend/src/components/complex-table/index.vue @@ -21,7 +21,12 @@ -
+
+ { let heightDiff = 320; + let tabHeight = 0; if (props.heightDiff) { heightDiff = props.heightDiff; } + if (globalStore.openMenuTabs) { + tabHeight = 48; + } if (props.height) { - tableHeight.value = props.height; + tableHeight.value = props.height - tabHeight; } else { - tableHeight.value = window.innerHeight - heightDiff; + tableHeight.value = window.innerHeight - heightDiff - tabHeight; } window.onresize = () => { return (() => { if (props.height) { - tableHeight.value = props.height; + tableHeight.value = props.height - tabHeight; } else { - tableHeight.value = window.innerHeight - heightDiff; + tableHeight.value = window.innerHeight - heightDiff - tabHeight; } })(); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index eba50a5e1..0a4c07475 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -80,6 +80,7 @@ const message = { fix: 'Fix', down: 'Stop', up: 'Start', + sure: 'Confirm', }, operate: { start: 'Start', @@ -1342,6 +1343,7 @@ const message = { taskRunning: 'Running', }, file: { + currentDir: 'Directory', dir: 'Folder', fileName: 'File name', search: 'Find', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index b2838c848..9bfd3a532 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -77,6 +77,7 @@ const message = { fix: '修正', down: '停止', up: '起動', + sure: '確認', }, operate: { start: '開始', @@ -1278,6 +1279,7 @@ const message = { errLog: 'エラーログ', }, file: { + currentDir: '現在のディレクトリ', dir: 'フォルダ', upload: 'アップロード', uploadFile: '@:file.upload@.lower:file.file', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 8c60a86f7..ecce54ef7 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -77,6 +77,7 @@ const message = { fix: '수정', down: '중지', up: '시작', + sure: '확인', }, operate: { start: '시작', @@ -1265,6 +1266,7 @@ const message = { errLog: '에러 로그', }, file: { + currentDir: '현재 디렉터리', dir: '폴더', upload: '업로드', uploadFile: '@:file.upload @.lower:file.file', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index bd587782b..1a6a0734b 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -77,6 +77,7 @@ const message = { fix: 'Betulkan', down: 'Hentikan', up: 'Mulakan', + sure: 'Sahkan', }, operate: { start: 'Mula', @@ -1320,6 +1321,7 @@ const message = { errLog: 'Log Ralat', }, file: { + currentDir: 'Direktori Semasa', dir: 'Folder', upload: 'Muat naik', uploadFile: 'Muat naik fail', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index ef0ca93b7..5cfe3a536 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -77,6 +77,7 @@ const message = { fix: 'Corrigir', down: 'Parar', up: 'Iniciar', + sure: 'Confirmar', }, operate: { start: 'Iniciar', @@ -1304,6 +1305,7 @@ const message = { errLog: 'Logs de erro', }, file: { + currentDir: 'Diretório atual', dir: 'Pasta', upload: 'Carregar', uploadFile: '@:file.upload @.lower:file.file', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index cb0087bdc..a211d8bba 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -77,6 +77,7 @@ const message = { fix: 'Исправить', down: 'Остановить', up: 'Запустить', + sure: 'Подтвердить', }, operate: { start: 'Запустить', @@ -1308,6 +1309,7 @@ const message = { errLog: 'Логи ошибок', }, file: { + currentDir: 'Текущий каталог', dir: 'Папка', upload: 'Загрузить', uploadFile: '@:file.upload @.lower:file.file', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 272d5f4a3..8c32dd9cb 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -80,6 +80,7 @@ const message = { fix: '修復', down: '停止', up: '啟動', + sure: '確定', }, operate: { start: '啟動', @@ -1270,6 +1271,7 @@ const message = { taskRunning: '運行中', }, file: { + currentDir: '當前目錄', dir: '文件夾', upload: '上傳', download: '下載', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 0dd8a039c..aa1c895d1 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -80,6 +80,7 @@ const message = { fix: '修复', down: '停止', up: '启动', + sure: '确定', }, operate: { start: '启动', @@ -1268,6 +1269,7 @@ const message = { taskRunning: '执行中', }, file: { + currentDir: '当前目录', dir: '文件夹', fileName: '文件名', search: '在当前目录下查找', diff --git a/frontend/src/views/host/file-management/code-editor/index.vue b/frontend/src/views/host/file-management/code-editor/index.vue index 07c54dfad..072f1c1a7 100644 --- a/frontend/src/views/host/file-management/code-editor/index.vue +++ b/frontend/src/views/host/file-management/code-editor/index.vue @@ -30,10 +30,12 @@