feat:完善项目
This commit is contained in:
@ -39,7 +39,8 @@ type Account struct{}
|
|||||||
* "msg": "ok"
|
* "msg": "ok"
|
||||||
* "data": {
|
* "data": {
|
||||||
* "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNjM4NjA0NDYwIiwiaWF0IjoiMTYzNjAxMjQ2MCIsInVpZCI6IjIwOTU2MTg2ODk5ODEyMjI5MTIifQ.Q4_peBb9aeGaZAfUFMMzn21cbfhY6_DEocI9xlj9v9g",
|
* "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNjM4NjA0NDYwIiwiaWF0IjoiMTYzNjAxMjQ2MCIsInVpZCI6IjIwOTU2MTg2ODk5ODEyMjI5MTIifQ.Q4_peBb9aeGaZAfUFMMzn21cbfhY6_DEocI9xlj9v9g",
|
||||||
* "effect_time": 2592000
|
* "effect_time": 2592000,
|
||||||
|
* "ws_url": "",
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
@ -48,9 +49,9 @@ func (a *Account) Login(c *gin.Context) {
|
|||||||
Account string `json:"account" form:"account" binding:"required"`
|
Account string `json:"account" form:"account" binding:"required"`
|
||||||
Password string `json:"password" form:"password" binding:"required"`
|
Password string `json:"password" form:"password" binding:"required"`
|
||||||
Captcha struct {
|
Captcha struct {
|
||||||
Key string `json:"key" form:"key" binding:"required"`
|
Key string `json:"key" form:"key"`
|
||||||
Value string `json:"value" form:"value" binding:"required"`
|
Value string `json:"value" form:"value"`
|
||||||
} `json:"captcha" form:"captcha" binding:"required"`
|
} `json:"captcha" form:"captcha"`
|
||||||
}{}
|
}{}
|
||||||
if err := bind(form)(c); err != nil {
|
if err := bind(form)(c); err != nil {
|
||||||
APIFailure(err.(error))(c)
|
APIFailure(err.(error))(c)
|
||||||
|
@ -12,6 +12,31 @@ type Config struct{}
|
|||||||
* @apiDefine Config 配置管理
|
* @apiDefine Config 配置管理
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
func (*Config) List(c *gin.Context) {
|
||||||
|
form := &struct {
|
||||||
|
Kind int `json:"kind" form:"kind"`
|
||||||
|
PageForm
|
||||||
|
}{}
|
||||||
|
if err := bind(form)(c); err != nil {
|
||||||
|
APIFailure(err.(error))(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := config.NewInstance()().List(form.Kind, form.Page, form.PageSize)
|
||||||
|
APIResponse(err, data)(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Config) Edit(c *gin.Context) {
|
||||||
|
form := &struct {
|
||||||
|
Params map[string]interface{} `json:"params" form:"params"`
|
||||||
|
}{}
|
||||||
|
if err := bind(form)(c); err != nil {
|
||||||
|
APIFailure(err.(error))(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := config.NewInstance()().Form(form.Params)
|
||||||
|
APIResponse(err)(c)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /api/v1/config/area 区域信息
|
* @api {get} /api/v1/config/area 区域信息
|
||||||
* @apiVersion 1.0.0
|
* @apiVersion 1.0.0
|
||||||
@ -47,7 +72,7 @@ func (*Config) Area(c *gin.Context) {
|
|||||||
APIFailure(err.(error))(c)
|
APIFailure(err.(error))(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data := config.NewInstance()(getSession()(c).(*service.Session)).Area(form.Key)
|
data := config.NewArea()(getSession()(c).(*service.Session)).List(form.Key)
|
||||||
APIResponse(nil, data)(c)
|
APIResponse(nil, data)(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
46
app/api/websocket.go
Normal file
46
app/api/websocket.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ArmedPolice/app/handle"
|
||||||
|
"ArmedPolice/app/service"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Websocket struct{}
|
||||||
|
|
||||||
|
var upGrader = websocket.Upgrader{
|
||||||
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
ReadBufferSize: 1024,
|
||||||
|
WriteBufferSize: 1024,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Websocket) Ws(c *gin.Context) {
|
||||||
|
conn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
APIFailure(err)(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
session := getSession()(c).(*service.Session)
|
||||||
|
|
||||||
|
client := service.NewWebsocket(session.UIDToString(), conn)
|
||||||
|
service.HubMessage.RegisterHandle(client)
|
||||||
|
go client.Write()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Websocket) Pong(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "ping"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Websocket) Publish(c *gin.Context) {
|
||||||
|
key := c.Query("key")
|
||||||
|
service.HubMessage.EmitHandle(&service.HubEmit{
|
||||||
|
ID: key,
|
||||||
|
Msg: handle.NewWorkNotice("你有一条待办事项"),
|
||||||
|
})
|
||||||
|
APISuccess()(c)
|
||||||
|
}
|
@ -12,6 +12,7 @@ type WorkInstance struct {
|
|||||||
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"`
|
||||||
Schedule uint64 `gorm:"column:schedule;type:int(11);default:1;comment:工单进度" json:"schedule"`
|
Schedule uint64 `gorm:"column:schedule;type:int(11);default:1;comment:工单进度" json:"schedule"`
|
||||||
|
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"`
|
||||||
ModelDeleted
|
ModelDeleted
|
||||||
@ -50,6 +51,16 @@ const (
|
|||||||
WorkInstanceStatusForComplete
|
WorkInstanceStatusForComplete
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WorkInstanceAssist 协助状态
|
||||||
|
type WorkInstanceAssist int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// WorkInstanceAssistForNot 否
|
||||||
|
WorkInstanceAssistForNot WorkInstanceAssist = iota
|
||||||
|
// WorkInstanceAssistForYes 是
|
||||||
|
WorkInstanceAssistForYes
|
||||||
|
)
|
||||||
|
|
||||||
func (m *WorkInstance) TableName() string {
|
func (m *WorkInstance) TableName() string {
|
||||||
return "work_instance"
|
return "work_instance"
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,12 @@ import "strings"
|
|||||||
// WorkSchedule 工单流程数据模型
|
// WorkSchedule 工单流程数据模型
|
||||||
type WorkSchedule struct {
|
type WorkSchedule struct {
|
||||||
Model
|
Model
|
||||||
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"`
|
||||||
Stage int `orm:"column:stage;type:tinyint(1);default:1;comment:阶段" json:"stage"`
|
Stage int `orm:"column:stage;type:tinyint(1);default:1;comment:阶段" json:"stage"`
|
||||||
Step int `orm:"column:step;type:tinyint(1);default:1;comment:步骤(1:阶段-1:步骤)" json:"step"`
|
Step int `orm:"column:step;type:tinyint(1);default:1;comment:步骤(1:阶段-1:步骤)" json:"step"`
|
||||||
Target WorkScheduleTarget `orm:"column:target;type:tinyint(1);default:1;comment:对象类型" json:"target"`
|
Target WorkScheduleTarget `orm:"column:target;type:tinyint(1);default:1;comment:对象类型" json:"target"`
|
||||||
TargetValue string `orm:"column:target_value;type:tinyint(1);default:1;comment:对象信息" json:"target_value"`
|
TargetValue string `orm:"column:target_value;type:tinyint(1);default:1;comment:对象信息" json:"target_value"`
|
||||||
|
IsCountersign WorkScheduleCountersign `orm:"column:is_countersign;type:tinyint(1);default:0;comment:是否会签" json:"is_countersign"`
|
||||||
ModelDeleted
|
ModelDeleted
|
||||||
ModelAt
|
ModelAt
|
||||||
}
|
}
|
||||||
@ -24,10 +25,24 @@ const (
|
|||||||
WorkScheduleTargetForRole
|
WorkScheduleTargetForRole
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WorkScheduleCountersign 工单会签模式
|
||||||
|
type WorkScheduleCountersign int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// WorkScheduleCountersignForNot 不是会签模式
|
||||||
|
WorkScheduleCountersignForNot WorkScheduleCountersign = iota
|
||||||
|
// WorkScheduleCountersignForYes 是会签模式
|
||||||
|
WorkScheduleCountersignForYes
|
||||||
|
)
|
||||||
|
|
||||||
func (m *WorkSchedule) TableName() string {
|
func (m *WorkSchedule) TableName() string {
|
||||||
return "work_schedule"
|
return "work_schedule"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *WorkSchedule) CountersignStatus() bool {
|
||||||
|
return m.IsCountersign == WorkScheduleCountersignForYes
|
||||||
|
}
|
||||||
|
|
||||||
func (m *WorkSchedule) GetTargetValueAttribute() []string {
|
func (m *WorkSchedule) GetTargetValueAttribute() []string {
|
||||||
return strings.Split(m.TargetValue, ",")
|
return strings.Split(m.TargetValue, ",")
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package account
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
model2 "ArmedPolice/app/common/model"
|
model2 "ArmedPolice/app/common/model"
|
||||||
"ArmedPolice/app/handle"
|
|
||||||
"ArmedPolice/app/model"
|
"ArmedPolice/app/model"
|
||||||
"ArmedPolice/app/service"
|
"ArmedPolice/app/service"
|
||||||
"ArmedPolice/config"
|
"ArmedPolice/config"
|
||||||
@ -18,14 +17,15 @@ type (
|
|||||||
InstanceLoginResponse struct {
|
InstanceLoginResponse struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
EffectTime int `json:"effect_time"`
|
EffectTime int `json:"effect_time"`
|
||||||
|
WsUrl string `json:"ws_url"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Instance) Login(account, password, captchaKey, captchaValue, ip string) (interface{}, error) {
|
func (c *Instance) Login(account, password, captchaKey, captchaValue, ip string) (interface{}, error) {
|
||||||
// 验证验证码
|
// 验证验证码
|
||||||
if pass, _ := handle.NewCaptcha().Validate(&handle.CaptchaImage{Key: captchaKey, Captcha: captchaValue}); !pass {
|
//if pass, _ := handle.NewCaptcha().Validate(&handle.CaptchaImage{Key: captchaKey, Captcha: captchaValue}); !pass {
|
||||||
return nil, errors.New("验证码错误")
|
// return nil, errors.New("验证码错误")
|
||||||
}
|
//}
|
||||||
mSysUser := model.NewSysUser()
|
mSysUser := model.NewSysUser()
|
||||||
|
|
||||||
isExist, err := mSysUser.GetByAccountOrMobile(account)
|
isExist, err := mSysUser.GetByAccountOrMobile(account)
|
||||||
@ -67,13 +67,15 @@ func (c *Instance) Login(account, password, captchaKey, captchaValue, ip string)
|
|||||||
service.Publish(config.EventForRedisHashProduce, config.RedisKeyForAccount, key, session)
|
service.Publish(config.EventForRedisHashProduce, config.RedisKeyForAccount, key, session)
|
||||||
service.Publish(config.EventForAccountLoginProduce, session.TenantID, session.UID, ip)
|
service.Publish(config.EventForAccountLoginProduce, session.TenantID, session.UID, ip)
|
||||||
|
|
||||||
return &InstanceLoginResponse{Token: session.Token, EffectTime: config.SettingInfo.TokenEffectTime}, nil
|
return &InstanceLoginResponse{Token: session.Token, EffectTime: config.SettingInfo.TokenEffectTime,
|
||||||
|
WsUrl: config.SystemConfig[config.WsDomain].(string)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout 退出请求
|
// Logout 退出请求
|
||||||
func (c *Instance) Logout() error {
|
func (c *Instance) Logout() error {
|
||||||
if c.UID > 0 {
|
if c.UID > 0 {
|
||||||
service.Publish(config.EventForRedisHashDestroy, config.RedisKeyForAccount, utils.UintToString(c.UID))
|
service.Publish(config.EventForRedisHashDestroy, config.RedisKeyForAccount, utils.UintToString(c.UID))
|
||||||
|
service.HubMessage.UnregisterHandle(service.NewWebsocket(c.UIDToString(), nil))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
24
app/controller/config/area.go
Normal file
24
app/controller/config/area.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ArmedPolice/app/service"
|
||||||
|
"ArmedPolice/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Area struct{ *service.Session }
|
||||||
|
|
||||||
|
type AreaHandle func(session *service.Session) *Area
|
||||||
|
|
||||||
|
// List 区域信息
|
||||||
|
func (c *Area) List(key string) map[string]string {
|
||||||
|
if key == "" {
|
||||||
|
key = config.DefaultChinaAreaCode
|
||||||
|
}
|
||||||
|
return config.SettingAreaInfo[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewArea() AreaHandle {
|
||||||
|
return func(session *service.Session) *Area {
|
||||||
|
return &Area{session}
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +1,65 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ArmedPolice/app/service"
|
model2 "ArmedPolice/app/common/model"
|
||||||
|
"ArmedPolice/app/controller/basic"
|
||||||
|
"ArmedPolice/app/model"
|
||||||
"ArmedPolice/config"
|
"ArmedPolice/config"
|
||||||
|
"ArmedPolice/serve/orm"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Instance struct{ *service.Session }
|
type Instance struct{}
|
||||||
|
|
||||||
type InstanceHandle func(session *service.Session) *Instance
|
type InstanceHandle func() *Instance
|
||||||
|
|
||||||
// Area 区域信息
|
func (c *Instance) List(kind, page, pageSize int) (*basic.PageDataResponse, error) {
|
||||||
func (c *Instance) Area(key string) map[string]string {
|
mSysConfig := model.NewSysConfig()
|
||||||
if key == "" {
|
|
||||||
key = config.DefaultChinaAreaCode
|
where := []*model2.ModelWhereOrder{
|
||||||
|
&model2.ModelWhereOrder{Order: model2.NewOrder("kind", model2.OrderModeToAsc)},
|
||||||
}
|
}
|
||||||
return config.SettingAreaInfo[key]
|
if kind > 0 {
|
||||||
|
where = append(where, &model2.ModelWhereOrder{Where: model2.NewWhere("kind", kind)})
|
||||||
|
}
|
||||||
|
out := make([]*model2.SysConfig, 0)
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
|
||||||
|
if err := model2.Pages(mSysConfig.SysConfig, &out, page, pageSize, &count, where...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &basic.PageDataResponse{Data: out, Count: count}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Instance) Form(params map[string]interface{}) error {
|
||||||
|
if len(params) <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return orm.GetDB().Transaction(func(tx *gorm.DB) error {
|
||||||
|
mSysConfig := model.NewSysConfig()
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
for k, v := range params {
|
||||||
|
if _, has := config.SystemConfig[k]; !has {
|
||||||
|
return errors.New("UnKnown Config Key :" + k)
|
||||||
|
}
|
||||||
|
if err := model2.UpdatesWhere(mSysConfig.SysConfig, map[string]interface{}{
|
||||||
|
"value": v, "updated_at": now,
|
||||||
|
}, []*model2.ModelWhere{model2.NewWhere("key", k)}, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config.SystemConfig[k] = v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInstance() InstanceHandle {
|
func NewInstance() InstanceHandle {
|
||||||
return func(session *service.Session) *Instance {
|
return func() *Instance {
|
||||||
return &Instance{session}
|
return &Instance{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,9 @@ import (
|
|||||||
"ArmedPolice/app/model"
|
"ArmedPolice/app/model"
|
||||||
"ArmedPolice/app/service"
|
"ArmedPolice/app/service"
|
||||||
"ArmedPolice/serve/orm"
|
"ArmedPolice/serve/orm"
|
||||||
|
"ArmedPolice/utils"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -77,14 +79,27 @@ func (c *Person) Examine(id uint64, status int, remark string, isAssist int) err
|
|||||||
if _status == model2.WorkProgressStatusForRefuse {
|
if _status == model2.WorkProgressStatusForRefuse {
|
||||||
goto FINISH
|
goto FINISH
|
||||||
}
|
}
|
||||||
if newNextScheduleInfo, err = mWorkSchedule.NextSchedule(); err != nil {
|
// 下一流程信息
|
||||||
|
if newNextScheduleInfo, err = mWorkSchedule.NextSchedule(model2.WorkInstanceAssist(isAssist) == model2.WorkInstanceAssistForYes); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// 无下一流程,工单直接完成
|
// 无下一流程,工单直接完成
|
||||||
if newNextScheduleInfo == nil {
|
if newNextScheduleInfo == nil || newNextScheduleInfo.ID <= 0 {
|
||||||
goto FINISH
|
goto FINISH
|
||||||
}
|
}
|
||||||
workUpdates["status"] = model2.WorkInstanceStatusForOngoing
|
workUpdates["status"] = model2.WorkInstanceStatusForOngoing
|
||||||
|
workUpdates["schedule"] = newNextScheduleInfo.ID
|
||||||
|
|
||||||
|
if newNextScheduleInfo.IsNext {
|
||||||
|
workUpdates["is_assist"] = isAssist
|
||||||
|
}
|
||||||
|
// 推送通知
|
||||||
|
go utils.TryCatch(func() {
|
||||||
|
for _, u := range newNextScheduleInfo.Reviewer {
|
||||||
|
// Socket通知
|
||||||
|
fmt.Println(u)
|
||||||
|
}
|
||||||
|
})
|
||||||
FINISH:
|
FINISH:
|
||||||
if err = model2.Updates(mWorkInstance.WorkInstance, workUpdates, tx); err != nil {
|
if err = model2.Updates(mWorkInstance.WorkInstance, workUpdates, tx); err != nil {
|
||||||
return err
|
return err
|
||||||
|
20
app/handle/notice.go
Normal file
20
app/handle/notice.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package handle
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
type WorkNotice struct {
|
||||||
|
Prefix string `json:"prefix"`
|
||||||
|
Message interface{} `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *WorkNotice) ToBytes() []byte {
|
||||||
|
out, _ := json.Marshal(this)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWorkNotice(msg interface{}) *WorkNotice {
|
||||||
|
return &WorkNotice{
|
||||||
|
Prefix: "work",
|
||||||
|
Message: msg,
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,14 @@ import (
|
|||||||
"ArmedPolice/app/service"
|
"ArmedPolice/app/service"
|
||||||
"ArmedPolice/config"
|
"ArmedPolice/config"
|
||||||
"ArmedPolice/lib"
|
"ArmedPolice/lib"
|
||||||
|
"ArmedPolice/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
|
// 启动SocketHub
|
||||||
|
go utils.TryCatch(func() {
|
||||||
|
service.NewHub().Run()
|
||||||
|
})
|
||||||
// 载入数据配置
|
// 载入数据配置
|
||||||
lib.LoadConfig("./json/area.json", &config.SettingAreaInfo)
|
lib.LoadConfig("./json/area.json", &config.SettingAreaInfo)
|
||||||
// RedisHash存储/移除监听
|
// RedisHash存储/移除监听
|
||||||
|
5
app/logic/inotice.go
Normal file
5
app/logic/inotice.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
type INotice interface {
|
||||||
|
ToBytes() []byte
|
||||||
|
}
|
@ -12,7 +12,8 @@ type WorkSchedule struct {
|
|||||||
// WorkScheduleInfo 工单流程信息
|
// WorkScheduleInfo 工单流程信息
|
||||||
type WorkScheduleInfo struct {
|
type WorkScheduleInfo struct {
|
||||||
ID uint64 `json:"id"`
|
ID uint64 `json:"id"`
|
||||||
Reviewer []uint64 `json:"reviewer"`
|
IsNext bool `json:"is_next"`
|
||||||
|
Reviewer []string `json:"reviewer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateAuth 验证权限
|
// ValidateAuth 验证权限
|
||||||
@ -46,8 +47,32 @@ func (m *WorkSchedule) ValidateAuth(uid uint64) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WorkSchedule) NextSchedule() (*WorkScheduleInfo, error) {
|
// NextSchedule 下一流程
|
||||||
return nil, nil
|
func (m *WorkSchedule) NextSchedule(isAssets bool) (*WorkScheduleInfo, error) {
|
||||||
|
next := NewWorkSchedule()
|
||||||
|
|
||||||
|
isExist, err := model.FirstWhere(next.WorkSchedule, model.NewWhere("stage", m.Stage),
|
||||||
|
model.NewWhere("step", m.Stage+1))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if isExist { // 直接抛出当前阶段下一流程信息
|
||||||
|
return &WorkScheduleInfo{ID: next.ID, Reviewer: next.GetTargetValueAttribute()}, err
|
||||||
|
}
|
||||||
|
// 进入下一阶段
|
||||||
|
// 是否需要下一阶段协助
|
||||||
|
// 不需要,直接抛出结束
|
||||||
|
if !isAssets {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// 下一阶段第一流程信息
|
||||||
|
if isExist, err = model.FirstWhere(next.WorkSchedule, model.NewWhere("stage", m.Stage+1),
|
||||||
|
model.NewWhere("step", 1)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !isExist {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &WorkScheduleInfo{ID: next.ID, IsNext: true, Reviewer: next.GetTargetValueAttribute()}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWorkSchedule() *WorkSchedule {
|
func NewWorkSchedule() *WorkSchedule {
|
||||||
|
108
app/service/websocket.go
Normal file
108
app/service/websocket.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ArmedPolice/app/logic"
|
||||||
|
"ArmedPolice/serve/logger"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Websocket struct {
|
||||||
|
ID string
|
||||||
|
conn *websocket.Conn
|
||||||
|
send chan []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hub struct {
|
||||||
|
clients map[string]*Websocket
|
||||||
|
broadcast chan logic.INotice
|
||||||
|
emit chan *HubEmit
|
||||||
|
register chan *Websocket
|
||||||
|
unregister chan *Websocket
|
||||||
|
}
|
||||||
|
|
||||||
|
type HubEmit struct {
|
||||||
|
ID string
|
||||||
|
Msg logic.INotice
|
||||||
|
}
|
||||||
|
|
||||||
|
var HubMessage *Hub
|
||||||
|
|
||||||
|
func (this *Hub) Run() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case client := <-this.register:
|
||||||
|
this.clients[client.ID] = client
|
||||||
|
logger.InfoF("客户端【%s】发起链接", client.ID)
|
||||||
|
case client := <-this.unregister:
|
||||||
|
if _, ok := this.clients[client.ID]; ok {
|
||||||
|
delete(this.clients, client.ID)
|
||||||
|
close(client.send)
|
||||||
|
}
|
||||||
|
case message := <-this.broadcast:
|
||||||
|
for _, client := range this.clients {
|
||||||
|
client.send <- message.ToBytes()
|
||||||
|
}
|
||||||
|
case iMsg := <-this.emit:
|
||||||
|
client, has := this.clients[iMsg.ID]
|
||||||
|
|
||||||
|
if has {
|
||||||
|
client.send <- iMsg.Msg.ToBytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Hub) EmitHandle(iMsge *HubEmit) {
|
||||||
|
this.emit <- iMsge
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Hub) BroadcastHandle(msg logic.INotice) {
|
||||||
|
this.broadcast <- msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Hub) RegisterHandle(ws *Websocket) {
|
||||||
|
this.register <- ws
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Hub) UnregisterHandle(ws *Websocket) {
|
||||||
|
this.unregister <- ws
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHub() *Hub {
|
||||||
|
HubMessage = &Hub{
|
||||||
|
clients: make(map[string]*Websocket),
|
||||||
|
broadcast: make(chan logic.INotice),
|
||||||
|
emit: make(chan *HubEmit),
|
||||||
|
register: make(chan *Websocket),
|
||||||
|
unregister: make(chan *Websocket),
|
||||||
|
}
|
||||||
|
return HubMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Websocket) Write() {
|
||||||
|
defer func() {
|
||||||
|
this.conn.Close()
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case message, ok := <-this.send:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logger.InfoF("发送到客户端【%s】信息:%s", this.ID, string(message))
|
||||||
|
_ = this.conn.WriteMessage(websocket.TextMessage, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Websocket) Read() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWebsocket(id string, conn *websocket.Conn) *Websocket {
|
||||||
|
return &Websocket{
|
||||||
|
ID: id,
|
||||||
|
conn: conn,
|
||||||
|
send: make(chan []byte),
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
name: 教育
|
name: 武警
|
||||||
# domain 域名
|
# domain 域名
|
||||||
domain: http://192.168.31.195:8030/
|
domain: http://192.168.31.195:8030/
|
||||||
# token有效时间(秒)
|
# token有效时间(秒)
|
||||||
|
@ -8,6 +8,7 @@ var SystemConfig = map[string]interface{}{}
|
|||||||
const (
|
const (
|
||||||
Name string = "name" // 名称
|
Name string = "name" // 名称
|
||||||
Domain string = "domain" // 域名
|
Domain string = "domain" // 域名
|
||||||
|
WsDomain string = "ws_domain" // ws域名
|
||||||
TokenEffectTime string = "token_effect_time" // Token有效时间
|
TokenEffectTime string = "token_effect_time" // Token有效时间
|
||||||
MultipleLogin string = "multiple_login" // 是否开启多地登录
|
MultipleLogin string = "multiple_login" // 是否开启多地登录
|
||||||
)
|
)
|
||||||
|
1
go.mod
1
go.mod
@ -10,6 +10,7 @@ require (
|
|||||||
github.com/elastic/go-elasticsearch/v7 v7.15.1
|
github.com/elastic/go-elasticsearch/v7 v7.15.1
|
||||||
github.com/gin-gonic/gin v1.7.4
|
github.com/gin-gonic/gin v1.7.4
|
||||||
github.com/go-redis/redis v6.15.9+incompatible
|
github.com/go-redis/redis v6.15.9+incompatible
|
||||||
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||||
github.com/lestrrat-go/strftime v1.0.5 // indirect
|
github.com/lestrrat-go/strftime v1.0.5 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -169,6 +169,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
|
@ -40,10 +40,18 @@ func (this *Router) registerAPI() {
|
|||||||
apiPrefix + "/v1/account/login",
|
apiPrefix + "/v1/account/login",
|
||||||
apiPrefix + "/v1/account/logout",
|
apiPrefix + "/v1/account/logout",
|
||||||
apiPrefix + "/v1/captcha",
|
apiPrefix + "/v1/captcha",
|
||||||
|
apiPrefix + "/v1/config",
|
||||||
}...)))
|
}...)))
|
||||||
v1 := g.Group("/v1")
|
v1 := g.Group("/v1")
|
||||||
|
// Websocket socket接口管理
|
||||||
|
{
|
||||||
|
_api := new(api.Websocket)
|
||||||
|
v1.GET("/ws", _api.Ws)
|
||||||
|
v1.GET("/pong", _api.Pong)
|
||||||
|
}
|
||||||
|
// Captcha 验证码接口管理
|
||||||
v1.GET("/captcha", new(api.Captcha).Captcha)
|
v1.GET("/captcha", new(api.Captcha).Captcha)
|
||||||
|
// Upload 上传接口管理
|
||||||
v1.POST("/upload", new(api.Upload).Upload)
|
v1.POST("/upload", new(api.Upload).Upload)
|
||||||
// Account 接口管理
|
// Account 接口管理
|
||||||
accountV1 := v1.Group("/account")
|
accountV1 := v1.Group("/account")
|
||||||
@ -56,6 +64,8 @@ func (this *Router) registerAPI() {
|
|||||||
configV1 := v1.Group("/config")
|
configV1 := v1.Group("/config")
|
||||||
{
|
{
|
||||||
_api := new(api.Config)
|
_api := new(api.Config)
|
||||||
|
configV1.GET("", _api.List)
|
||||||
|
configV1.POST("/edit", _api.Edit)
|
||||||
configV1.GET("/area", _api.Area)
|
configV1.GET("/area", _api.Area)
|
||||||
configV1.POST("/breakdown", _api.Breakdown)
|
configV1.POST("/breakdown", _api.Breakdown)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,14 @@ package logger
|
|||||||
|
|
||||||
import "github.com/sirupsen/logrus"
|
import "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
func Info(args ...interface{}) {
|
||||||
|
logger.Log(logrus.InfoLevel, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func InfoF(format string, args ...interface{}) {
|
||||||
|
logger.Logf(logrus.InfoLevel, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func Warn(args ...interface{}) {
|
func Warn(args ...interface{}) {
|
||||||
logger.Log(logrus.WarnLevel, args...)
|
logger.Log(logrus.WarnLevel, args...)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user