add app页面
This commit is contained in:
parent
ec0ee66af2
commit
78990c6094
57
devcloud/mcenter/apps/label/api/api.go
Normal file
57
devcloud/mcenter/apps/label/api/api.go
Normal file
@ -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"`
|
||||
}
|
||||
32
devcloud/mcenter/apps/label/api/label.go
Normal file
32
devcloud/mcenter/apps/label/api/label.go
Normal file
@ -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)
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -49,6 +49,7 @@ func NewQueryLabelRequest() *QueryLabelRequest {
|
||||
|
||||
type QueryLabelRequest struct {
|
||||
*request.PageRequest
|
||||
Key string `json:"key" form:"key"`
|
||||
}
|
||||
|
||||
type DescribeLabelRequest struct {
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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的返回结果, 如果是异常 提取异常信息,并展示
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -134,7 +134,7 @@ const handleUserOption = (option) => {
|
||||
.router-view-wrapper {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
// min-height: calc(100vh - 180px);
|
||||
min-height: calc(100vh - 180px);
|
||||
/* 调整最小高度 */
|
||||
}
|
||||
|
||||
|
||||
@ -174,7 +174,7 @@
|
||||
.router-view-wrapper {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
// min-height: calc(100vh - 180px);
|
||||
min-height: calc(100vh - 180px);
|
||||
/* 调整最小高度 */
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
/* 动态计算最小高度 */
|
||||
}
|
||||
|
||||
|
||||
@ -1,63 +1,71 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="action-bar">
|
||||
<a-space>
|
||||
<a-button type="primary">
|
||||
<template #icon><icon-plus /></template>
|
||||
新建项目空间
|
||||
</a-button>
|
||||
</a-space>
|
||||
<a-space>
|
||||
<a-select v-model="query.ready" :style="{ width: '220px', backgroundColor: '#fff' }" @change="fetchAppList"
|
||||
placeholder="选择状态" allow-clear>
|
||||
<a-option :value="true">就绪</a-option>
|
||||
<a-option :value="false">未就绪</a-option>
|
||||
</a-select>
|
||||
<a-input-search v-model="searchKey" placeholder="搜索项目名称/描述" allow-clear
|
||||
style="width: 300px;background-color: #fff;" />
|
||||
</a-space>
|
||||
</div>
|
||||
<a-table :data="data.items" :loading="fetchAppLoading">
|
||||
<template #columns>
|
||||
<a-table-column title="名称" data-index="name"></a-table-column>
|
||||
<a-table-column title="描述" data-index="description"></a-table-column>
|
||||
<a-table-column title="团队" data-index="label.team"></a-table-column>
|
||||
<a-table-column title="创建时间" data-index="create_at"></a-table-column>
|
||||
<a-table-column title="类型" data-index="type"></a-table-column>
|
||||
<a-table-column title="仓库地址" data-index="code_repository.ssh_url"></a-table-column>
|
||||
<a-table-column title="是否就绪" data-index="ready">
|
||||
<template #cell="{ record }">
|
||||
<a-switch type="round" disabled v-model="record.ready">
|
||||
<template #checked>
|
||||
就绪
|
||||
</template>
|
||||
<template #unchecked>
|
||||
未就绪
|
||||
</template>
|
||||
</a-switch>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column title="操作">
|
||||
<template #cell="{ record }">
|
||||
<a-space>
|
||||
<a-button @click="editApp(record)">编辑</a-button>
|
||||
<a-button @click="deleteApp(record)" type="primary">删除</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-card>
|
||||
<div class="action-bar">
|
||||
<a-space>
|
||||
<a-button type="outline" @click="addApp()">
|
||||
<template #icon><icon-plus /></template>
|
||||
新建应用
|
||||
</a-button>
|
||||
</a-space>
|
||||
<a-space>
|
||||
<a-select v-model="query.ready" :style="{ width: '220px' }" @change="fetchAppList" @clear="query.ready = null"
|
||||
placeholder="选择状态" allow-clear>
|
||||
<a-option :value="true">就绪</a-option>
|
||||
<a-option :value="false">未就绪</a-option>
|
||||
</a-select>
|
||||
<a-input-search v-model="query.keywords" placeholder="搜索项目名称/描述" allow-clear @press-enter="fetchAppList"
|
||||
@search="fetchAppList" style="width: 300px" />
|
||||
</a-space>
|
||||
</div>
|
||||
<a-table :data="data.items" :loading="fetchAppLoading">
|
||||
<template #columns>
|
||||
<a-table-column title="名称" data-index="name"></a-table-column>
|
||||
<a-table-column title="描述" data-index="description"></a-table-column>
|
||||
<a-table-column title="团队" data-index="label.team"></a-table-column>
|
||||
<a-table-column title="创建时间" data-index="create_at"></a-table-column>
|
||||
<a-table-column title="类型" data-index="type"></a-table-column>
|
||||
<a-table-column title="仓库地址" data-index="code_repository.ssh_url"></a-table-column>
|
||||
<a-table-column title="是否就绪" data-index="ready">
|
||||
<template #cell="{ record }">
|
||||
<a-switch type="round" disabled v-model="record.ready">
|
||||
<template #checked>
|
||||
就绪
|
||||
</template>
|
||||
<template #unchecked>
|
||||
未就绪
|
||||
</template>
|
||||
</a-switch>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column title="操作">
|
||||
<template #cell="{ record }">
|
||||
<a-space>
|
||||
<a-button @click="editApp(record)" type="primary">编辑</a-button>
|
||||
<a-popconfirm :content="`确定要删除${record.name}吗?`" :on-before-ok="() => doDeleteApp(record)"
|
||||
:ok-loading="deleteAppLoading" @ok="deleteApp(record)" type="warning">
|
||||
<a-button status="danger">删除</a-button>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
<AppFormModel v-model:visible="formVisible" @update:visible="(v) => console.log(v)" :appData="currentApp"
|
||||
@submit="fetchAppList" />
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import API from '@/api'
|
||||
import AppFormModel from './components/AppFormModel.vue';
|
||||
|
||||
const query = reactive({
|
||||
const query = ref({
|
||||
page_size: 20,
|
||||
page_number: 1,
|
||||
|
||||
keywords: '',
|
||||
});
|
||||
|
||||
// 通过API获取应用列表
|
||||
@ -67,9 +75,13 @@ const data = ref({
|
||||
});
|
||||
const fetchAppLoading = ref(false);
|
||||
const fetchAppList = async () => {
|
||||
console.log(query.value.ready)
|
||||
if (query.value.ready === null || query.value.ready === undefined || query.value.ready === '') {
|
||||
delete query.value.ready;
|
||||
}
|
||||
try {
|
||||
fetchAppLoading.value = true;
|
||||
const resp = await API.mpaas.AppList(query);
|
||||
const resp = await API.mpaas.AppList(query.value);
|
||||
data.value = resp;
|
||||
console.log('Fetched app list:', data.value);
|
||||
} catch (error) {
|
||||
@ -82,4 +94,35 @@ const fetchAppList = async () => {
|
||||
onMounted(() => {
|
||||
fetchAppList();
|
||||
});
|
||||
|
||||
|
||||
// 编辑新增
|
||||
const formVisible = ref(false);
|
||||
const currentApp = ref(null);
|
||||
|
||||
const addApp = () => {
|
||||
formVisible.value = true;
|
||||
currentApp.value = null
|
||||
}
|
||||
|
||||
const editApp = (app) => {
|
||||
currentApp.value = app;
|
||||
formVisible.value = true;
|
||||
};
|
||||
|
||||
const deleteAppLoading = ref(false);
|
||||
const doDeleteApp = async (app) => {
|
||||
try {
|
||||
deleteAppLoading.value = true;
|
||||
await API.mpaas.AppDelete(app.id);
|
||||
fetchAppList();
|
||||
} catch (error) {
|
||||
console.error('Error deleting app:', error);
|
||||
} finally {
|
||||
deleteAppLoading.value = false;
|
||||
}
|
||||
}
|
||||
const deleteApp = (app) => {
|
||||
doDeleteApp(app);
|
||||
};
|
||||
</script>
|
||||
|
||||
175
devcloud/web/src/pages/develop/components/AppFormModel.vue
Normal file
175
devcloud/web/src/pages/develop/components/AppFormModel.vue
Normal file
@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<a-modal draggable v-model:visible="modelVisible" :ok-loading="createAppLoading" :title="editMode ? '编辑应用' : '新建应用'"
|
||||
@ok="handleOk" :on-before-ok="handleBeforeOk" @cancel="handleCancel" :ok-text="editMode ? '保存' : '创建'"
|
||||
unmount-on-close>
|
||||
<a-form ref="appFormRef" :model="form" layout="vertical">
|
||||
<a-form-item label="应用名称" field="name" :rules="[{ required: true, message: '请输入应用名称' }]"
|
||||
:validate-trigger="['change', 'blur']">
|
||||
<a-input v-model="form.name" placeholder="请输入应用名称" allow-clear />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="应用描述" field="description">
|
||||
<a-textarea v-model="form.description" placeholder="请输入应用描述" :auto-size="{ minRows: 3, maxRows: 5 }"
|
||||
allow-clear />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="应用类型" field="type" :rules="[{ required: true, message: '请选择应用类型' }]">
|
||||
<a-select v-model="form.type" placeholder="应用类型" allow-clear>
|
||||
<a-option value="SOURCE_CODE">源代码</a-option>
|
||||
<a-option value="CONTAINER_IMAGE">容器镜像</a-option>
|
||||
<a-option value="OTHER">其他</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<div v-if="form.type === 'SOURCE_CODE'">
|
||||
<a-form-item label="代码仓库" field="code_repository.ssh_url" :rules="[{ required: true, message: '请输入代码仓库地址' }]">
|
||||
<a-input v-model="form.code_repository.ssh_url" placeholder="请输入代码仓库地址" allow-clear />
|
||||
</a-form-item>
|
||||
</div>
|
||||
|
||||
<a-form-item label="团队" field="label.team" :rules="[{ required: true, message: '请输入团队名称' }]">
|
||||
<a-tree-select v-model="form.label.team" :field-names="{
|
||||
key: 'value',
|
||||
title: 'label'
|
||||
}" :data="teamOptions" :loading="fetchAppTeamsLoading" placeholder="请选择团队"></a-tree-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, computed, onMounted } from 'vue';
|
||||
import API from '@/api'
|
||||
import { useTemplateRef } from 'vue'
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
appData: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:visible', 'submit']);
|
||||
|
||||
const appFormRef = useTemplateRef('appFormRef')
|
||||
|
||||
// 1. 先定义所有函数和变量
|
||||
const resetForm = () => {
|
||||
form.value = {
|
||||
name: '',
|
||||
description: '',
|
||||
code_repository: {
|
||||
ssh_url: ''
|
||||
},
|
||||
label: {
|
||||
team: ''
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 2. 再定义其他响应式数据
|
||||
const modelVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (v) => emit('update:visible', v)
|
||||
});
|
||||
|
||||
const editMode = computed(() => !!props.appData);
|
||||
|
||||
const form = ref({
|
||||
name: '',
|
||||
description: '',
|
||||
type: 'SOURCE_CODE',
|
||||
code_repository: {}
|
||||
});
|
||||
|
||||
// 拉去团队的选型
|
||||
const fetchAppTeamsLoading = ref(false);
|
||||
const teamOptions = ref([])
|
||||
const fetchAppTeams = async () => {
|
||||
try {
|
||||
fetchAppTeamsLoading.value = true
|
||||
const resp = await API.mcenter.LabelList({
|
||||
key: 'team',
|
||||
});
|
||||
console.log(resp.items)
|
||||
if (resp.items.length > 0) {
|
||||
teamOptions.value = resp.items[0].enum_options
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching app teams:', error);
|
||||
return [];
|
||||
} finally {
|
||||
fetchAppTeamsLoading.value = false
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (props.appData) {
|
||||
form.value = { ...props.appData };
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
fetchAppTeams()
|
||||
});
|
||||
|
||||
// 3. 最后定义watch(此时resetForm已经定义)
|
||||
watch(() => props.appData, (newVal) => {
|
||||
if (newVal) {
|
||||
form.value = { ...newVal };
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
|
||||
// 提交前校验, 阻止模态框关闭
|
||||
const createAppLoading = ref(false)
|
||||
const handleBeforeOk = async () => {
|
||||
// 检查
|
||||
const resp = await appFormRef.value.validate();
|
||||
if (resp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 创建
|
||||
createAppLoading.value = true
|
||||
try {
|
||||
createAppLoading.value = true
|
||||
await API.mpaas.AppCreate({
|
||||
...form.value,
|
||||
name: form.value.name.trim()
|
||||
});
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('Error creating app:', error);
|
||||
} finally {
|
||||
createAppLoading.value = false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const handleOk = async () => {
|
||||
emit('submit', {
|
||||
...form.value,
|
||||
name: form.value.name.trim()
|
||||
});
|
||||
resetForm(); // 提交后重置表单
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
resetForm(); // 取消时也重置表单
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 可以添加自定义样式 */
|
||||
:deep(.arco-form-item-label) {
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
2
go.mod
2
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
|
||||
|
||||
4
go.sum
4
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=
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user