1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-02-07 17:10:07 +08:00
zhengkunwang 2023-10-15 22:08:15 -05:00 committed by GitHub
parent 51ca89daba
commit 8efe0c8bed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 147 additions and 153 deletions

View File

@ -24,22 +24,26 @@ func Exec(cmdStr string) (string, error) {
return "", buserr.New(constant.ErrCmdTimeout) return "", buserr.New(constant.ErrCmdTimeout)
} }
if err != nil { if err != nil {
errMsg := "" return handleErr(stdout, stderr, err)
if len(stderr.String()) != 0 {
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
}
if len(stdout.String()) != 0 {
if len(errMsg) != 0 {
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
} else {
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
}
}
return errMsg, err
} }
return stdout.String(), nil return stdout.String(), nil
} }
func handleErr(stdout, stderr bytes.Buffer, err error) (string, error) {
errMsg := ""
if len(stderr.String()) != 0 {
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
}
if len(stdout.String()) != 0 {
if len(errMsg) != 0 {
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
} else {
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
}
}
return errMsg, err
}
func ExecWithTimeOut(cmdStr string, timeout time.Duration) (string, error) { func ExecWithTimeOut(cmdStr string, timeout time.Duration) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout) ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel() defer cancel()
@ -52,18 +56,7 @@ func ExecWithTimeOut(cmdStr string, timeout time.Duration) (string, error) {
return "", buserr.New(constant.ErrCmdTimeout) return "", buserr.New(constant.ErrCmdTimeout)
} }
if err != nil { if err != nil {
errMsg := "" return handleErr(stdout, stderr, err)
if len(stderr.String()) != 0 {
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
}
if len(stdout.String()) != 0 {
if len(errMsg) != 0 {
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
} else {
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
}
}
return errMsg, err
} }
return stdout.String(), nil return stdout.String(), nil
} }
@ -114,18 +107,7 @@ func Execf(cmdStr string, a ...interface{}) (string, error) {
cmd.Stderr = &stderr cmd.Stderr = &stderr
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
errMsg := "" return handleErr(stdout, stderr, err)
if len(stderr.String()) != 0 {
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
}
if len(stdout.String()) != 0 {
if len(errMsg) != 0 {
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
} else {
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
}
}
return errMsg, err
} }
return stdout.String(), nil return stdout.String(), nil
} }
@ -137,18 +119,7 @@ func ExecWithCheck(name string, a ...string) (string, error) {
cmd.Stderr = &stderr cmd.Stderr = &stderr
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
errMsg := "" return handleErr(stdout, stderr, err)
if len(stderr.String()) != 0 {
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
}
if len(stdout.String()) != 0 {
if len(errMsg) != 0 {
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
} else {
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
}
}
return errMsg, err
} }
return stdout.String(), nil return stdout.String(), nil
} }
@ -166,22 +137,20 @@ func ExecScript(scriptPath, workDir string) (string, error) {
return "", buserr.New(constant.ErrCmdTimeout) return "", buserr.New(constant.ErrCmdTimeout)
} }
if err != nil { if err != nil {
errMsg := "" return handleErr(stdout, stderr, err)
if len(stderr.String()) != 0 {
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
}
if len(stdout.String()) != 0 {
if len(errMsg) != 0 {
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
} else {
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
}
}
return errMsg, err
} }
return stdout.String(), nil return stdout.String(), nil
} }
func ExecCmd(cmdStr string) error {
cmd := exec.Command("bash", "-c", cmdStr)
err := cmd.Run()
if err != nil {
return err
}
return nil
}
func CheckIllegal(args ...string) bool { func CheckIllegal(args ...string) bool {
if args == nil { if args == nil {
return false return false

View File

@ -312,83 +312,14 @@ func (f FileOp) CopyDir(src, dst string) error {
return err return err
} }
dstDir := filepath.Join(dst, srcInfo.Name()) dstDir := filepath.Join(dst, srcInfo.Name())
if err := f.Fs.MkdirAll(dstDir, srcInfo.Mode()); err != nil { if err = f.Fs.MkdirAll(dstDir, srcInfo.Mode()); err != nil {
return err return err
} }
return cmd.ExecCmd(fmt.Sprintf("cp -rf %s %s", src, dst+"/"))
dir, _ := f.Fs.Open(src)
obs, err := dir.Readdir(-1)
if err != nil {
return err
}
var errs []error
for _, obj := range obs {
fSrc := filepath.Join(src, obj.Name())
if obj.IsDir() {
err = f.CopyDir(fSrc, dstDir)
if err != nil {
errs = append(errs, err)
}
} else {
err = f.CopyFile(fSrc, dstDir)
if err != nil {
errs = append(errs, err)
}
}
}
var errString string
for _, err := range errs {
errString += err.Error() + "\n"
}
if errString != "" {
return errors.New(errString)
}
return nil
} }
func (f FileOp) CopyFile(src, dst string) error { func (f FileOp) CopyFile(src, dst string) error {
srcFile, err := f.Fs.Open(src) return cmd.ExecCmd(fmt.Sprintf("cp -f %s %s", src, dst+"/"))
if err != nil {
return err
}
defer srcFile.Close()
srcInfo, err := f.Fs.Stat(src)
if err != nil {
return err
}
dstPath := path.Join(dst, srcInfo.Name())
if src == dstPath {
return nil
}
err = f.Fs.MkdirAll(filepath.Dir(dst), 0666)
if err != nil {
return err
}
dstFile, err := f.Fs.OpenFile(dstPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775)
if err != nil {
return err
}
defer dstFile.Close()
if _, err = io.Copy(dstFile, srcFile); err != nil {
return err
}
info, err := f.Fs.Stat(src)
if err != nil {
return err
}
if err = f.Fs.Chmod(dstFile.Name(), info.Mode()); err != nil {
return err
}
return nil
} }
func (f FileOp) GetDirSize(path string) (float64, error) { func (f FileOp) GetDirSize(path string) (float64, error) {

View File

@ -10,6 +10,7 @@ import (
"os/exec" "os/exec"
"path" "path"
"path/filepath" "path/filepath"
"sort"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
@ -52,6 +53,8 @@ type FileOption struct {
ShowHidden bool `json:"showHidden"` ShowHidden bool `json:"showHidden"`
Page int `json:"page"` Page int `json:"page"`
PageSize int `json:"pageSize"` PageSize int `json:"pageSize"`
SortBy string `json:"sortBy" validate:"oneof=name size modTime"`
SortOrder string `json:"sortOrder" validate:"oneof=ascending descending"`
} }
type FileSearchInfo struct { type FileSearchInfo struct {
@ -90,7 +93,7 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
} }
if op.Expand { if op.Expand {
if file.IsDir { if file.IsDir {
if err := file.listChildren(op.Dir, op.ShowHidden, op.ContainSub, op.Search, op.Page, op.PageSize); err != nil { if err := file.listChildren(op); err != nil {
return nil, err return nil, err
} }
return file, nil return file, nil
@ -139,7 +142,42 @@ func (f *FileInfo) search(search string, count int) (files []FileSearchInfo, tot
return return
} }
func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string, page, pageSize int) error { func sortFileList(list []FileSearchInfo, sortBy, sortOrder string) {
switch sortBy {
case "name":
if sortOrder == "ascending" {
sort.Slice(list, func(i, j int) bool {
return list[i].Name() < list[j].Name()
})
} else {
sort.Slice(list, func(i, j int) bool {
return list[i].Name() > list[j].Name()
})
}
case "size":
if sortOrder == "ascending" {
sort.Slice(list, func(i, j int) bool {
return list[i].Size() < list[j].Size()
})
} else {
sort.Slice(list, func(i, j int) bool {
return list[i].Size() > list[j].Size()
})
}
case "modTime":
if sortOrder == "ascending" {
sort.Slice(list, func(i, j int) bool {
return list[i].ModTime().Before(list[j].ModTime())
})
} else {
sort.Slice(list, func(i, j int) bool {
return list[i].ModTime().After(list[j].ModTime())
})
}
}
}
func (f *FileInfo) listChildren(option FileOption) error {
afs := &afero.Afero{Fs: f.Fs} afs := &afero.Afero{Fs: f.Fs}
var ( var (
files []FileSearchInfo files []FileSearchInfo
@ -147,8 +185,8 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
total int total int
) )
if search != "" && containSub { if option.Search != "" && option.ContainSub {
files, total, err = f.search(search, page*pageSize) files, total, err = f.search(option.Search, option.Page*option.PageSize)
if err != nil { if err != nil {
return err return err
} }
@ -157,34 +195,46 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
if err != nil { if err != nil {
return err return err
} }
var (
dirs []FileSearchInfo
fileList []FileSearchInfo
)
for _, file := range dirFiles { for _, file := range dirFiles {
files = append(files, FileSearchInfo{ info := FileSearchInfo{
Path: f.Path, Path: f.Path,
FileInfo: file, FileInfo: file,
}) }
if file.IsDir() {
dirs = append(dirs, info)
} else {
fileList = append(fileList, info)
}
} }
sortFileList(dirs, option.SortBy, option.SortOrder)
sortFileList(fileList, option.SortBy, option.SortOrder)
files = append(dirs, fileList...)
} }
var items []*FileInfo var items []*FileInfo
for _, df := range files { for _, df := range files {
if dir && !df.IsDir() { if option.Dir && !df.IsDir() {
continue continue
} }
name := df.Name() name := df.Name()
fPath := path.Join(df.Path, df.Name()) fPath := path.Join(df.Path, df.Name())
if search != "" { if option.Search != "" {
if containSub { if option.ContainSub {
fPath = df.Path fPath = df.Path
name = strings.TrimPrefix(strings.TrimPrefix(fPath, f.Path), "/") name = strings.TrimPrefix(strings.TrimPrefix(fPath, f.Path), "/")
} else { } else {
lowerName := strings.ToLower(name) lowerName := strings.ToLower(name)
lowerSearch := strings.ToLower(search) lowerSearch := strings.ToLower(option.Search)
if !strings.Contains(lowerName, lowerSearch) { if !strings.Contains(lowerName, lowerSearch) {
continue continue
} }
} }
} }
if !showHidden && IsHidden(name) { if !option.ShowHidden && IsHidden(name) {
continue continue
} }
f.ItemTotal++ f.ItemTotal++
@ -228,11 +278,11 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
} }
items = append(items, file) items = append(items, file)
} }
if containSub { if option.ContainSub {
f.ItemTotal = total f.ItemTotal = total
} }
start := (page - 1) * pageSize start := (option.Page - 1) * option.PageSize
end := pageSize + start end := option.PageSize + start
var result []*FileInfo var result []*FileInfo
if start < 0 || start > f.ItemTotal || end < 0 || start > end { if start < 0 || start > f.ItemTotal || end < 0 || start > end {
result = items result = items

View File

@ -1,7 +1,7 @@
{ {
"name": "panel", "name": "1Panel-Frontend",
"private": true, "private": true,
"version": "1.3", "version": "1.7",
"description": "1Panel 前端", "description": "1Panel 前端",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@ -30,6 +30,8 @@ export namespace File {
dir?: boolean; dir?: boolean;
showHidden?: boolean; showHidden?: boolean;
containSub?: boolean; containSub?: boolean;
sortBy?: string;
sortOrder?: string;
} }
export interface SearchUploadInfo extends ReqPage { export interface SearchUploadInfo extends ReqPage {

View File

@ -75,9 +75,15 @@ function sort(prop: string, order: string) {
function clearSelects() { function clearSelects() {
tableRef.value.refElTable.clearSelection(); tableRef.value.refElTable.clearSelection();
} }
function clearSort() {
tableRef.value.refElTable.clearSort();
}
defineExpose({ defineExpose({
clearSelects, clearSelects,
sort, sort,
clearSort,
}); });
onMounted(() => { onMounted(() => {

View File

@ -952,6 +952,7 @@ const message = {
currentSelect: 'Current Select: ', currentSelect: 'Current Select: ',
unsupportType: 'Unsupported file type', unsupportType: 'Unsupported file type',
deleteHelper: 'The following resources will be deleted, this operation cannot be rolled back, continue? ', deleteHelper: 'The following resources will be deleted, this operation cannot be rolled back, continue? ',
fileHeper: 'Note: 1. Sorting is not supported after searching 2. Folders are not supported by size sorting',
}, },
ssh: { ssh: {
sshAlert: sshAlert:

View File

@ -916,6 +916,7 @@ const message = {
currentSelect: '當前選中: ', currentSelect: '當前選中: ',
unsupportType: '不支持的文件類型', unsupportType: '不支持的文件類型',
deleteHelper: '以下資源將被刪除此操作不可回滾是否繼續', deleteHelper: '以下資源將被刪除此操作不可回滾是否繼續',
fileHeper: '注意1.搜尋之後不支援排序 2.依大小排序不支援資料夾',
}, },
ssh: { ssh: {
sshAlert: '列表數據根據登錄時間排序但請註意切換時區或其他操作可能導致登錄日誌的時間出現偏差', sshAlert: '列表數據根據登錄時間排序但請註意切換時區或其他操作可能導致登錄日誌的時間出現偏差',

View File

@ -916,6 +916,7 @@ const message = {
currentSelect: '当前选中: ', currentSelect: '当前选中: ',
unsupportType: '不支持的文件类型', unsupportType: '不支持的文件类型',
deleteHelper: '以下资源将被删除此操作不可回滚是否继续', deleteHelper: '以下资源将被删除此操作不可回滚是否继续',
fileHeper: '注意1.搜索之后不支持排序 2.按大小排序不支持文件夹',
}, },
ssh: { ssh: {
sshAlert: '列表数据根据登录时间排序但请注意切换时区或其他操作可能导致登录日志的时间出现偏差', sshAlert: '列表数据根据登录时间排序但请注意切换时区或其他操作可能导致登录日志的时间出现偏差',

View File

@ -40,6 +40,13 @@
/> />
</div> </div>
<LayoutContent :title="$t('file.file')" v-loading="loading"> <LayoutContent :title="$t('file.file')" v-loading="loading">
<template #prompt>
<el-alert type="info" :closable="false">
<template #default>
<span><span v-html="$t('file.fileHeper')"></span></span>
</template>
</el-alert>
</template>
<template #toolbar> <template #toolbar>
<el-dropdown @command="handleCreate"> <el-dropdown @command="handleCreate">
<el-button type="primary"> <el-button type="primary">
@ -111,9 +118,17 @@
ref="tableRef" ref="tableRef"
:data="data" :data="data"
@search="search" @search="search"
@sort-change="changeSort"
> >
<el-table-column type="selection" width="30" /> <el-table-column type="selection" width="30" />
<el-table-column :label="$t('commons.table.name')" min-width="250" fix show-overflow-tooltip> <el-table-column
:label="$t('commons.table.name')"
min-width="250"
fix
show-overflow-tooltip
sortable
prop="name"
>
<template #default="{ row }"> <template #default="{ row }">
<svg-icon v-if="row.isDir" className="table-icon" iconName="p-file-folder"></svg-icon> <svg-icon v-if="row.isDir" className="table-icon" iconName="p-file-folder"></svg-icon>
<svg-icon v-else className="table-icon" :iconName="getIconName(row.extension)"></svg-icon> <svg-icon v-else className="table-icon" :iconName="getIconName(row.extension)"></svg-icon>
@ -140,7 +155,7 @@
</el-link> </el-link>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('file.size')" prop="size" max-width="50"> <el-table-column :label="$t('file.size')" prop="size" max-width="50" sortable>
<template #default="{ row }"> <template #default="{ row }">
<span v-if="row.isDir"> <span v-if="row.isDir">
<el-button type="primary" link small @click="getDirSize(row)"> <el-button type="primary" link small @click="getDirSize(row)">
@ -156,15 +171,16 @@
<el-table-column <el-table-column
:label="$t('file.updateTime')" :label="$t('file.updateTime')"
prop="modTime" prop="modTime"
min-width="150" width="180"
:formatter="dateFormat" :formatter="dateFormat"
show-overflow-tooltip show-overflow-tooltip
sortable
></el-table-column> ></el-table-column>
<fu-table-operations <fu-table-operations
:ellipsis="mobile ? 0 : 3" :ellipsis="mobile ? 0 : 3"
:buttons="buttons" :buttons="buttons"
:label="$t('commons.table.operate')" :label="$t('commons.table.operate')"
:min-width="mobile ? 'auto' : 300" :min-width="mobile ? 'auto' : 200"
:fixed="mobile ? false : 'right'" :fixed="mobile ? false : 'right'"
fix fix
/> />
@ -213,7 +229,6 @@ import Detail from './detail/index.vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { Back, Refresh } from '@element-plus/icons-vue'; import { Back, Refresh } from '@element-plus/icons-vue';
import { MsgSuccess, MsgWarning } from '@/utils/message'; import { MsgSuccess, MsgWarning } from '@/utils/message';
// import { ElMessageBox } from 'element-plus';
import { useSearchable } from './hooks/searchable'; import { useSearchable } from './hooks/searchable';
import { ResultData } from '@/api/interface'; import { ResultData } from '@/api/interface';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
@ -238,6 +253,8 @@ const initData = () => ({
pageSize: 100, pageSize: 100,
search: '', search: '',
containSub: false, containSub: false,
sortBy: 'name',
sortOrder: 'ascending',
}); });
let req = reactive(initData()); let req = reactive(initData());
let loading = ref(false); let loading = ref(false);
@ -288,6 +305,12 @@ const mobile = computed(() => {
const search = async () => { const search = async () => {
loading.value = true; loading.value = true;
if (req.search != '') {
req.sortBy = 'name';
req.sortOrder = 'ascending';
tableRef.value.clearSort();
}
req.page = paginationConfig.currentPage; req.page = paginationConfig.currentPage;
req.pageSize = paginationConfig.pageSize; req.pageSize = paginationConfig.pageSize;
await GetFilesList(req) await GetFilesList(req)
@ -584,6 +607,16 @@ const openDetail = (row: File.File) => {
detailRef.value.acceptParams({ path: row.path }); detailRef.value.acceptParams({ path: row.path });
}; };
const changeSort = ({ prop, order }) => {
req.sortBy = prop;
req.sortOrder = order;
req.search = '';
req.page = 1;
req.pageSize = paginationConfig.pageSize;
req.containSub = false;
search();
};
const buttons = [ const buttons = [
{ {
label: i18n.global.t('file.open'), label: i18n.global.t('file.open'),