新增代理实名认证和授权

This commit is contained in:
liangzai
2025-05-24 14:26:20 +08:00
parent 16e57387db
commit 2d3ca4c18e
54 changed files with 4069 additions and 435 deletions

View File

@@ -65,6 +65,9 @@ service main {
// 下级贡献详情
@handler GetAgentSubordinateContributionDetail
get /subordinate/contribution/detail (GetAgentSubordinateContributionDetailReq) returns (GetAgentSubordinateContributionDetailResp)
@handler AgentRealName
post /real_name (AgentRealNameReq) returns (AgentRealNameResp)
}
type (
@@ -75,8 +78,8 @@ type (
level string `json:"level"`
region string `json:"region"`
mobile string `json:"mobile"`
wechatID string `json:"wechat_id"`
expiryTime string `json:"expiry_time"`
isRealName bool `json:"is_real_name"`
}
// 查询代理申请状态响应
AgentAuditStatusResp {
@@ -150,6 +153,15 @@ type (
DescendantWithdrawCount int64 `json:"descendant_withdraw_count"` // 下级提现次数
DescendantWithdrawAmount float64 `json:"descendant_withdraw_amount"` // 下级提现总额
}
AgentRealNameReq {
Name string `json:"name"`
IDCard string `json:"id_card"`
Mobile string `json:"mobile"`
Code string `json:"code"`
}
AgentRealNameResp {
Status string `json:"status"`
}
)
@server (
@@ -331,7 +343,6 @@ type (
AgentApplyReq {
Region string `json:"region"`
Mobile string `json:"mobile"`
WechatID string `json:"wechat_id"`
Code string `json:"code"`
Ancestor string `json:"ancestor,optional"`
}

View File

@@ -42,6 +42,9 @@ service main {
@handler PaymentCheck
post /pay/check (PaymentCheckReq) returns (PaymentCheckResp)
@handler QueryPaymentCheck
post /pay/query_check (QueryPaymentCheckReq) returns (QueryPaymentCheckResp)
}
type (
@@ -62,6 +65,16 @@ type (
Type string `json:"type"`
Status string `json:"status"`
}
QueryPaymentCheckReq {
OrderNo string `json:"order_no" validate:"required"`
}
QueryPaymentCheckResp {
OrderStatus string `json:"order_status"`
AuthorizationStatus string `json:"authorization_status"`
Name string `json:"name"`
IdCard string `json:"id_card"`
ProductName string `json:"product_name"`
}
)
type (

View File

@@ -20,6 +20,9 @@ type Query {
CreateTime string `json:"create_time"` // 创建时间
UpdateTime string `json:"update_time"` // 更新时间
QueryState string `json:"query_state"` // 查询状态
IsPaid bool `json:"is_paid"` // 是否支付
IsQueryCompleted bool `json:"is_query_completed"` // 查询是否完成
IsAuthCompleted bool `json:"is_auth_completed"` // 授权是否完成
}
@@ -107,6 +110,10 @@ service main {
@doc "更新查询数据"
@handler updateQueryData
post /query/update_data (UpdateQueryDataReq) returns (UpdateQueryDataResp)
@doc "确认查询状态"
@handler confirmQueryState
post /query/confirm_state (ConfirmQueryStateReq) returns (ConfirmQueryStateResp)
}
// 获取查询临时订单
@@ -218,3 +225,14 @@ type QuerySingleTestResp {
Api string `json:"api"`
}
// 新增接口的请求、响应类型定义
type (
ConfirmQueryStateReq {
OrderID int64 `json:"order_id" validate:"required"`
}
ConfirmQueryStateResp {
OrderState string `json:"order_state"` // 查询状态,例如"pending"、"success"、"failed"等
QueryState string `json:"query_state"`
}
)

View File

@@ -146,22 +146,63 @@ type (
//============================> auth v1 <============================
@server (
prefix: api/v1
prefix: api/v1/auth
group: auth
)
service main {
@doc "get mobile verify code"
@handler sendSms
post /auth/sendSms (sendSmsReq)
post /sendSms (sendSmsReq)
@doc "发起人脸认证"
@handler initFaceVerify
post /face/init (InitFaceVerifyReq) returns (InitFaceVerifyResp)
@doc "查询人脸认证结果"
@handler getFaceVerifyResult
post /face/result (GetFaceVerifyResultReq) returns (GetFaceVerifyResultResp)
@doc "第三方拒绝授权"
@handler rejectAuthorization
post /rejectAuthorization (RejectAuthorizationReq) returns (RejectAuthorizationResp)
}
type (
sendSmsReq {
Mobile string `json:"mobile" validate:"required,mobile"`
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply bindMobile"`
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply bindMobile realName"`
}
// 发起人脸认证请求
InitFaceVerifyReq {
MetaInfo string `json:"meta_info" validate:"required"` // H5端获取的MetaInfoJSON格式
OrderNo string `json:"order_no" validate:"required"` // 订单号
AuthType int64 `json:"auth_type" validate:"required"` // 认证类型
}
// 发起人脸认证响应
InitFaceVerifyResp {
CertifyId string `json:"certify_id"` // 认证ID
CertifyUrl string `json:"certify_url"` // 跳转认证页面URL
}
// 查询人脸认证结果请求
GetFaceVerifyResultReq {
CertifyId string `json:"certify_id" validate:"required"` // 认证ID
}
// 查询人脸认证结果响应
GetFaceVerifyResultResp {
Passed bool `json:"passed"` // 是否通过
OrderID int64 `json:"order_id"`
AuthType int64 `json:"auth_type"`
}
RejectAuthorizationReq {
OrderNo string `json:"order_no" validate:"required"` // 订单号
}
RejectAuthorizationResp {
}
)
//============================> notification v1 <============================
@server (
prefix: api/v1

View File

@@ -37,7 +37,7 @@ Alipay:
AlipayRootCertPath: "etc/merchant/alipayRootCert.crt"
IsProduction: true
NotifyUrl: "https://6m4685017o.goho.co/api/v1/pay/alipay/callback"
ReturnURL: "http://192.168.10.13:5679/payment/result"
ReturnURL: "http://192.168.10.16:5679/authorization"
Wxpay:
AppID: "wx442ee1ac1ee75917"
@@ -64,3 +64,9 @@ SystemConfig:
WechatH5:
AppID: "wx442ee1ac1ee75917"
AppSecret: "c80474909db42f63913b7a307b3bee17"
CloudAuth:
AccessKeyId: "LTAI5tSWnaq1kvUawsV4ayL8"
AccessKeySecret: "fSGdUzm4TGtkus9rUVzipSOhEtimG5"
Endpoint: "cloudauth.aliyuncs.com"
SceneId: 1000013341
ReturnUrl: "https://www.quannengcha.com/authorization/result"

View File

@@ -65,3 +65,9 @@ SystemConfig:
WechatH5:
AppID: "wx442ee1ac1ee75917"
AppSecret: "c80474909db42f63913b7a307b3bee17"
CloudAuth:
AccessKeyId: "LTAI5tSWnaq1kvUawsV4ayL8"
AccessKeySecret: "fSGdUzm4TGtkus9rUVzipSOhEtimG5"
Endpoint: "cloudauth.aliyuncs.com"
SceneId: 1000013341
ReturnUrl: "https://www.quannengcha.com/authorization/face/result"

View File

@@ -20,6 +20,7 @@ type Config struct {
YushanConfig YushanConfig
SystemConfig SystemConfig
WechatH5 WechatH5Config
CloudAuth CloudAuthConfig
}
// JwtAuth 用于 JWT 鉴权配置
@@ -92,3 +93,10 @@ type WechatH5Config struct {
AppID string
AppSecret string
}
type CloudAuthConfig struct {
AccessKeyId string
AccessKeySecret string
Endpoint string
SceneId int64
ReturnUrl string
}

View File

@@ -0,0 +1,29 @@
package agent
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"qnc-server/app/user/cmd/api/internal/logic/agent"
"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 AgentRealNameHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.AgentRealNameReq
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 := agent.NewAgentRealNameLogic(r.Context(), svcCtx)
resp, err := l.AgentRealName(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@@ -0,0 +1,29 @@
package auth
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"qnc-server/app/user/cmd/api/internal/logic/auth"
"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 GetFaceVerifyResultHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetFaceVerifyResultReq
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 := auth.NewGetFaceVerifyResultLogic(r.Context(), svcCtx)
resp, err := l.GetFaceVerifyResult(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@@ -0,0 +1,29 @@
package auth
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"qnc-server/app/user/cmd/api/internal/logic/auth"
"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 InitFaceVerifyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.InitFaceVerifyReq
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 := auth.NewInitFaceVerifyLogic(r.Context(), svcCtx)
resp, err := l.InitFaceVerify(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@@ -0,0 +1,29 @@
package auth
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"qnc-server/app/user/cmd/api/internal/logic/auth"
"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 RejectAuthorizationHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.RejectAuthorizationReq
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 := auth.NewRejectAuthorizationLogic(r.Context(), svcCtx)
resp, err := l.RejectAuthorization(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@@ -0,0 +1,29 @@
package pay
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"qnc-server/app/user/cmd/api/internal/logic/pay"
"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 QueryPaymentCheckHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.QueryPaymentCheckReq
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 := pay.NewQueryPaymentCheckLogic(r.Context(), svcCtx)
resp, err := l.QueryPaymentCheck(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@@ -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 ConfirmQueryStateHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ConfirmQueryStateReq
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.NewConfirmQueryStateLogic(r.Context(), svcCtx)
resp, err := l.ConfirmQueryState(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@@ -40,6 +40,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/product_config",
Handler: agent.GetAgentProductConfigHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/real_name",
Handler: agent.AgentRealNameHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/subordinate/contribution/detail",
@@ -144,14 +149,32 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
// 发起人脸认证
Method: http.MethodPost,
Path: "/face/init",
Handler: auth.InitFaceVerifyHandler(serverCtx),
},
{
// 查询人脸认证结果
Method: http.MethodPost,
Path: "/face/result",
Handler: auth.GetFaceVerifyResultHandler(serverCtx),
},
{
// 第三方拒绝授权
Method: http.MethodPost,
Path: "/rejectAuthorization",
Handler: auth.RejectAuthorizationHandler(serverCtx),
},
{
// get mobile verify code
Method: http.MethodPost,
Path: "/auth/sendSms",
Path: "/sendSms",
Handler: auth.SendSmsHandler(serverCtx),
},
},
rest.WithPrefix("/api/v1"),
rest.WithPrefix("/api/v1/auth"),
)
server.AddRoutes(
@@ -206,6 +229,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/pay/payment",
Handler: pay.PaymentHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/pay/query_check",
Handler: pay.QueryPaymentCheckHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
@@ -275,6 +303,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
// 确认查询状态
Method: http.MethodPost,
Path: "/query/confirm_state",
Handler: query.ConfirmQueryStateHandler(serverCtx),
},
{
// 查询列表
Method: http.MethodGet,

View File

@@ -0,0 +1,99 @@
package agent
import (
"context"
"database/sql"
"fmt"
"time"
"qnc-server/app/user/cmd/api/internal/service"
"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"
"github.com/zeromicro/go-zero/core/stores/redis"
)
type AgentRealNameLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAgentRealNameLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AgentRealNameLogic {
return &AgentRealNameLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AgentRealNameLogic) AgentRealName(req *types.AgentRealNameReq) (resp *types.AgentRealNameResp, err error) {
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败, %v", err)
}
secretKey := l.svcCtx.Config.Encrypt.SecretKey
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理实名, 加密手机号失败: %v", err)
}
// 检查手机号是否在一分钟内已发送过验证码
redisKey := fmt.Sprintf("%s:%s", "realName", encryptedMobile)
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "代理实名, 验证码过期: %s", encryptedMobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理实名, 读取验证码redis缓存失败, mobile: %s, err: %+v", encryptedMobile, err)
}
if cacheCode != req.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "代理实名, 验证码不正确: %s", encryptedMobile)
}
agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理信息失败, %v", err)
}
agentRealName, err := l.svcCtx.AgentRealNameModel.FindOneByAgentId(l.ctx, agent.Id)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理实名信息失败, %v", err)
}
if agentRealName != nil && agentRealName.Status == model.AgentRealNameStatusApproved {
return nil, errors.Wrapf(xerr.NewErrMsg("代理实名信息已审核通过"), "代理实名信息已审核通过")
}
// 三要素验证
threeVerification := service.ThreeFactorVerificationRequest{
Name: req.Name,
IDCard: req.IDCard,
Mobile: req.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)
}
agentRealName = &model.AgentRealName{
AgentId: agent.Id,
Status: model.AgentRealNameStatusApproved,
Name: req.Name,
IdCard: req.IDCard,
ApproveTime: sql.NullTime{Time: time.Now(), Valid: true},
}
_, err = l.svcCtx.AgentRealNameModel.Insert(l.ctx, nil, agentRealName)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "添加代理实名信息失败, %v", err)
}
return &types.AgentRealNameResp{
Status: agentRealName.Status,
}, nil
}

View File

@@ -60,11 +60,22 @@ func (l *AgentWithdrawalLogic) AgentWithdrawal(req *types.WithdrawalReq) (*types
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败: %v", err)
}
// 查询代理信息
agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败: %v", err)
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询代理信息失败: %v", err)
}
agentRealName, err := l.svcCtx.AgentRealNameModel.FindOneByAgentId(l.ctx, agentModel.Id)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return errors.Wrapf(xerr.NewErrMsg("您未进行实名认证, 无法提现"), "您未进行实名认证")
}
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询代理实名信息失败: %v", err)
}
if agentRealName.Status != model.AgentRealNameStatusApproved {
return errors.Wrapf(xerr.NewErrMsg("您的实名认证未通过, 无法提现"), "您的实名认证未通过")
}
if agentRealName.Name != req.PayeeName {
return errors.Wrapf(xerr.NewErrMsg("您的实名认证信息不匹配, 无法提现"), "您的实名认证信息不匹配")
}
// 查询钱包

View File

@@ -8,7 +8,6 @@ import (
jwtx "qnc-server/common/jwt"
"qnc-server/common/xerr"
"qnc-server/pkg/lzkit/crypto"
"qnc-server/pkg/lzkit/lzUtils"
"time"
"github.com/pkg/errors"
@@ -108,7 +107,6 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type
agentAudit.UserId = user.Id
agentAudit.Mobile = encryptedMobile
agentAudit.Region = req.Region
agentAudit.WechatId = lzUtils.StringToNullString(req.WechatID)
agentAudit.Status = 1
_, insetAgentAuditErr := l.svcCtx.AgentAuditModel.Insert(transCtx, session, &agentAudit)
if insetAgentAuditErr != nil {
@@ -131,7 +129,6 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type
agentModel.Mobile = agentAudit.Mobile
agentModel.Region = agentAudit.Region
agentModel.UserId = agentAudit.UserId
agentModel.WechatId = lzUtils.StringToNullString(req.WechatID)
agentModelInsert, insertAgentModelErr := l.svcCtx.AgentModel.Insert(transCtx, session, &agentModel)
if insertAgentModelErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 新增代理失败: %+v", insertAgentModelErr)

View File

@@ -6,12 +6,12 @@ import (
"qnc-server/common/ctxdata"
"qnc-server/common/xerr"
"qnc-server/pkg/lzkit/crypto"
"qnc-server/pkg/lzkit/lzUtils"
"github.com/pkg/errors"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/app/user/model"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -64,6 +64,16 @@ func (l *GetAgentInfoLogic) GetAgentInfo() (resp *types.AgentInfoResp, err error
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理信息, 解密手机号失败: %v", err)
}
IsRealName := false
agentRealName, err := l.svcCtx.AgentRealNameModel.FindOneByAgentId(l.ctx, agent.Id)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理实名信息失败, %v", err)
}
if agentRealName != nil {
IsRealName = true
}
return &types.AgentInfoResp{
AgentID: agent.Id,
Level: agent.LevelName,
@@ -72,6 +82,6 @@ func (l *GetAgentInfoLogic) GetAgentInfo() (resp *types.AgentInfoResp, err error
Region: agent.Region,
Mobile: agent.Mobile,
ExpiryTime: agent.MembershipExpiryTime.Time.Format("2006-01-02 15:04:05"),
WechatID: lzUtils.NullStringToString(agent.WechatId),
IsRealName: IsRealName,
}, nil
}

View File

@@ -0,0 +1,122 @@
package auth
import (
"context"
"fmt"
"qnc-server/common/xerr"
"github.com/bytedance/sonic"
"github.com/pkg/errors"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/app/user/model"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type GetFaceVerifyResultLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetFaceVerifyResultLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFaceVerifyResultLogic {
return &GetFaceVerifyResultLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetFaceVerifyResultLogic) GetFaceVerifyResult(req *types.GetFaceVerifyResultReq) (resp *types.GetFaceVerifyResultResp, err error) {
// 1. 查询认证明细
face, err := l.svcCtx.AuthorizationFaceModel.FindOneByCertifyId(l.ctx, req.CertifyId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询认证明细失败: %v", err)
}
if face == nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询认证明细为空")
}
// 2. 查询主授权(如后续需要可用)
auth, err := l.svcCtx.AuthorizationModel.FindOne(l.ctx, face.AuthorizationId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询授权主表失败: %v", err)
}
// 3. 判断人脸认证明细和主授权状态,若均已是"success",则直接返回通过
if (face.Status == model.AuthorizationFaceStatusSuccess) && (auth.Status == model.AuthorizationStatusSuccess) {
return &types.GetFaceVerifyResultResp{
OrderID: auth.OrderId,
Passed: true,
}, nil
}
// 4. 调用阿里云接口查询认证结果
describeResp, err := l.svcCtx.CloudAuthService.DescribeFaceVerify(req.CertifyId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "校验人脸识别结果失败: %v", err)
}
// 5. 判断认证状态并更新(使用事务)
if describeResp.Passed {
// 使用事务更新状态
err = l.svcCtx.AuthorizationModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
order, err := l.svcCtx.OrderModel.FindOne(ctx, auth.OrderId)
if err != nil {
return errors.Wrapf(err, "查询订单失败")
}
redisKey := fmt.Sprintf(types.QueryCacheKey, order.UserId, order.OrderNo)
cache, cacheErr := l.svcCtx.Redis.GetCtx(ctx, redisKey)
if cacheErr != nil {
return fmt.Errorf("获取缓存内容失败: %+v", cacheErr)
}
var data types.QueryCacheLoad
err = sonic.Unmarshal([]byte(cache), &data)
if err != nil {
return fmt.Errorf("解析缓存内容失败: %+v", err)
}
// 插入新queryModel
query := &model.Query{
OrderId: auth.OrderId,
UserId: auth.UserId,
ProductId: order.ProductId,
QueryParams: data.Params,
QueryState: "pending",
}
_, insertQueryErr := l.svcCtx.QueryModel.Insert(ctx, session, query)
if insertQueryErr != nil {
return errors.Wrapf(insertQueryErr, "保存查询失败")
}
// 更新主授权状态
auth.Status = model.AuthorizationStatusSuccess
_, err = l.svcCtx.AuthorizationModel.Update(ctx, session, auth)
if err != nil {
return errors.Wrapf(err, "更新授权状态失败")
}
// 更新人脸认证明细状态
face.Status = model.AuthorizationFaceStatusSuccess
_, err = l.svcCtx.AuthorizationFaceModel.Update(ctx, session, face)
if err != nil {
return errors.Wrapf(err, "更新人脸认证状态失败")
}
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(auth.OrderId); asyncErr != nil {
logx.Errorf("异步任务调度失败: %v", asyncErr)
return asyncErr
}
return nil
})
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新认证状态失败: %v", err)
}
}
// 6. 返回respresp.Passed := describeResp.Passed和err如有
resp = &types.GetFaceVerifyResultResp{
OrderID: auth.OrderId,
Passed: describeResp.Passed,
AuthType: auth.AuthType.Int64,
}
return resp, nil
}

View File

@@ -0,0 +1,134 @@
package auth
import (
"context"
"database/sql"
"encoding/hex"
"math/rand"
"strconv"
"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/core/aliyun/cloudauth"
"qnc-server/pkg/lzkit/crypto"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type InitFaceVerifyLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewInitFaceVerifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InitFaceVerifyLogic {
return &InitFaceVerifyLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 生成带前缀的随机OuterOrderNo阿里云人脸验证单号
func genOuterOrderNo() string {
prefix := "FACE_"
timestamp := time.Now().UnixNano()
randNum := rand.Intn(1000000)
return prefix + strconv.FormatInt(timestamp, 10) + strconv.Itoa(randNum)
}
func (l *InitFaceVerifyLogic) InitFaceVerify(req *types.InitFaceVerifyReq) (resp *types.InitFaceVerifyResp, 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)
}
if order.Status != "paid" {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "订单未支付")
}
authorization, err := l.svcCtx.AuthorizationModel.FindOneByOrderId(l.ctx, order.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询授权信息失败: %v", err)
}
if authorization.Status != "pending" {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "授权信息状态不正确")
}
key, decodeErr := hex.DecodeString(l.svcCtx.Config.Encrypt.SecretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询授权信息失败: %v", decodeErr)
}
if authorization.GrantType == "face" {
authorizationFaceBuilder := l.svcCtx.AuthorizationFaceModel.SelectBuilder().
Where("authorization_id = ? AND status = ? AND certify_id != '' AND certify_url != ''",
authorization.Id, model.AuthorizationStatusPending).
OrderBy("create_time DESC").
Limit(1)
existingFaces, err := l.svcCtx.AuthorizationFaceModel.FindAll(l.ctx, authorizationFaceBuilder, "")
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询人脸认证记录失败: %v", err)
}
if len(existingFaces) > 0 {
// 如果存在记录,直接返回最新的认证信息
return &types.InitFaceVerifyResp{
CertifyId: existingFaces[0].CertifyId,
CertifyUrl: existingFaces[0].CertifyUrl,
}, nil
}
}
outerOrderNo := genOuterOrderNo()
name, err := crypto.AesDecrypt(authorization.TargetName, key)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解密姓名失败: %v", err)
}
idCard, err := crypto.AesDecrypt(authorization.TargetIdcard, key)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解密身份证号失败: %v", err)
}
initFaceVerifyResp, err := l.svcCtx.CloudAuthService.InitFaceVerify(cloudauth.InitFaceVerifyParam{
OuterOrderNo: outerOrderNo,
CertName: string(name),
CertNo: string(idCard),
MetaInfo: req.MetaInfo,
})
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "初始化人脸认证失败: %v", err)
}
err = l.svcCtx.AuthorizationModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
authorization.AuthType = sql.NullInt64{
Int64: req.AuthType,
Valid: true,
}
_, err = l.svcCtx.AuthorizationModel.Update(l.ctx, session, authorization)
if err != nil {
return err
}
authorizationFace := &model.AuthorizationFace{
AuthorizationId: authorization.Id,
CertifyId: initFaceVerifyResp.CertifyId,
CertifyUrl: initFaceVerifyResp.CertifyUrl,
Status: model.AuthorizationStatusPending,
CertifyUrlExpireAt: time.Now().Add(time.Minute * 30),
OuterOrderNo: outerOrderNo,
}
_, err = l.svcCtx.AuthorizationFaceModel.Insert(l.ctx, session, authorizationFace)
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新授权信息失败: %v", err)
}
return &types.InitFaceVerifyResp{
CertifyId: initFaceVerifyResp.CertifyId,
CertifyUrl: initFaceVerifyResp.CertifyUrl,
}, nil
}

View File

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

View File

@@ -2,8 +2,11 @@ package pay
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"qnc-server/pkg/lzkit/crypto"
"qnc-server/pkg/lzkit/lzUtils"
"strings"
"time"
@@ -11,6 +14,7 @@ import (
"github.com/smartwalle/alipay/v3"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/app/user/model"
"github.com/zeromicro/go-zero/core/logx"
@@ -95,9 +99,48 @@ func (l *AlipayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter, not
}
if order.Status == "paid" {
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
logx.Errorf("异步任务调度失败: %v", asyncErr)
return asyncErr
redisKey := fmt.Sprintf(types.QueryCacheKey, order.UserId, order.OrderNo)
cache, cacheErr := l.svcCtx.Redis.Get(redisKey)
if cacheErr != nil {
return fmt.Errorf("获取缓存内容失败: %+v", cacheErr)
}
var data types.QueryCacheLoad
err = json.Unmarshal([]byte(cache), &data)
if err != nil {
return fmt.Errorf("解析缓存内容失败: %+v", err)
}
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return fmt.Errorf("获取AES密钥失败: %+v", decodeErr)
}
decryptData, aesdecryptErr := crypto.AesDecrypt(data.Params, key)
if aesdecryptErr != nil {
return fmt.Errorf("解密参数失败: %+v", aesdecryptErr)
}
var paramsMap map[string]string
if err := json.Unmarshal([]byte(decryptData), &paramsMap); err != nil {
return fmt.Errorf("解析参数失败: %+v", err)
}
encryptName, err := crypto.AesEncrypt([]byte(paramsMap["name"]), key)
if err != nil {
return fmt.Errorf("生成订单, 加密姓名失败: %+v", err)
}
encryptIdcard, err := crypto.AesEncrypt([]byte(paramsMap["id_card"]), key)
if err != nil {
return fmt.Errorf("生成订单, 加密身份证号失败: %+v", err)
}
_, err = l.svcCtx.AuthorizationModel.Insert(l.ctx, nil, &model.Authorization{
OrderId: order.Id,
UserId: order.UserId,
TargetName: encryptName,
TargetIdcard: encryptIdcard,
GrantType: model.GrantTypeFace,
Status: model.AuthorizationStatusPending,
})
if err != nil {
logx.Errorf("支付宝支付回调,插入授权信息失败: %+v", err)
return fmt.Errorf("插入授权信息失败: %+v", err)
}
}
@@ -183,6 +226,7 @@ func (l *AlipayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWriter,
return nil
}
// 退款
func (l *AlipayCallbackLogic) handleRefund(order *model.AgentMembershipRechargeOrder) error {
ctx := context.Background()
// 退款

View File

@@ -5,6 +5,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"os"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/app/user/model"
@@ -125,6 +126,14 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
amount = 0.01
}
var orderID int64
Status := "pending"
env := os.Getenv("ENV")
if env == "" {
env = "production"
}
if env == "development" {
Status = "paid"
}
order := model.Order{
OrderNo: outTradeNo,
UserId: userID,
@@ -132,7 +141,7 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
PaymentPlatform: req.PayMethod,
PaymentScene: "app",
Amount: amount,
Status: "pending",
Status: Status,
}
orderInsertResult, insertOrderErr := l.svcCtx.OrderModel.Insert(l.ctx, session, &order)
if insertOrderErr != nil {
@@ -157,6 +166,53 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert)
}
}
if env == "development" {
redisKey := fmt.Sprintf(types.QueryCacheKey, order.UserId, order.OrderNo)
cache, cacheErr := l.svcCtx.Redis.Get(redisKey)
if cacheErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取缓存内容失败: %+v", 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)
}
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)
}
decryptData, aesdecryptErr := crypto.AesDecrypt(data.Params, key)
if aesdecryptErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解密参数失败: %+v", aesdecryptErr)
}
var paramsMap map[string]string
if err := json.Unmarshal([]byte(decryptData), &paramsMap); err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 解析参数失败: %+v", err)
}
encryptName, err := crypto.AesEncrypt([]byte(paramsMap["name"]), key)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 加密姓名失败: %+v", err)
}
encryptIdcard, err := crypto.AesEncrypt([]byte(paramsMap["id_card"]), key)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 加密身份证号失败: %+v", err)
}
_, err = l.svcCtx.AuthorizationModel.Insert(l.ctx, nil, &model.Authorization{
OrderId: orderID,
UserId: order.UserId,
TargetName: encryptName,
TargetIdcard: encryptIdcard,
GrantType: model.GrantTypeFace,
Status: model.AuthorizationStatusPending,
})
if err != nil {
logx.Errorf("支付宝支付回调,插入授权信息失败: %+v", err)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 插入授权信息失败: %+v", err)
}
}
return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName}, nil
}
func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {

View File

@@ -0,0 +1,100 @@
package pay
import (
"context"
"encoding/hex"
"strings"
"qnc-server/app/user/cmd/api/internal/svc"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/common/xerr"
"qnc-server/pkg/lzkit/crypto"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
type QueryPaymentCheckLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewQueryPaymentCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryPaymentCheckLogic {
return &QueryPaymentCheckLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *QueryPaymentCheckLogic) QueryPaymentCheck(req *types.QueryPaymentCheckReq) (resp *types.QueryPaymentCheckResp, 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)
}
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, order.ProductId)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询产品失败: %v", err)
}
resp = new(types.QueryPaymentCheckResp)
resp.OrderStatus = order.Status
resp.ProductName = product.ProductName
if order.Status == "paid" {
authorization, err := l.svcCtx.AuthorizationModel.FindOneByOrderId(l.ctx, order.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询授权信息失败: %v", err)
}
resp.AuthorizationStatus = authorization.Status
key, decodeErr := hex.DecodeString(l.svcCtx.Config.Encrypt.SecretKey)
if decodeErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询授权信息失败: %v", decodeErr)
}
decryptName, err := crypto.AesDecrypt(authorization.TargetName, key)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询授权信息失败: %v", err)
}
idCard, err := crypto.AesDecrypt(authorization.TargetIdcard, key)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询授权信息失败: %v", err)
}
resp.Name = maskName(string(decryptName))
resp.IdCard = maskIDCard(string(idCard))
}
return resp, nil
}
// 姓名脱敏
func maskName(name string) string {
// 将字符串转换为rune切片以正确处理中文字符
runes := []rune(name)
length := len(runes)
if length <= 1 {
return name
}
if length == 2 {
// 两个字:保留第一个字,第二个字用*替代
return string(runes[0]) + "*"
}
// 三个字及以上:保留首尾字,中间用*替代
first := string(runes[0])
last := string(runes[length-1])
mask := strings.Repeat("*", length-2)
return first + mask + last
}
// 身份证号脱敏
func maskIDCard(idCard string) string {
length := len(idCard)
if length <= 10 {
return idCard // 如果长度太短,可能不是身份证,不处理
}
// 保留前3位和后4位
return idCard[:3] + strings.Repeat("*", length-7) + idCard[length-4:]
}

View File

@@ -2,10 +2,14 @@ package pay
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"qnc-server/app/user/cmd/api/internal/service"
"qnc-server/app/user/cmd/api/internal/types"
"qnc-server/app/user/model"
"qnc-server/pkg/lzkit/crypto"
"qnc-server/pkg/lzkit/lzUtils"
"strings"
"time"
@@ -197,15 +201,41 @@ func (l *WechatPayCallbackLogic) handleRefund(order *model.AgentMembershipRechar
return refundErr
}
if refund.IsSuccess() {
logx.Errorf("支付宝退款成功, orderID: %d", order.Id)
// 更新订单状态为退款
order.Status = "refunded"
updateOrderErr := l.svcCtx.AgentMembershipRechargeOrderModel.UpdateWithVersion(ctx, nil, order)
if updateOrderErr != nil {
logx.Errorf("更新订单状态失败订单ID: %d, 错误: %v", order.Id, updateOrderErr)
return fmt.Errorf("更新订单状态失败: %v", updateOrderErr)
redisKey := fmt.Sprintf(types.QueryCacheKey, order.UserId, order.OrderNo)
cache, cacheErr := l.svcCtx.Redis.Get(redisKey)
if cacheErr != nil {
return fmt.Errorf("获取缓存内容失败: %+v", cacheErr)
}
var data types.QueryCacheLoad
err := json.Unmarshal([]byte(cache), &data)
if err != nil {
return fmt.Errorf("解析缓存内容失败: %+v", err)
}
secretKey := l.svcCtx.Config.Encrypt.SecretKey
key, decodeErr := hex.DecodeString(secretKey)
if decodeErr != nil {
return fmt.Errorf("获取AES密钥失败: %+v", decodeErr)
}
decryptData, aesdecryptErr := crypto.AesDecrypt(data.Params, key)
if aesdecryptErr != nil {
return fmt.Errorf("解密参数失败: %+v", aesdecryptErr)
}
var paramsMap map[string]string
if err := json.Unmarshal([]byte(decryptData), &paramsMap); err != nil {
return fmt.Errorf("解析参数失败: %+v", err)
}
_, err = l.svcCtx.AuthorizationModel.Insert(l.ctx, nil, &model.Authorization{
OrderId: order.Id,
UserId: order.UserId,
TargetName: paramsMap["name"],
TargetIdcard: paramsMap["id_card"],
GrantType: model.GrantTypeFace,
Status: model.AuthorizationStatusPending,
})
if err != nil {
logx.Errorf("支付宝支付回调,插入授权信息失败: %+v", err)
return fmt.Errorf("插入授权信息失败: %+v", err)
}
return nil
} else {
logx.Errorf("支付宝退款失败:%v", refundErr)
return refundErr

View File

@@ -0,0 +1,62 @@
package query
import (
"context"
"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"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
type ConfirmQueryStateLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewConfirmQueryStateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ConfirmQueryStateLogic {
return &ConfirmQueryStateLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ConfirmQueryStateLogic) ConfirmQueryState(req *types.ConfirmQueryStateReq) (resp *types.ConfirmQueryStateResp, err error) {
// 1. 通过 order_id 查询订单,判断订单是否已支付
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 == nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "订单不存在")
}
// 若订单未支付,则直接返回 OrderState := "pending", QueryState := ""
if order.Status != model.OrderStatusPaid {
return &types.ConfirmQueryStateResp{
OrderState: order.Status,
QueryState: "",
}, nil
}
// 2. 订单已支付,查询 query 状态(假设通过 order_id 查询 query 记录,例如使用 QueryModel.FindOneByOrderId
query, err := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, req.OrderID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询 query 失败: %v", err)
}
if query == nil {
// 若 query 不存在,则返回 OrderState := "paid", QueryState := ""
return &types.ConfirmQueryStateResp{
OrderState: order.Status,
QueryState: "",
}, nil
}
// 否则,返回 OrderState := "paid", QueryState := query.QueryState
return &types.ConfirmQueryStateResp{
OrderState: query.QueryState,
QueryState: query.QueryState,
}, nil
}

View File

@@ -4,11 +4,11 @@ import (
"context"
"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"
"github.com/Masterminds/squirrel"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -30,35 +30,66 @@ func NewQueryListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryLi
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)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "订单列表查询, 获取用户信息失败, %+v", getUidErr)
}
// 直接构建查询query表的条件
build := l.svcCtx.QueryModel.SelectBuilder().Where(squirrel.Eq{
// 构建查询订单表的条件,排除未支付的订单
build := l.svcCtx.OrderModel.SelectBuilder().Where(squirrel.And{
squirrel.Eq{
"user_id": userID,
},
squirrel.NotEq{
"status": model.OrderStatusPending,
},
})
// 直接从query表分页查询
queryList, total, err := l.svcCtx.QueryModel.FindPageListByPageWithTotal(l.ctx, build, req.Page, req.PageSize, "create_time DESC")
// 从订单表分页查询
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)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "订单列表查询, 查找订单列表错误, %+v", err)
}
var list []types.Query
if len(queryList) > 0 {
for _, queryModel := range queryList {
if len(orderList) > 0 {
for _, orderModel := range orderList {
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)
query.CreateTime = orderModel.CreateTime.Format("2006-01-02 15:04:05")
query.UpdateTime = orderModel.UpdateTime.Format("2006-01-02 15:04:05")
// 设置订单ID
query.OrderId = orderModel.Id
query.UserId = orderModel.UserId
// 获取商品信息
product, findProductErr := l.svcCtx.ProductModel.FindOne(l.ctx, orderModel.ProductId)
if findProductErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 获取商品信息失败, %+v", err)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "订单列表查询, 获取商品信息失败, %+v", findProductErr)
}
query.ProductName = product.ProductName
// 设置订单支付状态
query.IsPaid = orderModel.Status == model.OrderStatusPaid
// 查询查询状态
queryInfo, findQueryErr := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, orderModel.Id)
if findQueryErr == nil {
// 查询存在
query.Id = queryInfo.Id
query.QueryState = queryInfo.QueryState
query.IsQueryCompleted = queryInfo.QueryState == model.QueryStateSuccess
} else {
query.QueryState = "未创建"
query.IsQueryCompleted = false
}
// 获取授权状态
authInfo, findAuthErr := l.svcCtx.AuthorizationModel.FindOneByOrderId(l.ctx, orderModel.Id)
if findAuthErr == nil {
// 授权存在
query.IsAuthCompleted = authInfo.Status == model.AuthorizationStatusSuccess
} else {
query.IsAuthCompleted = false
}
list = append(list, query)
}
}

View File

@@ -463,16 +463,16 @@ func (l *QueryServiceLogic) ProcessBackgroundCheckLogic(req *types.QueryServiceR
}
// 校验验证码
//verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
//if verifyCodeErr != nil {
// return nil, verifyCodeErr
//}
//
//// 校验三要素
//verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
//if verifyErr != nil {
// return nil, verifyErr
//}
verifyCodeErr := l.VerifyCode(data.Mobile, data.Code)
if verifyCodeErr != nil {
return nil, verifyCodeErr
}
// 校验三要素
verifyErr := l.Verify(data.Name, data.IDCard, data.Mobile)
if verifyErr != nil {
return nil, verifyErr
}
// 缓存
params := map[string]interface{}{

View File

@@ -12,10 +12,9 @@ import (
"qnc-server/app/user/model"
"qnc-server/pkg/lzkit/crypto"
"qnc-server/pkg/lzkit/lzUtils"
"regexp"
"strings"
"time"
"github.com/bytedance/sonic"
"github.com/hibiken/asynq"
"github.com/zeromicro/go-zero/core/logx"
)
@@ -60,7 +59,7 @@ func (l *PaySuccessNotifyUserHandler) ProcessTask(ctx context.Context, t *asynq.
return fmt.Errorf("获取缓存内容失败: %+v", cacheErr)
}
var data types.QueryCacheLoad
err = json.Unmarshal([]byte(cache), &data)
err = sonic.Unmarshal([]byte(cache), &data)
if err != nil {
return fmt.Errorf("解析缓存内容失败: %+v", err)
}
@@ -74,38 +73,8 @@ func (l *PaySuccessNotifyUserHandler) ProcessTask(ctx context.Context, t *asynq.
return fmt.Errorf("解密参数失败: %+v", aesdecryptErr)
}
// 敏感数据脱敏处理
desensitizedParams, err := l.desensitizeParams(decryptData)
if err != nil {
return fmt.Errorf("脱敏处理失败: %+v", err)
}
// 对脱敏后的数据进行AES加密
encryptedParams, encryptErr := crypto.AesEncrypt(desensitizedParams, key)
if encryptErr != nil {
return fmt.Errorf("加密脱敏数据失败: %+v", encryptErr)
}
query := &model.Query{
OrderId: order.Id,
UserId: order.UserId,
ProductId: product.Id,
QueryParams: encryptedParams,
QueryState: "pending",
}
result, insertQueryErr := l.svcCtx.QueryModel.Insert(ctx, nil, query)
if insertQueryErr != nil {
return fmt.Errorf("保存查询失败: %+v", insertQueryErr)
}
// 获取插入后的ID
queryId, err := result.LastInsertId()
if err != nil {
return fmt.Errorf("获取插入的查询ID失败: %+v", err)
}
// 从数据库中查询完整的查询记录
query, err = l.svcCtx.QueryModel.FindOne(ctx, queryId)
query, err := l.svcCtx.QueryModel.FindOneByOrderId(ctx, order.Id)
if err != nil {
return fmt.Errorf("获取插入后的查询记录失败: %+v", err)
}
@@ -204,177 +173,3 @@ func (l *PaySuccessNotifyUserHandler) handleError(ctx context.Context, err error
return asynq.SkipRetry
}
// desensitizeParams 对敏感数据进行脱敏处理
func (l *PaySuccessNotifyUserHandler) desensitizeParams(data []byte) ([]byte, error) {
// 解析JSON数据到map
var paramsMap map[string]interface{}
if err := json.Unmarshal(data, &paramsMap); err != nil {
return nil, fmt.Errorf("解析JSON数据失败: %v", err)
}
// 处理可能包含敏感信息的字段
for key, value := range paramsMap {
if strValue, ok := value.(string); ok {
// 根据字段名和内容判断并脱敏
if isNameField(key) && len(strValue) > 0 {
// 姓名脱敏
paramsMap[key] = maskName(strValue)
} else if isIDCardField(key) && len(strValue) > 10 {
// 身份证号脱敏
paramsMap[key] = maskIDCard(strValue)
} else if isPhoneField(key) && len(strValue) >= 8 {
// 手机号脱敏
paramsMap[key] = maskPhone(strValue)
} else if len(strValue) > 3 {
// 其他所有未匹配的字段都进行通用脱敏
paramsMap[key] = maskGeneral(strValue)
}
} else if mapValue, ok := value.(map[string]interface{}); ok {
// 递归处理嵌套的map
for subKey, subValue := range mapValue {
if subStrValue, ok := subValue.(string); ok {
if isNameField(subKey) && len(subStrValue) > 0 {
mapValue[subKey] = maskName(subStrValue)
} else if isIDCardField(subKey) && len(subStrValue) > 10 {
mapValue[subKey] = maskIDCard(subStrValue)
} else if isPhoneField(subKey) && len(subStrValue) >= 8 {
mapValue[subKey] = maskPhone(subStrValue)
} else if len(subStrValue) > 3 {
// 其他所有未匹配的字段都进行通用脱敏
mapValue[subKey] = maskGeneral(subStrValue)
}
}
}
}
}
// 将处理后的map重新序列化为JSON
return json.Marshal(paramsMap)
}
// 判断是否为姓名字段
func isNameField(key string) bool {
key = strings.ToLower(key)
return strings.Contains(key, "name") || strings.Contains(key, "姓名") ||
strings.Contains(key, "owner") || strings.Contains(key, "user")
}
// 判断是否为身份证字段
func isIDCardField(key string) bool {
key = strings.ToLower(key)
return strings.Contains(key, "idcard") || strings.Contains(key, "id_card") ||
strings.Contains(key, "身份证") || strings.Contains(key, "证件号")
}
// 判断是否为手机号字段
func isPhoneField(key string) bool {
key = strings.ToLower(key)
return strings.Contains(key, "phone") || strings.Contains(key, "mobile") ||
strings.Contains(key, "手机") || strings.Contains(key, "电话")
}
// 判断是否包含敏感数据模式
func containsSensitivePattern(value string) bool {
// 检查是否包含连续的数字或字母模式
numPattern := regexp.MustCompile(`\d{6,}`)
return numPattern.MatchString(value)
}
// 姓名脱敏
func maskName(name string) string {
// 将字符串转换为rune切片以正确处理中文字符
runes := []rune(name)
length := len(runes)
if length <= 1 {
return name
}
if length == 2 {
// 两个字:保留第一个字,第二个字用*替代
return string(runes[0]) + "*"
}
// 三个字及以上:保留首尾字,中间用*替代
first := string(runes[0])
last := string(runes[length-1])
mask := strings.Repeat("*", length-2)
return first + mask + last
}
// 身份证号脱敏
func maskIDCard(idCard string) string {
length := len(idCard)
if length <= 10 {
return idCard // 如果长度太短,可能不是身份证,不处理
}
// 保留前3位和后4位
return idCard[:3] + strings.Repeat("*", length-7) + idCard[length-4:]
}
// 手机号脱敏
func maskPhone(phone string) string {
length := len(phone)
if length < 8 {
return phone // 如果长度太短,可能不是手机号,不处理
}
// 保留前3位和后4位
return phone[:3] + strings.Repeat("*", length-7) + phone[length-4:]
}
// 通用敏感信息脱敏 - 根据字符串长度比例进行脱敏
func maskGeneral(value string) string {
length := len(value)
// 小于3个字符的不脱敏
if length <= 3 {
return value
}
// 根据字符串长度计算保留字符数
var prefixLen, suffixLen int
switch {
case length <= 6: // 短字符串
// 保留首尾各1个字符
prefixLen, suffixLen = 1, 1
case length <= 10: // 中等长度字符串
// 保留首部30%和尾部20%的字符
prefixLen = int(float64(length) * 0.3)
suffixLen = int(float64(length) * 0.2)
case length <= 20: // 较长字符串
// 保留首部25%和尾部15%的字符
prefixLen = int(float64(length) * 0.25)
suffixLen = int(float64(length) * 0.15)
default: // 非常长的字符串
// 保留首部20%和尾部10%的字符
prefixLen = int(float64(length) * 0.2)
suffixLen = int(float64(length) * 0.1)
}
// 确保至少有一个字符被保留
if prefixLen < 1 {
prefixLen = 1
}
if suffixLen < 1 {
suffixLen = 1
}
// 确保前缀和后缀总长不超过总长度的80%
if prefixLen+suffixLen > int(float64(length)*0.8) {
// 调整为总长度的80%
totalVisible := int(float64(length) * 0.8)
// 前缀占60%后缀占40%
prefixLen = int(float64(totalVisible) * 0.6)
suffixLen = totalVisible - prefixLen
}
// 创建脱敏后的字符串
prefix := value[:prefixLen]
suffix := value[length-suffixLen:]
masked := strings.Repeat("*", length-prefixLen-suffixLen)
return prefix + masked + suffix
}

View File

@@ -5,6 +5,7 @@ import (
"qnc-server/app/user/cmd/api/internal/middleware"
"qnc-server/app/user/cmd/api/internal/service"
"qnc-server/app/user/model"
"qnc-server/pkg/core/aliyun/cloudauth"
"github.com/hibiken/asynq"
"github.com/zeromicro/go-zero/core/logx"
@@ -41,8 +42,11 @@ type ServiceContext struct {
AgentPlatformDeductionModel model.AgentPlatformDeductionModel
AgentActiveStatModel model.AgentActiveStatModel
AgentWithdrawalModel model.AgentWithdrawalModel
AgentRealNameModel model.AgentRealNameModel
ExampleModel model.ExampleModel
GlobalNotificationsModel model.GlobalNotificationsModel
AuthorizationModel model.AuthorizationModel
AuthorizationFaceModel model.AuthorizationFaceModel
AlipayService *service.AliPayService
WechatPayService *service.WechatPayService
ApplePayService *service.ApplePayService
@@ -54,6 +58,9 @@ type ServiceContext struct {
VerificationService *service.VerificationService
AgentService *service.AgentService
UserService *service.UserService
// core service
CloudAuthService *cloudauth.CloudAuthClient
}
func NewServiceContext(c config.Config) *ServiceContext {
@@ -75,7 +82,17 @@ func NewServiceContext(c config.Config) *ServiceContext {
Concurrency: 10,
},
)
cloudAuthService, err := cloudauth.NewCloudAuthClient(cloudauth.CloudAuthConfig{
AccessKeyId: c.CloudAuth.AccessKeyId,
AccessKeySecret: c.CloudAuth.AccessKeySecret,
Endpoint: c.CloudAuth.Endpoint,
SceneId: c.CloudAuth.SceneId,
ReturnUrl: c.CloudAuth.ReturnUrl,
})
if err != nil {
logx.Errorf("初始化阿里云人脸认证服务失败: %+v", err)
panic(err)
}
westDexService := service.NewWestDexService(c)
yushanService := service.NewYushanService(c)
productFeatureModel := model.NewProductFeatureModel(db, c.CacheRedis)
@@ -104,7 +121,10 @@ func NewServiceContext(c config.Config) *ServiceContext {
agentPlatformDeductionModel := model.NewAgentPlatformDeductionModel(db, c.CacheRedis)
agentActiveStatModel := model.NewAgentActiveStatModel(db, c.CacheRedis)
agentWithdrawalModel := model.NewAgentWithdrawalModel(db, c.CacheRedis)
agentRealNameModel := model.NewAgentRealNameModel(db, c.CacheRedis)
exampleModel := model.NewExampleModel(db, c.CacheRedis)
authorizationModel := model.NewAuthorizationModel(db, c.CacheRedis)
authorizationFaceModel := model.NewAuthorizationFaceModel(db, c.CacheRedis)
alipayService := service.NewAliPayService(c)
wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypePlatformCert)
@@ -117,6 +137,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
agentMembershipConfigModel, agentMembershipRechargeOrderModel, agentMembershipUserConfigModel,
agentProductConfigModel, agentPlatformDeductionModel, agentActiveStatModel, agentWithdrawalModel)
userService := service.NewUserService(userModel, userAuthModel)
return &ServiceContext{
Config: c,
Redis: redis.MustNewRedis(redisConf),
@@ -156,8 +177,12 @@ func NewServiceContext(c config.Config) *ServiceContext {
AgentPlatformDeductionModel: agentPlatformDeductionModel,
AgentActiveStatModel: agentActiveStatModel,
AgentWithdrawalModel: agentWithdrawalModel,
AgentRealNameModel: agentRealNameModel,
ExampleModel: exampleModel,
AuthorizationModel: authorizationModel,
AuthorizationFaceModel: authorizationFaceModel,
UserService: userService,
CloudAuthService: cloudAuthService,
}
}

View File

@@ -26,7 +26,6 @@ type AgentActivateMembershipResp struct {
type AgentApplyReq struct {
Region string `json:"region"`
Mobile string `json:"mobile"`
WechatID string `json:"wechat_id"`
Code string `json:"code"`
Ancestor string `json:"ancestor,optional"`
}
@@ -58,8 +57,8 @@ type AgentInfoResp struct {
Level string `json:"level"`
Region string `json:"region"`
Mobile string `json:"mobile"`
WechatID string `json:"wechat_id"`
ExpiryTime string `json:"expiry_time"`
IsRealName bool `json:"is_real_name"`
}
type AgentMembershipProductConfigReq struct {
@@ -98,6 +97,17 @@ type AgentProductConfigResp struct {
AgentProductConfig []AgentProductConfig
}
type AgentRealNameReq struct {
Name string `json:"name"`
IDCard string `json:"id_card"`
Mobile string `json:"mobile"`
Code string `json:"code"`
}
type AgentRealNameResp struct {
Status string `json:"status"`
}
type AgentSubordinateContributionDetail struct {
ID int64 `json:"id"`
CreateTime string `json:"create_time"`
@@ -148,6 +158,15 @@ type Commission struct {
CreateTime string `json:"create_time"`
}
type ConfirmQueryStateReq struct {
OrderID int64 `json:"order_id" validate:"required"`
}
type ConfirmQueryStateResp struct {
OrderState string `json:"order_state"` // 查询状态,例如"pending"、"success"、"failed"等
QueryState string `json:"query_state"`
}
type DirectPushReport struct {
TotalCommission float64 `json:"total_commission"`
TotalReport int `json:"total_report"`
@@ -211,6 +230,16 @@ type GetCommissionResp struct {
List []Commission `json:"list"` // 查询列表
}
type GetFaceVerifyResultReq struct {
CertifyId string `json:"certify_id" validate:"required"` // 认证ID
}
type GetFaceVerifyResultResp struct {
Passed bool `json:"passed"` // 是否通过
OrderID int64 `json:"order_id"`
AuthType int64 `json:"auth_type"`
}
type GetLinkDataReq struct {
LinkIdentifier string `form:"link_identifier"`
}
@@ -262,6 +291,17 @@ type IapCallbackReq struct {
TransactionReceipt string `json:"transaction_receipt" validate:"required"`
}
type InitFaceVerifyReq struct {
MetaInfo string `json:"meta_info" validate:"required"` // H5端获取的MetaInfoJSON格式
OrderNo string `json:"order_no" validate:"required"` // 订单号
AuthType int64 `json:"auth_type" validate:"required"` // 认证类型
}
type InitFaceVerifyResp struct {
CertifyId string `json:"certify_id"` // 认证ID
CertifyUrl string `json:"certify_url"` // 跳转认证页面URL
}
type MobileCodeLoginReq struct {
Mobile string `json:"mobile"`
Code string `json:"code" validate:"required"`
@@ -345,6 +385,9 @@ type Query struct {
CreateTime string `json:"create_time"` // 创建时间
UpdateTime string `json:"update_time"` // 更新时间
QueryState string `json:"query_state"` // 查询状态
IsPaid bool `json:"is_paid"` // 是否支付
IsQueryCompleted bool `json:"is_query_completed"` // 查询是否完成
IsAuthCompleted bool `json:"is_auth_completed"` // 授权是否完成
}
type QueryDetailByOrderIdReq struct {
@@ -394,6 +437,18 @@ type QueryListResp struct {
List []Query `json:"list"` // 查询列表
}
type QueryPaymentCheckReq struct {
OrderNo string `json:"order_no" validate:"required"`
}
type QueryPaymentCheckResp struct {
OrderStatus string `json:"order_status"`
AuthorizationStatus string `json:"authorization_status"`
Name string `json:"name"`
IdCard string `json:"id_card"`
ProductName string `json:"product_name"`
}
type QueryProvisionalOrderReq struct {
Id string `path:"id"`
}
@@ -457,6 +512,13 @@ type RegisterResp struct {
RefreshAfter int64 `json:"refreshAfter"`
}
type RejectAuthorizationReq struct {
OrderNo string `json:"order_no" validate:"required"` // 订单号
}
type RejectAuthorizationResp struct {
}
type Rewards struct {
Type string `json:"type"`
Amount float64 `json:"amount"`
@@ -545,5 +607,5 @@ type GetAppVersionResp struct {
type SendSmsReq struct {
Mobile string `json:"mobile" validate:"required,mobile"`
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply bindMobile"`
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply bindMobile realName"`
}

View File

@@ -60,7 +60,6 @@ type (
UserId int64 `db:"user_id"`
Region string `db:"region"`
Mobile string `db:"mobile"`
WechatId sql.NullString `db:"wechat_id"`
Status int64 `db:"status"`
AuditReason sql.NullString `db:"audit_reason"`
CreateTime time.Time `db:"create_time"`
@@ -84,11 +83,11 @@ func (m *defaultAgentAuditModel) Insert(ctx context.Context, session sqlx.Sessio
qncAgentAuditIdKey := fmt.Sprintf("%s%v", cacheQncAgentAuditIdPrefix, data.Id)
qncAgentAuditUserIdKey := fmt.Sprintf("%s%v", cacheQncAgentAuditUserIdPrefix, data.UserId)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentAuditRowsExpectAutoSet)
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentAuditRowsExpectAutoSet)
if session != nil {
return session.ExecCtx(ctx, query, data.UserId, data.Region, data.Mobile, data.WechatId, data.Status, data.AuditReason, data.AuditTime, data.DeleteTime, data.DelState, data.Version)
return session.ExecCtx(ctx, query, data.UserId, data.Region, data.Mobile, data.Status, data.AuditReason, data.AuditTime, data.DeleteTime, data.DelState, data.Version)
}
return conn.ExecCtx(ctx, query, data.UserId, data.Region, data.Mobile, data.WechatId, data.Status, data.AuditReason, data.AuditTime, data.DeleteTime, data.DelState, data.Version)
return conn.ExecCtx(ctx, query, data.UserId, data.Region, data.Mobile, data.Status, data.AuditReason, data.AuditTime, data.DeleteTime, data.DelState, data.Version)
}, qncAgentAuditIdKey, qncAgentAuditUserIdKey)
}
@@ -139,9 +138,9 @@ func (m *defaultAgentAuditModel) Update(ctx context.Context, session sqlx.Sessio
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentAuditRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.UserId, newData.Region, newData.Mobile, newData.WechatId, newData.Status, newData.AuditReason, newData.AuditTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
return session.ExecCtx(ctx, query, newData.UserId, newData.Region, newData.Mobile, newData.Status, newData.AuditReason, newData.AuditTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}
return conn.ExecCtx(ctx, query, newData.UserId, newData.Region, newData.Mobile, newData.WechatId, newData.Status, newData.AuditReason, newData.AuditTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
return conn.ExecCtx(ctx, query, newData.UserId, newData.Region, newData.Mobile, newData.Status, newData.AuditReason, newData.AuditTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}, qncAgentAuditIdKey, qncAgentAuditUserIdKey)
}
@@ -162,9 +161,9 @@ func (m *defaultAgentAuditModel) UpdateWithVersion(ctx context.Context, session
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentAuditRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.UserId, newData.Region, newData.Mobile, newData.WechatId, newData.Status, newData.AuditReason, newData.AuditTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
return session.ExecCtx(ctx, query, newData.UserId, newData.Region, newData.Mobile, newData.Status, newData.AuditReason, newData.AuditTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}
return conn.ExecCtx(ctx, query, newData.UserId, newData.Region, newData.Mobile, newData.WechatId, newData.Status, newData.AuditReason, newData.AuditTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
return conn.ExecCtx(ctx, query, newData.UserId, newData.Region, newData.Mobile, newData.Status, newData.AuditReason, newData.AuditTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}, qncAgentAuditIdKey, qncAgentAuditUserIdKey)
if err != nil {
return err

View File

@@ -63,7 +63,6 @@ type (
LevelName string `db:"level_name"` // 代理等级
Region string `db:"region"`
Mobile string `db:"mobile"`
WechatId sql.NullString `db:"wechat_id"`
MembershipExpiryTime sql.NullTime `db:"membership_expiry_time"` // 会员过期时间
CreateTime time.Time `db:"create_time"`
UpdateTime time.Time `db:"update_time"`
@@ -86,11 +85,11 @@ func (m *defaultAgentModel) Insert(ctx context.Context, session sqlx.Session, da
qncAgentMobileKey := fmt.Sprintf("%s%v", cacheQncAgentMobilePrefix, data.Mobile)
qncAgentUserIdKey := fmt.Sprintf("%s%v", cacheQncAgentUserIdPrefix, data.UserId)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentRowsExpectAutoSet)
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentRowsExpectAutoSet)
if session != nil {
return session.ExecCtx(ctx, query, data.UserId, data.LevelName, data.Region, data.Mobile, data.WechatId, data.MembershipExpiryTime, data.DeleteTime, data.DelState, data.Version)
return session.ExecCtx(ctx, query, data.UserId, data.LevelName, data.Region, data.Mobile, data.MembershipExpiryTime, data.DeleteTime, data.DelState, data.Version)
}
return conn.ExecCtx(ctx, query, data.UserId, data.LevelName, data.Region, data.Mobile, data.WechatId, data.MembershipExpiryTime, data.DeleteTime, data.DelState, data.Version)
return conn.ExecCtx(ctx, query, data.UserId, data.LevelName, data.Region, data.Mobile, data.MembershipExpiryTime, data.DeleteTime, data.DelState, data.Version)
}, qncAgentIdKey, qncAgentMobileKey, qncAgentUserIdKey)
}
@@ -162,9 +161,9 @@ func (m *defaultAgentModel) Update(ctx context.Context, session sqlx.Session, ne
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.UserId, newData.LevelName, newData.Region, newData.Mobile, newData.WechatId, newData.MembershipExpiryTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
return session.ExecCtx(ctx, query, newData.UserId, newData.LevelName, newData.Region, newData.Mobile, newData.MembershipExpiryTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}
return conn.ExecCtx(ctx, query, newData.UserId, newData.LevelName, newData.Region, newData.Mobile, newData.WechatId, newData.MembershipExpiryTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
return conn.ExecCtx(ctx, query, newData.UserId, newData.LevelName, newData.Region, newData.Mobile, newData.MembershipExpiryTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}, qncAgentIdKey, qncAgentMobileKey, qncAgentUserIdKey)
}
@@ -186,9 +185,9 @@ func (m *defaultAgentModel) UpdateWithVersion(ctx context.Context, session sqlx.
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.UserId, newData.LevelName, newData.Region, newData.Mobile, newData.WechatId, newData.MembershipExpiryTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
return session.ExecCtx(ctx, query, newData.UserId, newData.LevelName, newData.Region, newData.Mobile, newData.MembershipExpiryTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}
return conn.ExecCtx(ctx, query, newData.UserId, newData.LevelName, newData.Region, newData.Mobile, newData.WechatId, newData.MembershipExpiryTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
return conn.ExecCtx(ctx, query, newData.UserId, newData.LevelName, newData.Region, newData.Mobile, newData.MembershipExpiryTime, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}, qncAgentIdKey, qncAgentMobileKey, qncAgentUserIdKey)
if err != nil {
return err

View File

@@ -0,0 +1,27 @@
package model
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ AgentRealNameModel = (*customAgentRealNameModel)(nil)
type (
// AgentRealNameModel is an interface to be customized, add more methods here,
// and implement the added methods in customAgentRealNameModel.
AgentRealNameModel interface {
agentRealNameModel
}
customAgentRealNameModel struct {
*defaultAgentRealNameModel
}
)
// NewAgentRealNameModel returns a model for the database table.
func NewAgentRealNameModel(conn sqlx.SqlConn, c cache.CacheConf) AgentRealNameModel {
return &customAgentRealNameModel{
defaultAgentRealNameModel: newAgentRealNameModel(conn, c),
}
}

View File

@@ -0,0 +1,411 @@
// Code generated by goctl. DO NOT EDIT!
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"github.com/Masterminds/squirrel"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
"qnc-server/common/globalkey"
)
var (
agentRealNameFieldNames = builder.RawFieldNames(&AgentRealName{})
agentRealNameRows = strings.Join(agentRealNameFieldNames, ",")
agentRealNameRowsExpectAutoSet = strings.Join(stringx.Remove(agentRealNameFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
agentRealNameRowsWithPlaceHolder = strings.Join(stringx.Remove(agentRealNameFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
cacheQncAgentRealNameIdPrefix = "cache:qnc:agentRealName:id:"
cacheQncAgentRealNameAgentIdPrefix = "cache:qnc:agentRealName:agentId:"
)
type (
agentRealNameModel interface {
Insert(ctx context.Context, session sqlx.Session, data *AgentRealName) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*AgentRealName, error)
FindOneByAgentId(ctx context.Context, agentId int64) (*AgentRealName, error)
Update(ctx context.Context, session sqlx.Session, data *AgentRealName) (sql.Result, error)
UpdateWithVersion(ctx context.Context, session sqlx.Session, data *AgentRealName) error
Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error
SelectBuilder() squirrel.SelectBuilder
DeleteSoft(ctx context.Context, session sqlx.Session, data *AgentRealName) error
FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error)
FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error)
FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*AgentRealName, error)
FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*AgentRealName, error)
FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*AgentRealName, int64, error)
FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*AgentRealName, error)
FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*AgentRealName, error)
Delete(ctx context.Context, session sqlx.Session, id int64) error
}
defaultAgentRealNameModel struct {
sqlc.CachedConn
table string
}
AgentRealName struct {
Id int64 `db:"id"` // 主键ID
AgentId int64 `db:"agent_id"` // 代理ID
Name string `db:"name"` // 实名姓名
IdCard string `db:"id_card"` // 身份证号
Status string `db:"status"` // 认证状态(认证中、通过、拒绝)
DelState int64 `db:"del_state"` // 删除状态
Version int64 `db:"version"` // 版本号
CreateTime time.Time `db:"create_time"` // 创建时间
UpdateTime time.Time `db:"update_time"` // 更新时间
ApproveTime sql.NullTime `db:"approve_time"` // 认证通过时间
RejectTime sql.NullTime `db:"reject_time"` // 认证拒绝时间
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
}
)
func newAgentRealNameModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultAgentRealNameModel {
return &defaultAgentRealNameModel{
CachedConn: sqlc.NewConn(conn, c),
table: "`agent_real_name`",
}
}
func (m *defaultAgentRealNameModel) Insert(ctx context.Context, session sqlx.Session, data *AgentRealName) (sql.Result, error) {
data.DelState = globalkey.DelStateNo
qncAgentRealNameAgentIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameAgentIdPrefix, data.AgentId)
qncAgentRealNameIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameIdPrefix, data.Id)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentRealNameRowsExpectAutoSet)
if session != nil {
return session.ExecCtx(ctx, query, data.AgentId, data.Name, data.IdCard, data.Status, data.DelState, data.Version, data.ApproveTime, data.RejectTime, data.DeleteTime)
}
return conn.ExecCtx(ctx, query, data.AgentId, data.Name, data.IdCard, data.Status, data.DelState, data.Version, data.ApproveTime, data.RejectTime, data.DeleteTime)
}, qncAgentRealNameAgentIdKey, qncAgentRealNameIdKey)
}
func (m *defaultAgentRealNameModel) FindOne(ctx context.Context, id int64) (*AgentRealName, error) {
qncAgentRealNameIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameIdPrefix, id)
var resp AgentRealName
err := m.QueryRowCtx(ctx, &resp, qncAgentRealNameIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", agentRealNameRows, m.table)
return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo)
})
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAgentRealNameModel) FindOneByAgentId(ctx context.Context, agentId int64) (*AgentRealName, error) {
qncAgentRealNameAgentIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameAgentIdPrefix, agentId)
var resp AgentRealName
err := m.QueryRowIndexCtx(ctx, &resp, qncAgentRealNameAgentIdKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
query := fmt.Sprintf("select %s from %s where `agent_id` = ? and del_state = ? limit 1", agentRealNameRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, agentId, globalkey.DelStateNo); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAgentRealNameModel) Update(ctx context.Context, session sqlx.Session, newData *AgentRealName) (sql.Result, error) {
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return nil, err
}
qncAgentRealNameAgentIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameAgentIdPrefix, data.AgentId)
qncAgentRealNameIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameIdPrefix, data.Id)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentRealNameRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.AgentId, newData.Name, newData.IdCard, newData.Status, newData.DelState, newData.Version, newData.ApproveTime, newData.RejectTime, newData.DeleteTime, newData.Id)
}
return conn.ExecCtx(ctx, query, newData.AgentId, newData.Name, newData.IdCard, newData.Status, newData.DelState, newData.Version, newData.ApproveTime, newData.RejectTime, newData.DeleteTime, newData.Id)
}, qncAgentRealNameAgentIdKey, qncAgentRealNameIdKey)
}
func (m *defaultAgentRealNameModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, newData *AgentRealName) error {
oldVersion := newData.Version
newData.Version += 1
var sqlResult sql.Result
var err error
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return err
}
qncAgentRealNameAgentIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameAgentIdPrefix, data.AgentId)
qncAgentRealNameIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameIdPrefix, data.Id)
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentRealNameRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.AgentId, newData.Name, newData.IdCard, newData.Status, newData.DelState, newData.Version, newData.ApproveTime, newData.RejectTime, newData.DeleteTime, newData.Id, oldVersion)
}
return conn.ExecCtx(ctx, query, newData.AgentId, newData.Name, newData.IdCard, newData.Status, newData.DelState, newData.Version, newData.ApproveTime, newData.RejectTime, newData.DeleteTime, newData.Id, oldVersion)
}, qncAgentRealNameAgentIdKey, qncAgentRealNameIdKey)
if err != nil {
return err
}
updateCount, err := sqlResult.RowsAffected()
if err != nil {
return err
}
if updateCount == 0 {
return ErrNoRowsUpdate
}
return nil
}
func (m *defaultAgentRealNameModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *AgentRealName) error {
data.DelState = globalkey.DelStateYes
data.DeleteTime = sql.NullTime{Time: time.Now(), Valid: true}
if err := m.UpdateWithVersion(ctx, session, data); err != nil {
return errors.Wrapf(errors.New("delete soft failed "), "AgentRealNameModel delete err : %+v", err)
}
return nil
}
func (m *defaultAgentRealNameModel) FindSum(ctx context.Context, builder squirrel.SelectBuilder, field string) (float64, error) {
if len(field) == 0 {
return 0, errors.Wrapf(errors.New("FindSum Least One Field"), "FindSum Least One Field")
}
builder = builder.Columns("IFNULL(SUM(" + field + "),0)")
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return 0, err
}
var resp float64
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return 0, err
}
}
func (m *defaultAgentRealNameModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder, field string) (int64, error) {
if len(field) == 0 {
return 0, errors.Wrapf(errors.New("FindCount Least One Field"), "FindCount Least One Field")
}
builder = builder.Columns("COUNT(" + field + ")")
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return 0, err
}
var resp int64
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return 0, err
}
}
func (m *defaultAgentRealNameModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder, orderBy string) ([]*AgentRealName, error) {
builder = builder.Columns(agentRealNameRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return nil, err
}
var resp []*AgentRealName
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAgentRealNameModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*AgentRealName, error) {
builder = builder.Columns(agentRealNameRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
if page < 1 {
page = 1
}
offset := (page - 1) * pageSize
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*AgentRealName
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAgentRealNameModel) FindPageListByPageWithTotal(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*AgentRealName, int64, error) {
total, err := m.FindCount(ctx, builder, "id")
if err != nil {
return nil, 0, err
}
builder = builder.Columns(agentRealNameRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
if page < 1 {
page = 1
}
offset := (page - 1) * pageSize
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, total, err
}
var resp []*AgentRealName
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, total, nil
default:
return nil, total, err
}
}
func (m *defaultAgentRealNameModel) FindPageListByIdDESC(ctx context.Context, builder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*AgentRealName, error) {
builder = builder.Columns(agentRealNameRows)
if preMinId > 0 {
builder = builder.Where(" id < ? ", preMinId)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id DESC").Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*AgentRealName
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAgentRealNameModel) FindPageListByIdASC(ctx context.Context, builder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*AgentRealName, error) {
builder = builder.Columns(agentRealNameRows)
if preMaxId > 0 {
builder = builder.Where(" id > ? ", preMaxId)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id ASC").Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*AgentRealName
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAgentRealNameModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {
return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
return fn(ctx, session)
})
}
func (m *defaultAgentRealNameModel) SelectBuilder() squirrel.SelectBuilder {
return squirrel.Select().From(m.table)
}
func (m *defaultAgentRealNameModel) Delete(ctx context.Context, session sqlx.Session, id int64) error {
data, err := m.FindOne(ctx, id)
if err != nil {
return err
}
qncAgentRealNameAgentIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameAgentIdPrefix, data.AgentId)
qncAgentRealNameIdKey := fmt.Sprintf("%s%v", cacheQncAgentRealNameIdPrefix, id)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
if session != nil {
return session.ExecCtx(ctx, query, id)
}
return conn.ExecCtx(ctx, query, id)
}, qncAgentRealNameAgentIdKey, qncAgentRealNameIdKey)
return err
}
func (m *defaultAgentRealNameModel) formatPrimary(primary interface{}) string {
return fmt.Sprintf("%s%v", cacheQncAgentRealNameIdPrefix, primary)
}
func (m *defaultAgentRealNameModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error {
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", agentRealNameRows, m.table)
return conn.QueryRowCtx(ctx, v, query, primary, globalkey.DelStateNo)
}
func (m *defaultAgentRealNameModel) tableName() string {
return m.table
}

View File

@@ -0,0 +1,27 @@
package model
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ AuthorizationFaceModel = (*customAuthorizationFaceModel)(nil)
type (
// AuthorizationFaceModel is an interface to be customized, add more methods here,
// and implement the added methods in customAuthorizationFaceModel.
AuthorizationFaceModel interface {
authorizationFaceModel
}
customAuthorizationFaceModel struct {
*defaultAuthorizationFaceModel
}
)
// NewAuthorizationFaceModel returns a model for the database table.
func NewAuthorizationFaceModel(conn sqlx.SqlConn, c cache.CacheConf) AuthorizationFaceModel {
return &customAuthorizationFaceModel{
defaultAuthorizationFaceModel: newAuthorizationFaceModel(conn, c),
}
}

View File

@@ -0,0 +1,439 @@
// Code generated by goctl. DO NOT EDIT!
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"github.com/Masterminds/squirrel"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
"qnc-server/common/globalkey"
)
var (
authorizationFaceFieldNames = builder.RawFieldNames(&AuthorizationFace{})
authorizationFaceRows = strings.Join(authorizationFaceFieldNames, ",")
authorizationFaceRowsExpectAutoSet = strings.Join(stringx.Remove(authorizationFaceFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
authorizationFaceRowsWithPlaceHolder = strings.Join(stringx.Remove(authorizationFaceFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
cacheQncAuthorizationFaceIdPrefix = "cache:qnc:authorizationFace:id:"
cacheQncAuthorizationFaceCertifyIdPrefix = "cache:qnc:authorizationFace:certifyId:"
cacheQncAuthorizationFaceOuterOrderNoPrefix = "cache:qnc:authorizationFace:outerOrderNo:"
)
type (
authorizationFaceModel interface {
Insert(ctx context.Context, session sqlx.Session, data *AuthorizationFace) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*AuthorizationFace, error)
FindOneByCertifyId(ctx context.Context, certifyId string) (*AuthorizationFace, error)
FindOneByOuterOrderNo(ctx context.Context, outerOrderNo string) (*AuthorizationFace, error)
Update(ctx context.Context, session sqlx.Session, data *AuthorizationFace) (sql.Result, error)
UpdateWithVersion(ctx context.Context, session sqlx.Session, data *AuthorizationFace) error
Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error
SelectBuilder() squirrel.SelectBuilder
DeleteSoft(ctx context.Context, session sqlx.Session, data *AuthorizationFace) error
FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error)
FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error)
FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*AuthorizationFace, error)
FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*AuthorizationFace, error)
FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*AuthorizationFace, int64, error)
FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*AuthorizationFace, error)
FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*AuthorizationFace, error)
Delete(ctx context.Context, session sqlx.Session, id int64) error
}
defaultAuthorizationFaceModel struct {
sqlc.CachedConn
table string
}
AuthorizationFace struct {
Id int64 `db:"id"`
AuthorizationId int64 `db:"authorization_id"` // 关联授权主表ID
CertifyId string `db:"certify_id"`
OuterOrderNo string `db:"outer_order_no"` // 外部业务流水号
CertifyUrl string `db:"certify_url"`
CertifyUrlExpireAt time.Time `db:"certify_url_expire_at"` // 认证链接过期时间
Status string `db:"status"` // 认证状态pending待认证、success成功、fail失败
ResultMsg sql.NullString `db:"result_msg"`
PdfUrl sql.NullString `db:"pdf_url"`
CreateTime time.Time `db:"create_time"`
UpdateTime time.Time `db:"update_time"`
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
DelState int64 `db:"del_state"`
Version int64 `db:"version"` // 版本号
}
)
func newAuthorizationFaceModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultAuthorizationFaceModel {
return &defaultAuthorizationFaceModel{
CachedConn: sqlc.NewConn(conn, c),
table: "`authorization_face`",
}
}
func (m *defaultAuthorizationFaceModel) Insert(ctx context.Context, session sqlx.Session, data *AuthorizationFace) (sql.Result, error) {
data.DelState = globalkey.DelStateNo
qncAuthorizationFaceCertifyIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceCertifyIdPrefix, data.CertifyId)
qncAuthorizationFaceIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceIdPrefix, data.Id)
qncAuthorizationFaceOuterOrderNoKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceOuterOrderNoPrefix, data.OuterOrderNo)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, authorizationFaceRowsExpectAutoSet)
if session != nil {
return session.ExecCtx(ctx, query, data.AuthorizationId, data.CertifyId, data.OuterOrderNo, data.CertifyUrl, data.CertifyUrlExpireAt, data.Status, data.ResultMsg, data.PdfUrl, data.DeleteTime, data.DelState, data.Version)
}
return conn.ExecCtx(ctx, query, data.AuthorizationId, data.CertifyId, data.OuterOrderNo, data.CertifyUrl, data.CertifyUrlExpireAt, data.Status, data.ResultMsg, data.PdfUrl, data.DeleteTime, data.DelState, data.Version)
}, qncAuthorizationFaceCertifyIdKey, qncAuthorizationFaceIdKey, qncAuthorizationFaceOuterOrderNoKey)
}
func (m *defaultAuthorizationFaceModel) FindOne(ctx context.Context, id int64) (*AuthorizationFace, error) {
qncAuthorizationFaceIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceIdPrefix, id)
var resp AuthorizationFace
err := m.QueryRowCtx(ctx, &resp, qncAuthorizationFaceIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", authorizationFaceRows, m.table)
return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo)
})
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAuthorizationFaceModel) FindOneByCertifyId(ctx context.Context, certifyId string) (*AuthorizationFace, error) {
qncAuthorizationFaceCertifyIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceCertifyIdPrefix, certifyId)
var resp AuthorizationFace
err := m.QueryRowIndexCtx(ctx, &resp, qncAuthorizationFaceCertifyIdKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
query := fmt.Sprintf("select %s from %s where `certify_id` = ? and del_state = ? limit 1", authorizationFaceRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, certifyId, globalkey.DelStateNo); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAuthorizationFaceModel) FindOneByOuterOrderNo(ctx context.Context, outerOrderNo string) (*AuthorizationFace, error) {
qncAuthorizationFaceOuterOrderNoKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceOuterOrderNoPrefix, outerOrderNo)
var resp AuthorizationFace
err := m.QueryRowIndexCtx(ctx, &resp, qncAuthorizationFaceOuterOrderNoKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
query := fmt.Sprintf("select %s from %s where `outer_order_no` = ? and del_state = ? limit 1", authorizationFaceRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, outerOrderNo, globalkey.DelStateNo); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAuthorizationFaceModel) Update(ctx context.Context, session sqlx.Session, newData *AuthorizationFace) (sql.Result, error) {
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return nil, err
}
qncAuthorizationFaceCertifyIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceCertifyIdPrefix, data.CertifyId)
qncAuthorizationFaceIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceIdPrefix, data.Id)
qncAuthorizationFaceOuterOrderNoKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceOuterOrderNoPrefix, data.OuterOrderNo)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, authorizationFaceRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.AuthorizationId, newData.CertifyId, newData.OuterOrderNo, newData.CertifyUrl, newData.CertifyUrlExpireAt, newData.Status, newData.ResultMsg, newData.PdfUrl, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}
return conn.ExecCtx(ctx, query, newData.AuthorizationId, newData.CertifyId, newData.OuterOrderNo, newData.CertifyUrl, newData.CertifyUrlExpireAt, newData.Status, newData.ResultMsg, newData.PdfUrl, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}, qncAuthorizationFaceCertifyIdKey, qncAuthorizationFaceIdKey, qncAuthorizationFaceOuterOrderNoKey)
}
func (m *defaultAuthorizationFaceModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, newData *AuthorizationFace) error {
oldVersion := newData.Version
newData.Version += 1
var sqlResult sql.Result
var err error
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return err
}
qncAuthorizationFaceCertifyIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceCertifyIdPrefix, data.CertifyId)
qncAuthorizationFaceIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceIdPrefix, data.Id)
qncAuthorizationFaceOuterOrderNoKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceOuterOrderNoPrefix, data.OuterOrderNo)
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, authorizationFaceRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.AuthorizationId, newData.CertifyId, newData.OuterOrderNo, newData.CertifyUrl, newData.CertifyUrlExpireAt, newData.Status, newData.ResultMsg, newData.PdfUrl, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}
return conn.ExecCtx(ctx, query, newData.AuthorizationId, newData.CertifyId, newData.OuterOrderNo, newData.CertifyUrl, newData.CertifyUrlExpireAt, newData.Status, newData.ResultMsg, newData.PdfUrl, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}, qncAuthorizationFaceCertifyIdKey, qncAuthorizationFaceIdKey, qncAuthorizationFaceOuterOrderNoKey)
if err != nil {
return err
}
updateCount, err := sqlResult.RowsAffected()
if err != nil {
return err
}
if updateCount == 0 {
return ErrNoRowsUpdate
}
return nil
}
func (m *defaultAuthorizationFaceModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *AuthorizationFace) error {
data.DelState = globalkey.DelStateYes
data.DeleteTime = sql.NullTime{Time: time.Now(), Valid: true}
if err := m.UpdateWithVersion(ctx, session, data); err != nil {
return errors.Wrapf(errors.New("delete soft failed "), "AuthorizationFaceModel delete err : %+v", err)
}
return nil
}
func (m *defaultAuthorizationFaceModel) FindSum(ctx context.Context, builder squirrel.SelectBuilder, field string) (float64, error) {
if len(field) == 0 {
return 0, errors.Wrapf(errors.New("FindSum Least One Field"), "FindSum Least One Field")
}
builder = builder.Columns("IFNULL(SUM(" + field + "),0)")
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return 0, err
}
var resp float64
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return 0, err
}
}
func (m *defaultAuthorizationFaceModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder, field string) (int64, error) {
if len(field) == 0 {
return 0, errors.Wrapf(errors.New("FindCount Least One Field"), "FindCount Least One Field")
}
builder = builder.Columns("COUNT(" + field + ")")
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return 0, err
}
var resp int64
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return 0, err
}
}
func (m *defaultAuthorizationFaceModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder, orderBy string) ([]*AuthorizationFace, error) {
builder = builder.Columns(authorizationFaceRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return nil, err
}
var resp []*AuthorizationFace
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAuthorizationFaceModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*AuthorizationFace, error) {
builder = builder.Columns(authorizationFaceRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
if page < 1 {
page = 1
}
offset := (page - 1) * pageSize
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*AuthorizationFace
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAuthorizationFaceModel) FindPageListByPageWithTotal(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*AuthorizationFace, int64, error) {
total, err := m.FindCount(ctx, builder, "id")
if err != nil {
return nil, 0, err
}
builder = builder.Columns(authorizationFaceRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
if page < 1 {
page = 1
}
offset := (page - 1) * pageSize
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, total, err
}
var resp []*AuthorizationFace
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, total, nil
default:
return nil, total, err
}
}
func (m *defaultAuthorizationFaceModel) FindPageListByIdDESC(ctx context.Context, builder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*AuthorizationFace, error) {
builder = builder.Columns(authorizationFaceRows)
if preMinId > 0 {
builder = builder.Where(" id < ? ", preMinId)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id DESC").Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*AuthorizationFace
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAuthorizationFaceModel) FindPageListByIdASC(ctx context.Context, builder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*AuthorizationFace, error) {
builder = builder.Columns(authorizationFaceRows)
if preMaxId > 0 {
builder = builder.Where(" id > ? ", preMaxId)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id ASC").Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*AuthorizationFace
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAuthorizationFaceModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {
return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
return fn(ctx, session)
})
}
func (m *defaultAuthorizationFaceModel) SelectBuilder() squirrel.SelectBuilder {
return squirrel.Select().From(m.table)
}
func (m *defaultAuthorizationFaceModel) Delete(ctx context.Context, session sqlx.Session, id int64) error {
data, err := m.FindOne(ctx, id)
if err != nil {
return err
}
qncAuthorizationFaceCertifyIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceCertifyIdPrefix, data.CertifyId)
qncAuthorizationFaceIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceIdPrefix, id)
qncAuthorizationFaceOuterOrderNoKey := fmt.Sprintf("%s%v", cacheQncAuthorizationFaceOuterOrderNoPrefix, data.OuterOrderNo)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
if session != nil {
return session.ExecCtx(ctx, query, id)
}
return conn.ExecCtx(ctx, query, id)
}, qncAuthorizationFaceCertifyIdKey, qncAuthorizationFaceIdKey, qncAuthorizationFaceOuterOrderNoKey)
return err
}
func (m *defaultAuthorizationFaceModel) formatPrimary(primary interface{}) string {
return fmt.Sprintf("%s%v", cacheQncAuthorizationFaceIdPrefix, primary)
}
func (m *defaultAuthorizationFaceModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error {
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", authorizationFaceRows, m.table)
return conn.QueryRowCtx(ctx, v, query, primary, globalkey.DelStateNo)
}
func (m *defaultAuthorizationFaceModel) tableName() string {
return m.table
}

View File

@@ -0,0 +1,27 @@
package model
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ AuthorizationModel = (*customAuthorizationModel)(nil)
type (
// AuthorizationModel is an interface to be customized, add more methods here,
// and implement the added methods in customAuthorizationModel.
AuthorizationModel interface {
authorizationModel
}
customAuthorizationModel struct {
*defaultAuthorizationModel
}
)
// NewAuthorizationModel returns a model for the database table.
func NewAuthorizationModel(conn sqlx.SqlConn, c cache.CacheConf) AuthorizationModel {
return &customAuthorizationModel{
defaultAuthorizationModel: newAuthorizationModel(conn, c),
}
}

View File

@@ -0,0 +1,412 @@
// Code generated by goctl. DO NOT EDIT!
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"github.com/Masterminds/squirrel"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
"qnc-server/common/globalkey"
)
var (
authorizationFieldNames = builder.RawFieldNames(&Authorization{})
authorizationRows = strings.Join(authorizationFieldNames, ",")
authorizationRowsExpectAutoSet = strings.Join(stringx.Remove(authorizationFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
authorizationRowsWithPlaceHolder = strings.Join(stringx.Remove(authorizationFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
cacheQncAuthorizationIdPrefix = "cache:qnc:authorization:id:"
cacheQncAuthorizationOrderIdPrefix = "cache:qnc:authorization:orderId:"
)
type (
authorizationModel interface {
Insert(ctx context.Context, session sqlx.Session, data *Authorization) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*Authorization, error)
FindOneByOrderId(ctx context.Context, orderId int64) (*Authorization, error)
Update(ctx context.Context, session sqlx.Session, data *Authorization) (sql.Result, error)
UpdateWithVersion(ctx context.Context, session sqlx.Session, data *Authorization) error
Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error
SelectBuilder() squirrel.SelectBuilder
DeleteSoft(ctx context.Context, session sqlx.Session, data *Authorization) error
FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error)
FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error)
FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*Authorization, error)
FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*Authorization, error)
FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*Authorization, int64, error)
FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*Authorization, error)
FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*Authorization, error)
Delete(ctx context.Context, session sqlx.Session, id int64) error
}
defaultAuthorizationModel struct {
sqlc.CachedConn
table string
}
Authorization struct {
Id int64 `db:"id"`
OrderId int64 `db:"order_id"`
GrantType string `db:"grant_type"` // 授权类型face人脸后续可扩展
AuthType sql.NullInt64 `db:"auth_type"` // 1本人2他人
UserId int64 `db:"user_id"`
TargetName string `db:"target_name"`
TargetIdcard string `db:"target_idcard"`
Status string `db:"status"` // 授权状态pending待授权、success已授权、expired已失效、revoked已撤销
CreateTime time.Time `db:"create_time"`
UpdateTime time.Time `db:"update_time"`
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
DelState int64 `db:"del_state"`
Version int64 `db:"version"` // 版本号
}
)
func newAuthorizationModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultAuthorizationModel {
return &defaultAuthorizationModel{
CachedConn: sqlc.NewConn(conn, c),
table: "`authorization`",
}
}
func (m *defaultAuthorizationModel) Insert(ctx context.Context, session sqlx.Session, data *Authorization) (sql.Result, error) {
data.DelState = globalkey.DelStateNo
qncAuthorizationIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationIdPrefix, data.Id)
qncAuthorizationOrderIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationOrderIdPrefix, data.OrderId)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, authorizationRowsExpectAutoSet)
if session != nil {
return session.ExecCtx(ctx, query, data.OrderId, data.GrantType, data.AuthType, data.UserId, data.TargetName, data.TargetIdcard, data.Status, data.DeleteTime, data.DelState, data.Version)
}
return conn.ExecCtx(ctx, query, data.OrderId, data.GrantType, data.AuthType, data.UserId, data.TargetName, data.TargetIdcard, data.Status, data.DeleteTime, data.DelState, data.Version)
}, qncAuthorizationIdKey, qncAuthorizationOrderIdKey)
}
func (m *defaultAuthorizationModel) FindOne(ctx context.Context, id int64) (*Authorization, error) {
qncAuthorizationIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationIdPrefix, id)
var resp Authorization
err := m.QueryRowCtx(ctx, &resp, qncAuthorizationIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", authorizationRows, m.table)
return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo)
})
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAuthorizationModel) FindOneByOrderId(ctx context.Context, orderId int64) (*Authorization, error) {
qncAuthorizationOrderIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationOrderIdPrefix, orderId)
var resp Authorization
err := m.QueryRowIndexCtx(ctx, &resp, qncAuthorizationOrderIdKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
query := fmt.Sprintf("select %s from %s where `order_id` = ? and del_state = ? limit 1", authorizationRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, orderId, globalkey.DelStateNo); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultAuthorizationModel) Update(ctx context.Context, session sqlx.Session, newData *Authorization) (sql.Result, error) {
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return nil, err
}
qncAuthorizationIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationIdPrefix, data.Id)
qncAuthorizationOrderIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationOrderIdPrefix, data.OrderId)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, authorizationRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.OrderId, newData.GrantType, newData.AuthType, newData.UserId, newData.TargetName, newData.TargetIdcard, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}
return conn.ExecCtx(ctx, query, newData.OrderId, newData.GrantType, newData.AuthType, newData.UserId, newData.TargetName, newData.TargetIdcard, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}, qncAuthorizationIdKey, qncAuthorizationOrderIdKey)
}
func (m *defaultAuthorizationModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, newData *Authorization) error {
oldVersion := newData.Version
newData.Version += 1
var sqlResult sql.Result
var err error
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return err
}
qncAuthorizationIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationIdPrefix, data.Id)
qncAuthorizationOrderIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationOrderIdPrefix, data.OrderId)
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, authorizationRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.OrderId, newData.GrantType, newData.AuthType, newData.UserId, newData.TargetName, newData.TargetIdcard, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}
return conn.ExecCtx(ctx, query, newData.OrderId, newData.GrantType, newData.AuthType, newData.UserId, newData.TargetName, newData.TargetIdcard, newData.Status, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}, qncAuthorizationIdKey, qncAuthorizationOrderIdKey)
if err != nil {
return err
}
updateCount, err := sqlResult.RowsAffected()
if err != nil {
return err
}
if updateCount == 0 {
return ErrNoRowsUpdate
}
return nil
}
func (m *defaultAuthorizationModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *Authorization) error {
data.DelState = globalkey.DelStateYes
data.DeleteTime = sql.NullTime{Time: time.Now(), Valid: true}
if err := m.UpdateWithVersion(ctx, session, data); err != nil {
return errors.Wrapf(errors.New("delete soft failed "), "AuthorizationModel delete err : %+v", err)
}
return nil
}
func (m *defaultAuthorizationModel) FindSum(ctx context.Context, builder squirrel.SelectBuilder, field string) (float64, error) {
if len(field) == 0 {
return 0, errors.Wrapf(errors.New("FindSum Least One Field"), "FindSum Least One Field")
}
builder = builder.Columns("IFNULL(SUM(" + field + "),0)")
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return 0, err
}
var resp float64
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return 0, err
}
}
func (m *defaultAuthorizationModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder, field string) (int64, error) {
if len(field) == 0 {
return 0, errors.Wrapf(errors.New("FindCount Least One Field"), "FindCount Least One Field")
}
builder = builder.Columns("COUNT(" + field + ")")
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return 0, err
}
var resp int64
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return 0, err
}
}
func (m *defaultAuthorizationModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder, orderBy string) ([]*Authorization, error) {
builder = builder.Columns(authorizationRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return nil, err
}
var resp []*Authorization
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAuthorizationModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*Authorization, error) {
builder = builder.Columns(authorizationRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
if page < 1 {
page = 1
}
offset := (page - 1) * pageSize
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*Authorization
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAuthorizationModel) FindPageListByPageWithTotal(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*Authorization, int64, error) {
total, err := m.FindCount(ctx, builder, "id")
if err != nil {
return nil, 0, err
}
builder = builder.Columns(authorizationRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
if page < 1 {
page = 1
}
offset := (page - 1) * pageSize
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, total, err
}
var resp []*Authorization
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, total, nil
default:
return nil, total, err
}
}
func (m *defaultAuthorizationModel) FindPageListByIdDESC(ctx context.Context, builder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*Authorization, error) {
builder = builder.Columns(authorizationRows)
if preMinId > 0 {
builder = builder.Where(" id < ? ", preMinId)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id DESC").Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*Authorization
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAuthorizationModel) FindPageListByIdASC(ctx context.Context, builder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*Authorization, error) {
builder = builder.Columns(authorizationRows)
if preMaxId > 0 {
builder = builder.Where(" id > ? ", preMaxId)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id ASC").Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*Authorization
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultAuthorizationModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {
return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
return fn(ctx, session)
})
}
func (m *defaultAuthorizationModel) SelectBuilder() squirrel.SelectBuilder {
return squirrel.Select().From(m.table)
}
func (m *defaultAuthorizationModel) Delete(ctx context.Context, session sqlx.Session, id int64) error {
data, err := m.FindOne(ctx, id)
if err != nil {
return err
}
qncAuthorizationIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationIdPrefix, id)
qncAuthorizationOrderIdKey := fmt.Sprintf("%s%v", cacheQncAuthorizationOrderIdPrefix, data.OrderId)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
if session != nil {
return session.ExecCtx(ctx, query, id)
}
return conn.ExecCtx(ctx, query, id)
}, qncAuthorizationIdKey, qncAuthorizationOrderIdKey)
return err
}
func (m *defaultAuthorizationModel) formatPrimary(primary interface{}) string {
return fmt.Sprintf("%s%v", cacheQncAuthorizationIdPrefix, primary)
}
func (m *defaultAuthorizationModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error {
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", authorizationRows, m.table)
return conn.QueryRowCtx(ctx, v, query, primary, globalkey.DelStateNo)
}
func (m *defaultAuthorizationModel) tableName() string {
return m.table
}

View File

@@ -46,3 +46,27 @@ const (
QueryStateSuccess = "success"
QueryStateProcessing = "processing"
)
const (
GrantTypeFace string = "face"
)
const (
AuthorizationStatusPending = "pending"
AuthorizationStatusSuccess = "success"
AuthorizationStatusFailed = "failed"
AuthorizationStatusExpired = "expired"
AuthorizationStatusRevoked = "revoked"
AuthorizationStatusRejected = "rejected"
)
const (
AuthorizationFaceStatusPending = "pending"
AuthorizationFaceStatusSuccess = "success"
AuthorizationFaceStatusFailed = "failed"
)
const (
AgentRealNameStatusPending = "pending"
AgentRealNameStatusApproved = "approved"
AgentRealNameStatusRejected = "rejected"
)

110
common/jwt/jwtx_test.go Normal file
View File

@@ -0,0 +1,110 @@
package jwtx
import (
"fmt"
"testing"
"time"
)
func TestGenerateAndParseJwtToken(t *testing.T) {
// 测试参数
userId := int64(102)
secret := "WUvoIwL-FK0qnlxhvxR9tV6SjfOpeJMpKmY2QvT99lA"
expireTime := int64(2592000) // 1小时过期
// 生成token
token, err := GenerateJwtToken(userId, secret, expireTime)
if err != nil {
t.Fatalf("生成JWT令牌失败: %v", err)
}
if token == "" {
t.Fatal("生成的JWT令牌为空")
}
fmt.Println(token)
// 解析token
parsedUserId, err := ParseJwtToken(token, secret)
if err != nil {
t.Fatalf("解析JWT令牌失败: %v", err)
}
// 验证解析出的userId是否正确
if parsedUserId != userId {
t.Errorf("解析出的userId不匹配: 期望 %d, 实际 %d", userId, parsedUserId)
}
}
func TestTokenExpiration(t *testing.T) {
// 测试参数
userId := int64(10086)
secret := "test_secret_key"
expireTime := int64(1) // 1秒过期
// 生成token
token, err := GenerateJwtToken(userId, secret, expireTime)
if err != nil {
t.Fatalf("生成JWT令牌失败: %v", err)
}
// 等待令牌过期
time.Sleep(2 * time.Second)
// 解析已过期token
_, err = ParseJwtToken(token, secret)
if err == nil {
t.Error("期望令牌过期错误,但没有发生错误")
}
}
func TestInvalidToken(t *testing.T) {
secret := "test_secret_key"
// 测试无效token
invalidToken := "invalid.token.string"
_, err := ParseJwtToken(invalidToken, secret)
if err == nil {
t.Error("期望无效令牌错误,但没有发生错误")
}
// 测试密钥不匹配
userId := int64(10086)
expireTime := int64(3600)
token, _ := GenerateJwtToken(userId, "original_secret", expireTime)
_, err = ParseJwtToken(token, "wrong_secret")
if err == nil {
t.Error("期望密钥不匹配错误,但没有发生错误")
}
}
func TestUserIdTypes(t *testing.T) {
cases := []struct {
name string
setupFn func() (string, string, int64)
expected int64
}{
{
name: "正常int64类型",
setupFn: func() (string, string, int64) {
userId := int64(10086)
secret := "test_secret"
expireTime := int64(3600)
token, _ := GenerateJwtToken(userId, secret, expireTime)
return token, secret, userId
},
expected: 10086,
},
// 其他类型在实际场景中通过手动修改token内容测试这里省略
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
token, secret, expected := tc.setupFn()
userId, err := ParseJwtToken(token, secret)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
if userId != expected {
t.Errorf("用户ID不匹配: 期望 %d, 实际 %d", expected, userId)
}
})
}
}

163
deploy/script/README.md Normal file
View File

@@ -0,0 +1,163 @@
# Go-Zero 代码生成工具
这是一个用于 Go-Zero 微服务项目的代码生成工具,支持生成数据库模型和 API 代码。
## 功能特性
- 数据库模型生成:支持生成 Go-Zero 风格的数据库模型代码
- API 代码生成:支持生成 API 服务相关代码
- 灵活的表名管理:支持通过命令行指定表名,无需修改配置文件
- 配置文件支持:通过 config.json 配置数据库连接和表列表
- 命令行参数:支持通过命令行参数覆盖配置文件设置
## 安装
确保你的系统已安装 Node.js10.0+)。
```bash
# 安装依赖
cd deploy/script
npm install
```
## 使用方法
### 查看配置
```bash
npm run config
```
### 生成所有配置的表模型
```bash
npm run model
```
### 生成指定表的模型
```bash
# 生成单个表
npm run model:table agent
# 生成多个表(逗号分隔,不含空格)
npm run model:tables agent,user,order
# 或者使用完整命令
node codegen.js model --tables agent,user,order
```
### 排除指定表
```bash
# 从配置的表中排除某些表
npm run model:exclude user,order
# 或者使用完整命令
node codegen.js model --exclude user,order
```
### 生成所有数据库表的模型
```bash
npm run model:all
# 生成所有表但排除某些表
node codegen.js model --all --exclude system_table,temp_table
```
### 保存表配置
```bash
# 生成指定表并保存到配置文件
npm run model:save agent,user,order -- --save
# 或者使用完整命令
node codegen.js model --tables agent,user,order --save
```
### 生成 API 代码
```bash
npm run api
```
### 生成带样式的 API 代码
```bash
npm run api:style
```
### 查看帮助信息
```bash
npm run help
```
## 配置文件
所有配置都保存在`config.json`文件中,你可以编辑此文件来修改数据库连接信息和要生成的表列表:
```json
{
"model": {
"dbUrl": "user:password@tcp(host:port)/database",
"outputDir": "./model",
"templateDir": "../template",
"targetDir": "../../app/user/model",
"tables": ["table1", "table2"],
"disabledTables": ["disabled_table1"]
},
"api": {
"apiFile": "./app/user/cmd/api/desc/main.api",
"outputDir": "./app/user/cmd/api",
"templateDir": "./deploy/template",
"useStyle": false
}
}
```
## 表名管理
本工具提供了多种方式来指定需要生成的表:
1. **配置文件指定**:在`config.json``tables`数组中列出要生成的表
2. **命令行指定单个表**:使用`--table`参数指定单个表
3. **命令行指定多个表**:使用`--tables`参数指定多个表(逗号分隔)
4. **排除特定表**:使用`--exclude`参数排除特定表
5. **生成所有表**:使用`--all`参数生成数据库中的所有表
6. **保存到配置**:使用`--save`参数将当前指定的表保存到配置文件
这种灵活的表名管理方式使你可以根据需要随时调整要生成的表,而无需频繁修改配置文件。
## 高级用法
### 通过命令行参数覆盖配置
```bash
# 使用不同的数据库连接
node codegen.js model --db-url "user:pass@tcp(localhost:3306)/otherdb"
# 使用不同的API文件
node codegen.js api --api ./other_api.api
# 指定输出目录
node codegen.js api --dir ./output
```
### 组合使用参数
```bash
# 生成所有表但排除系统表,并使用自定义模板
node codegen.js model --all --exclude system_log,system_user --template ./my-templates
# 生成指定表并保存到配置
node codegen.js model --tables user,order,product --save
```
## 脚本文件说明
- `codegen.js` - 统一入口脚本
- `gen_models.js` - 模型生成脚本
- `gen_api.js` - API 生成脚本
- `config.json` - 配置文件

444
deploy/script/codegen.js Normal file
View File

@@ -0,0 +1,444 @@
#!/usr/bin/env node
/**
* 代码生成统一入口脚本
* 整合了model生成和api生成功能
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const { generateApi } = require('./gen_api');
// 读取配置文件
const CONFIG_FILE = path.join(__dirname, 'config.json');
let config = {};
try {
if (fs.existsSync(CONFIG_FILE)) {
const configContent = fs.readFileSync(CONFIG_FILE, 'utf8');
config = JSON.parse(configContent);
console.log('Configuration loaded from config.json');
} else {
console.log('config.json not found, using default settings');
}
} catch (error) {
console.error('Error loading configuration:', error.message);
console.log('Using default settings');
}
// 默认数据库配置
const modelConfig = config.model || {
// 数据库连接信息
dbUrl: 'qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc',
// 输出目录
outputDir: './model',
// 模板目录
templateDir: '../template',
// 目标目录
targetDir: '../../app/user/model',
// 表名列表
tables: [
'agent',
'agent_audit',
'agent_real_name'
],
// 禁用的表名列表
disabledTables: []
};
// 默认API配置
const apiConfig = config.api || {
// API定义文件路径
apiFile: './app/user/cmd/api/desc/main.api',
// 输出目录
outputDir: './app/user/cmd/api',
// 模板目录
templateDir: './deploy/template',
// 是否使用样式
useStyle: false
};
/**
* 将表名转换为驼峰命名法
* @param {string} tableName 表名
* @returns {string} 驼峰命名的表名
*/
function convertToCamelCase(tableName) {
try {
// 将表名按_分割并将每个部分首字母大写
const parts = tableName.split('_');
let camelCase = '';
for (const part of parts) {
if (part.length > 0) {
camelCase += part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
}
}
return camelCase;
} catch (error) {
console.error(`Error in convertToCamelCase for table: ${tableName}`);
console.error(error.message);
return tableName; // 出错时返回原表名
}
}
/**
* 确保目录存在
* @param {string} dirPath 目录路径
*/
function ensureDirectoryExists(dirPath) {
if (!fs.existsSync(dirPath)) {
console.log(`Creating directory: ${dirPath}`);
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 为单个表生成模型
* @param {string} table 表名
* @param {object} config 配置信息
*/
function generateModelForTable(table, config) {
try {
console.log('=========================================');
console.log(`Processing table: ${table}`);
// 生成模型
console.log('Generating model...');
const command = `goctl model mysql datasource -url="${config.dbUrl}" -table="${table}" -dir="${config.outputDir}" --home="${config.templateDir}" -cache=true --style=goZero`;
console.log(`Running command: ${command}`);
execSync(command, { stdio: 'inherit' });
// 将表名转换为驼峰命名法
const camelCaseName = convertToCamelCase(table);
console.log(`Table name converted to: ${camelCaseName}`);
// 定义源文件和目标文件路径
const sourceModelFile = path.join(config.outputDir, `${camelCaseName}Model.go`);
const sourceModelGenFile = path.join(config.outputDir, `${camelCaseName}Model_gen.go`);
const targetModelFile = path.join(config.targetDir, `${camelCaseName}Model.go`);
const targetModelGenFile = path.join(config.targetDir, `${camelCaseName}Model_gen.go`);
console.log('Source files:');
console.log(` - ${sourceModelFile}`);
console.log(` - ${sourceModelGenFile}`);
console.log('Target files:');
console.log(` - ${targetModelFile}`);
console.log(` - ${targetModelGenFile}`);
// 检查源文件是否存在并移动
if (fs.existsSync(sourceModelFile)) {
console.log(`Moving ${sourceModelFile} to ${targetModelFile}`);
fs.copyFileSync(sourceModelFile, targetModelFile);
fs.unlinkSync(sourceModelFile);
} else {
console.log(`WARNING: Source file not found: ${sourceModelFile}`);
}
if (fs.existsSync(sourceModelGenFile)) {
console.log(`Moving ${sourceModelGenFile} to ${targetModelGenFile}`);
fs.copyFileSync(sourceModelGenFile, targetModelGenFile);
fs.unlinkSync(sourceModelGenFile);
} else {
console.log(`WARNING: Source file not found: ${sourceModelGenFile}`);
}
console.log(`Processing completed for table: ${table}`);
} catch (error) {
console.error(`ERROR processing table: ${table}`);
console.error(error.message);
console.error(error.stack);
}
}
/**
* 生成指定表列表的模型
* @param {string[]} tables 表名列表
* @param {object} config 配置信息
*/
function generateModels(tables, config) {
try {
// 确保目录存在
ensureDirectoryExists(config.outputDir);
ensureDirectoryExists(config.targetDir);
if (tables.length === 0) {
console.log('No tables specified for generation.');
return;
}
// 为每个表生成模型
for (const table of tables) {
generateModelForTable(table, config);
}
console.log('=========================================');
console.log('All models generated successfully.');
} catch (error) {
console.error('ERROR in model generation:');
console.error(error.message);
console.error(error.stack);
process.exit(1);
}
}
/**
* 从数据库获取所有表名
* @param {string} dbUrl 数据库连接URL
* @returns {Promise<string[]>} 表名列表
*/
async function getAllTablesFromDB(dbUrl) {
try {
// 解析数据库连接信息
const dbName = dbUrl.split('/').pop().split('?')[0];
console.log(`Fetching all tables from database: ${dbName}`);
// 这里需要实现从数据库获取所有表的逻辑
// 由于需要依赖额外的库,这里只是示例
// 实际实现可能需要使用mysql2或其他数据库客户端库
// 模拟返回一些表名
return [
'agent',
'agent_audit',
'agent_real_name',
'agent_active_stat',
'agent_closure',
'agent_commission',
'agent_commission_deduction',
'agent_link',
'agent_membership_config',
'agent_membership_recharge_order',
'agent_membership_user_config',
'agent_order',
'agent_platform_deduction',
'agent_product_config',
'agent_rewards',
'agent_wallet',
'agent_withdrawal',
'feature',
'global_notifications',
'order',
'product',
'product_feature',
'query',
'user',
'user_auth',
'example',
'authorization',
'authorization_face'
];
} catch (error) {
console.error('Error fetching tables from database:', error.message);
return [];
}
}
/**
* 显示配置信息
*/
function showConfig() {
console.log('=========================================');
console.log('Current Configuration:');
console.log('\nModel Configuration:');
console.log(' Database URL:', modelConfig.dbUrl);
console.log(' Output Directory:', modelConfig.outputDir);
console.log(' Template Directory:', modelConfig.templateDir);
console.log(' Target Directory:', modelConfig.targetDir);
console.log(' Tables:');
modelConfig.tables.forEach(table => console.log(` - ${table}`));
if (modelConfig.disabledTables && modelConfig.disabledTables.length > 0) {
console.log(' Disabled Tables:');
modelConfig.disabledTables.forEach(table => console.log(` - ${table}`));
}
console.log('\nAPI Configuration:');
console.log(' API File:', apiConfig.apiFile);
console.log(' Output Directory:', apiConfig.outputDir);
console.log(' Template Directory:', apiConfig.templateDir);
console.log(' Use Style:', apiConfig.useStyle ? 'Yes' : 'No');
console.log('=========================================');
}
/**
* 保存配置到文件
* @param {object} config 配置对象
*/
function saveConfig(config) {
try {
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 4), 'utf8');
console.log('Configuration saved to config.json');
} catch (error) {
console.error('Error saving configuration:', error.message);
}
}
/**
* 显示帮助信息
*/
function showHelp() {
console.log('Usage: node codegen.js <command> [options]');
console.log('Commands:');
console.log(' model Generate database models');
console.log(' api Generate API code');
console.log(' config Show current configuration');
console.log(' help Show this help message');
console.log('');
console.log('Model Options:');
console.log(' --table <name> Generate model for specific table');
console.log(' --tables <names> Generate models for specific tables (comma-separated)');
console.log(' --exclude <names> Exclude specific tables (comma-separated)');
console.log(' --all Generate models for all tables in database');
console.log(' --db-url <url> Database connection URL');
console.log(' --template <dir> Template directory');
console.log(' --save Save specified tables to config.json');
console.log('');
console.log('API Options:');
console.log(' --api <file> API definition file path');
console.log(' --dir <dir> Output directory');
console.log(' --template <dir> Template directory');
console.log(' --style Use goZero style');
console.log('');
console.log('Configuration:');
console.log(' Settings are loaded from config.json');
console.log(' Command line options override config file settings');
console.log('');
console.log('Examples:');
console.log(' node codegen.js model --table agent');
console.log(' node codegen.js model --tables agent,user,order');
console.log(' node codegen.js model --exclude user,order');
console.log(' node codegen.js model --all --exclude system_table');
console.log(' node codegen.js model --tables agent,user --save');
process.exit(0);
}
/**
* 主函数
*/
async function main() {
// 解析命令行参数
const args = process.argv.slice(2);
if (args.length === 0 || args[0] === 'help') {
showHelp();
}
const command = args[0];
// 显示配置信息
if (command === 'config') {
showConfig();
return;
}
// 处理模型生成命令
if (command === 'model') {
const config = { ...modelConfig };
let singleTable = null;
let tablesToGenerate = [...config.tables];
let excludeTables = [];
let shouldSaveConfig = false;
let generateAllTables = false;
// 处理其他参数
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg === '--table' && i + 1 < args.length) {
singleTable = args[++i];
tablesToGenerate = [singleTable];
} else if (arg === '--tables' && i + 1 < args.length) {
const tableList = args[++i].split(',').map(t => t.trim()).filter(t => t);
tablesToGenerate = tableList;
} else if (arg === '--exclude' && i + 1 < args.length) {
excludeTables = args[++i].split(',').map(t => t.trim()).filter(t => t);
} else if (arg === '--all') {
generateAllTables = true;
} else if (arg === '--db-url' && i + 1 < args.length) {
config.dbUrl = args[++i];
} else if (arg === '--template' && i + 1 < args.length) {
config.templateDir = args[++i];
} else if (arg === '--save') {
shouldSaveConfig = true;
}
}
// 如果指定了--all参数获取所有表名
if (generateAllTables) {
tablesToGenerate = await getAllTablesFromDB(config.dbUrl);
}
// 排除指定的表
if (excludeTables.length > 0) {
tablesToGenerate = tablesToGenerate.filter(table => !excludeTables.includes(table));
}
// 保存配置
if (shouldSaveConfig) {
const newConfig = { ...config };
newConfig.tables = tablesToGenerate;
// 更新配置文件
if (fs.existsSync(CONFIG_FILE)) {
const existingConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
existingConfig.model = newConfig;
saveConfig(existingConfig);
} else {
saveConfig({ model: newConfig, api: apiConfig });
}
}
// 生成单个表的模型或所有表的模型
if (singleTable) {
generateModelForTable(singleTable, config);
} else {
generateModels(tablesToGenerate, config);
}
}
// 处理API生成命令
else if (command === 'api') {
const config = { ...apiConfig };
// 处理其他参数
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg === '--api' && i + 1 < args.length) {
config.apiFile = args[++i];
} else if (arg === '--dir' && i + 1 < args.length) {
config.outputDir = args[++i];
} else if (arg === '--template' && i + 1 < args.length) {
config.templateDir = args[++i];
} else if (arg === '--style') {
config.useStyle = true;
}
}
// 生成API代码
generateApi(config);
}
else {
console.error(`Unknown command: ${command}`);
showHelp();
}
}
// 执行主函数
if (require.main === module) {
main().catch(err => {
console.error('Error in main execution:', err);
process.exit(1);
});
}
// 导出函数,以便其他脚本可以调用
module.exports = {
generateModels,
generateModelForTable,
generateApi,
showConfig,
saveConfig,
getAllTablesFromDB
};

46
deploy/script/config.json Normal file
View File

@@ -0,0 +1,46 @@
{
"model": {
"dbUrl": "qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc",
"outputDir": "./model",
"templateDir": "../template",
"targetDir": "../../app/user/model",
"tables": [
"agent",
"agent_audit",
"agent_real_name"
],
"disabledTables": [
"agent_active_stat",
"agent_closure",
"agent_commission",
"agent_commission_deduction",
"agent_link",
"agent_membership_config",
"agent_membership_recharge_order",
"agent_membership_user_config",
"agent_order",
"agent_platform_deduction",
"agent_product_config",
"agent_rewards",
"agent_wallet",
"agent_withdrawal",
"feature",
"global_notifications",
"order",
"product",
"product_feature",
"query",
"user",
"user_auth",
"example",
"authorization",
"authorization_face"
]
},
"api": {
"apiFile": "./app/user/cmd/api/desc/main.api",
"outputDir": "./app/user/cmd/api",
"templateDir": "./deploy/template",
"useStyle": false
}
}

View File

@@ -1,102 +0,0 @@
package script
import (
"fmt"
"log"
"qnc-server/pkg/lzkit/crypto"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
const (
// 请替换为实际的数据库连接信息
dbHost = "localhost"
dbPort = "21001"
dbUser = "qnc"
dbPassword = "5vg67b3UNHu8"
dbName = "qnc"
// 请替换为实际的加密密钥
secretKey = "ff83609b2b24fc73196aac3d3dfb874f"
)
func RunEncryptMobile() {
fmt.Println("开始加密手机号")
// 连接数据库
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
dbUser, dbPassword, dbHost, dbPort, dbName)
db := sqlx.NewMysql(dsn)
// 加密user表的mobile字段
if err := encryptUserMobile(db); err != nil {
log.Fatalf("加密user表mobile字段失败: %v", err)
}
// 加密user_auth表的auth_key字段
if err := encryptUserAuthKey(db); err != nil {
log.Fatalf("加密user_auth表auth_key字段失败: %v", err)
}
fmt.Println("加密完成!")
}
func encryptUserMobile(db sqlx.SqlConn) error {
// 查询所有未加密的手机号
query := "SELECT id, mobile FROM user WHERE mobile IS NOT NULL AND mobile != ''"
var rows []struct {
ID int64 `db:"id"`
Mobile string `db:"mobile"`
}
if err := db.QueryRows(&rows, query); err != nil {
return fmt.Errorf("查询user表失败: %v", err)
}
// 准备更新语句
updateStmt := "UPDATE user SET mobile = ? WHERE id = ?"
// 处理每一行
for _, row := range rows {
// 加密手机号
encryptedMobile, err := crypto.EncryptMobile(row.Mobile, secretKey)
if err != nil {
return fmt.Errorf("加密手机号失败: %v", err)
}
// 更新数据库
if _, err := db.Exec(updateStmt, encryptedMobile, row.ID); err != nil {
return fmt.Errorf("更新user表失败: %v", err)
}
}
return nil
}
func encryptUserAuthKey(db sqlx.SqlConn) error {
// 查询所有需要加密的auth_key
query := "SELECT id, auth_key FROM user_auth WHERE auth_type = 'app_mobile' AND auth_key IS NOT NULL AND auth_key != ''"
var rows []struct {
ID int64 `db:"id"`
AuthKey string `db:"auth_key"`
}
if err := db.QueryRows(&rows, query); err != nil {
return fmt.Errorf("查询user_auth表失败: %v", err)
}
// 准备更新语句
updateStmt := "UPDATE user_auth SET auth_key = ? WHERE id = ?"
// 处理每一行
for _, row := range rows {
// 加密auth_key
encryptedAuthKey, err := crypto.EncryptMobile(row.AuthKey, secretKey)
if err != nil {
return fmt.Errorf("加密auth_key失败: %v", err)
}
// 更新数据库
if _, err := db.Exec(updateStmt, encryptedAuthKey, row.ID); err != nil {
return fmt.Errorf("更新user_auth表失败: %v", err)
}
}
return nil
}

108
deploy/script/gen_api.js Normal file
View File

@@ -0,0 +1,108 @@
#!/usr/bin/env node
/**
* API代码生成脚本
* 功能等同于gen_api.ps1
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
// 配置信息
const config = {
// API定义文件路径
apiFile: './app/user/cmd/api/desc/main.api',
// 输出目录
outputDir: './app/user/cmd/api',
// 模板目录
templateDir: './deploy/template'
};
/**
* 生成API代码
* @param {object} options 选项
* @param {string} options.apiFile API定义文件路径
* @param {string} options.outputDir 输出目录
* @param {string} options.templateDir 模板目录
* @param {boolean} options.useStyle 是否使用样式
*/
function generateApi({ apiFile, outputDir, templateDir, useStyle = false }) {
try {
console.log('=========================================');
console.log('Generating API code...');
// 构建命令
let command = `goctl api go --api ${apiFile} --dir ${outputDir} --home ${templateDir}`;
// 如果需要使用样式
if (useStyle) {
command += ' --style=goZero';
console.log('Using goZero style');
}
console.log(`Running command: ${command}`);
// 执行命令
execSync(command, { stdio: 'inherit' });
console.log('API code generation completed!');
console.log('=========================================');
} catch (error) {
console.error('ERROR in API generation:');
console.error(error.message);
console.error(error.stack);
process.exit(1);
}
}
/**
* 主函数
*/
function main() {
// 解析命令行参数
const args = process.argv.slice(2);
const options = {
apiFile: config.apiFile,
outputDir: config.outputDir,
templateDir: config.templateDir,
useStyle: false
};
// 处理命令行参数
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === '--api' && i + 1 < args.length) {
options.apiFile = args[++i];
} else if (arg === '--dir' && i + 1 < args.length) {
options.outputDir = args[++i];
} else if (arg === '--template' && i + 1 < args.length) {
options.templateDir = args[++i];
} else if (arg === '--style') {
options.useStyle = true;
} else if (arg === '--help') {
console.log('Usage: node gen_api.js [options]');
console.log('Options:');
console.log(' --api <file> API definition file path');
console.log(' --dir <dir> Output directory');
console.log(' --template <dir> Template directory');
console.log(' --style Use goZero style');
console.log(' --help Show this help message');
process.exit(0);
}
}
// 生成API代码
generateApi(options);
}
// 执行主函数
if (require.main === module) {
main();
}
// 导出函数,以便其他脚本可以调用
module.exports = {
generateApi
};

172
deploy/script/gen_models.js Normal file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env node
/**
* 数据库模型生成脚本
* 功能等同于gen_models.ps1
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
// 配置信息
const config = {
// 数据库连接信息
dbUrl: 'qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc',
// 输出目录
outputDir: './model',
// 模板目录
templateDir: '../template',
// 目标目录
targetDir: '../../app/user/model',
// 表名列表
tables: [
'agent',
// 'agent_active_stat',
'agent_audit',
'agent_real_name'
// 'agent_closure',
// 'agent_commission',
// 'agent_commission_deduction',
// 'agent_link',
// 'agent_membership_config',
// 'agent_membership_recharge_order',
// 'agent_membership_user_config',
// 'agent_order',
// 'agent_platform_deduction',
// 'agent_product_config',
// 'agent_rewards',
// 'agent_wallet',
// 'agent_withdrawal',
// 'feature',
// 'global_notifications',
// 'order',
// 'product',
// 'product_feature',
// 'query',
// 'user',
// 'user_auth',
// 'example',
// 'authorization',
// 'authorization_face'
]
};
/**
* 将表名转换为驼峰命名法
* @param {string} tableName 表名
* @returns {string} 驼峰命名的表名
*/
function convertToCamelCase(tableName) {
try {
// 将表名按_分割并将每个部分首字母大写
const parts = tableName.split('_');
let camelCase = '';
for (const part of parts) {
if (part.length > 0) {
camelCase += part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
}
}
return camelCase;
} catch (error) {
console.error(`Error in convertToCamelCase for table: ${tableName}`);
console.error(error.message);
return tableName; // 出错时返回原表名
}
}
/**
* 确保目录存在
* @param {string} dirPath 目录路径
*/
function ensureDirectoryExists(dirPath) {
if (!fs.existsSync(dirPath)) {
console.log(`Creating directory: ${dirPath}`);
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 为单个表生成模型
* @param {string} table 表名
*/
function generateModelForTable(table) {
try {
console.log('=========================================');
console.log(`Processing table: ${table}`);
// 生成模型
console.log('Generating model...');
const command = `goctl model mysql datasource -url="${config.dbUrl}" -table="${table}" -dir="${config.outputDir}" --home="${config.templateDir}" -cache=true --style=goZero`;
console.log(`Running command: ${command}`);
execSync(command, { stdio: 'inherit' });
// 将表名转换为驼峰命名法
const camelCaseName = convertToCamelCase(table);
console.log(`Table name converted to: ${camelCaseName}`);
// 定义源文件和目标文件路径
const sourceModelFile = path.join(config.outputDir, `${camelCaseName}Model.go`);
const sourceModelGenFile = path.join(config.outputDir, `${camelCaseName}Model_gen.go`);
const targetModelFile = path.join(config.targetDir, `${camelCaseName}Model.go`);
const targetModelGenFile = path.join(config.targetDir, `${camelCaseName}Model_gen.go`);
console.log('Source files:');
console.log(` - ${sourceModelFile}`);
console.log(` - ${sourceModelGenFile}`);
console.log('Target files:');
console.log(` - ${targetModelFile}`);
console.log(` - ${targetModelGenFile}`);
// 检查源文件是否存在并移动
if (fs.existsSync(sourceModelFile)) {
console.log(`Moving ${sourceModelFile} to ${targetModelFile}`);
fs.copyFileSync(sourceModelFile, targetModelFile);
fs.unlinkSync(sourceModelFile);
} else {
console.log(`WARNING: Source file not found: ${sourceModelFile}`);
}
if (fs.existsSync(sourceModelGenFile)) {
console.log(`Moving ${sourceModelGenFile} to ${targetModelGenFile}`);
fs.copyFileSync(sourceModelGenFile, targetModelGenFile);
fs.unlinkSync(sourceModelGenFile);
} else {
console.log(`WARNING: Source file not found: ${sourceModelGenFile}`);
}
console.log(`Processing completed for table: ${table}`);
} catch (error) {
console.error(`ERROR processing table: ${table}`);
console.error(error.message);
console.error(error.stack);
}
}
/**
* 主函数
*/
function main() {
try {
// 确保目录存在
ensureDirectoryExists(config.outputDir);
ensureDirectoryExists(config.targetDir);
// 为每个表生成模型
for (const table of config.tables) {
generateModelForTable(table);
}
console.log('=========================================');
console.log('Script execution completed.');
} catch (error) {
console.error('ERROR in main execution:');
console.error(error.message);
console.error(error.stack);
process.exit(1);
}
}
// 执行主函数
main();

View File

@@ -1,21 +1,64 @@
# 设置输出编码为UTF-8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# 数据库连接信息 - 修改了URL格式
$DB_URL = "qnc:5vg67b3UNHu8@(127.0.0.1:21001)/qnc"
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
# 启用详细输出和错误处理
$ErrorActionPreference = "Stop"
$VerbosePreference = "Continue"
# 检查并创建必要的目录
if (-not (Test-Path "./model")) {
Write-Output "Creating model directory..."
New-Item -ItemType Directory -Path "./model" | Out-Null
}
if (-not (Test-Path "../../app/user/model")) {
Write-Output "Creating target directory..."
New-Item -ItemType Directory -Path "../../app/user/model" -Force | Out-Null
}
# 将表名转换为驼峰命名法的函数
function ConvertToCamelCase {
param (
[string]$tableName
)
try {
# 将表名按_分割并将每个部分首字母大写
$parts = $tableName -split '_'
$camelCase = ""
foreach ($part in $parts) {
if ($part.Length -gt 0) {
$camelCase += $part.Substring(0, 1).ToUpper() + $part.Substring(1).ToLower()
}
}
return $camelCase
}
catch {
Write-Output "Error in ConvertToCamelCase for table: $tableName"
Write-Output $_.Exception.Message
return $tableName # 出错时返回原表名
}
}
# 数据库连接信息
$DB_URL = "qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc"
$OUTPUT_DIR = "./model"
$TEMPLATE_DIR = "../template"
$TARGET_DIR = "../../app/user/model"
# 表名列表
# 表名列表 - 每个元素后必须有逗号分隔
$tables = @(
# "agent",
"agent",
# "agent_active_stat",
# "agent_audit",
"agent_audit",
"agent_real_name"
# "agent_closure",
# "agent_commission",
# "agent_commission_deduction",
# "agent_link",
# "agent_membership_config",
# "agent_membership_recharge_order"
# "agent_membership_recharge_order",
# "agent_membership_user_config",
# "agent_order",
# "agent_platform_deduction",
@@ -29,12 +72,68 @@ $tables = @(
# "product",
# "product_feature",
# "query",
"user"
# "user_auth"
# "example"
# "user",
# "user_auth",
# "example",
# "authorization",
# "authorization_face"
)
# 为每个表生成模型
foreach ($table in $tables) {
goctl model mysql datasource -url="qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc" -table="$table" -dir="./model" --home="../template" -cache=true --style=goZero
try {
Write-Output "========================================="
Write-Output "Processing table: $table"
# 生成模型
Write-Output "Generating model..."
$command = "goctl model mysql datasource -url=`"$DB_URL`" -table=`"$table`" -dir=`"$OUTPUT_DIR`" --home=`"$TEMPLATE_DIR`" -cache=true --style=goZero"
Write-Output "Running command: $command"
Invoke-Expression $command
# 将表名转换为驼峰命名法
$camelCaseName = ConvertToCamelCase -tableName $table
Write-Output "Table name converted to: $camelCaseName"
# 定义源文件和目标文件路径
$sourceModelFile = "$OUTPUT_DIR/${camelCaseName}Model.go"
$sourceModelGenFile = "$OUTPUT_DIR/${camelCaseName}Model_gen.go"
$targetModelFile = "$TARGET_DIR/${camelCaseName}Model.go"
$targetModelGenFile = "$TARGET_DIR/${camelCaseName}Model_gen.go"
Write-Output "Source files:"
Write-Output " - $sourceModelFile"
Write-Output " - $sourceModelGenFile"
Write-Output "Target files:"
Write-Output " - $targetModelFile"
Write-Output " - $targetModelGenFile"
# 检查源文件是否存在
if (-not (Test-Path $sourceModelFile)) {
Write-Output "WARNING: Source file not found: $sourceModelFile"
}
if (-not (Test-Path $sourceModelGenFile)) {
Write-Output "WARNING: Source file not found: $sourceModelGenFile"
}
# 移动文件
if (Test-Path $sourceModelFile) {
Write-Output "Moving $sourceModelFile to $targetModelFile"
Move-Item -Path $sourceModelFile -Destination $targetModelFile -Force
}
if (Test-Path $sourceModelGenFile) {
Write-Output "Moving $sourceModelGenFile to $targetModelGenFile"
Move-Item -Path $sourceModelGenFile -Destination $targetModelGenFile -Force
}
Write-Output "Processing completed for table: $table"
}
catch {
Write-Output "ERROR processing table: $table"
Write-Output $_.Exception.Message
Write-Output $_.ScriptStackTrace
}
}
Write-Output "========================================="
Write-Output "Script execution completed."

View File

@@ -0,0 +1,26 @@
{
"name": "qnc-codegen",
"version": "1.0.0",
"description": "代码生成工具 - Go-Zero微服务项目",
"main": "codegen.js",
"scripts": {
"model": "node codegen.js model",
"model:table": "node codegen.js model --table",
"model:tables": "node codegen.js model --tables",
"model:exclude": "node codegen.js model --exclude",
"model:all": "node codegen.js model --all",
"model:save": "node codegen.js model --tables",
"model:save-exclude": "node codegen.js model --exclude",
"api": "node codegen.js api",
"api:style": "node codegen.js api --style",
"config": "node codegen.js config",
"help": "node codegen.js help"
},
"keywords": [
"go-zero",
"codegen",
"microservice"
],
"author": "",
"license": "ISC"
}

View File

@@ -0,0 +1,51 @@
-- 创建数据库(如果不存在)
CREATE DATABASE IF NOT EXISTS `qnc_server` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 使用数据库
USE `qnc_server`;
-- 创建代理实名认证表
CREATE TABLE `agent_real_name` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`agent_id` bigint NOT NULL COMMENT '代理ID',
`name` varchar(255) NOT NULL COMMENT '实名姓名',
`card_id` varchar(255) NOT NULL COMMENT '身份证号',
`status` enum(
'pending',
'approved',
'rejected'
) NOT NULL DEFAULT 'pending' COMMENT '认证状态(认证中、通过、拒绝)',
`del_state` tinyint NOT NULL DEFAULT '0' COMMENT '删除状态',
`version` bigint NOT NULL DEFAULT '0' COMMENT '版本号',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`approve_time` datetime DEFAULT NULL COMMENT '认证通过时间',
`reject_time` datetime DEFAULT NULL COMMENT '认证拒绝时间',
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_agent_id` (`agent_id`),
KEY `idx_status` (`status`),
KEY `idx_card_id` (`card_id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '代理实名认证表';
-- 添加表注释
ALTER TABLE `agent_real_name` COMMENT = '代理实名认证表';
-- 添加字段注释
ALTER TABLE `agent_real_name`
MODIFY COLUMN `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
MODIFY COLUMN `agent_id` bigint NOT NULL COMMENT '代理ID',
MODIFY COLUMN `name` varchar(255) NOT NULL COMMENT '实名姓名',
MODIFY COLUMN `card_id` varchar(255) NOT NULL COMMENT '身份证号',
MODIFY COLUMN `status` enum(
'pending',
'approved',
'rejected'
) NOT NULL DEFAULT 'pending' COMMENT '认证状态(认证中、通过、拒绝)',
MODIFY COLUMN `del_state` tinyint NOT NULL DEFAULT '0' COMMENT '删除状态',
MODIFY COLUMN `version` bigint NOT NULL DEFAULT '0' COMMENT '版本号',
MODIFY COLUMN `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
MODIFY COLUMN `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
MODIFY COLUMN `approve_time` datetime DEFAULT NULL COMMENT '认证通过时间',
MODIFY COLUMN `reject_time` datetime DEFAULT NULL COMMENT '认证拒绝时间',
MODIFY COLUMN `delete_time` datetime DEFAULT NULL COMMENT '删除时间';

21
go.mod
View File

@@ -4,17 +4,22 @@ go 1.22.4
require (
github.com/Masterminds/squirrel v1.5.4
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10
github.com/alibabacloud-go/cloudauth-20190307/v4 v4.6.0
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6
github.com/alibabacloud-go/tea v1.2.2
github.com/alibabacloud-go/tea-rpc v1.1.7
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
github.com/aliyun/credentials-go v1.4.6
github.com/bytedance/sonic v1.13.0
github.com/cenkalti/backoff/v4 v4.3.0
github.com/go-playground/validator/v10 v10.22.1
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/uuid v1.6.0
github.com/hibiken/asynq v0.25.0
github.com/jinzhu/copier v0.4.0
github.com/pkg/errors v0.9.1
github.com/redis/go-redis/v9 v9.7.0
github.com/shopspring/decimal v1.4.0
github.com/smartwalle/alipay/v3 v3.2.23
github.com/sony/sonyflake v1.2.0
@@ -30,10 +35,14 @@ require (
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
github.com/alibabacloud-go/tea-utils v1.3.1 // indirect
github.com/alibabacloud-go/openapi-util v0.1.1 // indirect
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect
github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect
github.com/alibabacloud-go/tea-oss-sdk v1.1.5 // indirect
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
github.com/alibabacloud-go/tea-rpc-utils v1.1.1 // indirect
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/credentials-go v1.3.10 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic/loader v0.2.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -60,7 +69,6 @@ require (
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@@ -81,14 +89,13 @@ require (
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/redis/go-redis/v9 v9.7.0 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/samber/lo v1.49.1 // indirect
github.com/smartwalle/ncrypto v1.0.4 // indirect
github.com/smartwalle/ngx v1.0.9 // indirect
github.com/smartwalle/nsign v1.0.9 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect

39
go.sum
View File

@@ -13,15 +13,18 @@ github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do2
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
github.com/alibabacloud-go/cloudauth-20190307/v4 v4.6.0 h1:msLjhAxXUrGVPCmVIz2SYMdERk4UDlMxaDTFt10GnXE=
github.com/alibabacloud-go/cloudauth-20190307/v4 v4.6.0/go.mod h1:XqPmDB32MyabzEsJBBzcFfRudijqlyyPyKBGRSbErYM=
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11 h1:GkVQ9AphMCmgAYakcTpH/OuFz0mQUypO/JiOvo0wgVA=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.11/go.mod h1:wHxkgZT1ClZdcwEVP/pDgYK/9HucsnCfMipmJgCz4xY=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
@@ -35,19 +38,35 @@ github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6/go.mod h1:UWpcGrWwTbES9QW
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
github.com/alibabacloud-go/openapi-util v0.1.1 h1:ujGErJjG8ncRW6XtBBMphzHTvCxn4DjrVw4m04HsS28=
github.com/alibabacloud-go/openapi-util v0.1.1/go.mod h1:/UehBSE2cf1gYT43GV4E+RxTdLRzURImCYY0aRmlXpw=
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 h1:L0TIjr9Qh/SLVc1yPhFkcB9+9SbCNK/jPq4ZKB5zmnc=
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1/go.mod h1:EKxBRDLcMzwl4VLF/1WJwlByZZECJawPXUvinKMsTTs=
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.10/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU=
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I=
github.com/alibabacloud-go/tea-fileform v1.1.1 h1:1YG6erAP3joQ0XdCXYIotuD7zyOM6qCR49xkp5FZDeU=
github.com/alibabacloud-go/tea-fileform v1.1.1/go.mod h1:ZeCV91o4ISmxidd686f0ebdS5EDHWU+vW+TkjLhrsFE=
github.com/alibabacloud-go/tea-oss-sdk v1.1.5 h1:CFUFcqanvBaoGN/CyTHUZrVNtFZd1WTjem46m0HTTV0=
github.com/alibabacloud-go/tea-oss-sdk v1.1.5/go.mod h1:5fhlKMa/kWRJNgPYRt+5qSg3UidRvNbf9Z2bI8Dp5/s=
github.com/alibabacloud-go/tea-oss-utils v1.1.0 h1:y65crjjcZ2Pbb6UZtC2deuIZHDVTS3IaDWE7M9nVLRc=
github.com/alibabacloud-go/tea-oss-utils v1.1.0/go.mod h1:PFCF12e9yEKyBUIn7X1IrF/pNjvxgkHy0CgxX4+xRuY=
github.com/alibabacloud-go/tea-rpc v1.1.7 h1:txkbgBb5DUBwQKqw9I+JY49eXGvvoAUSU2jnCr7Di+I=
github.com/alibabacloud-go/tea-rpc v1.1.7/go.mod h1:FU//dNbNYv1jSz1BGj6Sc3Co0IrbWsCnPiB/e1YnvgQ=
github.com/alibabacloud-go/tea-rpc-utils v1.1.1 h1:pthm/FnXIqXMNXXJhocvfEkbzUhHD8oWa10BlCHVKMw=
github.com/alibabacloud-go/tea-rpc-utils v1.1.1/go.mod h1:V5HdNi6Xdn0JMpgVhQ19vsFAS51tydr7BqcJtuXH1Yw=
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils v1.3.4/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA=
github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
github.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ=
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
@@ -64,8 +83,9 @@ github.com/alicebob/miniredis/v2 v2.33.0/go.mod h1:MhP4a3EU7aENRi9aO+tHfTBZicLqQ
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
github.com/aliyun/credentials-go v1.3.10 h1:45Xxrae/evfzQL9V10zL3xX31eqgLWEaIdCoPipOEQA=
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/aliyun/credentials-go v1.4.5/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/aliyun/credentials-go v1.4.6 h1:CG8rc/nxCNKfXbZWpWDzI9GjF4Tuu3Es14qT8Y0ClOk=
github.com/aliyun/credentials-go v1.4.6/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -261,8 +281,6 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/smartwalle/alipay/v3 v3.2.23 h1:i1VwJeu70EmwpsXXz6GZZnMAtRx5MTfn2dPoql/L3zE=
@@ -298,9 +316,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
@@ -460,10 +478,9 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@@ -0,0 +1,178 @@
package cloudauth
import (
"encoding/json"
"fmt"
cloudauth "github.com/alibabacloud-go/cloudauth-20190307/v4/client"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
"github.com/aliyun/credentials-go/credentials"
"github.com/zeromicro/go-zero/core/logx"
)
type CloudAuthClient struct {
Client *cloudauth.Client
Config *CloudAuthConfig
}
type CloudAuthConfig struct {
AccessKeyId string
AccessKeySecret string
Endpoint string
SceneId int64
ReturnUrl string
}
type InitFaceVerifyResp struct {
CertifyId string
CertifyUrl string
}
type DescribeFaceVerifyResp struct {
Passed bool
}
// InitFaceVerifyRequest 封装初始化人脸认证所需参数
type InitFaceVerifyParam struct {
OuterOrderNo string
CertName string
CertNo string
MetaInfo string
}
// NewCloudAuthClient 创建阿里云人脸认证客户端
func NewCloudAuthClient(cloudAuthconfig CloudAuthConfig) (*CloudAuthClient, error) {
// 使用AK 初始化Credentials Client。
credentialsConfig := new(credentials.Config).
// 凭证类型。
SetType("access_key").
// 设置为AccessKey ID值。
SetAccessKeyId(cloudAuthconfig.AccessKeyId).
// 设置为AccessKey Secret值。
SetAccessKeySecret(cloudAuthconfig.AccessKeySecret)
credentialClient, _err := credentials.NewCredential(credentialsConfig)
if _err != nil {
panic(_err)
}
ecsConfig := &openapi.Config{}
// 配置云产品服务接入地址endpoint
ecsConfig.Endpoint = tea.String(cloudAuthconfig.Endpoint)
// 使用Credentials配置凭证。
ecsConfig.Credential = credentialClient
// 创建客户端
client, err := cloudauth.NewClient(ecsConfig)
if err != nil {
panic(fmt.Sprintf("创建阿里云人脸认证客户端失败: %v", err))
}
return &CloudAuthClient{
Client: client,
Config: &CloudAuthConfig{
AccessKeyId: cloudAuthconfig.AccessKeyId,
AccessKeySecret: cloudAuthconfig.AccessKeySecret,
Endpoint: cloudAuthconfig.Endpoint,
SceneId: cloudAuthconfig.SceneId,
ReturnUrl: cloudAuthconfig.ReturnUrl,
},
}, nil
}
// InitFaceVerify 初始化人脸认证
func (c *CloudAuthClient) InitFaceVerify(param InitFaceVerifyParam) (*InitFaceVerifyResp, error) {
request := &cloudauth.InitFaceVerifyRequest{
SceneId: tea.Int64(c.Config.SceneId),
OuterOrderNo: tea.String(param.OuterOrderNo),
ProductCode: tea.String("ID_PRO"),
Model: tea.String("LIVENESS"),
CertType: tea.String("IDENTITY_CARD"),
CertName: tea.String(param.CertName),
CertNo: tea.String(param.CertNo),
MetaInfo: tea.String(param.MetaInfo),
ReturnUrl: tea.String(c.Config.ReturnUrl),
}
runtime := &util.RuntimeOptions{
ReadTimeout: tea.Int(10000),
ConnectTimeout: tea.Int(5000),
}
response, err := c.Client.InitFaceVerifyWithOptions(request, runtime)
if err != nil {
if sdkErr, ok := err.(*tea.SDKError); ok {
logx.Errorf("认证初始化失败: %s, 建议: %s",
tea.StringValue(sdkErr.Message),
getRecommendFromError(sdkErr))
return nil, fmt.Errorf("认证初始化失败: %s", tea.StringValue(sdkErr.Message))
}
logx.Errorf("认证初始化失败: %v", err)
return nil, fmt.Errorf("认证初始化失败: %v", err)
}
if tea.StringValue(response.Body.Code) != "200" {
logx.Errorf("认证初始化失败: %s", tea.StringValue(response.Body.Message))
return nil, fmt.Errorf("认证初始化失败: %s", tea.StringValue(response.Body.Message))
}
return &InitFaceVerifyResp{
CertifyId: tea.StringValue(response.Body.ResultObject.CertifyId),
CertifyUrl: tea.StringValue(response.Body.ResultObject.CertifyUrl),
}, nil
}
// DescribeFaceVerify 获取认证结果
func (c *CloudAuthClient) DescribeFaceVerify(certifyId string) (*DescribeFaceVerifyResp, error) {
request := &cloudauth.DescribeFaceVerifyRequest{
SceneId: tea.Int64(c.Config.SceneId),
CertifyId: tea.String(certifyId),
}
runtime := &util.RuntimeOptions{
ReadTimeout: tea.Int(10000),
ConnectTimeout: tea.Int(5000),
}
response, err := c.Client.DescribeFaceVerifyWithOptions(request, runtime)
if err != nil {
logx.Errorf("获取认证结果失败: %v", err)
return nil, fmt.Errorf("获取认证结果失败: %v", err)
}
if tea.StringValue(response.Body.Code) != "200" {
logx.Errorf("获取认证结果失败: %s", tea.StringValue(response.Body.Message))
return nil, fmt.Errorf("获取认证结果失败: %s", tea.StringValue(response.Body.Message))
}
var passed bool
var passedStr = tea.StringValue(response.Body.ResultObject.Passed)
switch passedStr {
case "T":
passed = true
case "F":
passed = false
default:
passed = false
}
return &DescribeFaceVerifyResp{
Passed: passed,
}, nil
}
// 从SDK错误中获取推荐信息
func getRecommendFromError(err *tea.SDKError) string {
if err == nil || err.Data == nil {
return ""
}
var data map[string]interface{}
if err := json.Unmarshal([]byte(tea.StringValue(err.Data)), &data); err != nil {
return ""
}
if recommend, ok := data["Recommend"].(string); ok {
return recommend
}
return ""
}

View File

@@ -0,0 +1,31 @@
package crypto
import (
"encoding/hex"
"fmt"
"testing"
)
func TestAesEncryptDecrypt(t *testing.T) {
keyHex := "ff83609b2b24fc73196aac3d3dfb874f"
key, decodeErr := hex.DecodeString(keyHex)
if decodeErr != nil {
t.Fatalf("key decode error: %v", decodeErr)
}
plainText := "45212220000827423X"
cipherText, err := AesEncrypt([]byte(plainText), key)
if err != nil {
t.Fatalf("AesEncrypt error: %v", err)
}
fmt.Println(cipherText)
decrypted, err := AesDecrypt(cipherText, key)
if err != nil {
t.Fatalf("AesDecrypt error: %v", err)
}
if string(decrypted) != plainText {
t.Errorf("AesDecrypt result not match, got: %s, want: %s", string(decrypted), plainText)
}
}