mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-02-07 17:10:07 +08:00
style: 增加计算文件夹大小接口
This commit is contained in:
parent
450114f049
commit
d333fae2fe
@ -207,3 +207,17 @@ func (b *BaseApi) Download(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
c.File(filePath)
|
c.File(filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) Size(c *gin.Context) {
|
||||||
|
var req dto.DirSizeReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := fileService.DirSize(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
|
@ -75,3 +75,11 @@ type FileDownload struct {
|
|||||||
Type string `json:"type" validate:"required"`
|
Type string `json:"type" validate:"required"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DirSizeReq struct {
|
||||||
|
Path string `json:"path" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DirSizeRes struct {
|
||||||
|
Size float64 `json:"size" validate:"required"`
|
||||||
|
}
|
||||||
|
@ -167,6 +167,15 @@ func (f FileService) FileDownload(d dto.FileDownload) (string, error) {
|
|||||||
return filePath, nil
|
return filePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f FileService) DirSize(req dto.DirSizeReq) (dto.DirSizeRes, error) {
|
||||||
|
fo := files.NewFileOp()
|
||||||
|
size, err := fo.GetDirSize(req.Path)
|
||||||
|
if err != nil {
|
||||||
|
return dto.DirSizeRes{}, err
|
||||||
|
}
|
||||||
|
return dto.DirSizeRes{Size: size}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func getUuid() string {
|
func getUuid() string {
|
||||||
b := make([]byte, 16)
|
b := make([]byte, 16)
|
||||||
_, _ = io.ReadFull(rand.Reader, b)
|
_, _ = io.ReadFull(rand.Reader, b)
|
||||||
|
@ -29,6 +29,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
|||||||
fileRouter.POST("/wget", baseApi.WgetFile)
|
fileRouter.POST("/wget", baseApi.WgetFile)
|
||||||
fileRouter.POST("/move", baseApi.MoveFile)
|
fileRouter.POST("/move", baseApi.MoveFile)
|
||||||
fileRouter.POST("/download", baseApi.Download)
|
fileRouter.POST("/download", baseApi.Download)
|
||||||
|
fileRouter.POST("/size", baseApi.Size)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileOp struct {
|
type FileOp struct {
|
||||||
@ -221,6 +222,23 @@ func (f FileOp) CopyFile(src, dst string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f FileOp) GetDirSize(path string) (float64, error) {
|
||||||
|
var m sync.Map
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go ScanDir(f.Fs, path, &m, &wg)
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
var dirSize float64
|
||||||
|
m.Range(func(k, v interface{}) bool {
|
||||||
|
dirSize = dirSize + v.(float64)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return dirSize, nil
|
||||||
|
}
|
||||||
|
|
||||||
type CompressType string
|
type CompressType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -2,9 +2,12 @@ package files
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gabriel-vasile/mimetype"
|
"github.com/gabriel-vasile/mimetype"
|
||||||
|
"github.com/spf13/afero"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IsSymlink(mode os.FileMode) bool {
|
func IsSymlink(mode os.FileMode) bool {
|
||||||
@ -43,6 +46,22 @@ func GetSymlink(path string) string {
|
|||||||
return linkPath
|
return linkPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ScanDir(fs afero.Fs, path string, dirMap *sync.Map, wg *sync.WaitGroup) {
|
||||||
|
afs := &afero.Afero{Fs: fs}
|
||||||
|
files, _ := afs.ReadDir(path)
|
||||||
|
for _, f := range files {
|
||||||
|
if f.IsDir() {
|
||||||
|
wg.Add(1)
|
||||||
|
go ScanDir(fs, filepath.Join(path, f.Name()), dirMap, wg)
|
||||||
|
} else {
|
||||||
|
if f.Size() > 0 {
|
||||||
|
dirMap.Store(filepath.Join(path, f.Name()), float64(f.Size()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
const dotCharacter = 46
|
const dotCharacter = 46
|
||||||
|
|
||||||
func IsHidden(path string) bool {
|
func IsHidden(path string) bool {
|
||||||
|
@ -15,6 +15,7 @@ export namespace File {
|
|||||||
modTime: string;
|
modTime: string;
|
||||||
mode: number;
|
mode: number;
|
||||||
mimeType: string;
|
mimeType: string;
|
||||||
|
dirSize: number;
|
||||||
items: File[];
|
items: File[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,4 +90,12 @@ export namespace File {
|
|||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DirSizeReq {
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DirSizeRes {
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,3 +56,7 @@ export const MoveFile = (params: File.FileMove) => {
|
|||||||
export const DownloadFile = (params: File.FileDownload) => {
|
export const DownloadFile = (params: File.FileDownload) => {
|
||||||
return http.download<BlobPart>('files/download', params, { responseType: 'blob' });
|
return http.download<BlobPart>('files/download', params, { responseType: 'blob' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ComputeDirSize = (params: File.DirSizeReq) => {
|
||||||
|
return http.post<File.DirSizeRes>('files/size', params);
|
||||||
|
};
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
<template #menu>
|
<template #menu>
|
||||||
<Menu></Menu>
|
<Menu></Menu>
|
||||||
</template>
|
</template>
|
||||||
<!-- <template #header>
|
<template #header>
|
||||||
<Header></Header>
|
<Header></Header>
|
||||||
</template> -->
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</template>
|
</template>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Layout from '@/layout/index.vue';
|
import Layout from '@/layout/index.vue';
|
||||||
// import Header from './header/index.vue';
|
import Header from './header/index.vue';
|
||||||
import Footer from './footer/index.vue';
|
import Footer from './footer/index.vue';
|
||||||
import Menu from './menu/index.vue';
|
import Menu from './menu/index.vue';
|
||||||
</script>
|
</script>
|
||||||
|
@ -242,5 +242,6 @@ export default {
|
|||||||
moveStart: 'Move start',
|
moveStart: 'Move start',
|
||||||
move: 'Move',
|
move: 'Move',
|
||||||
copy: 'Cpoy',
|
copy: 'Cpoy',
|
||||||
|
calculate: 'Calculate',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -242,5 +242,6 @@ export default {
|
|||||||
moveStart: '移动成功',
|
moveStart: '移动成功',
|
||||||
move: '移动',
|
move: '移动',
|
||||||
copy: '复制',
|
copy: '复制',
|
||||||
|
calculate: '计算',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -72,3 +72,13 @@ export function getRandomStr(e: number): string {
|
|||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function computeSize(size: number): string {
|
||||||
|
const num = 1024.0;
|
||||||
|
|
||||||
|
if (size < num) return size + ' B';
|
||||||
|
if (size < Math.pow(num, 2)) return (size / num).toFixed(2) + ' K';
|
||||||
|
if (size < Math.pow(num, 3)) return (size / Math.pow(num, 2)).toFixed(2) + ' MB';
|
||||||
|
if (size < Math.pow(num, 4)) return (size / Math.pow(num, 3)).toFixed(2) + ' GB';
|
||||||
|
return (size / Math.pow(num, 4)).toFixed(2) + ' TB';
|
||||||
|
}
|
||||||
|
@ -105,7 +105,19 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('file.user')" prop="user"></el-table-column>
|
<el-table-column :label="$t('file.user')" prop="user"></el-table-column>
|
||||||
<el-table-column :label="$t('file.group')" prop="group"></el-table-column>
|
<el-table-column :label="$t('file.group')" prop="group"></el-table-column>
|
||||||
<el-table-column :label="$t('file.size')" prop="size"></el-table-column>
|
<el-table-column :label="$t('file.size')" prop="size">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span v-if="row.isDir">
|
||||||
|
<el-button type="primary" link small @click="getDirSize(row)">
|
||||||
|
<span v-if="row.dirSize == undefined">
|
||||||
|
{{ $t('file.calculate') }}
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ getFileSize(row.dirSize) }}</span>
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ getFileSize(row.size) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
:label="$t('file.updateTime')"
|
:label="$t('file.updateTime')"
|
||||||
prop="modTime"
|
prop="modTime"
|
||||||
@ -170,8 +182,15 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
||||||
import { GetFilesList, GetFilesTree, DeleteFile, GetFileContent, SaveFileContent } from '@/api/modules/files';
|
import {
|
||||||
import { dateFromat, getRandomStr } from '@/utils/util';
|
GetFilesList,
|
||||||
|
GetFilesTree,
|
||||||
|
DeleteFile,
|
||||||
|
GetFileContent,
|
||||||
|
SaveFileContent,
|
||||||
|
ComputeDirSize,
|
||||||
|
} from '@/api/modules/files';
|
||||||
|
import { computeSize, dateFromat, getRandomStr } from '@/utils/util';
|
||||||
import { File } from '@/api/interface/file';
|
import { File } from '@/api/interface/file';
|
||||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
@ -192,10 +211,10 @@ import Move from './move/index.vue';
|
|||||||
import Download from './download/index.vue';
|
import Download from './download/index.vue';
|
||||||
|
|
||||||
const data = ref();
|
const data = ref();
|
||||||
const selects = ref<any>([]);
|
let selects = ref<any>([]);
|
||||||
const req = reactive({ path: '/', expand: true, showHidden: false });
|
let req = reactive({ path: '/', expand: true, showHidden: false });
|
||||||
const loading = ref(false);
|
let loading = ref(false);
|
||||||
const treeLoading = ref(false);
|
let treeLoading = ref(false);
|
||||||
const paths = ref<string[]>([]);
|
const paths = ref<string[]>([]);
|
||||||
const fileTree = ref<File.FileTree[]>([]);
|
const fileTree = ref<File.FileTree[]>([]);
|
||||||
const expandKeys = ref<string[]>([]);
|
const expandKeys = ref<string[]>([]);
|
||||||
@ -326,6 +345,24 @@ const delFile = async (row: File.File | null) => {
|
|||||||
search(req);
|
search(req);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getFileSize = (size: number) => {
|
||||||
|
return computeSize(size);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDirSize = async (row: any) => {
|
||||||
|
const req = {
|
||||||
|
path: row.path,
|
||||||
|
};
|
||||||
|
loading.value = true;
|
||||||
|
await ComputeDirSize(req)
|
||||||
|
.then(async (res) => {
|
||||||
|
row.dirSize = res.data.size;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const closeCreate = () => {
|
const closeCreate = () => {
|
||||||
filePage.open = false;
|
filePage.open = false;
|
||||||
search(req);
|
search(req);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user