Refactor brand service and related components

- Removed ListQuestionVersions method and associated types from BrandService and Queries.
- Updated PromptRuleGenerationService to change task naming and handling.
- Enhanced ScheduleTaskService to support filtering by created date range and keyword.
- Introduced InstantTaskService for managing instant tasks with appropriate filtering and response structures.
- Added InstantTaskHandler for handling API requests related to instant tasks.
- Created InstantTaskTab component for the admin web interface to display and manage instant tasks.
- Updated database migrations to rename source types for articles and generation tasks.
- Adjusted models and repository queries to reflect the removal of question version handling.
This commit is contained in:
2026-04-02 21:16:12 +08:00
parent 111498a65f
commit 8958cb44c0
36 changed files with 1378 additions and 358 deletions
+44 -6
View File
@@ -31,6 +31,7 @@ type ArticleListParams struct {
GenerateStatus *string
PublishStatus *string
SourceType *string
GenerationMode *string
TemplateID *int64
PromptRuleID *int64
Keyword *string
@@ -45,6 +46,7 @@ type ArticleListItem struct {
TemplateName *string `json:"template_name"`
PromptRuleID *int64 `json:"prompt_rule_id"`
PromptRuleName *string `json:"prompt_rule_name"`
GenerationMode *string `json:"generation_mode"`
Platforms []string `json:"platforms"`
GenerateStatus string `json:"generate_status"`
PublishStatus string `json:"publish_status"`
@@ -64,6 +66,7 @@ type ArticleListResponse struct {
func (s *ArticleService) List(ctx context.Context, params ArticleListParams) (*ArticleListResponse, error) {
actor := auth.MustActor(ctx)
sourceType := params.SourceType
if params.Page < 1 {
params.Page = 1
@@ -99,9 +102,14 @@ func (s *ArticleService) List(ctx context.Context, params ArticleListParams) (*A
countArgs = append(countArgs, *params.PublishStatus)
argIdx++
}
if params.SourceType != nil {
if sourceType != nil {
countQuery += ` AND a.source_type = $` + strconv.Itoa(argIdx)
countArgs = append(countArgs, *params.SourceType)
countArgs = append(countArgs, *sourceType)
argIdx++
}
if params.GenerationMode != nil {
countQuery += ` AND a.source_type = 'custom_generation' AND COALESCE(NULLIF(gt.input_params_json ->> 'generation_mode', ''), 'instant') = $` + strconv.Itoa(argIdx)
countArgs = append(countArgs, *params.GenerationMode)
argIdx++
}
if params.TemplateID != nil {
@@ -162,9 +170,14 @@ func (s *ArticleService) List(ctx context.Context, params ArticleListParams) (*A
listArgs = append(listArgs, *params.PublishStatus)
listIdx++
}
if params.SourceType != nil {
if sourceType != nil {
listQuery += ` AND a.source_type = $` + strconv.Itoa(listIdx)
listArgs = append(listArgs, *params.SourceType)
listArgs = append(listArgs, *sourceType)
listIdx++
}
if params.GenerationMode != nil {
listQuery += ` AND a.source_type = 'custom_generation' AND COALESCE(NULLIF(gt.input_params_json ->> 'generation_mode', ''), 'instant') = $` + strconv.Itoa(listIdx)
listArgs = append(listArgs, *params.GenerationMode)
listIdx++
}
if params.TemplateID != nil {
@@ -205,13 +218,16 @@ func (s *ArticleService) List(ctx context.Context, params ArticleListParams) (*A
var items []ArticleListItem
for rows.Next() {
var item ArticleListItem
var dbSourceType string
var markdownContent *string
var wizardStateJSON []byte
var inputParamsJSON []byte
if err := rows.Scan(&item.ID, &item.SourceType, &item.TemplateID, &item.PromptRuleID, &item.GenerateStatus, &item.PublishStatus, &item.CreatedAt,
if err := rows.Scan(&item.ID, &dbSourceType, &item.TemplateID, &item.PromptRuleID, &item.GenerateStatus, &item.PublishStatus, &item.CreatedAt,
&item.Title, &item.GenerationErrorMessage, &markdownContent, &item.WordCount, &item.SourceLabel, &item.TemplateName, &item.PromptRuleName, &wizardStateJSON, &inputParamsJSON); err != nil {
return nil, response.ErrInternal(50010, "scan_failed", err.Error())
}
item.SourceType = dbSourceType
item.GenerationMode = resolveArticleGenerationMode(dbSourceType, inputParamsJSON)
item.Platforms = resolveArticlePlatforms(wizardStateJSON, inputParamsJSON)
item.WordCount = resolveWordCount(markdownContent, item.WordCount)
items = append(items, item)
@@ -228,6 +244,7 @@ type ArticleDetailResponse struct {
SourceType string `json:"source_type"`
TemplateID *int64 `json:"template_id"`
TemplateName *string `json:"template_name"`
GenerationMode *string `json:"generation_mode"`
Platforms []string `json:"platforms"`
GenerateStatus string `json:"generate_status"`
PublishStatus string `json:"publish_status"`
@@ -245,6 +262,7 @@ type ArticleDetailResponse struct {
func (s *ArticleService) Detail(ctx context.Context, id int64) (*ArticleDetailResponse, error) {
actor := auth.MustActor(ctx)
var d ArticleDetailResponse
var dbSourceType string
var wizardStateJSON []byte
var inputParamsJSON []byte
@@ -263,15 +281,17 @@ func (s *ArticleService) Detail(ctx context.Context, id int64) (*ArticleDetailRe
LIMIT 1
) gt ON true
WHERE a.id = $1 AND a.tenant_id = $2 AND a.deleted_at IS NULL
`, id, actor.TenantID).Scan(&d.ID, &d.SourceType, &d.TemplateID, &d.GenerateStatus, &d.PublishStatus, &d.CreatedAt,
`, id, actor.TenantID).Scan(&d.ID, &dbSourceType, &d.TemplateID, &d.GenerateStatus, &d.PublishStatus, &d.CreatedAt,
&d.Title, &d.HTMLContent, &d.MarkdownContent, &d.WordCount, &d.SourceLabel, &d.VersionNo, &d.TemplateName, &d.GenerationErrorMessage, &wizardStateJSON, &inputParamsJSON)
if err != nil {
return nil, response.ErrNotFound(40411, "article_not_found", "article not found")
}
d.SourceType = dbSourceType
if len(wizardStateJSON) > 0 {
d.WizardState = map[string]interface{}{}
_ = json.Unmarshal(wizardStateJSON, &d.WizardState)
}
d.GenerationMode = resolveArticleGenerationMode(dbSourceType, inputParamsJSON)
d.Platforms = resolveArticlePlatforms(wizardStateJSON, inputParamsJSON)
d.WordCount = resolveWordCount(d.MarkdownContent, d.WordCount)
return &d, nil
@@ -455,6 +475,24 @@ func resolveWordCount(markdown *string, stored int) int {
return stored
}
func resolveArticleGenerationMode(sourceType string, inputParamsJSON []byte) *string {
if sourceType != "custom_generation" {
return nil
}
if len(inputParamsJSON) > 0 {
var payload map[string]interface{}
if err := json.Unmarshal(inputParamsJSON, &payload); err == nil {
if mode := strings.TrimSpace(extractString(payload, "generation_mode")); mode != "" {
return &mode
}
}
}
mode := "instant"
return &mode
}
func nilIfEmptyString(value string) *string {
value = strings.TrimSpace(value)
if value == "" {