feat: complete SOP execution workflow
This commit is contained in:
@@ -54,6 +54,8 @@ func ValidateGraph(startNodeKey string, nodes []model.SOPNode, edges []model.SOP
|
||||
}
|
||||
if _, exists := nodeMap[startNodeKey]; !exists && startNodeKey != "" {
|
||||
problems = append(problems, "开始节点不存在")
|
||||
} else if startNodeKey != "" && nodeMap[startNodeKey].Type != "start" {
|
||||
problems = append(problems, "开始节点标识必须指向 start 类型节点")
|
||||
}
|
||||
|
||||
adjacency := make(map[string][]string)
|
||||
@@ -77,6 +79,9 @@ func ValidateGraph(startNodeKey string, nodes []model.SOPNode, edges []model.SOP
|
||||
if node.Type != "finish" && node.Type != "escalate" && outgoing[node.NodeKey] == 0 {
|
||||
problems = append(problems, fmt.Sprintf("节点“%s”没有下一步", node.Title))
|
||||
}
|
||||
if (node.Type == "finish" || node.Type == "escalate") && outgoing[node.NodeKey] > 0 {
|
||||
problems = append(problems, fmt.Sprintf("结束节点“%s”不能配置下一步", node.Title))
|
||||
}
|
||||
}
|
||||
|
||||
visited := map[string]bool{}
|
||||
@@ -147,6 +152,9 @@ func ValidateForPublish(startNodeKey string, nodes []model.SOPNode, edges []mode
|
||||
problems = append(problems, fmt.Sprintf("节点“%s”引用的字段 %s 不存在", node.Title, fieldKey))
|
||||
} else {
|
||||
collected[fieldKey] = true
|
||||
if node.Type == "choice" {
|
||||
validateChoiceOptions(node, config, fieldMap[fieldKey], &problems)
|
||||
}
|
||||
}
|
||||
case "form":
|
||||
keys, _ := config["field_keys"].([]interface{})
|
||||
@@ -218,12 +226,57 @@ func ValidateForPublish(startNodeKey string, nodes []model.SOPNode, edges []mode
|
||||
return problems
|
||||
}
|
||||
|
||||
func validateChoiceOptions(node model.SOPNode, config map[string]interface{}, field model.ScenarioField, problems *[]string) {
|
||||
values, ok := config["options"].([]interface{})
|
||||
if !ok || len(values) == 0 {
|
||||
*problems = append(*problems, fmt.Sprintf("选择节点“%s”没有配置选项", node.Title))
|
||||
return
|
||||
}
|
||||
if field.FieldType != "text" && field.FieldType != "select" {
|
||||
*problems = append(*problems, fmt.Sprintf("选择节点“%s”只能写入文本或单选字段", node.Title))
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
for _, value := range values {
|
||||
option, ok := value.(string)
|
||||
if !ok || option == "" {
|
||||
*problems = append(*problems, fmt.Sprintf("选择节点“%s”包含无效选项", node.Title))
|
||||
continue
|
||||
}
|
||||
if seen[option] {
|
||||
*problems = append(*problems, fmt.Sprintf("选择节点“%s”包含重复选项", node.Title))
|
||||
}
|
||||
seen[option] = true
|
||||
if field.FieldType == "select" && !jsonStringArrayContains(field.Options, option) {
|
||||
*problems = append(*problems, fmt.Sprintf("选择节点“%s”的选项“%s”不在字段选项中", node.Title, option))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func jsonStringArrayContains(raw []byte, expected string) bool {
|
||||
var values []string
|
||||
if json.Unmarshal(raw, &values) != nil {
|
||||
return false
|
||||
}
|
||||
for _, value := range values {
|
||||
if value == expected {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func validateCondition(value interface{}, fields map[string]model.ScenarioField, label string, problems *[]string) {
|
||||
rule, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
*problems = append(*problems, label+"的条件结构不正确")
|
||||
return
|
||||
}
|
||||
_, hasAll := rule["all"]
|
||||
_, hasAny := rule["any"]
|
||||
if hasAll && hasAny {
|
||||
*problems = append(*problems, label+"不能同时包含全部满足和任一满足")
|
||||
return
|
||||
}
|
||||
for _, group := range []string{"all", "any"} {
|
||||
if raw, exists := rule[group]; exists {
|
||||
items, ok := raw.([]interface{})
|
||||
|
||||
Reference in New Issue
Block a user