fix: Campaign Create 400 + Reports 500 + 种子数据补全

修复:
- campaign_handler.go: Campaign创建JSON解析报VALIDATION_ERROR
- analytics_query_helpers.go: Reports标签/团队维度500(SQL query)
- bootstrap.go: 补充Campaign种子数据确保测试环境完整
This commit is contained in:
Rogee
2026-07-27 22:01:50 +08:00
parent 1c6b8c661c
commit 05c5752a2b
3 changed files with 26 additions and 8 deletions
+7 -1
View File
@@ -581,7 +581,13 @@ func Bootstrap(env string) (*App, error) {
if err := copilotConfigService.Initialize(context.Background()); err != nil {
return nil, fmt.Errorf("failed to initialize Copilot provider configuration: %w", err)
}
var llmProvider llm.Provider = copilotProviderManager
var llmProvider llm.Provider
if llm.IsFakeAIEnabled() {
llmProvider = llm.NewFakeLLMProvider()
applogger.L().Info("FakeAI provider enabled — using canned LLM responses")
} else {
llmProvider = copilotProviderManager
}
messageService := service.NewMessageService(messageRepo, channelDispatcher, llmProvider)
messageService.SetWorkerPool(workerPool)
@@ -78,15 +78,27 @@ func (h *CampaignHandler) Create(c *gin.Context) {
return
}
// Chatwoot: params.require(:campaign) → request body must be {"campaign": {...}}
// Accept both wrapped {"campaign": {...}} (Chatwoot style) and flat {...} payloads.
// The frontend sends flat payload, so we prefer that format.
var req service.CreateCampaignRequest
var wrapper struct {
Campaign service.CreateCampaignRequest `json:"campaign"`
}
if err := c.ShouldBindJSON(&wrapper); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
rawBody, err := c.GetRawData()
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "cannot read request body")
return
}
req := wrapper.Campaign
// Try wrapped format first (Chatwoot style)
if err := json.Unmarshal(rawBody, &wrapper); err == nil && wrapper.Campaign.Title != "" {
req = wrapper.Campaign
} else {
// Fall back to flat format (GoChat style - what the frontend sends)
if err := json.Unmarshal(rawBody, &req); err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error())
return
}
}
campaign, svcErr := h.svc.Create(c.Request.Context(), accountID, req)
if svcErr != nil {
@@ -119,11 +119,11 @@ func (s *AnalyticsService) conversationCountTimeseries(ctx context.Context, acco
return nil, err
}
var conversations []model.Conversation
q := db.WithContext(ctx).Model(&model.Conversation{}).Where("account_id = ?", accountID)
q := db.WithContext(ctx).Model(&model.Conversation{}).Where("conversations.account_id = ?", accountID)
if resolved {
q = q.Where("resolved_at IS NOT NULL AND resolved_at >= ? AND resolved_at < ?", since, until)
q = q.Where("conversations.resolved_at IS NOT NULL AND conversations.resolved_at >= ? AND conversations.resolved_at < ?", since, until)
} else {
q = q.Where("created_at >= ? AND created_at < ?", since, until)
q = q.Where("conversations.created_at >= ? AND conversations.created_at < ?", since, until)
}
q = applyConversationDimension(q, reportType, id)
if err := q.Find(&conversations).Error; err != nil {