diff --git a/backend/app/service/file.go b/backend/app/service/file.go
index cb4c4ae35..44f8eca2e 100644
--- a/backend/app/service/file.go
+++ b/backend/app/service/file.go
@@ -4,6 +4,7 @@ import (
"crypto/rand"
"fmt"
"github.com/1Panel-dev/1Panel/app/dto"
+ "github.com/1Panel-dev/1Panel/global"
"github.com/1Panel-dev/1Panel/utils/files"
"github.com/pkg/errors"
"io"
@@ -130,6 +131,24 @@ func (f FileService) MvFile(c dto.FileMove) error {
if c.Type == "cut" {
return fo.Cut(c.OldPaths, c.NewPath)
}
+ var errs []error
+ if c.Type == "copy" {
+ for _, src := range c.OldPaths {
+ if err := fo.Copy(src, c.NewPath); err != nil {
+ errs = append(errs, err)
+ global.LOG.Errorf("copy file [%s] to [%s] failed, err: %s", src, c.NewPath, err.Error())
+ }
+ }
+ }
+
+ var errString string
+ for _, err := range errs {
+ errString += err.Error() + "\n"
+ }
+ if errString != "" {
+ return errors.New(errString)
+ }
+
return nil
}
diff --git a/backend/utils/files/file_op.go b/backend/utils/files/file_op.go
index cf96d52a4..6ef469a73 100644
--- a/backend/utils/files/file_op.go
+++ b/backend/utils/files/file_op.go
@@ -4,11 +4,13 @@ import (
"context"
"github.com/1Panel-dev/1Panel/global"
"github.com/mholt/archiver/v4"
+ "github.com/pkg/errors"
"github.com/spf13/afero"
"io"
"io/fs"
"net/http"
"os"
+ "path"
"path/filepath"
)
@@ -116,6 +118,112 @@ func (f FileOp) Cut(oldPaths []string, dst string) error {
return nil
}
+func (f FileOp) Copy(src, dst string) error {
+ if src = path.Clean("/" + src); src == "" {
+ return os.ErrNotExist
+ }
+
+ if dst = path.Clean("/" + dst); dst == "" {
+ return os.ErrNotExist
+ }
+
+ if src == "/" || dst == "/" {
+ return os.ErrInvalid
+ }
+
+ if dst == src {
+ return os.ErrInvalid
+ }
+
+ info, err := f.Fs.Stat(src)
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ return f.CopyDir(src, dst)
+ }
+
+ return f.CopyFile(src, dst)
+}
+
+func (f FileOp) CopyDir(src, dst string) error {
+ srcInfo, err := f.Fs.Stat(src)
+ if err != nil {
+ return err
+ }
+ dstDir := filepath.Join(dst, srcInfo.Name())
+ if err := f.Fs.MkdirAll(dstDir, srcInfo.Mode()); err != nil {
+ return err
+ }
+
+ 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())
+ fDst := filepath.Join(dstDir, obj.Name())
+
+ if obj.IsDir() {
+ err = f.CopyDir(fSrc, fDst)
+ if err != nil {
+ errs = append(errs, err)
+ }
+ } else {
+ err = f.CopyFile(fSrc, fDst)
+ 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 {
+ srcFile, err := f.Fs.Open(src)
+ if err != nil {
+ return err
+ }
+ defer srcFile.Close()
+
+ err = f.Fs.MkdirAll(filepath.Dir(dst), 0666)
+ if err != nil {
+ return err
+ }
+
+ dstFile, err := f.Fs.OpenFile(dst, 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(dst, info.Mode()); err != nil {
+ return err
+ }
+
+ return nil
+}
+
type CompressType string
const (
diff --git a/frontend/src/components/file-role/index.vue b/frontend/src/components/file-role/index.vue
index 132fce99b..b153973b7 100644
--- a/frontend/src/components/file-role/index.vue
+++ b/frontend/src/components/file-role/index.vue
@@ -24,7 +24,7 @@
diff --git a/frontend/src/views/file-management/change-role/index.vue b/frontend/src/views/file-management/change-role/index.vue
index 01aad5555..193df8104 100644
--- a/frontend/src/views/file-management/change-role/index.vue
+++ b/frontend/src/views/file-management/change-role/index.vue
@@ -6,6 +6,7 @@
width="30%"
@open="onOpen"
v-loading="loading"
+ destory-on-close
>
diff --git a/frontend/src/views/file-management/compress/index.vue b/frontend/src/views/file-management/compress/index.vue
index a55edd7e9..3ce6c5149 100644
--- a/frontend/src/views/file-management/compress/index.vue
+++ b/frontend/src/views/file-management/compress/index.vue
@@ -87,6 +87,9 @@ const extension = computed(() => {
});
const handleClose = () => {
+ if (fileForm.value) {
+ fileForm.value.resetFields();
+ }
em('close', open);
};
diff --git a/frontend/src/views/file-management/create/index.vue b/frontend/src/views/file-management/create/index.vue
index 546b75139..415f20448 100644
--- a/frontend/src/views/file-management/create/index.vue
+++ b/frontend/src/views/file-management/create/index.vue
@@ -67,6 +67,9 @@ let addForm = reactive({ path: '', name: '', isDir: false, mode: 0o755, isLink:
const em = defineEmits(['close']);
const handleClose = () => {
+ if (fileForm.value) {
+ fileForm.value.resetFields();
+ }
em('close', open);
};
diff --git a/frontend/src/views/file-management/decompress/index.vue b/frontend/src/views/file-management/decompress/index.vue
index 78c93fc5b..52a3b65de 100644
--- a/frontend/src/views/file-management/decompress/index.vue
+++ b/frontend/src/views/file-management/decompress/index.vue
@@ -71,6 +71,9 @@ let form = ref({ type: 'zip', dst: '', path: '' });
const em = defineEmits(['close']);
const handleClose = () => {
+ if (fileForm.value) {
+ fileForm.value.resetFields();
+ }
em('close', open);
};
diff --git a/frontend/src/views/file-management/download/index.vue b/frontend/src/views/file-management/download/index.vue
index 71b29d527..70bbd5f97 100644
--- a/frontend/src/views/file-management/download/index.vue
+++ b/frontend/src/views/file-management/download/index.vue
@@ -67,6 +67,9 @@ const addForm = reactive({
const em = defineEmits(['close']);
const handleClose = () => {
+ if (fileForm.value) {
+ fileForm.value.resetFields();
+ }
em('close', open);
};
diff --git a/frontend/src/views/file-management/move/index.vue b/frontend/src/views/file-management/move/index.vue
index e1f19ab15..893be9b16 100644
--- a/frontend/src/views/file-management/move/index.vue
+++ b/frontend/src/views/file-management/move/index.vue
@@ -75,6 +75,9 @@ const rules = reactive({
const em = defineEmits(['close']);
const handleClose = () => {
+ if (fileForm.value) {
+ fileForm.value.resetFields();
+ }
em('close', open);
};
diff --git a/frontend/src/views/file-management/rename/index.vue b/frontend/src/views/file-management/rename/index.vue
index bd4dc2f1c..25ebaa5d2 100644
--- a/frontend/src/views/file-management/rename/index.vue
+++ b/frontend/src/views/file-management/rename/index.vue
@@ -60,6 +60,9 @@ const rules = reactive({
const em = defineEmits(['close']);
const handleClose = () => {
+ if (fileForm.value) {
+ fileForm.value.resetFields();
+ }
em('close', false);
};
diff --git a/frontend/src/views/file-management/upload/index.vue b/frontend/src/views/file-management/upload/index.vue
index c8f27864f..01964aee2 100644
--- a/frontend/src/views/file-management/upload/index.vue
+++ b/frontend/src/views/file-management/upload/index.vue
@@ -32,7 +32,6 @@ const props = defineProps({
});
const uploadRef = ref();
-// let loading = ref(false);
const em = defineEmits(['close']);
const handleClose = () => {