mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-10 23:47:39 +08:00
feat: 增加文件搜索功能
This commit is contained in:
parent
05f2c4661c
commit
292dbf58c5
5 changed files with 108 additions and 21 deletions
|
@ -4,9 +4,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -39,6 +41,7 @@ type FileInfo struct {
|
||||||
type FileOption struct {
|
type FileOption struct {
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Search string `json:"search"`
|
Search string `json:"search"`
|
||||||
|
ContainSub bool `json:"containSub"`
|
||||||
Expand bool `json:"expand"`
|
Expand bool `json:"expand"`
|
||||||
Dir bool `json:"dir"`
|
Dir bool `json:"dir"`
|
||||||
ShowHidden bool `json:"showHidden"`
|
ShowHidden bool `json:"showHidden"`
|
||||||
|
@ -46,6 +49,11 @@ type FileOption struct {
|
||||||
PageSize int `json:"pageSize"`
|
PageSize int `json:"pageSize"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileSearchInfo struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
fs.FileInfo
|
||||||
|
}
|
||||||
|
|
||||||
func NewFileInfo(op FileOption) (*FileInfo, error) {
|
func NewFileInfo(op FileOption) (*FileInfo, error) {
|
||||||
var appFs = afero.NewOsFs()
|
var appFs = afero.NewOsFs()
|
||||||
|
|
||||||
|
@ -75,7 +83,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.Page, op.PageSize); err != nil {
|
if err := file.listChildren(op.Dir, op.ShowHidden, op.ContainSub, op.Search, op.Page, op.PageSize); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return file, nil
|
return file, nil
|
||||||
|
@ -88,12 +96,59 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FileInfo) listChildren(dir, showHidden bool, page, pageSize int) error {
|
func (f *FileInfo) search(dir, showHidden bool, af afero.Afero, search string, count int) ([]FileSearchInfo, error) {
|
||||||
afs := &afero.Afero{Fs: f.Fs}
|
var files []FileSearchInfo
|
||||||
files, err := afs.ReadDir(f.Path)
|
if err := afero.Walk(af, f.Path, func(path string, info fs.FileInfo, err error) error {
|
||||||
if err != nil {
|
if info != nil {
|
||||||
return err
|
|
||||||
|
if dir && !info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !showHidden && IsHidden(info.Name()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lowerName := strings.ToLower(info.Name())
|
||||||
|
lowerSearch := strings.ToLower(search)
|
||||||
|
if strings.Contains(lowerName, lowerSearch) {
|
||||||
|
files = append(files, FileSearchInfo{
|
||||||
|
Path: path,
|
||||||
|
FileInfo: info,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string, page, pageSize int) error {
|
||||||
|
afs := &afero.Afero{Fs: f.Fs}
|
||||||
|
var (
|
||||||
|
files []FileSearchInfo
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if search != "" && containSub {
|
||||||
|
files, err = f.search(dir, showHidden, *afs, search, page*pageSize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dirFiles, err := afs.ReadDir(f.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, file := range dirFiles {
|
||||||
|
files = append(files, FileSearchInfo{
|
||||||
|
Path: f.Path,
|
||||||
|
FileInfo: file,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
f.ItemTotal = 0
|
f.ItemTotal = 0
|
||||||
|
|
||||||
var items []*FileInfo
|
var items []*FileInfo
|
||||||
|
@ -103,7 +158,20 @@ func (f *FileInfo) listChildren(dir, showHidden bool, page, pageSize int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
name := df.Name()
|
name := df.Name()
|
||||||
fPath := path.Join(f.Path, df.Name())
|
fPath := path.Join(df.Path, df.Name())
|
||||||
|
|
||||||
|
if search != "" {
|
||||||
|
if containSub {
|
||||||
|
fPath = df.Path
|
||||||
|
name = strings.TrimPrefix(strings.TrimPrefix(fPath, f.Path), "/")
|
||||||
|
} else {
|
||||||
|
lowerName := strings.ToLower(name)
|
||||||
|
lowerSearch := strings.ToLower(search)
|
||||||
|
if !strings.Contains(lowerName, lowerSearch) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !showHidden && IsHidden(name) {
|
if !showHidden && IsHidden(name) {
|
||||||
continue
|
continue
|
||||||
|
@ -115,7 +183,7 @@ func (f *FileInfo) listChildren(dir, showHidden bool, page, pageSize int) error
|
||||||
isSymlink = true
|
isSymlink = true
|
||||||
info, err := f.Fs.Stat(fPath)
|
info, err := f.Fs.Stat(fPath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
df = info
|
df.FileInfo = info
|
||||||
} else {
|
} else {
|
||||||
isInvalidLink = true
|
isInvalidLink = true
|
||||||
}
|
}
|
||||||
|
@ -137,6 +205,7 @@ func (f *FileInfo) listChildren(dir, showHidden bool, page, pageSize int) error
|
||||||
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
|
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
|
||||||
MimeType: GetMimeType(fPath),
|
MimeType: GetMimeType(fPath),
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSymlink {
|
if isSymlink {
|
||||||
file.LinkPath = GetSymlink(fPath)
|
file.LinkPath = GetSymlink(fPath)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ export namespace File {
|
||||||
expand: boolean;
|
expand: boolean;
|
||||||
dir?: boolean;
|
dir?: boolean;
|
||||||
showHidden?: boolean;
|
showHidden?: boolean;
|
||||||
|
containSub?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileTree {
|
export interface FileTree {
|
||||||
|
|
|
@ -652,7 +652,7 @@ export default {
|
||||||
upload: '上传',
|
upload: '上传',
|
||||||
download: '下载',
|
download: '下载',
|
||||||
fileName: '文件名',
|
fileName: '文件名',
|
||||||
search: '查找',
|
search: '在当前目录下查找',
|
||||||
mode: '权限',
|
mode: '权限',
|
||||||
owner: '所有者',
|
owner: '所有者',
|
||||||
file: '文件',
|
file: '文件',
|
||||||
|
|
|
@ -231,6 +231,10 @@
|
||||||
.el-input__wrapper {
|
.el-input__wrapper {
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
}
|
}
|
||||||
|
.el-input-group__prepend {
|
||||||
|
border-top-left-radius: 50px;
|
||||||
|
border-bottom-left-radius: 50px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// drawer头部增加按钮
|
// drawer头部增加按钮
|
||||||
|
|
|
@ -60,16 +60,18 @@
|
||||||
<el-button plain @click="openDownload" :disabled="selects.length === 0">
|
<el-button plain @click="openDownload" :disabled="selects.length === 0">
|
||||||
{{ $t('file.download') }}
|
{{ $t('file.download') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<!-- <div class="search-button">
|
<div class="search search-button">
|
||||||
<el-input
|
<el-input
|
||||||
clearable
|
v-model="req.search"
|
||||||
@clear="search()"
|
clearable
|
||||||
suffix-icon="Search"
|
@clear="search()"
|
||||||
@keyup.enter="search()"
|
suffix-icon="Search"
|
||||||
@blur="search()"
|
@blur="search()"
|
||||||
:placeholder="$t('commons.button.search')"
|
:placeholder="$t('file.search')"
|
||||||
></el-input>
|
>
|
||||||
</div> -->
|
<template #prepend><el-checkbox v-model="req.containSub">包含子目录</el-checkbox></template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #main>
|
<template #main>
|
||||||
<ComplexTable
|
<ComplexTable
|
||||||
|
@ -175,7 +177,15 @@ interface FilePaths {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const data = ref();
|
const data = ref();
|
||||||
let selects = ref<any>([]);
|
let selects = ref<any>([]);
|
||||||
let req = reactive({ path: '/', expand: true, showHidden: false, page: 1, pageSize: 100 });
|
let req = reactive({
|
||||||
|
path: '/',
|
||||||
|
expand: true,
|
||||||
|
showHidden: false,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 100,
|
||||||
|
search: '',
|
||||||
|
containSub: false,
|
||||||
|
});
|
||||||
let loading = ref(false);
|
let loading = ref(false);
|
||||||
const paths = ref<FilePaths[]>([]);
|
const paths = ref<FilePaths[]>([]);
|
||||||
let pathWidth = ref(0);
|
let pathWidth = ref(0);
|
||||||
|
@ -258,6 +268,8 @@ const handlePath = () => {
|
||||||
|
|
||||||
const jump = async (url: string) => {
|
const jump = async (url: string) => {
|
||||||
req.path = url;
|
req.path = url;
|
||||||
|
req.containSub = false;
|
||||||
|
req.search = '';
|
||||||
await search();
|
await search();
|
||||||
getPaths(req.path);
|
getPaths(req.path);
|
||||||
nextTick(function () {
|
nextTick(function () {
|
||||||
|
@ -482,8 +494,9 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-button {
|
.search {
|
||||||
float: right;
|
float: right;
|
||||||
display: inline;
|
display: inline;
|
||||||
|
width: 20%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Add table
Reference in a new issue