package cluemanage import ( "bytes" "crypto/sha1" "encoding/base64" "encoding/json" "errors" "fmt" util "github.com/alibabacloud-go/tea-utils/v2/service" "github.com/alibabacloud-go/tea/tea" "github.com/aliyun/credentials-go/credentials" "github.com/gin-gonic/gin" "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk/pkg/response" "go-admin/common/apis" "go-admin/tools/app" "io" "math/rand" "net" "net/url" "strconv" "strings" "time" openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" dypnsapi20170525 "github.com/alibabacloud-go/dypnsapi-20170525/v2/client" "go-admin/app/admin/models" "net/http" ) //const ( // SendDataUrl = "https://sapi.ads.oppomobile.com/v1/clue/sendData" // OwnerID = "1000253191" // OwnerIDNum = 1000253191 // ApiID = "85c646a87ac14d9f982579ba2301599e" // ApiKey = "516e23f836d648a18ee86d93c96285b4" // TransformType = 101 //) const ( SendDataUrl = "https://sapi.ads.oppomobile.com/v1/clue/sendData" // OwnerID1 Z1-迪为-H5 OwnerID1 = "1000253191" OwnerIDNum1 = 1000253191 ApiID1 = "85c646a87ac14d9f982579ba2301599e" ApiKey1 = "516e23f836d648a18ee86d93c96285b4" // OwnerID2 Z2-迪为-H5(自动汇:https://nice.deovo.com/) OwnerID2 = "1000261834" OwnerIDNum2 = 1000261834 ApiID2 = "3fc9c2d81aad4a879ec51e77b34264b0" ApiKey2 = "ddbebc0e34984ed286159165fb714497" // OwnerID3 Z3-迪为-H5(生活菜谱:https://cook.deovo.com/) OwnerID3 = "1000261837" OwnerIDNum3 = 1000261837 ApiID3 = "edfe5812c7b64708b44c122f1d7504e5" ApiKey3 = "1e7e8fc3a8f34243a456a39ac9c18e4b" // OwnerID4 Z4-迪为-H5(私房菜:https://magic.go2switch.deovo.com/) OwnerID4 = "1000268889" OwnerIDNum4 = 1000268889 ApiID4 = "41e3cb4360b54941a5a7d2f17d01129d" ApiKey4 = "5f7b237062b943fc82ef9c0979c46cae" // OwnerID11 Z11-迪为-H5 OwnerID11 = "1000276049" OwnerIDNum11 = 1000276049 ApiID11 = "228f1cbd5768465986d71db5ff44479c" ApiKey11 = "0c82a1b0e9534550a03ffb2c78a6d080" // OwnerID12 Z12-迪为-H5(重庆旅游: https://travel.deovo.com/) OwnerID12 = "1000276050" OwnerIDNum12 = 1000276050 ApiID12 = "113c010849e947ad92d2c876dafd8926" ApiKey12 = "6eae7531586a4fb88946d6368ad03d83" // OwnerID13 Z13-迪为-H5 OwnerID13 = "1000276052" OwnerIDNum13 = 1000276052 ApiID13 = "f129f76f4be54660938dc0f6cdbd3d31" ApiKey13 = "3c87769fa4d94cb5b21763217f7ba595" // OwnerID14 Z14-迪为-H5 (八大员操作证:https://learn.deovo.com/) OwnerID14 = "1000276053" OwnerIDNum14 = 1000276053 ApiID14 = "fb5913c8810b4ef5a1ee5eb999215b86" ApiKey14 = "b1072c9932304d12ab53f2dbb327c0be" // OwnerID15 Z15-迪为-H5 OwnerID15 = "1000276054" OwnerIDNum15 = 1000276054 ApiID15 = "517c0d58097d407e8d83ef59d46b61c7" ApiKey15 = "df78cfab18b04d2c8dabc64fc21f5e72" // OwnerID100 美食菜谱 https://ms.deovo.net/ OwnerID100 = "1000266972" OwnerIDNum100 = 1000266972 ApiID100 = "50e6a0c050c44c6cbf48c17bb9791ca9" ApiKey100 = "58497e3b9151445ea89241da6eb55505" // OwnerID101 美食汇 https://auto.deovo.net/ OwnerID101 = "1000266926" OwnerIDNum101 = 1000266926 ApiID101 = "4325bcd7c39043ad8d94dbc7f4954261" ApiKey101 = "de78f1f509d64977971f93429183d070" // OwnerID102 我家厨房 https://taste.go2switch.deovo.com/ OwnerID102 = "1000271633" OwnerIDNum102 = 1000271633 ApiID102 = "e317346a8df444df9a950c50960d301d" ApiKey102 = "2eb47b37c31c499087cc2ecd54b10258" // OwnerID103 美味菜肴 https://yummy.go2switch.deovo.com/ OwnerID103 = "1000271629" OwnerIDNum103 = 1000271629 ApiID103 = "831a61f7ab824ae182d10de88e626a94" ApiKey103 = "40e6f77260c845a8899c0a9b4b995854" // OwnerID104 (魔方菜谱:https://magic.deovo.com/) OwnerID104 = "1000417459" OwnerIDNum104 = 1000417459 ApiID104 = "22cbcfec05bd4f96bd049b1632a0ff1b" ApiKey104 = "f1effc0cde87404d9fb12238ee36ef81" TransformType = 101 ) var tidValue string var lbidValue string var pageIdValue string type ClueDeployService struct { apis.Api } func (e ClueDeployService) NewSendData(c *gin.Context) { fmt.Println("NewSendData") err := e.MakeContext(c).MakeOrm().Errors if err != nil { fmt.Println("MakeContext err:", err) e.Logger.Error(err) app.Error(c, http.StatusInternalServerError, err, "初始化失败") return } req := &models.NewSendDataReq{} if c.ShouldBindJSON(req) != nil { logger.Errorf("para err") app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } logger.Info("NewSendData req:", req) if req.Type == 1 && len(req.CertList) == 0 { app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误,证书为空") return } // 检查手机号是否存在 nFlag, err := models.CheckPhone(req.Type, req.Tel, e.Orm) if err != nil { logger.Errorf("err:", err) app.Error(c, http.StatusInternalServerError, err, "发送失败"+err.Error()) return } if nFlag { app.Error(c, http.StatusInternalServerError, err, "该手机号已存在,请勿重复提交") return } fmt.Println("Url is:", req.Url) tidValue, _ = extractTID(req.Url) // 解析URL parsedURL, err := url.Parse(req.Url) if err != nil { fmt.Println("URL解析错误:", err) return } // 获取查询参数 queryParams := parsedURL.Query() // 获取tid参数的值 pageIdValue = queryParams.Get("pageId") //tidValue = queryParams.Get("tid") lbidValue = queryParams.Get("lbid") fmt.Println("pageIdValue is:", pageIdValue) fmt.Println("tidValue is:", tidValue) fmt.Println("lbidValue is:", lbidValue) if strings.Contains(tidValue, "%") { fmt.Println("字符串中包含%") } else { fmt.Println("字符串中不包含%") } nType := 0 if req.Type == 1 { // 八大员 nType = 14 } else if req.Type == 2 { // 旅游 nType = 12 } reqData := getNewOppoData(req) resp, err := oppoSendData(reqData, nType) if err != nil { app.Error(c, http.StatusBadRequest, err, "oppoSendData err") } if resp.Code == 0 { // 回传成功则记录电话到数据库 models.RecordUserData(req, e.Orm) } logger.Info("NewSendData resp:", resp) if resp.Code != 0 { app.Error(c, resp.Code, errors.New("回传失败"), resp.Msg) } else { app.OK(c, "", resp.Msg) } } func (e ClueDeployService) GetUserData(c *gin.Context) { fmt.Println("GetUserData") err := e.MakeContext(c).MakeOrm().Errors if err != nil { fmt.Println("MakeContext err:", err) e.Logger.Error(err) app.Error(c, http.StatusInternalServerError, err, "初始化失败") return } req := &models.GetUserDataReq{} if c.ShouldBindJSON(req) != nil { logger.Errorf("para err") app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } logger.Info("NewSendData req:", req) resp, err := models.GetUserDataList(req, e.Orm) if err != nil { app.Error(c, http.StatusBadRequest, err, "查询失败") return } app.OK(c, resp, "") } func (e ClueDeployService) GetCode(c *gin.Context) { fmt.Println("GetCode") err := e.MakeContext(c).MakeOrm().Errors if err != nil { fmt.Println("MakeContext err:", err) e.Logger.Error(err) app.Error(c, http.StatusInternalServerError, err, "初始化失败") return } req := &models.GetCodeReq{} if c.ShouldBindJSON(req) != nil { logger.Errorf("para err") app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } // 检查手机号是否存在 nFlag, err := models.CheckPhone(req.Type, req.Tel, e.Orm) if err != nil { logger.Errorf("err:", err) app.Error(c, http.StatusInternalServerError, err, "发送失败"+err.Error()) return } if nFlag { app.Error(c, http.StatusInternalServerError, err, "该手机号已存在,请勿重复提交") return } resp, err := models.GetSMSCode(req, e.Orm, req.Type) if err != nil { app.Error(c, http.StatusBadRequest, err, "获取失败") return } app.OK(c, resp, "") } func (e ClueDeployService) RecordLog(c *gin.Context) { err := e.MakeContext(c).MakeOrm().Errors if err != nil { fmt.Println("MakeContext err:", err) e.Logger.Error(err) app.Error(c, http.StatusInternalServerError, err, "初始化失败") return } req := &models.RecordLog{} if c.ShouldBindJSON(req) != nil { logger.Errorf("para err") app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } fmt.Println("req param is:", req.Data) app.OK(c, "", "") } func (e ClueDeployService) VerifyCode(c *gin.Context) { fmt.Println("VerifyCode") err := e.MakeContext(c).MakeOrm().Errors if err != nil { fmt.Println("MakeContext err:", err) e.Logger.Error(err) app.Error(c, http.StatusInternalServerError, err, "初始化失败") return } req := &models.VerifyCodeReq{} if c.ShouldBindJSON(req) != nil { logger.Errorf("para err") app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } err = models.VerifySMSCode(req, e.Orm) if err != nil { app.Error(c, http.StatusBadRequest, err, "校验失败:"+err.Error()) return } app.OK(c, "验证通过", "") } func (e ClueDeployService) SendData(c *gin.Context) { fmt.Println("SendData") err := e.MakeContext(c).Errors if err != nil { fmt.Println("MakeContext err:", err) e.Logger.Error(err) return } req := &models.SendDataReq{} if c.ShouldBindJSON(req) != nil { logger.Errorf("para err") response.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } fmt.Println("Url is:", req.Url) tidValue, _ = extractTID(req.Url) // 解析URL parsedURL, err := url.Parse(req.Url) if err != nil { fmt.Println("URL解析错误:", err) return } // 获取查询参数 queryParams := parsedURL.Query() // 获取tid参数的值 pageIdValue = queryParams.Get("pageId") //tidValue = queryParams.Get("tid") lbidValue = queryParams.Get("lbid") fmt.Println("pageIdValue is:", pageIdValue) fmt.Println("tidValue is:", tidValue) fmt.Println("lbidValue is:", lbidValue) if strings.Contains(tidValue, "%") { fmt.Println("字符串中包含%") } else { fmt.Println("字符串中不包含%") } nType := 0 if strings.Contains(req.Url, "https://magic.deovo.com") { nType = 1 } else if strings.Contains(req.Url, "https://nice.deovo.com") { nType = 2 } else if strings.Contains(req.Url, "https://cook.deovo.com") { nType = 3 } else if strings.Contains(req.Url, "https://ms.deovo.net") { nType = 100 } else if strings.Contains(req.Url, "https://auto.deovo.net") { nType = 101 } reqData := getOppoData(nType) resp, err := oppoSendData(reqData, nType) if err != nil { response.Error(c, http.StatusBadRequest, err, "oppoSendData err") } e.OK(resp, "") } func (e ClueDeployService) GetAuthToken(c *gin.Context) { client, _err := CreateClient() if _err != nil { app.Error(c, http.StatusInternalServerError, _err, _err.Error()) return } getAuthTokenRequest := &dypnsapi20170525.GetAuthTokenRequest{ Url: tea.String("https://travel.deovo.com/"), Origin: tea.String("https://travel.deovo.com/"), SceneCode: tea.String("FC220000002610017"), } var _result *dypnsapi20170525.GetAuthTokenResponse tryErr := func() (_e error) { defer func() { if r := tea.Recover(recover()); r != nil { _e = r } }() // 复制代码运行请自行打印 API 的返回值 _result, _err = client.GetAuthTokenWithOptions(getAuthTokenRequest, &util.RuntimeOptions{}) if _err != nil { return _err } return nil }() if tryErr != nil { var error = &tea.SDKError{} if _t, ok := tryErr.(*tea.SDKError); ok { error = _t } else { error.Message = tea.String(tryErr.Error()) } // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 错误 message fmt.Println(tea.StringValue(error.Message)) // 诊断地址 var data interface{} d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data))) d.Decode(&data) if m, ok := data.(map[string]interface{}); ok { recommend, _ := m["Recommend"] fmt.Println(recommend) } _, _err = util.AssertAsString(error.Message) if _err != nil { app.Error(c, http.StatusInternalServerError, _err, _err.Error()) return } app.Error(c, http.StatusInternalServerError, _err, *error.Message) return } app.OK(c, _result, "获取token成功") } func (e ClueDeployService) GetPhoneWithToken(c *gin.Context) { fmt.Println("GetUserData") err := e.MakeContext(c).MakeOrm().Errors if err != nil { fmt.Println("MakeContext err:", err) e.Logger.Error(err) app.Error(c, http.StatusInternalServerError, err, "初始化失败") return } req := &models.GetPhoneWithTokenReq{} if c.ShouldBindJSON(req) != nil { logger.Errorf("para err") app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } client, _err := CreateClient() if _err != nil { app.Error(c, http.StatusInternalServerError, _err, _err.Error()) return } getPhoneWithTokenRequest := &dypnsapi20170525.GetPhoneWithTokenRequest{ SpToken: tea.String(req.SpToken), } var _result *dypnsapi20170525.GetPhoneWithTokenResponse tryErr := func() (_e error) { defer func() { if r := tea.Recover(recover()); r != nil { _e = r } }() // 复制代码运行请自行打印 API 的返回值 _result, _err = client.GetPhoneWithTokenWithOptions(getPhoneWithTokenRequest, &util.RuntimeOptions{}) if _err != nil { return _err } return nil }() if tryErr != nil { var error = &tea.SDKError{} if _t, ok := tryErr.(*tea.SDKError); ok { error = _t } else { error.Message = tea.String(tryErr.Error()) } // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 // 错误 message fmt.Println(tea.StringValue(error.Message)) // 诊断地址 var data interface{} d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data))) d.Decode(&data) if m, ok := data.(map[string]interface{}); ok { recommend, _ := m["Recommend"] fmt.Println(recommend) } _, _err = util.AssertAsString(error.Message) if _err != nil { app.Error(c, http.StatusInternalServerError, _err, _err.Error()) return } app.Error(c, http.StatusInternalServerError, _err, *error.Message) return } app.OK(c, _result, "获取token成功") } func CreateClient() (_result *dypnsapi20170525.Client, _err error) { // 使用AK 初始化Credentials Client。 credentialsConfig := new(credentials.Config). SetType("access_key"). SetAccessKeyId("LTAI5tH6oCpPPRufyxqYEHk1"). SetAccessKeySecret("SqKNm5YWXk097x5mpRMUjEAfEjcYbS") credentialClient, _err := credentials.NewCredential(credentialsConfig) if _err != nil { return nil, _err } config := &openapi.Config{} // Endpoint 请参考 https://api.aliyun.com/product/Dypnsapi config.Endpoint = tea.String("dypnsapi.aliyuncs.com") config.Credential = credentialClient _result = &dypnsapi20170525.Client{} _result, _err = dypnsapi20170525.NewClient(config) return _result, _err } func extractTID(urlString string) (tid string, err error) { // 查找"tid="的位置 tidIndex := strings.Index(urlString, "tid=") if tidIndex == -1 { return "", fmt.Errorf("未找到tid参数") } // 截取tid参数的值 tidStart := tidIndex + 4 // "tid="的长度为4 urlString = urlString[tidStart:] // 查找"&"或末尾的位置 ampersandIndex := strings.Index(urlString, "&") if ampersandIndex != -1 { urlString = urlString[:ampersandIndex] } return urlString, nil } // 常用的中文姓氏和名字部分 var surnames = []rune("赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨") var givenNames = []rune("伟芳娜敏静丽强磊军洋勇艳杰涛明超秀娟霞平刚桂") // 随机生成中文姓名(两个汉字) func generateChineseName() string { rand.Seed(time.Now().UnixNano()) surname := surnames[rand.Intn(len(surnames))] givenName := givenNames[rand.Intn(len(givenNames))] return string(surname) + string(givenName) } // 随机生成11位手机号 func generatePhoneNumber() string { rand.Seed(time.Now().UnixNano()) // 手机号以1开头,第二位可以是3-9 secondDigit := rand.Intn(9) + 3 // 剩余的9位数字随机生成 restDigits := rand.Int63n(1000000000) return fmt.Sprintf("1%d%09d", secondDigit, restDigits) } // 组合数据 func getOppoData(nType int) models.OppoSendDataReq { itemData1 := models.ClueDataItem{ Column: "姓名", Desc: "姓名输入框", IfNeed: true, Type: "1", Value: generateChineseName(), } itemData2 := models.ClueDataItem{ Column: "电话", Desc: "电话", IfNeed: true, Type: "3", Value: generatePhoneNumber(), } var itemList []models.ClueDataItem itemList = append(itemList, itemData1) itemList = append(itemList, itemData2) strPageId, _ := strconv.ParseInt(pageIdValue, 10, 64) var nOwnerId int64 switch nType { case 1: nOwnerId = OwnerIDNum104 case 2: nOwnerId = OwnerIDNum2 case 3: nOwnerId = OwnerIDNum3 case 100: nOwnerId = OwnerIDNum100 case 101: nOwnerId = OwnerIDNum101 default: nOwnerId = OwnerIDNum11 } data := models.OppoSendDataReq{ PageId: strPageId, OwnerId: nOwnerId, Ip: "121.35.103.72", Tid: tidValue, Lbid: lbidValue, TransformType: TransformType, Items: itemList, } return data } // 调用接口 func oppoSendData(r models.OppoSendDataReq, nType int) (models.OppoSendDataResp, error) { var clueResp models.OppoSendDataResp var token string switch nType { case 1: token = generateToken(OwnerID104, ApiID104, ApiKey104) case 2: token = generateToken(OwnerID2, ApiID2, ApiKey2) case 3: token = generateToken(OwnerID3, ApiID3, ApiKey3) case 12: token = generateToken(OwnerID12, ApiID12, ApiKey12) case 14: token = generateToken(OwnerID14, ApiID14, ApiKey14) case 100: token = generateToken(OwnerID100, ApiID100, ApiKey100) case 101: token = generateToken(OwnerID101, ApiID101, ApiKey101) } data, err := json.Marshal(r) if err != nil { logger.Error("oppoSendData err:", err) return clueResp, err } fmt.Println("data json:", string(data)) client := http.Client{} req, err := http.NewRequest("POST", SendDataUrl, bytes.NewBuffer(data)) if err != nil { logger.Error("oppoSendData err:", err) return clueResp, err } req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Authorization", "Bearer "+token) resp, err := client.Do(req) if err != nil { logger.Error("oppoSendData err:", err) return clueResp, err } body, err := io.ReadAll(resp.Body) if err != nil { logger.Error("oppoSendData err:", err) return clueResp, err } fmt.Println("body:", string(body)) defer resp.Body.Close() err = json.Unmarshal(body, &clueResp) if err != nil { logger.Error("clueResp err:", err) return clueResp, err } return clueResp, nil } func generateToken(ownerID, apiID, apiKey string) string { // 获取当前时间戳,精确到秒 timeStamp := time.Now().Unix() // 转换时间戳为字符串 timeStampStr := strconv.FormatInt(timeStamp, 10) // 计算签名字符串 signature := sha1.Sum([]byte(apiID + apiKey + timeStampStr)) signatureStr := fmt.Sprintf("%x", signature) fmt.Println("signatureStr is:", signatureStr) // 拼接所有内容并进行Base64编码 tokenContent := ownerID + "," + apiID + "," + timeStampStr + "," + signatureStr token := base64.StdEncoding.EncodeToString([]byte(tokenContent)) fmt.Println("token is:", token) return token } // randomIP 生成合法的随机IPv4地址 func randomIP() string { // 设置随机数种子 rand.Seed(time.Now().UnixNano()) // 生成四个随机整数作为IPv4地址的四个部分 ip := fmt.Sprintf("%d.%d.%d.%d", rand.Intn(256), rand.Intn(256), rand.Intn(256), rand.Intn(256)) // 检查生成的IP是否合法 parsedIP := net.ParseIP(ip) for parsedIP == nil || parsedIP.IsLoopback() || parsedIP.IsLinkLocalMulticast() || parsedIP.IsLinkLocalUnicast() || parsedIP.IsMulticast() || parsedIP.IsUnspecified() { ip = fmt.Sprintf("%d.%d.%d.%d", rand.Intn(256), rand.Intn(256), rand.Intn(256), rand.Intn(256)) parsedIP = net.ParseIP(ip) } return ip } // 组合数据 func getNewOppoData(req *models.NewSendDataReq) models.OppoSendDataReq { itemData1 := models.ClueDataItem{ Column: "姓名", Desc: "姓名输入框", IfNeed: true, Type: "1", Value: req.Name, } itemData2 := models.ClueDataItem{ Column: "电话", Desc: "电话", IfNeed: true, Type: "3", Value: req.Tel, } //itemData3 := models.ClueDataItem{} //if len(req.Options) != 0 { // itemData3.Column = "八大员" // itemData3.Desc = "八大员" // itemData3.IfNeed = true // itemData3.Type = "6" // 多选 // itemData3.Options = req.Options //} var itemList []models.ClueDataItem itemList = append(itemList, itemData1) itemList = append(itemList, itemData2) //if len(req.Options) != 0 { // itemList = append(itemList, itemData3) //} strPageId, _ := strconv.ParseInt(pageIdValue, 10, 64) var nOwnerId int64 if req.Type == 2 { nOwnerId = OwnerIDNum12 } else { nOwnerId = OwnerIDNum14 } data := models.OppoSendDataReq{ PageId: strPageId, OwnerId: nOwnerId, Ip: randomIP(), Tid: tidValue, Lbid: lbidValue, TransformType: TransformType, Items: itemList, } return data }