qnc init
This commit is contained in:
205
service/antifraud.go
Normal file
205
service/antifraud.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/model/request"
|
||||
"qnc-server/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AntiFraudService struct {
|
||||
}
|
||||
|
||||
const RetCodeSuccess = "000000"
|
||||
const RetCodeEmpty = "100000"
|
||||
|
||||
func (a *AntiFraudService) ReqYuShan(data *model.AntiFraudReqPayload) (plainText []byte, err error) {
|
||||
currentTime := time.Now()
|
||||
unixMilliseconds := currentTime.UnixNano() / int64(time.Millisecond)
|
||||
requestSN, _ := utils.GenerateRandomString()
|
||||
apiKey := config.ConfigData.Antifraud.ApiKey
|
||||
acctId := config.ConfigData.Antifraud.AcctId
|
||||
httpUrl := config.ConfigData.Antifraud.HttpUrl
|
||||
// 根据 ProdID 动态构建请求数据
|
||||
reqData := map[string]interface{}{
|
||||
"prod_id": data.ProdID,
|
||||
"req_time": unixMilliseconds,
|
||||
"request_sn": requestSN,
|
||||
"req_data": map[string]interface{}{},
|
||||
}
|
||||
|
||||
for _, param := range model.AntiFraudProdIDParams[data.ProdID] {
|
||||
switch param {
|
||||
case "cardNo":
|
||||
reqData["req_data"].(map[string]interface{})["cardNo"] = data.CardNo
|
||||
case "name":
|
||||
reqData["req_data"].(map[string]interface{})["name"] = data.Name
|
||||
case "mobile":
|
||||
reqData["req_data"].(map[string]interface{})["mobile"] = data.Mobile
|
||||
case "type":
|
||||
reqData["req_data"].(map[string]interface{})["type"] = 3
|
||||
case "keyWord":
|
||||
reqData["req_data"].(map[string]interface{})["keyWord"] = data.CardNo
|
||||
}
|
||||
}
|
||||
messageBytes, err := json.Marshal(reqData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
key, err := hex.DecodeString(apiKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//加密
|
||||
cipherText := utils.AES_CBC_Encrypt(messageBytes, key)
|
||||
|
||||
content := base64.StdEncoding.EncodeToString(cipherText)
|
||||
respStr, err := httpDo(httpUrl, content, acctId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//解密
|
||||
sDec, err := base64.StdEncoding.DecodeString(respStr)
|
||||
if err != nil {
|
||||
if utils.IsJSON(respStr) {
|
||||
return []byte(respStr), nil
|
||||
}
|
||||
return
|
||||
}
|
||||
plainText = utils.AES_CBC_Decrypt(sDec, key)
|
||||
return
|
||||
}
|
||||
|
||||
// post请求
|
||||
func httpDo(url string, content string, acctId string) (stringBody string, err error) {
|
||||
client := &http.Client{}
|
||||
|
||||
req, err := http.NewRequest("POST", url, strings.NewReader(content))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("ACCT_ID", acctId)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return string(body), nil
|
||||
}
|
||||
|
||||
// 对返回信息进行处理,返回一份完整的报告
|
||||
func (a *AntiFraudService) DataAnalysis(antiFraud model.AntiFraud) (report model.AntiFraudReport) {
|
||||
// 反欺诈评分(标准简版),分值越低风险越高
|
||||
var fraudScoreResp model.YuShanResponse[model.FraudScoreRetData]
|
||||
err := json.Unmarshal([]byte(antiFraud.FraudScoreResp), &fraudScoreResp)
|
||||
if err != nil {
|
||||
log.Printf("fraudScoreResp Unmarshal error:%v", err)
|
||||
}
|
||||
if fraudScoreResp.Retcode == RetCodeSuccess {
|
||||
report.FraudScore.Score = utils.ConvertScore(fraudScoreResp.Retdata.BjScore, 300, 850)
|
||||
} else {
|
||||
log.Printf("fraudScoreResp error:%s", fraudScoreResp.Retmsg)
|
||||
}
|
||||
|
||||
// 综合风险评估
|
||||
var riskAssessmentResp model.YuShanResponse[model.RiskAssessmentRetData]
|
||||
err = json.Unmarshal([]byte(antiFraud.RiskAssessmentResp), &riskAssessmentResp)
|
||||
if err != nil {
|
||||
log.Printf("riskAssessmentResp Unmarshal error:%v", err)
|
||||
}
|
||||
if riskAssessmentResp.Retcode == RetCodeSuccess {
|
||||
report.RiskAssessment.Score = utils.ConvertScore(riskAssessmentResp.Retdata.BjScore, 300, 850)
|
||||
} else {
|
||||
log.Printf("riskAssessmentResp error:%s", riskAssessmentResp.Retmsg)
|
||||
}
|
||||
|
||||
// 风险手机号列表核验
|
||||
var mobileRiskCheckResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(antiFraud.MobileRiskCheckResp), &mobileRiskCheckResp)
|
||||
if err != nil {
|
||||
log.Printf("mobileRiskCheckResp Unmarshal error:%v", err)
|
||||
}
|
||||
if mobileRiskCheckResp.Retcode == RetCodeSuccess {
|
||||
report.MobileRiskCheck = mobileRiskCheckResp.Retdata
|
||||
} else {
|
||||
log.Printf("mobileRiskCheckResp error:%s", mobileRiskCheckResp.Retmsg)
|
||||
}
|
||||
|
||||
// 风险人员V2 RiskPersonV2Resp
|
||||
var riskPersonV2Resp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(antiFraud.RiskPersonV2Resp), &riskPersonV2Resp)
|
||||
if err != nil {
|
||||
log.Printf("riskPersonV2Resp Unmarshal error:%v", err)
|
||||
}
|
||||
if riskPersonV2Resp.Retcode == RetCodeSuccess {
|
||||
report.RiskPersonV2 = riskPersonV2Resp.Retdata
|
||||
} else {
|
||||
log.Printf("riskPersonV2Resp error:%s", riskPersonV2Resp.Retmsg)
|
||||
}
|
||||
|
||||
// 反诈反赌核验 AntiFraudGamblingResp
|
||||
var antiFraudGamblingResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(antiFraud.AntiFraudGamblingResp), &antiFraudGamblingResp)
|
||||
if err != nil {
|
||||
log.Printf("antiFraudGamblingResp Unmarshal error:%v", err)
|
||||
}
|
||||
if antiFraudGamblingResp.Retcode == RetCodeSuccess {
|
||||
report.AntiFraudGambling = antiFraudGamblingResp.Retdata
|
||||
} else {
|
||||
log.Printf("antiFraudGamblingResp error:%s", antiFraudGamblingResp.Retmsg)
|
||||
}
|
||||
|
||||
// 电信诈骗名单 TelecomFraudListResp
|
||||
var telecomFraudListResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(antiFraud.TelecomFraudListResp), &telecomFraudListResp)
|
||||
if err != nil {
|
||||
log.Printf("telecomFraudListResp Unmarshal error:%v", err)
|
||||
}
|
||||
if telecomFraudListResp.Retcode == RetCodeSuccess {
|
||||
report.TelecomFraudList = telecomFraudListResp.Retdata
|
||||
} else {
|
||||
log.Printf("telecomFraudListResp error:%s", telecomFraudListResp.Retmsg)
|
||||
}
|
||||
|
||||
// 个人可信度 PersonalCredibilityResp
|
||||
var personalCredibilityResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(antiFraud.PersonalCredibilityResp), &personalCredibilityResp)
|
||||
if err != nil {
|
||||
log.Printf("personalCredibilityResp Unmarshal error:%v", err)
|
||||
}
|
||||
if personalCredibilityResp.Retcode == RetCodeSuccess {
|
||||
report.PersonalCredibility = personalCredibilityResp.Retdata
|
||||
} else {
|
||||
log.Printf("personalCredibilityResp error:%s", personalCredibilityResp.Retmsg)
|
||||
}
|
||||
return report
|
||||
}
|
||||
|
||||
func (a *AntiFraudService) GetAntifraud(reqBody request.AntiFraudQueryReq) (af model.AntiFraud) {
|
||||
db.DB.Where("card_no = ? AND name = ? AND mobile = ?", reqBody.CardNo, reqBody.Name, reqBody.Mobile).First(&af)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *AntiFraudService) QueryAntifraudOrder(orderID uint) (antifraud []model.AntiFraud, err error) {
|
||||
err = db.DB.Where("order_id = ?", orderID).Find(&antifraud).Error
|
||||
if err != nil {
|
||||
log.Printf("query antifraud order failed: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
354
service/car.go
Normal file
354
service/car.go
Normal file
@@ -0,0 +1,354 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"log"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CarService struct {
|
||||
}
|
||||
|
||||
func (c *CarService) CarReqYuShan(prodID string, data *map[string]interface{}) (plainText []byte, err error) {
|
||||
currentTime := time.Now()
|
||||
unixMilliseconds := currentTime.UnixNano() / int64(time.Millisecond)
|
||||
requestSN, _ := utils.GenerateRandomString()
|
||||
apiKey := config.ConfigData.Car.ApiKey
|
||||
acctId := config.ConfigData.Car.AcctId
|
||||
httpUrl := config.ConfigData.Car.HttpUrl
|
||||
// 根据 ProdID 动态构建请求数据
|
||||
reqData := map[string]interface{}{
|
||||
"prod_id": prodID,
|
||||
"req_time": unixMilliseconds,
|
||||
"request_sn": requestSN,
|
||||
"req_data": data,
|
||||
}
|
||||
|
||||
messageBytes, err := json.Marshal(reqData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
key, err := hex.DecodeString(apiKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//加密
|
||||
cipherText := utils.AES_CBC_Encrypt(messageBytes, key)
|
||||
|
||||
content := base64.StdEncoding.EncodeToString(cipherText)
|
||||
respStr, err := httpDo(httpUrl, content, acctId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//解密
|
||||
sDec, err := base64.StdEncoding.DecodeString(respStr)
|
||||
if err != nil {
|
||||
if utils.IsJSON(respStr) {
|
||||
return []byte(respStr), nil
|
||||
}
|
||||
return
|
||||
}
|
||||
plainText = utils.AES_CBC_Decrypt(sDec, key)
|
||||
return
|
||||
}
|
||||
|
||||
// 对返回信息进行处理,返回一份完整的报告
|
||||
func (c *CarService) CarInsuranceDataAnalysis(respString string) (data map[string]interface{}, err error) {
|
||||
var resp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(respString), &resp)
|
||||
if err != nil {
|
||||
log.Printf("CarInsurance Unmarshal error:%v", err)
|
||||
return nil, utils.ErrSystemError
|
||||
}
|
||||
if resp.Retcode == RetCodeSuccess {
|
||||
data = resp.Retdata
|
||||
return data, nil
|
||||
} else if resp.Retcode == RetCodeEmpty {
|
||||
log.Printf("Car resp empty:%s", resp.Retmsg)
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
log.Printf("Car resp error:%s", resp.Retmsg)
|
||||
return data, utils.ErrSystemError
|
||||
}
|
||||
}
|
||||
|
||||
// 对返回信息进行处理,返回一份完整的报告
|
||||
func (c *CarService) CarDataAnalysis(respString string) (data model.YuShanResponse[map[string]interface{}], err error) {
|
||||
err = json.Unmarshal([]byte(respString), &data)
|
||||
if err != nil {
|
||||
log.Printf("CarInsurance Unmarshal error:%v", err)
|
||||
return data, utils.ErrUnmashal
|
||||
}
|
||||
if data.Retcode == RetCodeSuccess {
|
||||
return data, nil
|
||||
} else if data.Retcode == RetCodeEmpty {
|
||||
log.Printf("Car resp empty:%s", data.Retmsg)
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
log.Printf("Car resp error:%s", data.Retmsg)
|
||||
return data, utils.ErrSystemError
|
||||
}
|
||||
}
|
||||
|
||||
// 对返回信息进行处理,返回一份完整的报告 人车核验特殊版
|
||||
func (c *CarService) CarPersonCarVerifyDataAnalysis(respString string) (data map[string]interface{}, err error) {
|
||||
var resp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(respString), &resp)
|
||||
if err != nil {
|
||||
log.Printf("CarPersonCarVerifyDataAnalysis Unmarshal error:%v", err)
|
||||
return nil, utils.ErrSystemError
|
||||
}
|
||||
if resp.Retcode == RetCodeSuccess {
|
||||
if resp.Retdata == nil {
|
||||
log.Printf("Car resp empty:%s", resp.Retmsg)
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
data = resp.Retdata
|
||||
return data, nil
|
||||
}
|
||||
|
||||
} else if resp.Retcode == RetCodeEmpty {
|
||||
log.Printf("Car resp empty:%s", resp.Retmsg)
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
log.Printf("Car resp error:%s", resp.Retmsg)
|
||||
return data, utils.ErrSystemError
|
||||
}
|
||||
}
|
||||
func (c *CarService) GetRecordByFeature(feature string, id uint, userID uint) (interface{}, error) {
|
||||
var result interface{}
|
||||
switch feature {
|
||||
case "chexian":
|
||||
var record model.CarInsurance
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "weibao":
|
||||
var record model.CarMaintenance
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "rencheheyan":
|
||||
var record model.CarPersonCarVerify
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarPersonCarVerifyDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "mingxiacheliang":
|
||||
var record model.CarUnderName
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "cheliangshangxian":
|
||||
var record model.CarInsuranceInfo
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysisSx, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysisWx, err := c.CarInsuranceDataAnalysis(record.FiveResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = gin.H{
|
||||
"shangxian": analysisSx,
|
||||
"chewuxiang": analysisWx,
|
||||
}
|
||||
case "cheliangguohu":
|
||||
var record model.CarVehicleTransfer
|
||||
if err := db.DB.Where("order_id = ?", id).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "vinchache":
|
||||
var record model.CarVinCheckInfo
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "cheliangguzhi":
|
||||
var record model.CarVehicleValuation
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
default:
|
||||
return nil, errors.New("Invalid feature")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *CarService) GetRecordCaseByFeature(feature string) (interface{}, error) {
|
||||
var result interface{}
|
||||
switch feature {
|
||||
case "chexian":
|
||||
var record model.CarInsurance
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "weibao":
|
||||
var record model.CarMaintenance
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "mingxiacheliang":
|
||||
var record model.CarUnderName
|
||||
if err := db.DB.Where("id = ? ", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "rencheheyan":
|
||||
var record model.CarPersonCarVerify
|
||||
if err := db.DB.Where("id = ? ", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarPersonCarVerifyDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "cheliangshangxian":
|
||||
var record model.CarInsuranceInfo
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysisSx, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysisWx, err := c.CarInsuranceDataAnalysis(record.FiveResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = gin.H{
|
||||
"shangxian": analysisSx,
|
||||
"chewuxiang": analysisWx,
|
||||
}
|
||||
case "vinchache":
|
||||
var record model.CarVinCheckInfo
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "cheliangguohu":
|
||||
var record model.CarVehicleTransfer
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
case "cheliangguzhi":
|
||||
var record model.CarVehicleValuation
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.CarInsuranceDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis
|
||||
default:
|
||||
return nil, errors.New("Invalid feature")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *CarService) DecodeYushan(resp []byte) (plainText []byte, err error) {
|
||||
apiKey := config.ConfigData.Car.ApiKey
|
||||
key, err := hex.DecodeString(apiKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
respStr := string(resp)
|
||||
sDec, err := base64.StdEncoding.DecodeString(respStr)
|
||||
if err != nil {
|
||||
if utils.IsJSON(respStr) {
|
||||
log.Printf("车辆维保记录CAR058回调 DecodeJSON err:%s", respStr)
|
||||
return []byte(respStr), nil
|
||||
}
|
||||
}
|
||||
plainText = utils.AES_CBC_Decrypt(sDec, key)
|
||||
return plainText, nil
|
||||
}
|
||||
func (c *CarService) GetMaintenanceBySn(sn string) (maintenance *model.CarMaintenance, err error) {
|
||||
err = db.DB.Where("notify_sn = ?", sn).First(&maintenance).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return maintenance, nil
|
||||
}
|
||||
func (c *CarService) GetMaintenanceList(pageSize int, pageNum int, userId uint) (list []model.CarMaintenance, err error) {
|
||||
offset := (pageNum - 1) * pageSize
|
||||
result := db.DB.Model(&model.CarMaintenance{}).
|
||||
Select("id, created_at, updated_at, order_id, status, userid, vin").
|
||||
Where("userid = ?", userId).Order("id desc").
|
||||
Limit(pageSize).
|
||||
Offset(offset).
|
||||
Find(&list)
|
||||
if result.Error != nil {
|
||||
return list, result.Error
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
117
service/ent.go
Normal file
117
service/ent.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/model/request"
|
||||
"qnc-server/model/response"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type EntSerivce struct {
|
||||
}
|
||||
|
||||
// 请求天眼查
|
||||
func (e *EntSerivce) RequestTycOpen(data interface{}, link string) (respData interface{}, err error) {
|
||||
baseURL := config.ConfigData.TycOpen.Url
|
||||
completeURL := fmt.Sprintf("%s/%s", baseURL, link)
|
||||
token := config.ConfigData.TycOpen.Token
|
||||
// 创建查询参数
|
||||
params := url.Values{}
|
||||
// 根据数据类型设置查询参数
|
||||
switch v := data.(type) {
|
||||
case request.EntReq:
|
||||
params.Add("keyword", v.Keyword)
|
||||
case request.EntListReq:
|
||||
if link == "open/v4/open/partners" || link == "open/human/companyholding/2.0" {
|
||||
params.Add("cid", v.Keyword)
|
||||
} else {
|
||||
params.Add("keyword", v.Keyword)
|
||||
}
|
||||
if v.PageNum != 0 {
|
||||
params.Add("page_num", strconv.Itoa(v.PageNum))
|
||||
}
|
||||
if v.PageSize != 0 {
|
||||
params.Add("page_size", strconv.Itoa(v.PageSize))
|
||||
}
|
||||
case request.EntSearchReq:
|
||||
params.Add("word", v.Work)
|
||||
if v.PageNum != 0 {
|
||||
params.Add("page_num", strconv.Itoa(v.PageNum))
|
||||
}
|
||||
if v.PageSize != 0 {
|
||||
params.Add("page_size", strconv.Itoa(v.PageSize))
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("未知的数据类型")
|
||||
return
|
||||
}
|
||||
|
||||
// 构建完整的请求 URL
|
||||
requestURL := fmt.Sprintf("%s?%s", completeURL, params.Encode())
|
||||
|
||||
// 创建请求
|
||||
reqBody := bytes.NewBuffer([]byte{})
|
||||
req, err := http.NewRequest("GET", requestURL, reqBody)
|
||||
if err != nil {
|
||||
log.Printf("failed 创建请求: %v", err)
|
||||
return
|
||||
}
|
||||
// 设置请求头
|
||||
req.Header.Set("Authorization", token)
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("failed 发送请求: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("failed 读取响应体: %v", err)
|
||||
return
|
||||
}
|
||||
log.Printf("【企业响应】: %v", string(body))
|
||||
var queryResp response.EntResponse
|
||||
err = json.Unmarshal(body, &queryResp)
|
||||
if err != nil {
|
||||
log.Printf("failed to unmarshal response: %v", err)
|
||||
return
|
||||
}
|
||||
if queryResp.ErrorCode == 0 || queryResp.ErrorCode == 300000 {
|
||||
respData = queryResp.Result
|
||||
return
|
||||
}
|
||||
if message, exists := response.EntRepsStatusCodeMap[queryResp.ErrorCode]; exists {
|
||||
log.Println(message, queryResp.Reason, requestURL)
|
||||
return nil, fmt.Errorf("response status error: %s", queryResp.Reason)
|
||||
} else {
|
||||
log.Println("未知的状态码:", queryResp.Reason)
|
||||
return nil, fmt.Errorf("response undefind status error: %s", queryResp.Reason)
|
||||
}
|
||||
}
|
||||
func (e *EntSerivce) QueryEntFeatureOrder(orderID uint) (entFeature []model.EntFeature, err error) {
|
||||
err = db.DB.Where("order_id = ?", orderID).Find(&entFeature).Error
|
||||
if err != nil {
|
||||
log.Printf("query entFeature order failed: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (e *EntSerivce) SaveEntFeatureRecords(record model.EntFeature) (err error) {
|
||||
err = db.DB.Save(&record).Error
|
||||
if err != nil {
|
||||
log.Printf("entFeature save record failed: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
174
service/feature.go
Normal file
174
service/feature.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/jung-kurt/gofpdf"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"qnc-server/utils"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const API_KEY = "aMsrBNGUJxgcgqdm3SEdcumm"
|
||||
const SECRET_KEY = "sWlv2h2AWA3aAt5bjXCkE6WeA5AzpAAD"
|
||||
|
||||
type Feature struct {
|
||||
}
|
||||
|
||||
// Service 函数:接受 base64 编码的图像,返回 OCR 识别结果
|
||||
func (f *Feature) OCRService(imageBase64 string) (string, error) {
|
||||
// 获取 Access Token
|
||||
accessToken := f.GetAccessToken()
|
||||
if accessToken == "" {
|
||||
return "", fmt.Errorf("获取 Access Token 失败")
|
||||
}
|
||||
|
||||
// 设置请求 URL
|
||||
url := "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + accessToken
|
||||
|
||||
// 设置请求体,包含图片的 base64 编码
|
||||
payload := strings.NewReader(fmt.Sprintf("image=%s&detect_direction=false¶graph=false&probability=false&multidirectional_recognize=false", imageBase64))
|
||||
|
||||
// 创建 HTTP 客户端和请求
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("POST", url, payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Add("Accept", "application/json")
|
||||
|
||||
// 发送请求并获取响应
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(body), nil
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 AK,SK 生成鉴权签名(Access Token)
|
||||
* @return string 鉴权签名信息(Access Token)
|
||||
*/
|
||||
func (f *Feature) GetAccessToken() string {
|
||||
url := "https://aip.baidubce.com/oauth/2.0/token"
|
||||
postData := fmt.Sprintf("grant_type=client_credentials&client_id=%s&client_secret=%s", API_KEY, SECRET_KEY)
|
||||
resp, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(postData))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return ""
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return ""
|
||||
}
|
||||
accessTokenObj := map[string]interface{}{}
|
||||
_ = json.Unmarshal(body, &accessTokenObj)
|
||||
return accessTokenObj["access_token"].(string)
|
||||
}
|
||||
|
||||
func (f *Feature) GenerateSignPDF(name string, id uint, signatureBase64 string) (fileName string, err error) {
|
||||
// 创建 PDF 实例,A4 纸张大小
|
||||
pdf := gofpdf.New("P", "mm", "A4", "")
|
||||
|
||||
fontPath := "simhei.ttf"
|
||||
|
||||
// 添加中文字体支持
|
||||
pdf.AddUTF8Font("SimHei", "", fontPath) // 使用 simhei.ttf 字体
|
||||
pdf.SetFont("SimHei", "", 12)
|
||||
|
||||
// 添加一页
|
||||
pdf.AddPage()
|
||||
|
||||
// 插入标题,居中对齐
|
||||
pdf.SetFont("SimHei", "", 20)
|
||||
pdf.CellFormat(0, 10, "声明", "", 1, "C", false, 0, "") // C 表示居中对齐
|
||||
pdf.Ln(12)
|
||||
|
||||
// 插入副标题
|
||||
pdf.SetFont("SimHei", "", 14)
|
||||
pdf.Cell(40, 10, "全能查声明:")
|
||||
pdf.Ln(10)
|
||||
|
||||
// 插入正文内容,添加两字符的缩进(全角空格)
|
||||
pdf.SetFont("SimHei", "", 12)
|
||||
indent := " " // 两字符的缩进,使用全角空格
|
||||
pdf.MultiCell(0, 10, indent+"1、本产品所有数据均来自第三方。可能部分数据未公开,数据更新延迟或信息受到限制,不一定全部返回,因此我们不做准确性、真实性、完整性承诺。不同数据格式及记录详细程度会存在差异,此为行业正常现象。本报告仅供参考,不能作为诉讼证据、决策性依据等材料,请结合实际情况,做出更准确的决策。", "", "", false)
|
||||
pdf.Ln(3)
|
||||
|
||||
pdf.MultiCell(0, 10, indent+"2、本产品仅供用户本人查询或被授权查询。除非用户取得合法授权,用户不得利用本产品查询他人信息。用户因未获得合法授权而擅自查询他人信息所产生的任何后果,由用户自行承担责任。", "", "", false)
|
||||
pdf.Ln(3)
|
||||
|
||||
// 插入承诺声明
|
||||
pdf.SetFont("SimHei", "", 14)
|
||||
pdf.Cell(40, 10, "本人承诺:")
|
||||
pdf.Ln(10)
|
||||
|
||||
text := fmt.Sprintf("本人%s在此声明,我即将通过此小程序查询的婚姻状态信息仅涉及本人。本人确认不将所得信息用作任何诉讼证据,不会将所获取的信息用于任何非法用途,包括但不限于欺诈、胁迫、侵犯隐私或其他违法行为,不将所得信息转卖、传播给他人。本人承诺对查询结果所引发的任何后果承担全部责任。", name)
|
||||
|
||||
// 插入承诺内容,添加两字符的缩进
|
||||
pdf.SetFont("SimHei", "", 12)
|
||||
pdf.MultiCell(0, 10, indent+text, "", "", false)
|
||||
pdf.Ln(10)
|
||||
|
||||
// 定位签名和日期到右下角
|
||||
pageWidth, pageHeight := pdf.GetPageSize()
|
||||
rightMargin := 20.0
|
||||
bottomMargin := 20.0
|
||||
|
||||
// 设置签名部分的 XY 坐标,靠右下角
|
||||
pdf.SetXY(pageWidth-rightMargin-40, pageHeight-bottomMargin-40) // 签名部分坐标
|
||||
pdf.SetFont("SimHei", "", 12)
|
||||
pdf.Cell(40, 10, "签名:")
|
||||
|
||||
// 解码 Base64 签名图片并保存为临时文件
|
||||
var tempFileName = fmt.Sprintf("signature-%d.png", id)
|
||||
signaturePath, err := utils.DecodeBase64ToPNG(signatureBase64, tempFileName)
|
||||
if err != nil {
|
||||
log.Printf("【签名图片生成】解码 Base64 签名图片并保存为临时文件失败:%v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 在 PDF 中嵌入签名图片
|
||||
pdf.ImageOptions(signaturePath, pageWidth-rightMargin-28, pageHeight-bottomMargin-40, 40, 10, false, gofpdf.ImageOptions{ImageType: "PNG"}, 0, "")
|
||||
|
||||
// 插入当前日期,显示在签名下方
|
||||
currentDate := time.Now().Format("2006-01-02")
|
||||
currentDateCN := time.Now().Format("2006年01月02日")
|
||||
pdf.SetXY(pageWidth-rightMargin-40, pageHeight-bottomMargin-20)
|
||||
pdf.Cell(40, 10, "日期:"+currentDateCN)
|
||||
|
||||
// 根据日期和 ID 动态生成文件名
|
||||
outputDir := "signature"
|
||||
os.MkdirAll(outputDir, os.ModePerm) // 如果不存在则创建目录
|
||||
fileName = fmt.Sprintf("%s/%s_%d.pdf", outputDir, currentDate, id)
|
||||
|
||||
// 保存 PDF 文件
|
||||
err = pdf.OutputFileAndClose(fileName)
|
||||
if err != nil {
|
||||
log.Printf("【签名图片生成】保存 PDF 文件失败:%v", err)
|
||||
return "", err
|
||||
}
|
||||
// 删除临时签名图片文件
|
||||
err = os.Remove(signaturePath)
|
||||
if err != nil {
|
||||
log.Printf("【签名图片生成】删除临时文件失败:%v", err)
|
||||
}
|
||||
return fileName, nil
|
||||
}
|
||||
280
service/lawsuitQuery.go
Normal file
280
service/lawsuitQuery.go
Normal file
@@ -0,0 +1,280 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/model/request"
|
||||
"qnc-server/model/response"
|
||||
"qnc-server/utils"
|
||||
)
|
||||
|
||||
type LawsuitQueryService struct {
|
||||
}
|
||||
|
||||
func (l *LawsuitQueryService) QueryList(reqData request.LawsuitQueryReq) (data []response.CaseDetail, err error) {
|
||||
baseURL := config.ConfigData.LawsuitQuery.ListURL
|
||||
appCode := config.ConfigData.LawsuitQuery.AppCode
|
||||
// 创建查询参数
|
||||
params := url.Values{}
|
||||
params.Add("sign", utils.GenerateMD5())
|
||||
params.Add("entityName", reqData.Name)
|
||||
params.Add("entityId", reqData.CardNo)
|
||||
params.Add("needBranch", "1")
|
||||
params.Add("fl", "1")
|
||||
|
||||
// 构建完整的请求 URL
|
||||
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
|
||||
|
||||
// 创建请求
|
||||
reqBody := bytes.NewBuffer([]byte{})
|
||||
req, err := http.NewRequest("POST", requestURL, reqBody)
|
||||
if err != nil {
|
||||
log.Printf("failed 创建请求: %v", err)
|
||||
return
|
||||
}
|
||||
// 设置请求头
|
||||
req.Header.Set("Authorization", "APPCODE "+appCode)
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("failed 发送请求: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("failed 读取响应体: %v", err)
|
||||
return
|
||||
}
|
||||
var queryResp response.LawsuitQueryListResponse
|
||||
err = json.Unmarshal(body, &queryResp)
|
||||
if err != nil {
|
||||
log.Printf("query list failed to unmarshal response: %v", err)
|
||||
return
|
||||
}
|
||||
switch queryResp.Rc {
|
||||
case "0000":
|
||||
var respData response.LawsuitQueryListData
|
||||
queryRespBytes, err := json.Marshal(queryResp.Data)
|
||||
if err != nil {
|
||||
log.Printf("queryResp Marshal Error: %v", err)
|
||||
return nil, fmt.Errorf("响应错误,请稍后再试")
|
||||
}
|
||||
err = json.Unmarshal(queryRespBytes, &respData)
|
||||
if err != nil {
|
||||
log.Printf("sxr queryResp Unmarshal Error: %v", err)
|
||||
return nil, fmt.Errorf("响应错误,请稍后再试")
|
||||
}
|
||||
return respData.List, nil
|
||||
case "0001":
|
||||
log.Printf("涉诉专业版查询成功无数据: %v", queryResp.Msg)
|
||||
return data, nil
|
||||
case "1000":
|
||||
log.Printf("apikey校验失败: %v", err)
|
||||
return data, fmt.Errorf("响应错误,请稍后再试")
|
||||
default:
|
||||
log.Printf("未知响应代码: %s", queryResp.Rc)
|
||||
return data, fmt.Errorf("响应错误,请稍后再试")
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LawsuitQueryService) QuerySxrList(reqData request.LawsuitQueryReq) (data []response.SxrDetail, err error) {
|
||||
baseURL := config.ConfigData.LawsuitQuery.SxrURL
|
||||
appCode := config.ConfigData.LawsuitQuery.AppCode
|
||||
// 创建查询参数
|
||||
params := url.Values{}
|
||||
params.Add("sign", utils.GenerateMD5())
|
||||
params.Add("entityName", reqData.Name)
|
||||
params.Add("entityId", reqData.CardNo)
|
||||
params.Add("btype", "1")
|
||||
params.Add("related", "0")
|
||||
|
||||
// 构建完整的请求 URL
|
||||
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
|
||||
|
||||
// 创建请求
|
||||
reqBody := bytes.NewBuffer([]byte{})
|
||||
req, err := http.NewRequest("POST", requestURL, reqBody)
|
||||
if err != nil {
|
||||
log.Printf("failed 创建请求: %v", err)
|
||||
return
|
||||
}
|
||||
// 设置请求头
|
||||
req.Header.Set("Authorization", "APPCODE "+appCode)
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("failed 发送请求: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("failed 读取响应体: %v", err)
|
||||
return
|
||||
}
|
||||
var queryResp response.LawsuitQueryListResponse
|
||||
err = json.Unmarshal(body, &queryResp)
|
||||
if err != nil {
|
||||
log.Printf("sxr failed to unmarshal response: %v", err)
|
||||
return
|
||||
}
|
||||
switch queryResp.Rc {
|
||||
case "0000":
|
||||
var respData []response.SxrDetail
|
||||
queryRespBytes, err := json.Marshal(queryResp.Data)
|
||||
if err != nil {
|
||||
log.Printf("queryResp Marshal Error: %v", err)
|
||||
return nil, fmt.Errorf("响应错误,请稍后再试")
|
||||
}
|
||||
err = json.Unmarshal(queryRespBytes, &respData)
|
||||
if err != nil {
|
||||
log.Printf("sxr queryResp Unmarshal Error: %v", err)
|
||||
return nil, fmt.Errorf("响应错误,请稍后再试")
|
||||
}
|
||||
return respData, nil
|
||||
case "0001":
|
||||
return data, nil
|
||||
case "1000":
|
||||
log.Printf("apikey校验失败: %v", err)
|
||||
return data, fmt.Errorf("响应错误,请稍后再试")
|
||||
default:
|
||||
log.Printf("未知响应代码: %s", queryResp.Rc)
|
||||
return data, fmt.Errorf("响应错误,请稍后再试")
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LawsuitQueryService) QueryLimitHighList(reqData request.LawsuitQueryReq) (data []response.LimitHightDetail, err error) {
|
||||
baseURL := config.ConfigData.LawsuitQuery.LimitHightURL
|
||||
appCode := config.ConfigData.LawsuitQuery.AppCode
|
||||
// 创建查询参数
|
||||
params := url.Values{}
|
||||
params.Add("name", reqData.Name)
|
||||
params.Add("idcard_number", reqData.CardNo)
|
||||
params.Add("mobile_number", reqData.Mobile)
|
||||
|
||||
// 创建请求
|
||||
reqBody := bytes.NewBufferString(params.Encode())
|
||||
req, err := http.NewRequest("POST", baseURL, reqBody)
|
||||
if err != nil {
|
||||
log.Printf("failed 创建请求: %v", err)
|
||||
return
|
||||
}
|
||||
// 设置请求头
|
||||
req.Header.Set("Authorization", "APPCODE "+appCode)
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("failed 发送请求: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("failed 读取响应体: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
var queryResp response.LawsuitLimitHightQueryListResponse
|
||||
err = json.Unmarshal(body, &queryResp)
|
||||
if err != nil {
|
||||
log.Printf("limit hight failed to unmarshal response: %v", err)
|
||||
return
|
||||
}
|
||||
switch queryResp.Code {
|
||||
case 200:
|
||||
var respData response.LimitHightData
|
||||
queryRespBytes, err := json.Marshal(queryResp.Data)
|
||||
if err != nil {
|
||||
log.Printf("limit hight Marshal Error: %v", err)
|
||||
return nil, fmt.Errorf("响应错误,请稍后再试")
|
||||
}
|
||||
err = json.Unmarshal(queryRespBytes, &respData)
|
||||
if err != nil {
|
||||
log.Printf("limit hight failed to unmarshal data: %v", err)
|
||||
return nil, fmt.Errorf("响应错误,请稍后再试")
|
||||
}
|
||||
return respData.CaseList, nil
|
||||
case 400:
|
||||
return data, nil
|
||||
default:
|
||||
log.Printf("%s响应错误: %s", params.Encode(), queryResp.Msg)
|
||||
return data, fmt.Errorf("请求错误:%s", queryResp.Msg)
|
||||
}
|
||||
}
|
||||
func (l *LawsuitQueryService) SaveLawsuit(userid uint, reqBody request.LawsuitQueryReq, orderID uint, combinedResponse response.CombinedResponse) (err error) {
|
||||
ListRespMarshal, err := json.Marshal(combinedResponse.ListResp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
SxrRespMarshal, err := json.Marshal(combinedResponse.SxrResp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
LimitHightRespMarshal, err := json.Marshal(combinedResponse.LimitHightResp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = db.DB.Create(&model.Lawsuit{
|
||||
UserID: userid,
|
||||
CardNo: reqBody.CardNo,
|
||||
Name: reqBody.Name,
|
||||
Mobile: reqBody.Mobile,
|
||||
ListResp: string(ListRespMarshal),
|
||||
SxrResp: string(SxrRespMarshal),
|
||||
LimitHightResp: string(LimitHightRespMarshal),
|
||||
OrderID: orderID,
|
||||
}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (l *LawsuitQueryService) CheckPayment(userid uint) (payment bool, err error) {
|
||||
var lawsuits []model.Lawsuit
|
||||
err = db.DB.Where("userid = ?", userid).Order("id desc").Limit(2).Find(&lawsuits).Error
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(lawsuits) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
checkFields := func(lawsuit model.Lawsuit) bool {
|
||||
return (lawsuit.ListResp == "" || lawsuit.ListResp == "null") &&
|
||||
(lawsuit.SxrResp == "" || lawsuit.SxrResp == "null") &&
|
||||
(lawsuit.LimitHightResp == "" || lawsuit.LimitHightResp == "null")
|
||||
}
|
||||
|
||||
if len(lawsuits) == 1 {
|
||||
if checkFields(lawsuits[0]) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(lawsuits) == 2 {
|
||||
if checkFields(lawsuits[0]) && !checkFields(lawsuits[1]) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
175
service/loanEvaluation.go
Normal file
175
service/loanEvaluation.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
const RetCodeYiDong = "000001"
|
||||
const RetCodeLianTong = "000002"
|
||||
const RetCodeDianXin = "000003"
|
||||
|
||||
type LoanEvaluationService struct {
|
||||
}
|
||||
|
||||
func (a *LoanEvaluationService) QueryLoanEvaluationOrder(orderID uint) (oanEvaluation []model.LoanEvaluation, err error) {
|
||||
err = db.DB.Where("order_id = ?", orderID).Find(&oanEvaluation).Error
|
||||
if err != nil {
|
||||
log.Printf("query oanEvaluation order failed: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (a *LoanEvaluationService) ReqYuShan(data *model.LoanEvaluationReqPayload) (plainText []byte, err error) {
|
||||
currentTime := time.Now()
|
||||
unixMilliseconds := currentTime.UnixNano() / int64(time.Millisecond)
|
||||
requestSN, _ := utils.GenerateRandomString()
|
||||
apiKey := config.ConfigData.Antifraud.ApiKey
|
||||
acctId := config.ConfigData.Antifraud.AcctId
|
||||
httpUrl := config.ConfigData.Antifraud.HttpUrl
|
||||
// 根据 ProdID 动态构建请求数据
|
||||
reqData := map[string]interface{}{
|
||||
"prod_id": data.ProdID,
|
||||
"req_time": unixMilliseconds,
|
||||
"request_sn": requestSN,
|
||||
"req_data": map[string]interface{}{},
|
||||
}
|
||||
|
||||
for _, param := range model.LoanEvaluationProdIDParams[data.ProdID] {
|
||||
switch param {
|
||||
case "cardNo":
|
||||
reqData["req_data"].(map[string]interface{})["cardNo"] = data.CardNo
|
||||
case "name":
|
||||
reqData["req_data"].(map[string]interface{})["name"] = data.Name
|
||||
case "mobile":
|
||||
reqData["req_data"].(map[string]interface{})["mobile"] = data.Mobile
|
||||
case "encryptionType":
|
||||
reqData["req_data"].(map[string]interface{})["encryptionType"] = 1
|
||||
case "idCard":
|
||||
reqData["req_data"].(map[string]interface{})["idCard"] = data.CardNo
|
||||
case "phone":
|
||||
reqData["req_data"].(map[string]interface{})["phone"] = data.Mobile
|
||||
}
|
||||
}
|
||||
messageBytes, err := json.Marshal(reqData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
key, err := hex.DecodeString(apiKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//加密
|
||||
cipherText := utils.AES_CBC_Encrypt(messageBytes, key)
|
||||
|
||||
content := base64.StdEncoding.EncodeToString(cipherText)
|
||||
respStr, err := httpDo(httpUrl, content, acctId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//解密
|
||||
sDec, err := base64.StdEncoding.DecodeString(respStr)
|
||||
if err != nil {
|
||||
if utils.IsJSON(respStr) {
|
||||
return []byte(respStr), nil
|
||||
}
|
||||
return
|
||||
}
|
||||
plainText = utils.AES_CBC_Decrypt(sDec, key)
|
||||
return
|
||||
}
|
||||
|
||||
// 对返回信息进行处理,返回一份完整的报告
|
||||
func (a *LoanEvaluationService) DataAnalysis(loanEvaluation model.LoanEvaluation) (report model.LoanEvaluationReport) {
|
||||
// 手机月消费档次
|
||||
var mobileMonthlyConsumptionLevelResp model.YuShanResponse[map[string]interface{}]
|
||||
err := json.Unmarshal([]byte(loanEvaluation.MobileMonthlyConsumptionLevelResp), &mobileMonthlyConsumptionLevelResp)
|
||||
if err != nil {
|
||||
log.Printf("mobileMonthlyConsumptionLevelResp Unmarshal error:%v", err)
|
||||
}
|
||||
|
||||
if mobileMonthlyConsumptionLevelResp.Retcode == RetCodeSuccess || mobileMonthlyConsumptionLevelResp.Retcode == RetCodeYiDong || mobileMonthlyConsumptionLevelResp.Retcode == RetCodeLianTong || mobileMonthlyConsumptionLevelResp.Retcode == RetCodeDianXin {
|
||||
report.MobileMonthlyConsumptionLevel = mobileMonthlyConsumptionLevelResp.Retdata
|
||||
} else {
|
||||
log.Printf("mobileMonthlyConsumptionLevelResp error:%s", mobileMonthlyConsumptionLevelResp.Retmsg)
|
||||
}
|
||||
|
||||
// 近六个月欠费停机次数查询
|
||||
var recentSixMonthsSuspendedTimesResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(loanEvaluation.RecentSixMonthsSuspendedTimesResp), &recentSixMonthsSuspendedTimesResp)
|
||||
if err != nil {
|
||||
log.Printf("recentSixMonthsSuspendedTimesResp Unmarshal error:%v", err)
|
||||
}
|
||||
if recentSixMonthsSuspendedTimesResp.Retcode == RetCodeSuccess || recentSixMonthsSuspendedTimesResp.Retcode == RetCodeYiDong || recentSixMonthsSuspendedTimesResp.Retcode == RetCodeLianTong || recentSixMonthsSuspendedTimesResp.Retcode == RetCodeDianXin {
|
||||
report.RecentSixMonthsSuspendedTimes = recentSixMonthsSuspendedTimesResp.Retdata
|
||||
} else {
|
||||
log.Printf("recentSixMonthsSuspendedTimesResp error:%s", recentSixMonthsSuspendedTimesResp.Retmsg)
|
||||
}
|
||||
|
||||
// 逾选指数 OverdueSelectionIndexResp
|
||||
var overdueSelectionIndexResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(loanEvaluation.OverdueSelectionIndexResp), &overdueSelectionIndexResp)
|
||||
if err != nil {
|
||||
log.Printf("overdueSelectionIndexResp Unmarshal error:%v", err)
|
||||
}
|
||||
if overdueSelectionIndexResp.Retcode == RetCodeSuccess {
|
||||
report.OverdueSelectionIndex = overdueSelectionIndexResp.Retdata
|
||||
} else {
|
||||
log.Printf("overdueSelectionIndexResp error:%s", overdueSelectionIndexResp.Retmsg)
|
||||
}
|
||||
|
||||
// 付选指数 PaymentSelectionIndexResp
|
||||
var paymentSelectionIndexResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(loanEvaluation.PaymentSelectionIndexResp), &paymentSelectionIndexResp)
|
||||
if err != nil {
|
||||
log.Printf("paymentSelectionIndexResp Unmarshal error:%v", err)
|
||||
}
|
||||
if paymentSelectionIndexResp.Retcode == RetCodeSuccess {
|
||||
report.PaymentSelectionIndex = paymentSelectionIndexResp.Retdata
|
||||
} else {
|
||||
log.Printf("paymentSelectionIndexResp error:%s", paymentSelectionIndexResp.Retmsg)
|
||||
}
|
||||
|
||||
// 贷选指数 LoanSelectionIndexResp
|
||||
var loanSelectionIndexResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(loanEvaluation.LoanSelectionIndexResp), &loanSelectionIndexResp)
|
||||
if err != nil {
|
||||
log.Printf("loanSelectionIndexResp Unmarshal error:%v", err)
|
||||
}
|
||||
if loanSelectionIndexResp.Retcode == RetCodeSuccess {
|
||||
report.LoanSelectionIndex = loanSelectionIndexResp.Retdata
|
||||
} else {
|
||||
log.Printf("loanSelectionIndexResp error:%s", loanSelectionIndexResp.Retmsg)
|
||||
}
|
||||
|
||||
// 借选指数 BorrowSelectionIndexResp
|
||||
var borrowSelectionIndexResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(loanEvaluation.BorrowSelectionIndexResp), &borrowSelectionIndexResp)
|
||||
if err != nil {
|
||||
log.Printf("borrowSelectionIndexResp Unmarshal error:%v", err)
|
||||
}
|
||||
if borrowSelectionIndexResp.Retcode == RetCodeSuccess {
|
||||
report.BorrowSelectionIndex = borrowSelectionIndexResp.Retdata
|
||||
} else {
|
||||
log.Printf("borrowSelectionIndexResp error:%s", borrowSelectionIndexResp.Retmsg)
|
||||
}
|
||||
|
||||
// 金融黑名单 FinancialBlacklistResp
|
||||
var financialBlacklistResp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(loanEvaluation.FinancialBlacklistResp), &financialBlacklistResp)
|
||||
if err != nil {
|
||||
log.Printf("financialBlacklistResp Unmarshal error:%v", err)
|
||||
}
|
||||
if financialBlacklistResp.Retcode == RetCodeSuccess {
|
||||
report.FinancialBlacklist = financialBlacklistResp.Retdata
|
||||
} else {
|
||||
log.Printf("financialBlacklistResp error:%s", financialBlacklistResp.Retmsg)
|
||||
}
|
||||
return report
|
||||
}
|
||||
127
service/notify.go
Normal file
127
service/notify.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"qnc-server/config"
|
||||
"qnc-server/utils"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// const webhookURL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=3b71e94f-8ca6-459b-b678-1db890e8170f"
|
||||
type Notify struct {
|
||||
}
|
||||
type MarkdownMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Markdown Markdown `json:"markdown"`
|
||||
}
|
||||
|
||||
type Markdown struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
func (n *Notify) SendNotification(message string, interfa string, userID uint, orderID uint) {
|
||||
enID, err := utils.IDEncrypt(strconv.Itoa(int(orderID)), "njbh287yfbuyh18suygbhd98")
|
||||
if err != nil {
|
||||
log.Println("IDEncrypt error:", err)
|
||||
return
|
||||
}
|
||||
url := fmt.Sprintf("%s/api/pay/refund_details/%s", config.ConfigData.Server.Domain, enID)
|
||||
currentTime := time.Now().Format("2006年1月2日 15:04:05")
|
||||
content := fmt.Sprintf(
|
||||
`<font color="warning">【全能查】</font>%s。
|
||||
>接口:<font color="comment">%s</font>
|
||||
>用户ID:<font color="comment">%d</font>
|
||||
>订单ID:<font color="comment">%d</font>
|
||||
>时间:<font color="comment">%s</font>
|
||||
[点击跳转到退款页面](%s)`,
|
||||
message, interfa, userID, orderID, currentTime, url,
|
||||
)
|
||||
|
||||
var webhookURL = fmt.Sprintf("%s?key=%s", config.ConfigData.Robot.Addr, config.ConfigData.Robot.Webhook)
|
||||
|
||||
markdownMessage := MarkdownMessage{
|
||||
MsgType: "markdown",
|
||||
Markdown: Markdown{
|
||||
Content: content,
|
||||
},
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(markdownMessage)
|
||||
if err != nil {
|
||||
log.Printf("机器人通知 Marshal 错误:%s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
log.Printf("机器人通知 NewRequest 错误:%s", err.Error())
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("机器人通知 请求 错误:%s", err.Error())
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Printf("机器人通知 响应 错误:%s", resp.Status)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notify) SendComplaintNotification(message string, complaintType string, platform string, complaintID string) {
|
||||
currentTime := time.Now().Format("2006年1月2日 15:04:05")
|
||||
content := fmt.Sprintf(
|
||||
`<font color="warning">【全能查】</font>用户投诉
|
||||
>投诉单号:<font color="comment">%s</font>
|
||||
>投诉状态:<font color="comment">%s</font>
|
||||
>投诉内容:<font color="comment">%s</font>
|
||||
>投诉商户号平台:<font color="comment">%s</font>
|
||||
>时间:<font color="comment">%s</font>`,
|
||||
complaintID, complaintType, message, platform, currentTime,
|
||||
)
|
||||
|
||||
var webhookURL = fmt.Sprintf("%s?key=%s", config.ConfigData.Robot.Addr, config.ConfigData.Robot.Webhook)
|
||||
|
||||
markdownMessage := MarkdownMessage{
|
||||
MsgType: "markdown",
|
||||
Markdown: Markdown{
|
||||
Content: content,
|
||||
},
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(markdownMessage)
|
||||
if err != nil {
|
||||
log.Printf("机器人通知 Marshal 错误:%s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
log.Printf("机器人通知 NewRequest 错误:%s", err.Error())
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("机器人通知 请求 错误:%s", err.Error())
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Printf("机器人通知 响应 错误:%s", resp.Status)
|
||||
return
|
||||
}
|
||||
}
|
||||
236
service/order.go
Normal file
236
service/order.go
Normal file
@@ -0,0 +1,236 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/smartwalle/alipay/v3"
|
||||
wxcore "github.com/wechatpay-apiv3/wechatpay-go/core"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/h5"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
||||
"log"
|
||||
"net/http"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/global"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/utils"
|
||||
)
|
||||
|
||||
type OrderService struct {
|
||||
}
|
||||
|
||||
func (a *OrderService) QueryConsumedOrder(userid uint, productEn string) (payOrder model.PayOrder, err error) {
|
||||
err = db.DB.Joins("JOIN product ON product.id = pay_order.product_id").Where("pay_order.userid = ? AND pay_order.pay_status = ? AND pay_order.has_consumed = ? AND product.product_en = ?", userid, model.PayStatusSuccess, model.NotConsumed, productEn).First(&payOrder).Error
|
||||
return
|
||||
}
|
||||
|
||||
// 付款消费
|
||||
func (a *OrderService) OrderConsumed(payOrder model.PayOrder) {
|
||||
payOrder.HasConsumed = 1
|
||||
err := db.DB.Save(&payOrder).Error
|
||||
if err != nil {
|
||||
log.Printf("消费订单失败:%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 失效并退款
|
||||
func (a *OrderService) OrderFailure(payOrder model.PayOrder) {
|
||||
payOrder.HasConsumed = 2
|
||||
err := db.DB.Save(&payOrder).Error
|
||||
if err != nil {
|
||||
log.Printf("失效订单失败:%v", err)
|
||||
}
|
||||
}
|
||||
func (a *OrderService) GetList(pageSize int, pageNum int, userId uint) (list []model.PayOrder, err error) {
|
||||
offset := (pageNum - 1) * pageSize
|
||||
result := db.DB.Preload("Product").Where("userid = ? AND pay_status IN ?", userId, []string{model.PayStatusSuccess, model.PayStatusRefund, model.PayStatusUnderRefund}).Order("id desc").Limit(pageSize).Offset(offset).Find(&list)
|
||||
if result.Error != nil {
|
||||
return list, result.Error
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
func (a *OrderService) GetOrderByid(id uint) (order *model.PayOrder, err error) {
|
||||
order = &model.PayOrder{}
|
||||
err = db.DB.Preload("Product").Where("id = ?", id).First(order).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 微信小程序或公众号
|
||||
func (a *OrderService) WechatJSAPIPrepay(appid string, mchID string, product model.Product, outTradeNo string, amount int64, openid string, platform string, client *wxcore.Client) (resp *jsapi.PrepayWithRequestPaymentResponse, err error) {
|
||||
prepayReq := jsapi.PrepayRequest{
|
||||
Appid: &appid,
|
||||
Mchid: &mchID,
|
||||
Description: wxcore.String(product.ProductName),
|
||||
OutTradeNo: wxcore.String(outTradeNo), // 唯一的订单号
|
||||
Attach: wxcore.String(product.Description),
|
||||
NotifyUrl: wxcore.String(fmt.Sprintf("%s/%s", config.ConfigData.WxPay.NotifyURL, platform)), // 回调地址,需替换为实际地址
|
||||
Amount: &jsapi.Amount{
|
||||
Total: wxcore.Int64(amount), // 订单金额,单位为分
|
||||
},
|
||||
Payer: &jsapi.Payer{
|
||||
Openid: wxcore.String(openid), // 用户的 OpenID,通过前端传入
|
||||
}}
|
||||
// 发起预支付请求
|
||||
svc := jsapi.JsapiApiService{Client: client}
|
||||
resp, _, err = svc.PrepayWithRequestPayment(ctx, prepayReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// 浏览器H5
|
||||
func (a *OrderService) WechatH5Prepay(appid string, mchID string, product model.Product, outTradeNo string, amount int64, userIP string, client *wxcore.Client) (resp *h5.PrepayResponse, err error) {
|
||||
prepayReq := h5.PrepayRequest{
|
||||
Appid: wxcore.String(appid),
|
||||
Mchid: wxcore.String(mchID),
|
||||
Description: wxcore.String(product.ProductName),
|
||||
OutTradeNo: wxcore.String(outTradeNo), // 唯一的订单号
|
||||
Attach: wxcore.String(product.Description),
|
||||
NotifyUrl: wxcore.String(config.ConfigData.WxPay.NotifyURL), // 回调地址,需替换为实际地址
|
||||
Amount: &h5.Amount{
|
||||
Total: wxcore.Int64(amount), // 订单金额,单位为分
|
||||
},
|
||||
SceneInfo: &h5.SceneInfo{
|
||||
PayerClientIp: wxcore.String(userIP), // 可通过前端传入
|
||||
H5Info: &h5.H5Info{
|
||||
Type: wxcore.String("Wap"),
|
||||
//AppName: wxcore.String("全能查"),
|
||||
//AppUrl: wxcore.String("https://你的域名"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 发起预支付请求
|
||||
svc := h5.H5ApiService{Client: client}
|
||||
resp, _, err = svc.Prepay(context.Background(), prepayReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
func (a *OrderService) WeChatRefund(order model.PayOrder) (err error) {
|
||||
var client *wxcore.Client
|
||||
switch order.Platform {
|
||||
case model.PlatformMPWEIXIN:
|
||||
client = global.GlobalData.PayClient
|
||||
case model.PlatformMPH5:
|
||||
client = global.GlobalData.PayH5Client
|
||||
}
|
||||
outRefundNo := utils.GenerateOrderRefundNumber()
|
||||
svc := refunddomestic.RefundsApiService{Client: client}
|
||||
resp, result, err := svc.Create(ctx,
|
||||
refunddomestic.CreateRequest{
|
||||
OutTradeNo: wxcore.String(order.OutTradeNo),
|
||||
OutRefundNo: wxcore.String(outRefundNo), //退款单号
|
||||
NotifyUrl: wxcore.String(fmt.Sprintf("%s/%s", config.ConfigData.WxPay.RefundNotifyURL, order.Platform)),
|
||||
Amount: &refunddomestic.AmountReq{
|
||||
Currency: wxcore.String("CNY"),
|
||||
Refund: wxcore.Int64(order.Amount),
|
||||
Total: wxcore.Int64(order.Amount),
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
// 处理错误
|
||||
log.Printf("微信订单申请退款错误:%s", err)
|
||||
return errors.New(fmt.Sprintf("微信订单申请退款错误:%s", err))
|
||||
} else {
|
||||
// 处理返回结果
|
||||
log.Printf("微信订单申请退款 response status=%d resp=%s", result.Response.StatusCode, resp)
|
||||
order.PayStatus = model.PayStatusUnderRefund
|
||||
err = db.DB.Save(order).Error
|
||||
if err != nil {
|
||||
log.Printf("微信订单退状态修改失败 underRefund Error:%v", err)
|
||||
return errors.New(fmt.Sprintf("微信订单退状态修改失败 underRefund Error:%v", err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// 创建投诉回调URL
|
||||
func (a *OrderService) RegisterComplaintNotificationURL(client *wxcore.Client, platform string) {
|
||||
url := "https://api.mch.weixin.qq.com/v3/merchant-service/complaint-notifications"
|
||||
|
||||
// 请求体数据
|
||||
requestBody := map[string]string{
|
||||
"url": fmt.Sprintf("%s/%s/pay/complaint_callback/%s", config.ConfigData.Server.Domain, config.ConfigData.Server.Prefix, platform), // 你的回调URL
|
||||
}
|
||||
|
||||
// 将请求体序列化为 JSON
|
||||
requestBodyJson, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
log.Fatalf("【%s创建投诉回调URL】请求体JSON序列化失败: %v", platform, err)
|
||||
}
|
||||
|
||||
// 发送POST请求
|
||||
result, err := client.Post(context.Background(), url, requestBodyJson)
|
||||
if err != nil {
|
||||
// 尝试解析响应内容,获取详细错误信息
|
||||
var response map[string]interface{}
|
||||
if err := json.NewDecoder(result.Response.Body).Decode(&response); err != nil {
|
||||
log.Fatalf("【%s创建投诉回调URL】解析错误响应失败: %v", platform, err)
|
||||
}
|
||||
// 检查错误代码和信息
|
||||
if responseCode, ok := response["code"].(string); ok && responseCode == "PARAM_ERROR" {
|
||||
if responseMessage, ok := response["message"].(string); ok && responseMessage == "数据已存在" {
|
||||
log.Printf("【%s创建投诉回调URL】数据已存在,不需要重新创建: %+v\n", platform, response)
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Fatalf("【%s创建投诉回调URL】请求失败: %v", platform, err)
|
||||
}
|
||||
|
||||
// 处理响应
|
||||
defer result.Response.Body.Close()
|
||||
|
||||
// 检查请求状态
|
||||
if result.Response.StatusCode != http.StatusOK {
|
||||
log.Fatalf("【%s创建投诉回调URL】请求失败,状态码: %v", platform, result.Response.StatusCode)
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var response map[string]interface{}
|
||||
if err := json.NewDecoder(result.Response.Body).Decode(&response); err != nil {
|
||||
log.Fatalf("【%s创建投诉回调URL】解析响应失败: %v", platform, err)
|
||||
}
|
||||
|
||||
log.Printf("【%s创建投诉回调URL】投诉通知回调URL创建成功: %+v\n", platform, response)
|
||||
return
|
||||
}
|
||||
|
||||
func (a *OrderService) AliRefund(ctx context.Context, payOrder model.PayOrder) error {
|
||||
// 创建退款请求参数
|
||||
refund := alipay.TradeRefund{}
|
||||
refund.OutTradeNo = payOrder.OutTradeNo
|
||||
refund.RefundAmount = utils.ConvertCentsToYuan(int(payOrder.Amount)) // 退款金额,单位元
|
||||
refund.OutRequestNo = fmt.Sprintf("ali_refund_%s", utils.GenerateOrderNumber()) // 生成的唯一退款请求号
|
||||
|
||||
// 发起退款请求
|
||||
refundResp, err := global.GlobalData.AliPayClient.TradeRefund(ctx, refund)
|
||||
if err != nil {
|
||||
log.Printf("【阿里支付退款】退款请求错误:%v", err)
|
||||
return fmt.Errorf("refund request failed")
|
||||
}
|
||||
|
||||
if refundResp.IsSuccess() {
|
||||
// 更新订单状态
|
||||
err = db.DB.Model(&model.PayOrder{}).Where("out_trade_no = ?", payOrder.OutTradeNo).Updates(model.PayOrder{
|
||||
PayStatus: model.PayStatusRefund,
|
||||
}).Error
|
||||
if err != nil {
|
||||
log.Printf("【阿里支付退款】订单更新错误:%v", err)
|
||||
return fmt.Errorf("order update failed")
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
log.Printf("【阿里支付退款】退款失败:%v", refundResp.SubMsg)
|
||||
return fmt.Errorf("refund failed: %s", refundResp.SubMsg)
|
||||
}
|
||||
}
|
||||
17
service/product.go
Normal file
17
service/product.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"log"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
)
|
||||
|
||||
type ProductService struct{}
|
||||
|
||||
func (p *ProductService) GetProduct(productName string) (product model.Product, err error) {
|
||||
err = db.DB.Where("BINARY product_en = ?", productName).First(&product).Error
|
||||
if err != nil {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
35
service/render.go
Normal file
35
service/render.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
)
|
||||
|
||||
type RenderService struct {
|
||||
}
|
||||
|
||||
func (r *RenderService) GetIndex() (renderList []model.Render, err error) {
|
||||
err = db.DB.Find(&renderList).Error
|
||||
return
|
||||
}
|
||||
func (r *RenderService) GetCarIndex() (renderList []model.CarRender, err error) {
|
||||
err = db.DB.Find(&renderList).Error
|
||||
return
|
||||
}
|
||||
func (r *RenderService) GetVerifyIndex() (renderList []model.VerifyRender, err error) {
|
||||
err = db.DB.Find(&renderList).Error
|
||||
return
|
||||
}
|
||||
func (r *RenderService) GetNotificationList() (Notification []model.GlobalNotification, err error) {
|
||||
if err := db.DB.Find(&Notification).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
func (r *RenderService) GetShadow() (shadow model.RenderShadow, err error) {
|
||||
err = db.DB.First(&shadow).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
227
service/request.go
Normal file
227
service/request.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"qnc-server/config"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/model/response"
|
||||
"qnc-server/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RequestService struct {
|
||||
}
|
||||
|
||||
func (r *RequestService) AliYunRequest(method string, urlStr string, params map[string]string, body map[string]any) (data string, err error) {
|
||||
appCode := config.ConfigData.LawsuitQuery.AppCode
|
||||
// 创建查询参数
|
||||
// 构造 URL 参数
|
||||
if method == http.MethodGet && len(params) > 0 {
|
||||
queryParams := url.Values{}
|
||||
for key, value := range params {
|
||||
queryParams.Add(key, value)
|
||||
}
|
||||
urlStr = fmt.Sprintf("%s?%s", urlStr, queryParams.Encode())
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(string(method), urlStr, nil)
|
||||
if err != nil {
|
||||
log.Printf("【阿里云市场请求】创建请求失败 err:%v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Authorization", "APPCODE "+appCode)
|
||||
|
||||
if method == http.MethodPost && body != nil {
|
||||
formData := url.Values{}
|
||||
for key, value := range body {
|
||||
formData.Set(key, fmt.Sprintf("%v", value))
|
||||
}
|
||||
req.Body = io.NopCloser(strings.NewReader(formData.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("【阿里云市场请求】请求失败,\nURL:%s \nerr:%v", req.URL, err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
// 检查响应状态码
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Printf("请求失败,状态码: %d", resp.StatusCode)
|
||||
return "", fmt.Errorf("【阿里云市场请求】请求失败,\nURL:%s \n状态码: %d", req.URL, resp.StatusCode)
|
||||
}
|
||||
|
||||
// 读取响应体
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("【阿里云市场请求】响应体读取失败,\nURL:%s \n响应:%s \nerr:%v", req.URL, resp.Body, err)
|
||||
return
|
||||
}
|
||||
return string(respBody), nil
|
||||
}
|
||||
|
||||
// 羽山请求
|
||||
func (r *RequestService) YuShanRequest(prodID string, reqData map[string]interface{}) (plainText []byte, err error) {
|
||||
currentTime := time.Now()
|
||||
unixMilliseconds := currentTime.UnixNano() / int64(time.Millisecond)
|
||||
requestSN, _ := utils.GenerateRandomString()
|
||||
apiKey := config.ConfigData.Antifraud.ApiKey
|
||||
acctId := config.ConfigData.Antifraud.AcctId
|
||||
httpUrl := config.ConfigData.Antifraud.HttpUrl
|
||||
// 根据 ProdID 动态构建请求数据
|
||||
reqBody := map[string]interface{}{
|
||||
"prod_id": prodID,
|
||||
"req_time": unixMilliseconds,
|
||||
"request_sn": requestSN,
|
||||
"req_data": reqData,
|
||||
}
|
||||
|
||||
messageBytes, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
key, err := hex.DecodeString(apiKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//加密
|
||||
cipherText := utils.AES_CBC_Encrypt(messageBytes, key)
|
||||
|
||||
content := base64.StdEncoding.EncodeToString(cipherText)
|
||||
respStr, err := httpDo(httpUrl, content, acctId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//解密
|
||||
sDec, err := base64.StdEncoding.DecodeString(respStr)
|
||||
if err != nil {
|
||||
if utils.IsJSON(respStr) {
|
||||
return []byte(respStr), nil
|
||||
}
|
||||
return
|
||||
}
|
||||
plainText = utils.AES_CBC_Decrypt(sDec, key)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析羽山响应数据
|
||||
func (r *RequestService) AnalysisDataYuShan(respByte []byte) (data []map[string]interface{}, err error) {
|
||||
var resp model.YuShanResponse[[]map[string]interface{}]
|
||||
err = json.Unmarshal(respByte, &resp)
|
||||
if err != nil {
|
||||
return nil, utils.ErrSystemError
|
||||
}
|
||||
if resp.Retcode == RetCodeSuccess {
|
||||
data = resp.Retdata
|
||||
return data, nil
|
||||
} else if resp.Retcode == RetCodeEmpty {
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
return data, errors.New(resp.Retmsg)
|
||||
}
|
||||
}
|
||||
|
||||
// 三要素解析
|
||||
func (r *RequestService) ThreeElementsParse(threeElementsResp string) (resp response.ThreeElementsResp, err error) {
|
||||
err = json.Unmarshal([]byte(threeElementsResp), &resp)
|
||||
if err != nil {
|
||||
log.Printf("【三要素响应解析】解析错误 err:%v", err)
|
||||
return
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// westdex 西部数据API请求
|
||||
func (r *RequestService) WestDexRequest(code string, reqData map[string]interface{}) (respStr string, err error) {
|
||||
// 生成当前的13位时间戳
|
||||
timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
|
||||
|
||||
// 构造请求URL
|
||||
secretId := "449159"
|
||||
reqUrl := fmt.Sprintf("https://apimaster.westdex.com.cn/api/invoke/%s/%s?timestamp=%s", secretId, code, timestamp)
|
||||
|
||||
// 将请求参数编码为JSON格式
|
||||
data := map[string]interface{}{
|
||||
"data": reqData,
|
||||
}
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
log.Printf("【西部数据请求】JSON编码错误: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建HTTP POST请求
|
||||
req, err := http.NewRequest("POST", reqUrl, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
log.Printf("【西部数据请求】创建请求错误: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("【西部数据请求】发送请求错误: %v", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 检查请求是否成功
|
||||
if resp.StatusCode == 200 {
|
||||
// 读取响应体
|
||||
bodyBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Printf("【西部数据请求】读取响应体错误: %v", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 手动调用 json.Unmarshal 触发自定义的 UnmarshalJSON 方法
|
||||
var westDexResp response.WestdexResp
|
||||
err = json.Unmarshal(bodyBytes, &westDexResp)
|
||||
if err != nil {
|
||||
log.Printf("【西部数据请求】JSON反序列化错误: %v", err)
|
||||
return "", err
|
||||
}
|
||||
key := "121a1e41fc1690dd6b90afbcacd80cf4" // 你的AES密钥
|
||||
|
||||
if westDexResp.Code != "00000" {
|
||||
//decryptedData, err := utils.WestDexDecrypt(westDexResp.Data, key)
|
||||
if err != nil {
|
||||
log.Printf("【西部数据请求】响应数据解密错误: %v", err)
|
||||
return "", err
|
||||
}
|
||||
log.Printf("【西部数据请求】响应数据业务失败:%v", westDexResp.Message)
|
||||
return "", errors.New("业务失败")
|
||||
}
|
||||
// 解密响应数据
|
||||
decryptedData, err := utils.WestDexDecrypt(westDexResp.Data, key)
|
||||
if err != nil {
|
||||
log.Printf("【西部数据请求】响应数据解密错误: %v", err)
|
||||
return "", err
|
||||
}
|
||||
// 输出解密后的数据
|
||||
log.Printf("【西部数据请求】解密后的响应数据: %s", decryptedData)
|
||||
return decryptedData, nil
|
||||
}
|
||||
log.Printf("【西部数据请求】请求失败,状态码: %s", resp.Status)
|
||||
return
|
||||
}
|
||||
139
service/singleQuery.go
Normal file
139
service/singleQuery.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SingleQueryService struct {
|
||||
}
|
||||
|
||||
func (s *SingleQueryService) EvaluateMarriageReqYuShan(data *model.EvaluateMarriagePayload) (plainText []byte, err error) {
|
||||
currentTime := time.Now()
|
||||
unixMilliseconds := currentTime.UnixNano() / int64(time.Millisecond)
|
||||
requestSN, _ := utils.GenerateRandomString()
|
||||
apiKey := config.ConfigData.Antifraud.ApiKey
|
||||
acctId := config.ConfigData.Antifraud.AcctId
|
||||
httpUrl := config.ConfigData.Antifraud.HttpUrl
|
||||
// 根据 ProdID 动态构建请求数据
|
||||
reqData := map[string]interface{}{
|
||||
"prod_id": data.ProdID,
|
||||
"req_time": unixMilliseconds,
|
||||
"request_sn": requestSN,
|
||||
"req_data": map[string]interface{}{},
|
||||
}
|
||||
|
||||
for _, param := range model.SingleQueryProdIDParams[data.ProdID] {
|
||||
switch param {
|
||||
case "cardNo":
|
||||
reqData["req_data"].(map[string]interface{})["cardNo"] = data.CardNo
|
||||
case "name":
|
||||
reqData["req_data"].(map[string]interface{})["name"] = data.Name
|
||||
case "pageNo":
|
||||
reqData["req_data"].(map[string]interface{})["pageNo"] = 1
|
||||
case "pageSize":
|
||||
reqData["req_data"].(map[string]interface{})["pageSize"] = 100
|
||||
}
|
||||
}
|
||||
messageBytes, err := json.Marshal(reqData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
key, err := hex.DecodeString(apiKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//加密
|
||||
cipherText := utils.AES_CBC_Encrypt(messageBytes, key)
|
||||
|
||||
content := base64.StdEncoding.EncodeToString(cipherText)
|
||||
respStr, err := httpDo(httpUrl, content, acctId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//解密
|
||||
sDec, err := base64.StdEncoding.DecodeString(respStr)
|
||||
if err != nil {
|
||||
if utils.IsJSON(respStr) {
|
||||
return []byte(respStr), nil
|
||||
}
|
||||
return
|
||||
}
|
||||
plainText = utils.AES_CBC_Decrypt(sDec, key)
|
||||
return
|
||||
}
|
||||
|
||||
// 对返回信息进行处理,返回一份完整的报告
|
||||
func (a *SingleQueryService) DataAnalysis(respString string) (data map[string]interface{}, err error) {
|
||||
var resp model.YuShanResponse[map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(respString), &resp)
|
||||
if err != nil {
|
||||
log.Printf("singleQuery Unmarshal error:%v", err)
|
||||
return nil, utils.ErrSystemError
|
||||
}
|
||||
if resp.Retcode == RetCodeSuccess {
|
||||
data = resp.Retdata
|
||||
return data, nil
|
||||
} else if resp.Retcode == RetCodeEmpty {
|
||||
log.Printf("singleQuery resp empty:%s", resp.Retmsg)
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
log.Printf("singleQuery resp error:%s", resp.Retmsg)
|
||||
return data, utils.ErrSystemError
|
||||
}
|
||||
}
|
||||
|
||||
// 对返回信息进行处理,返回一份完整的报告
|
||||
func (a *SingleQueryService) MarryDataAnalysis(respString string) (data []map[string]interface{}, err error) {
|
||||
var resp model.YuShanResponse[[]map[string]interface{}]
|
||||
err = json.Unmarshal([]byte(respString), &resp)
|
||||
if err != nil {
|
||||
log.Printf("singleQuery Unmarshal error:%v", err)
|
||||
return nil, utils.ErrSystemError
|
||||
}
|
||||
if resp.Retcode == RetCodeSuccess {
|
||||
data = resp.Retdata
|
||||
return data, nil
|
||||
} else if resp.Retcode == RetCodeEmpty {
|
||||
log.Printf("singleQuery resp empty:%s", resp.Retmsg)
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
log.Printf("singleQuery resp error:%s", resp.Retmsg)
|
||||
return data, utils.ErrSystemError
|
||||
}
|
||||
}
|
||||
func (a *SingleQueryService) MarryAnalysis(jsonStr string) (resp *model.MerryResponse, err error) {
|
||||
err = json.Unmarshal([]byte(jsonStr), &resp)
|
||||
if err != nil {
|
||||
fmt.Printf("【婚姻结果解析错误】JSON解析错误: %v\n", err)
|
||||
return
|
||||
}
|
||||
// 根据状态码分类处理
|
||||
switch resp.Code {
|
||||
case 201, 202, 203:
|
||||
return resp, nil
|
||||
case 300:
|
||||
return nil, utils.ErrNoRecord
|
||||
default:
|
||||
return nil, errors.New(resp.Msg)
|
||||
}
|
||||
}
|
||||
func (a *SingleQueryService) QueryEvaluateMarriageOrder(orderID uint) (m model.EvaluateMarriage, err error) {
|
||||
err = db.DB.Where("order_id = ?", orderID).First(&m).Error
|
||||
return
|
||||
}
|
||||
|
||||
// 获取婚姻评估记录
|
||||
func (a *SingleQueryService) QueryEvaluateMarriageRecord(id uint) (m model.EvaluateMarriage, err error) {
|
||||
err = db.DB.Where("id = ?", id).First(&m).Error
|
||||
return
|
||||
}
|
||||
361
service/user.go
Normal file
361
service/user.go
Normal file
@@ -0,0 +1,361 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/model/response"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserService struct {
|
||||
}
|
||||
|
||||
// 全能查小程序Code获取openid Unionid
|
||||
func (UserService *UserService) RequestWx(code string) (wxResponse response.WxLoginResp, err error) {
|
||||
|
||||
// 向微信发出登录请求
|
||||
baseURL := config.ConfigData.System.WxLoginUrl
|
||||
// 创建查询参数
|
||||
params := url.Values{}
|
||||
params.Add("appid", config.ConfigData.System.WxAppId)
|
||||
params.Add("secret", config.ConfigData.System.WxSecret)
|
||||
params.Add("js_code", code)
|
||||
params.Add("grant_type", "authorization_code")
|
||||
|
||||
// 构建完整的请求 URL
|
||||
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
|
||||
|
||||
// 发送 GET 请求
|
||||
resp, err := http.Get(requestURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 将响应体解析为结构体
|
||||
err = json.Unmarshal(body, &wxResponse)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if wxResponse.ErrCode != 0 {
|
||||
err = errors.New(wxResponse.ErrMsg)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Login 全能查 公众号 获取access_token
|
||||
func (UserService *UserService) RequestWxH5(code string) (wxH5Response response.WxH5LoginResp, err error) {
|
||||
|
||||
// 向微信发出登录请求
|
||||
baseURL := config.ConfigData.System.WxH5LoginUrl
|
||||
// 创建查询参数
|
||||
params := url.Values{}
|
||||
params.Add("appid", config.ConfigData.System.WxH5AppId)
|
||||
params.Add("secret", config.ConfigData.System.WxH5Secret)
|
||||
params.Add("code", code)
|
||||
params.Add("grant_type", "authorization_code")
|
||||
|
||||
// 构建完整的请求 URL
|
||||
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
|
||||
|
||||
// 发送 GET 请求
|
||||
resp, err := http.Get(requestURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &wxH5Response)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("H5-以Code获取access_token响应:%v", wxH5Response)
|
||||
if wxH5Response.Errcode != 0 {
|
||||
err = errors.New(wxH5Response.Errmsg)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 刷新token
|
||||
// access_token 2小时过期
|
||||
// refresh_token 30天过期
|
||||
//func (UserService *UserService) RefreshToken(openid string) (err error) {
|
||||
//
|
||||
//}
|
||||
|
||||
// snsapi_userinfo授权拉取用户信息
|
||||
func (UserService *UserService) GetSnsUserInfo(accessToken string, openid string) (userinfoResp response.WeChatUserInfoResp, err error) {
|
||||
//https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
|
||||
// 向微信发出登录请求
|
||||
baseURL := config.ConfigData.System.WxH5UserinfoUrl
|
||||
// 创建查询参数
|
||||
params := url.Values{}
|
||||
params.Add("access_token", accessToken)
|
||||
params.Add("openid", openid)
|
||||
params.Add("lang", "zh_CN")
|
||||
// 构建完整的请求 URL
|
||||
requestURL := fmt.Sprintf("%s?%s", baseURL, params.Encode())
|
||||
log.Printf("请求url: %s", requestURL)
|
||||
// 发送 GET 请求
|
||||
resp, err := http.Get(requestURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &userinfoResp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("H5-snsapi_userinfo授权拉取用户信息响应:%v", userinfoResp)
|
||||
if userinfoResp.Errcode != 0 {
|
||||
err = errors.New(userinfoResp.Errmsg)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 刷新token
|
||||
// access_token 2小时过期
|
||||
// refresh_token 30天过期
|
||||
//func (UserService *UserService) RefreshToken(openid string) (err error) {
|
||||
//
|
||||
//}
|
||||
|
||||
// 注册用户,创建
|
||||
func (UserService *UserService) Register(user model.User, authType model.AuthType, authIdentifier model.AuthIdentifier) (auth model.Authentication, err error) {
|
||||
err = db.DB.Create(&user).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
auth = model.Authentication{
|
||||
UserID: user.ID,
|
||||
AuthType: authType,
|
||||
OpenID: authIdentifier.OpenID,
|
||||
UnionID: authIdentifier.UnionID,
|
||||
Phone: authIdentifier.Phone,
|
||||
}
|
||||
err = db.DB.Create(&auth).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MatchingAuthentications配对是否有相交的校验
|
||||
func (UserService *UserService) MatchingAuthentications(authIdentifier model.AuthIdentifier) (authentications []model.Authentication, err error) {
|
||||
query := db.DB
|
||||
if authIdentifier.OpenID != "" {
|
||||
query = query.Or("open_id = ?", authIdentifier.OpenID)
|
||||
}
|
||||
if authIdentifier.UnionID != "" {
|
||||
query = query.Or("union_id = ?", authIdentifier.UnionID)
|
||||
}
|
||||
if authIdentifier.Phone != "" {
|
||||
query = query.Or("phone = ?", authIdentifier.Phone)
|
||||
}
|
||||
err = query.Find(&authentications).Error
|
||||
return
|
||||
}
|
||||
|
||||
// CreateAuthentications 创建校验
|
||||
func (UserService *UserService) CreateAuthentications(userid uint, authIdentifier model.AuthIdentifier, AuthType model.AuthType) (authentications model.Authentication, err error) {
|
||||
authentications = model.Authentication{
|
||||
UserID: userid,
|
||||
AuthType: AuthType,
|
||||
OpenID: authIdentifier.OpenID,
|
||||
UnionID: authIdentifier.UnionID,
|
||||
Phone: authIdentifier.Phone,
|
||||
}
|
||||
err = db.DB.Create(&authentications).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetUser 根据openid获取全能查用户记录
|
||||
func (UserService *UserService) GetUser(id uint) (user *model.User, err error) {
|
||||
err = db.DB.Where("id = ?", id).First(&user).Error
|
||||
return
|
||||
}
|
||||
|
||||
// GetUser 根据h5_openid获取全能查用户记录
|
||||
func (UserService *UserService) GetUserByH5(h5Openid string) (user *model.User, err error) {
|
||||
err = db.DB.Where("h5_openid = ?", h5Openid).First(&user).Error
|
||||
return
|
||||
}
|
||||
|
||||
// GetUser 根据unionid获取全能查用户记录
|
||||
func (UserService *UserService) GetUserByUnionid(unionid string) (user *model.User, err error) {
|
||||
err = db.DB.Where("unionid = ?", unionid).First(&user).Error
|
||||
return
|
||||
}
|
||||
|
||||
// GetUser 根据userid获取全能查用户记录
|
||||
func (UserService *UserService) GetUserByUserid(userid uint) (user *model.User, err error) {
|
||||
err = db.DB.Where("userid = ?", userid).First(&user).Error
|
||||
return
|
||||
}
|
||||
|
||||
// CreateUser 创建全能查用户
|
||||
func (UserService *UserService) CreateUser(user *model.User) (err error) {
|
||||
err = db.DB.Create(&user).Error
|
||||
return err
|
||||
}
|
||||
|
||||
// update 按unionid更新用户信息
|
||||
func (UserService *UserService) UpdateUser(user *model.User) (err error) {
|
||||
err = db.DB.Save(user).Error
|
||||
return err
|
||||
}
|
||||
|
||||
// h5 SDK 获取config部分
|
||||
var (
|
||||
mutex sync.Mutex
|
||||
)
|
||||
var ctx = context.Background()
|
||||
|
||||
// GetJsapiTicket 获取JSAPI Ticket
|
||||
func (UserService *UserService) GetJsapiTicket() (string, error) {
|
||||
|
||||
jsapiTicket, err := db.RedisClient.Get(ctx, "JsapiTicket").Result()
|
||||
if err != nil && !errors.Is(err, redis.Nil) {
|
||||
return "", err
|
||||
}
|
||||
if jsapiTicket != "" {
|
||||
return jsapiTicket, nil
|
||||
}
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
accessToken, err := UserService.getAccessToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ticket, err := UserService.fetchJsapiTicket(accessToken)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
log.Printf("获取到新的JsapiTicket:%s", ticket)
|
||||
jsapiTicket = ticket
|
||||
|
||||
err = db.RedisClient.Set(ctx, "JsapiTicket", jsapiTicket, 7200*time.Second).Err()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return jsapiTicket, nil
|
||||
}
|
||||
|
||||
func (UserService *UserService) getAccessToken() (string, error) {
|
||||
reqUrl := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", config.ConfigData.System.WxH5AppId, config.ConfigData.System.WxH5Secret)
|
||||
resp, err := http.Get(reqUrl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Errcode int `json:"errcode"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
}
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if result.Errcode != 0 {
|
||||
log.Printf("获取AccessToken错误:%s", result.Errmsg)
|
||||
return "", errors.New(result.Errmsg)
|
||||
}
|
||||
return result.AccessToken, nil
|
||||
}
|
||||
|
||||
func (UserService *UserService) fetchJsapiTicket(accessToken string) (string, error) {
|
||||
reqUrl := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", accessToken)
|
||||
resp, err := http.Get(reqUrl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result struct {
|
||||
Ticket string `json:"ticket"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Errcode int `json:"errcode"`
|
||||
Errmsg string `json:"errmsg"`
|
||||
}
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if result.Errcode != 0 {
|
||||
log.Printf("获取JsapiTicket错误:%s", result.Errmsg)
|
||||
return "", errors.New(result.Errmsg)
|
||||
}
|
||||
return result.Ticket, nil
|
||||
}
|
||||
|
||||
// CreateSignature 创建签名
|
||||
func (UserService *UserService) CreateSignature(ticket, nonceStr, timestamp, url string) string {
|
||||
// 将参数按 key=value 格式拼接
|
||||
params := map[string]string{
|
||||
"jsapi_ticket": ticket,
|
||||
"noncestr": nonceStr,
|
||||
"timestamp": timestamp,
|
||||
"url": url,
|
||||
}
|
||||
// 按照 key 的字典序排序
|
||||
keys := make([]string, 0, len(params))
|
||||
for key := range params {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// 拼接成一个字符串
|
||||
str := ""
|
||||
for _, key := range keys {
|
||||
if str != "" {
|
||||
str += "&"
|
||||
}
|
||||
str += fmt.Sprintf("%s=%s", key, params[key])
|
||||
}
|
||||
// 对字符串进行 SHA1 加密
|
||||
h := sha1.New()
|
||||
h.Write([]byte(str))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
177
service/verify.go
Normal file
177
service/verify.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"qnc-server/config"
|
||||
"qnc-server/db"
|
||||
"qnc-server/model/model"
|
||||
"qnc-server/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
type VerifyService struct {
|
||||
}
|
||||
|
||||
func (c *VerifyService) VerifReqYuShan(prodID string, data *map[string]interface{}) (plainText []byte, err error) {
|
||||
currentTime := time.Now()
|
||||
unixMilliseconds := currentTime.UnixNano() / int64(time.Millisecond)
|
||||
requestSN, _ := utils.GenerateRandomString()
|
||||
apiKey := config.ConfigData.YuShan.ApiKey
|
||||
acctId := config.ConfigData.YuShan.AcctId
|
||||
httpUrl := config.ConfigData.YuShan.HttpUrl
|
||||
// 根据 ProdID 动态构建请求数据
|
||||
reqData := map[string]interface{}{
|
||||
"prod_id": prodID,
|
||||
"req_time": unixMilliseconds,
|
||||
"request_sn": requestSN,
|
||||
"req_data": data,
|
||||
}
|
||||
|
||||
messageBytes, err := json.Marshal(reqData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
key, err := hex.DecodeString(apiKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//加密
|
||||
cipherText := utils.AES_CBC_Encrypt(messageBytes, key)
|
||||
|
||||
content := base64.StdEncoding.EncodeToString(cipherText)
|
||||
respStr, err := httpDo(httpUrl, content, acctId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
//解密
|
||||
sDec, err := base64.StdEncoding.DecodeString(respStr)
|
||||
if err != nil {
|
||||
if utils.IsJSON(respStr) {
|
||||
return []byte(respStr), nil
|
||||
}
|
||||
return
|
||||
}
|
||||
plainText = utils.AES_CBC_Decrypt(sDec, key)
|
||||
return
|
||||
}
|
||||
|
||||
// 对返回信息进行处理,返回一份完整的报告
|
||||
func (c *VerifyService) VerifyDataAnalysis(respString string) (data model.YuShanResponse[map[string]interface{}], err error) {
|
||||
err = json.Unmarshal([]byte(respString), &data)
|
||||
if err != nil {
|
||||
log.Printf("VerifInsurance Unmarshal error:%v", err)
|
||||
return data, utils.ErrUnmashal
|
||||
}
|
||||
if data.Retcode == RetCodeSuccess {
|
||||
return data, nil
|
||||
} else if data.Retcode == RetCodeEmpty {
|
||||
log.Printf("Verif resp empty:%s", data.Retmsg)
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
log.Printf("Verif resp error:%s", data.Retmsg)
|
||||
return data, utils.ErrSystemError
|
||||
}
|
||||
}
|
||||
func (c *VerifyService) VerifyCertDataAnalysis(respString string) (data model.YuShanResponse[[]map[string]interface{}], err error) {
|
||||
err = json.Unmarshal([]byte(respString), &data)
|
||||
if err != nil {
|
||||
log.Printf("VerifInsurance Unmarshal error:%v", err)
|
||||
return data, utils.ErrUnmashal
|
||||
}
|
||||
if data.Retcode == RetCodeSuccess {
|
||||
return data, nil
|
||||
} else if data.Retcode == RetCodeEmpty {
|
||||
log.Printf("Verif resp empty:%s", data.Retmsg)
|
||||
return data, utils.ErrNoRecord
|
||||
} else {
|
||||
log.Printf("Verif resp error:%s", data.Retmsg)
|
||||
return data, utils.ErrSystemError
|
||||
}
|
||||
}
|
||||
|
||||
func (c *VerifyService) GetRecordByFeature(feature string, id uint, userID uint) (interface{}, error) {
|
||||
var result interface{}
|
||||
switch feature {
|
||||
case "shoujiheyan":
|
||||
var record model.VerifyPhoneName
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = record.Resp
|
||||
case "shenfenzhengheyan":
|
||||
var record model.VerifyCardName
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = record.Resp
|
||||
|
||||
case "yinhangkaheimingdan":
|
||||
var record model.VerifyBankCard
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.VerifyDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis.Retdata
|
||||
case "jinengzigezhengshu":
|
||||
var record model.VerifySkillCert
|
||||
if err := db.DB.Where("order_id = ? AND userid = ?", id, userID).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.VerifyCertDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis.Retdata
|
||||
default:
|
||||
return nil, errors.New("Invalid feature")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *VerifyService) GetRecordCaseByFeature(feature string) (interface{}, error) {
|
||||
var result interface{}
|
||||
switch feature {
|
||||
case "shoujiheyan":
|
||||
var record model.VerifyPhoneName
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = record.Resp
|
||||
case "shenfenzhengheyan":
|
||||
var record model.VerifyCardName
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = record.Resp
|
||||
case "yinhangkaheimingdan":
|
||||
var record model.VerifyBankCard
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.VerifyDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis.Retdata
|
||||
case "jinengzigezhengshu":
|
||||
var record model.VerifySkillCert
|
||||
if err := db.DB.Where("id = ?", 1).First(&record).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysis, err := c.VerifyCertDataAnalysis(record.Resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = analysis.Retdata
|
||||
default:
|
||||
return nil, errors.New("Invalid feature")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
85
service/verifyCode.go
Normal file
85
service/verifyCode.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
dysmsapi "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
|
||||
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
config "qnc-server/config"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type VerifyCode struct {
|
||||
}
|
||||
|
||||
func (v *VerifyCode) CreateClient() (result *dysmsapi.Client, err error) {
|
||||
clientConfig := &openapi.Config{
|
||||
AccessKeyId: &config.ConfigData.VerifyCode.AccessKeyID,
|
||||
AccessKeySecret: &config.ConfigData.VerifyCode.AccessKeySecret,
|
||||
}
|
||||
clientConfig.Endpoint = tea.String(config.ConfigData.VerifyCode.EndpointURL)
|
||||
result, err = dysmsapi.NewClient(clientConfig)
|
||||
return
|
||||
}
|
||||
|
||||
func (v *VerifyCode) Send(code string, phoneNumber string, templateCode string) (err error) {
|
||||
client, err := v.CreateClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sendSmsRequest := &dysmsapi.SendSmsRequest{
|
||||
SignName: tea.String(config.ConfigData.VerifyCode.SignName),
|
||||
TemplateCode: tea.String(templateCode),
|
||||
PhoneNumbers: tea.String(phoneNumber),
|
||||
TemplateParam: tea.String(fmt.Sprintf("{code:\"%s\"}", code)),
|
||||
}
|
||||
|
||||
runtime := &util.RuntimeOptions{}
|
||||
|
||||
err = func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
resp, err := client.SendSmsWithOptions(sendSmsRequest, runtime)
|
||||
|
||||
if err != nil {
|
||||
var error = &tea.SDKError{}
|
||||
if _t, ok := err.(*tea.SDKError); ok {
|
||||
error = _t
|
||||
} else {
|
||||
error.Message = tea.String(err.Error())
|
||||
}
|
||||
|
||||
fmt.Println(tea.StringValue(error.Message))
|
||||
// 诊断地址
|
||||
var data interface{}
|
||||
d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data)))
|
||||
err := d.Decode(&data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m, ok := data.(map[string]interface{}); ok {
|
||||
recommend, _ := m["Recommend"]
|
||||
fmt.Println(recommend)
|
||||
}
|
||||
_, err = util.AssertAsString(error.Message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if *resp.Body.Code != "OK" {
|
||||
return errors.New(*resp.Body.Message)
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user