add task apis

This commit is contained in:
2026-08-31 18:15:26 +08:00
parent 6758ced988
commit ebd9c932d2
26 changed files with 1175 additions and 98 deletions
+13
View File
@@ -0,0 +1,13 @@
package config
type Config struct {
Nacos NacosConf
}
type NacosConf struct {
Hosts []string
NamespaceId string `json:",optional"`
Group string `json:",optional"`
RegisterIP string `json:",optional"`
ConfigID string `json:",optional"`
}
+48
View File
@@ -0,0 +1,48 @@
package dao
const (
TaskTimeMonth = 1 //为月
TaskTimeQuarter = 2 //为季度
TaskTimeHalfYear = 3 //为半年
TaskTimeYear = 4 //为一年
)
type TaskCreate struct {
Id int64 `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT" json:"id"`
Type int32 `gorm:"column:type;type:tinyint(4) unsigned;default:0;comment:1、为销售,2为销售人;NOT NULL" json:"type"`
Time int32 `gorm:"column:time;type:tinyint(4) unsigned;default:0;comment:时间,1为月,2为季度,3为半年,4为一年" json:"time"`
Province int64 `gorm:"column:province;type:int(11);default:0;comment:省;NOT NULL" json:"province"`
ProvinceName string `gorm:"column:province_name;type:varchar(100);comment:省名" json:"province_name"`
ProductId int64 `json:"product_id" gorm:"product_id"` // 产品ID
Task int32 `gorm:"column:task;type:int(11) unsigned;default:0;comment:任务 盒数" json:"task"`
Award float64 `gorm:"column:award;type:decimal(10,2);comment:奖励金额/盒" json:"award"`
AdminId int64 `gorm:"column:admin_id;type:int(11)" json:"admin_id"`
AdminName string `gorm:"column:admin_name;type:varchar(255)" json:"admin_name"`
}
type TaskInfo struct {
Id int64 `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT" json:"id"`
Type int32 `gorm:"column:type;type:tinyint(4) unsigned;default:0;comment:1、为销售,2为销售人;NOT NULL" json:"type"`
Time int32 `gorm:"column:time;type:tinyint(4) unsigned;default:0;comment:时间,1为月,2为季度,3为半年,4为一年" json:"time"`
Province int `gorm:"column:province;type:int(11);default:0;comment:省;NOT NULL" json:"province"`
ProvinceName string `gorm:"column:province_name;type:varchar(100);comment:省名" json:"province_name"`
ProductId int64 `json:"product_id" gorm:"product_id"` // 产品ID
ProductName string `gorm:"-" json:"product_name"`
Task int32 `gorm:"column:task;type:int(11) unsigned;default:0;comment:任务 盒数" json:"task"`
Award float64 `gorm:"column:award;type:decimal(10,2);comment:奖励金额/盒" json:"award"`
AdminId int64 `gorm:"column:admin_id;type:int(11)" json:"admin_id"`
AdminName string `gorm:"column:admin_name;type:varchar(255)" json:"admin_name"`
Reason string `gorm:"column:reason;type:varchar(255);comment:禁用原因" json:"reason"`
Status int32 `gorm:"column:status;type:tinyint(1);default:1;comment:状态,1为正常,2为禁用;NOT NULL" json:"status"`
}
type TaskStatus struct {
Id int64 `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT;comment:ID" json:"id"`
Type int32 `gorm:"column:type;type:tinyint(4) unsigned;default:0;comment:1、为销售,2为销售人;NOT NULL" json:"type"`
Time int32 `gorm:"column:time;type:tinyint(4) unsigned;default:0;comment:时间,1为月,2为季度,3为半年,4为一年" json:"time"`
Province int64 `gorm:"column:province;type:int(11);default:0;comment:省;NOT NULL" json:"province"`
Reason string `gorm:"column:reason;type:varchar(255);comment:禁用原因" json:"reason"`
Status int32 `gorm:"column:status;type:tinyint(1);default:1;comment:状态,1为正常,2为禁用;NOT NULL" json:"status"`
AdminId int64 `gorm:"column:admin_id;type:int(11)" json:"admin_id"`
AdminName string `gorm:"column:admin_name;type:varchar(255)" json:"admin_name"`
}
+44
View File
@@ -0,0 +1,44 @@
package logic
import (
"lone-services/pkg/utils"
"lone-services/pkg/validate"
task "lone-services/rpc/task/pb"
"reflect"
jsoniter "github.com/json-iterator/go"
)
type BaseLogic struct {
}
func (l *BaseLogic) checkParams(in interface{}, v validate.IValidator) *task.Response {
rv := reflect.ValueOf(in)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return &task.Response{
Code: utils.ErrorParams.Code,
Msg: "request must be nonnil proto pointer",
}
}
resp := validate.ValidateFromProto(in, v)
if resp != utils.StringEmpty {
return &task.Response{
Code: utils.ErrorParams.Code,
Msg: resp,
}
}
return nil
}
func (l *BaseLogic) fail(status utils.Status) (*task.Response, error) {
return l.out(status, status.Msg)
}
func (l *BaseLogic) out(status utils.Status, msg string) (*task.Response, error) {
return &task.Response{Code: status.Code, Msg: msg}, nil
}
func (l *BaseLogic) ok(data any) (*task.Response, error) {
buf, _ := jsoniter.Marshal(data)
return &task.Response{Code: utils.Ok.Code, Msg: utils.Ok.Msg, Data: string(buf)}, nil
}
@@ -0,0 +1,66 @@
package logic
import (
"context"
"lone-services/pkg/utils"
"lone-services/services/task/internal/dao"
"lone-services/services/task/internal/model"
"lone-services/services/task/validator"
"lone-services/rpc/task/pb"
"lone-services/services/task/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type CreateLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
BaseLogic
}
func NewCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateLogic {
return &CreateLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *CreateLogic) Create(in *task.CreateRequest) (*task.Response, error) {
var v validator.TaskCreateValidator
if fail := l.checkParams(in, &v); fail != nil {
return fail, nil
}
adminInfo := utils.GetUserFromCtx(l.ctx)
if adminInfo.ID < utils.NumberOne {
return l.fail(utils.ErrorNoLoginInfo)
}
data := dao.TaskCreate{
Type: in.Type,
Time: in.Time,
ProvinceName: in.ProvinceName,
ProductId: in.ProductId,
Task: in.Task,
Award: utils.RoundFloat(in.Award),
Province: in.Province,
AdminId: adminInfo.ID,
AdminName: adminInfo.Name,
}
err := model.TaskModel{}.Init().Create(&data)
if err != nil {
l.Logger.Error(err)
return l.fail(utils.Fail)
}
action := utils.ActionAdd{
NewContent: data,
Type: utils.LogActionTypeAdd,
ModuleName: utils.LogActionModuleTask,
}
utils.SetActionLog(adminInfo, action)
return l.ok(data.Id)
}
+75
View File
@@ -0,0 +1,75 @@
package logic
import (
"context"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
"lone-services/services/task/internal/dao"
"lone-services/services/task/internal/model"
"lone-services/services/task/validator"
"strconv"
"lone-services/rpc/task/pb"
"lone-services/services/task/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type EditLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
BaseLogic
}
func NewEditLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditLogic {
return &EditLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *EditLogic) Edit(in *task.EditRequest) (*task.Response, error) {
var v validator.TaskEditValidator
if fail := l.checkParams(in, &v); fail != nil {
return fail, nil
}
adminInfo := utils.GetUserFromCtx(l.ctx)
if adminInfo.ID < utils.NumberOne {
return l.fail(utils.ErrorNoLoginInfo)
}
var info dao.TaskCreate
w := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(int(in.Id))}}
err := model.TaskModel{}.Init().GetOne(w, &info)
if err != nil {
return l.fail(utils.ErrorNotFund)
}
if info.Id < utils.NumberOne {
return l.fail(utils.ErrorNotFund)
}
action := utils.ActionAdd{
OldContent: info,
Type: utils.LogActionTypeEdit,
ModuleName: utils.LogActionModuleTask,
}
info.AdminId = adminInfo.ID
info.AdminName = adminInfo.Name
info.Task = in.Task
info.Award = in.Award
row, err := model.TaskModel{}.Init().Edit(w, &info)
if err != nil {
l.Logger.Error(err)
return l.fail(utils.Fail)
}
if row > utils.NumberZero {
action.NewContent = info
utils.SetActionLog(adminInfo, action)
}
return l.ok(info.Id)
}
+69
View File
@@ -0,0 +1,69 @@
package logic
import (
"context"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
product "lone-services/rpc/product/pb"
"lone-services/services/task/internal/dao"
"lone-services/services/task/internal/model"
"lone-services/services/task/validator"
"strconv"
"lone-services/rpc/task/pb"
"lone-services/services/task/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type InfoLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
BaseLogic
}
func NewInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InfoLogic {
return &InfoLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *InfoLogic) Info(in *task.IdRequest) (*task.Response, error) {
var v validator.TaskInfoValidator
if fail := l.checkParams(in, &v); fail != nil {
return fail, nil
}
var info dao.TaskInfo
modelObj := model.TaskModel{}.Init()
w := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(int(in.Id))}}
err := modelObj.GetOne(w, &info)
if err != nil {
return l.fail(utils.ErrorNotFund)
}
if info.ProductId < utils.NumberOne {
return l.fail(utils.ErrorNotFund)
}
cli, err := svc.GetRpcClient(l.svcCtx.ProductSvcName)
if err != nil {
logx.Errorf("get rpc client err: %v", err)
return l.fail(utils.ErrorInternalServer)
}
productClient := product.NewProductClient(cli.Conn())
productInfo, err := productClient.InfoById(context.Background(), &product.InfoByIdReq{Id: info.ProductId})
if err != nil {
logx.Errorf("get products err: %v", err)
return l.fail(utils.ErrorInternalServer)
}
if info.Id < utils.NumberOne {
return l.fail(utils.ErrorNotFund)
}
info.ProductName = productInfo.Name
return l.ok(info)
}
@@ -0,0 +1,72 @@
package logic
import (
"context"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
product "lone-services/rpc/product/pb"
"lone-services/services/task/internal/dao"
"lone-services/services/task/internal/model"
"lone-services/rpc/task/pb"
"lone-services/services/task/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type ItemsLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
BaseLogic
}
func NewItemsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ItemsLogic {
return &ItemsLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *ItemsLogic) Items(in *task.EmtpyRequest) (*task.Response, error) {
modelObj := model.TaskModel{}.Init()
w := modelbase.Params{}
var data []dao.TaskInfo
err := modelObj.Items(w, &data)
if err != nil {
return l.fail(utils.ErrorNotFund)
}
var ids []int64
if len(data) < utils.NumberOne {
return l.ok(data)
}
for _, productItem := range data {
ids = append(ids, productItem.ProductId)
}
cli, err := svc.GetRpcClient(l.svcCtx.ProductSvcName)
if err != nil {
logx.Errorf("get rpc client err: %v", err)
return l.fail(utils.ErrorInternalServer)
}
productClient := product.NewProductClient(cli.Conn())
productItems, err := productClient.ItemsByIds(context.Background(), &product.ItemsByIdsReq{Ids: ids})
if err != nil {
logx.Errorf("get products err: %v", err)
return l.fail(utils.ErrorInternalServer)
}
names := make(map[int64]string)
for _, productItem := range productItems.Items {
names[productItem.Id] = productItem.Name
}
for key, dataItem := range data {
if _, ok := names[dataItem.ProductId]; ok {
l.Logger.Error(ok)
data[key].ProductName = names[dataItem.ProductId]
}
}
return l.ok(data)
}
@@ -0,0 +1,72 @@
package logic
import (
"context"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
"lone-services/services/task/internal/dao"
"lone-services/services/task/internal/model"
"lone-services/services/task/validator"
"strconv"
"lone-services/rpc/task/pb"
"lone-services/services/task/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type StatusLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
BaseLogic
}
func NewStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StatusLogic {
return &StatusLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *StatusLogic) Status(in *task.StatusRequest) (*task.Response, error) {
var v validator.TaskStatusValidator
if fail := l.checkParams(in, &v); fail != nil {
return fail, nil
}
adminInfo := utils.GetUserFromCtx(l.ctx)
if adminInfo.ID < utils.NumberOne {
return l.fail(utils.ErrorNoLoginInfo)
}
var action = utils.ActionAdd{}
var info dao.TaskStatus
w := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(int(in.Id))}}
modelObj := model.TaskModel{}.Init()
err := modelObj.GetOne(w, &info)
if err != nil {
l.Logger.Error(err)
return l.fail(utils.Fail)
}
if info.Id < utils.NumberOne {
return l.fail(utils.ErrorNotFund)
}
action.OldContent = info
info.Status = in.Status
info.Reason = in.Reason
info.AdminName = adminInfo.Name
info.AdminId = adminInfo.ID
row, editErr := modelObj.Edit(w, info)
if editErr != nil {
l.Logger.Error(editErr)
return l.fail(utils.Fail)
}
if row > utils.NumberZero {
action.NewContent = info
action.Reason = in.Reason
action.Type = utils.LogActionTypeStatus
action.ModuleName = utils.LogActionModuleTask
utils.SetActionLog(adminInfo, action)
}
return l.ok(utils.NumberOne)
}
+23
View File
@@ -0,0 +1,23 @@
package model
import (
"lone-services/pkg/modelbase"
"lone-services/services/task/internal/dao"
)
type TaskModel struct {
modelbase.Base
}
func (m TaskModel) TableName() string {
return modelbase.Prefix() + "task"
}
func (m TaskModel) Init() TaskModel {
m.Table = m.TableName()
return m
}
func (m TaskModel) Create(data *dao.TaskCreate) error {
return m.Base.Create(data)
}
@@ -0,0 +1,49 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.10.2
// Source: task.proto
package server
import (
"context"
"lone-services/rpc/task/pb"
"lone-services/services/task/internal/logic"
"lone-services/services/task/internal/svc"
)
type TaskServer struct {
svcCtx *svc.ServiceContext
task.UnimplementedTaskServer
}
func NewTaskServer(svcCtx *svc.ServiceContext) *TaskServer {
return &TaskServer{
svcCtx: svcCtx,
}
}
func (s *TaskServer) Items(ctx context.Context, in *task.EmtpyRequest) (*task.Response, error) {
l := logic.NewItemsLogic(ctx, s.svcCtx)
return l.Items(in)
}
func (s *TaskServer) Info(ctx context.Context, in *task.IdRequest) (*task.Response, error) {
l := logic.NewInfoLogic(ctx, s.svcCtx)
return l.Info(in)
}
func (s *TaskServer) Create(ctx context.Context, in *task.CreateRequest) (*task.Response, error) {
l := logic.NewCreateLogic(ctx, s.svcCtx)
return l.Create(in)
}
func (s *TaskServer) Edit(ctx context.Context, in *task.EditRequest) (*task.Response, error) {
l := logic.NewEditLogic(ctx, s.svcCtx)
return l.Edit(in)
}
func (s *TaskServer) Status(ctx context.Context, in *task.StatusRequest) (*task.Response, error) {
l := logic.NewStatusLogic(ctx, s.svcCtx)
return l.Status(in)
}
@@ -0,0 +1,96 @@
package svc
import (
"fmt"
"lone-services/pkg/discovery"
"lone-services/pkg/utils"
"lone-services/services/task/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
ProductSvcName string //服务名
}
func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
//启动仅读取配置,不建立rpc连接 多个服务就多个
productSvc := utils.GetConfigString("services.product")
if productSvc == utils.StringEmpty {
logx.Error("config services.product empty")
}
return &ServiceContext{
Config: c,
DB: db,
Prefix: utils.GetConfigString("mysql.prefix"),
ProductSvcName: productSvc,
}
}