From c3274af4cd78c99dbb8aece80c5405e4731aff58 Mon Sep 17 00:00:00 2001
From: zhengkunwang223 <zhengkun@fit2cloud.com>
Date: Mon, 26 Sep 2022 22:54:38 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=88=A0=E9=99=A4?=
 =?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 backend/app/dto/app.go                           |  1 +
 backend/app/repo/app_install.go                  |  9 +++++++++
 backend/app/service/app.go                       | 16 +++++++++++++++-
 backend/utils/compose/compose.go                 |  9 +++++++++
 frontend/src/lang/modules/en.ts                  | 13 +++++++------
 frontend/src/lang/modules/zh.ts                  |  1 +
 frontend/src/views/app-store/installed/index.vue | 15 ++++++++++++---
 7 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/backend/app/dto/app.go b/backend/app/dto/app.go
index a38a227c2..3630ce5e8 100644
--- a/backend/app/dto/app.go
+++ b/backend/app/dto/app.go
@@ -87,6 +87,7 @@ var (
 	Up      AppOperate = "up"
 	Down    AppOperate = "down"
 	Restart AppOperate = "restart"
+	Delete  AppOperate = "delete"
 )
 
 type AppInstallOperate struct {
diff --git a/backend/app/repo/app_install.go b/backend/app/repo/app_install.go
index deafa72e2..09f43134d 100644
--- a/backend/app/repo/app_install.go
+++ b/backend/app/repo/app_install.go
@@ -21,11 +21,20 @@ func (a AppInstallRepo) Create(install *model.AppInstall) error {
 	db := global.DB.Model(&model.AppInstall{})
 	return db.Create(&install).Error
 }
+
 func (a AppInstallRepo) Save(install model.AppInstall) error {
 	db := global.DB.Model(&model.AppInstall{})
 	return db.Save(&install).Error
 }
 
+func (a AppInstallRepo) Delete(opts ...DBOption) error {
+	db := global.DB.Model(&model.AppInstall{})
+	for _, opt := range opts {
+		db = opt(db)
+	}
+	return db.Delete(&model.AppInstall{}).Error
+}
+
 func (a AppInstallRepo) Page(page, size int, opts ...DBOption) (int64, []model.AppInstall, error) {
 	var apps []model.AppInstall
 	db := global.DB.Model(&model.AppInstall{})
diff --git a/backend/app/service/app.go b/backend/app/service/app.go
index f16ce9be9..6796412ef 100644
--- a/backend/app/service/app.go
+++ b/backend/app/service/app.go
@@ -154,7 +154,7 @@ func (a AppService) Operate(req dto.AppInstallOperate) error {
 		return err
 	}
 	if len(appInstall) == 0 {
-		return errors.New("not found")
+		return errors.New("req not found")
 	}
 
 	install := appInstall[0]
@@ -175,6 +175,20 @@ func (a AppService) Operate(req dto.AppInstallOperate) error {
 		if err != nil {
 			return handleErr(install, err, out)
 		}
+	case dto.Delete:
+		op := files.NewFileOp()
+		appDir := path.Join(global.CONF.System.AppDir, install.App.Key, install.ContainerName)
+		dir, _ := os.Stat(appDir)
+		if dir == nil {
+			_ = appInstallRepo.Delete(commonRepo.WithByID(install.ID))
+			break
+		}
+		_ = op.DeleteDir(appDir)
+		out, err := compose.Rmf(dockerComposePath)
+		if err != nil {
+			return handleErr(install, err, out)
+		}
+		_ = appInstallRepo.Delete(commonRepo.WithByID(install.ID))
 	default:
 		return errors.New("operate not support")
 	}
diff --git a/backend/utils/compose/compose.go b/backend/utils/compose/compose.go
index 593b5b9bc..6bbe44016 100644
--- a/backend/utils/compose/compose.go
+++ b/backend/utils/compose/compose.go
@@ -28,3 +28,12 @@ func Restart(filePath string) (string, error) {
 	}
 	return string(stdout), nil
 }
+
+func Rmf(filePath string) (string, error) {
+	cmd := exec.Command("docker-compose", "-f", filePath, "rm", "-f")
+	stdout, err := cmd.CombinedOutput()
+	if err != nil {
+		return "", err
+	}
+	return string(stdout), nil
+}
diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts
index 6e8e984dd..c103e04e3 100644
--- a/frontend/src/lang/modules/en.ts
+++ b/frontend/src/lang/modules/en.ts
@@ -408,11 +408,12 @@ export default {
         sync: 'sync',
         appName: 'App Name',
         status: 'status',
-        container: 'container',
-        restart: 'restart',
-        up: 'start',
-        down: 'stop',
-        name: 'name',
-        description: 'description',
+        container: 'Container',
+        restart: 'Restart',
+        up: 'Start',
+        down: 'Stop',
+        name: 'Name',
+        description: 'Description',
+        delete: 'Delete',
     },
 };
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index 3cd216d6f..8b8c25c95 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -406,5 +406,6 @@ export default {
         down: '停止',
         name: '名称',
         description: '描述',
+        delete: '删除',
     },
 };
diff --git a/frontend/src/views/app-store/installed/index.vue b/frontend/src/views/app-store/installed/index.vue
index e26a66a4a..ee85e11b4 100644
--- a/frontend/src/views/app-store/installed/index.vue
+++ b/frontend/src/views/app-store/installed/index.vue
@@ -1,7 +1,7 @@
 <template>
     <ComplexTable :pagination-config="paginationConfig" :data="data" @search="search" v-loading="loading">
         <el-table-column :label="$t('app.name')" prop="name"></el-table-column>
-        <el-table-column :label="$t('app.description')" prop="description"></el-table-column>
+        <!-- <el-table-column :label="$t('app.description')" prop="description"></el-table-column> -->
         <el-table-column :label="$t('app.appName')" prop="appName"></el-table-column>
         <el-table-column :label="$t('app.version')" prop="version"></el-table-column>
         <el-table-column :label="$t('app.container')">
@@ -41,7 +41,7 @@ import { onMounted, reactive, ref } from 'vue';
 import ComplexTable from '@/components/complex-table/index.vue';
 import { dateFromat } from '@/utils/util';
 import i18n from '@/lang';
-import { ElMessageBox } from 'element-plus';
+import { ElMessage, ElMessageBox } from 'element-plus';
 
 let data = ref<any>();
 let loading = ref(false);
@@ -77,7 +77,10 @@ const operate = async (row: any, op: string) => {
     }).then(async () => {
         loading.value = true;
         InstalledOp(req)
-            .then(() => {})
+            .then(() => {
+                ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
+                search();
+            })
             .finally(() => {
                 loading.value = false;
             });
@@ -103,6 +106,12 @@ const buttons = [
             operate(row, 'down');
         },
     },
+    {
+        label: i18n.global.t('app.delete'),
+        click: (row: any) => {
+            operate(row, 'delete');
+        },
+    },
 ];
 
 onMounted(() => {