Merge branch 'develop' of git.ailuowan.com:zzw/lone-services into develop
CI / changes (push) Successful in 13s
CI / docker-bff (push) Successful in 26s
CI / docker-product (push) Successful in 19s
CI / docker-admin (push) Successful in 24s
CI / docker-user (push) Successful in 18s
CI / docker-ad (push) Successful in 16s
CI / docker-chore (push) Successful in 24s
CI / docker-express (push) Successful in 17s
CI / docker-sale (push) Successful in 22s

This commit is contained in:
zzw
2026-08-31 11:10:24 +08:00
18 changed files with 637 additions and 173 deletions
+34 -23
View File
@@ -14,29 +14,32 @@ import (
)
type (
AdminEditRequest = admin.AdminEditRequest
AdminEmptyRequest = admin.AdminEmptyRequest
AdminInfoRequest = admin.AdminInfoRequest
AdminItemsRequest = admin.AdminItemsRequest
AuthorityEditRequest = admin.AuthorityEditRequest
AuthorityItemsRequest = admin.AuthorityItemsRequest
AuthorityNameRequest = admin.AuthorityNameRequest
AuthoritySortRequest = admin.AuthoritySortRequest
InfoRequest = admin.InfoRequest
LoginKickedOutRequest = admin.LoginKickedOutRequest
LoginRequest = admin.LoginRequest
OwnPasswordRequest = admin.OwnPasswordRequest
PasswordRequest = admin.PasswordRequest
Response = admin.Response
RoleEditRequest = admin.RoleEditRequest
RoleItemsRequest = admin.RoleItemsRequest
RoleNameRequest = admin.RoleNameRequest
RoleRuleRequest = admin.RoleRuleRequest
RoutesRequest = admin.RoutesRequest
ServiceEditRequest = admin.ServiceEditRequest
ServiceItemsRequest = admin.ServiceItemsRequest
ServiceNameRequest = admin.ServiceNameRequest
StatusRequest = admin.StatusRequest
AdminEditRequest = admin.AdminEditRequest
AdminEmptyRequest = admin.AdminEmptyRequest
AdminInfoRequest = admin.AdminInfoRequest
AdminItemsRequest = admin.AdminItemsRequest
AdminNamesByIdsRequest = admin.AdminNamesByIdsRequest
AdminNamesByIdsResponse = admin.AdminNamesByIdsResponse
AuthorityEditRequest = admin.AuthorityEditRequest
AuthorityItemsRequest = admin.AuthorityItemsRequest
AuthorityNameRequest = admin.AuthorityNameRequest
AuthoritySortRequest = admin.AuthoritySortRequest
InfoRequest = admin.InfoRequest
LoginKickedOutRequest = admin.LoginKickedOutRequest
LoginRequest = admin.LoginRequest
NamesItem = admin.NamesItem
OwnPasswordRequest = admin.OwnPasswordRequest
PasswordRequest = admin.PasswordRequest
Response = admin.Response
RoleEditRequest = admin.RoleEditRequest
RoleItemsRequest = admin.RoleItemsRequest
RoleNameRequest = admin.RoleNameRequest
RoleRuleRequest = admin.RoleRuleRequest
RoutesRequest = admin.RoutesRequest
ServiceEditRequest = admin.ServiceEditRequest
ServiceItemsRequest = admin.ServiceItemsRequest
ServiceNameRequest = admin.ServiceNameRequest
StatusRequest = admin.StatusRequest
Admin interface {
AdminEdit(ctx context.Context, in *AdminEditRequest, opts ...grpc.CallOption) (*Response, error)
@@ -70,6 +73,8 @@ type (
RoleItems(ctx context.Context, in *RoleItemsRequest, opts ...grpc.CallOption) (*Response, error)
RoleStatus(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*Response, error)
RoleRule(ctx context.Context, in *RoleRuleRequest, opts ...grpc.CallOption) (*Response, error)
// 传入IDS []int64,返回[]NamesItem{id int64,name string}
AdminNamesByIds(ctx context.Context, in *AdminNamesByIdsRequest, opts ...grpc.CallOption) (*AdminNamesByIdsResponse, error)
}
defaultAdmin struct {
@@ -237,3 +242,9 @@ func (m *defaultAdmin) RoleRule(ctx context.Context, in *RoleRuleRequest, opts .
client := admin.NewAdminClient(m.cli.Conn())
return client.RoleRule(ctx, in, opts...)
}
// 传入IDS []int64,返回[]NamesItem{id int64,name string}
func (m *defaultAdmin) AdminNamesByIds(ctx context.Context, in *AdminNamesByIdsRequest, opts ...grpc.CallOption) (*AdminNamesByIdsResponse, error) {
client := admin.NewAdminClient(m.cli.Conn())
return client.AdminNamesByIds(ctx, in, opts...)
}
+8
View File
@@ -2,6 +2,11 @@ package dao
import "lone-services/pkg/utils"
const (
AdminTypeAdmin = 2
AdminTypeSale = 1
)
// Admin 公司内部人员表
type Admin struct {
Id int64 `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT;comment:ID" json:"id"`
@@ -53,6 +58,9 @@ type AdminInfo struct {
Type uint8 `json:"type" gorm:"type"` // 1:销售,2:管理员
SaleId int64 `json:"sale_id" gorm:"sale_id"` // 销售ID
FailNumber int `gorm:"column:fail_number;type:tinyint(2);default:0;comment:连续登录失败次数" json:"fail_number"`
SaleName string `json:"sale_name" gorm:"-"`
GroupId int64 `json:"group_id" gorm:"-"`
GroupName string `json:"group_name" gorm:"-"`
}
type AdminInfoRet struct {
+15 -9
View File
@@ -3,15 +3,21 @@ package dao
import "lone-services/pkg/utils"
type JwtInfo struct {
Id int64 `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT" json:"id"`
Avatar string `gorm:"column:avatar;type:varchar(255);comment:头像" json:"avatar"`
Name string `gorm:"column:name;type:varchar(30);comment:真实姓名;NOT NULL" json:"name"`
Phone string `gorm:"column:phone;type:char(12);comment:电话" json:"phone"`
Email string `gorm:"column:email;type:varchar(255);comment:邮箱" json:"email"`
LastTime utils.CustomTime `gorm:"column:last_time;type:datetime;comment:最后一次登录时间" json:"last_time"`
Time int `json:"time"`
Roles []JwtInfoServices `json:"roles"`
Refresh string `json:"refresh"`
Id int64 `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT" json:"id"`
Avatar string `gorm:"column:avatar;type:varchar(255);comment:头像" json:"avatar"`
Name string `gorm:"column:name;type:varchar(30);comment:真实姓名;NOT NULL" json:"name"`
Phone string `gorm:"column:phone;type:char(12);comment:电话" json:"phone"`
Email string `gorm:"column:email;type:varchar(255);comment:邮箱" json:"email"`
LastTime utils.CustomTime `gorm:"column:last_time;type:datetime;comment:最后一次登录时间" json:"last_time"`
Time int `json:"time"`
Roles []JwtInfoServices `json:"roles"`
Refresh string `json:"refresh"`
Type uint8 `json:"type" gorm:"type"` // 销售ID
SaleId int64 `json:"sale_id" gorm:"sale_id"` // 销售ID
SaleMobile string `json:"sale_mobile" gorm:"-"`
SaleName string `json:"sale_name" gorm:"-"`
GroupId int64 `json:"group_id" gorm:"-"`
GroupName string `json:"group_name" gorm:"-"`
}
type JwtOutInfo struct {
@@ -0,0 +1,73 @@
package logic
import (
"context"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
"lone-services/pkg/validate"
"lone-services/services/admin/internal/dao"
"lone-services/services/admin/internal/model"
"lone-services/services/admin/validator"
"strconv"
"lone-services/rpc/admin/pb"
"lone-services/services/admin/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type AdminNamesByIdsLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewAdminNamesByIdsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminNamesByIdsLogic {
return &AdminNamesByIdsLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// 传入IDS []int64,返回[]NamesItem{id int64,name string}
func (l *AdminNamesByIdsLogic) AdminNamesByIds(in *admin.AdminNamesByIdsRequest) (*admin.AdminNamesByIdsResponse, error) {
var req validator.AdminNamesByIdsValidator
if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty {
return nil, status.Error(codes.InvalidArgument, msg)
}
ids := make([]string, utils.NumberZero, len(in.Ids))
for _, id := range in.Ids {
ids = append(ids, strconv.FormatInt(id, utils.NumberTen))
}
w := modelbase.Params{
In: map[string][]string{"id in ?": ids},
Eq: map[string]string{"status": utils.StringStatusOk},
}
var items []dao.AdminNames
err := model.AdminModel{}.Init().Items(w, &items)
if err != nil {
l.Logger.Error(err)
return nil, status.Error(codes.Code(utils.Fail.Code), utils.Fail.Msg)
}
if len(items) < utils.NumberOne {
return nil, status.Error(codes.Code(utils.ErrorNotFund.Code), utils.ErrorNotFund.Msg)
}
var result []*admin.NamesItem
for item := range items {
mobile, dErr := utils.DecryptPhone(items[item].Phone)
if dErr == nil {
items[item].Phone = mobile
}
result = append(result, &admin.NamesItem{
Id: int64(items[item].Id),
Name: items[item].Name,
})
}
return &admin.AdminNamesByIdsResponse{Items: result}, nil
}
@@ -5,6 +5,7 @@ import (
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
admin "lone-services/rpc/admin/pb"
sale "lone-services/rpc/sale/pb"
"lone-services/services/admin/internal/dao"
"lone-services/services/admin/internal/model"
"lone-services/services/admin/internal/svc"
@@ -57,6 +58,24 @@ func (l *AdminInfoLogic) AdminInfo(in *admin.AdminInfoRequest) (*admin.Response,
roles = append(roles, r)
}
}
if info.Type == dao.AdminTypeSale {
cli, err := svc.GetRpcClient(l.svcCtx.SaleSvcName)
if err != nil {
logx.Errorf("get rpc client err: %v", err)
return l.fail(utils.ErrorInternalServer)
}
saleClient := sale.NewSaleClient(cli.Conn())
saleInfo, err := saleClient.InfoInternal(context.Background(), &sale.InfoReq{Id: info.SaleId})
if err != nil {
logx.Errorf("get sale err: %v", err)
return l.fail(utils.ErrorInternalServer)
}
info.GroupName = saleInfo.Group.Name
info.GroupId = saleInfo.GroupId
info.SaleName = saleInfo.Name
}
retData := dao.AdminInfoRet{
AdminInfo: info,
Roles: roles,
@@ -6,6 +6,7 @@ import (
"lone-services/pkg/redis"
"lone-services/pkg/utils"
admin "lone-services/rpc/admin/pb"
sale "lone-services/rpc/sale/pb"
"lone-services/services/admin/internal/dao"
"lone-services/services/admin/internal/model"
"lone-services/services/admin/internal/svc"
@@ -69,10 +70,31 @@ func (l *LoginLogic) Login(in *admin.LoginRequest) (*admin.Response, error) {
Id: info.Id,
Name: info.Name,
Email: info.Email,
Type: info.Type,
Avatar: info.Avatar,
LastTime: utils.Now(),
}
if info.Type == dao.AdminTypeSale {
cli, err := svc.GetRpcClient(l.svcCtx.SaleSvcName)
if err != nil {
logx.Errorf("get rpc client err: %v", err)
return l.fail(utils.ErrorInternalServer)
}
saleClient := sale.NewSaleClient(cli.Conn())
saleInfo, err := saleClient.InfoInternal(context.Background(), &sale.InfoReq{Id: info.SaleId})
if err != nil {
logx.Errorf("get sale err: %v", err)
return l.fail(utils.ErrorInternalServer)
}
data.GroupName = saleInfo.Group.Name
data.GroupId = saleInfo.GroupId
data.SaleId = saleInfo.Id
data.SaleName = saleInfo.Name
data.SaleMobile = saleInfo.OriginMobile
}
data.Phone, _ = utils.DecryptPhone(info.Phone)
retData := dao.Token{
@@ -177,3 +177,9 @@ func (s *AdminServer) RoleRule(ctx context.Context, in *admin.RoleRuleRequest) (
l := logic.NewRoleRuleLogic(ctx, s.svcCtx)
return l.RoleRule(in)
}
// 传入IDS []int64,返回[]NamesItem{id int64,name string}
func (s *AdminServer) AdminNamesByIds(ctx context.Context, in *admin.AdminNamesByIdsRequest) (*admin.AdminNamesByIdsResponse, error) {
l := logic.NewAdminNamesByIdsLogic(ctx, s.svcCtx)
return l.AdminNamesByIds(in)
}
+77 -3
View File
@@ -1,22 +1,96 @@
package svc
import (
"fmt"
"lone-services/pkg/discovery"
"lone-services/pkg/utils"
"lone-services/services/admin/internal/config"
"net"
"strconv"
"sync"
"time"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/zrpc"
"gorm.io/gorm"
)
type rpcClientCacheEntry struct {
cli zrpc.Client
target string
expireAt time.Time
}
const rpcClientCacheTTL = 30 * time.Second //缓存过期时间
var (
rpcCacheLock sync.Mutex
rpcCache = make(map[string]*rpcClientCacheEntry)
)
func GetRpcClient(serviceName string) (zrpc.Client, error) {
if serviceName == utils.StringEmpty {
err := fmt.Errorf("rpc serviceName is empty")
logx.Error(err)
return nil, err
}
cacheKey := serviceName
rpcCacheLock.Lock()
entry, ok := rpcCache[cacheKey]
if ok && time.Now().Before(entry.expireAt) {
rpcCacheLock.Unlock()
return entry.cli, nil
}
delete(rpcCache, cacheKey)
rpcCacheLock.Unlock()
inst, err := discovery.Pick(serviceName)
if err != nil {
err = fmt.Errorf("discovery pick %s failed: %w", serviceName, err)
logx.Error(err)
return nil, err
}
target := net.JoinHostPort(inst.IP, strconv.FormatUint(inst.Port, utils.NumberTen))
cli := zrpc.MustNewClient(zrpc.RpcClientConf{
Target: target,
Timeout: utils.RpcTimeOut, //rpc调用超时5s
})
rpcCacheLock.Lock()
rpcCache[cacheKey] = &rpcClientCacheEntry{
cli: cli,
target: target,
expireAt: time.Now().Add(rpcClientCacheTTL),
}
rpcCacheLock.Unlock()
return cli, nil
}
type ServiceContext struct {
Config config.Config
DB *gorm.DB
Prefix string
SaleSvcName string //服务名
}
func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
//启动仅读取配置,不建立rpc连接 多个服务就多个
SaleSvc := utils.GetConfigString("services.sale")
if SaleSvc == utils.StringEmpty {
logx.Error("config services.sale empty")
}
return &ServiceContext{
Config: c,
DB: db,
Prefix: utils.GetConfigString("mysql.prefix"),
Config: c,
DB: db,
Prefix: utils.GetConfigString("mysql.prefix"),
SaleSvcName: SaleSvc,
}
}
+11
View File
@@ -135,3 +135,14 @@ func (p LoginKickedOutValidator) GetMessage() validate.ValidatorMessages {
"Id.required": "ID不能为空",
}
}
type AdminNamesByIdsValidator struct {
Ids []int64 `validate:"required"`
}
// GetMessage 提示消息
func (p AdminNamesByIdsValidator) GetMessage() validate.ValidatorMessages {
return validate.ValidatorMessages{
"Ids.required": "ID不能为空",
}
}
@@ -4,6 +4,7 @@ import (
"context"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
product "lone-services/rpc/product/pb"
"lone-services/services/order/internal/dao"
"lone-services/services/order/internal/model"
"lone-services/services/order/validator"
@@ -68,7 +69,8 @@ func (l *OrderCreateLogic) OrderCreate(in *order.AdminCreateOrderRequest) (*orde
ww := modelbase.Params{
Eq: map[string]string{
"type": strconv.Itoa(dao.OrderTypeStore),
"type": strconv.Itoa(dao.OrderTypeStore),
"store_id": strconv.FormatInt(adminInfo.ID, utils.NumberTen),
},
}
data.StoreId = int(adminInfo.ID)
@@ -79,7 +81,6 @@ func (l *OrderCreateLogic) OrderCreate(in *order.AdminCreateOrderRequest) (*orde
data.SaleProvince = int(adminInfo.SaleProvince)
data.CreateType = dao.OrderTypeStore
data.Type = dao.OrderTypeStore
ww.Eq["store_id"] = strconv.FormatInt(adminInfo.ID, utils.NumberTen)
data.OrderSn = svc.GetOrderSn(strconv.Itoa(dao.OrderTypeStore), adminInfo.ID)
var cart dao.Cart
@@ -96,6 +97,8 @@ func (l *OrderCreateLogic) OrderCreate(in *order.AdminCreateOrderRequest) (*orde
var totalPrice float64
errData := make(map[int64]int64)
productItems := []dao.OrderProductCreate{}
NumItems := make([]*product.NumberItem, utils.NumberZero)
for _, item := range products.Items {
if buyNum, ok := ids[item.Id]; ok {
if buyNum > int64(item.Number) {
@@ -103,6 +106,8 @@ func (l *OrderCreateLogic) OrderCreate(in *order.AdminCreateOrderRequest) (*orde
return l.out(utils.Fail,
item.Name+"购买数量超出库存,目前可以够买:"+strconv.Itoa(int(item.Number)))
} else {
numItem := &product.NumberItem{Id: item.Id, Number: uint32(buyNum)}
NumItems = append(NumItems, numItem)
keys = append(keys, strconv.Itoa(int(item.Id)))
totalPrice += item.Price * float64(buyNum)
productItems = append(productItems, dao.OrderProductCreate{
@@ -143,20 +148,19 @@ func (l *OrderCreateLogic) OrderCreate(in *order.AdminCreateOrderRequest) (*orde
return l.fail(utils.Fail)
}
//TODO 扣库存接口
//cli, err := svc.GetRpcClient(l.svcCtx.ProductSvcName)
//if err != nil {
// mobileObj.Rollback()
// return l.fail(utils.Fail)
//}
cli, err := svc.GetRpcClient(l.svcCtx.ProductSvcName)
if err != nil {
mobileObj.Rollback()
return l.fail(utils.Fail)
}
//productClient := product.NewProductClient(cli.Conn())
//_, err = productClient.Number(l.ctx, &product.NumberReq{Id: item.Id, Type: utils.NumberOne, Number: buyNum})
//if err != nil {
// mobileObj.Rollback()
// logx.Errorf("get products err: %v", err)
// return l.fail(utils.Fail, "产品库存不足")
//}
productClient := product.NewProductClient(cli.Conn())
_, err = productClient.NumberItems(l.ctx, &product.NumberItemsReq{Type: utils.NumberOne, Items: NumItems})
if err != nil {
mobileObj.Rollback()
logx.Errorf("get products err: %v", err)
return l.out(utils.Fail, "产品库存不足")
}
mobileObj.Commit()
+17 -13
View File
@@ -4,6 +4,7 @@ import (
"context"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
product "lone-services/rpc/product/pb"
"lone-services/services/order/internal/dao"
"lone-services/services/order/internal/model"
"lone-services/services/order/validator"
@@ -124,6 +125,8 @@ func (l *WebCreateLogic) WebCreate(in *order.CreateOrderRequest) (*order.Respons
var totalPrice float64
errData := make(map[int64]int64)
productItems := []dao.OrderProductCreate{}
NumItems := make([]*product.NumberItem, utils.NumberZero)
for _, item := range products.Items {
if buyNum, ok := ids[item.Id]; ok {
if buyNum > int64(item.Number) {
@@ -131,6 +134,8 @@ func (l *WebCreateLogic) WebCreate(in *order.CreateOrderRequest) (*order.Respons
return l.out(utils.Fail,
item.Name+"购买数量超出库存,目前可以够买:"+strconv.Itoa(int(item.Number)))
} else {
numItem := &product.NumberItem{Id: item.Id, Number: uint32(buyNum)}
NumItems = append(NumItems, numItem)
keys = append(keys, strconv.Itoa(int(item.Id)))
totalPrice += item.Price * float64(buyNum)
productItems = append(productItems, dao.OrderProductCreate{
@@ -171,20 +176,19 @@ func (l *WebCreateLogic) WebCreate(in *order.CreateOrderRequest) (*order.Respons
return l.fail(utils.Fail)
}
//TODO 扣库存接口
//cli, err := svc.GetRpcClient(l.svcCtx.ProductSvcName)
//if err != nil {
// mobileObj.Rollback()
// return l.fail(utils.Fail)
//}
cli, err := svc.GetRpcClient(l.svcCtx.ProductSvcName)
if err != nil {
mobileObj.Rollback()
return l.fail(utils.Fail)
}
//productClient := product.NewProductClient(cli.Conn())
//_, err = productClient.Number(l.ctx, &product.NumberReq{Id: item.Id, Type: utils.NumberOne, Number: buyNum})
//if err != nil {
// mobileObj.Rollback()
// logx.Errorf("get products err: %v", err)
// return l.fail(utils.Fail, "产品库存不足")
//}
productClient := product.NewProductClient(cli.Conn())
_, err = productClient.NumberItems(l.ctx, &product.NumberItemsReq{Type: utils.NumberOne, Items: NumItems})
if err != nil {
mobileObj.Rollback()
logx.Errorf("get products err: %v", err)
return l.out(utils.Fail, "产品库存不足")
}
mobileObj.Commit()
+2 -5
View File
@@ -2,7 +2,7 @@
login_out_time=43200 #api接口超时时间分
login_refresh_out_time=83200
name = "sale-service"
listenOn = "0.0.0.0:10300"
listenOn = "0.0.0.0:10900"
mode = "dev"
[log]
path = "logs"
@@ -52,7 +52,4 @@
db = 0
[encrypt]
data_key = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a"
[services]
chore = "chore-service"
data_key = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a"