1、新增自定义用户私人价格2、优化api服务鉴权缓存3、新增管理员端对公充值

This commit is contained in:
liangzai 2024-10-21 16:01:20 +08:00
parent 8896fd6b30
commit 2292d25d74
37 changed files with 1903 additions and 907 deletions

View File

@ -152,3 +152,41 @@ service admin-api {
get /list (GetProductListReq) returns (GetProductListResp) get /list (GetProductListReq) returns (GetProductListResp)
} }
type (
UserListRequest {
Page int64 `json:"page"` // 分页页码
PageSize int64 `json:"pageSize"` // 每页大小
}
UserListResponse {
List []UserItem `json:"list"`
Total int64 `json:"total"`
}
UserItem {
Id int64 `json:"id"` // 主键ID
Username string `json:"username"` // 用户名
Phone string `json:"phone"` // 电话
Disable int64 `json:"disable"` // 是否禁用状态1为禁用0为启用
QuotaExceeded int64 `json:"quotaExceeded"` // 是否超出配额1为超出0为未超出
Balance float64 `json:"balance"` // 余额
CreatedAt string `json:"createdAt"` // 创建时间
UpdatedAt string `json:"updatedAt"` // 更新时间
}
rechargeRequest {
UserId int64 `json:userId`
Amount int64 `json:amount`
}
)
@server (
group: user
prefix: /api/admin/user
middleware: AuthInterceptor
)
service admin-api {
@handler getUserList
post /user/list (UserListRequest) returns (UserListResponse)
@handler recharge
post /user/recharge (rechargeRequest)
}

View File

@ -93,4 +93,23 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
), ),
rest.WithPrefix("/api/admin/user"), rest.WithPrefix("/api/admin/user"),
) )
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.AuthInterceptor},
[]rest.Route{
{
Method: http.MethodPost,
Path: "/user/list",
Handler: user.GetUserListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/user/recharge",
Handler: user.RechargeHandler(serverCtx),
},
}...,
),
rest.WithPrefix("/api/admin/user"),
)
} }

View File

@ -0,0 +1,30 @@
package user
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"tianyuan-api/apps/admin/internal/logic/user"
"tianyuan-api/apps/admin/internal/svc"
"tianyuan-api/apps/admin/internal/types"
xhttp "github.com/zeromicro/x/http"
)
func GetUserListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.UserListRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := user.NewGetUserListLogic(r.Context(), svcCtx)
resp, err := l.GetUserList(&req)
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
xhttp.JsonBaseResponseCtx(r.Context(), w, resp)
}
}
}

View File

@ -0,0 +1,30 @@
package user
import (
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"tianyuan-api/apps/admin/internal/logic/user"
"tianyuan-api/apps/admin/internal/svc"
"tianyuan-api/apps/admin/internal/types"
xhttp "github.com/zeromicro/x/http"
)
func RechargeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.RechargeRequest
if err := httpx.Parse(r, &req); err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
return
}
l := user.NewRechargeLogic(r.Context(), svcCtx)
err := l.Recharge(&req)
if err != nil {
xhttp.JsonBaseResponseCtx(r.Context(), w, err)
} else {
xhttp.JsonBaseResponseCtx(r.Context(), w, nil)
}
}
}

View File

@ -0,0 +1,53 @@
package user
import (
"context"
"tianyuan-api/apps/user/user"
"tianyuan-api/apps/admin/internal/svc"
"tianyuan-api/apps/admin/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserListLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserListLogic {
return &GetUserListLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *GetUserListLogic) GetUserList(req *types.UserListRequest) (resp *types.UserListResponse, err error) {
list, err := l.svcCtx.UserRpc.GetUserList(l.ctx, &user.UserListRequest{
Page: req.Page,
PageSize: req.PageSize,
})
if err != nil {
return nil, err
}
var listResp []types.UserItem
for _, item := range list.List {
listResp = append(listResp, types.UserItem{
Id: item.Id,
Username: item.Username,
Phone: item.Phone,
Disable: item.Disable,
Balance: item.Balance,
QuotaExceeded: item.QuotaExceeded,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
})
}
return &types.UserListResponse{
List: listResp,
Total: list.Total,
}, nil
}

View File

@ -0,0 +1,39 @@
package user
import (
"context"
"tianyuan-api/apps/admin/internal/svc"
"tianyuan-api/apps/admin/internal/types"
"tianyuan-api/apps/user/user"
"tianyuan-api/pkg/generate"
"github.com/zeromicro/go-zero/core/logx"
)
type RechargeLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewRechargeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RechargeLogic {
return &RechargeLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *RechargeLogic) Recharge(req *types.RechargeRequest) error {
outTradeNo := generate.GenerateTransactionID()
_, err := l.svcCtx.WalletsRpc.RechargeWallet(l.ctx, &user.RechargeWalletRequest{
UserId: req.UserId,
OutTradeNo: outTradeNo,
Amount: req.Amount,
PaymentMethod: 2,
})
if err != nil {
return err
}
return nil
}

View File

@ -15,6 +15,7 @@ type ServiceContext struct {
EntRpc user.EnterpriseClient EntRpc user.EnterpriseClient
UserRpc user.UserClient UserRpc user.UserClient
ProductRpc sentinel.ProductClient ProductRpc sentinel.ProductClient
WalletsRpc user.WalletServiceClient
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
@ -24,5 +25,6 @@ func NewServiceContext(c config.Config) *ServiceContext {
EntRpc: user.NewEnterpriseClient(zrpc.MustNewClient(c.UserRpc).Conn()), EntRpc: user.NewEnterpriseClient(zrpc.MustNewClient(c.UserRpc).Conn()),
UserRpc: user.NewUserClient(zrpc.MustNewClient(c.UserRpc).Conn()), UserRpc: user.NewUserClient(zrpc.MustNewClient(c.UserRpc).Conn()),
ProductRpc: sentinel.NewProductClient(zrpc.MustNewClient(c.SentinelRpc).Conn()), ProductRpc: sentinel.NewProductClient(zrpc.MustNewClient(c.SentinelRpc).Conn()),
WalletsRpc: user.NewWalletServiceClient(zrpc.MustNewClient(c.UserRpc).Conn()),
} }
} }

View File

@ -98,3 +98,29 @@ type UpdateProductReq struct {
type UserInfoResp struct { type UserInfoResp struct {
Username string `json:"username"` Username string `json:"username"`
} }
type UserItem struct {
Id int64 `json:"id"` // 主键ID
Username string `json:"username"` // 用户名
Phone string `json:"phone"` // 电话
Disable int64 `json:"disable"` // 是否禁用状态1为禁用0为启用
QuotaExceeded int64 `json:"quotaExceeded"` // 是否超出配额1为超出0为未超出
Balance float64 `json:"balance"` // 余额
CreatedAt string `json:"createdAt"` // 创建时间
UpdatedAt string `json:"updatedAt"` // 更新时间
}
type UserListRequest struct {
Page int64 `json:"page"` // 分页页码
PageSize int64 `json:"pageSize"` // 每页大小
}
type UserListResponse struct {
List []UserItem `json:"list"`
Total int64 `json:"total"`
}
type RechargeRequest struct {
UserId int64 `json:userId`
Amount int64 `json:amount`
}

View File

@ -43,8 +43,10 @@ type (
UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest
UserProductEmptyResponse = sentinel.UserProductEmptyResponse UserProductEmptyResponse = sentinel.UserProductEmptyResponse
UserProductItem = sentinel.UserProductItem UserProductItem = sentinel.UserProductItem
UserProductPageListResponse = sentinel.UserProductPageListResponse
UserProductResponse = sentinel.UserProductResponse UserProductResponse = sentinel.UserProductResponse
UserProuctPageListRequest = sentinel.UserProuctPageListRequest UserProuctPageListRequest = sentinel.UserProuctPageListRequest
UserProuctRequest = sentinel.UserProuctRequest
WhitePageListRequest = sentinel.WhitePageListRequest WhitePageListRequest = sentinel.WhitePageListRequest
Whitelist = sentinel.Whitelist Whitelist = sentinel.Whitelist
WhitelistResponse = sentinel.WhitelistResponse WhitelistResponse = sentinel.WhitelistResponse

View File

@ -43,8 +43,10 @@ type (
UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest
UserProductEmptyResponse = sentinel.UserProductEmptyResponse UserProductEmptyResponse = sentinel.UserProductEmptyResponse
UserProductItem = sentinel.UserProductItem UserProductItem = sentinel.UserProductItem
UserProductPageListResponse = sentinel.UserProductPageListResponse
UserProductResponse = sentinel.UserProductResponse UserProductResponse = sentinel.UserProductResponse
UserProuctPageListRequest = sentinel.UserProuctPageListRequest UserProuctPageListRequest = sentinel.UserProuctPageListRequest
UserProuctRequest = sentinel.UserProuctRequest
WhitePageListRequest = sentinel.WhitePageListRequest WhitePageListRequest = sentinel.WhitePageListRequest
Whitelist = sentinel.Whitelist Whitelist = sentinel.Whitelist
WhitelistResponse = sentinel.WhitelistResponse WhitelistResponse = sentinel.WhitelistResponse

View File

@ -43,8 +43,10 @@ type (
UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest
UserProductEmptyResponse = sentinel.UserProductEmptyResponse UserProductEmptyResponse = sentinel.UserProductEmptyResponse
UserProductItem = sentinel.UserProductItem UserProductItem = sentinel.UserProductItem
UserProductPageListResponse = sentinel.UserProductPageListResponse
UserProductResponse = sentinel.UserProductResponse UserProductResponse = sentinel.UserProductResponse
UserProuctPageListRequest = sentinel.UserProuctPageListRequest UserProuctPageListRequest = sentinel.UserProuctPageListRequest
UserProuctRequest = sentinel.UserProuctRequest
WhitePageListRequest = sentinel.WhitePageListRequest WhitePageListRequest = sentinel.WhitePageListRequest
Whitelist = sentinel.Whitelist Whitelist = sentinel.Whitelist
WhitelistResponse = sentinel.WhitelistResponse WhitelistResponse = sentinel.WhitelistResponse

View File

@ -43,8 +43,10 @@ type (
UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest
UserProductEmptyResponse = sentinel.UserProductEmptyResponse UserProductEmptyResponse = sentinel.UserProductEmptyResponse
UserProductItem = sentinel.UserProductItem UserProductItem = sentinel.UserProductItem
UserProductPageListResponse = sentinel.UserProductPageListResponse
UserProductResponse = sentinel.UserProductResponse UserProductResponse = sentinel.UserProductResponse
UserProuctPageListRequest = sentinel.UserProuctPageListRequest UserProuctPageListRequest = sentinel.UserProuctPageListRequest
UserProuctRequest = sentinel.UserProuctRequest
WhitePageListRequest = sentinel.WhitePageListRequest WhitePageListRequest = sentinel.WhitePageListRequest
Whitelist = sentinel.Whitelist Whitelist = sentinel.Whitelist
WhitelistResponse = sentinel.WhitelistResponse WhitelistResponse = sentinel.WhitelistResponse
@ -52,7 +54,8 @@ type (
UserProduct interface { UserProduct interface {
// UserProduct methods // UserProduct methods
CreateUserProduct(ctx context.Context, in *CreateUserProductRequest, opts ...grpc.CallOption) (*UserProductEmptyResponse, error) CreateUserProduct(ctx context.Context, in *CreateUserProductRequest, opts ...grpc.CallOption) (*UserProductEmptyResponse, error)
GetUserProductPageList(ctx context.Context, in *UserProuctPageListRequest, opts ...grpc.CallOption) (*UserProductResponse, error) GetUserProductPageList(ctx context.Context, in *UserProuctPageListRequest, opts ...grpc.CallOption) (*UserProductPageListResponse, error)
GetUserProduct(ctx context.Context, in *UserProuctRequest, opts ...grpc.CallOption) (*UserProductResponse, error)
MatchingUserIdProductCode(ctx context.Context, in *MatchingUserIdProductCodeRequest, opts ...grpc.CallOption) (*MatchResponse, error) MatchingUserIdProductCode(ctx context.Context, in *MatchingUserIdProductCodeRequest, opts ...grpc.CallOption) (*MatchResponse, error)
} }
@ -73,11 +76,16 @@ func (m *defaultUserProduct) CreateUserProduct(ctx context.Context, in *CreateUs
return client.CreateUserProduct(ctx, in, opts...) return client.CreateUserProduct(ctx, in, opts...)
} }
func (m *defaultUserProduct) GetUserProductPageList(ctx context.Context, in *UserProuctPageListRequest, opts ...grpc.CallOption) (*UserProductResponse, error) { func (m *defaultUserProduct) GetUserProductPageList(ctx context.Context, in *UserProuctPageListRequest, opts ...grpc.CallOption) (*UserProductPageListResponse, error) {
client := sentinel.NewUserProductClient(m.cli.Conn()) client := sentinel.NewUserProductClient(m.cli.Conn())
return client.GetUserProductPageList(ctx, in, opts...) return client.GetUserProductPageList(ctx, in, opts...)
} }
func (m *defaultUserProduct) GetUserProduct(ctx context.Context, in *UserProuctRequest, opts ...grpc.CallOption) (*UserProductResponse, error) {
client := sentinel.NewUserProductClient(m.cli.Conn())
return client.GetUserProduct(ctx, in, opts...)
}
func (m *defaultUserProduct) MatchingUserIdProductCode(ctx context.Context, in *MatchingUserIdProductCodeRequest, opts ...grpc.CallOption) (*MatchResponse, error) { func (m *defaultUserProduct) MatchingUserIdProductCode(ctx context.Context, in *MatchingUserIdProductCodeRequest, opts ...grpc.CallOption) (*MatchResponse, error) {
client := sentinel.NewUserProductClient(m.cli.Conn()) client := sentinel.NewUserProductClient(m.cli.Conn())
return client.MatchingUserIdProductCode(ctx, in, opts...) return client.MatchingUserIdProductCode(ctx, in, opts...)

View File

@ -43,8 +43,10 @@ type (
UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest UpdateWhitelistRequest = sentinel.UpdateWhitelistRequest
UserProductEmptyResponse = sentinel.UserProductEmptyResponse UserProductEmptyResponse = sentinel.UserProductEmptyResponse
UserProductItem = sentinel.UserProductItem UserProductItem = sentinel.UserProductItem
UserProductPageListResponse = sentinel.UserProductPageListResponse
UserProductResponse = sentinel.UserProductResponse UserProductResponse = sentinel.UserProductResponse
UserProuctPageListRequest = sentinel.UserProuctPageListRequest UserProuctPageListRequest = sentinel.UserProuctPageListRequest
UserProuctRequest = sentinel.UserProuctRequest
WhitePageListRequest = sentinel.WhitePageListRequest WhitePageListRequest = sentinel.WhitePageListRequest
Whitelist = sentinel.Whitelist Whitelist = sentinel.Whitelist
WhitelistResponse = sentinel.WhitelistResponse WhitelistResponse = sentinel.WhitelistResponse

View File

@ -34,7 +34,11 @@ func (l *CreateUserProductLogic) CreateUserProduct(in *sentinel.CreateUserProduc
if isExist { if isExist {
return nil, errors.New("该产品已定阅读,无法重复订阅") return nil, errors.New("该产品已定阅读,无法重复订阅")
} }
_, err = l.svcCtx.UserProductsModel.Insert(l.ctx, &model.UserProducts{UserId: in.UserId, ProductId: in.ProductId}) product, err := l.svcCtx.ProductsModel.FindOne(l.ctx, in.ProductId)
if err != nil {
return nil, err
}
_, err = l.svcCtx.UserProductsModel.Insert(l.ctx, &model.UserProducts{UserId: in.UserId, ProductId: in.ProductId, ProductPrice: product.ProductPrice})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -0,0 +1,38 @@
package userproductlogic
import (
"context"
"tianyuan-api/apps/sentinel/internal/svc"
"tianyuan-api/apps/sentinel/sentinel"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserProductLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetUserProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserProductLogic {
return &GetUserProductLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetUserProductLogic) GetUserProduct(in *sentinel.UserProuctRequest) (*sentinel.UserProductResponse, error) {
userProduct, err := l.svcCtx.UserProductsModel.FindOneUserProduct(l.ctx, in.UserId, in.ProductId)
if err != nil {
return nil, err
}
return &sentinel.UserProductResponse{
Id: userProduct.Id,
UserId: userProduct.UserId,
ProductId: userProduct.ProductId,
ProductPrice: userProduct.ProductPrice,
}, nil
}

View File

@ -25,7 +25,7 @@ func NewGetUserProductPageListLogic(ctx context.Context, svcCtx *svc.ServiceCont
} }
} }
func (l *GetUserProductPageListLogic) GetUserProductPageList(in *sentinel.UserProuctPageListRequest) (*sentinel.UserProductResponse, error) { func (l *GetUserProductPageListLogic) GetUserProductPageList(in *sentinel.UserProuctPageListRequest) (*sentinel.UserProductPageListResponse, error) {
list, total, err := l.svcCtx.UserProductsModel.FindUserProductsList(l.ctx, in.UserId, in.Page, in.PageSize) list, total, err := l.svcCtx.UserProductsModel.FindUserProductsList(l.ctx, in.UserId, in.Page, in.PageSize)
if err != nil { if err != nil {
return nil, err return nil, err
@ -45,7 +45,7 @@ func (l *GetUserProductPageListLogic) GetUserProductPageList(in *sentinel.UserPr
UpdatedAt: up.UpdatedAt.Format("2006-01-02 15:04:05"), UpdatedAt: up.UpdatedAt.Format("2006-01-02 15:04:05"),
}) })
} }
return &sentinel.UserProductResponse{ return &sentinel.UserProductPageListResponse{
Total: total, Total: total,
UserProducts: userProducts, UserProducts: userProducts,
}, nil }, nil

View File

@ -61,7 +61,7 @@ func (m *defaultUserProductsModel) FindUserProductsList(ctx context.Context, use
p.product_code, p.product_code,
COALESCE(p.product_description, '') AS product_description, COALESCE(p.product_description, '') AS product_description,
p.product_group, p.product_group,
p.product_price, up.product_price,
up.created_at, up.created_at,
up.updated_at up.updated_at
FROM user_products up FROM user_products up
@ -87,26 +87,11 @@ func (m *defaultUserProductsModel) FindUserProductsList(ctx context.Context, use
return userProducts, total, nil return userProducts, total, nil
} }
func (m *customUserProductsModel) FindOneUserProduct(ctx context.Context, userId, productId int64) (*UserProducts, error) { func (m *customUserProductsModel) FindOneUserProduct(ctx context.Context, userId, productId int64) (*UserProducts, error) {
// 定义 Redis 缓存 Set 键
redisKey := fmt.Sprintf("user_products:%d", userId)
// 检查 Redis Set 中是否存在用户与产品的关联
isMember, err := m.rds.SismemberCtx(ctx, redisKey, productId)
if err == nil && isMember {
// 如果 Redis Set 中存在,返回空,因为不需要重复查询
return nil, nil
}
var userProduct UserProducts var userProduct UserProducts
query := fmt.Sprintf("SELECT %s FROM %s WHERE `user_id` = ? AND `product_id` = ? LIMIT 1", userProductsRows, m.table) query := fmt.Sprintf("SELECT %s FROM %s WHERE `user_id` = ? AND `product_id` = ? LIMIT 1", userProductsRows, m.table)
err = m.QueryRowNoCacheCtx(ctx, &userProduct, query, userId, productId) err := m.QueryRowNoCacheCtx(ctx, &userProduct, query, userId, productId)
switch err { switch err {
case nil: case nil:
// 将用户产品的关联写入 Redis Set
_, err = m.rds.SaddCtx(ctx, redisKey, productId)
if err != nil {
return nil, err
}
return &userProduct, nil return &userProduct, nil
case sqlc.ErrNotFound: case sqlc.ErrNotFound:
// 返回未找到的错误 // 返回未找到的错误

View File

@ -44,6 +44,7 @@ type (
Id int64 `db:"id"` // 用户产品ID Id int64 `db:"id"` // 用户产品ID
UserId int64 `db:"user_id"` // 用户ID UserId int64 `db:"user_id"` // 用户ID
ProductId int64 `db:"product_id"` // 产品ID ProductId int64 `db:"product_id"` // 产品ID
ProductPrice float64 `db:"product_price"` // 产品价格
CreatedAt time.Time `db:"created_at"` // 创建时间 CreatedAt time.Time `db:"created_at"` // 创建时间
UpdatedAt time.Time `db:"updated_at"` // 更新时间 UpdatedAt time.Time `db:"updated_at"` // 更新时间
} }
@ -85,8 +86,8 @@ func (m *defaultUserProductsModel) FindOne(ctx context.Context, id int64) (*User
func (m *defaultUserProductsModel) Insert(ctx context.Context, data *UserProducts) (sql.Result, error) { func (m *defaultUserProductsModel) Insert(ctx context.Context, data *UserProducts) (sql.Result, error) {
userProductsIdKey := fmt.Sprintf("%s%v", cacheUserProductsIdPrefix, data.Id) userProductsIdKey := fmt.Sprintf("%s%v", cacheUserProductsIdPrefix, data.Id)
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { ret, err := 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, userProductsRowsExpectAutoSet) query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?)", m.table, userProductsRowsExpectAutoSet)
return conn.ExecCtx(ctx, query, data.UserId, data.ProductId) return conn.ExecCtx(ctx, query, data.UserId, data.ProductId, data.ProductPrice)
}, userProductsIdKey) }, userProductsIdKey)
return ret, err return ret, err
} }
@ -95,7 +96,7 @@ func (m *defaultUserProductsModel) Update(ctx context.Context, data *UserProduct
userProductsIdKey := fmt.Sprintf("%s%v", cacheUserProductsIdPrefix, data.Id) userProductsIdKey := fmt.Sprintf("%s%v", cacheUserProductsIdPrefix, data.Id)
_, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { _, 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` = ?", m.table, userProductsRowsWithPlaceHolder) query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userProductsRowsWithPlaceHolder)
return conn.ExecCtx(ctx, query, data.UserId, data.ProductId, data.Id) return conn.ExecCtx(ctx, query, data.UserId, data.ProductId, data.ProductPrice, data.Id)
}, userProductsIdKey) }, userProductsIdKey)
return err return err
} }

View File

@ -29,11 +29,16 @@ func (s *UserProductServer) CreateUserProduct(ctx context.Context, in *sentinel.
return l.CreateUserProduct(in) return l.CreateUserProduct(in)
} }
func (s *UserProductServer) GetUserProductPageList(ctx context.Context, in *sentinel.UserProuctPageListRequest) (*sentinel.UserProductResponse, error) { func (s *UserProductServer) GetUserProductPageList(ctx context.Context, in *sentinel.UserProuctPageListRequest) (*sentinel.UserProductPageListResponse, error) {
l := userproductlogic.NewGetUserProductPageListLogic(ctx, s.svcCtx) l := userproductlogic.NewGetUserProductPageListLogic(ctx, s.svcCtx)
return l.GetUserProductPageList(in) return l.GetUserProductPageList(in)
} }
func (s *UserProductServer) GetUserProduct(ctx context.Context, in *sentinel.UserProuctRequest) (*sentinel.UserProductResponse, error) {
l := userproductlogic.NewGetUserProductLogic(ctx, s.svcCtx)
return l.GetUserProduct(in)
}
func (s *UserProductServer) MatchingUserIdProductCode(ctx context.Context, in *sentinel.MatchingUserIdProductCodeRequest) (*sentinel.MatchResponse, error) { func (s *UserProductServer) MatchingUserIdProductCode(ctx context.Context, in *sentinel.MatchingUserIdProductCodeRequest) (*sentinel.MatchResponse, error) {
l := userproductlogic.NewMatchingUserIdProductCodeLogic(ctx, s.svcCtx) l := userproductlogic.NewMatchingUserIdProductCodeLogic(ctx, s.svcCtx)
return l.MatchingUserIdProductCode(in) return l.MatchingUserIdProductCode(in)

View File

@ -14,6 +14,10 @@ message UserProuctPageListRequest {
int64 page = 2; int64 page = 2;
int64 page_size = 3; int64 page_size = 3;
} }
message UserProuctRequest {
int64 user_id = 1;
int64 product_id = 2;
}
message WhitePageListRequest { message WhitePageListRequest {
int64 user_id = 1; int64 user_id = 1;
int64 page = 2; int64 page = 2;
@ -85,7 +89,6 @@ message SecretResponse {
repeated Secret secrets = 2; repeated Secret secrets = 2;
} }
// Message for Products operations
message Product { message Product {
int64 id = 1; int64 id = 1;
string product_name = 2; string product_name = 2;
@ -126,7 +129,6 @@ message ProductResponse {
repeated Product products = 2; repeated Product products = 2;
} }
// Message for UserProducts operations
message UserProductEmptyResponse { message UserProductEmptyResponse {
} }
message UserProductItem { message UserProductItem {
@ -153,10 +155,16 @@ message DeleteUserProductRequest {
int64 id = 1; int64 id = 1;
} }
message UserProductResponse { message UserProductPageListResponse {
int64 total = 1; int64 total = 1;
repeated UserProductItem user_products = 2; repeated UserProductItem user_products = 2;
} }
message UserProductResponse {
int64 id = 1; // ID
int64 userId = 2;
int64 productId = 3; // ID
double productPrice = 4; //
}
message matchingUserIdProductCodeRequest { message matchingUserIdProductCodeRequest {
int64 id = 1; int64 id = 1;
@ -184,7 +192,6 @@ message AliTopUpNotifyRequest {
message AliTopUpNotifyResponse { message AliTopUpNotifyResponse {
bool success = 1; bool success = 1;
} }
// Service definitions for Whitelist, Secrets, Products, and UserProducts
service whitelist { service whitelist {
// Whitelist methods // Whitelist methods
rpc CreateWhitelist(CreateWhitelistRequest) returns (Whitelist); rpc CreateWhitelist(CreateWhitelistRequest) returns (Whitelist);
@ -211,7 +218,8 @@ service product {
service userProduct { service userProduct {
// UserProduct methods // UserProduct methods
rpc CreateUserProduct(CreateUserProductRequest) returns (UserProductEmptyResponse); rpc CreateUserProduct(CreateUserProductRequest) returns (UserProductEmptyResponse);
rpc GetUserProductPageList(UserProuctPageListRequest) returns (UserProductResponse); rpc GetUserProductPageList(UserProuctPageListRequest) returns (UserProductPageListResponse);
rpc GetUserProduct(UserProuctRequest) returns (UserProductResponse);
rpc MatchingUserIdProductCode(matchingUserIdProductCodeRequest) returns (matchResponse); rpc MatchingUserIdProductCode(matchingUserIdProductCodeRequest) returns (matchResponse);
} }

View File

@ -36,6 +36,7 @@ CREATE TABLE `user_products` (
`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '用户产品ID', `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '用户产品ID',
`user_id` INT(11) NOT NULL COMMENT '用户ID', `user_id` INT(11) NOT NULL COMMENT '用户ID',
`product_id` INT(11) NOT NULL COMMENT '产品ID', `product_id` INT(11) NOT NULL COMMENT '产品ID',
`product_price` DECIMAL(10, 2) NOT NULL COMMENT '产品价格',
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)

File diff suppressed because it is too large Load Diff

View File

@ -29,8 +29,6 @@ const (
// WhitelistClient is the client API for Whitelist service. // WhitelistClient is the client API for Whitelist service.
// //
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
//
// Service definitions for Whitelist, Secrets, Products, and UserProducts
type WhitelistClient interface { type WhitelistClient interface {
// Whitelist methods // Whitelist methods
CreateWhitelist(ctx context.Context, in *CreateWhitelistRequest, opts ...grpc.CallOption) (*Whitelist, error) CreateWhitelist(ctx context.Context, in *CreateWhitelistRequest, opts ...grpc.CallOption) (*Whitelist, error)
@ -101,8 +99,6 @@ func (c *whitelistClient) MatchWhitelistByIp(ctx context.Context, in *MatchWhite
// WhitelistServer is the server API for Whitelist service. // WhitelistServer is the server API for Whitelist service.
// All implementations must embed UnimplementedWhitelistServer // All implementations must embed UnimplementedWhitelistServer
// for forward compatibility // for forward compatibility
//
// Service definitions for Whitelist, Secrets, Products, and UserProducts
type WhitelistServer interface { type WhitelistServer interface {
// Whitelist methods // Whitelist methods
CreateWhitelist(context.Context, *CreateWhitelistRequest) (*Whitelist, error) CreateWhitelist(context.Context, *CreateWhitelistRequest) (*Whitelist, error)
@ -722,6 +718,7 @@ var Product_ServiceDesc = grpc.ServiceDesc{
const ( const (
UserProduct_CreateUserProduct_FullMethodName = "/userProduct/CreateUserProduct" UserProduct_CreateUserProduct_FullMethodName = "/userProduct/CreateUserProduct"
UserProduct_GetUserProductPageList_FullMethodName = "/userProduct/GetUserProductPageList" UserProduct_GetUserProductPageList_FullMethodName = "/userProduct/GetUserProductPageList"
UserProduct_GetUserProduct_FullMethodName = "/userProduct/GetUserProduct"
UserProduct_MatchingUserIdProductCode_FullMethodName = "/userProduct/MatchingUserIdProductCode" UserProduct_MatchingUserIdProductCode_FullMethodName = "/userProduct/MatchingUserIdProductCode"
) )
@ -731,7 +728,8 @@ const (
type UserProductClient interface { type UserProductClient interface {
// UserProduct methods // UserProduct methods
CreateUserProduct(ctx context.Context, in *CreateUserProductRequest, opts ...grpc.CallOption) (*UserProductEmptyResponse, error) CreateUserProduct(ctx context.Context, in *CreateUserProductRequest, opts ...grpc.CallOption) (*UserProductEmptyResponse, error)
GetUserProductPageList(ctx context.Context, in *UserProuctPageListRequest, opts ...grpc.CallOption) (*UserProductResponse, error) GetUserProductPageList(ctx context.Context, in *UserProuctPageListRequest, opts ...grpc.CallOption) (*UserProductPageListResponse, error)
GetUserProduct(ctx context.Context, in *UserProuctRequest, opts ...grpc.CallOption) (*UserProductResponse, error)
MatchingUserIdProductCode(ctx context.Context, in *MatchingUserIdProductCodeRequest, opts ...grpc.CallOption) (*MatchResponse, error) MatchingUserIdProductCode(ctx context.Context, in *MatchingUserIdProductCodeRequest, opts ...grpc.CallOption) (*MatchResponse, error)
} }
@ -753,10 +751,20 @@ func (c *userProductClient) CreateUserProduct(ctx context.Context, in *CreateUse
return out, nil return out, nil
} }
func (c *userProductClient) GetUserProductPageList(ctx context.Context, in *UserProuctPageListRequest, opts ...grpc.CallOption) (*UserProductResponse, error) { func (c *userProductClient) GetUserProductPageList(ctx context.Context, in *UserProuctPageListRequest, opts ...grpc.CallOption) (*UserProductPageListResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UserProductPageListResponse)
err := c.cc.Invoke(ctx, UserProduct_GetUserProductPageList_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *userProductClient) GetUserProduct(ctx context.Context, in *UserProuctRequest, opts ...grpc.CallOption) (*UserProductResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UserProductResponse) out := new(UserProductResponse)
err := c.cc.Invoke(ctx, UserProduct_GetUserProductPageList_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, UserProduct_GetUserProduct_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -779,7 +787,8 @@ func (c *userProductClient) MatchingUserIdProductCode(ctx context.Context, in *M
type UserProductServer interface { type UserProductServer interface {
// UserProduct methods // UserProduct methods
CreateUserProduct(context.Context, *CreateUserProductRequest) (*UserProductEmptyResponse, error) CreateUserProduct(context.Context, *CreateUserProductRequest) (*UserProductEmptyResponse, error)
GetUserProductPageList(context.Context, *UserProuctPageListRequest) (*UserProductResponse, error) GetUserProductPageList(context.Context, *UserProuctPageListRequest) (*UserProductPageListResponse, error)
GetUserProduct(context.Context, *UserProuctRequest) (*UserProductResponse, error)
MatchingUserIdProductCode(context.Context, *MatchingUserIdProductCodeRequest) (*MatchResponse, error) MatchingUserIdProductCode(context.Context, *MatchingUserIdProductCodeRequest) (*MatchResponse, error)
mustEmbedUnimplementedUserProductServer() mustEmbedUnimplementedUserProductServer()
} }
@ -791,9 +800,12 @@ type UnimplementedUserProductServer struct {
func (UnimplementedUserProductServer) CreateUserProduct(context.Context, *CreateUserProductRequest) (*UserProductEmptyResponse, error) { func (UnimplementedUserProductServer) CreateUserProduct(context.Context, *CreateUserProductRequest) (*UserProductEmptyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateUserProduct not implemented") return nil, status.Errorf(codes.Unimplemented, "method CreateUserProduct not implemented")
} }
func (UnimplementedUserProductServer) GetUserProductPageList(context.Context, *UserProuctPageListRequest) (*UserProductResponse, error) { func (UnimplementedUserProductServer) GetUserProductPageList(context.Context, *UserProuctPageListRequest) (*UserProductPageListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserProductPageList not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetUserProductPageList not implemented")
} }
func (UnimplementedUserProductServer) GetUserProduct(context.Context, *UserProuctRequest) (*UserProductResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserProduct not implemented")
}
func (UnimplementedUserProductServer) MatchingUserIdProductCode(context.Context, *MatchingUserIdProductCodeRequest) (*MatchResponse, error) { func (UnimplementedUserProductServer) MatchingUserIdProductCode(context.Context, *MatchingUserIdProductCodeRequest) (*MatchResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method MatchingUserIdProductCode not implemented") return nil, status.Errorf(codes.Unimplemented, "method MatchingUserIdProductCode not implemented")
} }
@ -846,6 +858,24 @@ func _UserProduct_GetUserProductPageList_Handler(srv interface{}, ctx context.Co
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _UserProduct_GetUserProduct_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UserProuctRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserProductServer).GetUserProduct(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: UserProduct_GetUserProduct_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserProductServer).GetUserProduct(ctx, req.(*UserProuctRequest))
}
return interceptor(ctx, in, info, handler)
}
func _UserProduct_MatchingUserIdProductCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _UserProduct_MatchingUserIdProductCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MatchingUserIdProductCodeRequest) in := new(MatchingUserIdProductCodeRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -879,6 +909,10 @@ var UserProduct_ServiceDesc = grpc.ServiceDesc{
MethodName: "GetUserProductPageList", MethodName: "GetUserProductPageList",
Handler: _UserProduct_GetUserProductPageList_Handler, Handler: _UserProduct_GetUserProductPageList_Handler,
}, },
{
MethodName: "GetUserProduct",
Handler: _UserProduct_GetUserProduct_Handler,
},
{ {
MethodName: "MatchingUserIdProductCode", MethodName: "MatchingUserIdProductCode",
Handler: _UserProduct_MatchingUserIdProductCode_Handler, Handler: _UserProduct_MatchingUserIdProductCode_Handler,

View File

@ -50,6 +50,9 @@ type (
UpdateWalletResponse = user.UpdateWalletResponse UpdateWalletResponse = user.UpdateWalletResponse
UserInfoReq = user.UserInfoReq UserInfoReq = user.UserInfoReq
UserInfoResp = user.UserInfoResp UserInfoResp = user.UserInfoResp
UserItem = user.UserItem
UserListRequest = user.UserListRequest
UserListResponse = user.UserListResponse
ApiRequestService interface { ApiRequestService interface {
// 添加API请求记录 // 添加API请求记录

View File

@ -50,6 +50,9 @@ type (
UpdateWalletResponse = user.UpdateWalletResponse UpdateWalletResponse = user.UpdateWalletResponse
UserInfoReq = user.UserInfoReq UserInfoReq = user.UserInfoReq
UserInfoResp = user.UserInfoResp UserInfoResp = user.UserInfoResp
UserItem = user.UserItem
UserListRequest = user.UserListRequest
UserListResponse = user.UserListResponse
Auth interface { Auth interface {
// 注册接口 // 注册接口

View File

@ -50,6 +50,9 @@ type (
UpdateWalletResponse = user.UpdateWalletResponse UpdateWalletResponse = user.UpdateWalletResponse
UserInfoReq = user.UserInfoReq UserInfoReq = user.UserInfoReq
UserInfoResp = user.UserInfoResp UserInfoResp = user.UserInfoResp
UserItem = user.UserItem
UserListRequest = user.UserListRequest
UserListResponse = user.UserListResponse
Enterprise interface { Enterprise interface {
// 获取待审核企业列表 // 获取待审核企业列表

View File

@ -50,12 +50,16 @@ type (
UpdateWalletResponse = user.UpdateWalletResponse UpdateWalletResponse = user.UpdateWalletResponse
UserInfoReq = user.UserInfoReq UserInfoReq = user.UserInfoReq
UserInfoResp = user.UserInfoResp UserInfoResp = user.UserInfoResp
UserItem = user.UserItem
UserListRequest = user.UserListRequest
UserListResponse = user.UserListResponse
User interface { User interface {
// 获取用户信息 // 获取用户信息
UserInfo(ctx context.Context, in *UserInfoReq, opts ...grpc.CallOption) (*UserInfoResp, error) UserInfo(ctx context.Context, in *UserInfoReq, opts ...grpc.CallOption) (*UserInfoResp, error)
GetUserInfo(ctx context.Context, in *UserInfoReq, opts ...grpc.CallOption) (*GetUserInfoResp, error) GetUserInfo(ctx context.Context, in *UserInfoReq, opts ...grpc.CallOption) (*GetUserInfoResp, error)
GetEnterpriseAuthStatus(ctx context.Context, in *GetEnterpriseAuthStatusReq, opts ...grpc.CallOption) (*GetEnterpriseAuthStatusResp, error) GetEnterpriseAuthStatus(ctx context.Context, in *GetEnterpriseAuthStatusReq, opts ...grpc.CallOption) (*GetEnterpriseAuthStatusResp, error)
GetUserList(ctx context.Context, in *UserListRequest, opts ...grpc.CallOption) (*UserListResponse, error)
} }
defaultUser struct { defaultUser struct {
@ -84,3 +88,8 @@ func (m *defaultUser) GetEnterpriseAuthStatus(ctx context.Context, in *GetEnterp
client := user.NewUserClient(m.cli.Conn()) client := user.NewUserClient(m.cli.Conn())
return client.GetEnterpriseAuthStatus(ctx, in, opts...) return client.GetEnterpriseAuthStatus(ctx, in, opts...)
} }
func (m *defaultUser) GetUserList(ctx context.Context, in *UserListRequest, opts ...grpc.CallOption) (*UserListResponse, error) {
client := user.NewUserClient(m.cli.Conn())
return client.GetUserList(ctx, in, opts...)
}

View File

@ -50,6 +50,9 @@ type (
UpdateWalletResponse = user.UpdateWalletResponse UpdateWalletResponse = user.UpdateWalletResponse
UserInfoReq = user.UserInfoReq UserInfoReq = user.UserInfoReq
UserInfoResp = user.UserInfoResp UserInfoResp = user.UserInfoResp
UserItem = user.UserItem
UserListRequest = user.UserListRequest
UserListResponse = user.UserListResponse
WalletService interface { WalletService interface {
// 修改钱包余额 // 修改钱包余额

View File

@ -0,0 +1,63 @@
package userlogic
import (
"context"
"tianyuan-api/apps/user/internal/svc"
"tianyuan-api/apps/user/user"
"github.com/zeromicro/go-zero/core/logx"
)
type GetUserListLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserListLogic {
return &GetUserListLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetUserListLogic) GetUserList(in *user.UserListRequest) (*user.UserListResponse, error) {
list, total, err := l.svcCtx.UserModel.FindUserPageList(l.ctx, in.Page, in.PageSize)
if err != nil {
return nil, err
}
userIds := make([]int64, len(list))
for i, userItem := range list {
userIds[i] = userItem.Id
}
walletMap, err := l.svcCtx.WalletsModel.FindWalletsByUserIds(l.ctx, userIds)
if err != nil {
return nil, err
}
var userList []*user.UserItem
for _, userItem := range list {
balance := float64(0)
if wallet, ok := walletMap[userItem.Id]; ok {
balance = wallet.Balance
}
userList = append(userList, &user.UserItem{
Id: userItem.Id,
Username: userItem.Username,
Phone: userItem.Phone,
Disable: userItem.Disable,
QuotaExceeded: userItem.QuotaExceeded,
Balance: balance,
CreatedAt: userItem.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: userItem.UpdatedAt.Format("2006-01-02 15:04:05"),
})
}
return &user.UserListResponse{
List: userList,
Total: total,
}, nil
}

View File

@ -6,6 +6,7 @@ import (
"errors" "errors"
"github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stores/sqlx"
"tianyuan-api/apps/sentinel/client/product" "tianyuan-api/apps/sentinel/client/product"
"tianyuan-api/apps/sentinel/sentinel"
"tianyuan-api/apps/user/internal/model" "tianyuan-api/apps/user/internal/model"
"time" "time"
@ -40,7 +41,13 @@ func (l *UpdateWalletLogic) UpdateWallet(in *user.UpdateWalletRequest) (*user.Up
if getProductByCodeErr != nil { if getProductByCodeErr != nil {
return nil, getProductByCodeErr return nil, getProductByCodeErr
} }
userProduct, getUserProductErr := l.svcCtx.UserProductRpc.GetUserProduct(l.ctx, &sentinel.UserProuctRequest{
UserId: in.UserId,
ProductId: consumeProduct.Id,
})
if getUserProductErr != nil {
return nil, getUserProductErr
}
// 检查是否已经扣款 // 检查是否已经扣款
deduction, FindOneByTransactionIdErr := l.svcCtx.DeductionsModel.FindOneByTransactionId(l.ctx, in.TransactionId) deduction, FindOneByTransactionIdErr := l.svcCtx.DeductionsModel.FindOneByTransactionId(l.ctx, in.TransactionId)
if FindOneByTransactionIdErr != nil { if FindOneByTransactionIdErr != nil {
@ -59,7 +66,7 @@ func (l *UpdateWalletLogic) UpdateWallet(in *user.UpdateWalletRequest) (*user.Up
var err error var err error
// 尝试多次更新余额(用于乐观锁) // 尝试多次更新余额(用于乐观锁)
for i := 0; i < maxRetries; i++ { for i := 0; i < maxRetries; i++ {
err = l.svcCtx.WalletsModel.UpdateBalance(session, l.ctx, in.UserId, -consumeProduct.ProductPrice) err = l.svcCtx.WalletsModel.UpdateBalance(session, l.ctx, in.UserId, -userProduct.ProductPrice)
if err == nil { if err == nil {
// 成功,退出循环 // 成功,退出循环
break break
@ -82,7 +89,7 @@ func (l *UpdateWalletLogic) UpdateWallet(in *user.UpdateWalletRequest) (*user.Up
_, err = l.svcCtx.DeductionsModel.InsertDeductionsTrans(ctx, &model.Deductions{ _, err = l.svcCtx.DeductionsModel.InsertDeductionsTrans(ctx, &model.Deductions{
TransactionId: in.TransactionId, TransactionId: in.TransactionId,
UserId: in.UserId, UserId: in.UserId,
Amount: consumeProduct.ProductPrice, Amount: userProduct.ProductPrice,
}, session) }, session)
if err != nil { if err != nil {
return err return err

View File

@ -18,6 +18,7 @@ type (
usersModel usersModel
UpdateUserTrans(ctx context.Context, user *Users, session sqlx.Session) (sql.Result, error) UpdateUserTrans(ctx context.Context, user *Users, session sqlx.Session) (sql.Result, error)
FindOneTrans(ctx context.Context, userId int64, session sqlx.Session) (*Users, error) FindOneTrans(ctx context.Context, userId int64, session sqlx.Session) (*Users, error)
FindUserPageList(ctx context.Context, page, pageSize int64) ([]Users, int64, error)
} }
customUsersModel struct { customUsersModel struct {
@ -76,3 +77,23 @@ func (m *defaultUsersModel) FindOneTrans(ctx context.Context, userId int64, sess
// 返回查询结果 // 返回查询结果
return &user, nil return &user, nil
} }
func (m *customUsersModel) FindUserPageList(ctx context.Context, page, pageSize int64) ([]Users, int64, error) {
offset := (page - 1) * pageSize
var users []Users
query := fmt.Sprintf("SELECT * FROM %s ORDER BY created_at DESC LIMIT ?,?", m.table)
err := m.QueryRowsNoCacheCtx(ctx, &users, query, offset, pageSize)
if err != nil {
return nil, 0, err
}
// 查询总数量
var total int64
countQuery := fmt.Sprintf("SELECT COUNT(*) FROM %s", m.table)
err = m.QueryRowNoCacheCtx(ctx, &total, countQuery)
if err != nil {
return nil, 0, err
}
return users, total, nil
}

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stores/sqlx"
"strings"
) )
var _ WalletsModel = (*customWalletsModel)(nil) var _ WalletsModel = (*customWalletsModel)(nil)
@ -19,6 +20,7 @@ type (
InsertWalletsTrans(ctx context.Context, wallets *Wallets, session sqlx.Session) (sql.Result, error) InsertWalletsTrans(ctx context.Context, wallets *Wallets, session sqlx.Session) (sql.Result, error)
UpdateBalance(session sqlx.Session, ctx context.Context, userId int64, amount float64) error UpdateBalance(session sqlx.Session, ctx context.Context, userId int64, amount float64) error
TransCtx(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error TransCtx(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error
FindWalletsByUserIds(ctx context.Context, userIds []int64) (map[int64]*Wallets, error)
} }
customWalletsModel struct { customWalletsModel struct {
@ -88,3 +90,36 @@ func (m *customWalletsModel) InsertWalletsTrans(ctx context.Context, wallets *Wa
return ret, err return ret, err
} }
func (m *customWalletsModel) FindWalletsByUserIds(ctx context.Context, userIds []int64) (map[int64]*Wallets, error) {
if len(userIds) == 0 {
return make(map[int64]*Wallets), nil
}
queryBuilder := strings.Builder{}
queryBuilder.WriteString(fmt.Sprintf("SELECT user_id, balance FROM %s WHERE user_id IN (", m.table))
placeholders := make([]string, len(userIds))
args := make([]interface{}, len(userIds))
for i, userId := range userIds {
placeholders[i] = "?"
args[i] = userId
}
queryBuilder.WriteString(strings.Join(placeholders, ","))
queryBuilder.WriteString(")")
query := queryBuilder.String()
var wallets []*Wallets
err := m.QueryRowNoCacheCtx(ctx, &wallets, query, args...)
if err != nil {
return nil, err
}
walletMap := make(map[int64]*Wallets)
for _, wallet := range wallets {
walletMap[wallet.UserId] = wallet
}
return walletMap, nil
}

View File

@ -38,3 +38,8 @@ func (s *UserServer) GetEnterpriseAuthStatus(ctx context.Context, in *user.GetEn
l := userlogic.NewGetEnterpriseAuthStatusLogic(ctx, s.svcCtx) l := userlogic.NewGetEnterpriseAuthStatusLogic(ctx, s.svcCtx)
return l.GetEnterpriseAuthStatus(in) return l.GetEnterpriseAuthStatus(in)
} }
func (s *UserServer) GetUserList(ctx context.Context, in *user.UserListRequest) (*user.UserListResponse, error) {
l := userlogic.NewGetUserListLogic(ctx, s.svcCtx)
return l.GetUserList(in)
}

View File

@ -23,6 +23,7 @@ type ServiceContext struct {
UserConfigModel model.UserConfigModel UserConfigModel model.UserConfigModel
SecretRpc sentinel.SecretClient SecretRpc sentinel.SecretClient
ProductRpc sentinel.ProductClient ProductRpc sentinel.ProductClient
UserProductRpc sentinel.UserProductClient
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
@ -35,7 +36,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
// 初始化 SecretRpc 和 ProductRpc // 初始化 SecretRpc 和 ProductRpc
var secretRpc sentinel.SecretClient var secretRpc sentinel.SecretClient
var productRpc sentinel.ProductClient var productRpc sentinel.ProductClient
var userProductRpc sentinel.UserProductClient
// 捕获RPC初始化时的错误但不影响服务启动 // 捕获RPC初始化时的错误但不影响服务启动
secretClient, err := zrpc.NewClient(c.SentinelRpc) secretClient, err := zrpc.NewClient(c.SentinelRpc)
if err != nil { if err != nil {
@ -49,6 +50,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
logx.Errorf("Failed to connect to ProductRpc: %v", err) logx.Errorf("Failed to connect to ProductRpc: %v", err)
} else { } else {
productRpc = sentinel.NewProductClient(productClient.Conn()) productRpc = sentinel.NewProductClient(productClient.Conn())
userProductRpc = sentinel.NewUserProductClient(productClient.Conn())
} }
// 使用 MustNewRedis 来初始化 Redis 客户端 // 使用 MustNewRedis 来初始化 Redis 客户端
@ -66,5 +68,6 @@ func NewServiceContext(c config.Config) *ServiceContext {
RechargeModel: model.NewRechargeModel(db, c.CacheRedis), RechargeModel: model.NewRechargeModel(db, c.CacheRedis),
SecretRpc: secretRpc, // 捕获连接错误后,继续运行 SecretRpc: secretRpc, // 捕获连接错误后,继续运行
ProductRpc: productRpc, // 捕获连接错误后,继续运行 ProductRpc: productRpc, // 捕获连接错误后,继续运行
UserProductRpc: userProductRpc,
} }
} }

View File

@ -113,7 +113,7 @@ message UserInfoResp{
string enterpriseName = 6; string enterpriseName = 6;
string creditCode = 7; string creditCode = 7;
string legalPerson = 8; string legalPerson = 8;
double balance= 9; double balance = 9;
} }
message GetUserInfoResp{ message GetUserInfoResp{
string username = 1; string username = 1;
@ -128,6 +128,27 @@ message GetEnterpriseAuthStatusReq {
message GetEnterpriseAuthStatusResp { message GetEnterpriseAuthStatusResp {
bool isAuth = 1; bool isAuth = 1;
} }
message UserListRequest {
int64 page = 1; //
int64 page_size = 2; //
}
message UserListResponse {
repeated UserItem list = 1;
int64 total = 2;
}
message UserItem {
int64 id = 1; // ID
string username = 2;
string phone = 3;
int64 disable = 4;
int64 quotaExceeded = 5;
double balance = 6;
string created_at = 7; //
string updated_at = 8; //
}
service User { service User {
// //
rpc UserInfo(UserInfoReq) returns (UserInfoResp); rpc UserInfo(UserInfoReq) returns (UserInfoResp);
@ -135,6 +156,9 @@ service User {
rpc GetUserInfo(UserInfoReq) returns (GetUserInfoResp); rpc GetUserInfo(UserInfoReq) returns (GetUserInfoResp);
rpc GetEnterpriseAuthStatus(GetEnterpriseAuthStatusReq) returns (GetEnterpriseAuthStatusResp); rpc GetEnterpriseAuthStatus(GetEnterpriseAuthStatusReq) returns (GetEnterpriseAuthStatusResp);
rpc GetUserList(UserListRequest) returns (UserListResponse);
} }

File diff suppressed because it is too large Load Diff

View File

@ -376,6 +376,7 @@ const (
User_UserInfo_FullMethodName = "/User/UserInfo" User_UserInfo_FullMethodName = "/User/UserInfo"
User_GetUserInfo_FullMethodName = "/User/GetUserInfo" User_GetUserInfo_FullMethodName = "/User/GetUserInfo"
User_GetEnterpriseAuthStatus_FullMethodName = "/User/GetEnterpriseAuthStatus" User_GetEnterpriseAuthStatus_FullMethodName = "/User/GetEnterpriseAuthStatus"
User_GetUserList_FullMethodName = "/User/GetUserList"
) )
// UserClient is the client API for User service. // UserClient is the client API for User service.
@ -386,6 +387,7 @@ type UserClient interface {
UserInfo(ctx context.Context, in *UserInfoReq, opts ...grpc.CallOption) (*UserInfoResp, error) UserInfo(ctx context.Context, in *UserInfoReq, opts ...grpc.CallOption) (*UserInfoResp, error)
GetUserInfo(ctx context.Context, in *UserInfoReq, opts ...grpc.CallOption) (*GetUserInfoResp, error) GetUserInfo(ctx context.Context, in *UserInfoReq, opts ...grpc.CallOption) (*GetUserInfoResp, error)
GetEnterpriseAuthStatus(ctx context.Context, in *GetEnterpriseAuthStatusReq, opts ...grpc.CallOption) (*GetEnterpriseAuthStatusResp, error) GetEnterpriseAuthStatus(ctx context.Context, in *GetEnterpriseAuthStatusReq, opts ...grpc.CallOption) (*GetEnterpriseAuthStatusResp, error)
GetUserList(ctx context.Context, in *UserListRequest, opts ...grpc.CallOption) (*UserListResponse, error)
} }
type userClient struct { type userClient struct {
@ -426,6 +428,16 @@ func (c *userClient) GetEnterpriseAuthStatus(ctx context.Context, in *GetEnterpr
return out, nil return out, nil
} }
func (c *userClient) GetUserList(ctx context.Context, in *UserListRequest, opts ...grpc.CallOption) (*UserListResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UserListResponse)
err := c.cc.Invoke(ctx, User_GetUserList_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// UserServer is the server API for User service. // UserServer is the server API for User service.
// All implementations must embed UnimplementedUserServer // All implementations must embed UnimplementedUserServer
// for forward compatibility // for forward compatibility
@ -434,6 +446,7 @@ type UserServer interface {
UserInfo(context.Context, *UserInfoReq) (*UserInfoResp, error) UserInfo(context.Context, *UserInfoReq) (*UserInfoResp, error)
GetUserInfo(context.Context, *UserInfoReq) (*GetUserInfoResp, error) GetUserInfo(context.Context, *UserInfoReq) (*GetUserInfoResp, error)
GetEnterpriseAuthStatus(context.Context, *GetEnterpriseAuthStatusReq) (*GetEnterpriseAuthStatusResp, error) GetEnterpriseAuthStatus(context.Context, *GetEnterpriseAuthStatusReq) (*GetEnterpriseAuthStatusResp, error)
GetUserList(context.Context, *UserListRequest) (*UserListResponse, error)
mustEmbedUnimplementedUserServer() mustEmbedUnimplementedUserServer()
} }
@ -450,6 +463,9 @@ func (UnimplementedUserServer) GetUserInfo(context.Context, *UserInfoReq) (*GetU
func (UnimplementedUserServer) GetEnterpriseAuthStatus(context.Context, *GetEnterpriseAuthStatusReq) (*GetEnterpriseAuthStatusResp, error) { func (UnimplementedUserServer) GetEnterpriseAuthStatus(context.Context, *GetEnterpriseAuthStatusReq) (*GetEnterpriseAuthStatusResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetEnterpriseAuthStatus not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetEnterpriseAuthStatus not implemented")
} }
func (UnimplementedUserServer) GetUserList(context.Context, *UserListRequest) (*UserListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserList not implemented")
}
func (UnimplementedUserServer) mustEmbedUnimplementedUserServer() {} func (UnimplementedUserServer) mustEmbedUnimplementedUserServer() {}
// UnsafeUserServer may be embedded to opt out of forward compatibility for this service. // UnsafeUserServer may be embedded to opt out of forward compatibility for this service.
@ -517,6 +533,24 @@ func _User_GetEnterpriseAuthStatus_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _User_GetUserList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UserListRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserServer).GetUserList(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: User_GetUserList_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServer).GetUserList(ctx, req.(*UserListRequest))
}
return interceptor(ctx, in, info, handler)
}
// User_ServiceDesc is the grpc.ServiceDesc for User service. // User_ServiceDesc is the grpc.ServiceDesc for User service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@ -536,6 +570,10 @@ var User_ServiceDesc = grpc.ServiceDesc{
MethodName: "GetEnterpriseAuthStatus", MethodName: "GetEnterpriseAuthStatus",
Handler: _User_GetEnterpriseAuthStatus_Handler, Handler: _User_GetEnterpriseAuthStatus_Handler,
}, },
{
MethodName: "GetUserList",
Handler: _User_GetUserList_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "user.proto", Metadata: "user.proto",