feat:完善项目

This commit is contained in:
henry
2021-11-08 17:42:23 +08:00
parent 1cc95fb5ca
commit 08083d26d3
7 changed files with 315 additions and 125 deletions

View File

@ -12,8 +12,28 @@ import (
type Work struct{} type Work struct{}
type workLaunchForm struct { type (
// workLaunchForm 工单发起基本信息
workLaunchForm struct {
Kind int `json:"kind" form:"kind" binding:"required"` // 类型
Title string `json:"title" form:"title"`
EquipmentID uint64 `json:"equipment_id" form:"equipment_id" binding:"required"` // 装备ID
Breakdowns []uint64 `json:"breakdowns" form:"breakdowns"` // 故障类型
PlateNumber string `json:"plate_number" form:"plate_number"` // 车牌号
Priority int `json:"priority" form:"priority" binding:"required"` // 优先级
IsAssist int `json:"is_assist" form:"is_assist"` // 是否需要上级审批
Remark string `json:"remark" form:"remark"` // 备注信息
} }
// workLaunchMaterialForm 工单发起配件信息
workLaunchMaterialForm struct {
}
// workLaunchDistributionForm 工单发起地址信息
workLaunchDistributionForm struct {
Name string `json:"name" form:"name" binding:"required"` // 联系人
Mobile string `json:"mobile" form:"mobile" binding:"required"` // 联系方式
Address string `json:"address" form:"address" binding:"required"` // 联系地址
}
)
/** /**
* @api {post} /api/v1/work/list 工单信息 * @api {post} /api/v1/work/list 工单信息
@ -80,16 +100,18 @@ func (*Work) ToDo(c *gin.Context) {
func (*Work) Launch(c *gin.Context) { func (*Work) Launch(c *gin.Context) {
form := &struct { form := &struct {
IDStringForm workLaunchForm
Status int `json:"status" form:"status" binding:"required"` Material []*workLaunchMaterialForm `json:"material" form:"material"`
Remark string `json:"remark" form:"remark"` Address workLaunchDistributionForm `json:"distribution" form:"distribution"`
IsAssist int `json:"is_assist" form:"is_assist"`
}{} }{}
if err := bind(form)(c); err != nil { if err := bind(form)(c); err != nil {
APIFailure(err.(error))(c) APIFailure(err.(error))(c)
return return
} }
err := work.NewInstance()(getSession()(c).(*service.Session)).Launch() err := work.NewInstance()(getSession()(c).(*service.Session)).Launch(&work.InstanceLaunchParams{
Kind: form.Kind, Title: form.Title, EquipmentID: form.EquipmentID, Breakdowns: form.Breakdowns,
PlateNumber: form.PlateNumber, Priority: form.Priority, IsAssist: form.IsAssist, Remark: form.Remark,
})
APIResponse(err) APIResponse(err)
} }
@ -104,6 +126,6 @@ func (*Work) Examine(c *gin.Context) {
APIFailure(err.(error))(c) APIFailure(err.(error))(c)
return return
} }
err := work.NewPerson()(getSession()(c).(*service.Session)).Examine(form.Convert(), form.Status, form.Remark, form.IsAssist) err := work.NewInstance()(getSession()(c).(*service.Session)).Examine(form.Convert(), form.Status, form.Remark, form.IsAssist)
APIResponse(err) APIResponse(err)
} }

View File

@ -1,13 +1,18 @@
package model package model
import (
"ArmedPolice/utils"
"strings"
)
// WorkInstance 工单数据模型 // WorkInstance 工单数据模型
type WorkInstance struct { type WorkInstance struct {
Model Model
ModelTenant ModelTenant
OrderNo string `gorm:"column:order_no;type:varchar(30);default:null;comment:工单单号" json:"order_no"` OrderNo string `gorm:"column:order_no;type:varchar(30);default:null;comment:工单单号" json:"order_no"`
Kind int `gorm:"column:kind;type:tinyint(1);default:0;comment:工单类型" json:"kind"` Kind WorkInstanceKind `gorm:"column:kind;type:tinyint(1);default:0;comment:工单类型" json:"kind"`
Title string `gorm:"column:title;type:varchar(30);default:null;comment:工单标题" json:"title"` Title string `gorm:"column:title;type:varchar(30);default:null;comment:工单标题" json:"title"`
MaterialID uint64 `gorm:"column:material_id;type:int(11);default:0;comment:装备ID" json:"material_id"` EquipmentID uint64 `gorm:"column:equipment_id;type:int(11);default:0;comment:装备ID" json:"equipment_id"`
PlateNumber string `gorm:"column:plate_number;type:varchar(10);default:null;comment:车牌号" json:"plate_number"` PlateNumber string `gorm:"column:plate_number;type:varchar(10);default:null;comment:车牌号" json:"plate_number"`
Breakdown string `gorm:"column:breakdown;type:varchar(150);default:null;comment:故障" json:"breakdown"` Breakdown string `gorm:"column:breakdown;type:varchar(150);default:null;comment:故障" json:"breakdown"`
Priority WorkInstancePriority `gorm:"column:priority;type:tinyint(1);default:1;comment:工单优先级" json:"priority"` Priority WorkInstancePriority `gorm:"column:priority;type:tinyint(1);default:1;comment:工单优先级" json:"priority"`
@ -15,10 +20,18 @@ type WorkInstance struct {
IsAssist WorkInstanceAssist `orm:"column:is_assist;type:tinyint(1);default:0;comment:协助状态" json:"is_assist"` // 当前阶段协助状态,确认是否需要下一阶段协助 IsAssist WorkInstanceAssist `orm:"column:is_assist;type:tinyint(1);default:0;comment:协助状态" json:"is_assist"` // 当前阶段协助状态,确认是否需要下一阶段协助
Status WorkInstanceStatus `gorm:"column:status;type:tinyint(1);default:0;comment:工单状态" json:"status"` Status WorkInstanceStatus `gorm:"column:status;type:tinyint(1);default:0;comment:工单状态" json:"status"`
Remark string `gorm:"column:remark;type:varchar(255);default:null;comment:备注信息" json:"remark"` Remark string `gorm:"column:remark;type:varchar(255);default:null;comment:备注信息" json:"remark"`
Distribution string `gorm:"column:distribution;type:varchar(255);default:null;comment:配送信息" json:"-"`
ModelDeleted ModelDeleted
ModelAt ModelAt
} }
// WorkInstanceDistribution 配送信息
type WorkInstanceDistribution struct {
Name string `json:"name"`
Mobile string `json:"mobile"`
Address string `json:"address"`
}
// WorkInstanceKind 工单类型 // WorkInstanceKind 工单类型
type WorkInstanceKind int type WorkInstanceKind int
@ -65,6 +78,39 @@ func (m *WorkInstance) TableName() string {
return "work_instance" return "work_instance"
} }
// SetBreakdownAttribute 设置故障信息
func (m *WorkInstance) SetBreakdownAttribute(value []uint64) {
out := make([]string, 0)
for _, v := range value {
out = append(out, utils.UintToString(v))
}
m.Breakdown = strings.Join(out, ",")
}
// GetBreakdownAttribute 获取故障信息
func (m *WorkInstance) GetBreakdownAttribute() []uint64 {
value := strings.Split(m.Breakdown, ",")
out := make([]uint64, 0)
for _, v := range value {
out = append(out, utils.StringToUnit64(v))
}
return out
}
// SetDistributionAttribute 设置配送信息
func (m *WorkInstance) SetDistributionAttribute(value *WorkInstanceDistribution) {
m.Distribution = utils.AnyToJSON(value)
}
// GetDistributionAttribute 获取配送信息
func (m *WorkInstance) GetDistributionAttribute() *WorkInstanceDistribution {
out := new(WorkInstanceDistribution)
_ = utils.FromJSON(m.Distribution, out)
return out
}
func NewWorkInstance() *WorkInstance { func NewWorkInstance() *WorkInstance {
return &WorkInstance{} return &WorkInstance{}
} }

View File

@ -3,8 +3,14 @@ package work
import ( import (
model2 "ArmedPolice/app/common/model" model2 "ArmedPolice/app/common/model"
"ArmedPolice/app/controller/basic" "ArmedPolice/app/controller/basic"
"ArmedPolice/app/handle"
"ArmedPolice/app/model" "ArmedPolice/app/model"
"ArmedPolice/app/service" "ArmedPolice/app/service"
"ArmedPolice/serve/orm"
"ArmedPolice/utils"
"errors"
"gorm.io/gorm"
"time"
) )
type Instance struct{ *service.Session } type Instance struct{ *service.Session }
@ -17,8 +23,40 @@ type (
basic.CommonIDString basic.CommonIDString
*model.WorkInstanceInfo *model.WorkInstanceInfo
} }
// InstanceLaunchParams 发起参数信息
InstanceLaunchParams struct {
ID uint64
Kind int // 类型
Title string
EquipmentID uint64 // 装备ID
Breakdowns []uint64 // 故障类型
PlateNumber string // 车牌号
Priority, IsAssist int // 优先级,是否需要上级审批
Remark string // 备注信息
Material []*InstanceLaunchParamsForMaterial
Distribution *InstanceLaunchParamsForDistribution
}
// InstanceLaunchParamsForMaterial 配件信息
InstanceLaunchParamsForMaterial struct {
}
// InstanceLaunchParamsForDistribution 配送信息
InstanceLaunchParamsForDistribution struct {
Name, Mobile, Address string
}
) )
func (c *Instance) publish(reviewer []string) {
utils.TryCatch(func() {
for _, v := range reviewer {
// Socket通知
service.HubMessage.EmitHandle(&service.HubEmit{
ID: v,
Msg: handle.NewWorkNotice("你有一条待办事项"),
})
}
})
}
// List 列表信息 // List 列表信息
func (c *Instance) List(materialID uint64, kind, page, pageSize int) (*basic.PageDataResponse, error) { func (c *Instance) List(materialID uint64, kind, page, pageSize int) (*basic.PageDataResponse, error) {
mWorkInstance := model.NewWorkInstance() mWorkInstance := model.NewWorkInstance()
@ -55,7 +93,164 @@ func (c *Instance) ToDo() {
} }
// Launch 发起工单申请 // Launch 发起工单申请
func (c *Instance) Launch() error { func (c *Instance) Launch(params *InstanceLaunchParams) error {
// 查询产品信息是否存在
mManageEquipment := model.NewManageEquipment()
var count int64
err := model2.Count(mManageEquipment.ManageEquipment, &count, model2.NewWhere("id", params.EquipmentID))
if err != nil {
return err
} else if count <= 0 {
return errors.New("操作错误,该装备信息不存在或已被删除")
}
// 工单信息
mWorkInstance := model.NewWorkInstance()
mWorkInstance.Kind = model2.WorkInstanceKind(params.Kind)
mWorkInstance.Title = params.Title
mWorkInstance.EquipmentID = params.EquipmentID
mWorkInstance.PlateNumber = params.PlateNumber
mWorkInstance.Priority = model2.WorkInstancePriority(params.Priority)
mWorkInstance.IsAssist = model2.WorkInstanceAssist(params.IsAssist)
mWorkInstance.SetBreakdownAttribute(params.Breakdowns)
mWorkInstance.SetDistributionAttribute(&model2.WorkInstanceDistribution{
Name: params.Distribution.Name, Mobile: params.Distribution.Mobile, Address: params.Distribution.Address,
})
mWorkInstance.Remark = params.Remark
// 工单流程信息
mWorkProgress := model.NewWorkProgress()
// 查询工单进度流程
// TODO工单流程
// 第一阶段:创建工单,默认创建时,直接完成
mWorkSchedule := model.NewWorkSchedule()
isExist := false
if isExist, err = mWorkSchedule.FirstSchedule(); err != nil {
return err
} else if !isExist {
return errors.New("操作错误,无工单流程信息,请先核实数据")
}
mWorkInstance.Schedule = mWorkSchedule.ID
// 下一流程
nextWorkSchedule := new(model.WorkScheduleInfo)
if nextWorkSchedule, err = mWorkSchedule.NextSchedule(mWorkInstance.IsAssist == model2.WorkInstanceAssistForYes); err != nil {
return err
}
if nextWorkSchedule == nil {
mWorkInstance.Status = model2.WorkInstanceStatusForComplete
}
return orm.GetDB().Transaction(func(tx *gorm.DB) error {
if err = model2.Create(mWorkInstance.WorkInstance, tx); err != nil {
return err
}
mWorkProgress.UID = c.UID
mWorkProgress.WorkID = mWorkInstance.ID
mWorkProgress.ScheduleID = mWorkInstance.Schedule
mWorkProgress.Status = model2.WorkProgressStatusForAgree
mWorkProgress.Remark = "发起工单"
if err = model2.Create(mWorkProgress.WorkProgress, tx); err != nil {
return err
}
// 创建维修工单
mWorkRepair := model.NewWorkRepair()
mWorkRepair.WorkID = mWorkInstance.ID
if err = model2.Create(mWorkRepair.WorkRepair, tx); err != nil {
return err
}
return nil
})
}
// Examine 审核操作
func (c *Instance) Examine(id uint64, status int, remark string, isAssist int) error {
_status := model2.WorkProgressStatus(status)
if _status != model2.WorkProgressStatusForAgree && _status != model2.WorkProgressStatusForRefuse {
return errors.New("操作错误,审核状态异常")
}
mWorkInstance := model.NewWorkInstance()
mWorkInstance.ID = id
isExist, err := model2.FirstField(mWorkInstance.WorkInstance, []string{"id", "schedule", "status"})
if err != nil {
return err
} else if !isExist {
return errors.New("操作错误,工单信息不存在")
} else if mWorkInstance.Status == model2.WorkInstanceStatusForComplete {
return errors.New("操作错误,当前工单信息已结束")
}
// 查询当前工单所在流程的信息
mWorkSchedule := model.NewWorkSchedule()
mWorkSchedule.ID = mWorkInstance.Schedule
if isExist, err = model2.First(mWorkSchedule); err != nil {
return err
} else if !isExist {
return errors.New("操作错误,未知的工单流程")
}
// 验证审核权限
isAuth := false
if isAuth, err = mWorkSchedule.ValidateAuth(c.UID); err != nil {
return err
} else if !isAuth {
return errors.New("操作错误,无权限审批")
}
if err = orm.GetDB().Transaction(func(tx *gorm.DB) error {
// 工单流程记录
mWorkProgress := model.NewWorkProgress()
mWorkProgress.UID = c.UID
mWorkProgress.WorkID = id
mWorkProgress.ScheduleID = mWorkSchedule.ID
mWorkProgress.Status = _status
mWorkProgress.Remark = remark
if err = model2.Create(mWorkProgress.WorkProgress, tx); err != nil {
return err
}
workUpdates := map[string]interface{}{
"status": model2.WorkInstanceStatusForComplete, "updated_at": time.Now(),
}
// 下一流程
newNextScheduleInfo := new(model.WorkScheduleInfo)
// 拒绝审批,工单直接结束
if _status == model2.WorkProgressStatusForRefuse {
goto FINISH
}
// 下一流程信息
if newNextScheduleInfo, err = mWorkSchedule.NextSchedule(model2.WorkInstanceAssist(isAssist) == model2.WorkInstanceAssistForYes); err != nil {
return err
}
// 无下一流程,工单直接完成
if newNextScheduleInfo == nil || newNextScheduleInfo.ID <= 0 {
goto FINISH
}
workUpdates["status"] = model2.WorkInstanceStatusForOngoing
workUpdates["schedule"] = newNextScheduleInfo.ID
if newNextScheduleInfo.IsNext {
workUpdates["is_assist"] = isAssist
}
// 推送通知
go c.publish(newNextScheduleInfo.Reviewer)
FINISH:
if err = model2.Updates(mWorkInstance.WorkInstance, workUpdates, tx); err != nil {
return err
}
return nil
}); err != nil {
return err
}
return nil return nil
} }

View File

@ -1,16 +1,8 @@
package work package work
import ( import (
model2 "ArmedPolice/app/common/model"
"ArmedPolice/app/controller/basic" "ArmedPolice/app/controller/basic"
"ArmedPolice/app/handle"
"ArmedPolice/app/model"
"ArmedPolice/app/service" "ArmedPolice/app/service"
"ArmedPolice/serve/orm"
"ArmedPolice/utils"
"errors"
"gorm.io/gorm"
"time"
) )
type Person struct{ *service.Session } type Person struct{ *service.Session }
@ -21,99 +13,6 @@ func (c *Person) List() (*basic.PageDataResponse, error) {
return &basic.PageDataResponse{Data: nil, Count: 0}, nil return &basic.PageDataResponse{Data: nil, Count: 0}, nil
} }
// Examine 审核操作
func (c *Person) Examine(id uint64, status int, remark string, isAssist int) error {
_status := model2.WorkProgressStatus(status)
if _status != model2.WorkProgressStatusForAgree && _status != model2.WorkProgressStatusForRefuse {
return errors.New("操作错误,审核状态异常")
}
mWorkInstance := model.NewWorkInstance()
mWorkInstance.ID = id
isExist, err := model2.FirstField(mWorkInstance.WorkInstance, []string{"id", "schedule", "status"})
if err != nil {
return err
} else if !isExist {
return errors.New("操作错误,工单信息不存在")
} else if mWorkInstance.Status == model2.WorkInstanceStatusForComplete {
return errors.New("操作错误,当前工单信息已结束")
}
// 查询当前工单所在流程的信息
mWorkSchedule := model.NewWorkSchedule()
mWorkSchedule.ID = mWorkInstance.Schedule
if isExist, err = model2.First(mWorkSchedule); err != nil {
return err
} else if !isExist {
return errors.New("操作错误,未知的工单流程")
}
// 验证审核权限
isAuth := false
if isAuth, err = mWorkSchedule.ValidateAuth(c.UID); err != nil {
return err
} else if !isAuth {
return errors.New("操作错误,无权限审批")
}
if err = orm.GetDB().Transaction(func(tx *gorm.DB) error {
// 工单流程记录
mWorkProgress := model.NewWorkProgress()
mWorkProgress.UID = c.UID
mWorkProgress.WorkID = id
mWorkProgress.ScheduleID = mWorkSchedule.ID
mWorkProgress.Status = _status
mWorkProgress.Remark = remark
if err = model2.Create(mWorkProgress.WorkProgress, tx); err != nil {
return err
}
workUpdates := map[string]interface{}{
"status": model2.WorkInstanceStatusForComplete, "updated_at": time.Now(),
}
// 下一流程
newNextScheduleInfo := new(model.WorkScheduleInfo)
// 拒绝审批,工单直接结束
if _status == model2.WorkProgressStatusForRefuse {
goto FINISH
}
// 下一流程信息
if newNextScheduleInfo, err = mWorkSchedule.NextSchedule(model2.WorkInstanceAssist(isAssist) == model2.WorkInstanceAssistForYes); err != nil {
return err
}
// 无下一流程,工单直接完成
if newNextScheduleInfo == nil || newNextScheduleInfo.ID <= 0 {
goto FINISH
}
workUpdates["status"] = model2.WorkInstanceStatusForOngoing
workUpdates["schedule"] = newNextScheduleInfo.ID
if newNextScheduleInfo.IsNext {
workUpdates["is_assist"] = isAssist
}
// 推送通知
go utils.TryCatch(func() {
for _, v := range newNextScheduleInfo.Reviewer {
// Socket通知
service.HubMessage.EmitHandle(&service.HubEmit{
ID: v,
Msg: handle.NewWorkNotice("你有一条待办事项"),
})
}
})
FINISH:
if err = model2.Updates(mWorkInstance.WorkInstance, workUpdates, tx); err != nil {
return err
}
return nil
}); err != nil {
return err
}
return nil
}
func NewPerson() PersonHandle { func NewPerson() PersonHandle {
return func(session *service.Session) *Person { return func(session *service.Session) *Person {
return &Person{session} return &Person{session}

View File

@ -15,8 +15,8 @@ type WorkInstance struct {
type WorkInstanceInfo struct { type WorkInstanceInfo struct {
ID uint64 `json:"-"` ID uint64 `json:"-"`
Title string `json:"title"` Title string `json:"title"`
MaterialCode string `json:"material_code"` EquipmentCode string `json:"equipment_code"`
MaterialTitle string `json:"material_title"` EquipmentTitle string `json:"equipment_title"`
BreakdownTitle string `json:"breakdown_title"` BreakdownTitle string `json:"breakdown_title"`
Priority int `json:"priority"` Priority int `json:"priority"`
Status int `json:"status"` Status int `json:"status"`
@ -26,9 +26,9 @@ type WorkInstanceInfo struct {
// Instances 基本信息 // Instances 基本信息
func (m *WorkInstance) Instances(page, pageSize int, count *int64, where ...*model.ModelWhere) ([]*WorkInstanceInfo, error) { func (m *WorkInstance) Instances(page, pageSize int, count *int64, where ...*model.ModelWhere) ([]*WorkInstanceInfo, error) {
db := orm.GetDB().Table(m.TableName()+" AS w"). db := orm.GetDB().Table(m.TableName()+" AS w").
Select("w.id", "w.title", "m.code AS material_code", "m.title AS material_title", "w.priority", Select("w.id", "w.title", "e.code AS equipment_code", "e.title AS equipment_title", "w.priority",
"GROUP_CONCAT(b.title) AS breakdown_title", "w.status", "w.created_at"). "GROUP_CONCAT(b.title) AS breakdown_title", "w.status", "w.created_at").
Joins(fmt.Sprintf("LEFT JOIN %s AS m ON w.material_id = m.id", model.NewManageMaterial().TableName())). Joins(fmt.Sprintf("LEFT JOIN %s AS e ON w.equipment_id = e.id", model.NewManageEquipment().TableName())).
Joins(fmt.Sprintf("LEFT JOIN %s AS b ON FIND_IN_SET(b.id, w.breakdown)", model.NewSysBreakdown().TableName())). Joins(fmt.Sprintf("LEFT JOIN %s AS b ON FIND_IN_SET(b.id, w.breakdown)", model.NewSysBreakdown().TableName())).
Where("w.is_deleted = ?", model.DeleteStatusForNot). Where("w.is_deleted = ?", model.DeleteStatusForNot).
Group("w.id") Group("w.id")

11
app/model/work_repair.go Normal file
View File

@ -0,0 +1,11 @@
package model
import "ArmedPolice/app/common/model"
type WorkRepair struct {
*model.WorkRepair
}
func NewWorkRepair() *WorkRepair {
return &WorkRepair{model.NewWorkRepair()}
}

View File

@ -2,7 +2,9 @@ package model
import ( import (
"ArmedPolice/app/common/model" "ArmedPolice/app/common/model"
"ArmedPolice/serve/orm"
"fmt" "fmt"
"gorm.io/gorm"
) )
type WorkSchedule struct { type WorkSchedule struct {
@ -47,6 +49,21 @@ func (m *WorkSchedule) ValidateAuth(uid uint64) (bool, error) {
return false, nil return false, nil
} }
// FirstSchedule 第一个流程
func (m *WorkSchedule) FirstSchedule() (bool, error) {
db := orm.GetDB().Table(m.TableName()).Select("id", "title", "stage", "step").
Where("is_deleted = ?", model.DeleteStatusForNot).
Order("stage " + model.OrderModeToAsc).Order("step " + model.OrderModeToAsc)
if err := db.First(m.WorkSchedule).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return false, nil
}
return false, err
}
return true, nil
}
// NextSchedule 下一流程 // NextSchedule 下一流程
func (m *WorkSchedule) NextSchedule(isAssets bool) (*WorkScheduleInfo, error) { func (m *WorkSchedule) NextSchedule(isAssets bool) (*WorkScheduleInfo, error) {
next := NewWorkSchedule() next := NewWorkSchedule()