first commit

This commit is contained in:
2025-01-10 00:09:25 +08:00
commit f54ead0f90
215 changed files with 16058 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
package auth
import (
"context"
"fmt"
"github.com/pkg/errors"
"math/rand"
"time"
"tydata-server/common/xerr"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
dysmsapi "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
"github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
"github.com/zeromicro/go-zero/core/logx"
)
type SendSmsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewSendSmsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendSmsLogic {
return &SendSmsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *SendSmsLogic) SendSms(req *types.SendSmsReq) error {
// 检查手机号是否在一分钟内已发送过验证码
limitCodeKey := fmt.Sprintf("limit:%s:%s", req.ActionType, req.Mobile)
exists, err := l.svcCtx.Redis.Exists(limitCodeKey)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "短信发送, 读取redis缓存失败: %s", req.Mobile)
}
if exists {
// 如果 Redis 中已经存在标记,说明在 1 分钟内请求过,返回错误
return errors.Wrapf(xerr.NewErrMsg("一分钟内不能重复发送验证码"), "短信发送, 手机号1分钟内重复请求发送二维码: %s", req.Mobile)
}
code := fmt.Sprintf("%06d", rand.New(rand.NewSource(time.Now().UnixNano())).Intn(1000000))
// 发送短信
smsResp, err := l.sendSmsRequest(req.Mobile, code)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "短信发送, 调用阿里客户端失败: %+v", err)
}
if *smsResp.Body.Code != "OK" {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "短信发送, 阿里客户端响应失败: %s", *smsResp.Body.Message)
}
codeKey := fmt.Sprintf("%s:%s", req.ActionType, req.Mobile)
// 将验证码保存到 Redis设置过期时间
err = l.svcCtx.Redis.Setex(codeKey, code, l.svcCtx.Config.VerifyCode.ValidTime) // 验证码有效期5分钟
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "短信发送, 验证码设置过期时间失败: %+v", err)
}
// 在 Redis 中设置 1 分钟的标记,限制重复请求
err = l.svcCtx.Redis.Setex(limitCodeKey, code, 60) // 标记 1 分钟内不能重复请求
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "短信发送, 验证码设置限制重复请求失败: %+v", err)
}
return nil
}
// CreateClient 创建阿里云短信客户端
func (l *SendSmsLogic) CreateClient() (*dysmsapi.Client, error) {
config := &openapi.Config{
AccessKeyId: &l.svcCtx.Config.VerifyCode.AccessKeyID,
AccessKeySecret: &l.svcCtx.Config.VerifyCode.AccessKeySecret,
}
config.Endpoint = tea.String(l.svcCtx.Config.VerifyCode.EndpointURL)
return dysmsapi.NewClient(config)
}
// sendSmsRequest 发送短信请求
func (l *SendSmsLogic) sendSmsRequest(mobile, code string) (*dysmsapi.SendSmsResponse, error) {
// 初始化阿里云短信客户端
cli, err := l.CreateClient()
if err != nil {
return nil, err
}
request := &dysmsapi.SendSmsRequest{
SignName: tea.String(l.svcCtx.Config.VerifyCode.SignName),
TemplateCode: tea.String(l.svcCtx.Config.VerifyCode.TemplateCode),
PhoneNumbers: tea.String(mobile),
TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%s\"}", code)),
}
runtime := &service.RuntimeOptions{}
return cli.SendSmsWithOptions(request, runtime)
}

View File

@@ -0,0 +1,56 @@
package notification
import (
"context"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"time"
"tydata-server/common/xerr"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetNotificationsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetNotificationsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetNotificationsLogic {
return &GetNotificationsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetNotificationsLogic) GetNotifications() (resp *types.GetNotificationsResp, err error) {
// 获取今天的日期
now := time.Now()
// 获取开始和结束日期的时间戳
todayStart := now.Format("2006-01-02") + " 00:00:00"
todayEnd := now.Format("2006-01-02") + " 23:59:59"
// 构建查询条件
builder := l.svcCtx.GlobalNotificationsModel.SelectBuilder().
Where("status = ?", "active").
Where("(start_date IS NULL OR start_date <= ?)", todayEnd). // start_date 是 NULL 或者小于等于今天结束时间
Where("(end_date IS NULL OR end_date >= ?)", todayStart) // end_date 是 NULL 或者大于等于今天开始时间
notificationsModelList, findErr := l.svcCtx.GlobalNotificationsModel.FindAll(l.ctx, builder, "")
if findErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "全局通知, 查找通知失败, err:%+v", findErr)
}
var notifications []types.Notification
copyErr := copier.Copy(&notifications, &notificationsModelList)
if copyErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "全局通知, 复制结构体失败, err:%+v", copyErr)
}
return &types.GetNotificationsResp{Notifications: notifications}, nil
}

View File

@@ -0,0 +1,74 @@
package pay
import (
"context"
"github.com/smartwalle/alipay/v3"
"net/http"
"time"
"tydata-server/pkg/lzkit/lzUtils"
"github.com/zeromicro/go-zero/core/logx"
"tydata-server/app/user/cmd/api/internal/svc"
)
type AlipayCallbackLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAlipayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AlipayCallbackLogic {
return &AlipayCallbackLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AlipayCallbackLogic) AlipayCallback(w http.ResponseWriter, r *http.Request) error {
notification, err := l.svcCtx.AlipayService.HandleAliPaymentNotification(r)
if err != nil {
logx.Errorf("支付宝支付回调,%+v", err)
return nil
}
order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, notification.OutTradeNo)
if findOrderErr != nil {
logx.Errorf("支付宝支付回调,查找订单失败: %+v", findOrderErr)
return nil
}
if order.Status != "pending" {
alipay.ACKNotification(w)
return nil
}
amount := lzUtils.ToAlipayAmount(order.Amount)
// 确保订单金额和状态正确,防止重复更新
if amount != notification.TotalAmount {
logx.Errorf("支付宝支付回调,金额不一致")
return nil
}
if order.Status != "pending" {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("success")) // 确保只写入一次响应
return nil
}
switch notification.TradeStatus {
case alipay.TradeStatusSuccess:
order.Status = "paid"
order.PayTime = lzUtils.TimeToNullTime(time.Now())
default:
return nil
}
order.PlatformOrderId = lzUtils.StringToNullString(notification.OutTradeNo)
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
logx.Errorf("支付宝支付回调,修改订单信息失败: %+v", updateErr)
return nil
}
if order.Status == "paid" {
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
logx.Errorf("异步任务调度失败: %v", asyncErr)
return asyncErr
}
}
alipay.ACKNotification(w)
return nil
}

View File

@@ -0,0 +1,81 @@
package pay
import (
"context"
"github.com/pkg/errors"
"time"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/lzUtils"
"github.com/zeromicro/go-zero/core/logx"
)
type IapCallbackLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewIapCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *IapCallbackLogic {
return &IapCallbackLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *IapCallbackLogic) IapCallback(req *types.IapCallbackReq) error {
// Step 1: 查找订单
order, findOrderErr := l.svcCtx.OrderModel.FindOne(l.ctx, req.OrderID)
if findOrderErr != nil {
logx.Errorf("苹果内购支付回调,查找订单失败: %+v", findOrderErr)
return nil
}
// Step 2: 验证订单状态
if order.Status != "pending" {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "苹果内购支付回调, 订单状态异常: %+v", order)
}
// Step 3: 调用 VerifyReceipt 验证苹果支付凭证
//receipt := req.TransactionReceipt // 从请求中获取支付凭证
//verifyResponse, verifyErr := l.svcCtx.ApplePayService.VerifyReceipt(l.ctx, receipt)
//if verifyErr != nil {
// return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "苹果内购支付回调, 验证订单异常: %+v", verifyErr)
//}
// Step 4: 验证订单
//product, findProductErr := l.svcCtx.ProductModel.FindOne(l.ctx, order.Id)
//if findProductErr != nil {
// return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "苹果内购支付回调, 获取订单相关商品失败: %+v", findProductErr)
//}
//isProductMatched := false
//appleProductID := l.svcCtx.ApplePayService.GetIappayAppID(product.ProductEn)
//for _, item := range verifyResponse.Receipt.InApp {
// if item.ProductID == appleProductID {
// isProductMatched = true
// order.PlatformOrderId = lzUtils.StringToNullString(item.TransactionID) // 记录交易 ID
// break
// }
//}
//if !isProductMatched {
// return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "苹果内购支付回调, 商品 ID 不匹配,订单 ID: %d, 回调苹果商品 ID: %s", order.Id, verifyResponse.Receipt.InApp[0].ProductID)
//}
// Step 5: 更新订单状态 mm
order.Status = "paid"
order.PayTime = lzUtils.TimeToNullTime(time.Now())
// 更新订单到数据库
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "苹果内购支付回调, 修改订单信息失败: %+v", updateErr)
}
// Step 6: 处理订单完成后的逻辑
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "苹果内购支付回调,异步任务调度失败: %v", asyncErr)
}
return nil
}

View File

@@ -0,0 +1,136 @@
package pay
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/app/user/model"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
)
type PaymentLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic {
return &PaymentLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取用户信息失败, %+v", getUidErr)
}
brand, ok := l.ctx.Value("brand").(string)
if !ok {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取平台失败, %+v", getUidErr)
}
redisKey := fmt.Sprintf("%d:%s", userID, req.Id)
cache, cacheErr := l.svcCtx.Redis.GetCtx(l.ctx, redisKey)
if cacheErr != nil {
return nil, cacheErr
}
var data types.QueryCacheLoad
err = json.Unmarshal([]byte(cache), &data)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析缓存内容失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOneByProductEn(l.ctx, data.Product)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 查找产品错误: %+v", err)
}
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)
}
params, marshalErr := json.Marshal(data.Params)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 序列化参数失败: %+v", marshalErr)
}
encryptParams, aesEncryptErr := crypto.AesEncrypt(params, key)
if aesEncryptErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 加密参数失败: %+v", aesEncryptErr)
}
var prepayID string
var outTradeNo string
var amount float64
user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取用户信息失败: %+v", err)
}
if user.Inside == 1 {
amount = 0.01
} else {
amount = product.SellPrice
}
var createOrderErr error
if req.PayMethod == "wechatpay" {
outTradeNo = l.svcCtx.WechatPayService.GenerateOutTradeNo()
prepayID, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, amount, product.ProductName, outTradeNo)
} else if req.PayMethod == "alipay" {
outTradeNo = l.svcCtx.AlipayService.GenerateOutTradeNo()
prepayID, createOrderErr = l.svcCtx.AlipayService.CreateAlipayOrder(l.ctx, amount, product.ProductName, outTradeNo, brand)
} else if req.PayMethod == "appleiap" {
outTradeNo = l.svcCtx.ApplePayService.GenerateOutTradeNo()
prepayID = l.svcCtx.ApplePayService.GetIappayAppID(product.ProductEn)
}
if createOrderErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr)
}
var orderID int64
transErr := l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
order := model.Order{
OrderNo: outTradeNo,
UserId: userID,
ProductId: product.Id,
PaymentPlatform: req.PayMethod,
PaymentScene: "app",
Amount: amount,
Status: "pending",
}
orderInsertResult, insertOrderErr := l.svcCtx.OrderModel.Insert(ctx, session, &order)
if insertOrderErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 保存订单失败: %+v", insertOrderErr)
}
insertedOrderID, lastInsertIdErr := orderInsertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取保存订单ID失败: %+v", lastInsertIdErr)
}
orderID = insertedOrderID
query := model.Query{
OrderId: orderID,
UserId: userID,
ProductId: product.Id,
QueryParams: encryptParams,
QueryState: "pending",
}
_, insertQueryErr := l.svcCtx.QueryModel.Insert(l.ctx, session, &query)
if insertQueryErr != nil {
return insertQueryErr
}
return nil
})
if transErr != nil {
return nil, transErr
}
return &types.PaymentResp{PrepayID: prepayID, OrderID: orderID}, nil
}

View File

@@ -0,0 +1,78 @@
package pay
import (
"context"
"net/http"
"time"
"tydata-server/app/user/cmd/api/internal/service"
"tydata-server/pkg/lzkit/lzUtils"
"github.com/zeromicro/go-zero/core/logx"
"tydata-server/app/user/cmd/api/internal/svc"
)
type WechatPayCallbackLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewWechatPayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WechatPayCallbackLogic {
return &WechatPayCallbackLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WechatPayCallbackLogic) WechatPayCallback(w http.ResponseWriter, r *http.Request) error {
notification, err := l.svcCtx.WechatPayService.HandleWechatPayNotification(l.ctx, r)
if err != nil {
logx.Errorf("微信支付回调,%+v", err)
return nil
}
order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, *notification.OutTradeNo)
if findOrderErr != nil {
logx.Errorf("微信支付回调,查找订单信息失败: %+v", findOrderErr)
return nil
}
amount := lzUtils.ToWechatAmount(order.Amount)
if &amount != notification.Amount.Total {
logx.Errorf("微信支付回调,金额不一致")
return nil
}
if order.Status != "pending" {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("success")) // 确保只写入一次响应
return nil
}
switch *notification.TradeState {
case service.TradeStateSuccess:
order.Status = "paid"
order.PayTime = lzUtils.TimeToNullTime(time.Now())
case service.TradeStateClosed:
order.Status = "closed"
order.CloseTime = lzUtils.TimeToNullTime(time.Now())
case service.TradeStateRevoked:
order.Status = "failed"
default:
return nil
}
order.PlatformOrderId = lzUtils.StringToNullString(*notification.TransactionId)
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
logx.Errorf("微信支付回调,更新订单失败%+v", updateErr)
return nil
}
if order.Status == "paid" {
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
logx.Errorf("异步任务调度失败: %v", asyncErr)
return asyncErr
}
}
// 响应微信回调成功
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("success")) // 确保只写入一次响应
return nil
}

View File

@@ -0,0 +1,54 @@
package pay
import (
"context"
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
"github.com/zeromicro/go-zero/core/logx"
"net/http"
"tydata-server/app/user/cmd/api/internal/svc"
)
type WechatPayRefundCallbackLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewWechatPayRefundCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WechatPayRefundCallbackLogic {
return &WechatPayRefundCallbackLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WechatPayRefundCallbackLogic) WechatPayRefundCallback(w http.ResponseWriter, r *http.Request) error {
notification, err := l.svcCtx.WechatPayService.HandleRefundNotification(l.ctx, r)
if err != nil {
logx.Errorf("微信退款回调,%+v", err)
return nil
}
order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, *notification.OutTradeNo)
if findOrderErr != nil {
logx.Errorf("微信退款回调,查找订单信息失败: %+v", findOrderErr)
return nil
}
switch *notification.Status {
case refunddomestic.STATUS_SUCCESS:
order.Status = "refunded"
case refunddomestic.STATUS_ABNORMAL:
// 异常
return nil
default:
return nil
}
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
logx.Errorf("微信退款回调,更新订单失败%+v", updateErr)
return nil
}
// 响应微信回调成功
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("success")) // 确保只写入一次响应
return nil
}

View File

@@ -0,0 +1,74 @@
package product
import (
"context"
"github.com/Masterminds/squirrel"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/mr"
"tydata-server/app/user/model"
"tydata-server/common/xerr"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetProductByEnLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetProductByEnLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductByEnLogic {
return &GetProductByEnLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetProductByEnLogic) GetProductByEn(req *types.GetProductByEnRequest) (resp *types.ProductResponse, err error) {
productModel, err := l.svcCtx.ProductModel.FindOneByProductEn(l.ctx, req.ProductEn)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "产品查询, 查找产品错误: %+v", err)
}
build := l.svcCtx.ProductFeatureModel.SelectBuilder().Where(squirrel.Eq{
"product_id": productModel.Id,
})
productFeatureAll, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, build, "")
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "产品查询, 查找产品关联错误: %+v", err)
}
var product types.Product
err = copier.Copy(&product, productModel)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, 用户信息结构体复制失败, %+v", err)
}
mr.MapReduceVoid(func(source chan<- interface{}) {
for _, productFeature := range productFeatureAll {
source <- productFeature.FeatureId
}
}, func(item interface{}, writer mr.Writer[*model.Feature], cancel func(error)) {
id := item.(int64)
feature, findFeatureErr := l.svcCtx.FeatureModel.FindOne(l.ctx, id)
if findFeatureErr != nil {
logx.WithContext(l.ctx).Errorf("产品查询, 查找关联feature错误: %d, err:%v", id, findFeatureErr)
return
}
if feature != nil && feature.Id > 0 {
writer.Write(feature)
}
}, func(pipe <-chan *model.Feature, cancel func(error)) {
for item := range pipe {
var feature types.Feature
_ = copier.Copy(&feature, item)
product.Features = append(product.Features, feature)
}
})
return &types.ProductResponse{Product: product}, nil
}

View File

@@ -0,0 +1,30 @@
package product
import (
"context"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetProductByIDLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetProductByIDLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductByIDLogic {
return &GetProductByIDLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetProductByIDLogic) GetProductByID(req *types.GetProductByIDRequest) (resp *types.ProductResponse, err error) {
// todo: add your logic here and delete this line
return
}

View File

@@ -0,0 +1,140 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"time"
"tydata-server/app/user/cmd/api/internal/service"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/validator"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type BackgroundCheckLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewBackgroundCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackgroundCheckLogic {
return &BackgroundCheckLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *BackgroundCheckLogic) BackgroundCheck(req *types.QueryReq) (resp *types.QueryResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "人事背调, 获取用户信息失败, %+v", getUidErr)
}
// 1、AES解密
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "人事背调, 密钥获取失败: %+v", decodeErr)
}
decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key)
if aesDecryptErr != nil || len(decryptData) == 0 {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "人事背调, 解密失败: %+v", decodeErr)
}
// 2、校验
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 data.Name == "刘福思" && data.IDCard == "45262419980929047X" && data.Mobile == "17776203797" {
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "backgroundcheck",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}
// 校验验证码
codeRedisKey := fmt.Sprintf("%s:%s", "query", data.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(codeRedisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "人事背调, 验证码过期: %s", data.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "人事背调, 读取验证码redis缓存失败, mobile: %s, err: %+v", data.Mobile, err)
}
if cacheCode != data.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "人事背调, 验证码不正确: %s", data.Mobile)
}
// 3、二要素三要素核验
//twoVerification := service.TwoFactorVerificationRequest{
// Name: data.Name,
// IDCard: data.IDCard,
//}
//verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification)
//if err != nil {
// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "人事背调, 二要素验证失败: %+v", err)
//}
//if !verification.Passed {
// return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "人事背调, 二要素验证不通过: %+v", err)
//}
// 3、二要素三要素核验
threeVerification := service.ThreeFactorVerificationRequest{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
}
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(threeVerification)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "人事背调, 三要素验证失败: %+v", err)
}
if !verification.Passed {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "人事背调, 三要素验证不通过: %+v", err)
}
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "backgroundcheck",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "人事背调, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}

View File

@@ -0,0 +1,140 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"time"
"tydata-server/app/user/cmd/api/internal/service"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/validator"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CompanyInfoLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCompanyInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CompanyInfoLogic {
return &CompanyInfoLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *CompanyInfoLogic) CompanyInfo(req *types.QueryReq) (resp *types.QueryResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "企业报告, 获取用户信息失败, %+v", getUidErr)
}
// 1、AES解密
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "企业报告, 密钥获取失败: %+v", decodeErr)
}
decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key)
if aesDecryptErr != nil || len(decryptData) == 0 {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "企业报告, 解密失败: %+v", decodeErr)
}
// 2、校验
var data types.CompanyInfoReq
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 data.Name == "刘福思" && data.IDCard == "45262419980929047X" && data.Mobile == "17776203797" {
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "companyinfo",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}
// 校验验证码
codeRedisKey := fmt.Sprintf("%s:%s", "query", data.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(codeRedisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "企业报告, 验证码过期: %s", data.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "企业报告, 读取验证码redis缓存失败, mobile: %s, err: %+v", data.Mobile, err)
}
if cacheCode != data.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "企业报告, 验证码不正确: %s", data.Mobile)
}
// 3、二要素三要素核验
//twoVerification := service.TwoFactorVerificationRequest{
// Name: data.Name,
// IDCard: data.IDCard,
//}
//verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification)
//if err != nil {
// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "企业报告, 二要素验证失败: %+v", err)
//}
//if !verification.Passed {
// return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "企业报告, 二要素验证不通过: %+v", err)
//}
// 3、二要素三要素核验
threeVerification := service.ThreeFactorVerificationRequest{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
}
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(threeVerification)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "企业报告, 三要素验证失败: %+v", err)
}
if !verification.Passed {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "企业报告, 三要素验证不通过: %+v", err)
}
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "companyinfo",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "企业报告, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}

View File

@@ -0,0 +1,141 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"time"
"tydata-server/app/user/cmd/api/internal/service"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/validator"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type HomeServiceLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewHomeServiceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *HomeServiceLogic {
return &HomeServiceLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *HomeServiceLogic) HomeService(req *types.QueryReq) (resp *types.QueryResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "家政服务, 获取用户信息失败, %+v", getUidErr)
}
// 1、AES解密
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "家政服务, 密钥获取失败: %+v", decodeErr)
}
decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key)
if aesDecryptErr != nil || len(decryptData) == 0 {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "家政服务, 解密失败: %+v", decodeErr)
}
// 2、校验
var data types.HomeServiceReq
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 data.Name == "刘福思" && data.IDCard == "45262419980929047X" && data.Mobile == "17776203797" {
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "homeservice",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}
// 校验验证码
codeRedisKey := fmt.Sprintf("%s:%s", "query", data.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(codeRedisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "家政服务, 验证码过期: %s", data.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "家政服务, 读取验证码redis缓存失败, mobile: %s, err: %+v", data.Mobile, err)
}
if cacheCode != data.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "家政服务, 验证码不正确: %s", data.Mobile)
}
// 3、二要素三要素核验
//twoVerification := service.TwoFactorVerificationRequest{
// Name: data.Name,
// IDCard: data.IDCard,
//}
//verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification)
//if err != nil {
// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "家政服务, 二要素验证失败: %+v", err)
//}
//if !verification.Passed {
// return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "家政服务, 二要素验证不通过: %+v", err)
//}
// 3、二要素三要素核验
threeVerification := service.ThreeFactorVerificationRequest{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
}
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(threeVerification)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "家政服务, 三要素验证失败: %+v", err)
}
if !verification.Passed {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "家政服务, 三要素验证不通过: %+v", err)
}
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "homeservice",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "家政服务, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}

View File

@@ -0,0 +1,142 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/redis"
"time"
"tydata-server/app/user/cmd/api/internal/service"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/validator"
)
type MarriageLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewMarriageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MarriageLogic {
return &MarriageLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
const MERRIAGE = "marriage"
func (l *MarriageLogic) Marriage(req *types.QueryReq) (resp *types.QueryResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 获取用户信息失败, %+v", getUidErr)
}
// 1、AES解密
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 密钥获取失败: %+v", decodeErr)
}
decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key)
if aesDecryptErr != nil || len(decryptData) == 0 {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 解密失败: %+v", decodeErr)
}
// 2、校验
var data types.MarriageReq
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 data.Name == "刘福思" && data.IDCard == "45262419980929047X" && data.Mobile == "17776203797" {
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: MERRIAGE,
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}
// 校验验证码
codeRedisKey := fmt.Sprintf("%s:%s", "query", data.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(codeRedisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "婚恋评估, 验证码过期: %s", data.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "婚恋评估, 读取验证码redis缓存失败, mobile: %s, err: %+v", data.Mobile, err)
}
if cacheCode != data.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "婚恋评估, 验证码不正确: %s", data.Mobile)
}
//// 3、二要素核验
//twoVerification := service.TwoFactorVerificationRequest{
// Name: data.Name,
// IDCard: data.IDCard,
//}
//verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification)
//if err != nil {
// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 二要素验证失败: %+v", err)
//}
//if !verification.Passed {
// return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "婚恋评估, 二要素验证不通过: %+v", err)
//}
// 3、三要素核验
threeVerification := service.ThreeFactorVerificationRequest{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
}
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(threeVerification)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 三要素验证失败: %+v", err)
}
if !verification.Passed {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "婚恋评估, 三要素验证不通过: %+v", err)
}
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: MERRIAGE,
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}

View File

@@ -0,0 +1,140 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"time"
"tydata-server/app/user/cmd/api/internal/service"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/validator"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type PreLoanBackgroundCheckLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewPreLoanBackgroundCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PreLoanBackgroundCheckLogic {
return &PreLoanBackgroundCheckLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *PreLoanBackgroundCheckLogic) PreLoanBackgroundCheck(req *types.QueryReq) (resp *types.QueryResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "贷前背调, 获取用户信息失败, %+v", getUidErr)
}
// 1、AES解密
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "贷前背调, 密钥获取失败: %+v", decodeErr)
}
decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key)
if aesDecryptErr != nil || len(decryptData) == 0 {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "贷前背调, 解密失败: %+v", decodeErr)
}
// 2、校验
var data types.PreLoanBackgroundCheckReq
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 data.Name == "刘福思" && data.IDCard == "45262419980929047X" && data.Mobile == "17776203797" {
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "preloanbackgroundcheck",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}
// 校验验证码
codeRedisKey := fmt.Sprintf("%s:%s", "query", data.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(codeRedisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "贷前背调, 验证码过期: %s", data.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "贷前背调, 读取验证码redis缓存失败, mobile: %s, err: %+v", data.Mobile, err)
}
if cacheCode != data.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "贷前背调, 验证码不正确: %s", data.Mobile)
}
// 3、二要素三要素核验
//twoVerification := service.TwoFactorVerificationRequest{
// Name: data.Name,
// IDCard: data.IDCard,
//}
//verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification)
//if err != nil {
// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "贷前背调, 二要素验证失败: %+v", err)
//}
//if !verification.Passed {
// return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "贷前背调, 二要素验证不通过: %+v", err)
//}
// 3、二要素三要素核验
threeVerification := service.ThreeFactorVerificationRequest{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
}
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(threeVerification)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "贷前背调, 三要素验证失败: %+v", err)
}
if !verification.Passed {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "贷前背调, 三要素验证不通过: %+v", err)
}
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "preloanbackgroundcheck",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "贷前背调, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}

View File

@@ -0,0 +1,177 @@
package query
import (
"context"
"database/sql"
"encoding/hex"
"encoding/json"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"time"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/delay"
"tydata-server/pkg/lzkit/lzUtils"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryDetailByOrderIdLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryDetailByOrderIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryDetailByOrderIdLogic {
return &QueryDetailByOrderIdLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryDetailByOrderIdLogic) QueryDetailByOrderId(req *types.QueryDetailByOrderIdReq) (resp *types.QueryDetailByOrderIdResp, err error) {
// 获取订单信息
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, req.OrderId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
// 创建渐进式延迟策略实例
progressiveDelayOrder, err := delay.New(200*time.Millisecond, 3*time.Second, 10*time.Second, 1.5)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "初始化渐进式延迟策略失败: %+v", err)
}
// 等待订单状态变为 "paid"
startTime := time.Now()
for order.Status == "pending" {
if time.Since(startTime) > 10*time.Second {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_WAIT, ""), "")
}
// 使用渐进式延迟,获取下次延迟时间
nextDelay, _ := progressiveDelayOrder.NextDelay()
// 等待一段时间后再查一次订单状态
time.Sleep(nextDelay)
// 再次查找订单
order, err = l.svcCtx.OrderModel.FindOne(l.ctx, req.OrderId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找订单错误: %+v", err)
}
}
if order.Status != "paid" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_ERROR, ""), "")
}
// 获取报告信息
queryModel, err := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, req.OrderId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
// 创建渐进式延迟实例
progressiveDelayQuery, err := delay.New(200*time.Millisecond, 3*time.Second, 10*time.Second, 1.5)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "初始化渐进式延迟策略失败: %+v", err)
}
// 等待 queryModel.QueryState 不再是 "pending"
startTime = time.Now()
for queryModel.QueryState == "pending" {
if time.Since(startTime) > 10*time.Second {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询超时,查询状态长时间为 'pending'")
}
// 使用渐进式延迟,获取下次延迟时间
nextDelay, _ := progressiveDelayQuery.NextDelay()
// 每隔一段时间检查一次查询状态
time.Sleep(nextDelay)
// 再次查询 report 状态
queryModel, err = l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, req.OrderId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
}
// 根据 QueryState 做后续处理
if queryModel.QueryState == "failed" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_ERROR, ""), "")
}
var query types.Query
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
// 解密查询数据
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", err)
}
processParamsErr := ProcessQueryParams(queryModel.QueryParams, &query.QueryParams, key)
if processParamsErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告参数处理失败: %v", processParamsErr)
}
processErr := ProcessQueryData(queryModel.QueryData, &query.QueryData, key)
if processErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结果处理失败: %v", processErr)
}
// 复制报告数据
err = copier.Copy(&query, queryModel)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结构体复制失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
return &types.QueryDetailByOrderIdResp{
Query: query,
}, nil
}
// ProcessQueryData 解密和反序列化 QueryData
func ProcessQueryData(queryData sql.NullString, target *[]map[string]interface{}, key []byte) error {
queryDataStr := lzUtils.NullStringToString(queryData)
if queryDataStr == "" {
return nil
}
// 解密 queryData
decryptedData, decryptErr := crypto.AesDecrypt(queryDataStr, key)
if decryptErr != nil {
return decryptErr
}
// 反序列化解密后的数据
unmarshalErr := json.Unmarshal(decryptedData, target)
if unmarshalErr != nil {
return unmarshalErr
}
return nil
}
// ProcessQueryParams解密和反序列化 QueryParams
func ProcessQueryParams(QueryParams string, target *map[string]interface{}, key []byte) error {
// 解密 QueryParams
decryptedData, decryptErr := crypto.AesDecrypt(QueryParams, key)
if decryptErr != nil {
return decryptErr
}
// 反序列化解密后的数据
unmarshalErr := json.Unmarshal(decryptedData, target)
if unmarshalErr != nil {
return unmarshalErr
}
return nil
}

View File

@@ -0,0 +1,135 @@
package query
import (
"context"
"encoding/hex"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"time"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/delay"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryDetailByOrderNoLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryDetailByOrderNoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryDetailByOrderNoLogic {
return &QueryDetailByOrderNoLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryDetailByOrderNoLogic) QueryDetailByOrderNo(req *types.QueryDetailByOrderNoReq) (resp *types.QueryDetailByOrderNoResp, err error) {
// 获取订单信息
order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
// 创建渐进式延迟策略实例
progressiveDelayOrder, err := delay.New(200*time.Millisecond, 3*time.Second, 10*time.Second, 1.5)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "初始化渐进式延迟策略失败: %+v", err)
}
// 等待订单状态变为 "paid"
startTime := time.Now()
for order.Status == "pending" {
if time.Since(startTime) > 10*time.Second {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_WAIT, ""), "")
}
// 使用渐进式延迟,获取下次延迟时间
nextDelay, _ := progressiveDelayOrder.NextDelay()
// 等待一段时间后再查一次订单状态
time.Sleep(nextDelay)
// 再次查找订单
order, err = l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找订单错误: %+v", err)
}
}
if order.Status != "paid" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_ERROR, ""), "")
}
// 获取报告信息
queryModel, err := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, order.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
// 创建渐进式延迟实例
progressiveDelayQuery, err := delay.New(200*time.Millisecond, 3*time.Second, 10*time.Second, 1.5)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "初始化渐进式延迟策略失败: %+v", err)
}
// 等待 queryModel.QueryState 不再是 "pending"
startTime = time.Now()
for queryModel.QueryState == "pending" {
if time.Since(startTime) > 10*time.Second {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询超时,查询状态长时间为 'pending'")
}
// 使用渐进式延迟,获取下次延迟时间
nextDelay, _ := progressiveDelayQuery.NextDelay()
// 每隔一段时间检查一次查询状态
time.Sleep(nextDelay)
// 再次查询 report 状态
queryModel, err = l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, order.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
}
// 根据 QueryState 做后续处理
if queryModel.QueryState == "failed" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIC_QUERY_ERROR, ""), "")
}
var query types.Query
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
// 解密查询数据
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", err)
}
processParamsErr := ProcessQueryParams(queryModel.QueryParams, &query.QueryParams, key)
if processParamsErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告参数处理失败: %v", processParamsErr)
}
processErr := ProcessQueryData(queryModel.QueryData, &query.QueryData, key)
if processErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结果处理失败: %v", processErr)
}
// 复制报告数据
err = copier.Copy(&query, queryModel)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结构体复制失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
return &types.QueryDetailByOrderNoResp{
Query: query,
}, nil
}

View File

@@ -0,0 +1,69 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/lzUtils"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryDetailLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryDetailLogic {
return &QueryDetailLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryDetailLogic) QueryDetail(req *types.QueryDetailReq) (resp *types.QueryDetailResp, err error) {
queryModel, err := l.svcCtx.QueryModel.FindOne(l.ctx, req.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
}
var query types.Query
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
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", err)
}
if lzUtils.NullStringToString(queryModel.QueryData) != "" {
queryData, decryptErr := crypto.AesDecrypt(lzUtils.NullStringToString(queryModel.QueryData), key)
if decryptErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结果解密失败, %+v", decryptErr)
}
unmarshalErr := json.Unmarshal(queryData, &query.QueryData)
if unmarshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结构体处理失败, %+v", unmarshalErr)
}
}
err = copier.Copy(&query, queryModel)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结构体复制失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
return &types.QueryDetailResp{
Query: query,
}, nil
}

View File

@@ -0,0 +1,108 @@
package query
import (
"context"
"encoding/hex"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/common/xerr"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryExampleLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryExampleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryExampleLogic {
return &QueryExampleLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryExampleLogic) QueryExample(req *types.QueryExampleReq) (resp *types.QueryExampleResp, err error) {
var exampleID int64
switch req.Feature {
case "toc_PhoneThreeElements":
exampleID = 83
case "toc_BankCardBlacklist":
exampleID = 106
case "toc_IDCardTwoElements":
exampleID = 85
case "toc_PhoneTwoElements":
exampleID = 86
case "toc_NetworkDuration":
exampleID = 117
case "toc_PhoneSecondaryCard":
exampleID = 124
case "toc_PhoneNumberRisk":
exampleID = 126
case "toc_BankCardFourElements":
exampleID = 131
//case "toc_BankCardThreeElements":
// exampleID = 9
//case "toc_NaturalLifeStatus":
// exampleID = 10
//case "toc_EducationVerification":
// exampleID = 11
case "toc_PersonVehicleVerification":
exampleID = 110
case "toc_VehiclesUnderName":
exampleID = 108
case "toc_DualMarriage":
exampleID = 103
case "toc_PersonalBadRecord":
exampleID = 73
case "toc_ShareholderBusinessRelation":
exampleID = 16
case "toc_PersonalLawsuit":
exampleID = 75
case "toc_EnterpriseLawsuit":
exampleID = 81
case "toc_Marriage":
exampleID = 367
default:
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "示例报告, 获取示例报告失败: %v", err)
}
queryModel, err := l.svcCtx.QueryModel.FindOne(l.ctx, exampleID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "示例报告, 获取示例报告失败: %v", err)
}
var query types.Query
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
// 解密查询数据
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", err)
}
processParamsErr := ProcessQueryParams(queryModel.QueryParams, &query.QueryParams, key)
if processParamsErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 报告参数处理失败: %v", processParamsErr)
}
processErr := ProcessQueryData(queryModel.QueryData, &query.QueryData, key)
if processErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 报告结果处理失败: %v", processErr)
}
// 复制报告数据
err = copier.Copy(&query, queryModel)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 报告结构体复制失败, %+v", err)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "示例报告, 获取商品信息失败, %+v", err)
}
query.ProductName = product.ProductName
return &types.QueryExampleResp{
Query: query,
}, nil
}

View File

@@ -0,0 +1,72 @@
package query
import (
"context"
"github.com/Masterminds/squirrel"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
)
type QueryListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryListLogic {
return &QueryListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryListLogic) QueryList(req *types.QueryListReq) (resp *types.QueryListResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告列表查询, 获取用户信息失败, %+v", getUidErr)
}
build := l.svcCtx.OrderModel.SelectBuilder().Where(squirrel.Eq{
"user_id": userID,
}).Where(squirrel.NotEq{
"status": []string{"pending", "closed"},
})
orderList, total, err := l.svcCtx.OrderModel.FindPageListByPageWithTotal(l.ctx, build, req.Page, req.PageSize, "create_time DESC")
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告列表查询, 查找订单列表错误, %+v", err)
}
var list []types.Query
if len(orderList) > 0 {
for _, orderModel := range orderList {
queryModel, findQueryErr := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, orderModel.Id)
if findQueryErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 查找报告错误, %+v", findQueryErr)
}
var query types.Query
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
copyErr := copier.Copy(&query, queryModel)
if copyErr != nil {
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)
}
query.ProductName = product.ProductName
list = append(list, query)
}
}
return &types.QueryListResp{
Total: total,
List: list,
}, nil
}

View File

@@ -0,0 +1,62 @@
package query
import (
"context"
"encoding/json"
"fmt"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryProvisionalOrderLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryProvisionalOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryProvisionalOrderLogic {
return &QueryProvisionalOrderLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryProvisionalOrderLogic) QueryProvisionalOrder(req *types.QueryProvisionalOrderReq) (resp *types.QueryProvisionalOrderResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取临时订单, 获取用户信息失败, %+v", getUidErr)
}
redisKey := fmt.Sprintf("%d:%s", userID, req.Id)
cache, cacheErr := l.svcCtx.Redis.GetCtx(l.ctx, redisKey)
if cacheErr != nil {
return nil, cacheErr
}
var data types.QueryCache
err = json.Unmarshal([]byte(cache), &data)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取临时订单, 解析缓存内容失败, %+v", err)
}
productModel, err := l.svcCtx.ProductModel.FindOneByProductEn(l.ctx, data.Product)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取临时订单, 查找产品错误: %+v", err)
}
var product types.Product
err = copier.Copy(&product, productModel)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取临时订单, 用户信息结构体复制失败: %+v", err)
}
return &types.QueryProvisionalOrderResp{
Name: data.Name,
IdCard: data.Name,
Mobile: data.Mobile,
Product: product,
}, nil
}

View File

@@ -0,0 +1,43 @@
package query
import (
"context"
"github.com/pkg/errors"
"tydata-server/common/xerr"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryRetryLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryRetryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryRetryLogic {
return &QueryRetryLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryRetryLogic) QueryRetry(req *types.QueryRetryReq) (resp *types.QueryRetryResp, err error) {
query, err := l.svcCtx.QueryModel.FindOne(l.ctx, req.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询重试, 查找报告失败, %+v", err)
}
if query.QueryState == "success" {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.LOGIN_FAILED, "该报告不能重试"), "报告查询重试, 该报告不能重试, %d", query.Id)
}
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(query.OrderId); asyncErr != nil {
logx.Errorf("异步任务调度失败: %v", asyncErr)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询重试, 异步任务调度失败, %+v", asyncErr)
}
return
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"time"
"tydata-server/app/user/cmd/api/internal/service"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/validator"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type RentalInfoLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewRentalInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RentalInfoLogic {
return &RentalInfoLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *RentalInfoLogic) RentalInfo(req *types.QueryReq) (resp *types.QueryResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "租赁服务, 获取用户信息失败, %+v", getUidErr)
}
// 1、AES解密
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "租赁服务, 密钥获取失败: %+v", decodeErr)
}
decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key)
if aesDecryptErr != nil || len(decryptData) == 0 {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "租赁服务, 解密失败: %+v", decodeErr)
}
// 2、校验
var data types.RentalInfoReq
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 data.Name == "刘福思" && data.IDCard == "45262419980929047X" && data.Mobile == "17776203797" {
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "rentalinfo",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}
// 校验验证码
codeRedisKey := fmt.Sprintf("%s:%s", "query", data.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(codeRedisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "租赁服务, 验证码过期: %s", data.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "租赁服务, 读取验证码redis缓存失败, mobile: %s, err: %+v", data.Mobile, err)
}
if cacheCode != data.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "租赁服务, 验证码不正确: %s", data.Mobile)
}
// 3、二要素三要素核验
//twoVerification := service.TwoFactorVerificationRequest{
// Name: data.Name,
// IDCard: data.IDCard,
//}
//verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification)
//if err != nil {
// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "租赁服务, 二要素验证失败: %+v", err)
//}
//if !verification.Passed {
// return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "租赁服务, 二要素验证不通过: %+v", err)
//}
// 3、二要素三要素核验
threeVerification := service.ThreeFactorVerificationRequest{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
}
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(threeVerification)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "租赁服务, 三要素验证失败: %+v", err)
}
if !verification.Passed {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "租赁服务, 三要素验证不通过: %+v", err)
}
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "rentalinfo",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "租赁服务, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}

View File

@@ -0,0 +1,140 @@
package query
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"time"
"tydata-server/app/user/cmd/api/internal/service"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/validator"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type RiskAssessmentLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewRiskAssessmentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RiskAssessmentLogic {
return &RiskAssessmentLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *RiskAssessmentLogic) RiskAssessment(req *types.QueryReq) (resp *types.QueryResp, err error) {
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
if getUidErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "个人风险, 获取用户信息失败, %+v", getUidErr)
}
// 1、AES解密
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "个人风险, 密钥获取失败: %+v", decodeErr)
}
decryptData, aesDecryptErr := crypto.AesDecrypt(req.Data, key)
if aesDecryptErr != nil || len(decryptData) == 0 {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "个人风险, 解密失败: %+v", decodeErr)
}
// 2、校验
var data types.RiskAssessmentReq
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 data.Name == "刘福思" && data.IDCard == "45262419980929047X" && data.Mobile == "17776203797" {
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "riskassessment",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "婚恋评估, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}
// 校验验证码
codeRedisKey := fmt.Sprintf("%s:%s", "query", data.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(codeRedisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "个人风险, 验证码过期: %s", data.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "个人风险, 读取验证码redis缓存失败, mobile: %s, err: %+v", data.Mobile, err)
}
if cacheCode != data.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "个人风险, 验证码不正确: %s", data.Mobile)
}
// 3、二要素三要素核验
//twoVerification := service.TwoFactorVerificationRequest{
// Name: data.Name,
// IDCard: data.IDCard,
//}
//verification, err := l.svcCtx.VerificationService.TwoFactorVerification(twoVerification)
//if err != nil {
// return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "个人风险, 二要素验证失败: %+v", err)
//}
//if !verification.Passed {
// return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "个人风险, 二要素验证不通过: %+v", err)
//}
// 3、二要素三要素核验
threeVerification := service.ThreeFactorVerificationRequest{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
}
verification, err := l.svcCtx.VerificationService.ThreeFactorVerification(threeVerification)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "个人风险, 三要素验证失败: %+v", err)
}
if !verification.Passed {
return nil, errors.Wrapf(xerr.NewErrCodeMsg(xerr.SERVER_COMMON_ERROR, verification.Err.Error()), "个人风险, 三要素验证不通过: %+v", err)
}
// 缓存
queryCache := types.QueryCache{
Name: data.Name,
IDCard: data.IDCard,
Mobile: data.Mobile,
Product: "riskassessment",
}
jsonData, marshalErr := json.Marshal(queryCache)
if marshalErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "个人风险, 序列化参数失败: %+v", marshalErr)
}
outTradeNo := l.svcCtx.WechatPayService.GenerateOutTradeNo()
redisKey := fmt.Sprintf("%d:%s", userID, outTradeNo)
cacheErr := l.svcCtx.Redis.SetexCtx(l.ctx, redisKey, string(jsonData), int(2*time.Hour))
if cacheErr != nil {
return nil, cacheErr
}
return &types.QueryResp{Id: outTradeNo}, nil
}

View File

@@ -0,0 +1,46 @@
package user
import (
"context"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"github.com/zeromicro/go-zero/core/logx"
)
type DetailLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DetailLogic {
return &DetailLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *DetailLogic) Detail() (resp *types.UserInfoResp, err error) {
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %+v", err)
}
user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "用户信息, 数据库查询用户信息失败, %+v", err)
}
var userInfo types.User
err = copier.Copy(&userInfo, user)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, 用户信息结构体复制失败, %+v", err)
}
return &types.UserInfoResp{
UserInfo: userInfo,
}, nil
}

View File

@@ -0,0 +1,48 @@
package user
import (
"context"
"github.com/pkg/errors"
"time"
"tydata-server/common/ctxdata"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetTokenLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTokenLogic {
return &GetTokenLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetTokenLogic) GetToken() (resp *types.MobileCodeLoginResp, err error) {
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %+v", err)
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %d", userID)
}
// 获取当前时间戳
now := time.Now().Unix()
return &types.MobileCodeLoginResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}

View File

@@ -0,0 +1,99 @@
package user
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"time"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/app/user/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"github.com/zeromicro/go-zero/core/logx"
)
type MobileCodeLoginLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewMobileCodeLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MobileCodeLoginLogic {
return &MobileCodeLoginLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (resp *types.MobileCodeLoginResp, err error) {
if !l.MobileCodeLoginInside(req) {
// 检查手机号是否在一分钟内已发送过验证码
redisKey := fmt.Sprintf("%s:%s", "login", req.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "手机登录, 验证码过期: %s", req.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取验证码redis缓存失败, mobile: %s, err: %+v", req.Mobile, err)
}
if cacheCode != req.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确: %s", req.Mobile)
}
}
user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, req.Mobile)
if findUserErr != nil && findUserErr != model.ErrNotFound {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取数据库获取用户失败, mobile: %s, err: %+v", req.Mobile, err)
}
if user == nil {
user = &model.User{Mobile: req.Mobile}
if len(user.Nickname) == 0 {
user.Nickname = req.Mobile
}
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user)
if userInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入新用户失败, mobile%s, err: %+v", req.Mobile, err)
}
lastId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 获取新用户ID失败, err:%+v, user:%+v", lastInsertIdErr, user)
}
user.Id = lastId
userAuth := new(model.UserAuth)
userAuth.UserId = lastId
userAuth.AuthKey = req.Mobile
userAuth.AuthType = model.UserAuthTypeAppMobile
if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, userAuth); userAuthInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入用户认证失败, err:%+v", userAuthInsertErr)
}
return nil
}); transErr != nil {
return nil, transErr
}
}
token, generaErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", user.Id)
}
// 获取当前时间戳
now := time.Now().Unix()
return &types.MobileCodeLoginResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}
func (l *MobileCodeLoginLogic) MobileCodeLoginInside(req *types.MobileCodeLoginReq) (pass bool) {
if req.Mobile == "17776203797" && req.Code == "688629" {
return true
}
return false
}

View File

@@ -0,0 +1,57 @@
package user
import (
"context"
"github.com/pkg/errors"
"time"
"tydata-server/app/user/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/tool"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/lzUtils"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type MobileLoginLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewMobileLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MobileLoginLogic {
return &MobileLoginLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *MobileLoginLogic) MobileLogin(req *types.MobileLoginReq) (resp *types.MobileCodeLoginResp, err error) {
user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, req.Mobile)
if findUserErr != nil && findUserErr != model.ErrNotFound {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取数据库获取用户失败, mobile%s, err: %+v", req.Mobile, err)
}
if user == nil {
return nil, errors.Wrapf(xerr.NewErrMsg("手机号码未注册"), "手机登录, 手机号未注册:%s", req.Mobile)
}
if !(tool.Md5ByString(req.Password) == lzUtils.NullStringToString(user.Password)) {
return nil, errors.Wrapf(xerr.NewErrMsg("密码不正确"), "手机登录, 密码匹配不正确%s", req.Mobile)
}
token, generaErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", user.Id)
}
// 获取当前时间戳
now := time.Now().Unix()
return &types.MobileCodeLoginResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}

View File

@@ -0,0 +1,98 @@
package user
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"time"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"tydata-server/app/user/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/tool"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/lzUtils"
"github.com/zeromicro/go-zero/core/logx"
)
type RegisterLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic {
return &RegisterLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *RegisterLogic) Register(req *types.RegisterReq) (resp *types.RegisterResp, err error) {
// 检查手机号是否在一分钟内已发送过验证码
redisKey := fmt.Sprintf("%s:%s", "register", req.Mobile)
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "手机注册, 验证码过期: %s", req.Mobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 读取验证码redis缓存失败, mobile: %s, err: %+v", req.Mobile, err)
}
if cacheCode != req.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机注册, 验证码不正确: %s", req.Mobile)
}
hasUser, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, req.Mobile)
if findUserErr != nil && findUserErr != model.ErrNotFound {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 读取数据库获取用户失败, mobile%s, err: %+v", req.Mobile, err)
}
if hasUser != nil {
return nil, errors.Wrapf(xerr.NewErrMsg("该手机号码已注册"), "手机注册, 手机号码已注册, mobile:%s", req.Mobile)
}
var userId int64
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
user := new(model.User)
user.Mobile = req.Mobile
if len(user.Nickname) == 0 {
user.Nickname = req.Mobile
}
if len(req.Password) > 0 {
user.Password = lzUtils.StringToNullString(tool.Md5ByString(req.Password))
}
insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user)
if userInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入新用户失败, mobile%s, err: %+v", req.Mobile, err)
}
lastId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 获取新用户ID失败, err:%+v, user:%+v", lastInsertIdErr, user)
}
userId = lastId
userAuth := new(model.UserAuth)
userAuth.UserId = lastId
userAuth.AuthKey = req.Mobile
userAuth.AuthType = model.UserAuthTypeAppMobile
if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, userAuth); userAuthInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入用户认证失败, err:%+v", userAuthInsertErr)
}
return nil
}); transErr != nil {
return nil, transErr
}
token, generaErr := jwtx.GenerateJwtToken(userId, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机注册, 生成jwt token失败, userid: %d, err:%+v", userId, generaErr)
}
// 获取当前时间戳
now := time.Now().Unix()
return &types.RegisterResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}

View File

@@ -0,0 +1,135 @@
package user
import (
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"io"
"net/http"
"time"
"tydata-server/app/user/model"
jwtx "tydata-server/common/jwt"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type WxH5AuthLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewWxH5AuthLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WxH5AuthLogic {
return &WxH5AuthLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthResp, err error) {
// Step 1: 使用code获取access_token
accessTokenResp, err := GetAccessToken(req.Code)
if err != nil {
return nil, errors.Wrap(err, "获取access_token失败")
}
// Step 2: 查找用户授权信息
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, accessTokenResp.Openid, "h5-weixin")
if findErr != nil && !errors.Is(findErr, model.ErrNotFound) {
return nil, errors.Wrapf(findErr, "查询用户授权失败openid: %s", accessTokenResp.Openid)
}
// Step 3: 查找或创建用户
var user *model.User
if userAuth != nil {
// 授权信息存在,查找用户
userModel, findUserErr := l.svcCtx.UserModel.FindOne(l.ctx, userAuth.UserId)
if findUserErr != nil {
return nil, errors.Wrapf(findUserErr, "查询用户失败userId: %d", userAuth.UserId)
}
user = userModel
} else {
// 授权信息不存在,创建新用户
user = &model.User{}
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(context context.Context, session sqlx.Session) error {
// 插入数据库
insertResult, insertErr := l.svcCtx.UserModel.Insert(l.ctx, session, user)
if insertErr != nil {
return errors.Wrapf(insertErr, "创建新用户失败openid: %s", accessTokenResp.Openid)
}
// 获取插入后生成的 user.Id
lastInsertId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(lastInsertIdErr, "获取新用户ID失败openid: %s", accessTokenResp.Openid)
}
user.Id = lastInsertId
// 创建用户授权信息
userAuth = &model.UserAuth{
UserId: user.Id,
AuthKey: accessTokenResp.Openid,
AuthType: "mp-weixin", // 微信小程序
}
if _, insertUserAuthErr := l.svcCtx.UserAuthModel.Insert(l.ctx, session, userAuth); insertUserAuthErr != nil {
return errors.Wrapf(insertUserAuthErr, "创建用户授权失败openid: %s", accessTokenResp.Openid)
}
return nil
}); transErr != nil {
return nil, transErr
}
}
// Step 4: 生成JWT Token
token, genErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if genErr != nil {
return nil, errors.Wrap(genErr, "生成JWT token失败")
}
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 {
AccessToken string `json:"access_token"`
Openid string `json:"openid"`
}
// GetAccessToken 通过code获取access_token
func GetAccessToken(code string) (*AccessTokenResp, error) {
appID := "wxd1554b7a57cecc9e"
appSecret := "fb8026c0bc66625b580453300d4b43db"
url := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appID, appSecret, code)
resp, err := http.Get(url)
if err != nil {
return nil, errors.Wrap(err, "获取access_token失败")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "读取access_token响应失败")
}
var accessTokenResp AccessTokenResp
if err := json.Unmarshal(body, &accessTokenResp); err != nil {
return nil, errors.Wrap(err, "解析access_token响应失败")
}
if accessTokenResp.AccessToken == "" {
return nil, errors.New("获取access_token失败")
}
return &accessTokenResp, nil
}

View File

@@ -0,0 +1,30 @@
package user
import (
"context"
"tydata-server/app/user/cmd/api/internal/svc"
"tydata-server/app/user/cmd/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type WxMiniAuthLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewWxMiniAuthLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WxMiniAuthLogic {
return &WxMiniAuthLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WxMiniAuthLogic) WxMiniAuth(req *types.WXMiniAuthReq) (resp *types.WXMiniAuthResp, err error) {
// todo: add your logic here and delete this line
return
}