From e5af40466c5e85c7db84401a4f555ea43a50532c Mon Sep 17 00:00:00 2001 From: logan Date: Mon, 25 May 2026 23:47:21 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AE=9E=E4=BE=8B=E5=88=86=E7=BB=84?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E4=BF=9D=E5=AD=98=E5=AE=9E=E4=BE=8B=E5=85=B3?= =?UTF-8?q?=E8=81=94=20=E2=80=94=20UpdateInstanceGroup=20=E6=8E=A5?= =?UTF-8?q?=E6=94=B6=20readonly/write=5Finstance=5Fids?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UpdateInstanceGroup 新增 readonly_instance_ids/write_instance_ids 字段处理 - 清除旧成员后重新写入 instance_group_members 表 - enrichGroup 返回 readonly_instance_ids/write_instance_ids 供前端穿梭框回显 - 新增 collectInstanceIDs helper 去重提取 ID 列表 --- backend/internal/handler/instance_group.go | 98 ++++++++++++++++------ frontend/src/pages/WorkflowPage.tsx | 3 +- 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/backend/internal/handler/instance_group.go b/backend/internal/handler/instance_group.go index 4f3c973..b29dd06 100644 --- a/backend/internal/handler/instance_group.go +++ b/backend/internal/handler/instance_group.go @@ -40,6 +40,7 @@ func CreateInstanceGroup(c *gin.Context) { // PUT /api/v1/instance-groups/:id func UpdateInstanceGroup(c *gin.Context) { id := c.Param("id") + gid, _ := strconv.Atoi(id) var group model.InstanceGroup if err := model.DB.First(&group, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"detail": "Instance group not found"}) @@ -47,14 +48,16 @@ func UpdateInstanceGroup(c *gin.Context) { } var input struct { - Name *string `json:"name"` - Description *string `json:"description"` - DBType *string `json:"db_type"` - Permissions *string `json:"permissions"` - IsActive *bool `json:"is_active"` - WorkflowID *int `json:"workflow_id"` - AccessType *string `json:"access_type"` - AllowedDatabases *string `json:"allowed_databases"` + Name *string `json:"name"` + Description *string `json:"description"` + DBType *string `json:"db_type"` + Permissions *string `json:"permissions"` + IsActive *bool `json:"is_active"` + WorkflowID *int `json:"workflow_id"` + AccessType *string `json:"access_type"` + AllowedDatabases *string `json:"allowed_databases"` + ReadonlyInstanceIDs *[]int `json:"readonly_instance_ids"` + WriteInstanceIDs *[]int `json:"write_instance_ids"` } if err := c.ShouldBindJSON(&input); err != nil { c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()}) @@ -87,14 +90,41 @@ func UpdateInstanceGroup(c *gin.Context) { updates["allowed_databases"] = *input.AllowedDatabases } - if len(updates) == 0 { - c.JSON(http.StatusOK, enrichGroup(group)) - return + if len(updates) > 0 { + if err := model.DB.Model(&group).Updates(updates).Error; err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()}) + return + } } - if err := model.DB.Model(&group).Updates(updates).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()}) - return + // Update instance members if provided + if input.ReadonlyInstanceIDs != nil || input.WriteInstanceIDs != nil { + // Clear all existing members for this group + model.DB.Where("group_id = ?", gid).Delete(&model.InstanceGroupMember{}) + + // Add readonly instances + if input.ReadonlyInstanceIDs != nil { + for _, iid := range *input.ReadonlyInstanceIDs { + member := model.InstanceGroupMember{ + GroupID: gid, + InstanceID: iid, + AccessType: "readonly", + } + model.DB.Create(&member) + } + } + + // Add write instances + if input.WriteInstanceIDs != nil { + for _, iid := range *input.WriteInstanceIDs { + member := model.InstanceGroupMember{ + GroupID: gid, + InstanceID: iid, + AccessType: "write", + } + model.DB.Create(&member) + } + } } model.DB.First(&group, id) @@ -263,19 +293,33 @@ func enrichGroup(group model.InstanceGroup) gin.H { } return gin.H{ - "id": group.ID, - "name": group.Name, - "description": group.Description, - "db_type": group.DBType, - "permissions": group.Permissions, - "is_active": group.IsActive, - "created_at": group.CreatedAt, - "updated_at": group.UpdatedAt, - "workflow_id": group.WorkflowID, - "access_type": group.AccessType, - "allowed_databases": group.AllowedDatabases, + "id": group.ID, + "name": group.Name, + "description": group.Description, + "db_type": group.DBType, + "permissions": group.Permissions, + "is_active": group.IsActive, + "created_at": group.CreatedAt, + "updated_at": group.UpdatedAt, + "workflow_id": group.WorkflowID, + "access_type": group.AccessType, + "allowed_databases": group.AllowedDatabases, "readonly_instance_count": readonlyCount, - "write_instance_count": writeCount, - "user_count": userCount, + "write_instance_count": writeCount, + "user_count": userCount, + "readonly_instance_ids": collectInstanceIDs(readonlyMembers), + "write_instance_ids": collectInstanceIDs(writeMembers), } } + +func collectInstanceIDs(members []model.InstanceGroupMember) []int { + ids := []int{} + seen := map[int]bool{} + for _, m := range members { + if !seen[m.InstanceID] { + seen[m.InstanceID] = true + ids = append(ids, m.InstanceID) + } + } + return ids +} diff --git a/frontend/src/pages/WorkflowPage.tsx b/frontend/src/pages/WorkflowPage.tsx index d25e5e5..44c55a8 100644 --- a/frontend/src/pages/WorkflowPage.tsx +++ b/frontend/src/pages/WorkflowPage.tsx @@ -635,7 +635,8 @@ export default function WorkflowPage() {
{(wf.steps || []).map((step, i) => { const StepIcon = STEP_TYPE_ICONS[step.step_type] || Shield; - const uids: number[] = step.approver_ids ? JSON.parse(step.approver_ids) : []; + let uids: number[] = []; + try { const parsed = JSON.parse(step.approver_ids); if (Array.isArray(parsed)) uids = parsed; } catch {} const stepsArr = wf.steps || []; return (