Compare commits
38 Commits
de78857139
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bdb851b701 | |||
| a32ee2052d | |||
| e29e0f4d0f | |||
| d8b59829f1 | |||
| 063fb158c9 | |||
| 02cffff608 | |||
| c24f54ce8c | |||
| e18fe543cd | |||
| 6e77c88f9d | |||
| c229ea2d5a | |||
| a81f5198e3 | |||
| 867a1022dd | |||
| 0d476fa477 | |||
| 9e12db0cd4 | |||
| b0313b951e | |||
| 0431ee605b | |||
| 940bf64546 | |||
| 4c49724353 | |||
| 467f081a1a | |||
| 9c4fd95955 | |||
| fe18036478 | |||
| f2ac09acdd | |||
| d68184fa59 | |||
| 5d51b7a400 | |||
| 6d4d1b2aed | |||
| a09ba16e8c | |||
| ad1ceaef17 | |||
| 13dc22cfa9 | |||
| 8ccda35a97 | |||
| 71eb38e66f | |||
| 66d8d660f2 | |||
| 6e3c268b82 | |||
| 6b8e7eada6 | |||
| 6a627dc474 | |||
| ed35631900 | |||
| d80076e2c7 | |||
| 2d40d589e2 | |||
| 2d7e241b76 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -5,6 +5,13 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
|
|
||||||
|
# 忽略 IDE/调试生成的临时二进制文件
|
||||||
|
__debug_bin*
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
#deploy data
|
#deploy data
|
||||||
|
|
||||||
data/*
|
data/*
|
||||||
@@ -20,4 +27,6 @@ data/*
|
|||||||
/tmp/
|
/tmp/
|
||||||
|
|
||||||
/app/api
|
/app/api
|
||||||
**/__debug_bin*.exe
|
**/__debug_bin*.exe
|
||||||
|
**/api.exe
|
||||||
|
**/*.exe
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ service main {
|
|||||||
type (
|
type (
|
||||||
PaymentReq {
|
PaymentReq {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
PayMethod string `json:"pay_method"`
|
PayMethod string `json:"pay_method" validate:"required,oneof=wechat alipay appleiap test"`
|
||||||
PayType string `json:"pay_type" validate:"required,oneof=query agent_vip"`
|
PayType string `json:"pay_type" validate:"required,oneof=query agent_vip"`
|
||||||
}
|
}
|
||||||
PaymentResp {
|
PaymentResp {
|
||||||
|
|||||||
@@ -51,10 +51,11 @@ type (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
QueryServiceReq {
|
QueryServiceReq {
|
||||||
Product string `path:"product"`
|
Product string `path:"product"`
|
||||||
Data string `json:"data" validate:"required"`
|
Data string `json:"data" validate:"required"`
|
||||||
AgentIdentifier string `json:"agent_identifier,optional"`
|
AgentIdentifier string `json:"agent_identifier,optional"`
|
||||||
App bool `json:"app,optional"`
|
App bool `json:"app,optional"`
|
||||||
|
CaptchaVerifyParam string `json:"captchaVerifyParam,optional"`
|
||||||
}
|
}
|
||||||
QueryServiceResp {
|
QueryServiceResp {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
@@ -137,8 +138,9 @@ type (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
QueryListReq {
|
QueryListReq {
|
||||||
Page int64 `form:"page"` // 页码
|
Page int64 `form:"page"` // 页码
|
||||||
PageSize int64 `form:"page_size"` // 每页数据量
|
PageSize int64 `form:"page_size"` // 每页数据量
|
||||||
|
Source string `form:"source,optional"` // 来源: miniapp 小程序过滤非车辆产品
|
||||||
}
|
}
|
||||||
QueryListResp {
|
QueryListResp {
|
||||||
Total int64 `json:"total"` // 总记录数
|
Total int64 `json:"total"` // 总记录数
|
||||||
|
|||||||
32
app/main/api/desc/front/toolbox.api
Normal file
32
app/main/api/desc/front/toolbox.api
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
syntax = "v1"
|
||||||
|
|
||||||
|
info (
|
||||||
|
title: "工具箱服务"
|
||||||
|
desc: "免费小工具:手机号归属地、VIN解析、车牌归属地等"
|
||||||
|
version: "v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ==================== 通用请求/响应 ====================
|
||||||
|
|
||||||
|
type (
|
||||||
|
ToolboxQueryReq {
|
||||||
|
ToolKey string `json:"tool_key" validate:"required"`
|
||||||
|
Params map[string]interface{} `json:"params"`
|
||||||
|
}
|
||||||
|
ToolboxQueryResp {
|
||||||
|
ToolKey string `json:"tool_key"`
|
||||||
|
Result map[string]interface{} `json:"result"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// ==================== 免费接口(无需登录) ====================
|
||||||
|
|
||||||
|
@server (
|
||||||
|
prefix: api/v1
|
||||||
|
group: toolbox
|
||||||
|
)
|
||||||
|
service main {
|
||||||
|
@doc "通用工具查询"
|
||||||
|
@handler toolboxQuery
|
||||||
|
post /toolbox/query (ToolboxQueryReq) returns (ToolboxQueryResp)
|
||||||
|
}
|
||||||
@@ -141,8 +141,26 @@ service main {
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
sendSmsReq {
|
sendSmsReq {
|
||||||
Mobile string `json:"mobile" validate:"required,mobile"`
|
Mobile string `json:"mobile" validate:"required,mobile"`
|
||||||
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"`
|
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"`
|
||||||
|
CaptchaVerifyParam string `json:"captchaVerifyParam"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
//============================> captcha v1 <============================
|
||||||
|
@server (
|
||||||
|
prefix: api/v1
|
||||||
|
group: captcha
|
||||||
|
)
|
||||||
|
service main {
|
||||||
|
@doc "get encrypted scene id for aliyun captcha"
|
||||||
|
@handler getEncryptedSceneId
|
||||||
|
post /captcha/encryptedSceneId returns (GetEncryptedSceneIdResp)
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
GetEncryptedSceneIdResp {
|
||||||
|
EncryptedSceneId string `json:"encryptedSceneId"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,15 @@ VerifyCode:
|
|||||||
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
||||||
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
||||||
EndpointURL: "dysmsapi.aliyuncs.com"
|
EndpointURL: "dysmsapi.aliyuncs.com"
|
||||||
SignName: "天远查"
|
SignName: "海南海宇大数据"
|
||||||
TemplateCode: "SMS_302641455"
|
TemplateCode: "SMS_302641455"
|
||||||
ValidTime: 300
|
ValidTime: 300
|
||||||
|
Captcha:
|
||||||
|
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
||||||
|
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
||||||
|
EndpointURL: "captcha.cn-shanghai.aliyuncs.com"
|
||||||
|
SceneID: "wynt39to"
|
||||||
|
EKey: "xdhf5JbWVmFXx+2K+6kBk2aH++GtQBEI8Gmzdeen90o="
|
||||||
Encrypt:
|
Encrypt:
|
||||||
SecretKey: "ff83609b2b24fc73196aac3d3dfb874f"
|
SecretKey: "ff83609b2b24fc73196aac3d3dfb874f"
|
||||||
Alipay:
|
Alipay:
|
||||||
@@ -26,7 +32,6 @@ Alipay:
|
|||||||
AppCertPath: "etc/merchant/appCertPublicKey_2021006121698606.crt"
|
AppCertPath: "etc/merchant/appCertPublicKey_2021006121698606.crt"
|
||||||
AlipayCertPath: "etc/merchant/alipayCertPublicKey_RSA2.crt"
|
AlipayCertPath: "etc/merchant/alipayCertPublicKey_RSA2.crt"
|
||||||
AlipayRootCertPath: "etc/merchant/alipayRootCert.crt"
|
AlipayRootCertPath: "etc/merchant/alipayRootCert.crt"
|
||||||
|
|
||||||
AppIDBak: "2021004161631930"
|
AppIDBak: "2021004161631930"
|
||||||
PrivateKeyBak: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCRrZNr8DNs4LhPSulTLEg4RLREWVSFGS+Nl5Q2FxQ8DgkUYV+p3kfi4XmB2W/Ruz4egPxEB0V/xj75OktVphVKY8rI6OaNnVoFVe5NqGa5MTj3wLwBIv/hMHA1VAru2KLIv9R1FR7LpWmreHSkpJ65CD2mZqYuMCekOfzMQZIGgSagEU4my0bLbFWw7M3qZz4vm2KUtm4Ew28OUJDkqygjPzXgS5l5niYQvqPjiQNdnTtoIcNcHo07tS8lmf/hdgq9EtVfY7Y0brESfgvOoVJeg1hTHEj0hyWnnWPeA4HD2izANP/5ObRX4ZVqpVju+7PSpbeFd71fxbR1blAVnrqTAgMBAAECggEASpkwHN3r9507xJ7/zG+oq+fCyB1WgrHbAA7W/rviyL4HOECE1F/XP/9mUXAfKq9PqB81D0EJ/dxu8wE/AqUB0g44EZnyNiKVrpXKakoKEFt8aKJxo8NgdNhxHV3kG1skQNi62xntoysZaY1NbeI+xVHLACMghhZytk5bfd02Ac3rMBz3X8Cl1R+3mgU0zFc5f476VRxywiRQM+QNJIaHDNB4vw1TKI0K92mEKD8lOuNZD7d5TCBZi3r08t8FFAkMjIMDiFvFRFmAqMg3NyaIGUkLVDU2zUP0Vlzmo9ghCV9hluqDqeP4RhxQydOw+rxGBk+crYQBhPyYOI/I9PFXAQKBgQDHSRRTPqYbCfztmwk3AIH7VN6izyU3FljEXAsdf+UVJpRa8429J3e+sB96jxhiwVlCzX4CDjsa/Pu0iQQx22a0AZs5GTE0MJ1FVydfGlyqF6/hRS4TswSkklW3be7/KDAjgj2+/wap+mN7rRmDkdvxgCJG6MiWuRAthhg/g16wIwKBgQC7Iu7D4yQXRKheL6p6pbMtE+oD58/EJ2vO8ZUz3LiPc9pZ6+bp4nkBP6JOuYiB5jkzWQifKe6hsXpv06kWzaBEzz4f4SUpWDmdBchNoct3pB/k66FaxHLO/pG4RV86hqscqTdutmdC62bbwM6yCtJ+3rS5rlCxDGQkGJbM+wM60QKBgH5nQyYeCbwC1NRdTzX883VYerLoEyHi4cEC5OX8NnD4/IbIDzJYc2KXUhAp7XzOSPDPaMqi/ih7KKh1dByvnnA0yKEp8oS5BThzNHzlOruEtMF9YOGL3jkIvKfRahOcCRSsyr94AWEVeb57qEBE5y5CaPtzMbAwiCtn779xc0DjAoGAZwEGXWokDm6rIhSoiJO2OQSyFW4+LSDptWHCF2bRa5yAPmiblHck1awaAa0b1yxKpdnG5hzljbirxOvDMZsDMXzFHDUICGbYZ3asVxbMcNE1AQM1sElbTFZRDRWaIhPIEaGOsnDSC8KYvjK1UsikLlMVNPMe1SUV5cxnDPLJR1ECgYEAw8M09uLylPtfGq7oyE2R6xC2kUA8EJ6aapJgUs/UZ6dtjtvudbYzUo0Cgnb12hpN3hfLc5O0/P4nRzZ72Hm43cMiRNLJi4BYCa0m/mCxq+RcoBWYQTIraHnR17yIQhxt5IBRVjgbvYCnryx5Jd5wjOvv7DdnGFJLepzSJwlGqeU="
|
PrivateKeyBak: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCRrZNr8DNs4LhPSulTLEg4RLREWVSFGS+Nl5Q2FxQ8DgkUYV+p3kfi4XmB2W/Ruz4egPxEB0V/xj75OktVphVKY8rI6OaNnVoFVe5NqGa5MTj3wLwBIv/hMHA1VAru2KLIv9R1FR7LpWmreHSkpJ65CD2mZqYuMCekOfzMQZIGgSagEU4my0bLbFWw7M3qZz4vm2KUtm4Ew28OUJDkqygjPzXgS5l5niYQvqPjiQNdnTtoIcNcHo07tS8lmf/hdgq9EtVfY7Y0brESfgvOoVJeg1hTHEj0hyWnnWPeA4HD2izANP/5ObRX4ZVqpVju+7PSpbeFd71fxbR1blAVnrqTAgMBAAECggEASpkwHN3r9507xJ7/zG+oq+fCyB1WgrHbAA7W/rviyL4HOECE1F/XP/9mUXAfKq9PqB81D0EJ/dxu8wE/AqUB0g44EZnyNiKVrpXKakoKEFt8aKJxo8NgdNhxHV3kG1skQNi62xntoysZaY1NbeI+xVHLACMghhZytk5bfd02Ac3rMBz3X8Cl1R+3mgU0zFc5f476VRxywiRQM+QNJIaHDNB4vw1TKI0K92mEKD8lOuNZD7d5TCBZi3r08t8FFAkMjIMDiFvFRFmAqMg3NyaIGUkLVDU2zUP0Vlzmo9ghCV9hluqDqeP4RhxQydOw+rxGBk+crYQBhPyYOI/I9PFXAQKBgQDHSRRTPqYbCfztmwk3AIH7VN6izyU3FljEXAsdf+UVJpRa8429J3e+sB96jxhiwVlCzX4CDjsa/Pu0iQQx22a0AZs5GTE0MJ1FVydfGlyqF6/hRS4TswSkklW3be7/KDAjgj2+/wap+mN7rRmDkdvxgCJG6MiWuRAthhg/g16wIwKBgQC7Iu7D4yQXRKheL6p6pbMtE+oD58/EJ2vO8ZUz3LiPc9pZ6+bp4nkBP6JOuYiB5jkzWQifKe6hsXpv06kWzaBEzz4f4SUpWDmdBchNoct3pB/k66FaxHLO/pG4RV86hqscqTdutmdC62bbwM6yCtJ+3rS5rlCxDGQkGJbM+wM60QKBgH5nQyYeCbwC1NRdTzX883VYerLoEyHi4cEC5OX8NnD4/IbIDzJYc2KXUhAp7XzOSPDPaMqi/ih7KKh1dByvnnA0yKEp8oS5BThzNHzlOruEtMF9YOGL3jkIvKfRahOcCRSsyr94AWEVeb57qEBE5y5CaPtzMbAwiCtn779xc0DjAoGAZwEGXWokDm6rIhSoiJO2OQSyFW4+LSDptWHCF2bRa5yAPmiblHck1awaAa0b1yxKpdnG5hzljbirxOvDMZsDMXzFHDUICGbYZ3asVxbMcNE1AQM1sElbTFZRDRWaIhPIEaGOsnDSC8KYvjK1UsikLlMVNPMe1SUV5cxnDPLJR1ECgYEAw8M09uLylPtfGq7oyE2R6xC2kUA8EJ6aapJgUs/UZ6dtjtvudbYzUo0Cgnb12hpN3hfLc5O0/P4nRzZ72Hm43cMiRNLJi4BYCa0m/mCxq+RcoBWYQTIraHnR17yIQhxt5IBRVjgbvYCnryx5Jd5wjOvv7DdnGFJLepzSJwlGqeU="
|
||||||
AlipayPublicKeyBak: ""
|
AlipayPublicKeyBak: ""
|
||||||
@@ -37,16 +42,17 @@ Alipay:
|
|||||||
NotifyUrl: "https://www.tianyuancha.cn/api/v1/pay/alipay/callback"
|
NotifyUrl: "https://www.tianyuancha.cn/api/v1/pay/alipay/callback"
|
||||||
ReturnURL: "https://www.tianyuancha.cn/payment/result"
|
ReturnURL: "https://www.tianyuancha.cn/payment/result"
|
||||||
Wxpay:
|
Wxpay:
|
||||||
AppID: "wxa581992dc74d860e"
|
AppID: "wxd391e40295bd9dfb"
|
||||||
MchID: "1682635136"
|
MchID: "1105276690"
|
||||||
MchCertificateSerialNumber: "5369B8AEEBDCF7AF274510252E6A8C0659C30F61"
|
MchCertificateSerialNumber: "4F1738D21CAEB7F76193A770CDBA6D7002ED1CFD"
|
||||||
MchApiv3Key: "e3ea4cf0765f1e71b01bb387dfcdbc9f"
|
MchApiv3Key: "K2d8F5gJ1sP7zQ3bN9mR4xV6c0hL5tU2"
|
||||||
MchPrivateKeyPath: "etc/merchant/apiclient_key.pem"
|
MchPrivateKeyPath: "etc/merchant/apiclient_key.pem"
|
||||||
MchPublicKeyID: "PUB_KEY_ID_0116826351362025060900382267001601"
|
MchPublicKeyID: "PUB_KEY_ID_0111052766902026050900112134001605"
|
||||||
MchPublicKeyPath: "etc/merchant/pub_key.pem"
|
MchPublicKeyPath: "etc/merchant/pub_key.pem"
|
||||||
MchPlatformRAS: "1FFEC3F62E31885FAB4C91ADCB8D7557E9488781"
|
MchPlatformRAS: "PUB_KEY_ID_0111052766902026050900112134001605"
|
||||||
NotifyUrl: "https://www.tianyuancha.cn/api/v1/pay/wechat/callback"
|
NotifyUrl: "https://www.tianyuancha.cn/api/v1/pay/wechat/callback"
|
||||||
RefundNotifyUrl: "https://www.tianyuancha.cn/api/v1/wechat/refund_callback"
|
RefundNotifyUrl: "https://www.tianyuancha.cn/api/v1/wechat/refund_callback"
|
||||||
|
|
||||||
Applepay:
|
Applepay:
|
||||||
ProductionVerifyURL: "https://api.storekit.itunes.apple.com/inApps/v1/transactions/receipt"
|
ProductionVerifyURL: "https://api.storekit.itunes.apple.com/inApps/v1/transactions/receipt"
|
||||||
SandboxVerifyURL: "https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/receipt"
|
SandboxVerifyURL: "https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/receipt"
|
||||||
@@ -61,13 +67,14 @@ SystemConfig:
|
|||||||
ThreeVerify: false
|
ThreeVerify: false
|
||||||
CommissionSafeMode: false # 佣金安全防御模式:true-冻结模式,false-直接结算模式
|
CommissionSafeMode: false # 佣金安全防御模式:true-冻结模式,false-直接结算模式
|
||||||
WechatH5:
|
WechatH5:
|
||||||
AppID: "wxe323cdc072127c27"
|
AppID: "wxd391e40295bd9dfb"
|
||||||
AppSecret: "e68035927b054a20b8bfdb7f0caffebf"
|
AppSecret: "f0fa74f7ed8c3c9953677465d44a4c0c"
|
||||||
WechatMini:
|
WechatMini:
|
||||||
AppID: "wx781abb66b3368963" # 小程序的AppID
|
# AppID: "wx5bacc94add2da981" # 小程序的AppID
|
||||||
AppSecret: "c7d02cdb0fc23c35c93187af9243b00d" # 小程序的AppSecret
|
# AppSecret: "48a2c1e8ff1b7d4c0ff82fbefa64d2d0" # 小程序的AppSecret
|
||||||
TycAppID: "wxe74617f3dd56c196"
|
# TYC
|
||||||
TycAppSecret: "c8207e54aef5689b2a7c1f91ed7ae8a0"
|
AppID: "wxe74617f3dd56c196"
|
||||||
|
AppSecret: "c8207e54aef5689b2a7c1f91ed7ae8a0"
|
||||||
Query:
|
Query:
|
||||||
ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒
|
ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒
|
||||||
AdminConfig:
|
AdminConfig:
|
||||||
@@ -91,3 +98,9 @@ Upload:
|
|||||||
TempFileMaxAgeH: 24 # 临时文件保留时长(小时),超时自动删除,0 表示默认 24
|
TempFileMaxAgeH: 24 # 临时文件保留时长(小时),超时自动删除,0 表示默认 24
|
||||||
PublicBaseURL: "https://www.tianyuancha.cn"
|
PublicBaseURL: "https://www.tianyuancha.cn"
|
||||||
ExtensionTime: 24 # 佣金解冻延迟时间,单位:24小时
|
ExtensionTime: 24 # 佣金解冻延迟时间,单位:24小时
|
||||||
|
|
||||||
|
|
||||||
|
tianxingjuhe:
|
||||||
|
url: "https://apis.tianapi.com"
|
||||||
|
key: "4ceffb1ffb95b83230b9a9c9df2467e1"
|
||||||
|
timeout: 30
|
||||||
@@ -16,9 +16,19 @@ VerifyCode:
|
|||||||
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
||||||
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
||||||
EndpointURL: "dysmsapi.aliyuncs.com"
|
EndpointURL: "dysmsapi.aliyuncs.com"
|
||||||
SignName: "天远查"
|
SignName: "海南海宇大数据"
|
||||||
TemplateCode: "SMS_302641455"
|
TemplateCode: "SMS_302641455"
|
||||||
ValidTime: 300
|
ValidTime: 300
|
||||||
|
Captcha:
|
||||||
|
# 建议与短信相同的 AccessKey,或单独为验证码创建子账号
|
||||||
|
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
||||||
|
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
||||||
|
# 验证码服务 Endpoint,国内一般为 captcha.cn-shanghai.aliyuncs.com
|
||||||
|
EndpointURL: "captcha.cn-shanghai.aliyuncs.com"
|
||||||
|
# 阿里云控制台中该场景的 SceneId,请替换为真实值
|
||||||
|
SceneID: "wynt39to"
|
||||||
|
# 验证码控制台中的 ekey(通常为 Base64 字符串),用于生成 EncryptedSceneId
|
||||||
|
EKey: ""
|
||||||
Encrypt:
|
Encrypt:
|
||||||
SecretKey: "ff83609b2b24fc73196aac3d3dfb874f"
|
SecretKey: "ff83609b2b24fc73196aac3d3dfb874f"
|
||||||
WestConfig:
|
WestConfig:
|
||||||
@@ -48,14 +58,14 @@ Alipay:
|
|||||||
NotifyUrl: "https://www.tianyuancha.cn/api/v1/pay/alipay/callback"
|
NotifyUrl: "https://www.tianyuancha.cn/api/v1/pay/alipay/callback"
|
||||||
ReturnURL: "https://www.tianyuancha.cn/payment/result"
|
ReturnURL: "https://www.tianyuancha.cn/payment/result"
|
||||||
Wxpay:
|
Wxpay:
|
||||||
AppID: "wxa581992dc74d860e"
|
AppID: "wxd391e40295bd9dfb"
|
||||||
MchID: "1682635136"
|
MchID: "1105276690"
|
||||||
MchCertificateSerialNumber: "5369B8AEEBDCF7AF274510252E6A8C0659C30F61"
|
MchCertificateSerialNumber: "4F1738D21CAEB7F76193A770CDBA6D7002ED1CFD"
|
||||||
MchApiv3Key: "e3ea4cf0765f1e71b01bb387dfcdbc9f"
|
MchApiv3Key: "K2d8F5gJ1sP7zQ3bN9mR4xV6c0hL5tU2"
|
||||||
MchPrivateKeyPath: "etc/merchant/apiclient_key.pem"
|
MchPrivateKeyPath: "etc/merchant/apiclient_key.pem"
|
||||||
MchPublicKeyID: "PUB_KEY_ID_0116826351362025060900382267001601"
|
MchPublicKeyID: "PUB_KEY_ID_0111052766902026050900112134001605"
|
||||||
MchPublicKeyPath: "etc/merchant/pub_key.pem"
|
MchPublicKeyPath: "etc/merchant/pub_key.pem"
|
||||||
MchPlatformRAS: "1FFEC3F62E31885FAB4C91ADCB8D7557E9488781"
|
MchPlatformRAS: "PUB_KEY_ID_0111052766902026050900112134001605"
|
||||||
NotifyUrl: "https://www.tianyuancha.cn/api/v1/pay/wechat/callback"
|
NotifyUrl: "https://www.tianyuancha.cn/api/v1/pay/wechat/callback"
|
||||||
RefundNotifyUrl: "https://www.tianyuancha.cn/api/v1/wechat/refund_callback"
|
RefundNotifyUrl: "https://www.tianyuancha.cn/api/v1/wechat/refund_callback"
|
||||||
Applepay:
|
Applepay:
|
||||||
@@ -72,11 +82,14 @@ SystemConfig:
|
|||||||
ThreeVerify: true
|
ThreeVerify: true
|
||||||
CommissionSafeMode: false # 佣金安全防御模式:true-冻结模式,false-直接结算模式
|
CommissionSafeMode: false # 佣金安全防御模式:true-冻结模式,false-直接结算模式
|
||||||
WechatH5:
|
WechatH5:
|
||||||
AppID: "wxa581992dc74d860e"
|
AppID: "wxd391e40295bd9dfb"
|
||||||
AppSecret: "4de1fbf521712247542d49907fcd5dbf"
|
AppSecret: "f0fa74f7ed8c3c9953677465d44a4c0c"
|
||||||
WechatMini:
|
WechatMini:
|
||||||
AppID: "wx781abb66b3368963" # 小程序的AppID
|
# AppID: "wx5bacc94add2da981" # 小程序的AppID
|
||||||
AppSecret: "c7d02cdb0fc23c35c93187af9243b00d" # 小程序的AppSecret
|
# AppSecret: "48a2c1e8ff1b7d4c0ff82fbefa64d2d0" # 小程序的AppSecret
|
||||||
|
# TYC
|
||||||
|
AppID: "wxe74617f3dd56c196"
|
||||||
|
AppSecret: "c8207e54aef5689b2a7c1f91ed7ae8a0"
|
||||||
Query:
|
Query:
|
||||||
ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒
|
ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒
|
||||||
AdminConfig:
|
AdminConfig:
|
||||||
@@ -93,9 +106,15 @@ Tianyuanapi:
|
|||||||
Key: "74902aff197d72d1caa5593560cb281e"
|
Key: "74902aff197d72d1caa5593560cb281e"
|
||||||
BaseURL: "https://api.tianyuanapi.com"
|
BaseURL: "https://api.tianyuanapi.com"
|
||||||
Timeout: 60
|
Timeout: 60
|
||||||
|
tianxingjuhe:
|
||||||
|
url: "https://apis.tianapi.com"
|
||||||
|
key: "4ceffb1ffb95b83230b9a9c9df2467e1"
|
||||||
|
timeout: 30
|
||||||
Authorization:
|
Authorization:
|
||||||
FileBaseURL: "https://www.tianyuancha.cn/api/v1/auth-docs" # 授权书文件访问基础URL
|
FileBaseURL: "https://www.tianyuancha.cn/api/v1/auth-docs" # 授权书文件访问基础URL
|
||||||
Upload:
|
Upload:
|
||||||
FileBaseURL: "https://www.tianyuancha.cn/api/v1/upload/file" # 上传图片访问基础 URL(行驶证等)
|
FileBaseURL: "https://www.tianyuanfcha.cn/api/v1/upload/file" # 上传图片访问基础 URL(行驶证等)
|
||||||
|
TempFileMaxAgeH: 24
|
||||||
|
|
||||||
PublicBaseURL: "https://www.tianyuancha.cn"
|
PublicBaseURL: "https://www.tianyuancha.cn"
|
||||||
ExtensionTime: 24 # 佣金解冻延迟时间,单位:24小时
|
ExtensionTime: 24 # 佣金解冻延迟时间,单位:24小时
|
||||||
|
|||||||
BIN
app/main/api/etc/merchant/apiclient_cert.p12
Normal file
BIN
app/main/api/etc/merchant/apiclient_cert.p12
Normal file
Binary file not shown.
25
app/main/api/etc/merchant/apiclient_cert.pem
Normal file
25
app/main/api/etc/merchant/apiclient_cert.pem
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEKDCCAxCgAwIBAgIUTxc40hyut/dhk6dwzbptcALtHP0wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
|
||||||
|
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
|
||||||
|
Q0EwHhcNMjYwNTA5MDU0MTQyWhcNMzEwNTA4MDU0MTQyWjCBgTETMBEGA1UEAwwK
|
||||||
|
MTEwNTI3NjY5MDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMS0wKwYDVQQL
|
||||||
|
DCTlub/opb/npo/pk63nvZHnu5znp5HmioDmnInpmZDlhazlj7gxCzAJBgNVBAYT
|
||||||
|
AkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||||
|
AQoCggEBANOAJ29Xxux4wzqDqkOWa/dqwJNt/WkK8vecWhbKSLLVDLBYcMSaklU2
|
||||||
|
Cw5pHGeNZSF9uB+8T7mGzrmhDg2643hcrBN60EMDEQvmtQp8ftkTl8rpToOTZ3yT
|
||||||
|
qlSW1BdCFKgiZJc3uel0q83kAqlnXz/AQ8lFp967Zjmp0DVGO1Aj4ihIcVL3njM8
|
||||||
|
xvNwVe+E1aCKb2T07M1MoECtUC3+U/ypD2Rl17FJHaaTaLlr0buTvvHwRNbDCZHb
|
||||||
|
MRcwQoVNJZyX3cq6+AZqzDSyBBlYzFWVw1jgI3QtdqRXAADJGUv8dddUDrTK//O9
|
||||||
|
gP8XQ5M70TXnovTtZDXt6JyggTDMyq8CAwEAAaOBuTCBtjAJBgNVHRMEAjAAMAsG
|
||||||
|
A1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDovL2V2Y2Eu
|
||||||
|
aXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRC
|
||||||
|
MDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJFMTJCMjdB
|
||||||
|
OUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IBAQAqmiey
|
||||||
|
BVEG0EZVTsb41feExEANDiKAc1gL/coqZRqf4+zWHX8tARshK+HsgEM2d+pOkGAW
|
||||||
|
XK6T79gqUyXLaO1dwVNeg4zaPGQaTddGvwExkyBvxMSBggGqDNdoXc2DPJQsLFGL
|
||||||
|
0q7JPvzEFlupjlk1SM9XWJ24KzWBl1HZZPQASBmi/O4CoHTqy5b4gqi7EDzYN4gz
|
||||||
|
kNFwuU7eTKEPlqbgPY4beDsCMvF4NUu1YSo3hUJz9vKKIL9xIXw1Snf2YbwlVJyl
|
||||||
|
sjtzndM+oxfc5VvoGC96xILWP8yEgKadsPZrcO7J4JRv3eqU24pNgQnqtWQ5ghiJ
|
||||||
|
nCl6uF83dT49XUlC
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -1,28 +1,28 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
-----BEGIN PRIVATE KEY-----
|
||||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDCP6fWm1vXXybH
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDTgCdvV8bseMM6
|
||||||
m3Ne6PjacGrN2+iMrzWZlzdHCZ31udDPqSUYaZ+78b441KZK/CJFQWeSJ/1h//A+
|
g6pDlmv3asCTbf1pCvL3nFoWykiy1QywWHDEmpJVNgsOaRxnjWUhfbgfvE+5hs65
|
||||||
BGsQDKvE/fj2QzN1KkOuQ8WJXNGpixE5uu5bv/QTN/ukurGdA1aO2aFCANumlOmB
|
oQ4NuuN4XKwTetBDAxEL5rUKfH7ZE5fK6U6Dk2d8k6pUltQXQhSoImSXN7npdKvN
|
||||||
HkB/B2so57ii8iQQjwK2xM4r3oOU/IfcFGKL+9/QjLGFFp9PJXCDBCgrxxlZGaj1
|
5AKpZ18/wEPJRafeu2Y5qdA1RjtQI+IoSHFS954zPMbzcFXvhNWgim9k9OzNTKBA
|
||||||
3wowlfVOzlaX94gemQsCYVkuAFIYMAnFHs9cKNZQIU80somW/yy2Gy38N6n7NnbD
|
rVAt/lP8qQ9kZdexSR2mk2i5a9G7k77x8ETWwwmR2zEXMEKFTSWcl93KuvgGasw0
|
||||||
nvFSaq4GoDROqRgKbRZ5e706d/p7A3aS/2oRqq1jomUIugK8g++LmoHFTgfhfQkI
|
sgQZWMxVlcNY4CN0LXakVwAAyRlL/HXXVA60yv/zvYD/F0OTO9E156L07WQ17eic
|
||||||
v1aG/nPzAgMBAAECggEAD2RN31J2J42xm/V0YdviBCUOQXugZK1peN8jkSxw6Myt
|
oIEwzMqvAgMBAAECggEAB3o3arNSwBeA53eyNFOEG6o1hsDTvbv6XRC1Cqs6KMBp
|
||||||
gBbuCo4sCw9vvD8VYjGyYXx6QXmLuV03YyKkfSQT5EsflBvlEu6jaEaUe3rwXhfX
|
g26NBhZk6AhSGb9TlsGj+qwkL1MMCoYelud/xLJ/ykiUeNfVtxjLqH0Ol4FRRsFv
|
||||||
6JQoWPrP00oHVZk5g7CFBlK2VW2N+hgonIOSJr6mvhoGZlr7gphiZasYjx9Vm9N3
|
k2fuM66pcPkTg4wVkYDvlAYrQkFhHETYsh3GjlCuSGW2v83rom9DrPQ4/TkvbaTW
|
||||||
Pbnfru5ttzplYNniwH3DF6ph8VmdbD1nnbWSKLXvHCsXQT2wBcnsIagIH3vyq6K1
|
md3at3pfEN/UPhL6jYnIEYfZoFFrE3aMCCAc5v2VUMZlX8R6ziK+CXyAQHegzGFH
|
||||||
pc5abWsQJrixOPebpI8jD5w0HxHAqVLx58H/OC2zW/roAw1WS2AkueJ1j7dQ7Z0C
|
zJp6XDvxuVjo/axD4LvKCvpzZIO9DUo1J5NA3/tar60AYCjMF9vBpkWRSwwekNbX
|
||||||
mc9Xexz5gcAP0nMAQv+LP7iYqsa/niFhfcTFWfdxkQKBgQD5JkKNmInU2/IVYCwO
|
lT1/r2/iRDhNyHWSz7Wo0CnrhNhRfV4HB6p8pzZIUQKBgQD/9+LvfFuLRqIEh/R8
|
||||||
c483MCSv1+MnbRXlb7vut8T0IupHTU6hCge6C3q3HsjbKSBn8bRChtPUzvw9JFxK
|
wNaZTWRDkp7paSc9kN7YXrKDkn20iDV4huk2Z+fL53Asvu5jMJzWJD7QU9bnasdE
|
||||||
QWKiQqQDPLDJ08AIKhfQD2JiLtoikkZN0bF6OTL+Soney1yGx51mlfHM194+PcCJ
|
fL9oUGOldqj15mpi+2dpLwwSnkNIah3Nxwr/DmCEKq6YjzRDIw1QWPjCe+2NgFTD
|
||||||
jF7iWdMVbcBwHbgydNxxIS5cKQKBgQDHlvQ4lw6gvLILpGK494/vNYSJP/Jmd66V
|
GACilmpw2G0ZsI3CgOenqLCVmQKBgQDThtuqIS3bivHr3QprMKHni9aaSm5jMnfd
|
||||||
3oSGYi84YRKTSwH4NlbBVVieb3Dv+pPugbsXEuFHBif7WsivbYgNTE9++8Yvt0gh
|
eYqD12sop6HkSetdOCAFttJP7J+wegpvUwdPdgvL8A2ICNwrjfL4i3V6LtJOBuRo
|
||||||
duB1G4yh7m/ylQeSuipgQU9tozrU/15cWwmcCRV50wWXBGoVEM0kf7mzEKSxmjYk
|
lbl8LHTegVQFd2nOXe57VtmxzADpmEao6rzc+IpYamFaRl8kvswx2MBL/c20vAKF
|
||||||
Qzko/zxSuwKBgQCY6Bc+SViFz3qSDdTcBaXma+CIHsmlH7ipd9px1kzEvEzl95cD
|
moE9OY9/hwKBgQCE9UQh1dzPWZ8q71vluV0/QF4GY5C7+Wzyo9+9UGM1yNAXCHGN
|
||||||
FGHLl1H34qfIgUQHJvrHPXHyEBoT+CW/2MMM7DM2XV/ubctT92ln4pkxwqlTQExv
|
67YUFqDm3477DypQx52P9j/SgtosVuCvCIV8L9WyyxI0uL0mMSSkFFYXDbIxWT2l
|
||||||
Y/s1FLesAtj8Z/hgK0/5bprYab9WmZV5lTGCXzhB1XqeFE9AgCHuODv4iQKBgQC8
|
9/AUUGl9/ZW3lRs2jGyMAcslaq4YRELDHCKoUa10dFcncvgPwlmSUyN2cQKBgC/p
|
||||||
g2uwd5ytXQydymokYk9klJvWNrvw5GHV1BJAC0Smb6lnzZTSqCBRAxdsrb1yLK7E
|
40YVP+rz/TqdFigTmwj07waCB6EmpGohhtO4bwiFeDFa4Rp7hR1mPRtnkQCLlGOF
|
||||||
u2vGY2K7/qiM1DZw23eBd+4t9gg+0VIjqXBfq+GsoNTDvtckUwnrWER5PY831ut9
|
HinMpn1qgdYnk5+2BqxwAotLoc2U2BYsnBhZhZuFFgAq/WeGdWew05znhelj2dWX
|
||||||
N89fvYS3SAUjmlvIAdKBAtKWusWTqiAxJ/05J7oGOQKBgB5PSr5i0LlupIbKui9t
|
XnJ7RfMjHawyNoj/QwejfmN4OSlQUQ3sYov4xt1vAoGBAKEq1xI1J1p/t+4j6Esc
|
||||||
XtXnRqGPxxrZZUpTkyrGOAnlCz/zq2QiwFpBWo/NMHOp0KmxzJpQ8yEY2LWlRZ61
|
frDvu+xW8IJSMHGNBz1Z4xA5KX2DmKH+aCjzTHMO6CJ353RH/2TNP44S5bHobAzK
|
||||||
Oc9m0J/HtPw3Ohi1treBosEVG/0NOI9Tq1Obny23N51MVibdW6zEIyGUp/DbFS8h
|
GqNisApHHCMf7Q+R1dOdXhiAKa1Cm6CUztfDXr2mTEcyqkrVAqTMrP2TnX9cuRVE
|
||||||
5DljdOYX9IYIHHn3Ig4GeTGe
|
xAft+Nal9d1gfPoGL5AcXLHI
|
||||||
-----END PRIVATE KEY-----
|
-----END PRIVATE KEY-----
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
-----BEGIN PUBLIC KEY-----
|
-----BEGIN PUBLIC KEY-----
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvwSy7dS/ICZV38tI0HxM
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4/k/xM+ybCzcWPi73Es5
|
||||||
SAIE7+Ug92qryuNlkNyaNDRjfsykHsrPCSsUUQEZblBNmZOLfLQxmAaWC+cQqWCv
|
XHPPqR2oGFdI7TPvbSnNcCpUAdewiuLFJZ3x7/6uTPKRuaxJPA9n0wjQ9x3Crwpt
|
||||||
zfy4rXGAHE1widWFkHGzQzaw6cB0VdDXatK9yAt1PgXdp5jzBRzOn9Z3u4t0s771
|
t+XZW8+gHU8kq1vG1cg+oBZedyS3434i+FCovK8iFQnsr5W+ROtVq8pxys0w5P3Z
|
||||||
2zjuxCnLxMq84DovNgh2y0LBiuorWbtuTFTd8SXUGk2Jyuojq/02U3KTuyh+7SmW
|
rYsdTZ7TxQ/3h/5hd7poehFUIIX1ZgO8tjCqq9wsvb70FRn4hf8NvyuxMtg+Va8U
|
||||||
ffJXKrzhrKwSpGh59e/fFxqX2xGlVoJ1kdohMZPo/7k+e5jP7qjrf93l7JVeUKYa
|
XdvDiUCa8NeCkvxpfPjEoZTNPsNbEYyYEJ1NSlte/5bLUBKm0rU6QGITuzXdPcF/
|
||||||
V27hNVowJ4oho21WVCJ1AYo41IbPJWI+6WxlaVeoR4zKix0Mb2timaWayyLoN53y
|
R5PweiMXFNy0l5A4eNFyO4I0evC36mB58geZ2rgdq92LZMQQTS6Rf63AtC2ECs5B
|
||||||
aQIDAQAB
|
wQIDAQAB
|
||||||
-----END PUBLIC KEY-----
|
-----END PUBLIC KEY-----
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ type Config struct {
|
|||||||
CacheRedis cache.CacheConf
|
CacheRedis cache.CacheConf
|
||||||
JwtAuth JwtAuth // JWT 鉴权相关配置
|
JwtAuth JwtAuth // JWT 鉴权相关配置
|
||||||
VerifyCode VerifyCode
|
VerifyCode VerifyCode
|
||||||
|
Captcha CaptchaConfig
|
||||||
Encrypt Encrypt
|
Encrypt Encrypt
|
||||||
Alipay AlipayConfig
|
Alipay AlipayConfig
|
||||||
Wxpay WxpayConfig
|
Wxpay WxpayConfig
|
||||||
Applepay ApplepayConfig
|
Applepay ApplepayConfig
|
||||||
Ali AliConfig
|
Ali AliConfig
|
||||||
Tianyuanapi TianyuanapiConfig
|
Tianyuanapi TianyuanapiConfig
|
||||||
|
Tianxingjuhe TianxingjuheConfig
|
||||||
SystemConfig SystemConfig
|
SystemConfig SystemConfig
|
||||||
WechatH5 WechatH5Config
|
WechatH5 WechatH5Config
|
||||||
Authorization AuthorizationConfig // 授权书配置
|
Authorization AuthorizationConfig // 授权书配置
|
||||||
@@ -45,6 +47,13 @@ type VerifyCode struct {
|
|||||||
TemplateCode string
|
TemplateCode string
|
||||||
ValidTime int
|
ValidTime int
|
||||||
}
|
}
|
||||||
|
type CaptchaConfig struct {
|
||||||
|
AccessKeyID string
|
||||||
|
AccessKeySecret string
|
||||||
|
EndpointURL string
|
||||||
|
SceneID string
|
||||||
|
EKey string
|
||||||
|
}
|
||||||
type Encrypt struct {
|
type Encrypt struct {
|
||||||
SecretKey string
|
SecretKey string
|
||||||
}
|
}
|
||||||
@@ -142,6 +151,13 @@ type AuthorizationConfig struct {
|
|||||||
|
|
||||||
// UploadConfig 图片上传(行驶证等)配置,临时存储,按 hash 去重
|
// UploadConfig 图片上传(行驶证等)配置,临时存储,按 hash 去重
|
||||||
type UploadConfig struct {
|
type UploadConfig struct {
|
||||||
FileBaseURL string `json:",optional"` // 上传文件访问基础 URL,如 https://xxx/api/v1/upload/file
|
FileBaseURL string `json:"fileBaseURL,omitempty"` // 上传文件访问基础 URL,如 https://xxx/api/v1/upload/file
|
||||||
TempFileMaxAgeH int `json:",optional"` // 临时文件保留时长(小时),超时删除,0 表示默认 24 小时
|
TempFileMaxAgeH int `json:"tempFileMaxAgeH,omitempty"` // 临时文件保留时长(小时),超时删除,0 表示默认 24 小时
|
||||||
|
}
|
||||||
|
|
||||||
|
// TianxingjuheConfig 天行聚合API配置
|
||||||
|
type TianxingjuheConfig struct {
|
||||||
|
URL string // API基础URL
|
||||||
|
Key string // API密钥
|
||||||
|
Timeout int // 超时时间(秒),默认30秒
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"tyc-server/app/main/api/internal/logic/auth"
|
"tyc-server/app/main/api/internal/logic/auth"
|
||||||
@@ -23,7 +24,8 @@ func SendSmsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
result.ParamValidateErrorResult(r, w, err)
|
result.ParamValidateErrorResult(r, w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l := auth.NewSendSmsLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), auth.UserAgentContextKey, r.Header.Get("User-Agent"))
|
||||||
|
l := auth.NewSendSmsLogic(ctx, svcCtx)
|
||||||
err := l.SendSms(&req)
|
err := l.SendSms(&req)
|
||||||
result.HttpResult(r, w, nil, err)
|
result.HttpResult(r, w, nil, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package captcha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"tyc-server/app/main/api/internal/logic/captcha"
|
||||||
|
"tyc-server/app/main/api/internal/svc"
|
||||||
|
"tyc-server/common/result"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetEncryptedSceneIdHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
l := captcha.NewGetEncryptedSceneIdLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.GetEncryptedSceneId()
|
||||||
|
result.HttpResult(r, w, resp, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,11 +22,13 @@ import (
|
|||||||
app "tyc-server/app/main/api/internal/handler/app"
|
app "tyc-server/app/main/api/internal/handler/app"
|
||||||
auth "tyc-server/app/main/api/internal/handler/auth"
|
auth "tyc-server/app/main/api/internal/handler/auth"
|
||||||
authorization "tyc-server/app/main/api/internal/handler/authorization"
|
authorization "tyc-server/app/main/api/internal/handler/authorization"
|
||||||
|
captcha "tyc-server/app/main/api/internal/handler/captcha"
|
||||||
notification "tyc-server/app/main/api/internal/handler/notification"
|
notification "tyc-server/app/main/api/internal/handler/notification"
|
||||||
pay "tyc-server/app/main/api/internal/handler/pay"
|
pay "tyc-server/app/main/api/internal/handler/pay"
|
||||||
product "tyc-server/app/main/api/internal/handler/product"
|
product "tyc-server/app/main/api/internal/handler/product"
|
||||||
query "tyc-server/app/main/api/internal/handler/query"
|
query "tyc-server/app/main/api/internal/handler/query"
|
||||||
tianyuan "tyc-server/app/main/api/internal/handler/tianyuan"
|
tianyuan "tyc-server/app/main/api/internal/handler/tianyuan"
|
||||||
|
toolbox "tyc-server/app/main/api/internal/handler/toolbox"
|
||||||
upload "tyc-server/app/main/api/internal/handler/upload"
|
upload "tyc-server/app/main/api/internal/handler/upload"
|
||||||
user "tyc-server/app/main/api/internal/handler/user"
|
user "tyc-server/app/main/api/internal/handler/user"
|
||||||
"tyc-server/app/main/api/internal/svc"
|
"tyc-server/app/main/api/internal/svc"
|
||||||
@@ -954,6 +956,18 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
rest.WithPrefix("/api/v1"),
|
rest.WithPrefix("/api/v1"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
// get encrypted scene id for aliyun captcha
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/captcha/encryptedSceneId",
|
||||||
|
Handler: captcha.GetEncryptedSceneIdHandler(serverCtx),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rest.WithPrefix("/api/v1"),
|
||||||
|
)
|
||||||
|
|
||||||
server.AddRoutes(
|
server.AddRoutes(
|
||||||
[]rest.Route{
|
[]rest.Route{
|
||||||
{
|
{
|
||||||
@@ -1162,6 +1176,24 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
rest.WithPrefix("/api/v1"),
|
rest.WithPrefix("/api/v1"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
// 获取工具列表
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/toolbox/list",
|
||||||
|
Handler: toolbox.ToolboxListHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 通用工具查询
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/toolbox/query",
|
||||||
|
Handler: toolbox.ToolboxQueryHandler(serverCtx),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rest.WithPrefix("/api/v1"),
|
||||||
|
)
|
||||||
|
|
||||||
server.AddRoutes(
|
server.AddRoutes(
|
||||||
[]rest.Route{
|
[]rest.Route{
|
||||||
{
|
{
|
||||||
|
|||||||
17
app/main/api/internal/handler/toolbox/toolboxlisthandler.go
Normal file
17
app/main/api/internal/handler/toolbox/toolboxlisthandler.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package toolbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"tyc-server/app/main/api/internal/logic/toolbox"
|
||||||
|
"tyc-server/app/main/api/internal/svc"
|
||||||
|
"tyc-server/common/result"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToolboxListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
l := toolbox.NewToolboxListLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.ToolboxList()
|
||||||
|
result.HttpResult(r, w, resp, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/main/api/internal/handler/toolbox/toolboxqueryhandler.go
Normal file
29
app/main/api/internal/handler/toolbox/toolboxqueryhandler.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package toolbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"tyc-server/app/main/api/internal/logic/toolbox"
|
||||||
|
"tyc-server/app/main/api/internal/svc"
|
||||||
|
"tyc-server/app/main/api/internal/types"
|
||||||
|
"tyc-server/common/result"
|
||||||
|
"tyc-server/pkg/lzkit/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToolboxQueryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.ToolboxQueryReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
result.ParamErrorResult(r, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := validator.Validate(req); err != nil {
|
||||||
|
result.ParamValidateErrorResult(r, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l := toolbox.NewToolboxQueryLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.ToolboxQuery(&req)
|
||||||
|
result.HttpResult(r, w, resp, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"tyc-server/app/main/api/internal/logic/user"
|
"tyc-server/app/main/api/internal/logic/user"
|
||||||
"tyc-server/app/main/api/internal/svc"
|
"tyc-server/app/main/api/internal/svc"
|
||||||
"tyc-server/app/main/api/internal/types"
|
"tyc-server/app/main/api/internal/types"
|
||||||
|
jwtx "tyc-server/common/jwt"
|
||||||
"tyc-server/common/result"
|
"tyc-server/common/result"
|
||||||
"tyc-server/pkg/lzkit/validator"
|
"tyc-server/pkg/lzkit/validator"
|
||||||
|
|
||||||
@@ -23,7 +26,14 @@ func WxH5AuthHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
result.ParamValidateErrorResult(r, w, err)
|
result.ParamValidateErrorResult(r, w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l := user.NewWxH5AuthLogic(r.Context(), svcCtx)
|
ctx := r.Context()
|
||||||
|
// 本路由未挂 AuthInterceptor;若前端已带登录态(如手机号登录后再走静默授权),需解析 JWT 以便把 openid 写入当前正式用户 user_auth
|
||||||
|
if authHeader := strings.TrimSpace(r.Header.Get("Authorization")); authHeader != "" {
|
||||||
|
if claims, err := jwtx.ParseJwtToken(authHeader, svcCtx.Config.JwtAuth.AccessSecret); err == nil {
|
||||||
|
ctx = context.WithValue(ctx, jwtx.ExtraKey, claims)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l := user.NewWxH5AuthLogic(ctx, svcCtx)
|
||||||
resp, err := l.WxH5Auth(&req)
|
resp, err := l.WxH5Auth(&req)
|
||||||
result.HttpResult(r, w, resp, err)
|
result.HttpResult(r, w, resp, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func (l *AdminReviewBankCardWithdrawalLogic) approveWithdrawal(ctx context.Conte
|
|||||||
return l.approveAlipayWithdrawal(ctx, session, record)
|
return l.approveAlipayWithdrawal(ctx, session, record)
|
||||||
} else {
|
} else {
|
||||||
// 银行卡提现:直接更新状态为成功(线下转账)
|
// 银行卡提现:直接更新状态为成功(线下转账)
|
||||||
return l.approveBankCardWithdrawal(ctx, session, record)
|
return l.approveBankCardWithdrawal(ctx, session, record, taxRate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ func (l *AdminReviewBankCardWithdrawalLogic) approveAlipayWithdrawal(ctx context
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 确认银行卡提现
|
// 确认银行卡提现
|
||||||
func (l *AdminReviewBankCardWithdrawalLogic) approveBankCardWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal) error {
|
func (l *AdminReviewBankCardWithdrawalLogic) approveBankCardWithdrawal(ctx context.Context, session sqlx.Session, record *model.AgentWithdrawal, taxRate float64) error {
|
||||||
// 更新提现记录状态为成功
|
// 更新提现记录状态为成功
|
||||||
record.Status = StatusSuccess
|
record.Status = StatusSuccess
|
||||||
record.Remark = sql.NullString{String: "管理员确认提现", Valid: true}
|
record.Remark = sql.NullString{String: "管理员确认提现", Valid: true}
|
||||||
@@ -233,10 +233,13 @@ func (l *AdminReviewBankCardWithdrawalLogic) approveBankCardWithdrawal(ctx conte
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
|
||||||
}
|
}
|
||||||
|
// 注意:由于在 applyReviewTaxRate 中已经更新过 tax 记录(version 已经递增)
|
||||||
|
// 这里只需要更新 tax_status 和 tax_time,不需要再次调用 UpdateWithVersion
|
||||||
|
// 使用普通 Update 方法避免乐观锁冲突
|
||||||
if taxModel.TaxStatus == model.TaxStatusPending {
|
if taxModel.TaxStatus == model.TaxStatusPending {
|
||||||
taxModel.TaxStatus = model.TaxStatusSuccess // 扣税状态 = 成功
|
taxModel.TaxStatus = model.TaxStatusSuccess // 扣税状态 = 成功
|
||||||
taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
|
taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||||
if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil {
|
if _, err := l.svcCtx.AgentWithdrawalTaxModel.Update(ctx, session, taxModel); err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,10 +307,12 @@ func (l *AdminReviewBankCardWithdrawalLogic) rejectWithdrawal(ctx context.Contex
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
|
||||||
}
|
}
|
||||||
|
// 注意:由于在 applyReviewTaxRate 中已经更新过 tax 记录(version 已经递增)
|
||||||
|
// 这里只需要更新 tax_status 和 tax_time,使用普通 Update 方法避免乐观锁冲突
|
||||||
if taxModel.TaxStatus == model.TaxStatusPending {
|
if taxModel.TaxStatus == model.TaxStatusPending {
|
||||||
taxModel.TaxStatus = model.TaxStatusFailed // 扣税状态 = 失败
|
taxModel.TaxStatus = model.TaxStatusFailed // 扣税状态 = 失败
|
||||||
taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
|
taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||||
if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil {
|
if _, err := l.svcCtx.AgentWithdrawalTaxModel.Update(ctx, session, taxModel); err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,10 +369,12 @@ func (l *AdminReviewBankCardWithdrawalLogic) completeWithdrawalSuccess(ctx conte
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
|
||||||
}
|
}
|
||||||
|
// 注意:由于在 applyReviewTaxRate 中已经更新过 tax 记录(version 已经递增)
|
||||||
|
// 这里只需要更新 tax_status 和 tax_time,使用普通 Update 方法避免乐观锁冲突
|
||||||
if taxModel.TaxStatus == model.TaxStatusPending {
|
if taxModel.TaxStatus == model.TaxStatusPending {
|
||||||
taxModel.TaxStatus = model.TaxStatusSuccess // 扣税状态 = 成功
|
taxModel.TaxStatus = model.TaxStatusSuccess // 扣税状态 = 成功
|
||||||
taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
|
taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||||
if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil {
|
if _, err := l.svcCtx.AgentWithdrawalTaxModel.Update(ctx, session, taxModel); err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -435,10 +442,12 @@ func (l *AdminReviewBankCardWithdrawalLogic) completeWithdrawalFailure(ctx conte
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询扣税记录失败: %v", err)
|
||||||
}
|
}
|
||||||
|
// 注意:由于在 applyReviewTaxRate 中已经更新过 tax 记录(version 已经递增)
|
||||||
|
// 这里只需要更新 tax_status 和 tax_time,使用普通 Update 方法避免乐观锁冲突
|
||||||
if taxModel.TaxStatus == model.TaxStatusPending {
|
if taxModel.TaxStatus == model.TaxStatusPending {
|
||||||
taxModel.TaxStatus = model.TaxStatusFailed // 扣税状态 = 失败
|
taxModel.TaxStatus = model.TaxStatusFailed // 扣税状态 = 失败
|
||||||
taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
|
taxModel.TaxTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||||
if err := l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(ctx, session, taxModel); err != nil {
|
if _, err := l.svcCtx.AgentWithdrawalTaxModel.Update(ctx, session, taxModel); err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ func (l *AdminRefundOrderLogic) handleAlipayRefund(order *model.Order, req *type
|
|||||||
orderPayTime = &order.PayTime.Time
|
orderPayTime = &order.PayTime.Time
|
||||||
}
|
}
|
||||||
refundNo := l.generateRefundNo(order.OrderNo)
|
refundNo := l.generateRefundNo(order.OrderNo)
|
||||||
refundResp, err := l.svcCtx.AlipayService.AliRefund(l.ctx, order.OrderNo, req.RefundAmount, orderPayTime, refundNo)
|
// 按订单记录的商户号 payment_merchant 选择支付宝商户;老订单未写入时由 AliRefund 内部按时间区间兜底。
|
||||||
|
refundResp, err := l.svcCtx.AlipayService.AliRefund(l.ctx, order.PaymentMerchant, order.OrderNo, req.RefundAmount, orderPayTime, refundNo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 支付宝退款失败 err: %v", err)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 支付宝退款失败 err: %v", err)
|
||||||
}
|
}
|
||||||
@@ -146,6 +147,7 @@ func (l *AdminRefundOrderLogic) createRefundRecordAndUpdateOrder(order *model.Or
|
|||||||
OrderId: order.Id,
|
OrderId: order.Id,
|
||||||
UserId: order.UserId,
|
UserId: order.UserId,
|
||||||
ProductId: order.ProductId,
|
ProductId: order.ProductId,
|
||||||
|
PaymentMerchant: order.PaymentMerchant,
|
||||||
RefundAmount: req.RefundAmount,
|
RefundAmount: req.RefundAmount,
|
||||||
RefundReason: l.createNullString(req.RefundReason),
|
RefundReason: l.createNullString(req.RefundReason),
|
||||||
Status: refundStatus, // 使用传入的状态,不再硬编码
|
Status: refundStatus, // 使用传入的状态,不再硬编码
|
||||||
@@ -174,6 +176,7 @@ func (l *AdminRefundOrderLogic) createRefundRecordOnly(order *model.Order, req *
|
|||||||
OrderId: order.Id,
|
OrderId: order.Id,
|
||||||
UserId: order.UserId,
|
UserId: order.UserId,
|
||||||
ProductId: order.ProductId,
|
ProductId: order.ProductId,
|
||||||
|
PaymentMerchant: order.PaymentMerchant,
|
||||||
RefundAmount: req.RefundAmount,
|
RefundAmount: req.RefundAmount,
|
||||||
RefundReason: l.createNullString(req.RefundReason),
|
RefundReason: l.createNullString(req.RefundReason),
|
||||||
Status: refundStatus,
|
Status: refundStatus,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
"tyc-server/common/xerr"
|
"tyc-server/common/xerr"
|
||||||
|
"tyc-server/pkg/captcha"
|
||||||
"tyc-server/pkg/lzkit/crypto"
|
"tyc-server/pkg/lzkit/crypto"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -34,7 +35,21 @@ func NewSendSmsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendSmsLo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserAgentContextKey 用于从 context 读取 User-Agent(如判断是否微信)
|
||||||
|
const UserAgentContextKey = "user_agent"
|
||||||
|
|
||||||
func (l *SendSmsLogic) SendSms(req *types.SendSmsReq) error {
|
func (l *SendSmsLogic) SendSms(req *types.SendSmsReq) error {
|
||||||
|
userAgent, _ := l.ctx.Value(UserAgentContextKey).(string)
|
||||||
|
cfg := l.svcCtx.Config.Captcha
|
||||||
|
if err := captcha.VerifyWithUserAgent(captcha.Config{
|
||||||
|
AccessKeyID: cfg.AccessKeyID,
|
||||||
|
AccessKeySecret: cfg.AccessKeySecret,
|
||||||
|
EndpointURL: cfg.EndpointURL,
|
||||||
|
SceneID: cfg.SceneID,
|
||||||
|
}, req.CaptchaVerifyParam, userAgent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||||
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
|
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package captcha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"tyc-server/app/main/api/internal/svc"
|
||||||
|
"tyc-server/app/main/api/internal/types"
|
||||||
|
"tyc-server/pkg/captcha"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetEncryptedSceneIdLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetEncryptedSceneIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetEncryptedSceneIdLogic {
|
||||||
|
return &GetEncryptedSceneIdLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *GetEncryptedSceneIdLogic) GetEncryptedSceneId() (resp *types.GetEncryptedSceneIdResp, err error) {
|
||||||
|
cfg := l.svcCtx.Config.Captcha
|
||||||
|
encrypted, genErr := captcha.GenerateEncryptedSceneID(cfg.SceneID, cfg.EKey, 3600)
|
||||||
|
if genErr != nil {
|
||||||
|
// 记录日志,返回通用错误
|
||||||
|
l.Errorf("generate encrypted scene id error: %+v", genErr)
|
||||||
|
return nil, genErr
|
||||||
|
}
|
||||||
|
return &types.GetEncryptedSceneIdResp{
|
||||||
|
EncryptedSceneId: encrypted,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -32,22 +32,58 @@ func NewAlipayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Al
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *AlipayCallbackLogic) AlipayCallback(w http.ResponseWriter, r *http.Request) error {
|
func (l *AlipayCallbackLogic) AlipayCallback(w http.ResponseWriter, r *http.Request) error {
|
||||||
notification, err := l.svcCtx.AlipayService.HandleAliPaymentNotification(r)
|
// 先解析表单,拿到 out_trade_no 用于查找订单和对应商户号
|
||||||
if err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
logx.Errorf("支付宝支付回调,%v", err)
|
logx.Errorf("支付宝支付回调,解析请求表单失败: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据订单号前缀判断订单类型
|
orderNo := r.FormValue("out_trade_no")
|
||||||
orderNo := notification.OutTradeNo
|
if orderNo == "" {
|
||||||
|
logx.Errorf("支付宝支付回调,缺少 out_trade_no")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据订单号前缀判断订单类型,并查出对应商户标识
|
||||||
|
var merchant string
|
||||||
if strings.HasPrefix(orderNo, "Q_") {
|
if strings.HasPrefix(orderNo, "Q_") {
|
||||||
// 查询订单处理
|
// 查询订单
|
||||||
return l.handleQueryOrderPayment(w, notification)
|
order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("支付宝支付回调,查询订单失败: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
merchant = order.PaymentMerchant
|
||||||
} else if strings.HasPrefix(orderNo, "A_") {
|
} else if strings.HasPrefix(orderNo, "A_") {
|
||||||
// 代理会员订单处理
|
// 代理会员订单
|
||||||
return l.handleAgentVipOrderPayment(w, notification)
|
agentOrder, err := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, orderNo)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("支付宝支付回调,查询代理会员订单失败: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
merchant = agentOrder.PaymentMerchant
|
||||||
} else {
|
} else {
|
||||||
// 兼容旧订单,假设没有前缀的是查询订单
|
// 兼容旧订单,假设没有前缀的是查询订单
|
||||||
|
order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("支付宝支付回调(旧订单),查询订单失败: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
merchant = order.PaymentMerchant
|
||||||
|
}
|
||||||
|
|
||||||
|
notification, err := l.svcCtx.AlipayService.HandleAliPaymentNotification(merchant, r.Form)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("支付宝支付回调,验签失败: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再次根据订单号前缀分发到具体处理函数
|
||||||
|
if strings.HasPrefix(orderNo, "Q_") {
|
||||||
|
return l.handleQueryOrderPayment(w, notification)
|
||||||
|
} else if strings.HasPrefix(orderNo, "A_") {
|
||||||
|
return l.handleAgentVipOrderPayment(w, notification)
|
||||||
|
} else {
|
||||||
return l.handleQueryOrderPayment(w, notification)
|
return l.handleQueryOrderPayment(w, notification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,9 +254,10 @@ func (l *AlipayCallbackLogic) handleRefund(order *model.AgentMembershipRechargeO
|
|||||||
return refundErr
|
return refundErr
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 代理会员订单以创建时间为准,仅 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单走 bak 商户号
|
// 支付宝退款按订单记录的商户号 payment_merchant 走对应商户;
|
||||||
|
// 老订单若未写入商户号,则在 AliRefund 内按时间区间兜底。
|
||||||
orderPayTime := order.CreateTime
|
orderPayTime := order.CreateTime
|
||||||
refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.OrderNo, order.Amount, &orderPayTime, "")
|
refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.PaymentMerchant, order.OrderNo, order.Amount, &orderPayTime, "")
|
||||||
if refundErr != nil {
|
if refundErr != nil {
|
||||||
return refundErr
|
return refundErr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tyc-server/app/main/api/internal/svc"
|
"tyc-server/app/main/api/internal/svc"
|
||||||
"tyc-server/app/main/api/internal/types"
|
"tyc-server/app/main/api/internal/types"
|
||||||
@@ -28,10 +29,26 @@ type PaymentLogic struct {
|
|||||||
svcCtx *svc.ServiceContext
|
svcCtx *svc.ServiceContext
|
||||||
}
|
}
|
||||||
type PaymentTypeResp struct {
|
type PaymentTypeResp struct {
|
||||||
amount float64
|
amount float64
|
||||||
outTradeNo string
|
outTradeNo string
|
||||||
description string
|
description string
|
||||||
orderID int64
|
orderID int64
|
||||||
|
payMerchantID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepayDataMissing 判断第三方支付预创建是否未返回可用参数(含 interface 包了一层 nil 的情况)
|
||||||
|
func prepayDataMissing(v interface{}) bool {
|
||||||
|
if v == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch t := v.(type) {
|
||||||
|
case string:
|
||||||
|
return t == ""
|
||||||
|
case map[string]string:
|
||||||
|
return len(t) == 0
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic {
|
func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic {
|
||||||
@@ -43,10 +60,9 @@ func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) {
|
func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) {
|
||||||
// 暂时关闭微信支付
|
req.PayMethod = strings.TrimSpace(req.PayMethod)
|
||||||
if req.PayMethod == "wechat" {
|
req.PayType = strings.TrimSpace(req.PayType)
|
||||||
return nil, errors.Wrapf(xerr.NewErrMsg("微信支付暂时关闭"), "微信支付暂时关闭")
|
req.Id = strings.TrimSpace(req.Id)
|
||||||
}
|
|
||||||
|
|
||||||
var paymentTypeResp *PaymentTypeResp
|
var paymentTypeResp *PaymentTypeResp
|
||||||
var prepayData interface{}
|
var prepayData interface{}
|
||||||
@@ -79,19 +95,53 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
|||||||
if req.PayMethod == "wechat" {
|
if req.PayMethod == "wechat" {
|
||||||
prepayData, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
|
prepayData, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
|
||||||
} else if req.PayMethod == "alipay" {
|
} else if req.PayMethod == "alipay" {
|
||||||
prepayData, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
|
// 支付宝:按订单写入的商户标识(one/two)创建支付订单
|
||||||
|
prepayData, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, paymentTypeResp.payMerchantID, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
|
||||||
} else if req.PayMethod == "appleiap" {
|
} else if req.PayMethod == "appleiap" {
|
||||||
prepayData = l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo)
|
iap := l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo)
|
||||||
|
prepayData = iap
|
||||||
|
if iap == "" {
|
||||||
|
createOrderErr = fmt.Errorf("获取 IAP 参数失败")
|
||||||
|
}
|
||||||
|
} else if req.PayMethod == "test" {
|
||||||
|
// 开发环境测试支付已在上方分支写入 prepayData;若走到此处说明非 development
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("测试支付仅在开发环境可用"), "ENV!=development 且 pay_method=test")
|
||||||
}
|
}
|
||||||
if createOrderErr != nil {
|
if createOrderErr != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr)
|
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr)
|
||||||
}
|
}
|
||||||
|
// 在事务内校验并失败则回滚,避免订单已落库却无 prepay(此前仅事务外校验会产生脏订单)
|
||||||
|
if req.PayMethod == "wechat" || req.PayMethod == "alipay" {
|
||||||
|
if prepayDataMissing(prepayData) {
|
||||||
|
platformVal := l.ctx.Value("platform")
|
||||||
|
logx.WithContext(l.ctx).Errorf(
|
||||||
|
"[Payment] 事务内 prepay 为空将回滚: pay_method=%q pay_type=%q order_no=%s platform=%v prepayData_type=%T",
|
||||||
|
req.PayMethod, req.PayType, paymentTypeResp.outTradeNo, platformVal, prepayData,
|
||||||
|
)
|
||||||
|
return errors.Wrapf(
|
||||||
|
xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, "获取支付参数失败,请确认在微信内打开且已完成网页授权后重试"),
|
||||||
|
"创建支付失败: prepay 为空 platform=%v",
|
||||||
|
platformVal,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if req.PayMethod == "wechat" || req.PayMethod == "alipay" {
|
||||||
|
if prepayDataMissing(prepayData) {
|
||||||
|
logx.WithContext(l.ctx).Errorf("[Payment] 事务提交后 prepay 仍为空(不应出现): pay_method=%q id=%q platform=%v",
|
||||||
|
req.PayMethod, req.Id, l.ctx.Value("platform"))
|
||||||
|
return nil, errors.Wrapf(
|
||||||
|
xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, "获取支付参数失败,请稍后重试"),
|
||||||
|
"创建支付失败: 未生成支付参数",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 开发环境测试支付模式:事务提交后处理订单状态更新和后续流程(仅 pay_method=test 且 query 类型 orderID>0)
|
// 开发环境测试支付模式:事务提交后处理订单状态更新和后续流程(仅 pay_method=test 且 query 类型 orderID>0)
|
||||||
isDevTestPayment := os.Getenv("ENV") == "development" && req.PayMethod == "test"
|
isDevTestPayment := os.Getenv("ENV") == "development" && req.PayMethod == "test"
|
||||||
if isDevTestPayment && paymentTypeResp != nil && paymentTypeResp.orderID != 0 {
|
if isDevTestPayment && paymentTypeResp != nil && paymentTypeResp.orderID != 0 {
|
||||||
@@ -161,6 +211,11 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
|||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析缓存内容失败, %v", err)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析缓存内容失败, %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 代理推广链接订单仅支持支付宝,拒绝微信支付(与个人查询页选项一致)
|
||||||
|
if req.PayMethod == "wechat" && data.AgentIdentifier != "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("代理推广订单暂不支持微信支付"), "代理推广订单暂不支持微信支付")
|
||||||
|
}
|
||||||
|
|
||||||
product, err := l.svcCtx.ProductModel.FindOneByProductEn(l.ctx, data.Product)
|
product, err := l.svcCtx.ProductModel.FindOneByProductEn(l.ctx, data.Product)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 查找产品错误: %v", err)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 查找产品错误: %v", err)
|
||||||
@@ -186,12 +241,24 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
|||||||
amount = 0.01
|
amount = 0.01
|
||||||
}
|
}
|
||||||
var orderID int64
|
var orderID int64
|
||||||
|
|
||||||
|
// 默认支付宝商户号为 one;若为代理推广订单(存在 AgentIdentifier),则使用 two。
|
||||||
|
paymentMerchant := ""
|
||||||
|
if req.PayMethod == "alipay" {
|
||||||
|
if data.AgentIdentifier != "" {
|
||||||
|
paymentMerchant = "two"
|
||||||
|
} else {
|
||||||
|
paymentMerchant = "one"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
order := model.Order{
|
order := model.Order{
|
||||||
OrderNo: outTradeNo,
|
OrderNo: outTradeNo,
|
||||||
UserId: userID,
|
UserId: userID,
|
||||||
ProductId: product.Id,
|
ProductId: product.Id,
|
||||||
PaymentPlatform: req.PayMethod,
|
PaymentPlatform: req.PayMethod,
|
||||||
PaymentScene: "app",
|
PaymentScene: "app",
|
||||||
|
PaymentMerchant: paymentMerchant,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
Status: "pending",
|
Status: "pending",
|
||||||
}
|
}
|
||||||
@@ -228,7 +295,13 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
|||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName, orderID: orderID}, nil
|
return &PaymentTypeResp{
|
||||||
|
amount: amount,
|
||||||
|
outTradeNo: outTradeNo,
|
||||||
|
description: product.ProductName,
|
||||||
|
orderID: orderID,
|
||||||
|
payMerchantID: paymentMerchant,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {
|
func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {
|
||||||
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||||
@@ -274,20 +347,32 @@ func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.
|
|||||||
if user.Inside == 1 {
|
if user.Inside == 1 {
|
||||||
amount = 0.01
|
amount = 0.01
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paymentMerchant := ""
|
||||||
|
if req.PayMethod == "alipay" {
|
||||||
|
paymentMerchant = "one"
|
||||||
|
}
|
||||||
|
|
||||||
agentMembershipRechargeOrder := model.AgentMembershipRechargeOrder{
|
agentMembershipRechargeOrder := model.AgentMembershipRechargeOrder{
|
||||||
OrderNo: req.Id,
|
OrderNo: req.Id,
|
||||||
UserId: userID,
|
UserId: userID,
|
||||||
AgentId: agentModel.Id,
|
AgentId: agentModel.Id,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
PaymentMethod: req.PayMethod,
|
PaymentMethod: req.PayMethod,
|
||||||
LevelName: agentVipCache.Type,
|
PaymentMerchant: paymentMerchant,
|
||||||
Status: "pending",
|
LevelName: agentVipCache.Type,
|
||||||
|
Status: "pending",
|
||||||
}
|
}
|
||||||
_, err = l.svcCtx.AgentMembershipRechargeOrderModel.Insert(l.ctx, session, &agentMembershipRechargeOrder)
|
_, err = l.svcCtx.AgentMembershipRechargeOrderModel.Insert(l.ctx, session, &agentMembershipRechargeOrder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理会员充值订单失败: %+v", err)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理会员充值订单失败: %+v", err)
|
||||||
}
|
}
|
||||||
return &PaymentTypeResp{amount: amount, outTradeNo: req.Id, description: fmt.Sprintf("%s代理会员充值", agentMembershipConfig.LevelName)}, nil
|
return &PaymentTypeResp{
|
||||||
|
amount: amount,
|
||||||
|
outTradeNo: req.Id,
|
||||||
|
description: fmt.Sprintf("%s代理会员充值", agentMembershipConfig.LevelName),
|
||||||
|
payMerchantID: paymentMerchant,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
func (l *PaymentLogic) agentParsing(agentIdentifier string) (*types.AgentIdentifier, error) {
|
func (l *PaymentLogic) agentParsing(agentIdentifier string) (*types.AgentIdentifier, error) {
|
||||||
key, decodeErr := hex.DecodeString("8e3e7a2f60edb49221e953b9c029ed10")
|
key, decodeErr := hex.DecodeString("8e3e7a2f60edb49221e953b9c029ed10")
|
||||||
|
|||||||
@@ -221,9 +221,10 @@ func (l *WechatPayCallbackLogic) handleRefund(order *model.AgentMembershipRechar
|
|||||||
return refundErr
|
return refundErr
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 代理会员订单以创建时间为准,仅 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单走 bak 商户号
|
// 支付宝退款按订单记录的商户号 payment_merchant 走对应商户;
|
||||||
|
// 老订单若未写入商户号,则在 AliRefund 内按时间区间兜底。
|
||||||
orderPayTime := order.CreateTime
|
orderPayTime := order.CreateTime
|
||||||
refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.OrderNo, order.Amount, &orderPayTime, "")
|
refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.PaymentMerchant, order.OrderNo, order.Amount, &orderPayTime, "")
|
||||||
if refundErr != nil {
|
if refundErr != nil {
|
||||||
return refundErr
|
return refundErr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package query
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"strings"
|
||||||
"tyc-server/app/main/api/internal/svc"
|
"tyc-server/app/main/api/internal/svc"
|
||||||
"tyc-server/app/main/api/internal/types"
|
"tyc-server/app/main/api/internal/types"
|
||||||
"tyc-server/app/main/model"
|
"tyc-server/app/main/model"
|
||||||
@@ -28,51 +29,81 @@ func NewQueryListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isVehicleProduct 判断 product_en 是否为车辆类产品
|
||||||
|
func isVehicleProduct(productEn string) bool {
|
||||||
|
vehiclePrefixes := []string{
|
||||||
|
"toc_Vehicle",
|
||||||
|
"toc_PersonVehicle",
|
||||||
|
}
|
||||||
|
for _, p := range vehiclePrefixes {
|
||||||
|
if strings.HasPrefix(productEn, p) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (l *QueryListLogic) QueryList(req *types.QueryListReq) (resp *types.QueryListResp, err error) {
|
func (l *QueryListLogic) QueryList(req *types.QueryListReq) (resp *types.QueryListResp, err error) {
|
||||||
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||||
if getUidErr != nil {
|
if getUidErr != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告列表查询, 获取用户信息失败, %+v", getUidErr)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告列表查询, 获取用户信息失败, %+v", getUidErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 小程序端需要过滤非车辆产品,取更大分页后内存过滤
|
||||||
|
pageSize := req.PageSize
|
||||||
|
isMiniapp := req.Source == "miniapp"
|
||||||
|
if isMiniapp && pageSize < 200 {
|
||||||
|
pageSize = 200
|
||||||
|
}
|
||||||
|
|
||||||
// 直接构建查询query表的条件
|
// 直接构建查询query表的条件
|
||||||
build := l.svcCtx.QueryModel.SelectBuilder().Where(squirrel.Eq{
|
build := l.svcCtx.QueryModel.SelectBuilder().Where(squirrel.Eq{
|
||||||
"user_id": userID,
|
"user_id": userID,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 直接从query表分页查询
|
// 直接从query表分页查询
|
||||||
queryList, total, err := l.svcCtx.QueryModel.FindPageListByPageWithTotal(l.ctx, build, req.Page, req.PageSize, "create_time DESC")
|
queryList, total, err := l.svcCtx.QueryModel.FindPageListByPageWithTotal(l.ctx, build, req.Page, pageSize, "create_time DESC")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告列表查询, 查找报告列表错误, %+v", err)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告列表查询, 查找报告列表错误, %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var list []types.Query
|
var list []types.Query
|
||||||
if len(queryList) > 0 {
|
for _, queryModel := range queryList {
|
||||||
for _, queryModel := range queryList {
|
var query types.Query
|
||||||
var query types.Query
|
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
|
||||||
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
|
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
|
||||||
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
|
copyErr := copier.Copy(&query, queryModel)
|
||||||
copyErr := copier.Copy(&query, queryModel)
|
if copyErr != nil {
|
||||||
if copyErr != nil {
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 报告结构体复制失败, %+v", err)
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 报告结构体复制失败, %+v", err)
|
|
||||||
}
|
|
||||||
product, findProductErr := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
|
|
||||||
if findProductErr != nil {
|
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 获取商品信息失败, %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查订单状态,如果订单已退款,则设置查询状态为已退款
|
|
||||||
order, findOrderErr := l.svcCtx.OrderModel.FindOne(l.ctx, queryModel.OrderId)
|
|
||||||
if findOrderErr == nil && order.Status == model.OrderStatusRefunded {
|
|
||||||
query.QueryState = model.QueryStateRefunded
|
|
||||||
}
|
|
||||||
query.ProductName = product.ProductName
|
|
||||||
query.Product = product.ProductEn
|
|
||||||
list = append(list, query)
|
|
||||||
}
|
}
|
||||||
|
product, findProductErr := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
|
||||||
|
if findProductErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 获取商品信息失败, %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小程序端:过滤非车辆类产品(H5 端 source 为空,不做过滤)
|
||||||
|
if isMiniapp && !isVehicleProduct(product.ProductEn) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查订单状态,如果订单已退款,则设置查询状态为已退款
|
||||||
|
order, findOrderErr := l.svcCtx.OrderModel.FindOne(l.ctx, queryModel.OrderId)
|
||||||
|
if findOrderErr == nil && order.Status == model.OrderStatusRefunded {
|
||||||
|
query.QueryState = model.QueryStateRefunded
|
||||||
|
}
|
||||||
|
query.ProductName = product.ProductName
|
||||||
|
query.Product = product.ProductEn
|
||||||
|
list = append(list, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// H5 端返回数据库原始 total;小程序端返回过滤后的实际数量
|
||||||
|
respTotal := total
|
||||||
|
if isMiniapp {
|
||||||
|
respTotal = int64(len(list))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.QueryListResp{
|
return &types.QueryListResp{
|
||||||
Total: total,
|
Total: respTotal,
|
||||||
List: list,
|
List: list,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"tyc-server/common/ctxdata"
|
"tyc-server/common/ctxdata"
|
||||||
"tyc-server/common/globalkey"
|
"tyc-server/common/globalkey"
|
||||||
"tyc-server/common/xerr"
|
"tyc-server/common/xerr"
|
||||||
|
"tyc-server/pkg/captcha"
|
||||||
"tyc-server/pkg/lzkit/crypto"
|
"tyc-server/pkg/lzkit/crypto"
|
||||||
"tyc-server/pkg/lzkit/validator"
|
"tyc-server/pkg/lzkit/validator"
|
||||||
|
|
||||||
@@ -59,8 +60,9 @@ var productHandlers = map[string]queryHandlerFunc{
|
|||||||
"companyinfo": runMarriageReq,
|
"companyinfo": runMarriageReq,
|
||||||
"rentalinfo": runMarriageReq,
|
"rentalinfo": runMarriageReq,
|
||||||
"preloanbackgroundcheck": runMarriageReq,
|
"preloanbackgroundcheck": runMarriageReq,
|
||||||
"backgroundcheck": runMarriageReq,
|
"backgroundcheck": runBackgroundCheckReq,
|
||||||
"personalData": runMarriageReq,
|
"personalData": runMarriageReq,
|
||||||
|
"toc_PersonalBadRecord": runPersonalBadRecordReq,
|
||||||
"toc_PersonalLawsuit": runMarriageReq,
|
"toc_PersonalLawsuit": runMarriageReq,
|
||||||
"toc_EnterpriseLawsuit": runEntLawsuitReq,
|
"toc_EnterpriseLawsuit": runEntLawsuitReq,
|
||||||
// 人企关系加强版:仅身份证号
|
// 人企关系加强版:仅身份证号
|
||||||
@@ -109,7 +111,58 @@ var productHandlers = map[string]queryHandlerFunc{
|
|||||||
"toc_BankcardBlacklist": runVerifyBankBlackReq,
|
"toc_BankcardBlacklist": runVerifyBankBlackReq,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// productHasSmsCode 表示该 product 解密后的请求结构体中是否包含必填短信验证码 Code。
|
||||||
|
// 有 Code 的产品在「获取验证码」时已经做了滑块,这里不再强制要求 CaptchaVerifyParam。
|
||||||
|
// 其他产品(无 Code)在查询时必须传并校验 CaptchaVerifyParam,防止跳过图形验证;
|
||||||
|
// 微信小程序(X-Platform: wxmini,见 ctxdata.GetPlatformFromCtx)不嵌入 H5 滑块,由 PreprocessLogic 跳过图形校验。
|
||||||
|
func productHasSmsCode(product string) bool {
|
||||||
|
switch product {
|
||||||
|
case "marriage",
|
||||||
|
"homeservice",
|
||||||
|
"riskassessment",
|
||||||
|
"companyinfo",
|
||||||
|
"rentalinfo",
|
||||||
|
"preloanbackgroundcheck",
|
||||||
|
"personalData",
|
||||||
|
"toc_PersonalLawsuit",
|
||||||
|
"toc_EnterpriseLawsuit",
|
||||||
|
"toc_Marriage",
|
||||||
|
"toc_PersonalMarriageStatus",
|
||||||
|
"toc_MarriageStatusRegisterTime",
|
||||||
|
"toc_MarriageStatusSupplement",
|
||||||
|
"toc_MarriageStatusVerify",
|
||||||
|
"toc_DualMarriageStatusRegisterTime",
|
||||||
|
"toc_VehiclesUnderName",
|
||||||
|
"toc_VehiclesUnderNamePlate":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (l *QueryServiceLogic) PreprocessLogic(req *types.QueryServiceReq, product string) (*types.QueryServiceResp, error) {
|
func (l *QueryServiceLogic) PreprocessLogic(req *types.QueryServiceReq, product string) (*types.QueryServiceResp, error) {
|
||||||
|
// 无短信验证码 Code 的 product:查询前必须传并校验滑块;微信小程序端跳过(依赖登录态与 X-Platform)
|
||||||
|
requireCaptcha := !productHasSmsCode(product)
|
||||||
|
if requireCaptcha {
|
||||||
|
if plat, platErr := ctxdata.GetPlatformFromCtx(l.ctx); platErr == nil && plat == model.PlatformWxMini {
|
||||||
|
requireCaptcha = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if requireCaptcha {
|
||||||
|
if req.CaptchaVerifyParam == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("请完成图形验证"), "product %s requires captcha", product)
|
||||||
|
}
|
||||||
|
cfg := l.svcCtx.Config.Captcha
|
||||||
|
if err := captcha.Verify(captcha.Config{
|
||||||
|
AccessKeyID: cfg.AccessKeyID,
|
||||||
|
AccessKeySecret: cfg.AccessKeySecret,
|
||||||
|
EndpointURL: cfg.EndpointURL,
|
||||||
|
SceneID: cfg.SceneID,
|
||||||
|
}, req.CaptchaVerifyParam); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
decryptData, err := l.DecryptData(req.Data)
|
decryptData, err := l.DecryptData(req.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -170,6 +223,24 @@ func runMarriageReq(l *QueryServiceLogic, decryptData []byte, product string) (m
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runBackgroundCheckReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) {
|
||||||
|
var data types.BackgroundCheckReq
|
||||||
|
if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr)
|
||||||
|
}
|
||||||
|
if validatorErr := validator.Validate(data); validatorErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr)
|
||||||
|
}
|
||||||
|
if verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile); verifyErr != nil {
|
||||||
|
return nil, verifyErr
|
||||||
|
}
|
||||||
|
return map[string]interface{}{
|
||||||
|
"name": data.Name,
|
||||||
|
"id_card": data.IDCard,
|
||||||
|
"mobile": data.Mobile,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// runEntLawsuitReq 企业司法涉诉:企业名称+统一社会信用代码+手机+验证码
|
// runEntLawsuitReq 企业司法涉诉:企业名称+统一社会信用代码+手机+验证码
|
||||||
func runEntLawsuitReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) {
|
func runEntLawsuitReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) {
|
||||||
var data types.EntLawsuitReq
|
var data types.EntLawsuitReq
|
||||||
@@ -230,6 +301,21 @@ func runLimitHighExecutedReq(l *QueryServiceLogic, decryptData []byte, product s
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 本人不良 FLXGDEA9:姓名 + 身份证(授权由 ApiRequest 默认传 1)
|
||||||
|
func runPersonalBadRecordReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) {
|
||||||
|
var data types.PersonalBadRecordReq
|
||||||
|
if unmarshalErr := json.Unmarshal(decryptData, &data); unmarshalErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 解密后的数据格式不正确: %+v", unmarshalErr)
|
||||||
|
}
|
||||||
|
if validatorErr := validator.Validate(data); validatorErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.PARAM_VERIFICATION_ERROR, validatorErr.Error()), "查询服务, 参数不正确: %+v", validatorErr)
|
||||||
|
}
|
||||||
|
return map[string]interface{}{
|
||||||
|
"name": data.Name,
|
||||||
|
"id_card": data.IDCard,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// 失信被执行人 QYGL2S0W
|
// 失信被执行人 QYGL2S0W
|
||||||
func runDishonestExecutedReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) {
|
func runDishonestExecutedReq(l *QueryServiceLogic, decryptData []byte, product string) (map[string]interface{}, error) {
|
||||||
var data types.DishonestExecutedReq
|
var data types.DishonestExecutedReq
|
||||||
|
|||||||
43
app/main/api/internal/logic/toolbox/toolboxlistlogic.go
Normal file
43
app/main/api/internal/logic/toolbox/toolboxlistlogic.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package toolbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"tyc-server/app/main/api/internal/svc"
|
||||||
|
"tyc-server/app/main/api/internal/types"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ToolboxListLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewToolboxListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ToolboxListLogic {
|
||||||
|
return &ToolboxListLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ToolboxListLogic) ToolboxList() (resp *types.ToolboxListResp, err error) {
|
||||||
|
// 调用toolboxService获取工具列表
|
||||||
|
tools := l.svcCtx.ToolboxService.ListTools()
|
||||||
|
|
||||||
|
// 转换为响应格式
|
||||||
|
var toolInfos []types.ToolInfo
|
||||||
|
for _, tool := range tools {
|
||||||
|
toolInfos = append(toolInfos, types.ToolInfo{
|
||||||
|
Key: tool.Key,
|
||||||
|
Name: tool.Name,
|
||||||
|
Desc: tool.Desc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ToolboxListResp{
|
||||||
|
Tools: toolInfos,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
37
app/main/api/internal/logic/toolbox/toolboxquerylogic.go
Normal file
37
app/main/api/internal/logic/toolbox/toolboxquerylogic.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package toolbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"tyc-server/app/main/api/internal/svc"
|
||||||
|
"tyc-server/app/main/api/internal/types"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ToolboxQueryLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewToolboxQueryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ToolboxQueryLogic {
|
||||||
|
return &ToolboxQueryLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ToolboxQueryLogic) ToolboxQuery(req *types.ToolboxQueryReq) (resp *types.ToolboxQueryResp, err error) {
|
||||||
|
// 调用toolboxService执行工具查询
|
||||||
|
result, err := l.svcCtx.ToolboxService.Query(l.ctx, req.ToolKey, req.Params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ToolboxQueryResp{
|
||||||
|
ToolKey: req.ToolKey,
|
||||||
|
Result: result,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -38,7 +38,7 @@ func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (r
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err)
|
||||||
}
|
}
|
||||||
// 检查验证码(开发环境可跳过)
|
// 短信验证码校验(开发环境可跳过)
|
||||||
if os.Getenv("ENV") != "development" {
|
if os.Getenv("ENV") != "development" {
|
||||||
redisKey := fmt.Sprintf("%s:%s", "login", encryptedMobile)
|
redisKey := fmt.Sprintf("%s:%s", "login", encryptedMobile)
|
||||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tyc-server/app/main/model"
|
"tyc-server/app/main/model"
|
||||||
|
"tyc-server/common/ctxdata"
|
||||||
"tyc-server/common/xerr"
|
"tyc-server/common/xerr"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -39,6 +41,11 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe
|
|||||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token失败: %v", err)
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 已登录正式用户 + 静默授权 code:把当前公众号 openid 写入 user_auth(wxh5_openid),供微信内 JSAPI 支付使用
|
||||||
|
if claims, claimsErr := ctxdata.GetClaimsFromCtx(l.ctx); claimsErr == nil && claims != nil && claims.UserType == model.UserTypeNormal {
|
||||||
|
return l.bindWxh5OpenidToNormalUser(claims.UserId, accessTokenResp.Openid)
|
||||||
|
}
|
||||||
|
|
||||||
// Step 2: 查找用户授权信息
|
// Step 2: 查找用户授权信息
|
||||||
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid)
|
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid)
|
||||||
if findErr != nil && !errors.Is(findErr, model.ErrNotFound) {
|
if findErr != nil && !errors.Is(findErr, model.ErrNotFound) {
|
||||||
@@ -94,6 +101,53 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bindWxh5OpenidToNormalUser 将 snsapi_base 换得的 openid 绑定到当前正式用户(插入或更新 user_auth)。
|
||||||
|
// 临时用户不能走此分支:需在绑定手机号时由 TempUserBindUser 写入 user_auth,避免与临时转正逻辑冲突。
|
||||||
|
func (l *WxH5AuthLogic) bindWxh5OpenidToNormalUser(normalUserID int64, openid string) (*types.WXH5AuthResp, error) {
|
||||||
|
openid = strings.TrimSpace(openid)
|
||||||
|
if openid == "" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "微信 openid 为空")
|
||||||
|
}
|
||||||
|
existingByOpenid, err := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, openid)
|
||||||
|
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询 wxh5_openid 失败: %v", err)
|
||||||
|
}
|
||||||
|
if existingByOpenid != nil && existingByOpenid.UserId != normalUserID {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("该微信已绑定其他账号"), "wxh5_openid 已被占用 user_id=%d", existingByOpenid.UserId)
|
||||||
|
}
|
||||||
|
rowByUser, err := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(l.ctx, normalUserID, model.UserAuthTypeWxh5OpenID)
|
||||||
|
if errors.Is(err, model.ErrNotFound) {
|
||||||
|
_, insErr := l.svcCtx.UserAuthModel.Insert(l.ctx, nil, &model.UserAuth{
|
||||||
|
UserId: normalUserID,
|
||||||
|
AuthType: model.UserAuthTypeWxh5OpenID,
|
||||||
|
AuthKey: openid,
|
||||||
|
})
|
||||||
|
if insErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "写入 wxh5_openid 失败: %v", insErr)
|
||||||
|
}
|
||||||
|
logx.WithContext(l.ctx).Infof("[WxH5Auth] 已写入 user_auth wxh5_openid user_id=%d", normalUserID)
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户 wxh5_openid 失败: %v", err)
|
||||||
|
} else if rowByUser.AuthKey != openid {
|
||||||
|
rowByUser.AuthKey = openid
|
||||||
|
if _, updErr := l.svcCtx.UserAuthModel.Update(l.ctx, nil, rowByUser); updErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新 wxh5_openid 失败: %v", updErr)
|
||||||
|
}
|
||||||
|
logx.WithContext(l.ctx).Infof("[WxH5Auth] 已更新 user_auth wxh5_openid user_id=%d", normalUserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, normalUserID, model.UserTypeNormal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成JWT token失败: %v", err)
|
||||||
|
}
|
||||||
|
now := time.Now().Unix()
|
||||||
|
return &types.WXH5AuthResp{
|
||||||
|
AccessToken: token,
|
||||||
|
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||||
|
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type AccessTokenResp struct {
|
type AccessTokenResp struct {
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
Openid string `json:"openid"`
|
Openid string `json:"openid"`
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -12,7 +13,7 @@ const (
|
|||||||
func GlobalSourceInterceptor(next http.HandlerFunc) http.HandlerFunc {
|
func GlobalSourceInterceptor(next http.HandlerFunc) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
// 获取请求头 X-Platform 的值
|
// 获取请求头 X-Platform 的值
|
||||||
platform := r.Header.Get(PlatformKey)
|
platform := strings.TrimSpace(r.Header.Get(PlatformKey))
|
||||||
|
|
||||||
// 将值放入新的 context 中
|
// 将值放入新的 context 中
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|||||||
@@ -322,12 +322,13 @@ func (l *PaySuccessNotifyUserHandler) handleError(ctx context.Context, err error
|
|||||||
logx.Infof("已发起微信退款申请, orderID: %d, amount: %f", order.Id, order.Amount)
|
logx.Infof("已发起微信退款申请, orderID: %d, amount: %f", order.Id, order.Amount)
|
||||||
return asynq.SkipRetry
|
return asynq.SkipRetry
|
||||||
} else {
|
} else {
|
||||||
// 支付宝退款为同步结果,仅 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单走 bak 商户号
|
// 支付宝退款为同步结果,优先按订单记录的 payment_merchant 选择商户;
|
||||||
|
// 老订单若未写入商户号,则在 AliRefund 内按时间区间兜底。
|
||||||
orderPayTime := &order.CreateTime
|
orderPayTime := &order.CreateTime
|
||||||
if order.PayTime.Valid {
|
if order.PayTime.Valid {
|
||||||
orderPayTime = &order.PayTime.Time
|
orderPayTime = &order.PayTime.Time
|
||||||
}
|
}
|
||||||
refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.OrderNo, order.Amount, orderPayTime, "")
|
refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.PaymentMerchant, order.OrderNo, order.Amount, orderPayTime, "")
|
||||||
if refundErr != nil {
|
if refundErr != nil {
|
||||||
logx.Error(refundErr)
|
logx.Error(refundErr)
|
||||||
return asynq.SkipRetry
|
return asynq.SkipRetry
|
||||||
|
|||||||
113
app/main/api/internal/service/1.md
Normal file
113
app/main/api/internal/service/1.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
首页
|
||||||
|
生活服务
|
||||||
|
垃圾分类问答
|
||||||
|
垃圾分类问答接口
|
||||||
|
158 13540
|
||||||
|
垃圾分类问答正常服务支持MCP
|
||||||
|
提供垃圾分类知识判断题,帮助用户掌握干湿垃圾、可回收物等分类标准。
|
||||||
|
会员免费・升级会员畅享160+免费接口,立即升级>>
|
||||||
|
收藏
|
||||||
|
普通会员
|
||||||
|
100次/天
|
||||||
|
高级会员
|
||||||
|
1W次/天
|
||||||
|
黄金会员
|
||||||
|
50W次/天
|
||||||
|
钻石会员
|
||||||
|
不限次数
|
||||||
|
|
||||||
|
▼ 接口文档
|
||||||
|
|
||||||
|
价格
|
||||||
|
|
||||||
|
返回示例
|
||||||
|
|
||||||
|
参考代码
|
||||||
|
|
||||||
|
MCP服务
|
||||||
|
|
||||||
|
帮助
|
||||||
|
|
||||||
|
生成小程序
|
||||||
|
垃圾分类问答判断题,每次调用接口返回一个废弃物名称及正确分类。
|
||||||
|
接入点列表:
|
||||||
|
|
||||||
|
垃圾分类问答
|
||||||
|
相关资源:
|
||||||
|
|
||||||
|
垃圾分类问答功能演示
|
||||||
|
▼ 接口信息
|
||||||
|
随机返回带结果的垃圾分类知识库
|
||||||
|
|
||||||
|
接口地址:https://apis.tianapi.com/anslajifenlei/index?key={apiKey}
|
||||||
|
支持协议:http/https
|
||||||
|
请求方法:get/post
|
||||||
|
返回格式:utf-8 json
|
||||||
|
▼ 请求参数
|
||||||
|
上传文件时请使用标准表单格式 multipart/form-data
|
||||||
|
|
||||||
|
普通参数请使用默认表单格式 application/x-www-form-urlencoded
|
||||||
|
|
||||||
|
当参数值(如url、base64)包含特殊字符时,建议urlencode编码后传递
|
||||||
|
|
||||||
|
名称 类型 必须 示例值/默认值 说明
|
||||||
|
key string 是 您自己的ApiKey(注册账号后获得) API密钥
|
||||||
|
▼ 返回示例
|
||||||
|
接口数据示例仅作为预览参考,请以实际测试结果为准
|
||||||
|
|
||||||
|
旧接口域名返回的数据结构和现在略有不同,请查看说明
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
成功调用,返回内容并产生计费:
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"msg": "success",
|
||||||
|
"code": 200,
|
||||||
|
"result": {
|
||||||
|
"name": "西红柿",
|
||||||
|
"type": 2,
|
||||||
|
"explain": "湿垃圾"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
失败调用,查看接口错误码释义:
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"code": 150,
|
||||||
|
"msg": "API可用次数不足"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
▼ 返回参数
|
||||||
|
公共参数指所有接口都会返回的参数,应用参数每个接口都不同
|
||||||
|
|
||||||
|
建议对返回的字段进行存在性与类型校验,可参考API安全接入指南
|
||||||
|
|
||||||
|
名称 类型 示例值 说明
|
||||||
|
公共参数
|
||||||
|
code int 200 状态码
|
||||||
|
msg string success 错误信息
|
||||||
|
result object {} 返回结果集
|
||||||
|
应用参数
|
||||||
|
name string 西红柿 垃圾物品
|
||||||
|
type int 2 垃圾分类,0为可回收、1为有害、2为厨余(湿)、3为其他(干)
|
||||||
|
explain string 湿垃圾 中文释义
|
||||||
|
▼ 接口价格
|
||||||
|
本接口为会员免费类接口,可根据业务需求选择升级会员方案>>
|
||||||
|
|
||||||
|
|
||||||
|
不同会员方案仅每日调用量等配额上限不同,数据本身无区别
|
||||||
|
|
||||||
|
|
||||||
|
会员方案 免费接口数 每日调用量 QPS 价格
|
||||||
|
普通会员 10个 100次 3 免费
|
||||||
|
高级会员 不限 1万次 20 29元/月、348元/年169元/年惠
|
||||||
|
黄金会员 不限 50万次 30 89元/月、1068元/年529元/年惠
|
||||||
|
钻石会员 不限 不限次 60 3380元/年1699元/年惠
|
||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -28,6 +28,28 @@ type AliPayService struct {
|
|||||||
AlipayClientBak *alipay.Client // 仅用于 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单的退款
|
AlipayClientBak *alipay.Client // 仅用于 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内订单的退款
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clientForMerchant 根据商户标识与订单时间选择对应的支付宝 client。
|
||||||
|
// - merchant == "two" 且 Bak 存在:优先返回 Bak;
|
||||||
|
// - merchant == "one" 或空:默认返回主商户;
|
||||||
|
// - merchant 为空且 orderPayTime 落在备份时间区间:兼容老订单,走 Bak。
|
||||||
|
func (a *AliPayService) clientForMerchant(merchant string, orderPayTime *time.Time) *alipay.Client {
|
||||||
|
// 显式指定 two,则优先走 Bak
|
||||||
|
if merchant == "two" && a.AlipayClientBak != nil {
|
||||||
|
return a.AlipayClientBak
|
||||||
|
}
|
||||||
|
// 显式指定 one 或其他未知标识,一律走主商户
|
||||||
|
if merchant == "one" || merchant == "" {
|
||||||
|
// 对于老订单未写入 merchant 的情况,继续保留时间区间兜底逻辑
|
||||||
|
if merchant == "" && orderPayTime != nil && a.AlipayClientBak != nil &&
|
||||||
|
!orderPayTime.Before(AlipayBakRefundStart) && orderPayTime.Before(AlipayBakRefundEnd) {
|
||||||
|
return a.AlipayClientBak
|
||||||
|
}
|
||||||
|
return a.AlipayClient
|
||||||
|
}
|
||||||
|
// 兜底:未知标识时仍走主商户,避免因为配置问题导致整体不可用
|
||||||
|
return a.AlipayClient
|
||||||
|
}
|
||||||
|
|
||||||
// NewAliPayService 是一个构造函数,用于初始化 AliPayService
|
// NewAliPayService 是一个构造函数,用于初始化 AliPayService
|
||||||
func NewAliPayService(c config.Config) *AliPayService {
|
func NewAliPayService(c config.Config) *AliPayService {
|
||||||
client, err := alipay.New(c.Alipay.AppID, c.Alipay.PrivateKey, c.Alipay.IsProduction)
|
client, err := alipay.New(c.Alipay.AppID, c.Alipay.PrivateKey, c.Alipay.IsProduction)
|
||||||
@@ -77,8 +99,8 @@ func NewAliPayService(c config.Config) *AliPayService {
|
|||||||
return svc
|
return svc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AliPayService) CreateAlipayAppOrder(amount float64, subject string, outTradeNo string) (string, error) {
|
func (a *AliPayService) CreateAlipayAppOrder(merchant string, amount float64, subject string, outTradeNo string) (string, error) {
|
||||||
client := a.AlipayClient
|
client := a.clientForMerchant(merchant, nil)
|
||||||
totalAmount := lzUtils.ToAlipayAmount(amount)
|
totalAmount := lzUtils.ToAlipayAmount(amount)
|
||||||
// 构造移动支付请求
|
// 构造移动支付请求
|
||||||
p := alipay.TradeAppPay{
|
p := alipay.TradeAppPay{
|
||||||
@@ -101,8 +123,8 @@ func (a *AliPayService) CreateAlipayAppOrder(amount float64, subject string, out
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateAlipayH5Order 创建支付宝H5支付订单
|
// CreateAlipayH5Order 创建支付宝H5支付订单
|
||||||
func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outTradeNo string) (string, error) {
|
func (a *AliPayService) CreateAlipayH5Order(merchant string, amount float64, subject string, outTradeNo string) (string, error) {
|
||||||
client := a.AlipayClient
|
client := a.clientForMerchant(merchant, nil)
|
||||||
totalAmount := lzUtils.ToAlipayAmount(amount)
|
totalAmount := lzUtils.ToAlipayAmount(amount)
|
||||||
// 构造H5支付请求
|
// 构造H5支付请求
|
||||||
p := alipay.TradeWapPay{
|
p := alipay.TradeWapPay{
|
||||||
@@ -124,8 +146,9 @@ func (a *AliPayService) CreateAlipayH5Order(amount float64, subject string, outT
|
|||||||
return payUrl.String(), nil
|
return payUrl.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAlipayOrder 根据平台类型创建支付宝支付订单
|
// CreateAlipayOrder 根据平台类型和商户标识创建支付宝支付订单
|
||||||
func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, subject string, outTradeNo string) (string, error) {
|
// merchant: 商户标识,目前约定 "one"=主商户, "two"=备商户
|
||||||
|
func (a *AliPayService) CreateAlipayOrder(ctx context.Context, merchant string, amount float64, subject string, outTradeNo string) (string, error) {
|
||||||
// 根据 ctx 中的 platform 判断平台
|
// 根据 ctx 中的 platform 判断平台
|
||||||
platform, platformOk := ctx.Value("platform").(string)
|
platform, platformOk := ctx.Value("platform").(string)
|
||||||
if !platformOk {
|
if !platformOk {
|
||||||
@@ -134,23 +157,21 @@ func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, s
|
|||||||
switch platform {
|
switch platform {
|
||||||
case model.PlatformApp:
|
case model.PlatformApp:
|
||||||
// 调用App支付的创建方法
|
// 调用App支付的创建方法
|
||||||
return a.CreateAlipayAppOrder(amount, subject, outTradeNo)
|
return a.CreateAlipayAppOrder(merchant, amount, subject, outTradeNo)
|
||||||
case model.PlatformH5:
|
case model.PlatformH5:
|
||||||
// 调用H5支付的创建方法,并传入 returnUrl
|
// 调用H5支付的创建方法,并传入 returnUrl
|
||||||
return a.CreateAlipayH5Order(amount, subject, outTradeNo)
|
return a.CreateAlipayH5Order(merchant, amount, subject, outTradeNo)
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("不支持的支付平台: %s", platform)
|
return "", fmt.Errorf("不支持的支付平台: %s", platform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AliRefund 发起支付宝退款。orderPayTime 为订单支付时间(或创建时间);仅当落在 [2026-01-25 16:38:17, 2026-02-02 18:26) 区间内时使用 bak 商户号,否则使用正式商户号;传 nil 则使用正式商户号。
|
// AliRefund 发起支付宝退款。
|
||||||
|
// merchant: 支付商户标识(one/two)。为空时按老逻辑仅在备份时间区间内使用 Bak。
|
||||||
|
// orderPayTime 为订单支付时间(或创建时间);用于老订单按时间区间选择商户;传 nil 则忽略时间区间。
|
||||||
// outRequestNo 为商户退款请求号,同一笔退款需唯一;传空则使用 "refund-"+outTradeNo,重试时建议传入唯一号避免支付宝报重复。
|
// outRequestNo 为商户退款请求号,同一笔退款需唯一;传空则使用 "refund-"+outTradeNo,重试时建议传入唯一号避免支付宝报重复。
|
||||||
func (a *AliPayService) AliRefund(ctx context.Context, outTradeNo string, refundAmount float64, orderPayTime *time.Time, outRequestNo string) (*alipay.TradeRefundRsp, error) {
|
func (a *AliPayService) AliRefund(ctx context.Context, merchant string, outTradeNo string, refundAmount float64, orderPayTime *time.Time, outRequestNo string) (*alipay.TradeRefundRsp, error) {
|
||||||
client := a.AlipayClient
|
client := a.clientForMerchant(merchant, orderPayTime)
|
||||||
if orderPayTime != nil && a.AlipayClientBak != nil &&
|
|
||||||
!orderPayTime.Before(AlipayBakRefundStart) && orderPayTime.Before(AlipayBakRefundEnd) {
|
|
||||||
client = a.AlipayClientBak
|
|
||||||
}
|
|
||||||
|
|
||||||
if outRequestNo == "" {
|
if outRequestNo == "" {
|
||||||
outRequestNo = fmt.Sprintf("refund-%s", outTradeNo)
|
outRequestNo = fmt.Sprintf("refund-%s", outTradeNo)
|
||||||
@@ -168,27 +189,26 @@ func (a *AliPayService) AliRefund(ctx context.Context, outTradeNo string, refund
|
|||||||
return refundResp, nil
|
return refundResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleAliPaymentNotification 支付宝支付回调
|
// HandleAliPaymentNotification 支付宝支付回调验签。
|
||||||
func (a *AliPayService) HandleAliPaymentNotification(r *http.Request) (*alipay.Notification, error) {
|
// 由上层根据 out_trade_no 查出订单并传入对应商户标识 merchant。
|
||||||
// 解析表单
|
func (a *AliPayService) HandleAliPaymentNotification(merchant string, form url.Values) (*alipay.Notification, error) {
|
||||||
err := r.ParseForm()
|
client := a.clientForMerchant(merchant, nil)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("解析请求表单失败:%v", err)
|
|
||||||
}
|
|
||||||
// 解析并验证通知,DecodeNotification 会自动验证签名
|
// 解析并验证通知,DecodeNotification 会自动验证签名
|
||||||
notification, err := a.AlipayClient.DecodeNotification(r.Form)
|
notification, err := client.DecodeNotification(form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("验证签名失败: %v", err)
|
return nil, fmt.Errorf("验证签名失败: %v", err)
|
||||||
}
|
}
|
||||||
return notification, nil
|
return notification, nil
|
||||||
}
|
}
|
||||||
func (a *AliPayService) QueryOrderStatus(ctx context.Context, outTradeNo string) (*alipay.TradeQueryRsp, error) {
|
// QueryOrderStatus 按商户标识查询支付宝订单状态
|
||||||
|
func (a *AliPayService) QueryOrderStatus(ctx context.Context, merchant string, outTradeNo string) (*alipay.TradeQueryRsp, error) {
|
||||||
|
client := a.clientForMerchant(merchant, nil)
|
||||||
queryRequest := alipay.TradeQuery{
|
queryRequest := alipay.TradeQuery{
|
||||||
OutTradeNo: outTradeNo,
|
OutTradeNo: outTradeNo,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发起查询请求
|
// 发起查询请求
|
||||||
resp, err := a.AlipayClient.TradeQuery(ctx, queryRequest)
|
resp, err := client.TradeQuery(ctx, queryRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("查询支付宝订单失败: %v", err)
|
return nil, fmt.Errorf("查询支付宝订单失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,15 +39,17 @@ type ApiRequestService struct {
|
|||||||
featureModel model.FeatureModel
|
featureModel model.FeatureModel
|
||||||
productFeatureModel model.ProductFeatureModel
|
productFeatureModel model.ProductFeatureModel
|
||||||
tianyuanapi *tianyuanapi.Client
|
tianyuanapi *tianyuanapi.Client
|
||||||
|
authService *AuthorizationService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApiRequestService 是一个构造函数,用于初始化 ApiRequestService
|
// NewApiRequestService 是一个构造函数,用于初始化 ApiRequestService
|
||||||
func NewApiRequestService(c config.Config, featureModel model.FeatureModel, productFeatureModel model.ProductFeatureModel, tianyuanapi *tianyuanapi.Client) *ApiRequestService {
|
func NewApiRequestService(c config.Config, featureModel model.FeatureModel, productFeatureModel model.ProductFeatureModel, tianyuanapi *tianyuanapi.Client, authService *AuthorizationService) *ApiRequestService {
|
||||||
return &ApiRequestService{
|
return &ApiRequestService{
|
||||||
config: c,
|
config: c,
|
||||||
featureModel: featureModel,
|
featureModel: featureModel,
|
||||||
productFeatureModel: productFeatureModel,
|
productFeatureModel: productFeatureModel,
|
||||||
tianyuanapi: tianyuanapi,
|
tianyuanapi: tianyuanapi,
|
||||||
|
authService: authService,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,10 +216,10 @@ var requestProcessors = map[string]func(*ApiRequestService, []byte) ([]byte, err
|
|||||||
"YYSY09CD": (*ApiRequestService).ProcessYYSY09CDRequest,
|
"YYSY09CD": (*ApiRequestService).ProcessYYSY09CDRequest,
|
||||||
"QCXGGB2Q": (*ApiRequestService).ProcessQCXGGB2QRequest,
|
"QCXGGB2Q": (*ApiRequestService).ProcessQCXGGB2QRequest,
|
||||||
"QCXGYTS2": (*ApiRequestService).ProcessQCXGYTS2Request,
|
"QCXGYTS2": (*ApiRequestService).ProcessQCXGYTS2Request,
|
||||||
"QCXG5F3A": (*ApiRequestService).ProcessQCXG5F3ARequest,
|
"QCXG5F3A": (*ApiRequestService).ProcessQCXG5F3ARequest, //内部替换名下
|
||||||
"FLXG0687": (*ApiRequestService).ProcessFLXG0687Request,
|
"FLXG0687": (*ApiRequestService).ProcessFLXG0687Request,
|
||||||
"FLXG3D56": (*ApiRequestService).ProcessFLXG3D56Request,
|
"FLXG3D56": (*ApiRequestService).ProcessFLXG3D56Request,
|
||||||
"FLXG0V4B": (*ApiRequestService).ProcesFLXG0V4BRequest,
|
"FLXG0V4B": (*ApiRequestService).ProcessFLXG0V4BRequest,
|
||||||
"QYGL8271": (*ApiRequestService).ProcessQYGL8271Request,
|
"QYGL8271": (*ApiRequestService).ProcessQYGL8271Request,
|
||||||
"IVYZ5733": (*ApiRequestService).ProcessIVYZ5733Request,
|
"IVYZ5733": (*ApiRequestService).ProcessIVYZ5733Request,
|
||||||
"IVYZ9A2B": (*ApiRequestService).ProcessIVYZ9A2BRequest,
|
"IVYZ9A2B": (*ApiRequestService).ProcessIVYZ9A2BRequest,
|
||||||
@@ -269,6 +271,9 @@ var requestProcessors = map[string]func(*ApiRequestService, []byte) ([]byte, err
|
|||||||
"QYGL66SL": (*ApiRequestService).ProcessQYGL66SLRequest,
|
"QYGL66SL": (*ApiRequestService).ProcessQYGL66SLRequest,
|
||||||
"FLXG3A9B": (*ApiRequestService).ProcessFLXG3A9BRequest,
|
"FLXG3A9B": (*ApiRequestService).ProcessFLXG3A9BRequest,
|
||||||
"QYGL2S0W": (*ApiRequestService).ProcessQYGL2S0WRequest,
|
"QYGL2S0W": (*ApiRequestService).ProcessQYGL2S0WRequest,
|
||||||
|
"FLXGDEA9": (*ApiRequestService).ProcessFLXGDEA9Request,
|
||||||
|
"IVYZ4Y27": (*ApiRequestService).ProcessIVYZ4Y27Request,
|
||||||
|
"IVYZ0S0D": (*ApiRequestService).ProcessIVYZ0S0DRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreprocessRequestApi 调用指定的请求处理函数
|
// PreprocessRequestApi 调用指定的请求处理函数
|
||||||
@@ -1505,6 +1510,23 @@ func (a *ApiRequestService) ProcessQYGL2S0WRequest(params []byte) ([]byte, error
|
|||||||
return a.processVerifyPassThrough(params, "QYGL2S0W")
|
return a.processVerifyPassThrough(params, "QYGL2S0W")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FLXGDEA9 本人不良
|
||||||
|
func (a *ApiRequestService) ProcessFLXGDEA9Request(params []byte) ([]byte, error) {
|
||||||
|
var m map[string]interface{}
|
||||||
|
if err := json.Unmarshal(params, &m); err != nil {
|
||||||
|
return nil, fmt.Errorf("api请求, FLXGDEA9, 解析参数失败: %w", err)
|
||||||
|
}
|
||||||
|
// 授权由后端默认传 1,前端与查询服务不再感知 authorized
|
||||||
|
if v, ok := m["authorized"]; !ok || v == "" {
|
||||||
|
m["authorized"] = "1"
|
||||||
|
}
|
||||||
|
resp, err := a.tianyuanapi.CallInterface("FLXGDEA9", m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return convertTianyuanResponse(resp)
|
||||||
|
}
|
||||||
|
|
||||||
// buildVehicleBody 从 params 中取 required 与 optional 键,仅非空才写入 body
|
// buildVehicleBody 从 params 中取 required 与 optional 键,仅非空才写入 body
|
||||||
func buildVehicleBody(params []byte, required, optional []string) map[string]interface{} {
|
func buildVehicleBody(params []byte, required, optional []string) map[string]interface{} {
|
||||||
body := make(map[string]interface{})
|
body := make(map[string]interface{})
|
||||||
@@ -1909,3 +1931,54 @@ func (a *ApiRequestService) ProcessQCXG9P1CFRequest(params []byte) ([]byte, erro
|
|||||||
|
|
||||||
return convertTianyuanResponse(resp)
|
return convertTianyuanResponse(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProcessIVYZ4Y27Request 学历信息查询(需生成专用授权书PDF并Base64编码传入)
|
||||||
|
func (a *ApiRequestService) ProcessIVYZ4Y27Request(params []byte) ([]byte, error) {
|
||||||
|
name := gjson.GetBytes(params, "name")
|
||||||
|
idCard := gjson.GetBytes(params, "id_card")
|
||||||
|
mobile := gjson.GetBytes(params, "mobile")
|
||||||
|
if !name.Exists() || !idCard.Exists() {
|
||||||
|
return nil, errors.New("api请求, IVYZ4Y27, 获取相关参数失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成专用授权书PDF并Base64编码
|
||||||
|
userInfo := map[string]interface{}{
|
||||||
|
"name": name.String(),
|
||||||
|
"id_card": idCard.String(),
|
||||||
|
"mobile": mobile.String(),
|
||||||
|
}
|
||||||
|
authFileBase64, err := a.authService.GenerateIVYZ4Y27AuthorizationBase64(userInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("生成IVYZ4Y27授权书失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := a.tianyuanapi.CallInterface("IVYZ4Y27", map[string]interface{}{
|
||||||
|
"name": name.String(),
|
||||||
|
"id_card": idCard.String(),
|
||||||
|
"auth_authorize_file_base64": authFileBase64,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertTianyuanResponse(resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessIVYZ0S0DRequest 劳动仲裁信息查询(个人版)
|
||||||
|
func (a *ApiRequestService) ProcessIVYZ0S0DRequest(params []byte) ([]byte, error) {
|
||||||
|
idCard := gjson.GetBytes(params, "id_card")
|
||||||
|
name := gjson.GetBytes(params, "name")
|
||||||
|
if !idCard.Exists() || !name.Exists() {
|
||||||
|
return nil, errors.New("api请求, IVYZ0S0D, 获取相关参数失败")
|
||||||
|
}
|
||||||
|
resp, err := a.tianyuanapi.CallInterface("IVYZ0S0D", map[string]interface{}{
|
||||||
|
"id_card": idCard.String(),
|
||||||
|
"name": name.String(),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertTianyuanResponse(resp)
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
"tyc-server/app/main/api/internal/config"
|
"tyc-server/app/main/api/internal/config"
|
||||||
"tyc-server/app/main/model"
|
"tyc-server/app/main/model"
|
||||||
@@ -329,3 +331,116 @@ func getUserInfoString(userInfo map[string]interface{}, key string) string {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateIVYZ4Y27AuthorizationBase64 生成IVYZ4Y27专用授权书PDF并返回Base64编码字符串
|
||||||
|
func (s *AuthorizationService) GenerateIVYZ4Y27AuthorizationBase64(userInfo map[string]interface{}) (string, error) {
|
||||||
|
name := getUserInfoString(userInfo, "name")
|
||||||
|
idCard := getUserInfoString(userInfo, "id_card")
|
||||||
|
if name == "" || idCard == "" {
|
||||||
|
return "", fmt.Errorf("缺少必要的用户信息(name或id_card)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建模板变量
|
||||||
|
data := map[string]string{
|
||||||
|
"CompanyName": "广西福铭网络科技有限公司",
|
||||||
|
"Name": name,
|
||||||
|
"IdCard": idCard,
|
||||||
|
"Mobile": getUserInfoString(userInfo, "mobile"),
|
||||||
|
"Date": time.Now().Format("2006年1月2日"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从模板生成PDF
|
||||||
|
pdfBytes, err := s.generatePDFFromTemplate("static/authorization_ivyz4y27.tmpl", data)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "生成IVYZ4Y27授权书PDF失败")
|
||||||
|
}
|
||||||
|
// Base64编码
|
||||||
|
return base64.StdEncoding.EncodeToString(pdfBytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// generatePDFFromTemplate 从模板生成PDF
|
||||||
|
func (s *AuthorizationService) generatePDFFromTemplate(templatePath string, data interface{}) ([]byte, error) {
|
||||||
|
// 1. 读取模板文件
|
||||||
|
tmplContent, err := os.ReadFile(templatePath)
|
||||||
|
if err != nil {
|
||||||
|
// 尝试从项目根目录读取
|
||||||
|
absPath, _ := filepath.Abs(templatePath)
|
||||||
|
if _, err := os.Stat(absPath); err == nil {
|
||||||
|
tmplContent, err = os.ReadFile(absPath)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "读取模板文件失败: %s", templatePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 解析并执行模板
|
||||||
|
tmpl, err := template.New("auth").Parse(string(tmplContent))
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "解析模板失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := tmpl.Execute(&buf, data); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "执行模板失败")
|
||||||
|
}
|
||||||
|
content := buf.String()
|
||||||
|
|
||||||
|
// 3. 创建PDF
|
||||||
|
pdf := gofpdf.New("P", "mm", "A4", "")
|
||||||
|
pdf.AddPage()
|
||||||
|
|
||||||
|
// 4. 加载中文字体
|
||||||
|
fontPaths := []string{
|
||||||
|
"static/SIMHEI.TTF",
|
||||||
|
"/app/static/SIMHEI.TTF",
|
||||||
|
"app/main/api/static/SIMHEI.TTF",
|
||||||
|
"../static/SIMHEI.TTF",
|
||||||
|
}
|
||||||
|
|
||||||
|
fontAdded := false
|
||||||
|
for _, fontPath := range fontPaths {
|
||||||
|
if _, err := os.Stat(fontPath); err == nil {
|
||||||
|
pdf.AddUTF8Font("ChineseFont", "", fontPath)
|
||||||
|
fontAdded = true
|
||||||
|
logx.Infof("generatePDFFromTemplate 成功加载字体: %s", fontPath)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fontAdded {
|
||||||
|
pdf.SetFont("ChineseFont", "", 12)
|
||||||
|
} else {
|
||||||
|
pdf.SetFont("Arial", "", 12)
|
||||||
|
logx.Errorf("generatePDFFromTemplate 未找到中文字体文件,使用默认Arial字体")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 写入内容
|
||||||
|
// 简单处理:按行分割并使用 MultiCell
|
||||||
|
lines := strings.Split(content, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.TrimSpace(line) == "" {
|
||||||
|
pdf.Ln(5)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// MultiCell 支持自动换行
|
||||||
|
pdf.MultiCell(0, 6, line, "", "L", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 添加水印 (简单实现:在页面中间添加浅灰色文字)
|
||||||
|
if fontAdded {
|
||||||
|
pdf.SetFont("ChineseFont", "", 40)
|
||||||
|
pdf.SetTextColor(220, 220, 220) // 非常浅的灰色
|
||||||
|
// 将坐标移动到页面中间附近,并旋转或倾斜(gofpdf 旋转比较复杂,这里简单放几个位置)
|
||||||
|
pdf.Text(40, 100, "仅供背景调查使用")
|
||||||
|
pdf.Text(40, 180, "仅供背景调查使用")
|
||||||
|
pdf.Text(40, 260, "仅供背景调查使用")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 输出PDF
|
||||||
|
var pdfBuf bytes.Buffer
|
||||||
|
if err := pdf.Output(&pdfBuf); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "输出PDF字节数组失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdfBuf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|||||||
150
app/main/api/internal/service/tianxingjuhe_sdk/client.go
Normal file
150
app/main/api/internal/service/tianxingjuhe_sdk/client.go
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
package tianxingjuhe
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client 天行聚合API客户端
|
||||||
|
type Client struct {
|
||||||
|
baseURL string
|
||||||
|
key string
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config 客户端配置
|
||||||
|
type Config struct {
|
||||||
|
BaseURL string // API基础URL
|
||||||
|
Key string // API密钥
|
||||||
|
Timeout int // 超时时间(秒)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response 通用API响应结构
|
||||||
|
type Response struct {
|
||||||
|
Code int `json:"code"` // 状态码,200表示成功
|
||||||
|
Msg string `json:"msg"` // 返回说明
|
||||||
|
Result interface{} `json:"result"` // 返回结果集,具体内容根据接口而定
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient 创建新的客户端实例
|
||||||
|
func NewClient(config Config) (*Client, error) {
|
||||||
|
if config.BaseURL == "" {
|
||||||
|
return nil, fmt.Errorf("baseURL不能为空")
|
||||||
|
}
|
||||||
|
if config.Key == "" {
|
||||||
|
return nil, fmt.Errorf("key不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
baseURL: config.BaseURL,
|
||||||
|
key: config.Key,
|
||||||
|
client: &http.Client{
|
||||||
|
Timeout: time.Duration(config.Timeout) * time.Second,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 发送GET请求
|
||||||
|
func (c *Client) Get(endpoint string, params map[string]interface{}) (*Response, error) {
|
||||||
|
// 构建完整URL
|
||||||
|
fullURL := fmt.Sprintf("%s/%s", c.baseURL, endpoint)
|
||||||
|
|
||||||
|
// 添加请求参数
|
||||||
|
queryParams := url.Values{}
|
||||||
|
for key, value := range params {
|
||||||
|
queryParams.Set(key, fmt.Sprintf("%v", value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加key参数
|
||||||
|
queryParams.Set("key", c.key)
|
||||||
|
|
||||||
|
// 拼接查询参数
|
||||||
|
if len(queryParams) > 0 {
|
||||||
|
fullURL = fmt.Sprintf("%s?%s", fullURL, queryParams.Encode())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建HTTP请求
|
||||||
|
req, err := http.NewRequest("GET", fullURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("User-Agent", "Tianxingjuhe-Go-SDK/1.0.0")
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
resp, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 读取响应
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
var apiResp Response
|
||||||
|
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||||
|
return nil, fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apiResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post 发送POST请求
|
||||||
|
func (c *Client) Post(endpoint string, params map[string]interface{}) (*Response, error) {
|
||||||
|
// 构建完整URL
|
||||||
|
fullURL := fmt.Sprintf("%s/%s", c.baseURL, endpoint)
|
||||||
|
|
||||||
|
// 添加key参数
|
||||||
|
if params == nil {
|
||||||
|
params = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
params["key"] = c.key
|
||||||
|
|
||||||
|
// 序列化请求体
|
||||||
|
requestBody, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("序列化请求体失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建HTTP请求
|
||||||
|
req, err := http.NewRequest("POST", fullURL, bytes.NewBuffer(requestBody))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("创建HTTP请求失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置请求头
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("User-Agent", "Tianxingjuhe-Go-SDK/1.0.0")
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
resp, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("发送HTTP请求失败: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 读取响应
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
var apiResp Response
|
||||||
|
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||||
|
return nil, fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &apiResp, nil
|
||||||
|
}
|
||||||
8276
app/main/api/internal/service/toolboxService.go
Normal file
8276
app/main/api/internal/service/toolboxService.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,11 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tyc-server/app/main/api/internal/config"
|
"tyc-server/app/main/api/internal/config"
|
||||||
"tyc-server/app/main/model"
|
"tyc-server/app/main/model"
|
||||||
@@ -24,6 +26,14 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// wxpayAPIHTTPStatus 安全读取微信支付 API 的 HTTP 状态码;本地签名/随机串失败时 result 可能为 nil。
|
||||||
|
func wxpayAPIHTTPStatus(result *core.APIResult) int {
|
||||||
|
if result == nil || result.Response == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return result.Response.StatusCode
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TradeStateSuccess = "SUCCESS" // 支付成功
|
TradeStateSuccess = "SUCCESS" // 支付成功
|
||||||
TradeStateRefund = "REFUND" // 转入退款
|
TradeStateRefund = "REFUND" // 转入退款
|
||||||
@@ -172,14 +182,54 @@ func (w *WechatPayService) CreateWechatAppOrder(ctx context.Context, amount floa
|
|||||||
|
|
||||||
// 发起预支付请求
|
// 发起预支付请求
|
||||||
resp, result, err := svc.Prepay(ctx, payRequest)
|
resp, result, err := svc.Prepay(ctx, payRequest)
|
||||||
|
logx.Infof("微信app支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, wxpayAPIHTTPStatus(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回预支付交易会话标识
|
// 返回预支付交易会话标识
|
||||||
return *resp.PrepayId, nil
|
return *resp.PrepayId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// jsapiRequestPaymentToMap 将 JSAPI 调起参数转为 map[string]string,便于 JSON 序列化给前端 WeixinJSBridge
|
||||||
|
func jsapiRequestPaymentToMap(resp *jsapi.PrepayWithRequestPaymentResponse) (map[string]string, error) {
|
||||||
|
if resp == nil {
|
||||||
|
return nil, fmt.Errorf("微信下单返回为空")
|
||||||
|
}
|
||||||
|
m := map[string]string{}
|
||||||
|
if resp.Appid != nil {
|
||||||
|
m["appId"] = *resp.Appid
|
||||||
|
}
|
||||||
|
if resp.TimeStamp != nil {
|
||||||
|
m["timeStamp"] = *resp.TimeStamp
|
||||||
|
}
|
||||||
|
if resp.NonceStr != nil {
|
||||||
|
m["nonceStr"] = *resp.NonceStr
|
||||||
|
}
|
||||||
|
if resp.Package != nil {
|
||||||
|
m["package"] = *resp.Package
|
||||||
|
}
|
||||||
|
if resp.SignType != nil && *resp.SignType != "" {
|
||||||
|
m["signType"] = *resp.SignType
|
||||||
|
} else {
|
||||||
|
m["signType"] = "RSA"
|
||||||
|
}
|
||||||
|
if resp.PaySign != nil {
|
||||||
|
m["paySign"] = *resp.PaySign
|
||||||
|
}
|
||||||
|
var missing []string
|
||||||
|
for _, key := range []string{"appId", "timeStamp", "nonceStr", "package", "paySign"} {
|
||||||
|
if m[key] == "" {
|
||||||
|
missing = append(missing, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missing) > 0 {
|
||||||
|
logx.Errorf("[WechatPay] JSAPI 调起参数缺项: missing=%v resp=%s", missing, resp.String())
|
||||||
|
return nil, fmt.Errorf("微信 JSAPI 调起参数不完整: 缺少或为空 %v", missing)
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateWechatMiniProgramOrder 创建微信小程序支付订单
|
// CreateWechatMiniProgramOrder 创建微信小程序支付订单
|
||||||
func (w *WechatPayService) CreateWechatMiniProgramOrder(ctx context.Context, amount float64, description string, outTradeNo string, openid string) (interface{}, error) {
|
func (w *WechatPayService) CreateWechatMiniProgramOrder(ctx context.Context, amount float64, description string, outTradeNo string, openid string) (interface{}, error) {
|
||||||
totalAmount := lzUtils.ToWechatAmount(amount)
|
totalAmount := lzUtils.ToWechatAmount(amount)
|
||||||
@@ -203,17 +253,18 @@ func (w *WechatPayService) CreateWechatMiniProgramOrder(ctx context.Context, amo
|
|||||||
|
|
||||||
// 发起预支付请求
|
// 发起预支付请求
|
||||||
resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
|
resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
|
||||||
|
logx.Infof("微信小程序支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, wxpayAPIHTTPStatus(result))
|
||||||
}
|
}
|
||||||
// 返回预支付交易会话标识
|
return jsapiRequestPaymentToMap(resp)
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateWechatH5Order 创建微信H5支付订单
|
// CreateWechatH5Order 创建微信H5支付订单
|
||||||
func (w *WechatPayService) CreateWechatH5Order(ctx context.Context, amount float64, description string, outTradeNo string, openid string) (interface{}, error) {
|
func (w *WechatPayService) CreateWechatH5Order(ctx context.Context, amount float64, description string, outTradeNo string, openid string) (interface{}, error) {
|
||||||
totalAmount := lzUtils.ToWechatAmount(amount)
|
totalAmount := lzUtils.ToWechatAmount(amount)
|
||||||
|
|
||||||
|
logx.Infof("微信h5支付订单:amount: %+v, description: %+v, outTradeNo: %+v, openid: %+v", amount, description, outTradeNo, openid)
|
||||||
// 构建支付请求参数
|
// 构建支付请求参数
|
||||||
payRequest := jsapi.PrepayRequest{
|
payRequest := jsapi.PrepayRequest{
|
||||||
Appid: core.String(w.config.WechatH5.AppID),
|
Appid: core.String(w.config.WechatH5.AppID),
|
||||||
@@ -231,20 +282,31 @@ func (w *WechatPayService) CreateWechatH5Order(ctx context.Context, amount float
|
|||||||
// 初始化 AppApiService
|
// 初始化 AppApiService
|
||||||
svc := jsapi.JsapiApiService{Client: w.wechatClient}
|
svc := jsapi.JsapiApiService{Client: w.wechatClient}
|
||||||
|
|
||||||
|
logx.Infof("微信h5支付订单:payRequest: %+v", payRequest)
|
||||||
// 发起预支付请求
|
// 发起预支付请求
|
||||||
resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
|
resp, result, err := svc.PrepayWithRequestPayment(ctx, payRequest)
|
||||||
logx.Infof("微信h5支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
logx.Infof("微信h5支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
logx.Infof("微信h5支付订单:resp: %+v, result: %+v, err: %+v", resp, result, err)
|
||||||
|
return "", fmt.Errorf("微信支付订单创建失败: %v, 状态码: %d", err, wxpayAPIHTTPStatus(result))
|
||||||
}
|
}
|
||||||
// 返回预支付交易会话标识
|
return jsapiRequestPaymentToMap(resp)
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateWechatOrder 创建微信支付订单(集成 APP、H5、小程序)
|
// CreateWechatOrder 创建微信支付订单(集成 APP、H5、小程序)
|
||||||
func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64, description string, outTradeNo string) (interface{}, error) {
|
func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64, description string, outTradeNo string) (interface{}, error) {
|
||||||
// 根据 ctx 中的 platform 判断平台
|
platformVal := ctx.Value("platform")
|
||||||
platform := ctx.Value("platform").(string)
|
platform, ok := platformVal.(string)
|
||||||
|
rawPlatform := platform
|
||||||
|
platform = strings.TrimSpace(platform)
|
||||||
|
logx.WithContext(ctx).Infof(
|
||||||
|
"[WechatPay] CreateWechatOrder platform ctx: value_type=%T assert_ok=%v raw=%q trimmed=%q ref_wxh5=%q ref_wxmini=%q ref_app=%q out_trade_no=%s",
|
||||||
|
platformVal, ok, rawPlatform, platform, model.PlatformWxH5, model.PlatformWxMini, model.PlatformApp, outTradeNo,
|
||||||
|
)
|
||||||
|
if !ok || platform == "" {
|
||||||
|
logx.WithContext(ctx).Errorf("[WechatPay] CreateWechatOrder 缺少 X-Platform")
|
||||||
|
return "", fmt.Errorf("缺少 X-Platform 请求头(微信内请传 wxh5)")
|
||||||
|
}
|
||||||
|
|
||||||
var prepayData interface{}
|
var prepayData interface{}
|
||||||
var err error
|
var err error
|
||||||
@@ -264,15 +326,33 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
case model.PlatformWxH5:
|
case model.PlatformWxH5:
|
||||||
|
logx.WithContext(ctx).Infof(
|
||||||
|
"[WechatPay] CreateWechatOrder branch=wxh5 out_trade_no=%s amount=%.2f desc_len=%d",
|
||||||
|
outTradeNo, amount, len(description),
|
||||||
|
)
|
||||||
userID, getUidErr := ctxdata.GetUidFromCtx(ctx)
|
userID, getUidErr := ctxdata.GetUidFromCtx(ctx)
|
||||||
if getUidErr != nil {
|
if getUidErr != nil {
|
||||||
return "", getUidErr
|
return "", getUidErr
|
||||||
}
|
}
|
||||||
userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5OpenID)
|
// 微信内置浏览器 JSAPI 必须使用与商户公众号一致的 openid(snsapi_base / snsapi_userinfo 授权后写入 wxh5_openid)。
|
||||||
if findAuthModelErr != nil {
|
// 不可使用小程序 openid 兜底:AppID 与 openid 主体不一致会导致下单失败或调起异常。
|
||||||
return "", findAuthModelErr
|
h5Auth, h5Err := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5OpenID)
|
||||||
|
if h5Err != nil {
|
||||||
|
if errors.Is(h5Err, model.ErrNotFound) {
|
||||||
|
logx.WithContext(ctx).Infof(
|
||||||
|
"[WechatPay] wxh5 缺少 user_auth(wxh5_openid) user_id=%d out_trade_no=%s,需先走公众号网页授权(建议 scope=snsapi_base)",
|
||||||
|
userID, outTradeNo,
|
||||||
|
)
|
||||||
|
return "", fmt.Errorf("微信内支付需先完成公众号网页授权以获取 openid(建议使用 snsapi_base 静默授权)")
|
||||||
|
}
|
||||||
|
return "", h5Err
|
||||||
}
|
}
|
||||||
prepayData, err = w.CreateWechatH5Order(ctx, amount, description, outTradeNo, userAuthModel.AuthKey)
|
if strings.TrimSpace(h5Auth.AuthKey) == "" {
|
||||||
|
logx.WithContext(ctx).Errorf("[WechatPay] wxh5_openid 记录存在但 auth_key 为空 user_id=%d", userID)
|
||||||
|
return "", fmt.Errorf("微信内支付 openid 未就绪,请重新完成公众号网页授权")
|
||||||
|
}
|
||||||
|
logx.Infof("微信h5支付订单:userAuthModel(wxh5): %+v", h5Auth)
|
||||||
|
prepayData, err = w.CreateWechatH5Order(ctx, amount, description, outTradeNo, strings.TrimSpace(h5Auth.AuthKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -288,6 +368,21 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64
|
|||||||
return "", fmt.Errorf("支付订单创建失败: %v", err)
|
return "", fmt.Errorf("支付订单创建失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if prepayData == nil {
|
||||||
|
logx.WithContext(ctx).Errorf("[WechatPay] CreateWechatOrder 返回 prepayData 为 nil platform=%q", platform)
|
||||||
|
return nil, fmt.Errorf("微信支付返回数据为空 platform=%s", platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, isMap := prepayData.(map[string]string); isMap {
|
||||||
|
keys := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
logx.WithContext(ctx).Infof("[WechatPay] CreateWechatOrder return prepay: platform=%q type=map[string]string len=%d keys=%v", platform, len(m), keys)
|
||||||
|
} else {
|
||||||
|
logx.WithContext(ctx).Infof("[WechatPay] CreateWechatOrder return prepay: platform=%q type=%T", platform, prepayData)
|
||||||
|
}
|
||||||
|
|
||||||
// 返回预支付ID
|
// 返回预支付ID
|
||||||
return prepayData, nil
|
return prepayData, nil
|
||||||
}
|
}
|
||||||
@@ -323,7 +418,7 @@ func (w *WechatPayService) QueryOrderStatus(ctx context.Context, transactionID s
|
|||||||
Mchid: core.String(w.config.Wxpay.MchID),
|
Mchid: core.String(w.config.Wxpay.MchID),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("订单查询失败: %v, 状态码: %d", err, result.Response.StatusCode)
|
return nil, fmt.Errorf("订单查询失败: %v, 状态码: %d", err, wxpayAPIHTTPStatus(result))
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"tyc-server/app/main/api/internal/config"
|
"tyc-server/app/main/api/internal/config"
|
||||||
"tyc-server/app/main/api/internal/middleware"
|
"tyc-server/app/main/api/internal/middleware"
|
||||||
"tyc-server/app/main/api/internal/service"
|
"tyc-server/app/main/api/internal/service"
|
||||||
|
tianxingjuhe "tyc-server/app/main/api/internal/service/tianxingjuhe_sdk"
|
||||||
tianyuanapi "tyc-server/app/main/api/internal/service/tianyuanapi_sdk"
|
tianyuanapi "tyc-server/app/main/api/internal/service/tianyuanapi_sdk"
|
||||||
"tyc-server/app/main/model"
|
"tyc-server/app/main/model"
|
||||||
|
|
||||||
@@ -101,6 +102,8 @@ type ServiceContext struct {
|
|||||||
AdminPromotionLinkStatsService *service.AdminPromotionLinkStatsService
|
AdminPromotionLinkStatsService *service.AdminPromotionLinkStatsService
|
||||||
ImageService *service.ImageService
|
ImageService *service.ImageService
|
||||||
AuthorizationService *service.AuthorizationService
|
AuthorizationService *service.AuthorizationService
|
||||||
|
ToolboxService *service.ToolboxService
|
||||||
|
TianxingjuheService *tianxingjuhe.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServiceContext 创建服务上下文
|
// NewServiceContext 创建服务上下文
|
||||||
@@ -188,13 +191,22 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
logx.Errorf("初始化天远API失败: %+v", err)
|
logx.Errorf("初始化天远API失败: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化天行聚合API客户端
|
||||||
|
tianxingjuhe, err := tianxingjuhe.NewClient(tianxingjuhe.Config{
|
||||||
|
BaseURL: c.Tianxingjuhe.URL,
|
||||||
|
Key: c.Tianxingjuhe.Key,
|
||||||
|
Timeout: c.Tianxingjuhe.Timeout,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("初始化天行聚合API失败: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// ============================== 业务服务初始化 ==============================
|
// ============================== 业务服务初始化 ==============================
|
||||||
alipayService := service.NewAliPayService(c)
|
alipayService := service.NewAliPayService(c)
|
||||||
// wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypeWxPayPubKey)
|
wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypeWxPayPubKey)
|
||||||
// 为暂时关闭微信支付,将 WechatPayService 置为 nil,避免在项目启动时初始化微信支付相关配置
|
|
||||||
var wechatPayService *service.WechatPayService
|
|
||||||
applePayService := service.NewApplePayService(c)
|
applePayService := service.NewApplePayService(c)
|
||||||
apiRequestService := service.NewApiRequestService(c, featureModel, productFeatureModel, tianyuanapi)
|
authorizationService := service.NewAuthorizationService(c, authorizationDocumentModel)
|
||||||
|
apiRequestService := service.NewApiRequestService(c, featureModel, productFeatureModel, tianyuanapi, authorizationService)
|
||||||
verificationService := service.NewVerificationService(c, tianyuanapi, apiRequestService)
|
verificationService := service.NewVerificationService(c, tianyuanapi, apiRequestService)
|
||||||
asynqService := service.NewAsynqService(c)
|
asynqService := service.NewAsynqService(c)
|
||||||
agentService := service.NewAgentService(c, orderModel, agentModel, agentAuditModel, agentClosureModel,
|
agentService := service.NewAgentService(c, orderModel, agentModel, agentAuditModel, agentClosureModel,
|
||||||
@@ -207,7 +219,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
adminPromotionLinkStatsService := service.NewAdminPromotionLinkStatsService(adminPromotionLinkModel,
|
adminPromotionLinkStatsService := service.NewAdminPromotionLinkStatsService(adminPromotionLinkModel,
|
||||||
adminPromotionLinkStatsTotalModel, adminPromotionLinkStatsHistoryModel)
|
adminPromotionLinkStatsTotalModel, adminPromotionLinkStatsHistoryModel)
|
||||||
imageService := service.NewImageService()
|
imageService := service.NewImageService()
|
||||||
authorizationService := service.NewAuthorizationService(c, authorizationDocumentModel)
|
toolboxService := service.NewToolboxService(tianxingjuhe)
|
||||||
|
tianxingjuheService := tianxingjuhe
|
||||||
|
|
||||||
// ============================== 异步任务服务 ==============================
|
// ============================== 异步任务服务 ==============================
|
||||||
asynqServer := asynq.NewServer(
|
asynqServer := asynq.NewServer(
|
||||||
@@ -223,8 +236,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
|
|
||||||
// ============================== 返回服务上下文 ==============================
|
// ============================== 返回服务上下文 ==============================
|
||||||
return &ServiceContext{
|
return &ServiceContext{
|
||||||
Config: c,
|
Config: c,
|
||||||
Redis: redisClient,
|
Redis: redisClient,
|
||||||
AuthInterceptor: middleware.NewAuthInterceptorMiddleware(c).Handle,
|
AuthInterceptor: middleware.NewAuthInterceptorMiddleware(c).Handle,
|
||||||
UserAuthInterceptor: middleware.NewUserAuthInterceptorMiddleware().Handle,
|
UserAuthInterceptor: middleware.NewUserAuthInterceptorMiddleware().Handle,
|
||||||
UserDisableInterceptor: middleware.NewUserDisableInterceptorMiddleware(userModel).Handle,
|
UserDisableInterceptor: middleware.NewUserDisableInterceptorMiddleware(userModel).Handle,
|
||||||
@@ -306,6 +319,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
AdminPromotionLinkStatsService: adminPromotionLinkStatsService,
|
AdminPromotionLinkStatsService: adminPromotionLinkStatsService,
|
||||||
ImageService: imageService,
|
ImageService: imageService,
|
||||||
AuthorizationService: authorizationService,
|
AuthorizationService: authorizationService,
|
||||||
|
ToolboxService: toolboxService,
|
||||||
|
TianxingjuheService: tianxingjuheService,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,12 +45,10 @@ type PreLoanBackgroundCheckReq struct {
|
|||||||
Code string `json:"code" validate:"required"`
|
Code string `json:"code" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BackgroundCheck 查询请求结构
|
|
||||||
type BackgroundCheckReq struct {
|
type BackgroundCheckReq struct {
|
||||||
Name string `json:"name" validate:"required,name"`
|
Name string `json:"name" validate:"required,name"`
|
||||||
IDCard string `json:"id_card" validate:"required,idCard"`
|
IDCard string `json:"id_card" validate:"required,idCard"`
|
||||||
Mobile string `json:"mobile" validate:"required,mobile"`
|
Mobile string `json:"mobile" validate:"required,mobile"`
|
||||||
Code string `json:"code" validate:"required"`
|
|
||||||
}
|
}
|
||||||
type PersonalDataReq struct {
|
type PersonalDataReq struct {
|
||||||
Name string `json:"name" validate:"required,name"`
|
Name string `json:"name" validate:"required,name"`
|
||||||
@@ -85,6 +83,12 @@ type DishonestExecutedReq struct {
|
|||||||
IDCard string `json:"id_card" validate:"required,idCard"`
|
IDCard string `json:"id_card" validate:"required,idCard"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PersonalBadRecord 本人不良(FLXGDEA9):姓名 + 身份证(授权由 ApiRequest 默认传 1)
|
||||||
|
type PersonalBadRecordReq struct {
|
||||||
|
Name string `json:"name" validate:"required,name"`
|
||||||
|
IDCard string `json:"id_card" validate:"required,idCard"`
|
||||||
|
}
|
||||||
|
|
||||||
// TocPersonEnterprisePro 人企关系加强版预查询:仅身份证号
|
// TocPersonEnterprisePro 人企关系加强版预查询:仅身份证号
|
||||||
type TocPersonEnterpriseProReq struct {
|
type TocPersonEnterpriseProReq struct {
|
||||||
IDCard string `json:"id_card" validate:"required,idCard"`
|
IDCard string `json:"id_card" validate:"required,idCard"`
|
||||||
|
|||||||
@@ -1547,6 +1547,10 @@ type GetCommissionResp struct {
|
|||||||
List []Commission `json:"list"` // 查询列表
|
List []Commission `json:"list"` // 查询列表
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetEncryptedSceneIdResp struct {
|
||||||
|
EncryptedSceneId string `json:"encryptedSceneId"`
|
||||||
|
}
|
||||||
|
|
||||||
type GetLinkDataReq struct {
|
type GetLinkDataReq struct {
|
||||||
LinkIdentifier string `form:"link_identifier"`
|
LinkIdentifier string `form:"link_identifier"`
|
||||||
}
|
}
|
||||||
@@ -1847,7 +1851,7 @@ type PaymentCheckResp struct {
|
|||||||
|
|
||||||
type PaymentReq struct {
|
type PaymentReq struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
PayMethod string `json:"pay_method"`
|
PayMethod string `json:"pay_method" validate:"required,oneof=wechat alipay appleiap test"`
|
||||||
PayType string `json:"pay_type" validate:"required,oneof=query agent_vip"`
|
PayType string `json:"pay_type" validate:"required,oneof=query agent_vip"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2013,8 +2017,9 @@ type QueryItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QueryListReq struct {
|
type QueryListReq struct {
|
||||||
Page int64 `form:"page"` // 页码
|
Page int64 `form:"page"` // 页码
|
||||||
PageSize int64 `form:"page_size"` // 每页数据量
|
PageSize int64 `form:"page_size"` // 每页数据量
|
||||||
|
Source string `form:"source,optional"` // 来源: miniapp 小程序过滤非车辆产品
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryListResp struct {
|
type QueryListResp struct {
|
||||||
@@ -2050,10 +2055,11 @@ type QueryRetryResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QueryServiceReq struct {
|
type QueryServiceReq struct {
|
||||||
Product string `path:"product"`
|
Product string `path:"product"`
|
||||||
Data string `json:"data" validate:"required"`
|
Data string `json:"data" validate:"required"`
|
||||||
AgentIdentifier string `json:"agent_identifier,optional"`
|
AgentIdentifier string `json:"agent_identifier,optional"`
|
||||||
App bool `json:"app,optional"`
|
App bool `json:"app,optional"`
|
||||||
|
CaptchaVerifyParam string `json:"captchaVerifyParam,optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryServiceResp struct {
|
type QueryServiceResp struct {
|
||||||
@@ -2129,6 +2135,26 @@ type TimeRangeReport struct {
|
|||||||
Report int `json:"report"` // 报告量
|
Report int `json:"report"` // 报告量
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ToolboxQueryReq struct {
|
||||||
|
ToolKey string `json:"tool_key" validate:"required"`
|
||||||
|
Params map[string]interface{} `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolboxQueryResp struct {
|
||||||
|
ToolKey string `json:"tool_key"`
|
||||||
|
Result map[string]interface{} `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolInfo struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToolboxListResp struct {
|
||||||
|
Tools []ToolInfo `json:"tools"`
|
||||||
|
}
|
||||||
|
|
||||||
type UpdateMenuReq struct {
|
type UpdateMenuReq struct {
|
||||||
Id int64 `path:"id"` // 菜单ID
|
Id int64 `path:"id"` // 菜单ID
|
||||||
Pid int64 `json:"pid,optional"` // 父菜单ID
|
Pid int64 `json:"pid,optional"` // 父菜单ID
|
||||||
@@ -2245,6 +2271,7 @@ type GetAppVersionResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SendSmsReq struct {
|
type SendSmsReq struct {
|
||||||
Mobile string `json:"mobile" validate:"required,mobile"`
|
Mobile string `json:"mobile" validate:"required,mobile"`
|
||||||
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"`
|
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"`
|
||||||
|
CaptchaVerifyParam string `json:"captchaVerifyParam"`
|
||||||
}
|
}
|
||||||
|
|||||||
85
app/main/api/static/authorization_ivyz4y27.tmpl
Normal file
85
app/main/api/static/authorization_ivyz4y27.tmpl
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
【重要提示】为了保障您的合法权益,您在签署本授权书前,应当确保您为具有完全民事权利能力和民事行为能力的自然人,并审慎阅读、充分理解本授权书所有条款(特别是加粗字体的条款)。您在操作页面上的确认、勾选等行为或以其他方式接受即表示您已阅读并同意本授权书,本授权书随即在法律上生效并在您和{{.CompanyName}}之间产生法律约束力。
|
||||||
|
|
||||||
|
个人信息处理授权书
|
||||||
|
|
||||||
|
致:{{.CompanyName}}
|
||||||
|
|
||||||
|
本人("授权人")在此确认、同意并授权{{.CompanyName}}("贵司")及贵司授权的第三方,为本文件所列之目的,处理(指收集、整理、存储、使用、加工、分析和比对、核验、传输、提供等)本人的个人信息。
|
||||||
|
|
||||||
|
一、 授权处理的个人信息范围
|
||||||
|
|
||||||
|
1.本人同意并授权贵司处理以下类型的个人信息(无论以电子或非电子形式存在):
|
||||||
|
|
||||||
|
身份信息:包括但不限于姓名、身份证号码。
|
||||||
|
|
||||||
|
教育背景信息:包括但不限于各教育阶段的入学与毕业时间、毕业院校、专业、学位类型、学历学位证书信息、学信网验证信息等。
|
||||||
|
|
||||||
|
婚姻家庭信息:包括但不限于婚姻状况(未婚、已婚、离异等)。
|
||||||
|
|
||||||
|
工作履历信息:包括但不限于过往及当前工作单位、任职时间、职位、职责、证明人及其联系方式等。
|
||||||
|
|
||||||
|
其他与背景调查相关的信息:贵司为完成背景调查认为必要的其他信息。
|
||||||
|
|
||||||
|
2.本人知悉且同意,贵司拟处理的数据信息可能包含身份证件信息、生物识别信息等敏感信息,本人明确知悉对本人权益的影响且同意贵司处理该等信息。
|
||||||
|
|
||||||
|
二、 信息来源与查询方式
|
||||||
|
|
||||||
|
本人知晓并同意,贵司为完成背景调查,将通过以下方式查询并核实本授权书第一条所列的个人信息:
|
||||||
|
|
||||||
|
1. 通过本人或委托贵司开展背景调查的拟入职机构提供的联系方式和证明材料进行直接核实。
|
||||||
|
|
||||||
|
2. 通过贵司链接的权威数据源进行查询或验证、核实,包括但不限于政府部门或事业单位、社会团体、公用事业服务单位、第三方数据库或数据平台(如从中国高等教育学生信息网-学信网)等。本人授权贵司通过地方信用服务平台向前述数据源单位收集、处理、加工和分析本人的婚姻家庭信息、教育背景信息。
|
||||||
|
|
||||||
|
3. 通过向本人前任及现任雇主、同事、证明人等进行访谈核实。
|
||||||
|
|
||||||
|
4. 在法律允许的范围内,通过其他公开、合法的渠道进行核实。
|
||||||
|
|
||||||
|
三、 信息处理的目的与使用
|
||||||
|
|
||||||
|
本人同意贵司将本授权书项下收集的个人信息用于以下目的:
|
||||||
|
|
||||||
|
1. 为{{.CompanyName}}("委托方")对本人进行的员工招聘/录用前背景调查/持续的尽职调查提供信息核实与报告服务。
|
||||||
|
|
||||||
|
2. 基于核实的信息,生成关于本人的《背景调查报告》或《尽职调查报告》("报告"),并提供给委托方,以供其评估本人的任职资格与工作能力。
|
||||||
|
|
||||||
|
3. 贵司为内部质量控制和合规目的而对相关信息进行留存、处理与管理。
|
||||||
|
|
||||||
|
四、 信息存储与保护
|
||||||
|
|
||||||
|
贵司承诺将采取必要的技术和管理措施,保护本人个人信息的安全性与机密性,防止信息丢失、泄露、篡改或毁损。
|
||||||
|
|
||||||
|
除非法律法规另有规定或为履行本授权书目的之必要,贵司处理及存储本人个人信息的时间将在完成本次背景调查目的后12个月内,或直至委托方与本人的劳动关系确立或明确终止之时。具体留存期限届满后,贵司将依法对相关信息进行删除或匿名化处理。删除个人信息从技术上难以实现的,贵司将停止除存储和采取必要的安全保护措施之外的处理。
|
||||||
|
|
||||||
|
五、 授权转移与共享
|
||||||
|
|
||||||
|
(一)本人知晓并同意,为实现本授权书之目的,贵司可能将本人的个人信息提供给以下接收方:
|
||||||
|
|
||||||
|
1. 委托方(即本次背景调查的发起企业/拟入职机构)。
|
||||||
|
|
||||||
|
2. 为完成特定核实工作而必需的第三方合作伙伴,如数据源提供方(包括但不限于地方融资信用服务平台、政府部门或事业单位)等,但贵司应确保该等第三方受到与本授权书同等严格的保密义务约束。
|
||||||
|
|
||||||
|
六、 权利告知与行使
|
||||||
|
|
||||||
|
1.本人知悉并理解,根据相关法律法规,本人有权:
|
||||||
|
|
||||||
|
(1)查阅、复制及要求更正本人的个人信息;
|
||||||
|
|
||||||
|
(2)在满足法定条件时,要求删除个人信息或撤回本授权同意。
|
||||||
|
|
||||||
|
本人确认,撤回本授权同意将不影响撤回前基于本授权已进行的个人信息处理活动的效力。但若撤回授权,可能导致委托方无法完整评估本人的任职资格,从而可能影响本次招聘/录用结果,本人将自行承担相应后果。
|
||||||
|
|
||||||
|
2. 本人知悉:如本人对贵司或数据源单位个人信息处理活动有任何疑问、意见建议或需要依法行使权利,可通过以下联系方式进行咨询、反映或行使法定权利:
|
||||||
|
|
||||||
|
贵司:【联系方式:{{.Mobile}}】
|
||||||
|
|
||||||
|
七、 全部协议与授权效力
|
||||||
|
|
||||||
|
本授权书自本人同意之日起生效,并在上述业务办理及存续期间持续有效,至本授权书所述的所有业务终结之日止。
|
||||||
|
|
||||||
|
本人已仔细阅读并完全理解本授权书的全部内容,特别是加粗字体部分。本人的签署是基于本人的真实意愿,本人知悉且理解由此产生的法律效力及相应信息披露产生的不利后果(包括不限于第三方通过非法手段或方式获取、使用该信息,可能会给本人造成人身财产的损害,或是造成本人预期利益减少、损失扩大,或是其他不良或不利影响等),自愿作出上述授权。
|
||||||
|
|
||||||
|
|
||||||
|
授权人签署:{{.Name}}
|
||||||
|
身份证号码:{{.IdCard}}
|
||||||
|
|
||||||
|
签署日期:{{.Date}}
|
||||||
@@ -10,8 +10,6 @@ import (
|
|||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tyc-server/common/globalkey"
|
|
||||||
|
|
||||||
"github.com/Masterminds/squirrel"
|
"github.com/Masterminds/squirrel"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||||
@@ -19,6 +17,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
||||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
"github.com/zeromicro/go-zero/core/stringx"
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
|
"tyc-server/common/globalkey"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -65,6 +64,7 @@ type (
|
|||||||
LevelName string `db:"level_name"` // 会员级别,如 VIP,SVIP,normal
|
LevelName string `db:"level_name"` // 会员级别,如 VIP,SVIP,normal
|
||||||
Amount float64 `db:"amount"` // 充值金额
|
Amount float64 `db:"amount"` // 充值金额
|
||||||
PaymentMethod string `db:"payment_method"` // 支付方式:支付宝,微信,苹果支付,其他
|
PaymentMethod string `db:"payment_method"` // 支付方式:支付宝,微信,苹果支付,其他
|
||||||
|
PaymentMerchant string `db:"payment_merchant"` // 支付商户标识,例如 one/two
|
||||||
OrderNo string `db:"order_no"` // 交易号
|
OrderNo string `db:"order_no"` // 交易号
|
||||||
PlatformOrderId sql.NullString `db:"platform_order_id"` // 支付平台订单号
|
PlatformOrderId sql.NullString `db:"platform_order_id"` // 支付平台订单号
|
||||||
Status string `db:"status"`
|
Status string `db:"status"`
|
||||||
@@ -89,11 +89,11 @@ func (m *defaultAgentMembershipRechargeOrderModel) Insert(ctx context.Context, s
|
|||||||
tycAgentMembershipRechargeOrderOrderNoKey := fmt.Sprintf("%s%v", cacheTycAgentMembershipRechargeOrderOrderNoPrefix, data.OrderNo)
|
tycAgentMembershipRechargeOrderOrderNoKey := fmt.Sprintf("%s%v", cacheTycAgentMembershipRechargeOrderOrderNoPrefix, data.OrderNo)
|
||||||
tycAgentMembershipRechargeOrderPlatformOrderIdKey := fmt.Sprintf("%s%v", cacheTycAgentMembershipRechargeOrderPlatformOrderIdPrefix, data.PlatformOrderId)
|
tycAgentMembershipRechargeOrderPlatformOrderIdKey := fmt.Sprintf("%s%v", cacheTycAgentMembershipRechargeOrderPlatformOrderIdPrefix, data.PlatformOrderId)
|
||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentMembershipRechargeOrderRowsExpectAutoSet)
|
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentMembershipRechargeOrderRowsExpectAutoSet)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.OrderNo, data.PlatformOrderId, data.Status, data.DeleteTime, data.DelState, data.Version)
|
return session.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.PaymentMerchant, data.OrderNo, data.PlatformOrderId, data.Status, data.DeleteTime, data.DelState, data.Version)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.OrderNo, data.PlatformOrderId, data.Status, data.DeleteTime, data.DelState, data.Version)
|
return conn.ExecCtx(ctx, query, data.UserId, data.AgentId, data.LevelName, data.Amount, data.PaymentMethod, data.PaymentMerchant, data.OrderNo, data.PlatformOrderId, data.Status, data.DeleteTime, data.DelState, data.Version)
|
||||||
}, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey)
|
}, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +165,9 @@ func (m *defaultAgentMembershipRechargeOrderModel) Update(ctx context.Context, s
|
|||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentMembershipRechargeOrderRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentMembershipRechargeOrderRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
|
return session.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.PaymentMerchant, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
|
return conn.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.PaymentMerchant, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
|
||||||
}, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey)
|
}, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,9 +189,9 @@ func (m *defaultAgentMembershipRechargeOrderModel) UpdateWithVersion(ctx context
|
|||||||
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentMembershipRechargeOrderRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentMembershipRechargeOrderRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
|
return session.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.PaymentMerchant, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
|
return conn.ExecCtx(ctx, query, newData.UserId, newData.AgentId, newData.LevelName, newData.Amount, newData.PaymentMethod, newData.PaymentMerchant, newData.OrderNo, newData.PlatformOrderId, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
|
||||||
}, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey)
|
}, tycAgentMembershipRechargeOrderIdKey, tycAgentMembershipRechargeOrderOrderNoKey, tycAgentMembershipRechargeOrderPlatformOrderIdKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import (
|
|||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tyc-server/common/globalkey"
|
|
||||||
|
|
||||||
"github.com/Masterminds/squirrel"
|
"github.com/Masterminds/squirrel"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||||
@@ -19,6 +17,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
||||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
"github.com/zeromicro/go-zero/core/stringx"
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
|
"tyc-server/common/globalkey"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -63,6 +62,7 @@ type (
|
|||||||
ProductId int64 `db:"product_id"` // 产品ID(软关联到产品表)
|
ProductId int64 `db:"product_id"` // 产品ID(软关联到产品表)
|
||||||
PaymentPlatform string `db:"payment_platform"` // 支付平台(支付宝、微信、苹果内购、其他)
|
PaymentPlatform string `db:"payment_platform"` // 支付平台(支付宝、微信、苹果内购、其他)
|
||||||
PaymentScene string `db:"payment_scene"` // 支付场景(App、H5、微信小程序、公众号)
|
PaymentScene string `db:"payment_scene"` // 支付场景(App、H5、微信小程序、公众号)
|
||||||
|
PaymentMerchant string `db:"payment_merchant"` // 支付商户标识,例如 one/two
|
||||||
PlatformOrderId sql.NullString `db:"platform_order_id"` // 支付平台订单号
|
PlatformOrderId sql.NullString `db:"platform_order_id"` // 支付平台订单号
|
||||||
Amount float64 `db:"amount"` // 支付金额
|
Amount float64 `db:"amount"` // 支付金额
|
||||||
Status string `db:"status"` // 支付状态
|
Status string `db:"status"` // 支付状态
|
||||||
@@ -90,11 +90,11 @@ func (m *defaultOrderModel) Insert(ctx context.Context, session sqlx.Session, da
|
|||||||
tycOrderIdKey := fmt.Sprintf("%s%v", cacheTycOrderIdPrefix, data.Id)
|
tycOrderIdKey := fmt.Sprintf("%s%v", cacheTycOrderIdPrefix, data.Id)
|
||||||
tycOrderOrderNoKey := fmt.Sprintf("%s%v", cacheTycOrderOrderNoPrefix, data.OrderNo)
|
tycOrderOrderNoKey := fmt.Sprintf("%s%v", cacheTycOrderOrderNoPrefix, data.OrderNo)
|
||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRowsExpectAutoSet)
|
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRowsExpectAutoSet)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.SalesCost)
|
return session.ExecCtx(ctx, query, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PaymentMerchant, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.SalesCost)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.SalesCost)
|
return conn.ExecCtx(ctx, query, data.OrderNo, data.UserId, data.ProductId, data.PaymentPlatform, data.PaymentScene, data.PaymentMerchant, data.PlatformOrderId, data.Amount, data.Status, data.DelState, data.Version, data.PayTime, data.RefundTime, data.CloseTime, data.DeleteTime, data.SalesCost)
|
||||||
}, tycOrderIdKey, tycOrderOrderNoKey)
|
}, tycOrderIdKey, tycOrderOrderNoKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,9 +145,9 @@ func (m *defaultOrderModel) Update(ctx context.Context, session sqlx.Session, ne
|
|||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, orderRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, orderRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id)
|
return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PaymentMerchant, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id)
|
return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PaymentMerchant, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id)
|
||||||
}, tycOrderIdKey, tycOrderOrderNoKey)
|
}, tycOrderIdKey, tycOrderOrderNoKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,9 +168,9 @@ func (m *defaultOrderModel) UpdateWithVersion(ctx context.Context, session sqlx.
|
|||||||
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, orderRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, orderRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id, oldVersion)
|
return session.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PaymentMerchant, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id, oldVersion)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id, oldVersion)
|
return conn.ExecCtx(ctx, query, newData.OrderNo, newData.UserId, newData.ProductId, newData.PaymentPlatform, newData.PaymentScene, newData.PaymentMerchant, newData.PlatformOrderId, newData.Amount, newData.Status, newData.DelState, newData.Version, newData.PayTime, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.SalesCost, newData.Id, oldVersion)
|
||||||
}, tycOrderIdKey, tycOrderOrderNoKey)
|
}, tycOrderIdKey, tycOrderOrderNoKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import (
|
|||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tyc-server/common/globalkey"
|
|
||||||
|
|
||||||
"github.com/Masterminds/squirrel"
|
"github.com/Masterminds/squirrel"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||||
@@ -19,6 +17,7 @@ import (
|
|||||||
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
||||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
"github.com/zeromicro/go-zero/core/stringx"
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
|
"tyc-server/common/globalkey"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -64,6 +63,7 @@ type (
|
|||||||
OrderId int64 `db:"order_id"` // 关联的订单ID
|
OrderId int64 `db:"order_id"` // 关联的订单ID
|
||||||
UserId int64 `db:"user_id"` // 用户ID
|
UserId int64 `db:"user_id"` // 用户ID
|
||||||
ProductId int64 `db:"product_id"` // 产品ID
|
ProductId int64 `db:"product_id"` // 产品ID
|
||||||
|
PaymentMerchant string `db:"payment_merchant"` // 退款对应的支付商户标识,例如 one/two
|
||||||
PlatformRefundId sql.NullString `db:"platform_refund_id"` // 支付平台退款单号
|
PlatformRefundId sql.NullString `db:"platform_refund_id"` // 支付平台退款单号
|
||||||
RefundAmount float64 `db:"refund_amount"` // 退款金额
|
RefundAmount float64 `db:"refund_amount"` // 退款金额
|
||||||
RefundReason sql.NullString `db:"refund_reason"` // 退款原因
|
RefundReason sql.NullString `db:"refund_reason"` // 退款原因
|
||||||
@@ -91,11 +91,11 @@ func (m *defaultOrderRefundModel) Insert(ctx context.Context, session sqlx.Sessi
|
|||||||
tycOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheTycOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId)
|
tycOrderRefundPlatformRefundIdKey := fmt.Sprintf("%s%v", cacheTycOrderRefundPlatformRefundIdPrefix, data.PlatformRefundId)
|
||||||
tycOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheTycOrderRefundRefundNoPrefix, data.RefundNo)
|
tycOrderRefundRefundNoKey := fmt.Sprintf("%s%v", cacheTycOrderRefundRefundNoPrefix, data.RefundNo)
|
||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRefundRowsExpectAutoSet)
|
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, orderRefundRowsExpectAutoSet)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime)
|
return session.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PaymentMerchant, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime)
|
return conn.ExecCtx(ctx, query, data.RefundNo, data.OrderId, data.UserId, data.ProductId, data.PaymentMerchant, data.PlatformRefundId, data.RefundAmount, data.RefundReason, data.Status, data.DelState, data.Version, data.RefundTime, data.CloseTime, data.DeleteTime)
|
||||||
}, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey)
|
}, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,9 +167,9 @@ func (m *defaultOrderRefundModel) Update(ctx context.Context, session sqlx.Sessi
|
|||||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, orderRefundRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, orderRefundRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id)
|
return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PaymentMerchant, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id)
|
return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PaymentMerchant, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id)
|
||||||
}, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey)
|
}, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,9 +191,9 @@ func (m *defaultOrderRefundModel) UpdateWithVersion(ctx context.Context, session
|
|||||||
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, orderRefundRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, orderRefundRowsWithPlaceHolder)
|
||||||
if session != nil {
|
if session != nil {
|
||||||
return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion)
|
return session.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PaymentMerchant, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion)
|
||||||
}
|
}
|
||||||
return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion)
|
return conn.ExecCtx(ctx, query, newData.RefundNo, newData.OrderId, newData.UserId, newData.ProductId, newData.PaymentMerchant, newData.PlatformRefundId, newData.RefundAmount, newData.RefundReason, newData.Status, newData.DelState, newData.Version, newData.RefundTime, newData.CloseTime, newData.DeleteTime, newData.Id, oldVersion)
|
||||||
}, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey)
|
}, tycOrderRefundIdKey, tycOrderRefundPlatformRefundIdKey, tycOrderRefundRefundNoKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ func GetPlatformFromCtx(ctx context.Context) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch platform {
|
switch platform {
|
||||||
case model.PlatformWxMini:
|
case model.PlatformWxMini, "mp-weixin": // 兼容旧客户端误传的 uni 平台名
|
||||||
return model.PlatformWxMini, nil
|
return model.PlatformWxMini, nil
|
||||||
case model.PlatformWxH5:
|
case model.PlatformWxH5:
|
||||||
return model.PlatformWxH5, nil
|
return model.PlatformWxH5, nil
|
||||||
@@ -99,6 +99,6 @@ func GetPlatformFromCtx(ctx context.Context) (string, error) {
|
|||||||
case model.PlatformH5:
|
case model.PlatformH5:
|
||||||
return model.PlatformH5, nil
|
return model.PlatformH5, nil
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("不支持的支付平台: %s", platform)
|
return "", fmt.Errorf("不支持的客户端平台: %s", platform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ $DB_URL = "tyc:5vg67b3UNHu8@tcp(127.0.0.1:22001)/tyc"
|
|||||||
$OUTPUT_DIR = "./model"
|
$OUTPUT_DIR = "./model"
|
||||||
$TEMPLATE_DIR = "../template"
|
$TEMPLATE_DIR = "../template"
|
||||||
|
|
||||||
# 表名列表
|
# 表名列表(按需开启)
|
||||||
$tables = @(
|
$tables = @(
|
||||||
# "agent"
|
# "agent"
|
||||||
# "agent_active_stat",
|
# "agent_active_stat",
|
||||||
@@ -16,7 +16,7 @@ $tables = @(
|
|||||||
# "agent_commission_deduction"
|
# "agent_commission_deduction"
|
||||||
# "agent_link",
|
# "agent_link",
|
||||||
# "agent_membership_config",
|
# "agent_membership_config",
|
||||||
# "agent_membership_recharge_order"
|
"agent_membership_recharge_order"
|
||||||
# "agent_membership_user_config",
|
# "agent_membership_user_config",
|
||||||
# "agent_order",
|
# "agent_order",
|
||||||
# "agent_platform_deduction"
|
# "agent_platform_deduction"
|
||||||
@@ -29,15 +29,15 @@ $tables = @(
|
|||||||
# "agent_withdrawal_tax_exemption"
|
# "agent_withdrawal_tax_exemption"
|
||||||
# "feature"
|
# "feature"
|
||||||
# "global_notifications"
|
# "global_notifications"
|
||||||
# "order"
|
"order"
|
||||||
# "order_refund"
|
"order_refund"
|
||||||
# "product",
|
# "product",
|
||||||
# "product_feature"
|
# "product_feature"
|
||||||
# "query",
|
# "query",
|
||||||
# "query_cleanup_log"
|
# "query_cleanup_log"
|
||||||
# "query_cleanup_detail"
|
# "query_cleanup_detail"
|
||||||
# "query_cleanup_config"
|
# "query_cleanup_config"
|
||||||
"user"
|
# "user"
|
||||||
# "user_auth"
|
# "user_auth"
|
||||||
# "user_temp"
|
# "user_temp"
|
||||||
# "example"
|
# "example"
|
||||||
@@ -55,7 +55,6 @@ $tables = @(
|
|||||||
# "admin_promotion_link_stats_history"
|
# "admin_promotion_link_stats_history"
|
||||||
# "admin_promotion_order"
|
# "admin_promotion_order"
|
||||||
# "query_user_record"
|
# "query_user_record"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 为每个表生成模型
|
# 为每个表生成模型
|
||||||
|
|||||||
90
deploy/script/m.sql
Normal file
90
deploy/script/m.sql
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
-- =========================
|
||||||
|
-- 1. 表结构变更:新增 payment_merchant
|
||||||
|
-- =========================
|
||||||
|
|
||||||
|
-- 1.1 order 表:增加支付商户标识
|
||||||
|
ALTER TABLE `order`
|
||||||
|
ADD COLUMN `payment_merchant` varchar(64) NOT NULL DEFAULT '' COMMENT '支付商户标识,例如 one/two' AFTER `payment_scene`;
|
||||||
|
|
||||||
|
-- 1.2 order_refund 表:增加支付商户标识
|
||||||
|
ALTER TABLE `order_refund`
|
||||||
|
ADD COLUMN `payment_merchant` varchar(64) NOT NULL DEFAULT '' COMMENT '退款对应的支付商户标识,例如 one/two' AFTER `product_id`;
|
||||||
|
|
||||||
|
-- 1.3 agent_membership_recharge_order 表:增加支付商户标识
|
||||||
|
ALTER TABLE `agent_membership_recharge_order`
|
||||||
|
ADD COLUMN `payment_merchant` varchar(64) NOT NULL DEFAULT '' COMMENT '支付商户标识,例如 one/two' AFTER `payment_method`;
|
||||||
|
|
||||||
|
-- =========================
|
||||||
|
-- 2. 历史数据初始化:one / two
|
||||||
|
-- 约定:
|
||||||
|
-- - one:当前主支付宝商户
|
||||||
|
-- - two:当前 bak 支付宝商户
|
||||||
|
-- 时间区间:
|
||||||
|
-- [2026-01-25 16:38:17, 2026-02-02 18:26:00)
|
||||||
|
-- =========================
|
||||||
|
|
||||||
|
-- 2.1 order 表:按时间区间映射 one / two
|
||||||
|
-- 仅处理支付宝订单(payment_platform='alipay')
|
||||||
|
-- 区间内用 two,其余用 one
|
||||||
|
-- 时间优先用 pay_time,pay_time 为空则用 create_time
|
||||||
|
|
||||||
|
-- 2.1.1 全部支付宝订单默认标记为 one
|
||||||
|
UPDATE `order`
|
||||||
|
SET
|
||||||
|
payment_merchant = 'one'
|
||||||
|
WHERE
|
||||||
|
payment_platform = 'alipay'
|
||||||
|
AND del_state = 0;
|
||||||
|
|
||||||
|
-- 2.1.2 区间内的支付宝订单标记为 two
|
||||||
|
UPDATE `order`
|
||||||
|
SET
|
||||||
|
payment_merchant = 'two'
|
||||||
|
WHERE
|
||||||
|
payment_platform = 'alipay'
|
||||||
|
AND del_state = 0
|
||||||
|
AND (
|
||||||
|
(
|
||||||
|
pay_time IS NOT NULL
|
||||||
|
AND pay_time >= '2026-01-25 16:38:17'
|
||||||
|
AND pay_time < '2026-02-02 18:26:00'
|
||||||
|
)
|
||||||
|
OR (
|
||||||
|
pay_time IS NULL
|
||||||
|
AND create_time >= '2026-01-25 16:38:17'
|
||||||
|
AND create_time < '2026-02-02 18:26:00'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 2.2 agent_membership_recharge_order 表:按创建时间映射 one / two
|
||||||
|
-- 仅处理支付宝支付(payment_method='alipay')
|
||||||
|
-- 区间内创建的订单标记为 two,其余为 one
|
||||||
|
|
||||||
|
-- 2.2.1 所有支付宝代理会员充值订单默认标记为 one
|
||||||
|
UPDATE `agent_membership_recharge_order`
|
||||||
|
SET
|
||||||
|
payment_merchant = 'one'
|
||||||
|
WHERE
|
||||||
|
payment_method = 'alipay'
|
||||||
|
AND del_state = 0;
|
||||||
|
|
||||||
|
-- 2.2.2 区间内的支付宝代理会员订单标记为 two
|
||||||
|
UPDATE `agent_membership_recharge_order`
|
||||||
|
SET
|
||||||
|
payment_merchant = 'two'
|
||||||
|
WHERE
|
||||||
|
payment_method = 'alipay'
|
||||||
|
AND del_state = 0
|
||||||
|
AND create_time >= '2026-01-25 16:38:17'
|
||||||
|
AND create_time < '2026-02-02 18:26:00';
|
||||||
|
|
||||||
|
-- 2.3 order_refund 表:跟随对应订单的 payment_merchant
|
||||||
|
-- 直接复制 order.payment_merchant,避免逻辑重复
|
||||||
|
|
||||||
|
UPDATE `order_refund` r
|
||||||
|
JOIN `order` o ON r.order_id = o.id
|
||||||
|
SET
|
||||||
|
r.payment_merchant = o.payment_merchant
|
||||||
|
WHERE
|
||||||
|
r.del_state = 0
|
||||||
|
AND o.del_state = 0;
|
||||||
228
docs/toolbox_implementation.md
Normal file
228
docs/toolbox_implementation.md
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
# 天远查车询功能实现说明
|
||||||
|
|
||||||
|
## 功能概述
|
||||||
|
实现了一个完整的工具查询系统,包含11个实用工具,用户可以通过首页点击工具进行查询。
|
||||||
|
|
||||||
|
## 后端实现
|
||||||
|
|
||||||
|
### 1. 配置和类型定义
|
||||||
|
|
||||||
|
#### 配置文件更新
|
||||||
|
- `config/config.go`: 添加了 `TianxingjuheConfig` 结构体和 `Tianxingjuhe` 字段
|
||||||
|
- `etc/main.yaml` 和 `etc/main.dev.yaml`: 添加了天行聚合API配置
|
||||||
|
|
||||||
|
#### 类型定义
|
||||||
|
- `types/types.go`: 添加了工具相关类型
|
||||||
|
- `ToolInfo`: 工具信息结构
|
||||||
|
- `ToolboxListResp`: 工具列表响应
|
||||||
|
- `ToolboxQueryReq`: 工具查询请求
|
||||||
|
- `ToolboxQueryResp`: 工具查询响应
|
||||||
|
|
||||||
|
### 2. 天行聚合API客户端
|
||||||
|
|
||||||
|
#### 文件结构
|
||||||
|
- `service/tianxingjuhe_sdk/client.go`: 天行聚合API客户端实现
|
||||||
|
|
||||||
|
#### 功能特性
|
||||||
|
- 支持GET和POST请求
|
||||||
|
- 自动添加API密钥
|
||||||
|
- 统一的响应处理
|
||||||
|
- 错误处理机制
|
||||||
|
|
||||||
|
### 3. 工具箱服务
|
||||||
|
|
||||||
|
#### 文件结构
|
||||||
|
- `service/toolboxService.go`: 工具箱服务核心实现
|
||||||
|
|
||||||
|
#### 工具列表(11个工具)
|
||||||
|
1. **IP地址查询** (ip-location)
|
||||||
|
- 查询IP地址归属地、运营商等信息
|
||||||
|
- 支持ipv4和ipv6
|
||||||
|
- 内网IP自动识别
|
||||||
|
|
||||||
|
2. **身份证归属地** (idcard-info)
|
||||||
|
- 查询身份证归属地、性别、出生日期等信息
|
||||||
|
- 校验身份证有效性
|
||||||
|
- 计算年龄
|
||||||
|
|
||||||
|
3. **手机号归属地** (phone-location)
|
||||||
|
- 查询手机号码归属地、运营商等信息
|
||||||
|
|
||||||
|
4. **北京时间查询** (beijing-time)
|
||||||
|
- 获取当前北京时间
|
||||||
|
- 不需要输入参数
|
||||||
|
|
||||||
|
5. **银行卡识别** (bank-card)
|
||||||
|
- 识别银行卡发卡行与卡种
|
||||||
|
|
||||||
|
6. **车牌号解析** (plate-parse)
|
||||||
|
- 解析车牌类型与归属地
|
||||||
|
|
||||||
|
7. **金额大写转换** (money-to-chinese)
|
||||||
|
- 阿拉伯数字转中文大写金额
|
||||||
|
|
||||||
|
8. **密码强度检测** (password-strength)
|
||||||
|
- 检测密码安全性并给出建议
|
||||||
|
|
||||||
|
9. **日期间隔计算** (days-between-dates)
|
||||||
|
- 计算两个日期相差的天数
|
||||||
|
|
||||||
|
10. **文件大小格式化** (file-size-format)
|
||||||
|
- 字节数转为 KB / MB / GB
|
||||||
|
|
||||||
|
11. **文本字数统计** (text-stats)
|
||||||
|
- 统计字符数、单词数、行数
|
||||||
|
|
||||||
|
### 4. API接口
|
||||||
|
|
||||||
|
#### 路由配置
|
||||||
|
- `handler/routes.go`: 添加了工具箱相关路由
|
||||||
|
- `GET /api/v1/toolbox/list`: 获取工具列表
|
||||||
|
- `POST /api/v1/toolbox/query`: 执行工具查询
|
||||||
|
|
||||||
|
#### Handler实现
|
||||||
|
- `handler/toolbox/toolboxlisthandler.go`: 工具列表接口
|
||||||
|
- `handler/toolbox/toolboxqueryhandler.go`: 工具查询接口
|
||||||
|
|
||||||
|
#### Logic实现
|
||||||
|
- `logic/toolbox/toolboxlistlogic.go`: 工具列表业务逻辑
|
||||||
|
- `logic/toolbox/toolboxquerylogic.go`: 工具查询业务逻辑
|
||||||
|
|
||||||
|
### 5. 服务上下文注册
|
||||||
|
|
||||||
|
#### 文件更新
|
||||||
|
- `svc/servicecontext.go`:
|
||||||
|
- 导入天行聚合SDK包
|
||||||
|
- 添加 `TianxingjuheService` 字段
|
||||||
|
- 初始化天行聚合客户端实例
|
||||||
|
- 注册到服务上下文
|
||||||
|
|
||||||
|
## 前端实现
|
||||||
|
|
||||||
|
### 1. 工具配置
|
||||||
|
|
||||||
|
#### 文件结构
|
||||||
|
- `config/toolboxRegistry.js`: 工具配置注册表
|
||||||
|
|
||||||
|
#### 配置内容
|
||||||
|
每个工具配置包含:
|
||||||
|
- `key`: 工具唯一标识
|
||||||
|
- `name`: 工具名称
|
||||||
|
- `desc`: 工具描述
|
||||||
|
- `icon`: 图标类名(使用carbon图标库)
|
||||||
|
- `fields`: 输入字段配置
|
||||||
|
- `validate`: 表单验证函数
|
||||||
|
- `validateMsg`: 验证失败提示信息
|
||||||
|
- `resultLabels`: 结果展示字段映射
|
||||||
|
|
||||||
|
### 2. 首页集成
|
||||||
|
|
||||||
|
#### 文件更新
|
||||||
|
- `pages/index.vue`:
|
||||||
|
- 添加了"天远查车询"卡片
|
||||||
|
- 显示所有11个工具
|
||||||
|
- 点击工具跳转到查询页面
|
||||||
|
- 添加了自定义图标样式
|
||||||
|
|
||||||
|
### 3. 工具查询页面
|
||||||
|
|
||||||
|
#### 文件结构
|
||||||
|
- `pages/toolbox/query.vue`: 工具查询页面
|
||||||
|
|
||||||
|
#### 功能特性
|
||||||
|
- 动态表单生成(支持text、digit、date、textarea等类型)
|
||||||
|
- 表单验证
|
||||||
|
- 自动查询(无需输入参数的工具)
|
||||||
|
- 结果展示
|
||||||
|
- 错误处理
|
||||||
|
- 加载状态
|
||||||
|
|
||||||
|
#### 支持的字段类型
|
||||||
|
- `text`: 普通文本输入
|
||||||
|
- `digit`: 数字输入
|
||||||
|
- `idcard`: 身份证号输入
|
||||||
|
- `date`: 日期选择器
|
||||||
|
- `textarea`: 多行文本输入
|
||||||
|
|
||||||
|
### 4. API调用
|
||||||
|
|
||||||
|
#### 文件结构
|
||||||
|
- `api/toolbox.js`: 工具箱API封装
|
||||||
|
|
||||||
|
#### 接口函数
|
||||||
|
- `postToolboxQuery(toolKey, params)`: 执行工具查询
|
||||||
|
|
||||||
|
## 使用流程
|
||||||
|
|
||||||
|
### 用户使用流程
|
||||||
|
1. 打开首页
|
||||||
|
2. 看到"天远查车询"卡片
|
||||||
|
3. 点击任意工具图标
|
||||||
|
4. 跳转到工具查询页面
|
||||||
|
5. 填写表单(如需)
|
||||||
|
6. 点击"立即查询"按钮
|
||||||
|
7. 查看查询结果
|
||||||
|
|
||||||
|
### 数据流程
|
||||||
|
1. 前端调用 `/api/v1/toolbox/list` 获取工具列表
|
||||||
|
2. 用户选择工具后调用 `/api/v1/toolbox/query` 执行查询
|
||||||
|
3. 后端根据 toolKey 分发到对应的处理函数
|
||||||
|
4. 处理函数执行查询逻辑(可能调用第三方API)
|
||||||
|
5. 返回查询结果
|
||||||
|
6. 前端展示结果
|
||||||
|
|
||||||
|
## 技术特点
|
||||||
|
|
||||||
|
### 后端特点
|
||||||
|
- 统一的工具接口设计
|
||||||
|
- 工具处理器注册表模式
|
||||||
|
- 灵活的参数传递(map[string]interface{})
|
||||||
|
- 完善的错误处理
|
||||||
|
- 支持第三方API集成(天行聚合)
|
||||||
|
|
||||||
|
### 前端特点
|
||||||
|
- 动态表单生成
|
||||||
|
- 类型安全的TypeScript
|
||||||
|
- 响应式UI设计
|
||||||
|
- 统一的错误处理
|
||||||
|
- 良好的用户体验
|
||||||
|
|
||||||
|
## 扩展指南
|
||||||
|
|
||||||
|
### 添加新工具
|
||||||
|
|
||||||
|
#### 后端步骤
|
||||||
|
1. 在 `toolboxService.go` 中添加处理函数
|
||||||
|
2. 在 `toolProcessors` 映射中注册新工具
|
||||||
|
3. 在 `ListTools()` 方法中添加工具信息
|
||||||
|
|
||||||
|
#### 前端步骤
|
||||||
|
1. 在 `toolboxRegistry.js` 中添加工具配置
|
||||||
|
2. 定义字段配置和验证规则
|
||||||
|
3. 定义结果展示字段映射
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **API密钥管理**: 天行聚合API的密钥已配置,请在生产环境中使用真实的API密钥
|
||||||
|
2. **错误处理**: 所有工具都有完善的错误处理机制
|
||||||
|
3. **表单验证**: 前端和后端都有验证,确保数据安全
|
||||||
|
4. **性能优化**: 工具查询响应时间已优化,建议在3秒内完成
|
||||||
|
5. **用户体验**: 无需输入参数的工具会自动查询,提升用户体验
|
||||||
|
|
||||||
|
## 测试建议
|
||||||
|
|
||||||
|
1. 测试每个工具的输入验证
|
||||||
|
2. 测试错误处理(如格式错误的输入)
|
||||||
|
3. 测试网络异常情况
|
||||||
|
4. 测试边界情况(如最大长度、特殊字符等)
|
||||||
|
5. 测试响应速度
|
||||||
|
|
||||||
|
## 部署检查清单
|
||||||
|
|
||||||
|
- [ ] 配置文件中的API密钥已更新为生产环境密钥
|
||||||
|
- [ ] 天行聚合API客户端已正确初始化
|
||||||
|
- [ ] 所有工具路由已正确注册
|
||||||
|
- [ ] 前端工具配置已同步更新
|
||||||
|
- [ ] 表单验证规则已测试通过
|
||||||
|
- [ ] 错误处理已测试
|
||||||
|
- [ ] 性能测试已通过
|
||||||
9
go.mod
9
go.mod
@@ -6,9 +6,9 @@ toolchain go1.23.4
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/squirrel v1.5.4
|
github.com/Masterminds/squirrel v1.5.4
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13
|
||||||
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6
|
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6
|
||||||
github.com/alibabacloud-go/tea v1.2.2
|
github.com/alibabacloud-go/tea v1.3.13
|
||||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
|
||||||
github.com/bytedance/sonic v1.13.0
|
github.com/bytedance/sonic v1.13.0
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0
|
github.com/cenkalti/backoff/v4 v4.3.0
|
||||||
@@ -37,16 +37,17 @@ require (
|
|||||||
require (
|
require (
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
|
||||||
|
github.com/alibabacloud-go/captcha-20230305 v1.1.3 // indirect
|
||||||
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
github.com/alibabacloud-go/debug v1.0.1 // indirect
|
||||||
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
|
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
|
||||||
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
|
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
|
||||||
github.com/alibabacloud-go/tea-utils v1.3.1 // indirect
|
github.com/alibabacloud-go/tea-utils v1.3.1 // indirect
|
||||||
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||||
github.com/aliyun/credentials-go v1.3.10 // indirect
|
github.com/aliyun/credentials-go v1.4.5 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.2.2 // indirect
|
github.com/bytedance/sonic/loader v0.2.2 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/clbanning/mxj/v2 v2.5.5 // indirect
|
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
|||||||
33
go.sum
33
go.sum
@@ -13,6 +13,8 @@ github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do2
|
|||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
|
||||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
|
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
|
||||||
|
github.com/alibabacloud-go/captcha-20230305 v1.1.3 h1:0Aobw12m3x28aeDMPjwjXsfF8MuLvRjlQ4Hhoy5hFOY=
|
||||||
|
github.com/alibabacloud-go/captcha-20230305 v1.1.3/go.mod h1:ydzBIN2OiM7eeQPpAFyBrv1H5TY1MtUP2rQig44C4UQ=
|
||||||
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
|
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
|
||||||
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
|
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
|
||||||
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
|
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
|
||||||
@@ -22,6 +24,8 @@ github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+M
|
|||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13 h1:Q00FU3H94Ts0ZIHDmY+fYGgB7dV9D/YX6FGsgorQPgw=
|
||||||
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.13/go.mod h1:lxFGfobinVsQ49ntjpgWghXmIF0/Sm4+wvBJ1h5RtaE=
|
||||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
||||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
||||||
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
||||||
@@ -46,6 +50,8 @@ github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy
|
|||||||
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||||
github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU=
|
github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU=
|
||||||
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||||
|
github.com/alibabacloud-go/tea v1.3.13 h1:WhGy6LIXaMbBM6VBYcsDCz6K/TPsT1Ri2hPmmZffZ94=
|
||||||
|
github.com/alibabacloud-go/tea v1.3.13/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
|
||||||
github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I=
|
github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I=
|
||||||
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
|
github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
|
||||||
@@ -64,6 +70,8 @@ github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTs
|
|||||||
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
|
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
|
||||||
github.com/aliyun/credentials-go v1.3.10 h1:45Xxrae/evfzQL9V10zL3xX31eqgLWEaIdCoPipOEQA=
|
github.com/aliyun/credentials-go v1.3.10 h1:45Xxrae/evfzQL9V10zL3xX31eqgLWEaIdCoPipOEQA=
|
||||||
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
|
github.com/aliyun/credentials-go v1.4.5 h1:O76WYKgdy1oQYYiJkERjlA2dxGuvLRrzuO2ScrtGWSk=
|
||||||
|
github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
@@ -83,6 +91,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
|||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
|
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
|
||||||
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||||
|
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
@@ -326,10 +336,13 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@@ -342,6 +355,9 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
|||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -356,10 +372,13 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
|||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@@ -370,6 +389,9 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -384,20 +406,27 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@@ -406,6 +435,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||||
@@ -420,6 +451,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
82
pkg/captcha/aliyun.go
Normal file
82
pkg/captcha/aliyun.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package captcha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"tyc-server/common/xerr"
|
||||||
|
|
||||||
|
captcha20230305 "github.com/alibabacloud-go/captcha-20230305/client"
|
||||||
|
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||||
|
"github.com/alibabacloud-go/tea/tea"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config 阿里云验证码配置(与 api internal config 解耦,供 pkg 使用)
|
||||||
|
type Config struct {
|
||||||
|
AccessKeyID string
|
||||||
|
AccessKeySecret string
|
||||||
|
EndpointURL string
|
||||||
|
SceneID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// isWeChatUserAgent 判断 User-Agent 是否为微信内置浏览器(含 MicroMessenger)。
|
||||||
|
func isWeChatUserAgent(ua string) bool {
|
||||||
|
return strings.Contains(ua, "MicroMessenger")
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyWithUserAgent 根据 User-Agent 与 captchaVerifyParam 校验。微信请求直接通过。
|
||||||
|
func VerifyWithUserAgent(cfg Config, captchaVerifyParam string, userAgent string) error {
|
||||||
|
if isWeChatUserAgent(userAgent) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return Verify(cfg, captchaVerifyParam)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify 校验前端传入的 captchaVerifyParam。异常时视为通过以保证业务可用。
|
||||||
|
func Verify(cfg Config, captchaVerifyParam string) error {
|
||||||
|
if os.Getenv("ENV") == "development" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if captchaVerifyParam == "" {
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "empty captchaVerifyParam")
|
||||||
|
}
|
||||||
|
|
||||||
|
clientCfg := &openapi.Config{
|
||||||
|
AccessKeyId: tea.String(cfg.AccessKeyID),
|
||||||
|
AccessKeySecret: tea.String(cfg.AccessKeySecret),
|
||||||
|
}
|
||||||
|
clientCfg.Endpoint = tea.String(cfg.EndpointURL)
|
||||||
|
clientCfg.ConnectTimeout = tea.Int(5000)
|
||||||
|
clientCfg.ReadTimeout = tea.Int(5000)
|
||||||
|
|
||||||
|
client, err := captcha20230305.NewClient(clientCfg)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("init aliyun captcha client error: %+v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &captcha20230305.VerifyIntelligentCaptchaRequest{
|
||||||
|
SceneId: tea.String(cfg.SceneID),
|
||||||
|
CaptchaVerifyParam: tea.String(captchaVerifyParam),
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.VerifyIntelligentCaptcha(req)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("verify aliyun captcha error: %+v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if resp.Body == nil || resp.Body.Result == nil {
|
||||||
|
logx.Errorf("verify aliyun captcha empty result, resp: %+v", resp)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if tea.BoolValue(resp.Body.Result.VerifyResult) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyCode := tea.StringValue(resp.Body.Result.VerifyCode)
|
||||||
|
logx.Errorf("verify aliyun captcha failed, code: %s", verifyCode)
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "aliyun captcha verify fail, code: %s", verifyCode)
|
||||||
|
}
|
||||||
32
pkg/captcha/encrypt_scene.go
Normal file
32
pkg/captcha/encrypt_scene.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package captcha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
lzcrypto "tyc-server/pkg/lzkit/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateEncryptedSceneID 按阿里云文档生成 EncryptedSceneId(仅适用于 V3 架构加密模式)。
|
||||||
|
// 明文格式: sceneId×tamp&expireTime
|
||||||
|
// 加密: AES-256-CBC + PKCS7Padding,结果为 Base64( IV(16字节) + ciphertext )
|
||||||
|
func GenerateEncryptedSceneID(sceneId, ekey string, expireSeconds int) (string, error) {
|
||||||
|
if expireSeconds <= 0 || expireSeconds > 86400 {
|
||||||
|
expireSeconds = 3600
|
||||||
|
}
|
||||||
|
|
||||||
|
ts := time.Now().Unix() // 秒级时间戳
|
||||||
|
plaintext := fmt.Sprintf("%s&%d&%d", sceneId, ts, expireSeconds)
|
||||||
|
|
||||||
|
keyBytes, err := base64.StdEncoding.DecodeString(ekey)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("decode ekey error: %w", err)
|
||||||
|
}
|
||||||
|
if len(keyBytes) != 32 {
|
||||||
|
return "", fmt.Errorf("invalid ekey length, need 32 bytes after base64 decode, got %d", len(keyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复用已有的 AES-CBC + PKCS7 实现,输出即为 Base64(IV + ciphertext)
|
||||||
|
return lzcrypto.AesEncrypt([]byte(plaintext), keyBytes)
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
func TestAesEcbMobileEncryption(t *testing.T) {
|
func TestAesEcbMobileEncryption(t *testing.T) {
|
||||||
// 测试手机号加密
|
// 测试手机号加密
|
||||||
mobile := "18653052547"
|
mobile := "15029295957"
|
||||||
key := []byte("ff83609b2b24fc73196aac3d3dfb874f") // 16字节AES-128密钥
|
key := []byte("ff83609b2b24fc73196aac3d3dfb874f") // 16字节AES-128密钥
|
||||||
|
|
||||||
keyStr := hex.EncodeToString(key)
|
keyStr := hex.EncodeToString(key)
|
||||||
@@ -19,7 +19,8 @@ func TestAesEcbMobileEncryption(t *testing.T) {
|
|||||||
t.Fatalf("手机号加密失败: %v", err)
|
t.Fatalf("手机号加密失败: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("encrypted: %s\n", encrypted)
|
fmt.Printf("encrypted: %s\n", encrypted)
|
||||||
jmStr := "m9EEeW9ZBBJmi1hx1k1uIQ=="
|
|
||||||
|
jmStr := "Am8/KpmBnsbXZoZOZq/oVQ=="
|
||||||
// 测试解密
|
// 测试解密
|
||||||
decrypted, err := DecryptMobile(jmStr, keyStr)
|
decrypted, err := DecryptMobile(jmStr, keyStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user