137 lines
5.2 KiB
Go
137 lines
5.2 KiB
Go
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
|
|
}
|