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:
SunYF
2026-08-27 10:09:54 +08:00
commit 1f0ee844a4
408 changed files with 102201 additions and 0 deletions
@@ -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 ç±»åžçšå·¥åã产线上åªå许æœä¸ç§å·¥ä»ç±»åž?,
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
}