This commit is contained in:
Eric 1549169735@qq.com
2026-09-13 20:08:13 +08:00
parent 7cc06976ab
commit da3f16e6db
65 changed files with 3855 additions and 2153 deletions

99
internal/run/view.go Normal file
View File

@@ -0,0 +1,99 @@
package run
import (
"encoding/json"
"git.iwork-ai.com/xdc/iqudo-top1/internal/model"
"git.iwork-ai.com/xdc/iqudo-top1/internal/scriptkit"
"gorm.io/gorm"
)
// NodeView is the public view of the current SOP node.
type NodeView struct {
NodeKey string `json:"node_key"`
Type string `json:"type"`
Title string `json:"title"`
Content string `json:"content"`
Config json.RawMessage `json:"config,omitempty"`
Fields []PublicFieldView `json:"fields,omitempty"`
Presentation *NodePresentation `json:"presentation,omitempty"`
Stage *scriptkit.StageView `json:"stage,omitempty"`
}
// PublicFieldView mirrors a scenario field for the client.
type PublicFieldView struct {
Key string `json:"key"`
Name string `json:"name"`
Type string `json:"type"`
Required bool `json:"required"`
Options json.RawMessage `json:"options"`
Validation json.RawMessage `json:"validation"`
}
func nodeView(db *gorm.DB, run model.SOPRun, node model.SOPNode) (NodeView, error) {
view := NodeView{NodeKey: node.NodeKey, Type: node.Type, Title: node.Title, Content: node.Content, Config: json.RawMessage(node.Config)}
switch node.Type {
case "start":
input, derived, answers := mapsFromRun(run)
presentation, err := loadStartPresentation(db, node, run.TenantID, scriptkit.RenderContext{Input: input, Derived: derived, Form: answers})
if err != nil {
return view, err
}
view.Presentation = presentation
case "question", "choice", "form":
fields, err := loadPublicNodeFields(db, node, run.TenantID)
if err != nil {
return view, err
}
view.Fields = fields
case "stage":
stage, err := buildStageView(db, run, node)
if err != nil {
return view, err
}
view.Stage = stage
}
return view, nil
}
// mapsFromRun returns input, derived and form maps for legacy views.
func mapsFromRun(run model.SOPRun) (map[string]interface{}, map[string]interface{}, map[string]interface{}) {
input := map[string]interface{}{}
_ = json.Unmarshal(run.Input, &input)
derived := map[string]interface{}{}
_ = json.Unmarshal(run.Derived, &derived)
answers := map[string]interface{}{}
_ = json.Unmarshal(run.Answers, &answers)
return input, derived, answers
}
func loadPublicNodeFields(db *gorm.DB, node model.SOPNode, tenantID uint64) ([]PublicFieldView, error) {
var config answerNodeConfig
if err := json.Unmarshal(node.Config, &config); err != nil {
return nil, err
}
keys := config.FieldKeys
if config.FieldKey != "" {
keys = []string{config.FieldKey}
}
if len(keys) == 0 {
return nil, nil
}
var fields []model.ScenarioField
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
}
views := make([]PublicFieldView, 0, len(keys))
for _, key := range keys {
field, ok := byKey[key]
if !ok {
continue
}
views = append(views, PublicFieldView{Key: field.FieldKey, Name: field.FieldName, Type: field.FieldType, Required: field.Required || config.Required || containsString(config.RequiredFieldKeys, key), Options: json.RawMessage(field.Options), Validation: json.RawMessage(field.Validation)})
}
return views, nil
}