package console import ( "strings" "time" "yunyan/comm" "yunyan/lego/sys/postgres" "yunyan/pb" "github.com/gin-gonic/gin" ) // ============================ 应用/产品域 (product) ============================ // // 应用(产品) = SaaS 里的一个应用名(Voitrans/Lumi/…),下挂多条区域部署(app_registry,按应用名 app_name 关联)。 // 「应用管理」列表按应用名分组:一行一个应用,展开看它在各区域/环境的部署。 func (this *serverComp) productsList(c *gin.Context) { models, err := this.module.model.listProducts() if err != nil { writeErr(c, pb.ErrorCode_DBError, err.Error()) return } writeOK(c, models) } func (this *serverComp) productsAdd(c *gin.Context) { var model AppProduct if err := c.ShouldBindJSON(&model); err != nil { writeErr(c, pb.ErrorCode_ReqParameterError, err.Error()) return } model.Name = strings.TrimSpace(model.Name) if model.Name == "" { writeErr(c, pb.ErrorCode_ReqParameterError, "应用名必填") return } if exist, _ := this.module.model.getProductByName(model.Name); exist != nil && exist.Id != 0 { writeErr(c, pb.ErrorCode_ReqParameterError, "应用名已存在: "+model.Name) return } model.Id = 0 now := time.Now().Unix() model.Createtime = now model.Updatetime = now if err := this.module.model.addProduct(&model); err != nil { writeErr(c, pb.ErrorCode_DBError, err.Error()) return } writeOK(c, &model) } func (this *serverComp) productsUpdate(c *gin.Context) { var model AppProduct if err := c.ShouldBindJSON(&model); err != nil { writeErr(c, pb.ErrorCode_ReqParameterError, err.Error()) return } if model.Id == 0 { writeErr(c, pb.ErrorCode_ReqParameterError, "id 必填") return } model.Name = strings.TrimSpace(model.Name) if model.Name == "" { writeErr(c, pb.ErrorCode_ReqParameterError, "应用名必填") return } // 判重:同名但非本行则拒绝。 if exist, _ := this.module.model.getProductByName(model.Name); exist != nil && exist.Id != 0 && exist.Id != model.Id { writeErr(c, pb.ErrorCode_ReqParameterError, "应用名已存在: "+model.Name) return } old, err := this.module.model.getProduct(model.Id) if err != nil { writeErr(c, pb.ErrorCode_DBError, "应用不存在: "+err.Error()) return } model.Createtime = old.Createtime model.Updatetime = time.Now().Unix() if err := this.module.model.saveProduct(&model); err != nil { writeErr(c, pb.ErrorCode_DBError, err.Error()) return } // 应用名即关联键:改名时级联把其名下部署的 app_name 一并更新,避免部署掉进「未分组」。 if old.Name != model.Name { if res := postgres.Exec("UPDATE "+comm.TableAppRegistry+" SET app_name=? WHERE app_name=?", model.Name, old.Name); res.Error != nil { writeErr(c, pb.ErrorCode_DBError, "级联更新部署归属失败: "+res.Error.Error()) return } } writeOK(c, &model) } func (this *serverComp) productsDel(c *gin.Context) { var req struct { Id uint32 `json:"id"` } if err := c.ShouldBindJSON(&req); err != nil || req.Id == 0 { writeErr(c, pb.ErrorCode_ReqParameterError, "id 必填") return } // 引用完整性:应用下仍有区域部署(按应用名匹配)则拒删。 p, err := this.module.model.getProduct(req.Id) if err != nil { writeErr(c, pb.ErrorCode_DBError, "应用不存在: "+err.Error()) return } apps, err := this.module.model.listApps() if err != nil { writeErr(c, pb.ErrorCode_DBError, err.Error()) return } for _, a := range apps { if a.AppName == p.Name { writeErr(c, pb.ErrorCode_ReqParameterError, "该应用下仍有区域部署,请先删除其部署") return } } if err := this.module.model.delProduct(req.Id); err != nil { writeErr(c, pb.ErrorCode_DBError, err.Error()) return } writeOK(c, gin.H{"id": req.Id}) }