From 78990c6094cec97eac45a0aa4269925a5fac98c4 Mon Sep 17 00:00:00 2001
From: yumaojun03 <719118794@qq.com>
Date: Sun, 17 Aug 2025 18:25:13 +0800
Subject: [PATCH] =?UTF-8?q?add=20=20app=E9=A1=B5=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
devcloud/mcenter/apps/label/api/api.go | 57 ++++++
devcloud/mcenter/apps/label/api/label.go | 32 ++++
devcloud/mcenter/apps/label/impl/label.go | 5 +
.../mcenter/apps/label/impl/label_test.go | 1 +
devcloud/mcenter/apps/label/interface.go | 1 +
devcloud/mcenter/apps/registry.go | 1 +
devcloud/mpaas/apps/application/api/api.go | 23 +++
.../mpaas/apps/application/api/application.go | 38 ++++
.../apps/application/impl/application.go | 3 +
.../apps/application/impl/application_test.go | 1 +
devcloud/mpaas/apps/application/interface.go | 20 +-
devcloud/web/src/api/client.js | 2 +-
devcloud/web/src/api/mcenter.js | 3 +
devcloud/web/src/api/mppas.js | 9 +
devcloud/web/src/layout/DashboardLayout.vue | 2 +-
devcloud/web/src/layout/FrontendLayout.vue | 2 +-
devcloud/web/src/layout/MenuLayout.vue | 2 +-
devcloud/web/src/pages/develop/AppPage.vue | 145 ++++++++++-----
.../pages/develop/components/AppFormModel.vue | 175 ++++++++++++++++++
go.mod | 2 +-
go.sum | 4 +-
21 files changed, 467 insertions(+), 61 deletions(-)
create mode 100644 devcloud/mcenter/apps/label/api/api.go
create mode 100644 devcloud/mcenter/apps/label/api/label.go
create mode 100644 devcloud/web/src/pages/develop/components/AppFormModel.vue
diff --git a/devcloud/mcenter/apps/label/api/api.go b/devcloud/mcenter/apps/label/api/api.go
new file mode 100644
index 0000000..2808f94
--- /dev/null
+++ b/devcloud/mcenter/apps/label/api/api.go
@@ -0,0 +1,57 @@
+package api
+
+import (
+ "122.51.31.227/go-course/go18/devcloud/audit/audit"
+ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label"
+ "122.51.31.227/go-course/go18/devcloud/mcenter/permission"
+ "github.com/infraboard/mcube/v2/ioc"
+ "github.com/infraboard/mcube/v2/ioc/config/gorestful"
+
+ restfulspec "github.com/emicklei/go-restful-openapi/v2"
+ "github.com/emicklei/go-restful/v3"
+)
+
+func init() {
+ ioc.Api().Registry(&LabelRestfulApiHandler{})
+}
+
+type LabelRestfulApiHandler struct {
+ ioc.ObjectImpl
+
+ // 依赖控制器
+ svc label.Service
+}
+
+func (h *LabelRestfulApiHandler) Name() string {
+ return "labels"
+}
+
+func (h *LabelRestfulApiHandler) Init() error {
+ h.svc = label.GetService()
+
+ tags := []string{"标签管理"}
+ ws := gorestful.ObjectRouter(h)
+ // required_auth=true/false
+ ws.Route(ws.GET("").To(h.QueryLabel).
+ Doc("标签列表查询").
+ Metadata(restfulspec.KeyOpenAPITags, tags).
+ // 这个开关怎么生效
+ // 中间件需求读取接口的描述信息,来决定是否需要认证
+ Metadata(permission.Auth(true)).
+ Metadata(permission.Permission(false)).
+ Metadata(permission.Resource("labels")).
+ Metadata(permission.Action("list")).
+ Metadata(audit.Enable(true)).
+ Param(restful.QueryParameter("page_size", "分页大小").DataType("integer")).
+ Param(restful.QueryParameter("page_number", "页码").DataType("integer")).
+ Writes(Set{}).
+ Returns(200, "OK", Set{}))
+ return nil
+}
+
+// *types.Set[*Label]
+// 返回的泛型, API Doc这个工具 不支持泛型
+type Set struct {
+ Total int64 `json:"total"`
+ Items []label.Label `json:"items"`
+}
diff --git a/devcloud/mcenter/apps/label/api/label.go b/devcloud/mcenter/apps/label/api/label.go
new file mode 100644
index 0000000..3ca5067
--- /dev/null
+++ b/devcloud/mcenter/apps/label/api/label.go
@@ -0,0 +1,32 @@
+package api
+
+import (
+ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label"
+ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/token"
+ "github.com/emicklei/go-restful/v3"
+ "github.com/gin-gonic/gin/binding"
+ "github.com/infraboard/mcube/v2/http/restful/response"
+ "github.com/infraboard/mcube/v2/ioc/config/log"
+)
+
+func (h *LabelRestfulApiHandler) QueryLabel(r *restful.Request, w *restful.Response) {
+ req := label.NewQueryLabelRequest()
+
+ // 过滤条件在认证完成后的上下文中
+ tk := token.GetTokenFromCtx(r.Request.Context())
+ log.L().Debug().Msgf("resource scope: %s", tk.ResourceScope)
+
+ // 用户的参数
+ if err := binding.Query.Bind(r.Request, &req); err != nil {
+ response.Failed(w, err)
+ return
+ }
+
+ set, err := h.svc.QueryLabel(r.Request.Context(), req)
+ if err != nil {
+ response.Failed(w, err)
+ return
+ }
+
+ response.Success(w, set)
+}
diff --git a/devcloud/mcenter/apps/label/impl/label.go b/devcloud/mcenter/apps/label/impl/label.go
index 8fa0fc7..82545cd 100644
--- a/devcloud/mcenter/apps/label/impl/label.go
+++ b/devcloud/mcenter/apps/label/impl/label.go
@@ -30,6 +30,11 @@ func (i *LabelServiceImpl) QueryLabel(ctx context.Context, in *label.QueryLabelR
set := types.New[*label.Label]()
query := datasource.DBFromCtx(ctx).Model(&label.Label{})
+
+ if in.Key != "" {
+ query = query.Where("`key` = ?", in.Key)
+ }
+
err := query.Count(&set.Total).Error
if err != nil {
return nil, err
diff --git a/devcloud/mcenter/apps/label/impl/label_test.go b/devcloud/mcenter/apps/label/impl/label_test.go
index cb67b0e..449cb69 100644
--- a/devcloud/mcenter/apps/label/impl/label_test.go
+++ b/devcloud/mcenter/apps/label/impl/label_test.go
@@ -29,6 +29,7 @@ func TestCreateLabel(t *testing.T) {
func TestQueryLabel(t *testing.T) {
req := label.NewQueryLabelRequest()
+ req.Key = "team"
set, err := svc.QueryLabel(ctx, req)
if err != nil {
t.Fatal(err)
diff --git a/devcloud/mcenter/apps/label/interface.go b/devcloud/mcenter/apps/label/interface.go
index 9b3303f..0c5ae8d 100644
--- a/devcloud/mcenter/apps/label/interface.go
+++ b/devcloud/mcenter/apps/label/interface.go
@@ -49,6 +49,7 @@ func NewQueryLabelRequest() *QueryLabelRequest {
type QueryLabelRequest struct {
*request.PageRequest
+ Key string `json:"key" form:"key"`
}
type DescribeLabelRequest struct {
diff --git a/devcloud/mcenter/apps/registry.go b/devcloud/mcenter/apps/registry.go
index 269fc01..3ccb0a4 100644
--- a/devcloud/mcenter/apps/registry.go
+++ b/devcloud/mcenter/apps/registry.go
@@ -9,6 +9,7 @@ import (
// 鉴权
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/endpoint/impl"
+ _ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label/api"
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/label/impl"
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/namespace/impl"
_ "122.51.31.227/go-course/go18/devcloud/mcenter/apps/policy/impl"
diff --git a/devcloud/mpaas/apps/application/api/api.go b/devcloud/mpaas/apps/application/api/api.go
index 363b58d..ae0aecc 100644
--- a/devcloud/mpaas/apps/application/api/api.go
+++ b/devcloud/mpaas/apps/application/api/api.go
@@ -31,6 +31,18 @@ func (h *UserRestfulApiHandler) Init() error {
tags := []string{"应用管理"}
ws := gorestful.ObjectRouter(h)
+
+ ws.Route(ws.POST("").To(h.CreateApplication).
+ Doc("应用创建").
+ Metadata(restfulspec.KeyOpenAPITags, tags).
+ Metadata(permission.Auth(true)).
+ Metadata(permission.Permission(true)).
+ Metadata(permission.Resource("application")).
+ Metadata(permission.Action("create")).
+ Metadata(audit.Enable(true)).
+ Writes(application.Application{}).
+ Returns(200, "OK", application.Application{}))
+
// required_auth=true/false
ws.Route(ws.GET("").To(h.QueryApplication).
Doc("应用列表查询").
@@ -47,6 +59,17 @@ func (h *UserRestfulApiHandler) Init() error {
Writes(Set{}).
Returns(200, "OK", Set{}))
+ ws.Route(ws.DELETE("/{id}").To(h.DeleteApplication).
+ Doc("应用删除").
+ Metadata(restfulspec.KeyOpenAPITags, tags).
+ Metadata(permission.Auth(true)).
+ Metadata(permission.Permission(true)).
+ Metadata(permission.Resource("application")).
+ Metadata(permission.Action("delete")).
+ Metadata(audit.Enable(true)).
+ Writes().
+ Returns(200, "OK", nil))
+
return nil
}
diff --git a/devcloud/mpaas/apps/application/api/application.go b/devcloud/mpaas/apps/application/api/application.go
index 6e508ba..c22ff72 100644
--- a/devcloud/mpaas/apps/application/api/application.go
+++ b/devcloud/mpaas/apps/application/api/application.go
@@ -31,3 +31,41 @@ func (h *UserRestfulApiHandler) QueryApplication(r *restful.Request, w *restful.
response.Success(w, set)
}
+
+func (h *UserRestfulApiHandler) CreateApplication(r *restful.Request, w *restful.Response) {
+ req := application.NewCreateApplicationRequest()
+ if err := r.ReadEntity(req); err != nil {
+ response.Failed(w, err)
+ return
+ }
+
+ // 过滤条件在认证完成后的上下文中
+ tk := token.GetTokenFromCtx(r.Request.Context())
+ req.SetNamespaceId(*tk.NamespaceId)
+ req.CreateBy = tk.UserName
+
+ set, err := h.svc.CreateApplication(r.Request.Context(), req)
+ if err != nil {
+ response.Failed(w, err)
+ return
+ }
+
+ response.Success(w, set)
+}
+
+func (h *UserRestfulApiHandler) DeleteApplication(r *restful.Request, w *restful.Response) {
+ req := application.NewDeleteApplicationRequest(r.PathParameter("id"))
+
+ // 过滤条件在认证完成后的上下文中
+ tk := token.GetTokenFromCtx(r.Request.Context())
+ req.ResourceScope = tk.ResourceScope
+ log.L().Debug().Msgf("resource scope: %s", tk.ResourceScope)
+
+ set, err := h.svc.DeleteApplication(r.Request.Context(), req)
+ if err != nil {
+ response.Failed(w, err)
+ return
+ }
+
+ response.Success(w, set)
+}
diff --git a/devcloud/mpaas/apps/application/impl/application.go b/devcloud/mpaas/apps/application/impl/application.go
index 8a04f54..786df09 100644
--- a/devcloud/mpaas/apps/application/impl/application.go
+++ b/devcloud/mpaas/apps/application/impl/application.go
@@ -40,6 +40,9 @@ func (i *ApplicationServiceImpl) QueryApplication(ctx context.Context, in *appli
if in.Ready != nil {
query = query.Where("ready = ?", *in.Ready)
}
+ if in.Keywords != "" {
+ query = query.Where("name LIKE ?", "%"+in.Keywords+"%")
+ }
err := query.Count(&set.Total).Error
if err != nil {
diff --git a/devcloud/mpaas/apps/application/impl/application_test.go b/devcloud/mpaas/apps/application/impl/application_test.go
index 8504b21..5e3e91f 100644
--- a/devcloud/mpaas/apps/application/impl/application_test.go
+++ b/devcloud/mpaas/apps/application/impl/application_test.go
@@ -29,6 +29,7 @@ func TestQueryApplication(t *testing.T) {
// dev01.%
req.SetNamespaceId(1)
req.SetScope("team", []string{"dev01%"})
+ req.Keywords = "dev01"
// req.SetScope("env", []string{"prod"})
ins, err := svc.QueryApplication(ctx, req)
if err != nil {
diff --git a/devcloud/mpaas/apps/application/interface.go b/devcloud/mpaas/apps/application/interface.go
index ad0d4be..4018861 100644
--- a/devcloud/mpaas/apps/application/interface.go
+++ b/devcloud/mpaas/apps/application/interface.go
@@ -46,11 +46,13 @@ type QueryApplicationRequest struct {
type QueryApplicationRequestSpec struct {
*request.PageRequest
// 应用ID
- Id string `json:"id" bson:"_id"`
+ Id string `json:"id" form:"id"`
// 应用名称
- Name string `json:"name" bson:"name"`
+ Name string `json:"name" form:"name"`
// 应用是否就绪
- Ready *bool `json:"ready" bson:"ready"`
+ Ready *bool `json:"ready" form:"ready"`
+ // 关键字
+ Keywords string `json:"keywords" form:"keywords"`
}
type UpdateApplicationRequest struct {
@@ -60,10 +62,22 @@ type UpdateApplicationRequest struct {
CreateApplicationSpec
}
+func NewDeleteApplicationRequest(appId string) *DeleteApplicationRequest {
+ return &DeleteApplicationRequest{
+ DescribeApplicationRequest: *NewDescribeApplicationRequest(appId),
+ }
+}
+
type DeleteApplicationRequest struct {
DescribeApplicationRequest
}
+func NewDescribeApplicationRequest(appId string) *DescribeApplicationRequest {
+ return &DescribeApplicationRequest{
+ Id: appId,
+ }
+}
+
type DescribeApplicationRequest struct {
policy.ResourceScope
// 应用ID
diff --git a/devcloud/web/src/api/client.js b/devcloud/web/src/api/client.js
index af2fe5d..b3e176f 100644
--- a/devcloud/web/src/api/client.js
+++ b/devcloud/web/src/api/client.js
@@ -4,7 +4,7 @@ import { Message } from '@arco-design/web-vue'
// 封装一个axios的实例,http cient实例
// https://axios-http.com/zh/docs/instance
const client = axios.create({
- timeout: 3000,
+ timeout: 5000,
})
// 拦截API的返回结果, 如果是异常 提取异常信息,并展示
diff --git a/devcloud/web/src/api/mcenter.js b/devcloud/web/src/api/mcenter.js
index a26e1d1..2d197ba 100644
--- a/devcloud/web/src/api/mcenter.js
+++ b/devcloud/web/src/api/mcenter.js
@@ -4,6 +4,9 @@ var MCENTER_API = {
Login: (data) => {
return client.post('/api/devcloud/v1/token', data)
},
+ LabelList: (params) => {
+ return client.get('/api/devcloud/v1/labels', { params })
+ },
}
export default MCENTER_API
diff --git a/devcloud/web/src/api/mppas.js b/devcloud/web/src/api/mppas.js
index 00cee91..6fee80c 100644
--- a/devcloud/web/src/api/mppas.js
+++ b/devcloud/web/src/api/mppas.js
@@ -4,6 +4,15 @@ var MPAAS_API = {
AppList: (params) => {
return client.get('/api/devcloud/v1/applications', { params })
},
+ AppCreate: (data) => {
+ return client.post('/api/devcloud/v1/applications', data)
+ },
+ AppUpdate: (id, data) => {
+ return client.put(`/api/devcloud/v1/applications/${id}`, data)
+ },
+ AppDelete: (id) => {
+ return client.delete(`/api/devcloud/v1/applications/${id}`)
+ },
}
export default MPAAS_API
diff --git a/devcloud/web/src/layout/DashboardLayout.vue b/devcloud/web/src/layout/DashboardLayout.vue
index cdd7dcc..cd76db4 100644
--- a/devcloud/web/src/layout/DashboardLayout.vue
+++ b/devcloud/web/src/layout/DashboardLayout.vue
@@ -134,7 +134,7 @@ const handleUserOption = (option) => {
.router-view-wrapper {
flex: 1;
padding: 20px;
- // min-height: calc(100vh - 180px);
+ min-height: calc(100vh - 180px);
/* 调整最小高度 */
}
diff --git a/devcloud/web/src/layout/FrontendLayout.vue b/devcloud/web/src/layout/FrontendLayout.vue
index da59038..03b1f9d 100644
--- a/devcloud/web/src/layout/FrontendLayout.vue
+++ b/devcloud/web/src/layout/FrontendLayout.vue
@@ -174,7 +174,7 @@
.router-view-wrapper {
flex: 1;
padding: 20px;
- // min-height: calc(100vh - 180px);
+ min-height: calc(100vh - 180px);
/* 调整最小高度 */
}
diff --git a/devcloud/web/src/layout/MenuLayout.vue b/devcloud/web/src/layout/MenuLayout.vue
index 18d2434..1a1f955 100644
--- a/devcloud/web/src/layout/MenuLayout.vue
+++ b/devcloud/web/src/layout/MenuLayout.vue
@@ -418,7 +418,7 @@ const systemMenus = shallowReactive({
.router-view-wrapper {
flex: 1;
padding: 0px 20px 0px 40px;
- // min-height: calc(100vh - 180px);
+ min-height: calc(100vh - 180px);
/* 动态计算最小高度 */
}
diff --git a/devcloud/web/src/pages/develop/AppPage.vue b/devcloud/web/src/pages/develop/AppPage.vue
index 8931be8..8506812 100644
--- a/devcloud/web/src/pages/develop/AppPage.vue
+++ b/devcloud/web/src/pages/develop/AppPage.vue
@@ -1,63 +1,71 @@
-
-
-
-
- 新建项目空间
-
-
-
-
- 就绪
- 未就绪
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 就绪
-
-
- 未就绪
-
-
-
-
-
-
-
- 编辑
- 删除
-
-
-
-
-
+
+
+
+
+
+ 新建应用
+
+
+
+
+ 就绪
+ 未就绪
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 就绪
+
+
+ 未就绪
+
+
+
+
+
+
+
+ 编辑
+
+ 删除
+
+
+
+
+
+
+ console.log(v)" :appData="currentApp"
+ @submit="fetchAppList" />
+
diff --git a/devcloud/web/src/pages/develop/components/AppFormModel.vue b/devcloud/web/src/pages/develop/components/AppFormModel.vue
new file mode 100644
index 0000000..b0bb590
--- /dev/null
+++ b/devcloud/web/src/pages/develop/components/AppFormModel.vue
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 源代码
+ 容器镜像
+ 其他
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/go.mod b/go.mod
index 4a9d4f2..961440a 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
github.com/caarlos0/env/v6 v6.10.1
github.com/emicklei/go-restful-openapi/v2 v2.11.0
github.com/emicklei/go-restful/v3 v3.12.2
- github.com/gin-gonic/gin v1.10.0
+ github.com/gin-gonic/gin v1.10.1
github.com/google/uuid v1.6.0
github.com/infraboard/devops v0.0.6
github.com/infraboard/mcube/v2 v2.0.63
diff --git a/go.sum b/go.sum
index 443bea1..929b41d 100644
--- a/go.sum
+++ b/go.sum
@@ -36,8 +36,8 @@ github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3G
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
-github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
-github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
+github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
+github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=