add 站内通知、私信、websocket服务

This commit is contained in:
yxh 2024-01-02 17:50:07 +08:00
parent 8efecfb712
commit 1ddb117172
38 changed files with 2311 additions and 27 deletions

133
api/v1/system/sys_notice.go Normal file
View File

@ -0,0 +1,133 @@
// ==========================================================================
// GFast自动生成api操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: api/v1/system/sys_notice.go
// 生成人gfast
// desc:通知公告相关参数
// company:云南奇讯科技有限公司
// ==========================================================================
package system
import (
"github.com/gogf/gf/v2/frame/g"
commonApi "github.com/tiger1103/gfast/v3/api/v1/common"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
)
// SysNoticeSearchReq 分页请求参数
type SysNoticeSearchReq struct {
g.Meta `path:"/list" tags:"通知私信" method:"get" summary:"通知公告列表(管理)"`
commonApi.Author
model.SysNoticeSearchReq
}
// SysNoticeSearchRes 列表返回结果
type SysNoticeSearchRes struct {
g.Meta `mime:"application/json"`
*model.SysNoticeSearchRes
}
// SysNoticeSearchReq 分页请求参数
type SysNoticeShowSearchReq struct {
g.Meta `path:"/listShow" tags:"通知私信" method:"get" summary:"通知公告列表(浏览)"`
commonApi.Author
model.SysNoticeSearchReq
}
// SysNoticeSearchRes 列表返回结果
type SysNoticeShowSearchRes struct {
g.Meta `mime:"application/json"`
*model.SysNoticeSearchRes
}
// SysNoticeAddReq 添加操作请求参数
type SysNoticeAddReq struct {
g.Meta `path:"/add" tags:"通知私信" method:"post" summary:"通知公告添加"`
commonApi.Author
*model.SysNoticeAddReq
}
// SysNoticeAddRes 添加操作返回结果
type SysNoticeAddRes struct {
commonApi.EmptyRes
}
// SysNoticeEditReq 修改操作请求参数
type SysNoticeEditReq struct {
g.Meta `path:"/edit" tags:"通知私信" method:"put" summary:"通知公告修改"`
commonApi.Author
*model.SysNoticeEditReq
}
// SysNoticeEditRes 修改操作返回结果
type SysNoticeEditRes struct {
commonApi.EmptyRes
}
// SysNoticeGetReq 获取一条数据请求
type SysNoticeGetReq struct {
g.Meta `path:"/get" tags:"通知私信" method:"get" summary:"获取通知公告信息"`
commonApi.Author
Id int64 `p:"id" v:"required#主键必须"` //通过主键获取
}
// SysNoticeGetRes 获取一条数据结果
type SysNoticeGetRes struct {
g.Meta `mime:"application/json"`
*model.SysNoticeInfoRes
}
// SysNoticeDeleteReq 删除数据请求
type SysNoticeDeleteReq struct {
g.Meta `path:"/delete" tags:"通知私信" method:"delete" summary:"删除通知公告"`
commonApi.Author
Ids []int64 `p:"ids" v:"required#主键必须"` //通过主键删除
}
// SysNoticeDeleteRes 删除数据返回
type SysNoticeDeleteRes struct {
commonApi.EmptyRes
}
type SysNoticeIndexDataReq struct {
g.Meta `path:"getIndexData" tags:"通知私信" method:"get" summary:"获取首页通知预览数据"`
commonApi.Author
}
type SysNoticeIndexDataRes struct {
g.Meta `mime:"application/json"`
*model.SysNoticeIndexRes
}
type SysNoticeUnReadCountReq struct {
g.Meta `path:"unReadCount" tags:"通知私信" method:"get" summary:"获取未读数量"`
commonApi.Author
}
type SysNoticeUnReadCountRes struct {
g.Meta `mime:"application/json"`
*model.SysNoticeUnreadCount
}
// SysNoticeShowSearchReq 通知展示分页请求参数
type SysNoticeUserSearchReq struct {
g.Meta `path:"/userList" tags:"通知私信" method:"get" summary:"获取待指定的用户"`
commonApi.Author
UserNickName string `p:"userNickname"`
}
// SysNoticeSearchRes 通知展示列表返回结果
type SysNoticeUserSearchRes struct {
g.Meta `mime:"application/json"`
UserList []*model.SysNoticeUserNickname `json:"userList"`
}
// SysNoticeShowSearchReq 通知展示分页请求参数
type SysNoticeUserReadReq struct {
g.Meta `path:"/userList" tags:"通知私信" method:"get" summary:"获取待指定的用户"`
commonApi.Author
string `p:"userNickName"`
}
// SysNoticeSearchRes 通知展示列表返回结果
type SysNoticeUserReadRes struct {
commonApi.EmptyRes
}

View File

@ -0,0 +1,90 @@
// ==========================================================================
// GFast自动生成api操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: api/v1/system/sys_notice_read.go
// 生成人gfast
// desc:已读记录相关参数
// company:云南奇讯科技有限公司
// ==========================================================================
package system
import (
"github.com/gogf/gf/v2/frame/g"
commonApi "github.com/tiger1103/gfast/v3/api/v1/common"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
)
// SysNoticeReadSearchReq 分页请求参数
type SysNoticeReadSearchReq struct {
g.Meta `path:"/list" tags:"已读记录" method:"get" summary:"已读记录列表"`
commonApi.Author
model.SysNoticeReadSearchReq
}
// SysNoticeReadSearchRes 列表返回结果
type SysNoticeReadSearchRes struct {
g.Meta `mime:"application/json"`
*model.SysNoticeReadSearchRes
}
// SysNoticeReadAddReq 添加操作请求参数
type SysNoticeReadAddReq struct {
g.Meta `path:"/add" tags:"已读记录" method:"post" summary:"已读记录添加"`
commonApi.Author
*model.SysNoticeReadAddReq
}
// SysNoticeReadAddRes 添加操作返回结果
type SysNoticeReadAddRes struct {
commonApi.EmptyRes
}
// SysNoticeReadAddReq 添加操作请求参数
type SysNoticeReadNoticeAddReq struct {
g.Meta `path:"/readNotice" tags:"已读记录" method:"post" summary:"已读记录"`
commonApi.Author
*model.SysNoticeReadNoticeReq
}
// SysNoticeReadAddRes 添加操作返回结果
type SysNoticeReadNoticeAddRes struct {
commonApi.EmptyRes
}
// SysNoticeReadEditReq 修改操作请求参数
type SysNoticeReadEditReq struct {
g.Meta `path:"/edit" tags:"已读记录" method:"put" summary:"已读记录修改"`
commonApi.Author
*model.SysNoticeReadEditReq
}
// SysNoticeReadEditRes 修改操作返回结果
type SysNoticeReadEditRes struct {
commonApi.EmptyRes
}
// SysNoticeReadGetReq 获取一条数据请求
type SysNoticeReadGetReq struct {
g.Meta `path:"/get" tags:"已读记录" method:"get" summary:"获取已读记录信息"`
commonApi.Author
Id int64 `p:"id" v:"required#主键必须"` //通过主键获取
}
// SysNoticeReadGetRes 获取一条数据结果
type SysNoticeReadGetRes struct {
g.Meta `mime:"application/json"`
*model.SysNoticeReadInfoRes
}
// SysNoticeReadDeleteReq 删除数据请求
type SysNoticeReadDeleteReq struct {
g.Meta `path:"/delete" tags:"已读记录" method:"delete" summary:"删除已读记录"`
commonApi.Author
Ids []int64 `p:"ids" v:"required#主键必须"` //通过主键删除
}
// SysNoticeReadDeleteRes 删除数据返回
type SysNoticeReadDeleteRes struct {
commonApi.EmptyRes
}

View File

@ -0,0 +1,20 @@
/*
* @desc:ping
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2023/11/30 15:59
*/
package controller
import (
"github.com/tiger1103/gfast/v3/library/libWebsocket"
)
var Ping = new(pingController)
type pingController struct{}
func (c *pingController) Ping(client *libWebsocket.Client, req *libWebsocket.WRequest) {
libWebsocket.SendSuccess(client, req.Event)
}

View File

@ -18,7 +18,7 @@ func init() {
service.RegisterBigUpload(New())
}
func New() *sBigUpload {
func New() service.IBigUpload {
return &sBigUpload{}
}

View File

@ -19,7 +19,7 @@ func init() {
service.RegisterCache(New())
}
func New() *sCache {
func New() service.ICache {
var (
ctx = gctx.New()
cacheContainer *cache.GfCache

View File

@ -24,7 +24,7 @@ func init() {
service.RegisterCaptcha(New())
}
func New() *sCaptcha {
func New() service.ICaptcha {
return &sCaptcha{
driver: &base64Captcha.DriverString{
Height: 80,

View File

@ -16,7 +16,7 @@ func init() {
service.RegisterMiddleware(New())
}
func New() *sMiddleware {
func New() service.IMiddleware {
return &sMiddleware{}
}

View File

@ -27,7 +27,7 @@ func init() {
service.RegisterSysConfig(New())
}
func New() *sSysConfig {
func New() service.ISysConfig {
return &sSysConfig{}
}

View File

@ -26,7 +26,7 @@ func init() {
service.RegisterSysDictData(New())
}
func New() *sSysDictData {
func New() service.ISysDictData {
return &sSysDictData{}
}
@ -47,7 +47,7 @@ func (s *sSysDictData) GetDictWithDataByType(ctx context.Context, dictType, defa
err = dao.SysDictType.Ctx(ctx).Where(dao.SysDictType.Columns().DictType, dictType).
Where(dao.SysDictType.Columns().Status, 1).Fields(model.DictTypeRes{}).Scan(&dict.Info)
liberr.ErrIsNil(ctx, err, "获取字典类型失败")
if dict.Info==nil{
if dict.Info == nil {
return
}
err = dao.SysDictData.Ctx(ctx).Fields(model.DictDataRes{}).

View File

@ -29,7 +29,7 @@ func init() {
service.RegisterSysDictType(New())
}
func New() *sSysDictType {
func New() service.ISysDictType {
return &sSysDictType{}
}

View File

@ -28,7 +28,7 @@ func init() {
service.RegisterUpload(New())
}
func New() *sUpload {
func New() service.IUpload {
return &sUpload{}
}

View File

@ -1,5 +1,10 @@
package consts
const (
PageSize = 10 //分页长度
// PageSize 分页长度
PageSize = 10
// SysNoticeType 系统通知
SysNoticeType = 1
// SysLetterType 系统私信
SysLetterType = 2
)

View File

@ -0,0 +1,88 @@
// ==========================================================================
// GFast自动生成controller操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/controller/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package controller
import (
"context"
"fmt"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
)
type sysNoticeController struct {
BaseController
}
var SysNotice = new(sysNoticeController)
// List 列表(管理)
func (c *sysNoticeController) List(ctx context.Context, req *system.SysNoticeSearchReq) (res *system.SysNoticeSearchRes, err error) {
res = new(system.SysNoticeSearchRes)
res.SysNoticeSearchRes, err = service.SysNotice().List(ctx, &req.SysNoticeSearchReq)
return
}
// ShoWList(展示)
func (c *sysNoticeController) ShowList(ctx context.Context, req *system.SysNoticeShowSearchReq) (res *system.SysNoticeShowSearchRes, err error) {
res = new(system.SysNoticeShowSearchRes)
res.SysNoticeSearchRes, err = service.SysNotice().ListShow(ctx, &req.SysNoticeSearchReq)
return
}
// Get 获取通知公告
func (c *sysNoticeController) Get(ctx context.Context, req *system.SysNoticeGetReq) (res *system.SysNoticeGetRes, err error) {
res = new(system.SysNoticeGetRes)
res.SysNoticeInfoRes, err = service.SysNotice().GetById(ctx, req.Id)
return
}
// Add 添加通知公告
func (c *sysNoticeController) Add(ctx context.Context, req *system.SysNoticeAddReq) (res *system.SysNoticeAddRes, err error) {
req.CreatedBy = service.Context().GetUserId(ctx)
err = service.SysNotice().Add(ctx, req.SysNoticeAddReq)
return
}
// Edit 修改通知公告
func (c *sysNoticeController) Edit(ctx context.Context, req *system.SysNoticeEditReq) (res *system.SysNoticeEditRes, err error) {
req.UpdatedBy = service.Context().GetUserId(ctx)
err = service.SysNotice().Edit(ctx, req.SysNoticeEditReq)
return
}
// Delete 删除通知公告
func (c *sysNoticeController) Delete(ctx context.Context, req *system.SysNoticeDeleteReq) (res *system.SysNoticeDeleteRes, err error) {
err = service.SysNotice().Delete(ctx, req.Ids)
return
}
// IndexData 获取首页数据
func (c *sysNoticeController) IndexData(ctx context.Context, req *system.SysNoticeIndexDataReq) (res *system.SysNoticeIndexDataRes, err error) {
//res.SysNoticeIndexRes, err = service.SysNotice().IndexData(ctx)
return
}
// UnReadCount
func (c *sysNoticeController) UnReadCount(ctx context.Context, req *system.SysNoticeUnReadCountReq) (res *system.SysNoticeUnReadCountRes, err error) {
res = new(system.SysNoticeUnReadCountRes)
currentUser := service.Context().Get(ctx).User.Id
//noticeids, err := service.SysNotice().CurrentUseWithIds(ctx, currentUser)
res.SysNoticeUnreadCount, err = service.SysNotice().UnReadCount(ctx, currentUser)
fmt.Println(res)
return
}
// GetUserNameList 得到供选择用户列表
func (c *sysNoticeController) GetUserNameList(ctx context.Context, req *system.SysNoticeUserSearchReq) (res *system.SysNoticeUserSearchRes, err error) {
res = new(system.SysNoticeUserSearchRes)
list, err := service.SysNotice().GetUserNameList(ctx, req.UserNickName)
res.UserList = list
return
}

View File

@ -0,0 +1,61 @@
// ==========================================================================
// GFast自动生成controller操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/controller/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package controller
import (
"context"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
)
type sysNoticeReadController struct {
BaseController
}
var SysNoticeRead = new(sysNoticeReadController)
// List 列表
func (c *sysNoticeReadController) List(ctx context.Context, req *system.SysNoticeReadSearchReq) (res *system.SysNoticeReadSearchRes, err error) {
res = new(system.SysNoticeReadSearchRes)
res.SysNoticeReadSearchRes, err = service.SysNoticeRead().List(ctx, &req.SysNoticeReadSearchReq)
return
}
// Get 获取已读记录
func (c *sysNoticeReadController) Get(ctx context.Context, req *system.SysNoticeReadGetReq) (res *system.SysNoticeReadGetRes, err error) {
res = new(system.SysNoticeReadGetRes)
res.SysNoticeReadInfoRes, err = service.SysNoticeRead().GetById(ctx, req.Id)
return
}
// Add 添加已读记录
func (c *sysNoticeReadController) Add(ctx context.Context, req *system.SysNoticeReadAddReq) (res *system.SysNoticeReadAddRes, err error) {
err = service.SysNoticeRead().Add(ctx, req.SysNoticeReadAddReq)
return
}
// Add 添加已读记录
func (c *sysNoticeReadController) ReadNotice(ctx context.Context, req *system.SysNoticeReadNoticeAddReq) (res *system.SysNoticeReadNoticeAddRes, err error) {
err = service.SysNoticeRead().ReadNotice(ctx, req.SysNoticeReadNoticeReq)
return
}
// Edit 修改已读记录
func (c *sysNoticeReadController) Edit(ctx context.Context, req *system.SysNoticeReadEditReq) (res *system.SysNoticeReadEditRes, err error) {
err = service.SysNoticeRead().Edit(ctx, req.SysNoticeReadEditReq)
return
}
// Delete 删除已读记录
func (c *sysNoticeReadController) Delete(ctx context.Context, req *system.SysNoticeReadDeleteReq) (res *system.SysNoticeReadDeleteRes, err error) {
err = service.SysNoticeRead().Delete(ctx, req.Ids)
return
}

View File

@ -0,0 +1,103 @@
// ==========================================================================
// GFast自动生成dao internal操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/dao/internal/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// SysNoticeDao is the manager for logic model data accessing and custom defined data operations functions management.
type SysNoticeDao struct {
table string // Table is the underlying table name of the DAO.
group string // Group is the database configuration group name of current DAO.
columns SysNoticeColumns // Columns is the short type for Columns, which contains all the column names of Table for convenient usage.
}
// SysNoticeColumns defines and stores column names for table sys_notice.
type SysNoticeColumns struct {
Id string // ID
Title string // 标题
Type string // 类型
Tag string // 标签
Content string // 内容
Remark string // 备注
Sort string // 排序
Status string // 状态
Receiver string //接收者
CreatedBy string // 发送人
UpdatedBy string // 修改人
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
DeletedAt string // 删除时间
}
var sysNoticeColumns = SysNoticeColumns{
Id: "id",
Title: "title",
Type: "type",
Tag: "tag",
Content: "content",
Remark: "remark",
Sort: "sort",
Status: "status",
Receiver: "receiver",
CreatedBy: "created_by",
UpdatedBy: "updated_by",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewSysNoticeDao creates and returns a new DAO object for table data access.
func NewSysNoticeDao() *SysNoticeDao {
return &SysNoticeDao{
group: "default",
table: "sys_notice",
columns: sysNoticeColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *SysNoticeDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *SysNoticeDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *SysNoticeDao) Columns() SysNoticeColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *SysNoticeDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *SysNoticeDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *SysNoticeDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -0,0 +1,85 @@
// ==========================================================================
// GFast自动生成dao internal操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/dao/internal/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// SysNoticeReadDao is the manager for logic model data accessing and custom defined data operations functions management.
type SysNoticeReadDao struct {
table string // Table is the underlying table name of the DAO.
group string // Group is the database configuration group name of current DAO.
columns SysNoticeReadColumns // Columns is the short type for Columns, which contains all the column names of Table for convenient usage.
}
// SysNoticeReadColumns defines and stores column names for table sys_notice_read.
type SysNoticeReadColumns struct {
Id string // id
NoticeId string // 信息id
UserId string // 用户id
UpdatedAt string // 更新时间
CreatedAt string // 阅读时间
}
var sysNoticeReadColumns = SysNoticeReadColumns{
Id: "id",
NoticeId: "notice_id",
UserId: "user_id",
UpdatedAt: "updated_at",
CreatedAt: "created_at",
}
// NewSysNoticeReadDao creates and returns a new DAO object for table data access.
func NewSysNoticeReadDao() *SysNoticeReadDao {
return &SysNoticeReadDao{
group: "default",
table: "sys_notice_read",
columns: sysNoticeReadColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *SysNoticeReadDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *SysNoticeReadDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *SysNoticeReadDao) Columns() SysNoticeReadColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *SysNoticeReadDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *SysNoticeReadDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *SysNoticeReadDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -0,0 +1,29 @@
// ==========================================================================
// GFast自动生成dao操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/dao/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package dao
import (
"github.com/tiger1103/gfast/v3/internal/app/system/dao/internal"
)
// sysNoticeDao is the manager for logic model data accessing and custom defined data operations functions management.
// You can define custom methods on it to extend its functionality as you wish.
type sysNoticeDao struct {
*internal.SysNoticeDao
}
var (
// SysNotice is globally public accessible object for table tools_gen_table operations.
SysNotice = sysNoticeDao{
internal.NewSysNoticeDao(),
}
)
// Fill with you ideas below.

View File

@ -0,0 +1,29 @@
// ==========================================================================
// GFast自动生成dao操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/dao/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package dao
import (
"github.com/tiger1103/gfast/v3/internal/app/system/dao/internal"
)
// sysNoticeReadDao is the manager for logic model data accessing and custom defined data operations functions management.
// You can define custom methods on it to extend its functionality as you wish.
type sysNoticeReadDao struct {
*internal.SysNoticeReadDao
}
var (
// SysNoticeRead is globally public accessible object for table tools_gen_table operations.
SysNoticeRead = sysNoticeReadDao{
internal.NewSysNoticeReadDao(),
}
)
// Fill with you ideas below.

View File

@ -1,19 +1,23 @@
package logic
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/context"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/middleware"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/personal"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysAuthRule"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysDept"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysJob"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysJobLog"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysLoginLog"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysOperLog"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysPost"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysRole"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysUser"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysUserOnline"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/token"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/toolsGenTable"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/toolsGenTableColumn"
import _ "github.com/tiger1103/gfast/v3/internal/app/system/logic/timeTask"
import (
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/context"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/middleware"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/personal"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysAuthRule"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysDept"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysJob"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysJobLog"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysLoginLog"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysNotice"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysNoticeRead"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysOperLog"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysPost"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysRole"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysUser"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/sysUserOnline"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/timeTask"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/token"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/toolsGenTable"
_ "github.com/tiger1103/gfast/v3/internal/app/system/logic/toolsGenTableColumn"
)

View File

@ -0,0 +1,359 @@
// ==========================================================================
// GFast自动生成logic操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/logic/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package logic
import (
"context"
"database/sql"
"errors"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
sysDao "github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libWebsocket"
"github.com/tiger1103/gfast/v3/library/liberr"
"strconv"
)
func init() {
service.RegisterSysNotice(New())
}
func New() service.ISysNotice {
return &sSysNotice{}
}
type sSysNotice struct{}
func (s *sSysNotice) List(ctx context.Context, req *model.SysNoticeSearchReq) (listRes *model.SysNoticeSearchRes, err error) {
listRes = new(model.SysNoticeSearchRes)
currentUserId := service.Context().GetUserId(ctx)
if currentUserId <= 0 {
err = errors.New("用户信息查询失败")
return
}
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysNotice.Ctx(ctx).WithAll().As("n")
if req.Id != "" {
m = m.Where("n."+dao.SysNotice.Columns().Id+" = ?", req.Id)
}
if req.Title != "" {
m = m.Where("n."+dao.SysNotice.Columns().Title+" = ?", req.Title)
}
if req.Type != "" {
m = m.Where("n."+dao.SysNotice.Columns().Type+" = ?", gconv.Int64(req.Type))
}
if req.Tag != "" {
m = m.Where("n."+dao.SysNotice.Columns().Tag+" = ?", gconv.Int(req.Tag))
}
if req.Status != "" {
m = m.Where("n."+dao.SysNotice.Columns().Status+" = ?", gconv.Int(req.Status))
}
if len(req.DateRange) != 0 {
m = m.Where("n."+dao.SysNotice.Columns().CreatedAt+" >=? AND "+dao.SysNotice.Columns().CreatedAt+" <=?", req.DateRange[0], req.DateRange[1])
}
listRes.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取总行数失败")
if req.PageNum == 0 {
req.PageNum = 1
}
listRes.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
order := "n.id desc"
if req.OrderBy != "" {
order = req.OrderBy
}
m = m.LeftJoin("sys_notice_read as nr", "nr.notice_id=n.id")
//Where("nr.user_id=?", currentUserId)
var res []*model.SysNoticeListRes
err = m.Page(req.PageNum, req.PageSize).Fields("" +
"n.*," +
"SUM(nr.clicks) as clickNumber" +
//"(nr.user_id=" + strconv.FormatUint(currentUserId, 10) + ") as isRead" +
"").Order(order).Group("n.id").Scan(&res)
liberr.ErrIsNil(ctx, err, "获取数据失败")
listRes.List = res
})
return
}
func (s *sSysNotice) ListShow(ctx context.Context, req *model.SysNoticeSearchReq) (listRes *model.SysNoticeSearchRes, err error) {
listRes = new(model.SysNoticeSearchRes)
currentUserId := service.Context().GetUserId(ctx)
if currentUserId <= 0 {
err = errors.New("用户信息查询失败")
return
}
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysNotice.Ctx(ctx).WithAll().As("n")
if req.Id != "" {
m = m.Where("n."+dao.SysNotice.Columns().Id+" = ?", req.Id)
}
if req.Title != "" {
m = m.Where("n."+dao.SysNotice.Columns().Title+" = ?", req.Title)
}
if req.Type != "" {
m = m.Where("n."+dao.SysNotice.Columns().Type+" = ?", gconv.Int64(req.Type))
if req.Type == "2" {
ids, _ := s.CurrentUseWithIds(ctx, currentUserId, 2)
m = m.WhereIn("n."+dao.SysNotice.Columns().Id, ids)
}
}
if req.Tag != "" {
m = m.Where("n."+dao.SysNotice.Columns().Tag+" = ?", gconv.Int(req.Tag))
}
if req.Status != "" {
m = m.Where("n."+dao.SysNotice.Columns().Status+" = ?", gconv.Int(req.Status))
}
if len(req.DateRange) != 0 {
m = m.Where("n."+dao.SysNotice.Columns().CreatedAt+" >=? AND "+dao.SysNotice.Columns().CreatedAt+" <=?", req.DateRange[0], req.DateRange[1])
}
listRes.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取总行数失败")
if req.PageNum == 0 {
req.PageNum = 1
}
listRes.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
order := "n.id desc"
if req.OrderBy != "" {
order = req.OrderBy
}
m = m.LeftJoin("sys_notice_read as nr", "nr.notice_id=n.id")
/*Where("nr.user_id=?", currentUserId)*/
var res []*model.SysNoticeListRes
err = m.Page(req.PageNum, req.PageSize).Fields("" +
"n.*," +
"(nr.user_id=" + strconv.FormatUint(currentUserId, 10) + ") as isRead" + //查询是否已读
"").Order(order).Group("n.id").Scan(&res)
liberr.ErrIsNil(ctx, err, "获取数据失败")
listRes.List = res
})
return
}
func (s *sSysNotice) GetById(ctx context.Context, id int64) (res *model.SysNoticeInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysNotice.Ctx(ctx).WithAll().Where(dao.SysNotice.Columns().Id, id).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取信息失败")
})
return
}
func (s *sSysNotice) Add(ctx context.Context, req *model.SysNoticeAddReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
data := do.SysNotice{
Title: req.Title,
Type: req.Type,
Tag: req.Tag,
Content: req.Content,
Remark: req.Remark,
Receiver: req.Receiver,
Sort: req.Sort,
Status: req.Status,
CreatedBy: req.CreatedBy,
}
var rows sql.Result
rows, err = dao.SysNotice.Ctx(ctx).Insert(data)
liberr.ErrIsNil(ctx, err, "添加失败")
data.Id, err = rows.LastInsertId()
liberr.ErrIsNil(ctx, err, "获取ID失败")
response := &libWebsocket.WResponse{
Event: "notice",
Data: data,
}
if req.Type == consts.SysLetterType {
//系统私信
if len(req.Receiver) > 0 {
for _, id := range req.Receiver {
libWebsocket.SendToUser(id, response)
}
}
} else {
//系统通知
libWebsocket.SendToAll(response)
}
})
return
}
func (s *sSysNotice) Edit(ctx context.Context, req *model.SysNoticeEditReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
data := do.SysNotice{
Title: req.Title,
Tag: req.Tag,
Content: req.Content,
Remark: req.Remark,
Sort: req.Sort,
Status: req.Status,
Receiver: req.Receiver,
UpdatedBy: req.UpdatedBy,
}
_, err = dao.SysNotice.Ctx(ctx).WherePri(req.Id).Update(data)
liberr.ErrIsNil(ctx, err, "修改失败")
data.Id = req.Id
data.Type = req.Type
response := &libWebsocket.WResponse{
Event: "notice",
Data: data,
}
if data.Type == consts.SysLetterType {
//系统私信
if len(req.Receiver) > 0 {
for _, id := range req.Receiver {
libWebsocket.SendToUser(id, response)
}
}
} else {
//系统通知
libWebsocket.SendToAll(response)
}
})
return
}
func (s *sSysNotice) Delete(ctx context.Context, ids []int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysNotice.Ctx(ctx).Delete(dao.SysNotice.Columns().Id+" in (?)", ids)
liberr.ErrIsNil(ctx, err, "删除失败")
})
return
}
/*
func (s *sSysNotice) IndexData(ctx context.Context) (res *model.SysNoticeIndexRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
userInfo := service.Context().GetLoginUser(ctx)
readIdMap, err := dao.SysNoticeRead.Ctx(ctx).Where(dao.SysNoticeRead.Columns().UserId, userInfo.Id).Fields(dao.SysNoticeRead.Columns().NoticeId).All()
fmt.Println(readIdMap, err)
dao.SysNotice.Ctx(ctx).Where(dao.SysNotice.Columns().Type, "1").Order("id desc").Scan(res.Type1List)
dao.SysNotice.Ctx(ctx)
})
return
}
*/
//未读消息列表
func (s *sSysNotice) UnReadList(ctx context.Context) (res *model.SysNoticeListRes, err error) {
//TODO implement me
panic("implement me")
}
func (s *sSysNotice) UnReadCount(ctx context.Context, currentUserId uint64) (sysNoticeUnreadCount *model.SysNoticeUnreadCount, err error) {
if currentUserId <= 0 {
err = errors.New("获取用户信息失败")
return
}
countFunc := func(t int) (count int) {
noticeIds, serr := s.CurrentUseWithIds(ctx, currentUserId, t)
if serr != nil {
return 0
}
all, serr := dao.SysNotice.Ctx(ctx).
WhereIn(dao.SysNotice.Columns().Id, noticeIds).
Where(dao.SysNotice.Columns().Type, t).Count()
if serr != nil {
return 0
}
read, serr := dao.SysNoticeRead.Ctx(ctx).
WhereIn(dao.SysNoticeRead.Columns().NoticeId, noticeIds).
Where(dao.SysNoticeRead.Columns().UserId, currentUserId).
Count()
if serr != nil {
return 0
}
count = all - read
return
}
sysNoticeUnreadCount = new(model.SysNoticeUnreadCount)
sysNoticeUnreadCount.NotifyCount = countFunc(1) //获取未读通知数量
sysNoticeUnreadCount.NoticeCount = countFunc(2) //获取未读私信数量
return
}
func (s *sSysNotice) ReadAll(ctx context.Context, nType string) (err error) {
currentUserId := service.Context().GetUserId(ctx)
if currentUserId <= 0 {
err = errors.New("获取当前用户信息失败")
return
}
subQuery := g.Model("sys_notice_read").Where("user_id=?", currentUserId).Fields("id")
/* dao.SysNoticeRead.Ctx(ctx).Where(dao.SysNoticeRead.Columns().UserId, currentUserId)*/
unReadIdMap, err := dao.SysNotice.Ctx(ctx).WhereNotIn("id", subQuery).Fields("id").All()
if unReadIdMap != nil {
insertList := make([]*model.SysNoticeReadAddReq, 0)
for _, record := range unReadIdMap {
insertList = append(insertList, &model.SysNoticeReadAddReq{
NoticeId: record["id"].Int64(),
UserId: int64(currentUserId),
CreatedAt: gtime.Now(),
})
}
_, err = dao.SysNoticeRead.Ctx(ctx).Data(insertList).Insert()
if err != nil {
return
}
}
return
}
func (s *sSysNotice) GetUserNameList(ctx context.Context, search string) (res []*model.SysNoticeUserNickname, err error) {
res = make([]*model.SysNoticeUserNickname, 0)
err = sysDao.SysUser.Ctx(ctx).Where("user_nickname like ?", "%"+search+"%").Fields("id,user_nickname").Page(1, 6).Scan(&res)
return
}
/*func (s *sSysNotice) NoticeReadLengthAdd(ctx context.Context, id int64) (err error) {
_, err = g.DB().Exec(ctx, "update sys_notice set read_len=(read_len+1) where id = ?", id)
return
}
*/
func (s *sSysNotice) NoticeReadAddUserId(ctx context.Context, req *model.SysNoticeReadAddUserReq) (err error) {
return
}
func (s *sSysNotice) CurrentUseWithIds(ctx context.Context, currentUserId uint64, noticeType int) (ids []int64, err error) {
/* columns, err := s.Model(ctx, &handler.Option{FilterAuth: false}).
Fields("id").
Where("status", consts.StatusEnabled).
Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(memberId)+"')))",
[]int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}, consts.NoticeTypeLetter,
).Array()
if err != nil {
err = gerror.Wrap(err, "获取我的消息失败!")
return
}
ids = g.NewVar(columns).Int64s()*/
m := dao.SysNotice.Ctx(ctx)
m = m.Where("status =?", 1).
Where("type=?", noticeType).
Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(currentUserId)+"')))", 1, 2)
all, err := m.Fields("id").All()
if err != nil {
return
}
for _, record := range all {
ids = append(ids, record["id"].Int64())
}
return
}

View File

@ -0,0 +1,128 @@
// ==========================================================================
// GFast自动生成logic操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/logic/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package logic
import (
"context"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/frame/g"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/liberr"
)
func init() {
service.RegisterSysNoticeRead(New())
}
func New() service.ISysNoticeRead {
return &sSysNoticeRead{}
}
type sSysNoticeRead struct{}
func (s *sSysNoticeRead) List(ctx context.Context, req *model.SysNoticeReadSearchReq) (listRes *model.SysNoticeReadSearchRes, err error) {
listRes = new(model.SysNoticeReadSearchRes)
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysNoticeRead.Ctx(ctx).WithAll()
listRes.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取总行数失败")
if req.PageNum == 0 {
req.PageNum = 1
}
listRes.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
order := "id desc"
if req.OrderBy != "" {
order = req.OrderBy
}
var res []*model.SysNoticeReadListRes
err = m.Page(req.PageNum, req.PageSize).Order(order).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取数据失败")
listRes.List = make([]*model.SysNoticeReadListRes, len(res))
for k, v := range res {
listRes.List[k] = &model.SysNoticeReadListRes{
Id: v.Id,
NoticeId: v.NoticeId,
UserId: v.UserId,
CreatedAt: v.CreatedAt,
}
}
})
return
}
func (s *sSysNoticeRead) GetById(ctx context.Context, id int64) (res *model.SysNoticeReadInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysNoticeRead.Ctx(ctx).WithAll().Where(dao.SysNoticeRead.Columns().Id, id).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取信息失败")
})
return
}
func (s *sSysNoticeRead) Add(ctx context.Context, req *model.SysNoticeReadAddReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysNoticeRead.Ctx(ctx).Insert(do.SysNoticeRead{})
liberr.ErrIsNil(ctx, err, "添加失败")
})
return
}
func (s *sSysNoticeRead) ReadNotice(ctx context.Context, req *model.SysNoticeReadNoticeReq) (err error) {
currentUser := service.Context().Get(ctx).User.Id
err = g.Try(ctx, func(ctx context.Context) {
//判断是否有数据
count, err := dao.SysNoticeRead.Ctx(ctx).Where(dao.SysNoticeRead.Columns().NoticeId, req.NoticeId).
Where(dao.SysNoticeRead.Columns().UserId, currentUser).Count()
if err != nil {
return
}
if count > 0 {
_, err := g.DB().Exec(ctx, " update sys_notice_read set clicks=(clicks+1) where user_id =? and notice_id=?", currentUser, req.NoticeId)
if err != nil {
return
}
} else {
_, err = dao.SysNoticeRead.Ctx(ctx).Insert(do.SysNoticeRead{
NoticeId: req.NoticeId,
UserId: currentUser,
CreatedAt: gtime.Now(),
Clicks: 0,
})
if err != nil {
return
}
}
liberr.ErrIsNil(ctx, err, "添加失败")
})
return
}
func (s *sSysNoticeRead) Edit(ctx context.Context, req *model.SysNoticeReadEditReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysNoticeRead.Ctx(ctx).WherePri(req.Id).Update(do.SysNoticeRead{})
liberr.ErrIsNil(ctx, err, "修改失败")
})
return
}
func (s *sSysNoticeRead) Delete(ctx context.Context, ids []int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysNoticeRead.Ctx(ctx).Delete(dao.SysNoticeRead.Columns().Id+" in (?)", ids)
liberr.ErrIsNil(ctx, err, "删除失败")
})
return
}

View File

@ -0,0 +1,34 @@
// ==========================================================================
// GFast自动生成model entity操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/model/entity/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package do
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
)
// SysNotice is the golang structure for table sys_notice.
type SysNotice struct {
gmeta.Meta `orm:"table:sys_notice, do:true"`
Id interface{} `orm:"id,primary" json:"id"` // ID
Title interface{} `orm:"title" json:"title"` // 标题
Type interface{} `orm:"type" json:"type"` // 类型
Tag interface{} `orm:"tag" json:"tag"` // 标签
Content interface{} `orm:"content" json:"content"` // 内容
Remark interface{} `orm:"remark" json:"remark"` // 备注
Sort interface{} `orm:"sort" json:"sort"` // 排序
Status interface{} `orm:"status" json:"status"` // 状态
Receiver interface{} `orm:"receiver" json:"receiver"` //接收者
CreatedBy interface{} `orm:"created_by" json:"createdBy"` // 发送人
UpdatedBy interface{} `orm:"updated_by" json:"updatedBy"` // 修改人
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间
DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间
}

View File

@ -0,0 +1,26 @@
// ==========================================================================
// GFast自动生成model entity操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/model/entity/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package do
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
)
// SysNoticeRead is the golang structure for table sys_notice_read.
type SysNoticeRead struct {
gmeta.Meta `orm:"table:sys_notice_read, do:true"`
Id interface{} `orm:"id,primary" json:"id"` // id
NoticeId interface{} `orm:"notice_id" json:"noticeId"` // 信息id
UserId interface{} `orm:"user_id" json:"userId"` // 用户id
Clicks interface{} `orm:"clicks" json:"clicks"` //点击次数
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 阅读时间
}

View File

@ -0,0 +1,33 @@
// ==========================================================================
// GFast自动生成model entity操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/model/entity/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
)
// SysNotice is the golang structure for table sys_notice.
type SysNotice struct {
gmeta.Meta `orm:"table:sys_notice"`
Id int64 `orm:"id,primary" json:"id"` // ID
Title string `orm:"title" json:"title"` // 标题
Type int64 `orm:"type" json:"type"` // 类型
Tag int `orm:"tag" json:"tag"` // 标签
Content string `orm:"content" json:"content"` // 内容
Remark string `orm:"remark" json:"remark"` // 备注
Sort int `orm:"sort" json:"sort"` // 排序
Status int `orm:"status" json:"status"` // 状态
CreatedBy int64 `orm:"created_by" json:"createdBy"` // 发送人
UpdatedBy int64 `orm:"updated_by" json:"updatedBy"` // 修改人
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间
DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt"` // 删除时间
}

View File

@ -0,0 +1,25 @@
// ==========================================================================
// GFast自动生成model entity操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/model/entity/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
)
// SysNoticeRead is the golang structure for table sys_notice_read.
type SysNoticeRead struct {
gmeta.Meta `orm:"table:sys_notice_read"`
Id int64 `orm:"id,primary" json:"id"` // id
NoticeId int64 `orm:"notice_id" json:"noticeId"` // 信息id
UserId int64 `orm:"user_id" json:"userId"` // 用户id
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 更新时间
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 阅读时间
}

View File

@ -0,0 +1,120 @@
// ==========================================================================
// GFast自动生成model操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/model/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package model
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
comModel "github.com/tiger1103/gfast/v3/internal/app/common/model"
)
// SysNoticeInfoRes is the golang structure for table sys_notice.
type SysNoticeInfoRes struct {
gmeta.Meta `orm:"table:sys_notice"`
Id int64 `orm:"id,primary" json:"id" dc:"ID"` // ID
Title string `orm:"title" json:"title" dc:"标题"` // 标题
Type int64 `orm:"type" json:"type" dc:"类型"` // 类型
Tag int `orm:"tag" json:"tag" dc:"标签"` // 标签
Content string `orm:"content" json:"content" dc:"内容"` // 内容
Remark string `orm:"remark" json:"remark" dc:"备注"` // 备注
Sort int `orm:"sort" json:"sort" dc:"排序"` // 排序
Status int `orm:"status" json:"status" dc:"状态"` // 状态
CreatedBy int64 `orm:"created_by" json:"createdBy" dc:"发送人"` // 发送人
CreatedUser *LinkUserRes `orm:"with:id=created_by" json:"createdUser"`
UpdatedBy int64 `orm:"updated_by" json:"updatedBy" dc:"修改人"` // 修改人
UpdatedUser *LinkUserRes `orm:"with:id=updated_by" json:"updatedUser"`
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt" dc:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt" dc:"更新时间"` // 更新时间
DeletedAt *gtime.Time `orm:"deleted_at" json:"deletedAt" dc:"删除时间"` // 删除时间
Receiver []uint64 `json:"receiver" orm:"receiver"`
ReceiverUser []*LinkUserRes `orm:"with:id=receiver" json:"receiverUser"`
}
type SysNoticeListRes struct {
Id int64 `json:"id" dc:"ID"`
Title string `json:"title" dc:"标题"`
Type int64 `json:"type" dc:"类型"`
Tag int `json:"tag" dc:"标签"`
Content string `json:"content" dc:"内容"`
Remark string `json:"remark" dc:"备注"`
Sort int `json:"sort" dc:"排序"`
Status int `json:"status" dc:"状态"`
IsRead bool `json:"isRead" dc:"当前用户是否已读"`
ClickNumber int `json:"clickNumber"`
CreatedUser *LinkUserRes `orm:"with:id=created_by" json:"createdUser"`
CreatedBy int64 `json:"createdBy" dc:"发送人"`
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
}
// SysNoticeSearchReq 分页请求参数
type SysNoticeSearchReq struct {
comModel.PageReq
Id string `p:"id" dc:"ID"` //ID
Title string `p:"title" dc:"标题"` //标题
Type string `p:"type" v:"type@integer#类型需为整数" dc:"类型"` //类型
Tag string `p:"tag" v:"tag@integer#标签需为整数" dc:"标签"` //标签
Status string `p:"status" v:"status@integer#状态需为整数" dc:"状态"` //状态
CreatedAt string `p:"createdAt" v:"createdAt@datetime#创建时间需为YYYY-MM-DD hh:mm:ss格式" dc:"创建时间"` //创建时间
}
// SysNoticeSearchRes 列表返回结果
type SysNoticeSearchRes struct {
comModel.ListRes
List []*SysNoticeListRes `json:"list"`
}
type SysNoticeUserNickname struct {
Id int64 `json:"id"`
UserNickName string `json:"userNickname"`
}
// SysNoticeAddReq 添加操作请求参数
type SysNoticeAddReq struct {
Title string `p:"title" v:"required#标题不能为空" dc:"标题"`
Type int64 `p:"type" v:"required#类型不能为空" dc:"类型"`
Tag int `p:"tag" dc:"标签"`
Content string `p:"content" v:"required#内容不能为空" dc:"内容"`
Remark string `p:"remark" dc:"备注"`
Sort int `p:"sort" dc:"排序"`
Status int `p:"status" v:"required#状态不能为空" dc:"状态"`
Receiver []uint64 `p:"receiver"`
CreatedBy uint64
}
// SysNoticeEditReq 修改操作请求参数
type SysNoticeEditReq struct {
Id int64 `p:"id" v:"required#主键ID不能为空" dc:"ID"`
Title string `p:"title" v:"required#标题不能为空" dc:"标题"`
Type int64 `p:"type" v:"required#类型不能为空" dc:"类型"`
Tag int `p:"tag" dc:"标签"`
Content string `p:"content" v:"required#内容不能为空" dc:"内容"`
Remark string `p:"remark" dc:"备注"`
Sort int `p:"sort" dc:"排序"`
Status int `p:"status" v:"required#状态不能为空" dc:"状态"`
Receiver []uint64 `p:"receiver"`
UpdatedBy uint64
}
type SysNoticeIndexRes struct {
Type1Total int `json:"type1Total"`
Type2Total int `json:"type2Total"`
Type1List *SysNoticeListRes `json:"type1List"`
Type2List *SysNoticeListRes `json:"type2List"`
}
type SysNoticeUnreadCount struct {
NotifyCount int `json:"notifyCount"`
NoticeCount int `json:"noticeCount"`
}
type SysNoticeReadAddUserReq struct {
UserId int64
NoticeId int64 `p:"noticeId"`
}

View File

@ -0,0 +1,63 @@
// ==========================================================================
// GFast自动生成model操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/model/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package model
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
comModel "github.com/tiger1103/gfast/v3/internal/app/common/model"
)
// SysNoticeReadInfoRes is the golang structure for table sys_notice_read.
type SysNoticeReadInfoRes struct {
gmeta.Meta `orm:"table:sys_notice_read"`
Id int64 `orm:"id,primary" json:"id" dc:"id"` // id
NoticeId int64 `orm:"notice_id" json:"noticeId" dc:"信息id"` // 信息id
UserId int64 `orm:"user_id" json:"userId" dc:"用户id"` // 用户id
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt" dc:"更新时间"` // 更新时间
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt" dc:"阅读时间"` // 阅读时间
}
type SysNoticeReadListRes struct {
Id int64 `json:"id" dc:"id"`
NoticeId int64 `json:"noticeId" dc:"信息id"`
UserId int64 `json:"userId" dc:"用户id"`
CreatedAt *gtime.Time `json:"createdAt" dc:"阅读时间"`
}
// SysNoticeReadSearchReq 分页请求参数
type SysNoticeReadSearchReq struct {
comModel.PageReq
}
// SysNoticeReadSearchRes 列表返回结果
type SysNoticeReadSearchRes struct {
comModel.ListRes
List []*SysNoticeReadListRes `json:"list"`
}
// SysNoticeReadAddReq 添加操作请求参数
type SysNoticeReadAddReq struct {
NoticeId int64 `json:"noticeId" dc:"信息id"`
UserId int64 `json:"userId" dc:"用户id"`
CreatedAt *gtime.Time `json:"createdAt" dc:"阅读时间"`
}
// SysNoticeReadAddReq 添加操作请求参数
type SysNoticeReadNoticeReq struct {
NoticeId int64 `p:"noticeId" dc:"信息id"`
UserId int64
CreatedAt *gtime.Time
}
// SysNoticeReadEditReq 修改操作请求参数
type SysNoticeReadEditReq struct {
Id int64 `p:"id" v:"required#主键ID不能为空" dc:"id"`
}

View File

@ -0,0 +1,25 @@
// ==========================================================================
// GFast自动生成router操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/router/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package router
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/internal/app/system/controller"
)
func (router *Router) BindSysNoticeController(ctx context.Context, group *ghttp.RouterGroup) {
group.Group("/sysNotice", func(group *ghttp.RouterGroup) {
group.Bind(
controller.SysNotice,
)
})
}

View File

@ -0,0 +1,25 @@
// ==========================================================================
// GFast自动生成router操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/router/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package router
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/internal/app/system/controller"
)
func (router *Router) BindSysNoticeReadController(ctx context.Context, group *ghttp.RouterGroup) {
group.Group("/sysNoticeRead", func(group *ghttp.RouterGroup) {
group.Bind(
controller.SysNoticeRead,
)
})
}

View File

@ -0,0 +1,48 @@
// ==========================================================================
// GFast自动生成service操作代码。
// 生成日期2023-11-09 11:41:17
// 生成路径: internal/app/system/service/sys_notice.go
// 生成人gfast
// desc:通知公告
// company:云南奇讯科技有限公司
// ==========================================================================
package service
import (
"context"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
)
type ISysNotice interface {
List(ctx context.Context, req *model.SysNoticeSearchReq) (res *model.SysNoticeSearchRes, err error)
ListShow(ctx context.Context, req *model.SysNoticeSearchReq) (res *model.SysNoticeSearchRes, err error)
GetById(ctx context.Context, Id int64) (res *model.SysNoticeInfoRes, err error)
Add(ctx context.Context, req *model.SysNoticeAddReq) (err error)
Edit(ctx context.Context, req *model.SysNoticeEditReq) (err error)
Delete(ctx context.Context, Id []int64) (err error)
//IndexData(ctx context.Context) (res *model.SysNoticeIndexRes, err error)
/*首页相关数据接口*/
UnReadList(ctx context.Context) (res *model.SysNoticeListRes, err error)
UnReadCount(ctx context.Context, currentUser uint64) (sysNoticeUnreadIds *model.SysNoticeUnreadCount, err error)
ReadAll(ctx context.Context, nType string) (err error)
GetUserNameList(ctx context.Context, search string) (res []*model.SysNoticeUserNickname, err error)
//NoticeReadLengthAdd(ctx context.Context, id int64) (err error)
NoticeReadAddUserId(ctx context.Context, req *model.SysNoticeReadAddUserReq) (err error)
//获取有我的消息的所有私信
//CurrentUseWithIds(ctx context.Context, currentUserId uint64) (ids []int64, err error)
}
var localSysNotice ISysNotice
func SysNotice() ISysNotice {
if localSysNotice == nil {
panic("implement not found for interface ISysNotice, forgot register?")
}
return localSysNotice
}
func RegisterSysNotice(i ISysNotice) {
localSysNotice = i
}

View File

@ -0,0 +1,38 @@
// ==========================================================================
// GFast自动生成service操作代码。
// 生成日期2023-11-09 17:37:25
// 生成路径: internal/app/system/service/sys_notice_read.go
// 生成人gfast
// desc:已读记录
// company:云南奇讯科技有限公司
// ==========================================================================
package service
import (
"context"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
)
type ISysNoticeRead interface {
List(ctx context.Context, req *model.SysNoticeReadSearchReq) (res *model.SysNoticeReadSearchRes, err error)
ReadNotice(ctx context.Context, req *model.SysNoticeReadNoticeReq) (err error)
GetById(ctx context.Context, Id int64) (res *model.SysNoticeReadInfoRes, err error)
Add(ctx context.Context, req *model.SysNoticeReadAddReq) (err error)
Edit(ctx context.Context, req *model.SysNoticeReadEditReq) (err error)
Delete(ctx context.Context, Id []int64) (err error)
}
var localSysNoticeRead ISysNoticeRead
func SysNoticeRead() ISysNoticeRead {
if localSysNoticeRead == nil {
panic("implement not found for interface ISysNoticeRead, forgot register?")
}
return localSysNoticeRead
}
func RegisterSysNoticeRead(i ISysNoticeRead) {
localSysNoticeRead = i
}

View File

@ -0,0 +1,82 @@
/*
* @desc:websocket路由
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2023/11/30 15:06
*/
package router
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/guid"
"github.com/gorilla/websocket"
commonController "github.com/tiger1103/gfast/v3/internal/app/common/controller"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libUtils"
"github.com/tiger1103/gfast/v3/library/libWebsocket"
"net/http"
)
var R = new(Router)
type Router struct{}
// WsPage ws入口
func WsPage(r *ghttp.Request) {
upGrader := websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
conn, err := upGrader.Upgrade(r.Response.ResponseWriter, r.Request, nil)
if err != nil {
return
}
currentTime := uint64(gtime.Now().Unix())
client := NewClient(r, conn, currentTime)
go client.Read()
go client.Write()
// 用户连接事件
libWebsocket.Register(client)
}
// NewClient 初始化
func NewClient(r *ghttp.Request, socket *websocket.Conn, firstTime uint64) (client *libWebsocket.Client) {
client = &libWebsocket.Client{
Addr: socket.RemoteAddr().String(),
ID: guid.S(),
Socket: socket,
Send: make(chan *libWebsocket.WResponse, 100),
SendClose: false,
CloseSignal: make(chan struct{}, 1),
FirstTime: firstTime,
HeartbeatTime: firstTime,
User: service.Context().GetLoginUser(r.Context()),
IP: libUtils.GetClientIp(r.Context()),
UserAgent: r.UserAgent(),
}
return
}
func (router *Router) BindController(ctx context.Context, group *ghttp.RouterGroup) {
group.Group("/websocket", func(group *ghttp.RouterGroup) {
//登录验证拦截
service.GfToken().Middleware(group)
//context拦截器
group.Middleware(service.Middleware().Ctx)
group.GET("/", WsPage)
})
// 启动websocket监听
libWebsocket.Start()
// 注册消息路由
libWebsocket.RegisterMsg(libWebsocket.EventHandlers{
"ping": commonController.Ping.Ping, // 心跳
})
}

View File

@ -0,0 +1,11 @@
package router
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
websocketRouter "github.com/tiger1103/gfast/v3/internal/app/websocket/router"
)
func (router *Router) BindWebsocketModuleController(ctx context.Context, group *ghttp.RouterGroup) {
websocketRouter.R.BindController(ctx, group)
}

View File

@ -0,0 +1,172 @@
package libWebsocket
import (
"context"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gorilla/websocket"
systemModel "github.com/tiger1103/gfast/v3/internal/app/system/model"
"runtime/debug"
)
const (
// 用户连接超时时间
heartbeatExpirationTime = 5 * 60
)
// 用户登录
type login struct {
UserId uint64
Client *Client
}
// GetKey 读取客户端数据
func (l *login) GetKey() string {
return GetUserKey(l.UserId)
}
// Client 客户端连接
type Client struct {
Addr string // 客户端地址
ID string // 连接唯一标识
Socket *websocket.Conn // 用户连接
Send chan *WResponse // 待发送的数据
SendClose bool // 发送是否关闭
CloseSignal chan struct{} // 关闭信号
FirstTime uint64 // 首次连接时间
HeartbeatTime uint64 // 用户上次心跳时间
Tags garray.StrArray // 标签
User *systemModel.ContextUser // 用户信息
context context.Context // Custom context for internal usage purpose.
IP string // 客户端IP
UserAgent string // 用户代理
}
// 读取客户端数据
func (c *Client) Read() {
defer func() {
if r := recover(); r != nil {
g.Log().Warningf(mctx, "client read err: %+v, stack:%+v, user:%+v", r, string(debug.Stack()), c.User)
}
}()
defer c.close()
for {
_, message, err := c.Socket.ReadMessage()
if err != nil {
return
}
// 处理消息
handlerMsg(c, message)
}
}
// 向客户端写数据
func (c *Client) Write() {
defer func() {
if r := recover(); r != nil {
g.Log().Warningf(mctx, "client write err: %+v, stack:%+v, user:%+v", r, string(debug.Stack()), c.User)
}
}()
defer func() {
clientManager.Unregister <- c
_ = c.Socket.Close()
}()
for {
select {
case <-c.CloseSignal:
g.Log().Infof(mctx, "websocket client quit, user:%+v", c.User)
return
case message, ok := <-c.Send:
if !ok {
// 发送数据错误 关闭连接
g.Log().Warningf(mctx, "client write message, user:%+v", c.User)
return
}
_ = c.Socket.WriteJSON(message)
}
}
}
// SendMsg 发送数据
func (c *Client) SendMsg(msg *WResponse) {
if c == nil || c.SendClose {
return
}
defer func() {
if r := recover(); r != nil {
g.Log().Infof(mctx, "SendMsg err:%+v, stack:%+v", r, string(debug.Stack()))
}
}()
c.Send <- msg
}
// Context is alias for function GetCtx.
func (c *Client) Context() context.Context {
if c.context == nil {
c.context = gctx.New()
}
return c.context
}
// Heartbeat 心跳更新
func (c *Client) Heartbeat(currentTime uint64) {
c.HeartbeatTime = currentTime
}
// IsHeartbeatTimeout 心跳是否超时
func (c *Client) IsHeartbeatTimeout(currentTime uint64) (timeout bool) {
if c.HeartbeatTime+heartbeatExpirationTime <= currentTime {
timeout = true
}
return
}
// 关闭客户端
func (c *Client) close() {
if c.SendClose {
return
}
c.SendClose = true
c.CloseSignal <- struct{}{}
}
// Close 关闭指定客户端连接
func Close(client *Client) {
client.close()
}
// SendSuccess 发送成功消息
func SendSuccess(client *Client, event string, data ...interface{}) {
d := interface{}(nil)
if len(data) > 0 {
d = data[0]
}
client.SendMsg(&WResponse{
Event: event,
Data: d,
Code: gcode.CodeOK.Code(),
Timestamp: gtime.Now().Unix(),
})
before(client)
}
// SendError 发送错误消息
func SendError(client *Client, event string, err error) {
client.SendMsg(&WResponse{
Event: event,
Code: gcode.CodeNil.Code(),
ErrorMsg: err.Error(),
Timestamp: gtime.Now().Unix(),
})
before(client)
}
// before
func before(client *Client) {
client.Heartbeat(uint64(gtime.Now().Unix()))
}

View File

@ -0,0 +1,321 @@
package libWebsocket
import (
"context"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcron"
"github.com/gogf/gf/v2/os/gtime"
"runtime/debug"
"sync"
)
// ClientManager 客户端管理
type ClientManager struct {
Clients map[*Client]bool // 全部的连接
ClientsLock sync.RWMutex // 读写锁
Users map[string][]*Client // 登录的用户
UserLock sync.RWMutex // 读写锁
Register chan *Client // 连接连接处理
Login chan *login // 用户登录处理
Unregister chan *Client // 断开连接处理程序
Broadcast chan *WResponse // 广播 向全部成员发送数据
ClientBroadcast chan *ClientWResponse // 广播 向某个客户端发送数据
TagBroadcast chan *TagWResponse // 广播 向某个标签成员发送数据
UserBroadcast chan *UserWResponse // 广播 向某个用户的所有链接发送数据
closeSignal chan struct{} // 关闭信号
}
func NewClientManager() (clientManager *ClientManager) {
clientManager = &ClientManager{
Clients: make(map[*Client]bool),
Users: make(map[string][]*Client),
Register: make(chan *Client, 1000),
Unregister: make(chan *Client, 1000),
Broadcast: make(chan *WResponse, 1000),
TagBroadcast: make(chan *TagWResponse, 1000),
UserBroadcast: make(chan *UserWResponse, 1000),
closeSignal: make(chan struct{}, 1),
}
return
}
func Manager() *ClientManager {
return clientManager
}
// GetUserKey 获取用户key
func GetUserKey(userId uint64) (key string) {
key = fmt.Sprintf("%s_%d", "ws", userId)
return
}
// InClient 客户端是否存在
func (manager *ClientManager) InClient(client *Client) (ok bool) {
manager.ClientsLock.RLock()
defer manager.ClientsLock.RUnlock()
_, ok = manager.Clients[client]
return
}
// GetClients 获取所有客户端
func (manager *ClientManager) GetClients() (clients map[*Client]bool) {
clients = make(map[*Client]bool)
manager.ClientsRange(func(client *Client, value bool) (result bool) {
clients[client] = value
return true
})
return
}
// ClientsRange 遍历
func (manager *ClientManager) ClientsRange(f func(client *Client, value bool) (result bool)) {
manager.ClientsLock.RLock()
defer manager.ClientsLock.RUnlock()
for key, value := range manager.Clients {
if !f(key, value) {
return
}
}
}
// GetClientsLen 获取客户端总数
func (manager *ClientManager) GetClientsLen() (clientsLen int) {
clientsLen = len(manager.Clients)
return
}
// AddClients 添加客户端
func (manager *ClientManager) AddClients(client *Client) {
manager.ClientsLock.Lock()
defer manager.ClientsLock.Unlock()
manager.Clients[client] = true
}
// DelClients 删除客户端
func (manager *ClientManager) DelClients(client *Client) {
manager.ClientsLock.Lock()
defer manager.ClientsLock.Unlock()
delete(manager.Clients, client)
}
// GetClient 通过socket ID获取客户端的连接
func (manager *ClientManager) GetClient(id string) (client *Client) {
for c := range manager.Clients {
if c.ID == id {
return c
}
}
return
}
// GetUserClient 获取用户的连接
func (manager *ClientManager) GetUserClient(userId uint64) (clients []*Client) {
manager.UserLock.RLock()
defer manager.UserLock.RUnlock()
userKey := GetUserKey(userId)
if value, ok := manager.Users[userKey]; ok {
clients = value
}
return
}
// AddUsers 添加用户
func (manager *ClientManager) AddUsers(key string, client *Client) {
manager.UserLock.Lock()
defer manager.UserLock.Unlock()
manager.Users[key] = append(manager.Users[key], client)
}
// DelUsers 删除用户
func (manager *ClientManager) DelUsers(client *Client) (result bool) {
manager.UserLock.Lock()
defer manager.UserLock.Unlock()
key := GetUserKey(client.User.Id)
if clients, ok := manager.Users[key]; ok {
for _, value := range clients {
// 判断是否为相同的用户
if value.Addr != client.Addr {
return
}
delete(manager.Users, key)
result = true
}
}
return
}
// GetUsersLen 已登录用户数
func (manager *ClientManager) GetUsersLen() (userLen int) {
userLen = len(manager.Users)
return
}
// EventRegister 用户建立连接事件
func (manager *ClientManager) EventRegister(client *Client) {
manager.AddClients(client)
// 用户登录
manager.EventLogin(&login{
UserId: client.User.Id,
Client: client,
})
// 发送当前客户端标识
// SendSuccess(client, "connected", g.Map{"id": client.ID, "userInfo": client.User})
}
// EventLogin 用户登录事件
func (manager *ClientManager) EventLogin(login *login) {
client := login.Client
if manager.InClient(client) {
userKey := login.GetKey()
manager.AddUsers(userKey, login.Client)
}
}
// EventUnregister 用户断开连接事件
func (manager *ClientManager) EventUnregister(client *Client) {
manager.DelClients(client)
// 删除用户连接
deleteResult := manager.DelUsers(client)
if !deleteResult {
// 不是当前连接的客户端
return
}
client.close()
}
// ClearTimeoutConnections 定时清理超时连接
func (manager *ClientManager) clearTimeoutConnections() {
currentTime := uint64(gtime.Now().Unix())
clients := clientManager.GetClients()
for client := range clients {
if client.IsHeartbeatTimeout(currentTime) {
_ = client.Socket.Close()
}
}
}
// WebsocketPing 心跳处理
func (manager *ClientManager) ping() {
defer func() {
if r := recover(); r != nil {
g.Log().Warningf(mctx, "websocket gcron ping recover:%+v, stack:%+v", r, string(debug.Stack()))
return
}
}()
// 定时任务,发送心跳包
// gcron.Add(ctx, "0 */1 * * * *", func(ctx context.Context) {
// res := &WResponse{
// Event: "ping",
// Timestamp: gtime.Now().Unix(),
// }
// SendToAll(res)
// })
// 定时任务,清理超时连接
_, _ = gcron.Add(mctx, "*/30 * * * * *", func(ctx context.Context) {
manager.clearTimeoutConnections()
})
}
// 管道处理程序
func (manager *ClientManager) start() {
defer func() {
if r := recover(); r != nil {
g.Log().Warningf(mctx, "websocket start recover:%+v, stack:%+v", r, string(debug.Stack()))
return
}
}()
for {
select {
case conn := <-manager.Register:
// 建立连接事件
manager.EventRegister(conn)
case login := <-manager.Login:
// 用户登录
manager.EventLogin(login)
case conn := <-manager.Unregister:
// 断开连接事件
manager.EventUnregister(conn)
case message := <-manager.Broadcast:
// 全部客户端广播事件
clients := manager.GetClients()
for conn := range clients {
conn.SendMsg(message)
}
case message := <-manager.TagBroadcast:
// 标签广播事件
clients := manager.GetClients()
for conn := range clients {
if conn.Tags.Contains(message.Tag) {
if message.WResponse.Timestamp == 0 {
message.WResponse.Timestamp = gtime.Now().Timestamp()
}
conn.SendMsg(message.WResponse)
}
}
case message := <-manager.UserBroadcast:
// 用户广播事件
clients := manager.GetClients()
for conn := range clients {
if conn.User.Id == message.UserID {
if message.WResponse.Timestamp == 0 {
message.WResponse.Timestamp = gtime.Now().Timestamp()
}
conn.SendMsg(message.WResponse)
}
}
case message := <-manager.ClientBroadcast:
// 单个客户端广播事件
clients := manager.GetClients()
for conn := range clients {
if conn.ID == message.ID {
if message.WResponse.Timestamp == 0 {
message.WResponse.Timestamp = gtime.Now().Timestamp()
}
conn.SendMsg(message.WResponse)
}
}
case <-manager.closeSignal:
g.Log().Debug(mctx, "websocket CloseSignal quit..")
return
}
}
}
// SendToAll 发送全部客户端
func SendToAll(response *WResponse) {
clientManager.Broadcast <- response
}
// SendToClientID 发送单个客户端
func SendToClientID(id string, response *WResponse) {
clientRes := &ClientWResponse{
ID: id,
WResponse: response,
}
clientManager.ClientBroadcast <- clientRes
}
// SendToUser 发送单个用户
func SendToUser(userID uint64, response *WResponse) {
userRes := &UserWResponse{
UserID: userID,
WResponse: response,
}
clientManager.UserBroadcast <- userRes
}
// SendToTag 发送某个标签
func SendToTag(tag string, response *WResponse) {
tagRes := &TagWResponse{
Tag: tag,
WResponse: response,
}
clientManager.TagBroadcast <- tagRes
}

View File

@ -0,0 +1,30 @@
package libWebsocket
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/grpool"
)
var (
mctx = gctx.GetInitCtx() // 上下文
clientManager = NewClientManager() // 客户端管理
routers = make(map[string]EventHandler) // 消息路由
msgGo = grpool.New(20) // 消息处理协程池
)
// Start 启动
func Start() {
go clientManager.start()
go clientManager.ping()
g.Log().Debug(mctx, "start websocket..")
}
// Stop 关闭
func Stop() {
clientManager.closeSignal <- struct{}{}
}
func Register(client *Client) {
clientManager.Register <- client
}

View File

@ -0,0 +1,38 @@
package libWebsocket
import "github.com/gogf/gf/v2/frame/g"
// WRequest 输入对象
type WRequest struct {
Event string `json:"event"` // 事件名称
Data g.Map `json:"data"` // 数据
}
// WResponse 输出对象
type WResponse struct {
Event string `json:"event"` // 事件名称
Data interface{} `json:"data,omitempty"` // 数据
Code int `json:"code"` // 状态码
ErrorMsg string `json:"errorMsg,omitempty"` // 错误消息
Timestamp int64 `json:"timestamp"` // 服务器时间
}
type TagWResponse struct {
Tag string
WResponse *WResponse
}
type UserWResponse struct {
UserID uint64
WResponse *WResponse
}
type ClientWResponse struct {
ID string
WResponse *WResponse
}
// EventHandler 消息处理器
type EventHandler func(client *Client, req *WRequest)
type EventHandlers map[string]EventHandler

View File

@ -0,0 +1,59 @@
package libWebsocket
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"runtime/debug"
)
// handlerMsg 处理消息
func handlerMsg(client *Client, message []byte) {
defer func() {
if r := recover(); r != nil {
g.Log().Warningf(mctx, "handlerMsg recover, err:%+v, stack:%+v", r, string(debug.Stack()))
}
}()
var request *WRequest
if err := gconv.Struct(message, &request); err != nil {
g.Log().Warningf(mctx, "handlerMsg 数据解析失败,err:%+v, message:%+v", err, string(message))
return
}
if request.Event == "" {
g.Log().Warning(mctx, "handlerMsg request.Event is null")
return
}
fun, ok := routers[request.Event]
if !ok {
g.Log().Warningf(mctx, "handlerMsg function id %v: not registered", request.Event)
return
}
err := msgGo.AddWithRecover(mctx,
func(ctx context.Context) {
fun(client, request)
},
func(ctx context.Context, err error) {
g.Log().Warningf(mctx, "handlerMsg msgGo exec err:%+v", err)
},
)
if err != nil {
g.Log().Warningf(mctx, "handlerMsg msgGo Add err:%+v", err)
return
}
}
// RegisterMsg 注册消息
func RegisterMsg(handlers EventHandlers) {
for id, f := range handlers {
if _, ok := routers[id]; ok {
g.Log().Fatalf(mctx, "RegisterMsg function id %v: already registered", id)
return
}
routers[id] = f
}
}