chore: init bj_power monorepo (dashboard/mes/wms/wms_client/workstation), clear subproject git metadata and align naming to folder names
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"bj_power_mes/common/errorx"
|
||||
xhttp "bj_power_mes/common/httpx"
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/user"
|
||||
"bj_power_mes/internal/auth"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type LoginLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 登录
|
||||
func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
|
||||
return &LoginLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.TokenReply, err error) {
|
||||
u, err := l.svcCtx.EntClient.User.Query().Where(user.UsernameEQ(req.Username)).First(l.ctx)
|
||||
if ent.IsNotFound(err) {
|
||||
return nil, errorx.New(errorx.BadUsernameOrPassword, "not found user")
|
||||
} else if err != nil {
|
||||
l.Error(err)
|
||||
return nil, errorx.New(errorx.DbError)
|
||||
}
|
||||
if !auth.CheckPassword(req.Password, u.Password) {
|
||||
return nil, errorx.New(errorx.BadUsernameOrPassword, "wrong password")
|
||||
}
|
||||
token, _ := GenToken(l.svcCtx.Config.Auth.AccessSecret, time.Now().Unix(), int64(l.svcCtx.Config.Auth.AccessExpire), map[string]any{
|
||||
xhttp.CtxKeyJwtUserId: u.ID,
|
||||
})
|
||||
refreshToken := GenRefreshToken()
|
||||
l.svcCtx.TokenStore.Setex(l.ctx, fmt.Sprintf("user:%d:refesh_token", u.ID), refreshToken, l.svcCtx.Config.Auth.RefreshExpire)
|
||||
resp = &types.TokenReply{
|
||||
AccessToken: token,
|
||||
AccessExpire: l.svcCtx.Config.Auth.AccessExpire,
|
||||
RefreshToken: refreshToken,
|
||||
RefreshExpire: l.svcCtx.Config.Auth.RefreshExpire,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
xhttp "bj_power_mes/common/httpx"
|
||||
"bj_power_mes/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
// LogoutLogic 退出登��?
|
||||
type LogoutLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 退出登录:删除 refresh token,使已签发的 access token 无法续期
|
||||
func NewLogoutLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogoutLogic {
|
||||
return &LogoutLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LogoutLogic) Logout() error {
|
||||
userId := xhttp.GetUidFromCtx(l.ctx)
|
||||
if userId <= 0 {
|
||||
l.Logger.Errorf("退出登录失��? 未获取到用户ID")
|
||||
return nil // 兜底:不清除也不报错,前端已��?localStorage
|
||||
}
|
||||
key := fmt.Sprintf("user:%d:refesh_token", userId)
|
||||
if err := l.svcCtx.TokenStore.Del(l.ctx, key); err != nil {
|
||||
l.Logger.Errorf("退出登��? 删除 refresh token 失败 userId=%d error=%v", userId, err)
|
||||
}
|
||||
l.Logger.Infof("用户退出登��?userId=%d", userId)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"bj_power_mes/common/errorx"
|
||||
xhttp "bj_power_mes/common/httpx"
|
||||
"bj_power_mes/internal/auth"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type RefreshTokenLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 刷新token
|
||||
func NewRefreshTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RefreshTokenLogic {
|
||||
return &RefreshTokenLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *RefreshTokenLogic) RefreshToken(req *types.RefreshTokenReq) (resp *types.TokenReply, err error) {
|
||||
userId := xhttp.GetUidFromCtx(l.ctx)
|
||||
key := fmt.Sprintf("user:%d:refesh_token", userId)
|
||||
storedRefreshToken, err := l.svcCtx.TokenStore.Get(l.ctx, key)
|
||||
if errors.Is(err, auth.ErrNotFound) {
|
||||
return nil, errorx.Errorf(errorx.RefreshTokenInvalid, "not found refresh token for user: %d", userId)
|
||||
}
|
||||
if storedRefreshToken != req.RefreshToken {
|
||||
return nil, errorx.Errorf(errorx.RefreshTokenInvalid, "mismatch refresh token: %s:%s", req.RefreshToken, storedRefreshToken)
|
||||
}
|
||||
|
||||
token, _ := GenToken(l.svcCtx.Config.Auth.AccessSecret, time.Now().Unix(), int64(l.svcCtx.Config.Auth.AccessExpire), map[string]any{
|
||||
xhttp.CtxKeyJwtUserId: userId,
|
||||
})
|
||||
refreshToken := GenRefreshToken()
|
||||
l.svcCtx.TokenStore.Setex(l.ctx, key, refreshToken, l.svcCtx.Config.Auth.RefreshExpire)
|
||||
resp = &types.TokenReply{
|
||||
AccessToken: token,
|
||||
AccessExpire: l.svcCtx.Config.Auth.AccessExpire,
|
||||
RefreshToken: refreshToken,
|
||||
RefreshExpire: l.svcCtx.Config.Auth.RefreshExpire,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const RefreshTokenKeyPrefix = "token:refresh:"
|
||||
|
||||
func GenToken(secretKey string, iat int64, expireSeconds int64, payloads map[string]any) (string, error) {
|
||||
claims := make(jwt.MapClaims)
|
||||
claims["exp"] = iat + expireSeconds
|
||||
claims["iat"] = iat
|
||||
for k, v := range payloads {
|
||||
claims[k] = v
|
||||
}
|
||||
|
||||
token := jwt.New(jwt.SigningMethodHS256)
|
||||
token.Claims = claims
|
||||
|
||||
return token.SignedString([]byte(secretKey))
|
||||
}
|
||||
|
||||
func GenRefreshToken() string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(uuid.New().String()))
|
||||
}
|
||||
|
||||
func GenRefreshTokenCacheKey(userId int64) string {
|
||||
return fmt.Sprintf("%s%d", RefreshTokenKeyPrefix, userId)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package product_type
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/ent/producttype"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type CreateProductTypeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 创建产品类型
|
||||
func NewCreateProductTypeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateProductTypeLogic {
|
||||
return &CreateProductTypeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CreateProductTypeLogic) CreateProductType(req *types.CreateProductTypeReq) (resp int, err error) {
|
||||
pt, err := l.svcCtx.EntClient.ProductType.Create().
|
||||
SetCode(req.Code).
|
||||
SetName(req.Name).
|
||||
SetCategory(producttype.Category(req.Category)).
|
||||
SetCncMachineIds(req.CncMachineIDs).
|
||||
SetIsActive(true).
|
||||
SetRemark(req.Remark).
|
||||
Save(l.ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return pt.ID, nil
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package product_type
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type DeleteProductTypeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 删除产品类型
|
||||
func NewDeleteProductTypeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteProductTypeLogic {
|
||||
return &DeleteProductTypeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteProductTypeLogic) DeleteProductType(req *types.PathId) error {
|
||||
return l.svcCtx.EntClient.ProductType.DeleteOneID(req.Id).Exec(l.ctx)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package product_type
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetProductTypeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 通过ID查询产品类型
|
||||
func NewGetProductTypeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductTypeLogic {
|
||||
return &GetProductTypeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetProductTypeLogic) GetProductType(req *types.PathId) (resp *types.ProductTypeReply, err error) {
|
||||
pt, err := l.svcCtx.EntClient.ProductType.Get(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &types.ProductTypeReply{
|
||||
ID: pt.ID,
|
||||
Code: pt.Code,
|
||||
Name: pt.Name,
|
||||
RecipeID: pt.RecipeId,
|
||||
CncMachineIDs: pt.CncMachineIds,
|
||||
IsActive: pt.IsActive,
|
||||
Remark: pt.Remark,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package product_type
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/ent/producttype"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type ListProductTypesLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 获取产品类型列表
|
||||
func NewListProductTypesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListProductTypesLogic {
|
||||
return &ListProductTypesLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListProductTypesLogic) ListProductTypes(req *types.ListProductTypesReq) (resp []types.ProductTypeReply, err error) {
|
||||
wpTypes, err := l.svcCtx.EntClient.ProductType.Query().Order(producttype.ByID()).All(l.ctx)
|
||||
if err != nil {
|
||||
l.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp = make([]types.ProductTypeReply, 0, len(wpTypes))
|
||||
for _, wt := range wpTypes {
|
||||
resp = append(resp, types.ProductTypeReply{
|
||||
ID: wt.ID,
|
||||
Code: wt.Code,
|
||||
Name: wt.Name,
|
||||
Category: string(wt.Category),
|
||||
RecipeID: wt.RecipeId,
|
||||
CncMachineIDs: wt.CncMachineIds,
|
||||
IsActive: wt.IsActive,
|
||||
Remark: wt.Remark,
|
||||
})
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package product_type
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/ent/producttype"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type UpdateProductTypeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 更新产品类型
|
||||
func NewUpdateProductTypeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateProductTypeLogic {
|
||||
return &UpdateProductTypeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateProductTypeLogic) UpdateProductType(req *types.UpdateProductTypeReq) error {
|
||||
return l.svcCtx.EntClient.ProductType.UpdateOneID(req.ID).
|
||||
SetCode(req.Code).
|
||||
SetName(req.Name).
|
||||
SetCategory(producttype.Category(req.Category)).
|
||||
SetCncMachineIds(req.CncMachineIDs).
|
||||
SetRemark(req.Remark).
|
||||
Exec(l.ctx)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"bj_power_mes/common/errorx"
|
||||
xhttp "bj_power_mes/common/httpx"
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/user"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type UserinfoLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
func NewUserinfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserinfoLogic {
|
||||
return &UserinfoLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UserinfoLogic) Userinfo() (resp *types.UserInfoReply, err error) {
|
||||
userId := xhttp.GetUidFromCtx(l.ctx)
|
||||
query := l.svcCtx.EntClient.User.Query().Where(user.ID(int(userId))).WithDept().WithRole()
|
||||
u, err := query.Only(l.ctx)
|
||||
if err != nil {
|
||||
if ent.IsNotFound(err) {
|
||||
return nil, errorx.New(errorx.UserNotFound)
|
||||
}
|
||||
return nil, fmt.Errorf("获取用户信息失败: %w", err)
|
||||
}
|
||||
|
||||
resp = new(types.UserInfoReply)
|
||||
if err := copier.Copy(resp, u); err != nil {
|
||||
l.Errorf("用户信息拷贝失败: %v", err)
|
||||
}
|
||||
|
||||
resp.CreatedAt = u.CreatedAt.Unix()
|
||||
|
||||
if u.Edges.Dept != nil {
|
||||
resp.DeptId = u.Edges.Dept.ID
|
||||
resp.DeptName = u.Edges.Dept.Name
|
||||
}
|
||||
|
||||
if u.Edges.Role != nil {
|
||||
resp.RoleId = u.Edges.Role.ID
|
||||
resp.RoleName = u.Edges.Role.Name
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package workorder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"bj_power_mes/common/errorx"
|
||||
"bj_power_mes/constants"
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/producttype"
|
||||
"bj_power_mes/ent/workorder"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type CreateWorkOrderLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewCreateWorkOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateWorkOrderLogic {
|
||||
return &CreateWorkOrderLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CreateWorkOrderLogic) CreateWorkOrder(req *types.CreateWorkOrderReq) (*types.CreateWorkOrderReply, error) {
|
||||
if req.Quantity < 1 || req.Quantity > 1000 {
|
||||
return nil, errorx.NewDirectError(fmt.Sprintf("工件数é‡� %d æ— æ•ˆï¼Œå¿…é¡»åœ¨ 1-1000 之间", req.Quantity))
|
||||
}
|
||||
|
||||
pt, err := l.svcCtx.EntClient.ProductType.Query().
|
||||
Where(producttype.IDEQ(req.ProductTypeId)).
|
||||
Only(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errorx.NewDirectError("产å“�类型ä¸�å˜åœ?)
|
||||
}
|
||||
|
||||
// äº§çº¿äº’æ–¥æ ¡éªŒï¼šäº§çº¿ä¸Šå�ªå…�许有一ç§�工件类åž?
|
||||
// 如果å˜åœ¨æ´»è·ƒå·¥å�•(InProgress/Paused)且其产å“�类型ä¸�å�ŒäºŽå½“å‰�请求,则拒ç»�
|
||||
activeOrder, err := l.svcCtx.EntClient.WorkOrder.Query().
|
||||
Where(
|
||||
workorder.StatusIn(constants.WorkOrderStatus_InProgress, constants.WorkOrderStatus_Paused),
|
||||
).
|
||||
First(l.ctx)
|
||||
if err != nil && !ent.IsNotFound(err) {
|
||||
l.Errorf("查询活跃工�失败: %v", err)
|
||||
return nil, errorx.NewDirectError("查询活跃工�失败")
|
||||
}
|
||||
if activeOrder != nil {
|
||||
activePt, err := l.svcCtx.EntClient.ProductType.Get(l.ctx, activeOrder.ProductTypeId)
|
||||
if err != nil {
|
||||
l.Errorf("查询活跃工�产�类型失败: %v", err)
|
||||
return nil, errorx.NewDirectError("查询活跃工�产�类型失败")
|
||||
}
|
||||
if activePt.ID != req.ProductTypeId {
|
||||
return nil, errorx.NewDirectError(fmt.Sprintf(
|
||||
"产线当å‰�æ£åœ¨åŠ å·¥ %sï¼?sï¼‰ï¼Œæ— æ³•åˆ›å»º %s 类型的工å�•。产线上å�ªå…�许有一ç§�工件类åž?,
|
||||
activePt.Name, activePt.Code, pt.Name,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
tx, err := l.svcCtx.EntClient.BeginTx(l.ctx, nil)
|
||||
if err != nil {
|
||||
l.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workOrderNo := req.WorkOrderNo
|
||||
if workOrderNo == "" {
|
||||
workOrderNo = fmt.Sprintf("WO%s", time.Now().Format("20060102150405"))
|
||||
}
|
||||
|
||||
builder := tx.WorkOrder.Create().
|
||||
SetProductTypeId(req.ProductTypeId).
|
||||
SetQuantity(req.Quantity).
|
||||
SetWorkOrderNo(workOrderNo).
|
||||
SetSource(constants.WorkOrderSource_Manual).
|
||||
SetCreatedAt(time.Now())
|
||||
|
||||
o, err := builder.Save(l.ctx)
|
||||
if ent.IsValidationError(err) {
|
||||
if rbErr := tx.Rollback(); rbErr != nil {
|
||||
l.Errorf("回滚事务失败: %v", rbErr)
|
||||
}
|
||||
l.Error(err)
|
||||
return nil, err
|
||||
} else if err != nil {
|
||||
if rbErr := tx.Rollback(); rbErr != nil {
|
||||
l.Errorf("回滚事务失败: %v", rbErr)
|
||||
}
|
||||
l.Error(err)
|
||||
var pgErr *pgconn.PgError
|
||||
if errors.As(err, &pgErr) {
|
||||
return nil, errorx.New(errorx.WorkOrderAlreadyExists)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 工�创建完�,Job �AGV �达时或开始工�时创建
|
||||
if err = tx.Commit(); err != nil {
|
||||
if rbErr := tx.Rollback(); rbErr != nil {
|
||||
l.Errorf("回滚事务失败: %v", rbErr)
|
||||
}
|
||||
l.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.CreateWorkOrderReply{Id: o.ID}, nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package workorder
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/tasklog"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetLatestTaskLogsLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetLatestTaskLogsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLatestTaskLogsLogic {
|
||||
return &GetLatestTaskLogsLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetLatestTaskLogsLogic) GetLatestTaskLogs() (resp []types.TaskLogReply, err error) {
|
||||
logs, err := l.svcCtx.EntClient.TaskLog.Query().
|
||||
Order(ent.Desc(tasklog.FieldStartTime)).
|
||||
Limit(5).
|
||||
All(l.ctx)
|
||||
if err != nil {
|
||||
l.Errorf("查询最新任务日志失� %v", err)
|
||||
return []types.TaskLogReply{}, nil
|
||||
}
|
||||
|
||||
resp = make([]types.TaskLogReply, 0, len(logs))
|
||||
for _, lg := range logs {
|
||||
status := "FAILED"
|
||||
if lg.IsSuccess {
|
||||
status = "SUCCESS"
|
||||
}
|
||||
var durationMs int64
|
||||
if lg.EndTime != nil {
|
||||
durationMs = lg.EndTime.Sub(lg.StartTime).Milliseconds()
|
||||
}
|
||||
resp = append(resp, types.TaskLogReply{
|
||||
Id: lg.ID,
|
||||
JobId: lg.JobId,
|
||||
TaskKind: lg.ActionType,
|
||||
Status: status,
|
||||
DurationMs: durationMs,
|
||||
CreatedAt: lg.StartTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package workorder
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/common/errorx"
|
||||
"bj_power_mes/constants"
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/job"
|
||||
"bj_power_mes/ent/workorder"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetWorkOrderDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetWorkOrderDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWorkOrderDetailLogic {
|
||||
return &GetWorkOrderDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetWorkOrderDetailLogic) GetWorkOrderDetail(req *types.PathId) (resp *types.WorkOrderDetailReply, err error) {
|
||||
wo, err := l.svcCtx.EntClient.WorkOrder.Query().
|
||||
Where(workorder.IDEQ(req.Id), workorder.IsDelEQ(false)).
|
||||
WithProductType().
|
||||
Only(l.ctx)
|
||||
if ent.IsNotFound(err) {
|
||||
return nil, errorx.New(errorx.WorkOrderNotFound)
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base := types.WorkOrderReply{}
|
||||
if err := copier.Copy(&base, wo); err != nil {
|
||||
l.Errorf("憭滚�撌亙�霂行��唳旿憭梯揖: %v", err)
|
||||
}
|
||||
base.Source = string(wo.Source)
|
||||
if !wo.CreatedAt.IsZero() {
|
||||
base.CreatedTime = wo.CreatedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if wo.CompletedAt != nil && !wo.CompletedAt.IsZero() {
|
||||
base.CompletedTime = wo.CompletedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if wo.UpdatedAt != nil {
|
||||
base.UpdatedTime = wo.UpdatedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// 鈭批�蝐餃��滨妍
|
||||
productTypeName := ""
|
||||
if wo.Edges.ProductType != nil {
|
||||
productTypeName = wo.Edges.ProductType.Name
|
||||
}
|
||||
|
||||
// �亥砭撌亙�銝讠�撌乩辣嚗峕��嗆���霈?+ �瑕� recipe �滨妍嚗���方蔓�𣳇膄撌乩辣嚗?
|
||||
jobs, err := l.svcCtx.EntClient.Job.Query().
|
||||
Where(job.WorkOrderIdEQ(req.Id), job.IsDelEQ(false)).
|
||||
WithRecipe().
|
||||
All(l.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
statusCount := make(map[string]int)
|
||||
recipeName := ""
|
||||
for _, j := range jobs {
|
||||
statusCount[string(j.Status)]++
|
||||
if recipeName == "" && j.Edges.Recipe != nil {
|
||||
recipeName = j.Edges.Recipe.Name
|
||||
}
|
||||
}
|
||||
|
||||
stats := make([]types.JobStatusCount, 0, len(statusCount))
|
||||
for status, count := range statusCount {
|
||||
stats = append(stats, types.JobStatusCount{Status: status, Count: count})
|
||||
}
|
||||
|
||||
// 銝衤�銝芸�蝏穃�撌乩辣嚗帋� EventLoop handleBindDock ��龪�齿辺隞嗡�����?
|
||||
// 嚗㇊ositionRefId 銝箇征 + �嗆�?CREATED/PROCESSING/SUSPENDED嚗㚁�靘?瘛餃�撌乩辣"撘寧��鞟內憸�恣蝏穃�撌乩辣ID
|
||||
nextUnboundJobId := 0
|
||||
if wo.Status == constants.WorkOrderStatus_InProgress {
|
||||
if nxt, err := l.svcCtx.EntClient.Job.Query().
|
||||
Where(
|
||||
job.WorkOrderIdEQ(req.Id),
|
||||
job.IsDelEQ(false),
|
||||
job.PositionRefIdEQ(""),
|
||||
job.StatusIn(constants.JobStatus_Created, constants.JobStatus_Processing, constants.JobStatus_Suspended),
|
||||
).
|
||||
Order(ent.Asc(job.FieldID)).
|
||||
First(l.ctx); err == nil && nxt != nil {
|
||||
nextUnboundJobId = nxt.ID
|
||||
}
|
||||
}
|
||||
|
||||
return &types.WorkOrderDetailReply{
|
||||
WorkOrderReply: base,
|
||||
ProductTypeName: productTypeName,
|
||||
RecipeName: recipeName,
|
||||
JobStats: stats,
|
||||
TotalJobs: len(jobs),
|
||||
NextUnboundJobId: nextUnboundJobId,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package workorder
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/common/errorx"
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/workorder"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetWorkOrderLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetWorkOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWorkOrderLogic {
|
||||
return &GetWorkOrderLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetWorkOrderLogic) GetWorkOrder(req *types.PathId) (resp *types.WorkOrderReply, err error) {
|
||||
// æŽ’é™¤è½¯åˆ é™¤å·¥å�•ï¼šè½¯åˆ å�Žè¿”å›?å·¥å�•ä¸�å˜åœ?
|
||||
t, err := l.svcCtx.EntClient.WorkOrder.Query().
|
||||
Where(workorder.IDEQ(req.Id), workorder.IsDelEQ(false)).
|
||||
Only(l.ctx)
|
||||
|
||||
if ent.IsNotFound(err) {
|
||||
return nil, errorx.New(errorx.WorkOrderNotFound)
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp = new(types.WorkOrderReply)
|
||||
if err := copier.Copy(resp, t); err != nil {
|
||||
l.Errorf("�制工�数�失败: %v", err)
|
||||
}
|
||||
resp.Source = string(t.Source)
|
||||
|
||||
if !t.CreatedAt.IsZero() {
|
||||
resp.CreatedTime = t.CreatedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if t.CompletedAt != nil && !t.CompletedAt.IsZero() {
|
||||
resp.CompletedTime = t.CompletedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if t.UpdatedAt != nil {
|
||||
resp.UpdatedTime = t.UpdatedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package workorder
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/tasklog"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type QueryTaskLogsLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewQueryTaskLogsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryTaskLogsLogic {
|
||||
return &QueryTaskLogsLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (lo *QueryTaskLogsLogic) QueryTaskLogs(req *types.QueryTaskLogsReq) (resp *types.QueryTaskLogsReply, err error) {
|
||||
query := lo.svcCtx.EntClient.TaskLog.Query()
|
||||
|
||||
if req.JobId > 0 {
|
||||
query = query.Where(tasklog.JobId(req.JobId))
|
||||
}
|
||||
|
||||
total, err := query.Count(lo.ctx)
|
||||
if err != nil {
|
||||
lo.Errorf("查询任务日志总数失败: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query = query.
|
||||
Order(ent.Desc(tasklog.FieldStartTime)).
|
||||
Offset((req.Page - 1) * req.Limit).
|
||||
Limit(req.Limit)
|
||||
|
||||
logs, err := query.All(lo.ctx)
|
||||
if err != nil {
|
||||
lo.Errorf("执行任务日志查询失败: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]types.TaskLogReply, 0, len(logs))
|
||||
for _, lg := range logs {
|
||||
status := "FAILED"
|
||||
if lg.IsSuccess {
|
||||
status = "SUCCESS"
|
||||
}
|
||||
var durationMs int64
|
||||
if lg.EndTime != nil {
|
||||
durationMs = lg.EndTime.Sub(lg.StartTime).Milliseconds()
|
||||
}
|
||||
content := ""
|
||||
if lg.Result != nil {
|
||||
if v, ok := lg.Result["content"].(string); ok {
|
||||
content = v
|
||||
}
|
||||
}
|
||||
items = append(items, types.TaskLogReply{
|
||||
Id: lg.ID,
|
||||
JobId: lg.JobId,
|
||||
TaskKind: lg.ActionType,
|
||||
Status: status,
|
||||
Content: content,
|
||||
DurationMs: durationMs,
|
||||
CreatedAt: lg.StartTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
resp = &types.QueryTaskLogsReply{
|
||||
PageReply: types.PageReply{
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
},
|
||||
Data: items,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package workorder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"bj_power_mes/constants"
|
||||
"bj_power_mes/ent/workorder"
|
||||
"bj_power_mes/internal/svc"
|
||||
"bj_power_mes/internal/types"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type QueryWorkOrdersLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// 查询工�分页列表
|
||||
func NewQueryWorkOrdersLogic(ctx context.Context, svcCtx *svc.ServiceContext) *QueryWorkOrdersLogic {
|
||||
return &QueryWorkOrdersLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *QueryWorkOrdersLogic) QueryWorkOrders(req *types.QueryWorkOrdersReq) (resp *types.QueryWorkOrdersReply, err error) {
|
||||
// åˆ�å§‹åŒ–æŸ¥è¯¢å¯¹è±¡ï¼ˆæŽ’é™¤è½¯åˆ é™¤å·¥å�•)
|
||||
query := l.svcCtx.EntClient.WorkOrder.Query().
|
||||
Where(workorder.IsDelEQ(false)).
|
||||
WithProductType()
|
||||
|
||||
// WorkOrder no longer has No/Remark text fields; keyword filter removed
|
||||
if len(req.Statuses) > 0 {
|
||||
var statuses []constants.WorkOrderStatus
|
||||
for _, status := range req.Statuses {
|
||||
statuses = append(statuses, constants.WorkOrderStatus(status))
|
||||
}
|
||||
query.Where(workorder.StatusIn(statuses...))
|
||||
}
|
||||
|
||||
// 获�总数
|
||||
total, err := query.Count(l.ctx)
|
||||
if err != nil {
|
||||
l.Errorf("查询工�总数失败: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 分页处�
|
||||
query = query.
|
||||
Offset((req.Page - 1) * req.Limit).
|
||||
Limit(req.Limit)
|
||||
|
||||
// 执行查询
|
||||
orders, err := query.All(l.ctx)
|
||||
if err != nil {
|
||||
l.Errorf("执行工�列表查询失败: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// æž„é€ è¿”å›žæ•°æ�?
|
||||
data := make([]types.WorkOrderReply, 0, len(orders))
|
||||
for _, o := range orders {
|
||||
orderReply := types.WorkOrderReply{}
|
||||
if err := copier.Copy(&orderReply, o); err != nil {
|
||||
l.Errorf("�制工�列表数�失败: %v", err)
|
||||
}
|
||||
|
||||
// 处ç�†æ—¶é—´å—段
|
||||
if !o.CreatedAt.IsZero() {
|
||||
orderReply.CreatedTime = o.CreatedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if o.CompletedAt != nil && !o.CompletedAt.IsZero() {
|
||||
orderReply.CompletedTime = o.CompletedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if o.UpdatedAt != nil {
|
||||
orderReply.UpdatedTime = o.UpdatedAt.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
// WorkOrder no longer has a No field; generate from ID
|
||||
orderReply.No = fmt.Sprintf("WO-%d", o.ID)
|
||||
orderReply.Source = string(o.Source)
|
||||
orderReply.WorkOrderNo = o.WorkOrderNo
|
||||
// 产å“�ç±»åž‹ä¸æ–‡å��(列表展示用,æ¤å‰�仅详情接å�£æœ‰ï¼?
|
||||
if pt := o.Edges.ProductType; pt != nil {
|
||||
orderReply.ProductTypeName = string(pt.Category)
|
||||
// 产å“�代å�·ï¼Œå”¯ä¸€ä¸šåŠ¡ç¼–ç �(如 PART-SQR-107ï¼?
|
||||
orderReply.ProductTypeCode = pt.Code
|
||||
}
|
||||
|
||||
data = append(data, orderReply)
|
||||
}
|
||||
|
||||
// æž„é€ å“�åº?
|
||||
resp = &types.QueryWorkOrdersReply{
|
||||
PageReply: types.PageReply{
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
Limit: req.Limit,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
Reference in New Issue
Block a user