diff --git a/backend/app/dto/request/app.go b/backend/app/dto/request/app.go index c9598e291..573f8d8fe 100644 --- a/backend/app/dto/request/app.go +++ b/backend/app/dto/request/app.go @@ -35,10 +35,12 @@ type AppBackupDelete struct { } type AppInstalledOperate struct { - InstallId uint `json:"installId" validate:"required"` - BackupId uint `json:"backupId"` - DetailId uint `json:"detailId"` - Operate constant.AppOperate `json:"operate" validate:"required"` + InstallId uint `json:"installId" validate:"required"` + BackupId uint `json:"backupId"` + DetailId uint `json:"detailId"` + Operate constant.AppOperate `json:"operate" validate:"required"` + ForceDelete bool `json:"forceDelete"` + DeleteBackup bool `json:"deleteBackup"` } type PortUpdate struct { diff --git a/backend/app/service/app_install.go b/backend/app/service/app_install.go index 80f057303..3b5ade574 100644 --- a/backend/app/service/app_install.go +++ b/backend/app/service/app_install.go @@ -143,7 +143,7 @@ func (a AppInstallService) Operate(req request.AppInstalledOperate) error { install.Status = constant.Running case constant.Delete: tx, ctx := getTxAndContext() - if err := deleteAppInstall(ctx, install); err != nil { + if err := deleteAppInstall(ctx, install, req.ForceDelete, req.DeleteBackup); err != nil { tx.Rollback() return err } diff --git a/backend/app/service/app_utils.go b/backend/app/service/app_utils.go index 16a63013c..8e8b152b5 100644 --- a/backend/app/service/app_utils.go +++ b/backend/app/service/app_utils.go @@ -156,7 +156,7 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall return nil } -func deleteAppInstall(ctx context.Context, install model.AppInstall) error { +func deleteAppInstall(ctx context.Context, install model.AppInstall, forceDelete bool, deleteBackup bool) error { op := files.NewFileOp() appDir := install.GetPath() dir, _ := os.Stat(appDir) @@ -169,19 +169,20 @@ func deleteAppInstall(ctx context.Context, install model.AppInstall) error { return err } } - if err := appInstallRepo.Delete(ctx, install); err != nil { return err } - if err := deleteLink(ctx, &install); err != nil { + if err := deleteLink(ctx, &install); err != nil && !forceDelete { return err } - backups, _ := appInstallBackupRepo.GetBy(appInstallBackupRepo.WithAppInstallID(install.ID)) - for _, backup := range backups { - _ = op.DeleteDir(backup.Path) - } - if err := appInstallBackupRepo.Delete(ctx, appInstallBackupRepo.WithAppInstallID(install.ID)); err != nil { - return err + if deleteBackup { + backups, _ := appInstallBackupRepo.GetBy(appInstallBackupRepo.WithAppInstallID(install.ID)) + for _, backup := range backups { + _ = op.DeleteDir(backup.Path) + } + if err := appInstallBackupRepo.Delete(ctx, appInstallBackupRepo.WithAppInstallID(install.ID)); err != nil { + return err + } } return nil } diff --git a/backend/app/service/website.go b/backend/app/service/website.go index 01e5075ad..2c6810671 100644 --- a/backend/app/service/website.go +++ b/backend/app/service/website.go @@ -263,7 +263,7 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error { return err } if !reflect.DeepEqual(model.AppInstall{}, appInstall) { - if err := deleteAppInstall(ctx, appInstall); err != nil { + if err := deleteAppInstall(ctx, appInstall, req.ForceDelete, true); err != nil { return err } } diff --git a/frontend/src/api/interface/app.ts b/frontend/src/api/interface/app.ts index 5401ebb33..687c40cbc 100644 --- a/frontend/src/api/interface/app.ts +++ b/frontend/src/api/interface/app.ts @@ -108,6 +108,8 @@ export namespace App { operate: string; backupId?: number; detailId?: number; + forceDelete?: boolean; + deleteBackup?: boolean; } export interface AppInstalledSearch { diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 96d0ec81c..b86df324d 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -789,6 +789,10 @@ export default { database: '数据库', defaultConfig: '默认配置', defaultConfigHelper: '已恢复为默认配置,保存后生效', + forceDelete: '强制删除', + forceDeleteHelper: '强制删除,会忽略删除过程中碰到的问题,最终删除元数据', + deleteBackup: '删除备份', + deleteBackupHelper: '同时删除应用备份', }, website: { website: '网站', diff --git a/frontend/src/views/app-store/installed/delete/index.vue b/frontend/src/views/app-store/installed/delete/index.vue new file mode 100644 index 000000000..d2c560487 --- /dev/null +++ b/frontend/src/views/app-store/installed/delete/index.vue @@ -0,0 +1,105 @@ + + + + + + + + + {{ $t('app.forceDeleteHelper') }} + + + + + + + + {{ $t('app.deleteBackupHelper') }} + + + + + + + + + + + + {{ $t('commons.button.cancel') }} + + + {{ $t('commons.button.confirm') }} + + + + + + + + diff --git a/frontend/src/views/app-store/installed/index.vue b/frontend/src/views/app-store/installed/index.vue index dcfc6d3bf..f51c702b9 100644 --- a/frontend/src/views/app-store/installed/index.vue +++ b/frontend/src/views/app-store/installed/index.vue @@ -109,6 +109,7 @@ + @@ -127,8 +128,9 @@ import i18n from '@/lang'; import { ElMessage, ElMessageBox } from 'element-plus'; import Backups from './backups.vue'; import AppResources from './check/index.vue'; +import AppDelete from './delete/index.vue'; import { App } from '@/api/interface/app'; -import { useDeleteData } from '@/hooks/use-delete-data'; +// import { useDeleteData } from '@/hooks/use-delete-data'; import Status from '@/components/status/index.vue'; let data = ref(); @@ -148,6 +150,7 @@ let operateReq = reactive({ let versions = ref(); const backupRef = ref(); const checkRef = ref(); +const deleteRef = ref(); let searchName = ref(''); const sync = () => { @@ -192,8 +195,10 @@ const openOperate = (row: any, op: string) => { if (res.data && res.data.length > 0) { checkRef.value.acceptParams({ items: items }); } else { - await useDeleteData(InstalledOp, operateReq, 'app.deleteWarn'); - search(); + deleteRef.value.acceptParams(row); + + // await useDeleteData(InstalledOp, operateReq, 'app.deleteWarn'); + // search(); } }); } else {