package scriptkit import ( "fmt" "regexp" ) var keyPattern = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_]*$`) var allowedScriptTypes = map[string]bool{ "confirm": true, "info": true, "choice": true, "screen": true, "template": true, "fallback": true, "message": true, } var allowedEffects = map[string]bool{ "set": true, "add": true, "subtract": true, "zero": true, } var allowedRelationTypes = map[string]bool{ "contributes_to": true, "requires": true, "excludes": true, } // ValidatePackageInput checks a package document before saving. func ValidatePackageInput(input PackageInput) error { if input.Name == "" { return fmt.Errorf("话术包缺少名称") } if !keyPattern.MatchString(input.StartStageKey) { return fmt.Errorf("开始阶段标识格式不正确") } dimensionKeys := map[string]bool{} valueKeys := map[string]bool{} stageKeys := map[string]bool{} scriptKeys := map[string]bool{} valueDimension := map[string]string{} for _, dimension := range input.Dimensions { if !keyPattern.MatchString(dimension.DimKey) || dimensionKeys[dimension.DimKey] { return fmt.Errorf("维度标识必须唯一且格式正确") } if dimension.Name == "" { return fmt.Errorf("维度 %s 缺少名称", dimension.DimKey) } dimensionKeys[dimension.DimKey] = true for _, value := range dimension.Values { if !keyPattern.MatchString(value.ValueKey) || valueKeys[value.ValueKey] { return fmt.Errorf("维度值标识必须唯一且格式正确") } if value.Name == "" { return fmt.Errorf("维度值 %s 缺少名称", value.ValueKey) } valueKeys[value.ValueKey] = true valueDimension[value.ValueKey] = dimension.DimKey } } for _, stage := range input.Stages { if !keyPattern.MatchString(stage.StageKey) || stageKeys[stage.StageKey] { return fmt.Errorf("阶段标识必须唯一且格式正确") } if stage.Name == "" { return fmt.Errorf("阶段 %s 缺少名称", stage.StageKey) } if stage.PrimaryDimensionKey != "" && !dimensionKeys[stage.PrimaryDimensionKey] { return fmt.Errorf("阶段 %s 的主维度不存在", stage.StageKey) } stageKeys[stage.StageKey] = true for _, script := range stage.Scripts { if !keyPattern.MatchString(script.ScriptKey) || scriptKeys[script.ScriptKey] { return fmt.Errorf("话术标识必须唯一且格式正确") } if script.Name == "" { return fmt.Errorf("话术 %s 缺少名称", script.ScriptKey) } if !allowedScriptTypes[script.ScriptType] { return fmt.Errorf("话术 %s 的类型 %s 不支持", script.ScriptKey, script.ScriptType) } if script.DimensionValueKey != "" && !valueKeys[script.DimensionValueKey] { return fmt.Errorf("话术 %s 关联的维度值不存在", script.ScriptKey) } if script.ScriptType == "confirm" && script.DimensionValueKey == "" { return fmt.Errorf("确认性话术 %s 必须关联维度值", script.ScriptKey) } if script.ShowThreshold < 0 || script.ConfirmThreshold < 0 { return fmt.Errorf("话术 %s 的阈值不能为负数", script.ScriptKey) } if script.ConfirmThreshold > script.ShowThreshold && script.ShowThreshold > 0 { return fmt.Errorf("话术 %s 的确认阈值不能大于显示阈值", script.ScriptKey) } scriptKeys[script.ScriptKey] = true optionKeys := map[string]bool{} for _, option := range script.Options { if !keyPattern.MatchString(option.OptionKey) || optionKeys[option.OptionKey] { return fmt.Errorf("话术 %s 的选项标识必须唯一且格式正确", script.ScriptKey) } if option.Label == "" { return fmt.Errorf("话术 %s 的选项 %s 缺少文案", script.ScriptKey, option.OptionKey) } if option.TargetDimensionValueKey != "" && !valueKeys[option.TargetDimensionValueKey] { return fmt.Errorf("话术 %s 选项 %s 关联的维度值不存在", script.ScriptKey, option.OptionKey) } if !allowedEffects[option.Effect] { return fmt.Errorf("话术 %s 选项 %s 的效果 %s 不支持", script.ScriptKey, option.OptionKey, option.Effect) } if option.EffectValue < 0 { return fmt.Errorf("话术 %s 选项 %s 的效果值不能为负数", script.ScriptKey, option.OptionKey) } optionKeys[option.OptionKey] = true } } } if !stageKeys[input.StartStageKey] { return fmt.Errorf("开始阶段 %s 不存在", input.StartStageKey) } for _, linkage := range input.Linkages { if !valueKeys[linkage.FromDimensionValueKey] || !valueKeys[linkage.ToDimensionValueKey] { return fmt.Errorf("维度联动引用了不存在的维度值") } if !allowedRelationTypes[linkage.RelationType] { return fmt.Errorf("联动关系 %s 不支持", linkage.RelationType) } if linkage.Contribution <= 0 { return fmt.Errorf("联动贡献值必须为正数") } } for _, adapter := range input.Adapters { if adapter.SourceField == "" || adapter.MatchValue == "" { return fmt.Errorf("入场适配规则缺少来源字段或匹配值") } if !valueKeys[adapter.TargetDimensionValueKey] { return fmt.Errorf("入场适配规则 %s=%s 关联的维度值不存在", adapter.SourceField, adapter.MatchValue) } if adapter.Weight <= 0 { return fmt.Errorf("入场适配规则 %s=%s 的权重必须为正数", adapter.SourceField, adapter.MatchValue) } } _ = valueDimension return nil }