feat(widget): 优化访客在线轨迹、GeoIP与多站点渠道
CI / Frontend (typecheck + lint + build) (push) Successful in 2m5s
CI / Backend (go vet + test) (push) Failing after 5m20s

This commit is contained in:
yml2213
2026-11-06 18:21:30 +08:00
parent 24fac1bcf1
commit 38d6fc1684
37 changed files with 1071 additions and 123 deletions
+34 -14
View File
@@ -11,6 +11,7 @@ import (
"github.com/gin-gonic/gin"
"kefu-cloud/server/internal/middleware"
"kefu-cloud/server/internal/model"
"kefu-cloud/server/internal/service"
)
type ChannelHandler struct{}
@@ -28,6 +29,7 @@ type channelView struct {
Config string `json:"config"`
ScriptCode string `json:"script_code"`
ChannelKey string `json:"channel_key"`
SiteDomain string `json:"site_domain"`
}
func extractChannelKey(script string) string {
@@ -54,7 +56,7 @@ func toChannelView(ch model.Channel) channelView {
return channelView{
ID: ch.ID, TenantID: ch.TenantID, Type: ch.Type, Name: ch.Name,
Status: ch.Status, Config: ch.Config, ScriptCode: ch.ScriptCode,
ChannelKey: extractChannelKey(ch.ScriptCode),
ChannelKey: extractChannelKey(ch.ScriptCode), SiteDomain: ch.SiteDomain,
}
}
@@ -88,8 +90,9 @@ func (h *ChannelHandler) List(c *gin.Context) {
}
type updateChannelReq struct {
Name *string `json:"name"`
Status *string `json:"status"`
Name *string `json:"name"`
Status *string `json:"status"`
SiteDomain *string `json:"site_domain"`
}
func (h *ChannelHandler) Update(c *gin.Context) {
@@ -128,6 +131,14 @@ func (h *ChannelHandler) Update(c *gin.Context) {
}
updates["status"] = status
}
if req.SiteDomain != nil {
domain := service.NormalizeSiteDomain(*req.SiteDomain)
if strings.TrimSpace(*req.SiteDomain) != "" && domain == "" {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "网站域名格式无效"})
return
}
updates["site_domain"] = domain
}
if len(updates) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "没有可更新字段"})
return
@@ -142,8 +153,9 @@ func (h *ChannelHandler) Update(c *gin.Context) {
}
type createChannelReq struct {
Type string `json:"type" binding:"required"`
Name string `json:"name"`
Type string `json:"type" binding:"required"`
Name string `json:"name"`
SiteDomain string `json:"site_domain"`
}
func (h *ChannelHandler) Create(c *gin.Context) {
@@ -166,11 +178,13 @@ func (h *ChannelHandler) Create(c *gin.Context) {
return
}
tenantID := middleware.GetTenantID(c)
var exists int64
model.DB.Model(&model.Channel{}).Where("tenant_id = ? AND type = ?", tenantID, channelType).Count(&exists)
if exists > 0 {
c.JSON(http.StatusConflict, gin.H{"code": 409, "message": "该类型渠道已存在"})
return
if channelType != "web" {
var exists int64
model.DB.Model(&model.Channel{}).Where("tenant_id = ? AND type = ?", tenantID, channelType).Count(&exists)
if exists > 0 {
c.JSON(http.StatusConflict, gin.H{"code": 409, "message": "该类型渠道已存在"})
return
}
}
name := strings.TrimSpace(req.Name)
@@ -183,12 +197,18 @@ func (h *ChannelHandler) Create(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "生成渠道标识失败"})
return
}
siteDomain := service.NormalizeSiteDomain(req.SiteDomain)
if strings.TrimSpace(req.SiteDomain) != "" && siteDomain == "" {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "网站域名格式无效"})
return
}
channel := model.Channel{
TenantID: tenantID,
Type: channelType,
Name: name,
Status: "disabled",
TenantID: tenantID,
Type: channelType,
Name: name,
SiteDomain: siteDomain,
Status: "disabled",
}
if channelType == "web" {
channel.Status = "enabled"