add query url share
This commit is contained in:
parent
1bff356eb8
commit
bebabce346
@ -116,8 +116,23 @@ service main {
|
|||||||
@doc "确认查询状态"
|
@doc "确认查询状态"
|
||||||
@handler confirmQueryState
|
@handler confirmQueryState
|
||||||
post /query/confirm_state (ConfirmQueryStateReq) returns (ConfirmQueryStateResp)
|
post /query/confirm_state (ConfirmQueryStateReq) returns (ConfirmQueryStateResp)
|
||||||
|
|
||||||
|
@doc "生成分享链接"
|
||||||
|
@handler QueryGenerateShareLink
|
||||||
|
post /query/generate_share_link (QueryGenerateShareLinkReq) returns (QueryGenerateShareLinkResp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
QueryGenerateShareLinkReq {
|
||||||
|
OrderId *int64 `json:"order_id,optional"`
|
||||||
|
OrderNo *string `json:"order_no,optional"`
|
||||||
|
}
|
||||||
|
QueryGenerateShareLinkResp {
|
||||||
|
ShareLink string `json:"share_link"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
// 获取查询临时订单
|
// 获取查询临时订单
|
||||||
type (
|
type (
|
||||||
QueryProvisionalOrderReq {
|
QueryProvisionalOrderReq {
|
||||||
@ -208,15 +223,23 @@ service main {
|
|||||||
post /query/single/test (QuerySingleTestReq) returns (QuerySingleTestResp)
|
post /query/single/test (QuerySingleTestReq) returns (QuerySingleTestResp)
|
||||||
|
|
||||||
@doc "查询详情"
|
@doc "查询详情"
|
||||||
@handler queryDetail
|
@handler queryShareDetail
|
||||||
get /query/:id (QueryDetailReq) returns (QueryDetailResp)
|
get /query/share/:id (QueryShareDetailReq) returns (QueryShareDetailResp)
|
||||||
|
|
||||||
@doc "查询示例"
|
@doc "查询示例"
|
||||||
@handler queryExample
|
@handler queryExample
|
||||||
get /query/example (QueryExampleReq) returns (QueryExampleResp)
|
get /query/example (QueryExampleReq) returns (QueryExampleResp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
type (
|
||||||
|
QueryShareDetailReq {
|
||||||
|
Id string `path:"id"`
|
||||||
|
}
|
||||||
|
QueryShareDetailResp {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Query
|
||||||
|
}
|
||||||
|
)
|
||||||
type QuerySingleTestReq {
|
type QuerySingleTestReq {
|
||||||
Params map[string]interface{} `json:"params"`
|
Params map[string]interface{} `json:"params"`
|
||||||
Api string `json:"api"`
|
Api string `json:"api"`
|
||||||
|
@ -70,3 +70,5 @@ CloudAuth:
|
|||||||
Endpoint: "cloudauth.aliyuncs.com"
|
Endpoint: "cloudauth.aliyuncs.com"
|
||||||
SceneId: 1000013341
|
SceneId: 1000013341
|
||||||
ReturnUrl: "https://www.quannengcha.com/authorization/result"
|
ReturnUrl: "https://www.quannengcha.com/authorization/result"
|
||||||
|
Query:
|
||||||
|
ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒
|
||||||
|
@ -71,3 +71,5 @@ CloudAuth:
|
|||||||
Endpoint: "cloudauth.aliyuncs.com"
|
Endpoint: "cloudauth.aliyuncs.com"
|
||||||
SceneId: 1000013341
|
SceneId: 1000013341
|
||||||
ReturnUrl: "https://www.quannengcha.com/authorization/result"
|
ReturnUrl: "https://www.quannengcha.com/authorization/result"
|
||||||
|
Query:
|
||||||
|
ShareLinkExpire: 604800 # 7天 = 7 * 24 * 60 * 60 = 604800秒
|
||||||
|
@ -21,6 +21,7 @@ type Config struct {
|
|||||||
SystemConfig SystemConfig
|
SystemConfig SystemConfig
|
||||||
WechatH5 WechatH5Config
|
WechatH5 WechatH5Config
|
||||||
CloudAuth CloudAuthConfig
|
CloudAuth CloudAuthConfig
|
||||||
|
Query QueryConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// JwtAuth 用于 JWT 鉴权配置
|
// JwtAuth 用于 JWT 鉴权配置
|
||||||
@ -100,3 +101,6 @@ type CloudAuthConfig struct {
|
|||||||
SceneId int64
|
SceneId int64
|
||||||
ReturnUrl string
|
ReturnUrl string
|
||||||
}
|
}
|
||||||
|
type QueryConfig struct {
|
||||||
|
ShareLinkExpire int64
|
||||||
|
}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"qnc-server/app/user/cmd/api/internal/logic/query"
|
||||||
|
"qnc-server/app/user/cmd/api/internal/svc"
|
||||||
|
"qnc-server/app/user/cmd/api/internal/types"
|
||||||
|
"qnc-server/common/result"
|
||||||
|
"qnc-server/pkg/lzkit/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func QueryGenerateShareLinkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.QueryGenerateShareLinkReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
result.ParamErrorResult(r, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := validator.Validate(req); err != nil {
|
||||||
|
result.ParamValidateErrorResult(r, w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l := query.NewQueryGenerateShareLinkLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.QueryGenerateShareLink(&req)
|
||||||
|
result.HttpResult(r, w, resp, err)
|
||||||
|
}
|
||||||
|
}
|
@ -3,18 +3,17 @@ package query
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
"qnc-server/app/user/cmd/api/internal/logic/query"
|
"qnc-server/app/user/cmd/api/internal/logic/query"
|
||||||
"qnc-server/app/user/cmd/api/internal/svc"
|
"qnc-server/app/user/cmd/api/internal/svc"
|
||||||
"qnc-server/app/user/cmd/api/internal/types"
|
"qnc-server/app/user/cmd/api/internal/types"
|
||||||
"qnc-server/common/result"
|
"qnc-server/common/result"
|
||||||
"qnc-server/pkg/lzkit/validator"
|
"qnc-server/pkg/lzkit/validator"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func QueryDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func QueryShareDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
var req types.QueryDetailReq
|
var req types.QueryShareDetailReq
|
||||||
if err := httpx.Parse(r, &req); err != nil {
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
result.ParamErrorResult(r, w, err)
|
result.ParamErrorResult(r, w, err)
|
||||||
return
|
return
|
||||||
@ -23,8 +22,8 @@ func QueryDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
result.ParamValidateErrorResult(r, w, err)
|
result.ParamValidateErrorResult(r, w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l := query.NewQueryDetailLogic(r.Context(), svcCtx)
|
l := query.NewQueryShareDetailLogic(r.Context(), svcCtx)
|
||||||
resp, err := l.QueryDetail(&req)
|
resp, err := l.QueryShareDetail(&req)
|
||||||
result.HttpResult(r, w, resp, err)
|
result.HttpResult(r, w, resp, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -309,6 +309,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
Path: "/query/confirm_state",
|
Path: "/query/confirm_state",
|
||||||
Handler: query.ConfirmQueryStateHandler(serverCtx),
|
Handler: query.ConfirmQueryStateHandler(serverCtx),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// 生成分享链接
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/query/generate_share_link",
|
||||||
|
Handler: query.QueryGenerateShareLinkHandler(serverCtx),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// 查询列表
|
// 查询列表
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
@ -352,18 +358,18 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
|
|
||||||
server.AddRoutes(
|
server.AddRoutes(
|
||||||
[]rest.Route{
|
[]rest.Route{
|
||||||
{
|
|
||||||
// 查询详情
|
|
||||||
Method: http.MethodGet,
|
|
||||||
Path: "/query/:id",
|
|
||||||
Handler: query.QueryDetailHandler(serverCtx),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
// 查询示例
|
// 查询示例
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
Path: "/query/example",
|
Path: "/query/example",
|
||||||
Handler: query.QueryExampleHandler(serverCtx),
|
Handler: query.QueryExampleHandler(serverCtx),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// 查询详情
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/query/share/:id",
|
||||||
|
Handler: query.QueryShareDetailHandler(serverCtx),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
Path: "/query/single/test",
|
Path: "/query/single/test",
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
package query
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"qnc-server/common/xerr"
|
|
||||||
"qnc-server/pkg/lzkit/crypto"
|
|
||||||
"qnc-server/pkg/lzkit/lzUtils"
|
|
||||||
|
|
||||||
"github.com/jinzhu/copier"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"qnc-server/app/user/cmd/api/internal/svc"
|
|
||||||
"qnc-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
|
|
||||||
}
|
|
@ -0,0 +1,111 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"qnc-server/app/user/cmd/api/internal/svc"
|
||||||
|
"qnc-server/app/user/cmd/api/internal/types"
|
||||||
|
"qnc-server/app/user/model"
|
||||||
|
"qnc-server/common/ctxdata"
|
||||||
|
"qnc-server/common/xerr"
|
||||||
|
"qnc-server/pkg/lzkit/crypto"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type QueryGenerateShareLinkLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewQueryGenerateShareLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryGenerateShareLinkLogic {
|
||||||
|
return &QueryGenerateShareLinkLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *QueryGenerateShareLinkLogic) QueryGenerateShareLink(req *types.QueryGenerateShareLinkReq) (resp *types.QueryGenerateShareLinkResp, err error) {
|
||||||
|
userId, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 获取用户ID失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查参数
|
||||||
|
if (req.OrderId == nil || *req.OrderId == 0) && (req.OrderNo == nil || *req.OrderNo == "") {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("订单ID和订单号不能同时为空"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
var order *model.Order
|
||||||
|
// 优先使用OrderId查询
|
||||||
|
if req.OrderId != nil && *req.OrderId != 0 {
|
||||||
|
order, err = l.svcCtx.OrderModel.FindOne(l.ctx, *req.OrderId)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, model.ErrNotFound) {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("订单不存在"), "")
|
||||||
|
}
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 获取订单失败: %v", err)
|
||||||
|
}
|
||||||
|
} else if req.OrderNo != nil && *req.OrderNo != "" {
|
||||||
|
// 使用OrderNo查询
|
||||||
|
order, err = l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, *req.OrderNo)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, model.ErrNotFound) {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("订单不存在"), "")
|
||||||
|
}
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 获取订单失败: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("订单ID和订单号不能同时为空"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if order.Status != model.OrderStatusPaid {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 订单未支付")
|
||||||
|
}
|
||||||
|
|
||||||
|
query, err := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, order.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 获取查询失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.QueryState != model.QueryStateSuccess {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 查询未成功")
|
||||||
|
}
|
||||||
|
user, err := l.svcCtx.UserModel.FindOne(l.ctx, userId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 获取用户失败: %v", err)
|
||||||
|
}
|
||||||
|
if user.Inside != 1 {
|
||||||
|
if order.UserId != userId {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 无权操作此订单")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expireAt := time.Now().Add(time.Duration(l.svcCtx.Config.Query.ShareLinkExpire) * time.Second)
|
||||||
|
payload := types.QueryShareLinkPayload{
|
||||||
|
OrderId: order.Id, // 使用查询到的订单ID
|
||||||
|
ExpireAt: expireAt.Unix(),
|
||||||
|
}
|
||||||
|
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||||
|
key, err := hex.DecodeString(secretKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 解密失败: %v", err)
|
||||||
|
}
|
||||||
|
payloadBytes, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 序列化失败: %v", err)
|
||||||
|
}
|
||||||
|
encryptedPayload, err := crypto.AesEncryptURL(payloadBytes, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成分享链接, 加密失败: %v", err)
|
||||||
|
}
|
||||||
|
return &types.QueryGenerateShareLinkResp{
|
||||||
|
ShareLink: encryptedPayload,
|
||||||
|
}, nil
|
||||||
|
}
|
164
app/user/cmd/api/internal/logic/query/querysharedetaillogic.go
Normal file
164
app/user/cmd/api/internal/logic/query/querysharedetaillogic.go
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"qnc-server/app/user/cmd/api/internal/svc"
|
||||||
|
"qnc-server/app/user/cmd/api/internal/types"
|
||||||
|
"qnc-server/app/user/model"
|
||||||
|
"qnc-server/common/xerr"
|
||||||
|
"qnc-server/pkg/lzkit/crypto"
|
||||||
|
|
||||||
|
"github.com/bytedance/sonic"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type QueryShareDetailLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewQueryShareDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryShareDetailLogic {
|
||||||
|
return &QueryShareDetailLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *QueryShareDetailLogic) QueryShareDetail(req *types.QueryShareDetailReq) (resp *types.QueryShareDetailResp, err error) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
decryptedID, decryptErr := crypto.AesDecryptURL(req.Id, key)
|
||||||
|
if decryptErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 解密数据失败: %v", decryptErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload types.QueryShareLinkPayload
|
||||||
|
err = sonic.Unmarshal(decryptedID, &payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 解密数据失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查分享链接是否过期
|
||||||
|
now := time.Now().Unix()
|
||||||
|
if now > payload.ExpireAt {
|
||||||
|
return &types.QueryShareDetailResp{
|
||||||
|
Status: "expired",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取订单信息
|
||||||
|
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, payload.OrderId)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, model.ErrNotFound) {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.LOGIC_QUERY_NOT_FOUND), "报告查询, 订单不存在: %v", err)
|
||||||
|
}
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查订单状态
|
||||||
|
if order.Status != "paid" {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrMsg("订单未支付,无法查看报告"), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取报告信息
|
||||||
|
queryModel, err := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, order.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")
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
updateFeatureAndProductFeatureErr := l.UpdateFeatureAndProductFeature(queryModel.ProductId, &query.QueryData)
|
||||||
|
if updateFeatureAndProductFeatureErr != nil {
|
||||||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结果处理失败: %v", updateFeatureAndProductFeatureErr)
|
||||||
|
}
|
||||||
|
// 复制报告数据
|
||||||
|
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.QueryShareDetailResp{
|
||||||
|
Status: "success",
|
||||||
|
Query: query,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *QueryShareDetailLogic) UpdateFeatureAndProductFeature(productID int64, target *[]types.QueryItem) error {
|
||||||
|
// 遍历 target 数组,使用倒序遍历,以便删除元素时不影响索引
|
||||||
|
for i := len(*target) - 1; i >= 0; i-- {
|
||||||
|
queryItem := &(*target)[i]
|
||||||
|
|
||||||
|
// 确保 Data 为 map 类型
|
||||||
|
data, ok := queryItem.Data.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("queryItem.Data 必须是 map[string]interface{} 类型")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 Data 中获取 apiID
|
||||||
|
apiID, ok := data["apiID"].(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("queryItem.Data 中的 apiID 必须是字符串类型")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 Feature
|
||||||
|
feature, err := l.svcCtx.FeatureModel.FindOneByApiId(l.ctx, apiID)
|
||||||
|
if err != nil {
|
||||||
|
// 如果 Feature 查不到,也要删除当前 QueryItem
|
||||||
|
*target = append((*target)[:i], (*target)[i+1:]...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 ProductFeatureModel
|
||||||
|
builder := l.svcCtx.ProductFeatureModel.SelectBuilder().Where("product_id = ?", productID)
|
||||||
|
productFeatures, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, builder, "")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("查询 ProductFeatureModel 错误: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历 productFeatures,找到与 feature.ID 关联且 enable == 1 的项
|
||||||
|
var featureData map[string]interface{}
|
||||||
|
// foundFeature := false
|
||||||
|
sort := 0
|
||||||
|
for _, pf := range productFeatures {
|
||||||
|
if pf.FeatureId == feature.Id { // 确保和 Feature 关联
|
||||||
|
sort = int(pf.Sort)
|
||||||
|
break // 找到第一个符合条件的就退出循环
|
||||||
|
}
|
||||||
|
}
|
||||||
|
featureData = map[string]interface{}{
|
||||||
|
"featureName": feature.Name,
|
||||||
|
"sort": sort,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 queryItem 的 Feature 字段(不是数组)
|
||||||
|
queryItem.Feature = featureData
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
6
app/user/cmd/api/internal/types/encrypPayload.go
Normal file
6
app/user/cmd/api/internal/types/encrypPayload.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type QueryShareLinkPayload struct {
|
||||||
|
OrderId int64 `json:"order_id"`
|
||||||
|
ExpireAt int64 `json:"expire_at"`
|
||||||
|
}
|
@ -424,6 +424,15 @@ type QueryExampleResp struct {
|
|||||||
Query
|
Query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryGenerateShareLinkReq struct {
|
||||||
|
OrderId *int64 `json:"order_id,optional"`
|
||||||
|
OrderNo *string `json:"order_no,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueryGenerateShareLinkResp struct {
|
||||||
|
ShareLink string `json:"share_link"`
|
||||||
|
}
|
||||||
|
|
||||||
type QueryItem struct {
|
type QueryItem struct {
|
||||||
Feature interface{} `json:"feature"`
|
Feature interface{} `json:"feature"`
|
||||||
Data interface{} `json:"data"` // 这里可以是 map 或 具体的 struct
|
Data interface{} `json:"data"` // 这里可以是 map 或 具体的 struct
|
||||||
@ -492,6 +501,15 @@ type QueryServiceResp struct {
|
|||||||
RefreshAfter int64 `json:"refreshAfter"`
|
RefreshAfter int64 `json:"refreshAfter"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryShareDetailReq struct {
|
||||||
|
Id string `path:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueryShareDetailResp struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Query
|
||||||
|
}
|
||||||
|
|
||||||
type QuerySingleTestReq struct {
|
type QuerySingleTestReq struct {
|
||||||
Params map[string]interface{} `json:"params"`
|
Params map[string]interface{} `json:"params"`
|
||||||
Api string `json:"api"`
|
Api string `json:"api"`
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
func TestGenerateAndParseJwtToken(t *testing.T) {
|
func TestGenerateAndParseJwtToken(t *testing.T) {
|
||||||
// 测试参数
|
// 测试参数
|
||||||
userId := int64(2012)
|
userId := int64(2043)
|
||||||
secret := "WUvoIwL-FK0qnlxhvxR9tV6SjfOpeJMpKmY2QvT99lA"
|
secret := "WUvoIwL-FK0qnlxhvxR9tV6SjfOpeJMpKmY2QvT99lA"
|
||||||
expireTime := int64(2592000) // 1小时过期
|
expireTime := int64(2592000) // 1小时过期
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user