feat:完善项目

This commit is contained in:
henry
2021-11-08 15:52:46 +08:00
parent 1502076841
commit 1cc95fb5ca
16 changed files with 154 additions and 64 deletions

View File

@ -126,11 +126,30 @@ func (*Config) Breakdown(c *gin.Context) {
} }
func (*Config) BreakdownAdd(c *gin.Context) { func (*Config) BreakdownAdd(c *gin.Context) {
form := &struct {
Title string `json:"title" form:"title" binding:"required"`
Remark string `json:"remark" form:"remark"`
}{}
if err := bind(form)(c); err != nil {
APIFailure(err.(error))(c)
return
}
err := config.NewBreakdown()(getSession()(c).(*service.Session)).Form(0, form.Title, form.Remark)
APIResponse(err)(c)
} }
func (*Config) BreakdownEdit(c *gin.Context) { func (*Config) BreakdownEdit(c *gin.Context) {
form := &struct {
IDStringForm
Title string `json:"title" form:"title" binding:"required"`
Remark string `json:"remark" form:"remark"`
}{}
if err := bind(form)(c); err != nil {
APIFailure(err.(error))(c)
return
}
err := config.NewBreakdown()(getSession()(c).(*service.Session)).Form(form.Convert(), form.Title, form.Remark)
APIResponse(err)(c)
} }
func (*Config) BreakdownDelete(c *gin.Context) { func (*Config) BreakdownDelete(c *gin.Context) {

View File

@ -40,7 +40,7 @@ type (
* @apiSuccess (200) {Number} code 成功响应状态码! * @apiSuccess (200) {Number} code 成功响应状态码!
* @apiSuccess (200) {String} msg 成功提示 * @apiSuccess (200) {String} msg 成功提示
* @apiSuccess (200) {Array} data 具体信息 * @apiSuccess (200) {Array} data 具体信息
* @apiSuccess (200) {Number} data.id 菜单ID * @apiSuccess (200) {String} data.id 菜单ID
* @apiSuccess (200) {Number} data.parent_id 父级ID * @apiSuccess (200) {Number} data.parent_id 父级ID
* @apiSuccess (200) {String} data.name 菜单名称 * @apiSuccess (200) {String} data.name 菜单名称
* @apiSuccess (200) {Number} data.kind 类型1目录2菜单 * @apiSuccess (200) {Number} data.kind 类型1目录2菜单
@ -54,7 +54,7 @@ type (
* "code": 200 * "code": 200
* "msg": "ok" * "msg": "ok"
* "data": [ * "data": [
* "id": 1, * "id": "qeqwe",
* "parent_id": 0, * "parent_id": 0,
* "name": "系统管理", * "name": "系统管理",
* "kind": 1, * "kind": 1,
@ -62,7 +62,7 @@ type (
* "component": "" * "component": ""
* "children": [ * "children": [
* { * {
* "id": 2, * "id": "23123asqw",
* "parent_id": 1, * "parent_id": 1,
* "name": "用户管理", * "name": "用户管理",
* "kind": 1, * "kind": 1,

View File

@ -105,6 +105,8 @@ func (a *Role) Delete(c *gin.Context) {
* *
* @apiHeader {string} x-token token * @apiHeader {string} x-token token
* *
* @apiParam {Number} role_id 角色ID
*
* @apiSuccess (200) {Number} code 成功响应状态码! * @apiSuccess (200) {Number} code 成功响应状态码!
* @apiSuccess (200) {String} msg 成功提示 * @apiSuccess (200) {String} msg 成功提示
* @apiSuccess (200) {Array} data 具体信息 * @apiSuccess (200) {Array} data 具体信息
@ -144,13 +146,15 @@ func (a *Role) Delete(c *gin.Context) {
*/ */
func (a *Role) Menu(c *gin.Context) { func (a *Role) Menu(c *gin.Context) {
form := &struct { form := &struct {
RoleID uint64 `json:"role_id" form:"role_id" binding:"required"` RoleID string `json:"role_id" form:"role_id" binding:"required"`
}{} }{}
if err := bind(form)(c); err != nil { if err := bind(form)(c); err != nil {
APIFailure(err.(error))(c) APIFailure(err.(error))(c)
return return
} }
data, err := role.NewMenu()(getSession()(c).(*service.Session)).List(form.RoleID) obj := new(IDStringForm)
obj.ID = form.RoleID
data, err := role.NewMenu()(getSession()(c).(*service.Session)).List(obj.Convert())
APIResponse(err, data)(c) APIResponse(err, data)(c)
} }
@ -178,21 +182,22 @@ func (a *Role) Menu(c *gin.Context) {
*/ */
func (a *Role) MenuBind(c *gin.Context) { func (a *Role) MenuBind(c *gin.Context) {
form := &struct { form := &struct {
RoleID uint64 `json:"role_id" form:"role_id" binding:"required"` RoleID string `json:"role_id" form:"role_id" binding:"required"`
MenuIDs []string `json:"menu_ids" form:"menu_ids" binding:"required"` MenuIDs []string `json:"menu_ids" form:"menu_ids" binding:"required"`
}{} }{}
if err := bind(form)(c); err != nil { if err := bind(form)(c); err != nil {
APIFailure(err.(error))(c) APIFailure(err.(error))(c)
return return
} }
menuIDs := make([]uint64, 0)
handle := new(IDStringForm) handle := new(IDStringForm)
handle.ID = form.RoleID
roleID := handle.Convert()
menuIDs := make([]uint64, 0)
for _, v := range form.MenuIDs { for _, v := range form.MenuIDs {
handle.ID = v handle.ID = v
menuIDs = append(menuIDs, handle.Convert()) menuIDs = append(menuIDs, handle.Convert())
} }
err := role.NewMenu()(getSession()(c).(*service.Session)).Bind(form.RoleID, menuIDs) err := role.NewMenu()(getSession()(c).(*service.Session)).Bind(roleID, menuIDs)
APIResponse(err)(c) APIResponse(err)(c)
} }

View File

@ -3,6 +3,8 @@ package api
import ( import (
"ArmedPolice/app/handle" "ArmedPolice/app/handle"
"ArmedPolice/app/service" "ArmedPolice/app/service"
"ArmedPolice/config"
"errors"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"net/http" "net/http"
@ -25,8 +27,18 @@ func (*Websocket) Ws(c *gin.Context) {
APIFailure(err)(c) APIFailure(err)(c)
return return
} }
session := getSession()(c).(*service.Session) token := c.Query(config.APIRequestToken)
if token == "" {
APIFailure(errors.New("Token异常"))(c)
return
}
session := new(service.Session)
if session, err = service.NewAuthToken(token).Auth(); err != nil {
APIFailure(err)(c)
return
}
client := service.NewWebsocket(session.UIDToString(), conn) client := service.NewWebsocket(session.UIDToString(), conn)
service.HubMessage.RegisterHandle(client) service.HubMessage.RegisterHandle(client)
go client.Write() go client.Write()

View File

@ -12,6 +12,9 @@ import (
type Work struct{} type Work struct{}
type workLaunchForm struct {
}
/** /**
* @api {post} /api/v1/work/list 工单信息 * @api {post} /api/v1/work/list 工单信息
* @apiVersion 1.0.0 * @apiVersion 1.0.0
@ -76,7 +79,18 @@ func (*Work) ToDo(c *gin.Context) {
} }
func (*Work) Launch(c *gin.Context) { func (*Work) Launch(c *gin.Context) {
form := &struct {
IDStringForm
Status int `json:"status" form:"status" binding:"required"`
Remark string `json:"remark" form:"remark"`
IsAssist int `json:"is_assist" form:"is_assist"`
}{}
if err := bind(form)(c); err != nil {
APIFailure(err.(error))(c)
return
}
err := work.NewInstance()(getSession()(c).(*service.Session)).Launch()
APIResponse(err)
} }
func (*Work) Examine(c *gin.Context) { func (*Work) Examine(c *gin.Context) {

View File

@ -12,6 +12,7 @@ import (
// IModel // IModel
type IModel interface { type IModel interface {
SetID(id uint64)
GetID() uint64 GetID() uint64
GetEncodeID() string GetEncodeID() string
TableName() string TableName() string
@ -60,6 +61,10 @@ const (
FieldsForDeleted string = "is_deleted" FieldsForDeleted string = "is_deleted"
) )
func (m *Model) SetID(id uint64) {
m.ID = id
}
func (m *Model) GetID() uint64 { func (m *Model) GetID() uint64 {
return m.ID return m.ID
} }

View File

@ -15,6 +15,7 @@ type InstanceHandle func(session *service.Session) *Instance
type ( type (
// InstanceInfo 菜单信息 // InstanceInfo 菜单信息
InstanceInfo struct { InstanceInfo struct {
ID string `json:"id"`
*model2.SysMenu *model2.SysMenu
Children []*InstanceInfo `json:"children"` Children []*InstanceInfo `json:"children"`
} }
@ -42,6 +43,7 @@ func (c *Instance) tree(src []*model2.SysMenu, parentID uint64) []*InstanceInfo
for _, v := range src { for _, v := range src {
if v.ParentID == parentID { if v.ParentID == parentID {
out = append(out, &InstanceInfo{ out = append(out, &InstanceInfo{
ID: v.GetEncodeID(),
SysMenu: v, SysMenu: v,
Children: c.tree(src, v.ID), Children: c.tree(src, v.ID),
}) })
@ -51,15 +53,17 @@ func (c *Instance) tree(src []*model2.SysMenu, parentID uint64) []*InstanceInfo
} }
// TreeIdentity 树状筛选 // TreeIdentity 树状筛选
func TreeIdentity(src []*model.SysMenuScene, parentID uint64) []*InstanceIdentityInfo { func TreeIdentity(iModel model2.IModel, src []*model.SysMenuScene, parentID uint64) []*InstanceIdentityInfo {
out := make([]*InstanceIdentityInfo, 0) out := make([]*InstanceIdentityInfo, 0)
for _, v := range src { for _, v := range src {
if v.ParentID == parentID { if v.ParentID == parentID {
iModel.SetID(v.ID)
out = append(out, &InstanceIdentityInfo{ out = append(out, &InstanceIdentityInfo{
ID: iModel.GetEncodeID(),
SysMenuBasic: v.SysMenuBasic, SysMenuBasic: v.SysMenuBasic,
Checked: v.SceneID > 0, Checked: v.SceneID > 0,
Children: TreeIdentity(src, v.ID), Children: TreeIdentity(iModel, src, v.ID),
}) })
} }
} }

View File

@ -22,7 +22,7 @@ func (c *Menu) List(roleID uint64) ([]*menu.InstanceIdentityInfo, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return menu.TreeIdentity(out, 0), nil return menu.TreeIdentity(mSysMenu.SysMenu, out, 0), nil
} }
// Bind 绑定菜单 // Bind 绑定菜单

View File

@ -27,7 +27,7 @@ func (c *Menu) Menu() ([]*menu.InstanceIdentityInfo, error) {
return nil, err return nil, err
} }
RETURN: RETURN:
return menu.TreeIdentity(out, 0), nil return menu.TreeIdentity(mSysMenu.SysMenu, out, 0), nil
} }
func NewMenu() MenuHandle { func NewMenu() MenuHandle {

View File

@ -54,7 +54,8 @@ func (c *Instance) ToDo() {
} }
func (c *Instance) Form() error { // Launch 发起工单申请
func (c *Instance) Launch() error {
return nil return nil
} }

View File

@ -3,12 +3,12 @@ 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/serve/orm"
"ArmedPolice/utils" "ArmedPolice/utils"
"errors" "errors"
"fmt"
"gorm.io/gorm" "gorm.io/gorm"
"time" "time"
) )
@ -95,9 +95,12 @@ func (c *Person) Examine(id uint64, status int, remark string, isAssist int) err
} }
// 推送通知 // 推送通知
go utils.TryCatch(func() { go utils.TryCatch(func() {
for _, u := range newNextScheduleInfo.Reviewer { for _, v := range newNextScheduleInfo.Reviewer {
// Socket通知 // Socket通知
fmt.Println(u) service.HubMessage.EmitHandle(&service.HubEmit{
ID: v,
Msg: handle.NewWorkNotice("你有一条待办事项"),
})
} }
}) })
FINISH: FINISH:

47
app/service/auth.go Normal file
View File

@ -0,0 +1,47 @@
package service
import (
"ArmedPolice/config"
cache2 "ArmedPolice/serve/cache"
"ArmedPolice/utils"
"errors"
"fmt"
"time"
)
type AuthToken struct {
Token string `json:"token"`
}
func (this *AuthToken) Auth() (*Session, error) {
tokenInfo := utils.JWTDecrypt(this.Token)
if tokenInfo == nil || len(tokenInfo) <= 0 {
return nil, errors.New("Token无效")
}
expTimestamp := utils.StringToInt64(fmt.Sprintf("%v", tokenInfo["exp"]))
expTime := time.Unix(expTimestamp, 0)
ok := expTime.After(time.Now())
if !ok {
return nil, errors.New("Token过期")
}
cache, _ := cache2.Cache.HGet(config.RedisKeyForAccount, fmt.Sprintf("%v", tokenInfo[config.TokenForUID]))
if cache == "" {
return nil, errors.New("用户未登录或已退出")
}
session := new(Session)
_ = session.UnmarshalBinary([]byte(cache))
if !config.SettingInfo.MultipleLogin && session.Token != this.Token {
return nil, errors.New("登录失效,已在其他地方登录!")
}
return session, nil
}
func NewAuthToken(token string) *AuthToken {
return &AuthToken{
Token: token,
}
}

View File

@ -40,7 +40,12 @@ func (this *Hub) Run() {
} }
case message := <-this.broadcast: case message := <-this.broadcast:
for _, client := range this.clients { for _, client := range this.clients {
client.send <- message.ToBytes() select {
case client.send <- message.ToBytes():
default:
close(client.send)
delete(this.clients, client.ID)
}
} }
case iMsg := <-this.emit: case iMsg := <-this.emit:
client, has := this.clients[iMsg.ID] client, has := this.clients[iMsg.ID]

View File

@ -3,13 +3,9 @@ package router
import ( import (
"ArmedPolice/app/service" "ArmedPolice/app/service"
"ArmedPolice/config" "ArmedPolice/config"
cache2 "ArmedPolice/serve/cache"
"ArmedPolice/utils" "ArmedPolice/utils"
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/http"
) )
// SkipperURL 跳过验证 // SkipperURL 跳过验证
@ -40,34 +36,10 @@ func NeedLogin(skipperURL ...SkipperURL) gin.HandlerFunc {
c.Abort() c.Abort()
return return
} }
tokenInfo := utils.JWTDecrypt(token) session, err := service.NewAuthToken(token).Auth()
if tokenInfo == nil || len(tokenInfo) <= 0 { if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"message": "Token无效"}) c.JSON(http.StatusUnauthorized, gin.H{"message": err.Error()})
c.Abort()
return
}
expTimestamp := utils.StringToInt64(fmt.Sprintf("%v", tokenInfo["exp"]))
expTime := time.Unix(expTimestamp, 0)
ok := expTime.After(time.Now())
if !ok {
c.JSON(http.StatusUnauthorized, gin.H{"message": "Token过期"})
c.Abort()
return
}
cache, _ := cache2.Cache.HGet(config.RedisKeyForAccount, fmt.Sprintf("%v", tokenInfo[config.TokenForUID]))
if cache == "" {
c.JSON(http.StatusUnauthorized, gin.H{"message": "用户未登录或已退出"})
c.Abort()
return
}
session := new(service.Session)
_ = session.UnmarshalBinary([]byte(cache))
if !config.SettingInfo.MultipleLogin && session.Token != token {
c.JSON(http.StatusUnauthorized, gin.H{"message": "登录失效,已在其他地方登录!"})
c.Abort() c.Abort()
return return
} }

View File

@ -46,8 +46,9 @@ func (this *Router) registerAPI() {
// Websocket socket接口管理 // Websocket socket接口管理
{ {
_api := new(api.Websocket) _api := new(api.Websocket)
v1.GET("/ws", _api.Ws) this.handler.GET("/ws", _api.Ws)
v1.GET("/pong", _api.Pong) this.handler.GET("/pong", _api.Pong)
this.handler.GET("/publish", _api.Publish)
} }
// Captcha 验证码接口管理 // Captcha 验证码接口管理
v1.GET("/captcha", new(api.Captcha).Captcha) v1.GET("/captcha", new(api.Captcha).Captcha)
@ -68,6 +69,8 @@ func (this *Router) registerAPI() {
configV1.POST("/edit", _api.Edit) 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)
configV1.POST("/breakdown/add", _api.BreakdownAdd)
configV1.POST("/breakdown/edit", _api.BreakdownEdit)
} }
// Tenant 租户单位管理 // Tenant 租户单位管理
tenantV1 := v1.Group("/tenant") tenantV1 := v1.Group("/tenant")

View File

@ -42,18 +42,18 @@ func (this *Logger) Load() {
func (this *Logger) Init(option *Option) *Logger { func (this *Logger) Init(option *Option) *Logger {
this.Option = option this.Option = option
logger = log.New() _logger := log.New()
logger.SetFormatter(&log.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"}) _logger.SetFormatter(&log.JSONFormatter{TimestampFormat: "2006-01-02 15:04:05"})
logger.SetReportCaller(true) _logger.SetReportCaller(true)
logger.AddHook(NewHook(this.File, 0, this.LeastDay)) _logger.AddHook(NewHook(this.File, 0, this.LeastDay))
if this.IsStdout { if this.IsStdout {
logger.SetOutput(io.MultiWriter(os.Stdout)) _logger.SetOutput(io.MultiWriter(os.Stdout))
} }
logger.SetFormatter(formatter(true)) _logger.SetFormatter(formatter(true))
logger.SetLevel(this.level()) _logger.SetLevel(this.level())
this.Logger = logger this.Logger = _logger
return this return this
} }