package util import ( "encoding/json" "fmt" "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/util/gconv" ) // ConvertToMessages 将原始数据转换为消息列表 func ConvertToMessages(raw any) []map[string]any { if raw == nil { return nil } j := gjson.New(raw) messages := j.Get("messages") if !messages.IsNil() { return gconv.Maps(messages.Val()) } return []map[string]any{j.Map()} } // FormToJSON 将表单数据转换为 JSON 字符串 func FormToJSON(form []map[string]any) string { if form == nil { return "[]" } b, _ := json.Marshal(form) return string(b) } // UserFormToJSON 将用户表单数据转换为 JSON 字符串 func UserFormToJSON(form []map[string]any) string { if form == nil { return "{}" } b, _ := json.Marshal(form) return string(b) } // MustMarshalToMap 将对象序列化为 map[string]any,失败时返回空 map func MustMarshalToMap(v any) map[string]any { b, err := json.Marshal(v) if err != nil { return make(map[string]any) } var m map[string]any json.Unmarshal(b, &m) return m } // JSONPretty 将任意类型转为格式化的 JSON 字符串 func JSONPretty(v any) string { if gv, ok := v.(*gvar.Var); ok { v = gconv.Map(gv.String()) } var tmp map[string]any if err := gconv.Struct(v, &tmp); err != nil { return gconv.String(v) } b, _ := json.Marshal(tmp) return string(b) } // ParseJSONFieldFromGvar 专门处理 *gvar.Var 类型的 JSON 字段解析 func ParseJSONFieldFromGvar(source any, target any) { if source == nil { return } switch v := source.(type) { case *gvar.Var: if v.IsNil() { return } // 尝试获取 map if m := v.Map(); len(m) > 0 { data, _ := json.Marshal(m) json.Unmarshal(data, target) return } // 尝试解析 JSON 字符串 str := v.String() if str != "" && str != "" { json.Unmarshal([]byte(str), target) } default: // 其他类型走原来的逻辑 data, _ := json.Marshal(source) json.Unmarshal(data, target) } } // MergeConsult 将 consult 附件合并到模型生成的 messages 结构中 func MergeConsult(req map[string]any, messages map[string]any, extendMapping map[string]any) map[string]any { if len(req) == 0 || len(messages) == 0 || len(extendMapping) == 0 { return messages } // 1) 获取 consult 数组 consult := gconv.Interfaces(req["consult"]) if len(consult) == 0 { return messages } // 2) 获取配置 targetPath := gconv.String(extendMapping["target_content_path"]) if targetPath == "" { return messages } templates := gconv.Map(extendMapping["attachment_templates"]) if len(templates) == 0 { return messages } // 3) 转为 gjson 操作 msgJson := gjson.New(messages) // 固定:如果有 rounds 结构,路径替换为 rounds.0.{targetPath} if arr := msgJson.Get("rounds.0").Array(); arr != nil { targetPath = "rounds.0." + targetPath } // 4) 遍历 consult,按类型生成附件并追加 for _, item := range consult { itemJson := gjson.New(item) itemType := itemJson.Get("type").String() if itemType == "" { continue } // 查找对应模板 tmpl := gconv.Map(templates[itemType]) if len(tmpl) == 0 { continue } // 生成附件对象 attachment := buildAttachment(tmpl, itemJson.Get("url").String()) if attachment == nil { continue } // 获取当前数组长度,用索引追加 arr := msgJson.Get(targetPath).Array() idx := len(arr) indexPath := fmt.Sprintf("%s.%d", targetPath, idx) _ = msgJson.Set(indexPath, attachment) } return msgJson.Map() } // buildAttachment 根据模板和用户数据生成附件对象 func buildAttachment(tmpl map[string]any, url string) map[string]any { typ := gconv.String(tmpl["type"]) if typ == "" || url == "" { return nil } // 深拷贝 body 并填充 url body := gconv.Map(tmpl["body"]) bodyJson := gjson.New(body) bodyJson = fillEmpty(bodyJson, url) return map[string]any{ "type": typ, typ: bodyJson.Map(), } } // fillEmpty 递归查找空字符串并替换 func fillEmpty(j *gjson.Json, value string) *gjson.Json { m := j.Map() for k, v := range m { switch vv := v.(type) { case string: if vv == "" { _ = j.Set(k, value) } case map[string]any: _ = j.Set(k, fillEmpty(gjson.New(vv), value).Map()) } } return j }