f
This commit is contained in:
@@ -2,6 +2,8 @@ package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
@@ -9,6 +11,7 @@ import (
|
||||
"tydata-server/app/main/model"
|
||||
"tydata-server/common/globalkey"
|
||||
"tydata-server/common/xerr"
|
||||
"tydata-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
@@ -77,6 +80,19 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR
|
||||
builder = builder.Where("refund_time <= ?", req.RefundTimeEnd)
|
||||
}
|
||||
|
||||
// 按被查询人(query_user_record 表)过滤:姓名、身份证、手机号(库中为密文,需解密后匹配)
|
||||
if req.QueryName != "" || req.QueryIdCard != "" || req.QueryMobile != "" {
|
||||
orderIds, filterErr := l.filterOrderIdsByQueryUserRecord(req.QueryName, req.QueryIdCard, req.QueryMobile)
|
||||
if filterErr != nil {
|
||||
return nil, filterErr
|
||||
}
|
||||
if len(orderIds) == 0 {
|
||||
builder = builder.Where("1 = 0") // 无匹配时返回空
|
||||
} else {
|
||||
builder = builder.Where(squirrel.Eq{"id": orderIds})
|
||||
}
|
||||
}
|
||||
|
||||
// 并发获取总数和列表
|
||||
var total int64
|
||||
var orders []*model.Order
|
||||
@@ -294,3 +310,71 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// filterOrderIdsByQueryUserRecord 根据姓名、身份证、手机号(明文)从 query_user_record 解密后匹配,返回符合条件的 order_id 列表
|
||||
func (l *AdminGetOrderListLogic) filterOrderIdsByQueryUserRecord(queryName, queryIdCard, queryMobile string) ([]int64, error) {
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
key, keyErr := hex.DecodeString(secretKey)
|
||||
if keyErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "Encrypt.SecretKey 解析失败: %v", keyErr)
|
||||
}
|
||||
|
||||
qb := l.svcCtx.QueryUserRecordModel.SelectBuilder().Where("order_id > ?", 0)
|
||||
recs, err := l.svcCtx.QueryUserRecordModel.FindAll(l.ctx, qb, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询 query_user_record 失败: %v", err)
|
||||
}
|
||||
|
||||
orderIds := make([]int64, 0, len(recs))
|
||||
for _, rec := range recs {
|
||||
match := true
|
||||
|
||||
if queryName != "" {
|
||||
var decName string
|
||||
if rec.Name != "" {
|
||||
bs, e := crypto.AesEcbDecrypt(rec.Name, key)
|
||||
if e != nil {
|
||||
match = false
|
||||
} else {
|
||||
decName = string(bs)
|
||||
}
|
||||
}
|
||||
if match && !strings.Contains(decName, queryName) {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
|
||||
if match && queryIdCard != "" {
|
||||
var decIdCard string
|
||||
if rec.IdCard != "" {
|
||||
var e error
|
||||
decIdCard, e = crypto.DecryptIDCard(rec.IdCard, key)
|
||||
if e != nil {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
if match && decIdCard != queryIdCard {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
|
||||
if match && queryMobile != "" {
|
||||
var decMobile string
|
||||
if rec.Mobile != "" {
|
||||
var e error
|
||||
decMobile, e = crypto.DecryptMobile(rec.Mobile, secretKey)
|
||||
if e != nil {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
if match && decMobile != queryMobile {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
|
||||
if match {
|
||||
orderIds = append(orderIds, rec.OrderId)
|
||||
}
|
||||
}
|
||||
return orderIds, nil
|
||||
}
|
||||
|
||||
@@ -43,17 +43,20 @@ func (l *AgentRealNameLogic) AgentRealName(req *types.AgentRealNameReq) (resp *t
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理实名, 加密手机号失败: %v", err)
|
||||
}
|
||||
// 检查手机号是否在一分钟内已发送过验证码
|
||||
redisKey := fmt.Sprintf("%s:%s", "realName", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "代理实名, 验证码过期: %s", encryptedMobile)
|
||||
// 开发环境下跳过验证码验证
|
||||
if !l.svcCtx.Config.SystemConfig.SkipVerifyCode {
|
||||
// 检查手机号是否在一分钟内已发送过验证码
|
||||
redisKey := fmt.Sprintf("%s:%s", "realName", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "代理实名, 验证码过期: %s", encryptedMobile)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理实名, 读取验证码redis缓存失败, mobile: %s, err: %+v", encryptedMobile, err)
|
||||
}
|
||||
if cacheCode != req.Code {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "代理实名, 验证码不正确: %s", encryptedMobile)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理实名, 读取验证码redis缓存失败, mobile: %s, err: %+v", encryptedMobile, err)
|
||||
}
|
||||
if cacheCode != req.Code {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "代理实名, 验证码不正确: %s", encryptedMobile)
|
||||
}
|
||||
agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,13 +2,13 @@ package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
"tydata-server/app/main/model"
|
||||
"tydata-server/common/ctxdata"
|
||||
"tydata-server/common/xerr"
|
||||
"tydata-server/pkg/lzkit/crypto"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
@@ -44,7 +44,8 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %v", err)
|
||||
}
|
||||
if req.Mobile != "18889793585" {
|
||||
// 开发环境下跳过验证码验证,或者特定手机号跳过(保留原有逻辑)
|
||||
if !l.svcCtx.Config.SystemConfig.SkipVerifyCode && req.Mobile != "18889793585" {
|
||||
// 校验验证码
|
||||
redisKey := fmt.Sprintf("%s:%s", "agentApply", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
|
||||
@@ -93,7 +93,6 @@ func (l *AlipayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter, not
|
||||
logx.Errorf("支付宝支付回调,修改订单信息失败: %+v", updateErr)
|
||||
return nil
|
||||
}
|
||||
|
||||
if order.Status == "paid" {
|
||||
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
|
||||
logx.Errorf("异步任务调度失败: %v", asyncErr)
|
||||
|
||||
@@ -2,9 +2,13 @@ package pay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
"tydata-server/app/main/api/internal/types"
|
||||
"tydata-server/app/main/model"
|
||||
@@ -27,6 +31,7 @@ type PaymentTypeResp struct {
|
||||
amount float64
|
||||
outTradeNo string
|
||||
description string
|
||||
orderID int64 // 仅 query 类型有值;agent_vip 为 0
|
||||
}
|
||||
|
||||
func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic {
|
||||
@@ -40,6 +45,7 @@ func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLo
|
||||
func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) {
|
||||
var paymentTypeResp *PaymentTypeResp
|
||||
var prepayData interface{}
|
||||
|
||||
l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
switch req.PayType {
|
||||
case "agent_vip":
|
||||
@@ -55,6 +61,17 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
}
|
||||
}
|
||||
|
||||
// 开发环境测试支付模式:仅当 pay_method=test 时跳过实际支付,直接返回 test_payment_success
|
||||
// 支付宝/微信在开发环境下仍走真实支付流程(跳转沙箱),支付成功后由回调更新订单
|
||||
// 注意:订单状态更新在事务外进行,避免在事务中查询不到订单的问题
|
||||
isDevTestPayment := os.Getenv("ENV") == "development" && req.PayMethod == "test"
|
||||
if isDevTestPayment && paymentTypeResp != nil && paymentTypeResp.orderID != 0 {
|
||||
prepayData = "test_payment_success"
|
||||
logx.Infof("开发环境测试支付模式:订单 %s (ID: %d) 将在事务提交后更新状态", paymentTypeResp.outTradeNo, paymentTypeResp.orderID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 仅 wechat/alipay/appleiap 调起真实支付;test 仅在上面 isDevTestPayment 分支处理
|
||||
var createOrderErr error
|
||||
if req.PayMethod == "wechat" {
|
||||
prepayData, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
|
||||
@@ -62,6 +79,13 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
prepayData, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
|
||||
} else if req.PayMethod == "appleiap" {
|
||||
prepayData = l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo)
|
||||
} else if req.PayMethod == "test" {
|
||||
if os.Getenv("ENV") != "development" {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "开发环境测试支付仅在开发环境可用")
|
||||
}
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "开发环境测试支付仅支持 query 类型订单")
|
||||
} else {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "不支持的支付方式: %s", req.PayMethod)
|
||||
}
|
||||
if createOrderErr != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr)
|
||||
@@ -71,6 +95,46 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 开发环境测试支付模式:事务提交后处理订单状态更新和后续流程(仅 pay_method=test 且 query 类型 orderID>0)
|
||||
isDevTestPayment := os.Getenv("ENV") == "development" && req.PayMethod == "test"
|
||||
if isDevTestPayment && paymentTypeResp != nil && paymentTypeResp.orderID != 0 {
|
||||
go func() {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
finalOrderID := paymentTypeResp.orderID
|
||||
order, findOrderErr := l.svcCtx.OrderModel.FindOne(context.Background(), finalOrderID)
|
||||
if findOrderErr != nil {
|
||||
logx.Errorf("开发测试模式,查找订单失败,订单ID: %d, 错误: %v", finalOrderID, findOrderErr)
|
||||
return
|
||||
}
|
||||
order.Status = "paid"
|
||||
now := time.Now()
|
||||
order.PayTime = sql.NullTime{Time: now, Valid: true}
|
||||
|
||||
// 空报告模式:在 PaymentPlatform 标记为 "test",在 paySuccessNotify.ProcessTask 中通过
|
||||
// order.PaymentPlatform == "test" 识别(isEmptyReportMode),并生成空报告、跳过 API 调用
|
||||
isEmptyReportMode := req.PayMethod == "test"
|
||||
if isEmptyReportMode {
|
||||
order.PaymentPlatform = "test"
|
||||
logx.Infof("开发环境空报告模式:订单 %s (ID: %d) 已标记为空报告模式", paymentTypeResp.outTradeNo, finalOrderID)
|
||||
}
|
||||
updateErr := l.svcCtx.OrderModel.UpdateWithVersion(context.Background(), nil, order)
|
||||
if updateErr != nil {
|
||||
logx.Errorf("开发测试模式,更新订单状态失败,订单ID: %d, 错误: %v", finalOrderID, updateErr)
|
||||
return
|
||||
}
|
||||
|
||||
if enqErr := l.svcCtx.AsynqService.SendQueryTask(finalOrderID); enqErr != nil {
|
||||
logx.Errorf("开发测试模式,入队生成报告失败,订单ID: %d, 错误: %v", finalOrderID, enqErr)
|
||||
}
|
||||
|
||||
logx.Infof("开发测试模式,订单状态已更新为已支付并已入队生成报告,订单ID: %d", finalOrderID)
|
||||
|
||||
// 再次短暂延迟,确保订单状态更新已提交
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}()
|
||||
}
|
||||
|
||||
switch v := prepayData.(type) {
|
||||
case string:
|
||||
// 如果 prepayData 是字符串类型,直接返回
|
||||
@@ -124,6 +188,42 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
if user.Inside == 1 {
|
||||
amount = 0.01
|
||||
}
|
||||
|
||||
// 检查72小时内身份证查询次数限制
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
key, decodeErr := hex.DecodeString(secretKey)
|
||||
if decodeErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取AES密钥失败: %+v", decodeErr)
|
||||
}
|
||||
// 解密缓存中的参数
|
||||
decryptedParams, decryptErr := crypto.AesDecrypt(data.Params, key)
|
||||
if decryptErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解密缓存参数失败: %v", decryptErr)
|
||||
}
|
||||
var params map[string]interface{}
|
||||
if unmarshalErr := json.Unmarshal(decryptedParams, ¶ms); unmarshalErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析解密参数失败: %v", unmarshalErr)
|
||||
}
|
||||
// 获取身份证号
|
||||
idCard, ok := params["id_card"].(string)
|
||||
if !ok || idCard == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取身份证号失败")
|
||||
}
|
||||
// 加密身份证号用于查询
|
||||
encryptedIdCard, encryptErr := crypto.EncryptIDCard(idCard, key)
|
||||
if encryptErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 加密身份证号失败: %v", encryptErr)
|
||||
}
|
||||
// 查询72小时内的查询次数
|
||||
queryCount, countErr := l.svcCtx.QueryUserRecordModel.CountByEncryptedIdCardIn72Hours(l.ctx, encryptedIdCard)
|
||||
if countErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 查询记录失败: %v", countErr)
|
||||
}
|
||||
// 如果72小时内查询次数大于等于2次,禁止支付(当前这次是第3次)
|
||||
if queryCount >= 2 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("查询受限通知:检测到您72小时内已完成2次报告查询,系统已自动暂停服务。如需紧急查询,请联系客服申请临时额度。"), "生成订单, 查询次数超限: %d", queryCount)
|
||||
}
|
||||
|
||||
var orderID int64
|
||||
order := model.Order{
|
||||
OrderNo: outTradeNo,
|
||||
@@ -144,6 +244,12 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
}
|
||||
orderID = insertedOrderID
|
||||
|
||||
// 更新查询用户记录表的 order_id,便于通过查询信息追溯订单
|
||||
if rec, findErr := l.svcCtx.QueryUserRecordModel.FindOneByQueryNo(l.ctx, outTradeNo); findErr == nil {
|
||||
rec.OrderId = orderID
|
||||
_, _ = l.svcCtx.QueryUserRecordModel.Update(l.ctx, session, rec)
|
||||
}
|
||||
|
||||
if data.AgentIdentifier != "" {
|
||||
agent, parsingErr := l.agentParsing(data.AgentIdentifier)
|
||||
if parsingErr != nil {
|
||||
@@ -157,7 +263,7 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert)
|
||||
}
|
||||
}
|
||||
return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName}, nil
|
||||
return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName, orderID: orderID}, nil
|
||||
}
|
||||
func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {
|
||||
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
|
||||
@@ -90,6 +90,11 @@ func (l *WechatPayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter,
|
||||
logx.Errorf("微信支付回调,更新订单失败%+v", updateErr)
|
||||
return nil
|
||||
}
|
||||
// 更新查询用户记录表的 platform_order_id
|
||||
if rec, findErr := l.svcCtx.QueryUserRecordModel.FindOneByQueryNo(l.ctx, *notification.OutTradeNo); findErr == nil {
|
||||
rec.PlatformOrderId = lzUtils.StringToNullString(*notification.TransactionId)
|
||||
_, _ = l.svcCtx.QueryUserRecordModel.Update(l.ctx, nil, rec)
|
||||
}
|
||||
|
||||
if order.Status == "paid" {
|
||||
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -106,6 +107,7 @@ func (l *QueryServiceLogic) ProcessMarriageLogic(req *types.QueryServiceReq) (*t
|
||||
if cacheDataErr != nil {
|
||||
return nil, cacheDataErr
|
||||
}
|
||||
l.recordQueryUserRecord(params, "marriage", userID, cacheNo)
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
|
||||
@@ -166,7 +168,7 @@ func (l *QueryServiceLogic) ProcessHomeServiceLogic(req *types.QueryServiceReq)
|
||||
if cacheDataErr != nil {
|
||||
return nil, cacheDataErr
|
||||
}
|
||||
|
||||
l.recordQueryUserRecord(params, "homeservice", userID, cacheNo)
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
|
||||
@@ -227,7 +229,7 @@ func (l *QueryServiceLogic) ProcessRiskAssessmentLogic(req *types.QueryServiceRe
|
||||
if cacheDataErr != nil {
|
||||
return nil, cacheDataErr
|
||||
}
|
||||
|
||||
l.recordQueryUserRecord(params, "riskassessment", userID, cacheNo)
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
|
||||
@@ -287,7 +289,7 @@ func (l *QueryServiceLogic) ProcessCompanyInfoLogic(req *types.QueryServiceReq)
|
||||
if cacheDataErr != nil {
|
||||
return nil, cacheDataErr
|
||||
}
|
||||
|
||||
l.recordQueryUserRecord(params, "companyinfo", userID, cacheNo)
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
|
||||
@@ -348,7 +350,7 @@ func (l *QueryServiceLogic) ProcessRentalInfoLogic(req *types.QueryServiceReq) (
|
||||
if cacheDataErr != nil {
|
||||
return nil, cacheDataErr
|
||||
}
|
||||
|
||||
l.recordQueryUserRecord(params, "rentalinfo", userID, cacheNo)
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
|
||||
@@ -409,7 +411,7 @@ func (l *QueryServiceLogic) ProcessPreLoanBackgroundCheckLogic(req *types.QueryS
|
||||
if cacheDataErr != nil {
|
||||
return nil, cacheDataErr
|
||||
}
|
||||
|
||||
l.recordQueryUserRecord(params, "preloanbackgroundcheck", userID, cacheNo)
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
|
||||
@@ -469,7 +471,7 @@ func (l *QueryServiceLogic) ProcessBackgroundCheckLogic(req *types.QueryServiceR
|
||||
if cacheDataErr != nil {
|
||||
return nil, cacheDataErr
|
||||
}
|
||||
|
||||
l.recordQueryUserRecord(params, "backgroundcheck", userID, cacheNo)
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
|
||||
@@ -527,7 +529,7 @@ func (l *QueryServiceLogic) ProcessPersonalDataLogic(req *types.QueryServiceReq)
|
||||
if cacheDataErr != nil {
|
||||
return nil, cacheDataErr
|
||||
}
|
||||
|
||||
l.recordQueryUserRecord(params, "personalData", userID, cacheNo)
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
|
||||
@@ -558,6 +560,10 @@ func (l *QueryServiceLogic) DecryptData(data string) ([]byte, error) {
|
||||
|
||||
// 校验验证码
|
||||
func (l *QueryServiceLogic) VerifyCode(mobile string, code string) error {
|
||||
// 开发环境下跳过验证码验证
|
||||
if l.svcCtx.Config.SystemConfig.SkipVerifyCode {
|
||||
return nil
|
||||
}
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
encryptedMobile, err := crypto.EncryptMobile(mobile, secretKey)
|
||||
if err != nil {
|
||||
@@ -579,6 +585,10 @@ func (l *QueryServiceLogic) VerifyCode(mobile string, code string) error {
|
||||
|
||||
// 二、三要素验证
|
||||
func (l *QueryServiceLogic) Verify(Name string, IDCard string, Mobile string) error {
|
||||
// 空报告模式:开发环境下跳过二/三要素验证
|
||||
if l.svcCtx.Config.SystemConfig.SkipVerify {
|
||||
return nil
|
||||
}
|
||||
if !l.svcCtx.Config.SystemConfig.ThreeVerify {
|
||||
twoVerification := service.TwoFactorVerificationRequest{
|
||||
Name: Name,
|
||||
@@ -643,6 +653,76 @@ func (l *QueryServiceLogic) CacheData(params map[string]interface{}, Product str
|
||||
return outTradeNo, nil
|
||||
}
|
||||
|
||||
// recordQueryUserRecord 写入查询用户记录表,用于通过姓名/身份证/手机号追溯订单
|
||||
// 重要:name、id_card、mobile 必须以 AES-ECB+Base64 密文入库,禁止写入明文
|
||||
func (l *QueryServiceLogic) recordQueryUserRecord(params map[string]interface{}, product string, userID int64, queryNo string) {
|
||||
getStr := func(k string) string {
|
||||
if v, ok := params[k]; ok {
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
if secretKey == "" {
|
||||
l.Errorf("查询用户记录表加密失败, Encrypt.SecretKey 未配置,拒绝写入明文 queryNo=%s", queryNo)
|
||||
return
|
||||
}
|
||||
key, keyErr := hex.DecodeString(secretKey)
|
||||
if keyErr != nil {
|
||||
l.Errorf("查询用户记录表加密失败, 密钥解析错误 queryNo=%s err=%v", queryNo, keyErr)
|
||||
return
|
||||
}
|
||||
// 以下三字段仅使用加密后的值赋值,不得使用 getStr 的明文
|
||||
encName := ""
|
||||
if name := getStr("name"); name != "" {
|
||||
if s, err := crypto.AesEcbEncrypt([]byte(name), key); err != nil {
|
||||
l.Errorf("查询用户记录表姓名加密失败 queryNo=%s err=%v", queryNo, err)
|
||||
return
|
||||
} else {
|
||||
encName = s
|
||||
}
|
||||
}
|
||||
encIdCard := ""
|
||||
if idCard := getStr("id_card"); idCard != "" {
|
||||
if s, err := crypto.EncryptIDCard(idCard, key); err != nil {
|
||||
l.Errorf("查询用户记录表身份证加密失败 queryNo=%s err=%v", queryNo, err)
|
||||
return
|
||||
} else {
|
||||
encIdCard = s
|
||||
}
|
||||
}
|
||||
encMobile := ""
|
||||
if mobile := getStr("mobile"); mobile != "" {
|
||||
if s, err := crypto.EncryptMobile(mobile, secretKey); err != nil {
|
||||
l.Errorf("查询用户记录表手机号加密失败 queryNo=%s err=%v", queryNo, err)
|
||||
return
|
||||
} else {
|
||||
encMobile = s
|
||||
}
|
||||
}
|
||||
agentIdentifier := sql.NullString{}
|
||||
if v, ok := l.ctx.Value("agentIdentifier").(string); ok && v != "" {
|
||||
agentIdentifier = sql.NullString{String: v, Valid: true}
|
||||
}
|
||||
// rec 的 Name、IdCard、Mobile 仅使用密文 encName、encIdCard、encMobile
|
||||
rec := &model.QueryUserRecord{
|
||||
UserId: userID,
|
||||
Name: encName,
|
||||
IdCard: encIdCard,
|
||||
Mobile: encMobile,
|
||||
Product: product,
|
||||
QueryNo: queryNo,
|
||||
OrderId: 0,
|
||||
PlatformOrderId: sql.NullString{},
|
||||
AgentIdentifier: agentIdentifier,
|
||||
}
|
||||
if _, err := l.svcCtx.QueryUserRecordModel.Insert(l.ctx, nil, rec); err != nil {
|
||||
l.Errorf("查询用户记录表写入失败 queryNo=%s err=%v", queryNo, err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrCreateUser 获取或创建用户
|
||||
// 1. 如果上下文中已有用户ID,直接返回
|
||||
// 2. 如果是代理查询或APP请求,创建新用户
|
||||
|
||||
@@ -42,7 +42,8 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 加密手机号失败: %v", err)
|
||||
}
|
||||
if req.Mobile != "18889793585" {
|
||||
// 开发环境下跳过验证码验证,或者特定手机号跳过(保留原有逻辑)
|
||||
if !l.svcCtx.Config.SystemConfig.SkipVerifyCode && req.Mobile != "18889793585" {
|
||||
// 检查手机号是否在一分钟内已发送过验证码
|
||||
redisKey := fmt.Sprintf("%s:%s", "bindMobile", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
|
||||
@@ -37,17 +37,20 @@ func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (r
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err)
|
||||
}
|
||||
// 检查手机号是否在一分钟内已发送过验证码
|
||||
redisKey := fmt.Sprintf("%s:%s", "login", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "手机登录, 验证码过期: %s", encryptedMobile)
|
||||
// 开发环境下跳过验证码验证
|
||||
if !l.svcCtx.Config.SystemConfig.SkipVerifyCode {
|
||||
// 检查手机号是否在一分钟内已发送过验证码
|
||||
redisKey := fmt.Sprintf("%s:%s", "login", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "手机登录, 验证码过期: %s", encryptedMobile)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取验证码redis缓存失败, mobile: %s, err: %+v", encryptedMobile, err)
|
||||
}
|
||||
if cacheCode != req.Code {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确: %s", encryptedMobile)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取验证码redis缓存失败, mobile: %s, err: %+v", encryptedMobile, err)
|
||||
}
|
||||
if cacheCode != req.Code {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确: %s", encryptedMobile)
|
||||
}
|
||||
var userID int64
|
||||
user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
|
||||
|
||||
Reference in New Issue
Block a user