migu_admin_server/app/admin/models/migu_music.go
chenlin 71cb0c34e5 1、通过excel导入咪咕音乐数据接口;
2、优化"营收分析"、"用户留存记录(按天)"接口,增加产品id和渠道的筛选;
2025-03-28 13:59:48 +08:00

316 lines
8.5 KiB
Go

package models
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/go-admin-team/go-admin-core/logger"
"go-admin/common/database"
"io"
"net/http"
"net/url"
"time"
)
const (
MusicProductID = 2
MaxRetries = 3
LoginType = "3"
ServiceId = "698039049108516515"
MiGuSubscriptionUrl = "http://hz.migu.cn/order/rest/201906/all/bjhy/and/package/query.do"
MiGuLoginUrl = "http://hz.migu.cn/order/rest/login/secret/url.do"
SignSecretKey = "1524b4ed9eef4cdca934056499a1dd14" // 签名密钥
LoginSecretKey = "913efe5c6f274c278988af817f9d1c7d" // 登陆密钥
)
type MonthlySubscriptionReq struct {
ChannelCode string `json:"channelCode"`
Timestamp string `json:"timestamp"`
Signature string `json:"signature"`
Token string `json:"token"`
ServiceId string `json:"serviceId"`
}
type MonthlySubscriptionResp struct {
ResCode string `json:"resCode"`
ResMsg string `json:"resMsg"`
Status string `json:"status"`
ValidTime string `json:"validTime"`
}
func generateSignature(channelCode, timestamp string) string {
data := channelCode + timestamp + SignSecretKey
hash := md5.Sum([]byte(data))
return hex.EncodeToString(hash[:])
}
func MonthlySubscriptionQuery(token, serviceId, channelCode string) (MonthlySubscriptionResp, error) {
fmt.Println("MonthlySubscriptionQuery start")
logger.Info("MonthlySubscriptionQuery start")
var respData MonthlySubscriptionResp
timestamp := time.Now().Format("20060102150405")
signature := generateSignature(channelCode, timestamp)
reqBody := MonthlySubscriptionReq{
ChannelCode: channelCode,
Timestamp: timestamp,
Signature: signature,
Token: token,
ServiceId: serviceId,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
fmt.Println("Error marshalling request body:", err)
return respData, err
}
fmt.Println("MonthlySubscriptionQuery req:", string(jsonData))
logger.Info("MonthlySubscriptionQuery req:", string(jsonData))
client := &http.Client{}
req, err := http.NewRequest("GET", MiGuSubscriptionUrl+"?data="+url.QueryEscape(string(jsonData)), nil)
if err != nil {
fmt.Println("Error creating HTTP request:", err)
logger.Error("Error creating HTTP request:", err)
return respData, err
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error making HTTP request:", err)
logger.Error("Error making HTTP request:", err)
return respData, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
logger.Error("Error reading response body:", err)
return respData, err
}
fmt.Println("MonthlySubscriptionQuery resp:", string(body))
logger.Info("MonthlySubscriptionQuery resp:", string(body))
err = json.Unmarshal(body, &respData)
if err != nil {
fmt.Println("Error unmarshalling response body:", err)
logger.Error("Error unmarshalling response body:", err)
return respData, err
}
fmt.Println("MonthlySubscriptionQuery end")
logger.Info("MonthlySubscriptionQuery end")
return respData, nil
}
type LoginRequest struct {
ChannelCode string `json:"channelCode"`
Timestamp string `json:"timestamp"`
Signature string `json:"signature"`
LoginType string `json:"loginType"`
CallBackUrl string `json:"callBackUrl,omitempty"`
Key string `json:"key,omitempty"`
Msisdn string `json:"msisdn,omitempty"`
}
type LoginResponse struct {
ResCode string `json:"resCode"`
ResMsg string `json:"resMsg"`
Token string `json:"token"`
}
func Login(channelCode, loginType, callBackUrl, msisdn string) (LoginResponse, error) {
fmt.Println("login start")
logger.Info("login start")
var respData LoginResponse
timestamp := time.Now().Format("20060102150405")
signature := generateSignature(channelCode, timestamp)
reqBody := LoginRequest{
ChannelCode: channelCode,
Timestamp: timestamp,
Signature: signature,
LoginType: loginType,
}
if loginType == "1" && callBackUrl != "" {
reqBody.CallBackUrl = callBackUrl
} else if loginType == "3" {
reqBody.Key = LoginSecretKey
reqBody.Msisdn = msisdn
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
fmt.Println("Error marshalling request body:", err)
return respData, err
}
fmt.Println("login req:", string(jsonData))
logger.Info("login req:", string(jsonData))
client := &http.Client{}
req, err := http.NewRequest("GET", MiGuLoginUrl+"?data="+url.QueryEscape(string(jsonData)), nil)
if err != nil {
fmt.Println("Error creating HTTP request:", err)
logger.Error("Error creating HTTP request:", err)
return respData, err
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error making HTTP request:", err)
logger.Error("Error making HTTP request:", err)
return respData, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
logger.Error("Error reading response body:", err)
return respData, err
}
fmt.Println("login resp:", string(body))
logger.Info("login resp:", string(body))
err = json.Unmarshal(body, &respData)
if err != nil {
fmt.Println("Error unmarshalling response body:", err)
logger.Error("Error unmarshalling response body:", err)
return respData, err
}
fmt.Println("login end")
logger.Info("login end")
return respData, nil
}
// CheckMusicOrderState 定时任务,检查咪咕音乐的订单是否有退订
func CheckMusicOrderState() {
logger.Info("****** CheckMusicOrderState start ******")
fmt.Println("****** CheckMusicOrderState start ******")
if database.Db == nil {
logger.Error("Database connection is nil")
fmt.Println("Database connection is nil")
return
}
// 查询订单列表中未退订的用户,查询其是否退订;如果退订,则更新退订时间
var orderList []MgOrder
err := database.Db.Where("state = 1").
Where("product_id = ?", MusicProductID).
Order("created_at desc").
Find(&orderList).Error
if err != nil {
fmt.Println("query mg_order err:", err.Error())
logger.Error("query mg_order err:", err.Error())
return
}
fmt.Println("orderList size is:", len(orderList))
logger.Info("orderList size is:", len(orderList))
for _, order := range orderList {
var token string
// 登录接口调用
if !attemptLogin(&token, order) {
continue
}
// 订阅状态查询
if !checkSubscriptionStatus(token, order) {
continue
}
}
fmt.Println("****** CheckMusicOrderState end ******")
logger.Info("****** CheckMusicOrderState end ******")
}
func attemptLogin(token *string, order MgOrder) bool {
for j := 0; j < MaxRetries; j++ {
resp, err := Login(order.ChannelCode, LoginType, "", order.PhoneNumber)
if err != nil || resp.ResCode != "000000" {
if err != nil {
fmt.Println("Login failed:", err.Error())
logger.Error("Login failed:", err.Error())
} else {
fmt.Println("Login failed, loginResp:", resp)
logger.Error("Login failed, loginResp:", resp)
}
if j < MaxRetries-1 {
continue
}
return false
}
*token = resp.Token
return true
}
return false
}
func checkSubscriptionStatus(token string, order MgOrder) bool {
for j := 0; j < MaxRetries; j++ {
resp, err := MonthlySubscriptionQuery(token, ServiceId, order.ChannelCode)
if err != nil || resp.ResCode != "000000" {
if err != nil {
fmt.Println("MonthlySubscriptionQuery failed:", err.Error())
logger.Error("MonthlySubscriptionQuery failed:", err.Error())
} else {
fmt.Println("MonthlySubscriptionQuery failed, MonthlySubscriptionResp:", resp.ResCode)
logger.Error("MonthlySubscriptionQuery failed, MonthlySubscriptionResp:", resp.ResCode)
}
if j < MaxRetries-1 {
continue
}
return false
}
if resp.Status == "0" {
return true
} else if resp.Status == "1" {
if order.State == SubscribeOK {
subscribeTime := order.CreatedAt
unsubTime := time.Now().Format("2006-01-02 15:04:05")
cancelFlag := 0
if IsWithinOneHourCancel(subscribeTime, unsubTime) {
cancelFlag = 1
}
err = database.Db.Table("mg_order").Where("order_serial = ?", order.OrderSerial).Updates(map[string]interface{}{
"state": UnsubscribeOK,
"is_one_hour_cancel": cancelFlag,
"unsubscribe_time": unsubTime,
"updated_at": time.Now(),
}).Error
if err != nil {
fmt.Println("Failed to update order:", err.Error())
logger.Error("Failed to update order:", err.Error())
}
return false
}
}
}
return false
}