package resourceChannel import ( "bytes" "encoding/json" "fmt" "github.com/go-redis/redis" "golang.org/x/net/context" "io/ioutil" "log" "net/http" "net/url" "os" "path" "runtime" "strconv" "strings" "time" ) func redisCli() *redis.Client { client := redis.NewClient(&redis.Options{ //Addr: coo.RedisHost, // Redis地址 Addr: "192.168.204.193:6379", // Redis地址 Password: "", // Redis密码,默认为空 DB: 1, // 使用哪个数据库,默认为0 }) _, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) defer cancel() return client } type ResourceAssessment struct { ID uint `gorm:"primaryKey" json:"id"` // 留学评估表 DataType uint8 `json:"data_type"` // 1.网课 2.api资源 3.专题页 4.工作台录入 5.后台录入 6 小程序 ChatID string `json:"chat_id"` // 会话id Channel int `json:"channel"` // 渠道id Category int `json:"category"` // 分类id CreatedAt time.Time `json:"created_at"` // 数据创建时间 ReferPageURL string `json:"refer_page_url"` // 来源网址 URL string `json:"url"` // 落地页地址 ChatURL string `json:"chat_url"` // 对话发起页 GrUserId string `json:"gr_user_id"` // 神策distinct_id } type SemJsChatRecord struct { ChatID int64 `gorm:"column:CHAT_ID"` CreateTime time.Time `gorm:"column:CREATE_TIME"` ReferPage string `gorm:"type:text;column:REFER_PAGE"` ChatURL string `gorm:"type:text;column:CHAT_URL"` ChannleID int `gorm:"column:CHANNLE_ID"` CategoryID int `gorm:"column:CATEGORY_ID"` GrUserID string `gorm:"column:gr_user_id"` SourceUrl string `gorm:"column:source_url"` } type ChannelCategory struct { Channel int Category int } // GetChannel 表单渠道归因处理 func GetChannel(assessment ResourceAssessment) ChannelCategory { log.Printf("%v", assessment) // 获取神策URL(不包含utm) cc, _ := redisCli().Get("website:" + assessment.GrUserId).Result() var websiteUrl SensorsData json.Unmarshal([]byte(cc), &websiteUrl) // 到梦解析 if !strings.Contains(assessment.URL, "utm") && !strings.Contains(assessment.ChatURL, "utm") && !strings.Contains(assessment.ReferPageURL, "utm") && (strings.Contains(assessment.ReferPageURL, "daomeng") || strings.Contains(assessment.ChatURL, "daomeng")) { log.Printf("解析到梦") assessment.Channel = 38 assessment.Category = getCategory(201) return ChannelCategory{assessment.Channel, assessment.Category} } // 网课解析 if assessment.DataType == 1 { log.Printf("解析网课") assessment.Channel = 26 assessment.Category = getCategory(121) return ChannelCategory{assessment.Channel, assessment.Category} } // 小程序解析 if strings.Contains(assessment.ChatURL, "pages") && strings.Split(strings.Split(assessment.ChatURL, "?")[1], "=")[0] == "miniapp" && (strings.Contains(assessment.ChatURL, "baidu") || strings.Contains(assessment.ChatURL, "wechat")) { log.Printf("解析小程序") appType := strings.Split(strings.Split(strings.Split(assessment.ChatURL, "?")[1], "=")[1], "_")[1] if appType == "baidu" { assessment.Channel = 1 assessment.Category = getCategory(30) } else if appType == "wechat" { assessment.Channel = 8 assessment.Category = getCategory(32) } return ChannelCategory{assessment.Channel, assessment.Category} } // URL解析 if strings.Contains(assessment.URL, "link=") || strings.Contains(assessment.ReferPageURL, "link=") || strings.Contains(assessment.ChatURL, "link=") { log.Printf("解析URL") if len(strings.Split(assessment.URL, "_")) == 3 { var category, _ = strconv.Atoi(strings.Split(assessment.URL, "_")[1]) if category > 10000 { assessment.Channel = category assessment.Category = category } } if strings.Contains(assessment.URL, "link=") { split := strings.Split(assessment.URL, "link") if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") { assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.URL, "link")[1], "form")[0], "_")[1]) var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.URL, "link")[1], "form")[0], "_")[2]) assessment.Category = getCategory(category) } else { assessment.Channel = 5 assessment.Category = getCategory(11) } } else if strings.Contains(assessment.ReferPageURL, "link=") { split := strings.Split(assessment.ReferPageURL, "link") if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") { assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ReferPageURL, "link")[1], "form")[0], "_")[1]) var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ReferPageURL, "link")[1], "form")[0], "_")[2]) assessment.Category = getCategory(category) } else { assessment.Channel = 5 assessment.Category = getCategory(11) } } else { split := strings.Split(assessment.ChatURL, "link") if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") { assessment.Channel, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ChatURL, "link")[1], "form")[0], "_")[1]) var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(assessment.ChatURL, "link")[1], "form")[0], "_")[2]) assessment.Category = getCategory(category) } else { assessment.Channel = 5 assessment.Category = getCategory(11) } } // 百度惠生活渠道合并 if assessment.Category == 239 { assessment.Category = getCategory(292) } return ChannelCategory{assessment.Channel, assessment.Category} } // 获取神策url(包含utm) cc1, _ := redisCli().Get("sensors:" + assessment.GrUserId).Result() var utmUrl SensorsData json.Unmarshal([]byte(cc1), &utmUrl) // 神策解析 if utmUrl.Url != "" && !strings.Contains(assessment.URL, "link=") && !strings.Contains(assessment.ReferPageURL, "link=") && !strings.Contains(assessment.ChatURL, "link=") { log.Printf("解析神策") assessment.Channel = utmUrl.Channel assessment.Category = utmUrl.Category // 百度惠生活渠道合并 if assessment.Category == 239 { assessment.Category = getCategory(292) } return ChannelCategory{assessment.Channel, assessment.Category} } // 搜索引擎SEO,外链解析 if assessment.ReferPageURL != "" && !strings.Contains(assessment.ReferPageURL, "https://www.jjl.cn/") && !strings.Contains(assessment.ReferPageURL, "https://m.jjl.cn/") { log.Printf("解析SEO") assessment.Channel = 5 assessment.Category = getCategory(11) return ChannelCategory{assessment.Channel, assessment.Category} } // 官网自然访问解析 if strings.Contains(assessment.URL, "https://www.jjl.cn/") || strings.Contains(assessment.URL, "https://m.jjl.cn/") || strings.Contains(assessment.ReferPageURL, "https://www.jjl.cn/") || strings.Contains(assessment.ReferPageURL, "https://m.jjl.cn/") || strings.Contains(assessment.ChatURL, "https://www.jjl.cn/") || strings.Contains(assessment.ChatURL, "https://m.jjl.cn/") || strings.Contains(utmUrl.Url, "https://www.jjl.cn/") || strings.Contains(utmUrl.Url, "https://m.jjl.cn/") { log.Printf("解析官网") assessment.Channel = 7 assessment.Category = getCategory(126) return ChannelCategory{assessment.Channel, assessment.Category} } log.Printf("默认解析为SEO") assessment.Channel = 5 assessment.Category = getCategory(11) return ChannelCategory{assessment.Channel, assessment.Category} } // GetChatChannel 会话渠道归因处理 func GetChatChannel(chat SemJsChatRecord) ChannelCategory { log.Printf("%v", chat) // 获取神策URL(不包含utm) cc, _ := redisCli().Get("website:" + chat.GrUserID).Result() var websiteUrl SensorsData json.Unmarshal([]byte(cc), &websiteUrl) // 小程序解析 if strings.Contains(chat.ChatURL, "pages") && strings.Split(strings.Split(chat.ChatURL, "?")[1], "=")[0] == "miniapp" && (strings.Contains(chat.ChatURL, "baidu") || strings.Contains(chat.ChatURL, "wechat")) { log.Printf("小程序解析") log.Printf(chat.ChatURL) appType := strings.Split(strings.Split(strings.Split(chat.ChatURL, "?")[1], "=")[1], "_")[1] if appType == "baidu" { chat.ChannleID = 1 chat.CategoryID = getCategory(30) } else if appType == "wechat" { chat.ChannleID = 8 chat.CategoryID = getCategory(32) } return ChannelCategory{chat.ChannleID, chat.CategoryID} } // 到梦解析 if !strings.Contains(chat.ReferPage, "utm") && !strings.Contains(chat.ChatURL, "utm") && (strings.Contains(chat.ReferPage, "daomeng") || strings.Contains(chat.ChatURL, "daomeng")) { log.Printf("到梦解析") chat.ChannleID = 38 chat.CategoryID = getCategory(201) return ChannelCategory{chat.ChannleID, chat.CategoryID} } // URL解析 if strings.Contains(chat.ChatURL, "link=") || strings.Contains(chat.ReferPage, "link=") { log.Printf("解析CHATURL") if strings.Contains(chat.ChatURL, "link=") { split := strings.Split(chat.ChatURL, "link=") if strings.Contains(split[1], "form") || strings.Contains(split[1], "from") { chat.ChannleID, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ChatURL, "link")[1], "form")[0], "_")[1]) var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ChatURL, "link")[1], "form")[0], "_")[2]) chat.CategoryID = getCategory(category) } else { chat.ChannleID = 5 chat.CategoryID = getCategory(11) } } else { split := strings.Split(chat.ReferPage, "link=") if strings.Contains(split[01], "form") || strings.Contains(split[1], "from") { chat.ChannleID, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ReferPage, "link")[1], "form")[0], "_")[1]) var category, _ = strconv.Atoi(strings.Split(strings.Split(strings.Split(chat.ReferPage, "link")[1], "form")[0], "_")[2]) chat.CategoryID = getCategory(category) } else { chat.ChannleID = 5 chat.CategoryID = getCategory(11) } } // 百度惠生活渠道合并 if chat.CategoryID == 239 { chat.CategoryID = getCategory(292) } return ChannelCategory{chat.ChannleID, chat.CategoryID} } // 获取神策url(包含utm) cc1, _ := redisCli().Get("sensors:" + chat.GrUserID).Result() var utmUrl SensorsData json.Unmarshal([]byte(cc1), &utmUrl) // 神策解析 if utmUrl.Url != "" && utmUrl.Channel > 0 && !strings.Contains(chat.ReferPage, "link=") && !strings.Contains(chat.ChatURL, "link=") { log.Printf("解析神策") chat.ChannleID = utmUrl.Channel chat.CategoryID = utmUrl.Category // 百度惠生活渠道合并 if chat.CategoryID == 239 { chat.CategoryID = getCategory(292) } return ChannelCategory{chat.ChannleID, chat.CategoryID} } // 搜索引擎SEO,外链解析 if chat.ReferPage != "" && !strings.Contains(chat.ReferPage, "https://www.jjl.cn/") && !strings.Contains(chat.ReferPage, "https://m.jjl.cn/") { log.Printf("解析SEO") chat.ChannleID = 5 chat.CategoryID = getCategory(11) return ChannelCategory{chat.ChannleID, chat.CategoryID} } // 官网自然访问解析 if strings.Contains(chat.ReferPage, "https://www.jjl.cn/") || strings.Contains(chat.ReferPage, "https://m.jjl.cn/") || strings.Contains(chat.ChatURL, "https://www.jjl.cn/") || strings.Contains(chat.ChatURL, "https://m.jjl.cn/") || strings.Contains(utmUrl.Url, "https://www.jjl.cn/") || strings.Contains(utmUrl.Url, "https://m.jjl.cn/") { log.Printf("解析官网") chat.ChannleID = 7 chat.CategoryID = getCategory(126) return ChannelCategory{chat.ChannleID, chat.CategoryID} } log.Printf("默认解析为SEO") chat.ChannleID = 5 chat.CategoryID = getCategory(11) return ChannelCategory{chat.ChannleID, chat.CategoryID} } type SensorsData struct { DistinctId string `json:"distinctID"` Channel int `json:"channel"` Category int `json:"category"` Url string `json:"url"` } // 访问神策API func getSensorsData(sql string) string { sensorsUrl := "http://10.0.6.35:8107/api/sql/query?token=128d837f466684101710cfb308e7556de975b717c6c2465ba5fc2836d57a64c8&project=production&type=impala&q=" + url.QueryEscape(sql) + "&format=json" data := []byte("") log.Printf("REQ_URL:%s", sensorsUrl) req, err := http.NewRequest("POST", sensorsUrl, bytes.NewBuffer(data)) if err != nil { log.Printf("ERROR:%s", err.Error()) return err.Error() } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") client := &http.Client{} resp, err := client.Do(req) if err != nil { return err.Error() } defer resp.Body.Close() respBody, err := ioutil.ReadAll(resp.Body) if err != nil { return err.Error() } var sensors Sensors json.Unmarshal([]byte(string(respBody)), &sensors) return sensors.LatestReferrer } // Sensors 神策数据结构体 type Sensors struct { Url string `json:"$url"` LatestReferrer string `json:"$latest_referrer"` } type SysChannel struct { OriginalCategory string `json:"original_category"` // 主键ID CategoryId string `json:"category_id"` // 备注 } func getCurrentPath() string { _, filename, _, _ := runtime.Caller(1) return path.Dir(filename) } func getCategory(OriginalCategory int) int { endpoint := "oss-cn-beijing.aliyuncs.com" // 例如 "oss-cn-hangzhou.aliyuncs.com" accessKeyID := "LTAI5t7iAtrYaUgGgK8ws54e" accessKeySecret := "j4A6llCRqZBMzXLQ7ms84LdKl9l0IS" bucketName := "jjl-prod-bucket" objectName := "channel/category_mapper.json" client, err := oss.New(endpoint, accessKeyID, accessKeySecret) if err != nil { log.Fatalf("创建OSS客户端失败: %v", err) } // 获取存储空间 bucket, err := client.Bucket(bucketName) if err != nil { log.Fatalf("获取Bucket失败: %v", err) } // 获取对象 body, err := bucket.GetObject(objectName) if err != nil { log.Fatalf("获取对象失败: %v", err) } defer body.Close() // 读取对象内容 var channel []SysChannel decoder := json.NewDecoder(body) if err := decoder.Decode(&channel); err != nil { log.Fatalf("解析JSON失败: %v", err) } for i := range channel { ori, _ := strconv.Atoi(channel[i].OriginalCategory) if ori == OriginalCategory { category, _ := strconv.Atoi(channel[i].CategoryId) return category } } return -1 }