package run import ( "encoding/json" "fmt" "git.iwork-ai.com/xdc/iqudo-top1/internal/model" "gorm.io/gorm" ) type NodePresentation struct { Summary []PresentationField `json:"summary"` Items []PresentationItem `json:"items"` Opening *PresentationCopy `json:"opening,omitempty"` } type PresentationField struct { Key string `json:"key"` Label string `json:"label"` Kind string `json:"kind"` Value interface{} `json:"value"` } type PresentationItem struct { Fields []PresentationField `json:"fields"` } type PresentationCopy struct { Title string `json:"title"` Content string `json:"content"` } type startNodeConfig struct { Presentation *startPresentationConfig `json:"presentation"` } type startPresentationConfig struct { SummaryFieldKeys []string `json:"summary_field_keys"` ItemFieldKeys []string `json:"item_field_keys"` ImageFieldKeys []string `json:"image_field_keys"` OpeningTitle string `json:"opening_title"` OpeningTemplate string `json:"opening_template"` } func loadStartPresentation(db *gorm.DB, node model.SOPNode, tenantID uint64, context map[string]interface{}) (*NodePresentation, error) { var config startNodeConfig if err := json.Unmarshal(node.Config, &config); err != nil { return nil, err } if config.Presentation == nil { return nil, nil } keys := append([]string{}, config.Presentation.SummaryFieldKeys...) keys = append(keys, config.Presentation.ItemFieldKeys...) fields := make([]model.ScenarioField, 0) if len(keys) > 0 { if err := db.Table("scenario_fields sf").Select("sf.*"). Joins("JOIN sops s ON s.scenario_id = sf.scenario_id"). Where("s.id = ? AND sf.tenant_id = ? AND sf.field_key IN ?", node.SOPID, tenantID, keys). Find(&fields).Error; err != nil { return nil, err } } byKey := make(map[string]model.ScenarioField, len(fields)) for _, field := range fields { byKey[field.FieldKey] = field } return buildStartPresentation(*config.Presentation, byKey, context), nil } func buildStartPresentation(config startPresentationConfig, fields map[string]model.ScenarioField, context map[string]interface{}) *NodePresentation { view := &NodePresentation{Summary: []PresentationField{}, Items: []PresentationItem{}} imageKeys := make(map[string]bool, len(config.ImageFieldKeys)) for _, key := range config.ImageFieldKeys { imageKeys[key] = true } for _, key := range config.SummaryFieldKeys { value, ok := lookupContextValue(context, "input."+key) if !ok || presentationValueEmpty(value) { continue } view.Summary = append(view.Summary, presentationField(key, value, fields, imageKeys)) } itemValues := make(map[string][]interface{}, len(config.ItemFieldKeys)) itemCount := 0 for _, key := range config.ItemFieldKeys { value, _ := lookupContextValue(context, "input."+key) values := presentationValues(value) itemValues[key] = values if len(values) > itemCount { itemCount = len(values) } } for index := 0; index < itemCount; index++ { item := PresentationItem{Fields: []PresentationField{}} for _, key := range config.ItemFieldKeys { values := itemValues[key] if index >= len(values) || presentationValueEmpty(values[index]) { continue } item.Fields = append(item.Fields, presentationField(key, values[index], fields, imageKeys)) } if len(item.Fields) > 0 { view.Items = append(view.Items, item) } } if config.OpeningTemplate != "" { title := config.OpeningTitle if title == "" { title = "开场话术" } view.Opening = &PresentationCopy{Title: title, Content: fmt.Sprint(renderKnowledgeValue(config.OpeningTemplate, context))} } return view } func presentationField(key string, value interface{}, fields map[string]model.ScenarioField, imageKeys map[string]bool) PresentationField { label := key if field, ok := fields[key]; ok && field.FieldName != "" { label = field.FieldName } kind := "text" if imageKeys[key] { kind = "image" } return PresentationField{Key: key, Label: label, Kind: kind, Value: value} } func presentationValues(value interface{}) []interface{} { switch values := value.(type) { case []interface{}: return values case []string: result := make([]interface{}, 0, len(values)) for _, item := range values { result = append(result, item) } return result case nil: return nil default: return []interface{}{value} } } func presentationValueEmpty(value interface{}) bool { switch typed := value.(type) { case nil: return true case string: return typed == "" case []interface{}: return len(typed) == 0 case []string: return len(typed) == 0 default: return false } }