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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user