dengbiao преди 4 часа
родител
ревизия
0db04e21d0
променени са 33 файла, в които са добавени 949 реда и са изтрити 105 реда
  1. +5
    -1
      app/cfg/app_redis_key.go
  2. +1
    -0
      app/cfg/cfg_app.go
  3. +0
    -3
      app/cfg/cfg_cache_key.go
  4. +2
    -0
      app/cfg/init_cfg.go
  5. +1
    -0
      app/cfg/init_task.go
  6. +38
    -1
      app/db/db.go
  7. +0
    -36
      app/db/db_sys_cfg.go
  8. +1
    -0
      app/db/im/db_customer_service.go
  9. +46
    -0
      app/db/im/db_sys_cfg.go
  10. +15
    -0
      app/db/im/model/customer_service.go
  11. +12
    -0
      app/db/im/model/emoticon.go
  12. +7
    -0
      app/db/im/model/sys_cfg.go
  13. +18
    -0
      app/db/im/model/user.go
  14. +31
    -0
      app/enum/im/enum_sys_cfg.go
  15. +2
    -1
      app/hdl/hdl_login.go
  16. +85
    -0
      app/hdl/im/hdl_basic.go
  17. +111
    -0
      app/hdl/im/hdl_customer_service.go
  18. +137
    -0
      app/hdl/im/hdl_emoticon.go
  19. +0
    -55
      app/lib/qiniu/req_img_upload.go
  20. +19
    -0
      app/md/im/md_basic.go
  21. +41
    -0
      app/md/im/md_customer_service.go
  22. +48
    -0
      app/md/im/md_emoticon.go
  23. +2
    -2
      app/mw/mw_admin_permission.go
  24. +16
    -0
      app/router/router.go
  25. +126
    -0
      app/svc/im/svc_customer_service.go
  26. +98
    -0
      app/svc/im/svc_emoticon.go
  27. +58
    -0
      app/svc/im/svc_sys_cfg_get.go
  28. +2
    -2
      app/svc/svc_login.go
  29. +3
    -2
      app/svc/svc_role.go
  30. +5
    -2
      app/utils/cache/redis.go
  31. +5
    -0
      cmd/task/main.go
  32. +11
    -0
      etc/cfg.yml
  33. +3
    -0
      main.go

app/md/app_redis_key.go → app/cfg/app_redis_key.go Целия файл

@@ -1,4 +1,4 @@
package md
package cfg

// 缓存key统一管理, %s格式化为masterId
const (
@@ -14,3 +14,7 @@ const (

AdminRolePermissionCacheTime = 3600 * 24 * 0.5
)

const (
IM_KEY_SYS_CFG_CACHE = "egg_im_sys_cfg_cache" //im配置表缓存键
)

+ 1
- 0
app/cfg/cfg_app.go Целия файл

@@ -12,6 +12,7 @@ type Config struct {
RedisAddr string `yaml:"redis_addr"`
RedisPassword string `yaml:"redis_password"`
DB DBCfg `yaml:"db"`
ImDB DBCfg `yaml:"im_db"`
Log LogCfg `yaml:"log"`
ImBusinessRpc ImBusinessRpcCfg `yaml:"im_business_rpc"`
ImLogicRpc ImLogicRpcCfg `yaml:"im_logic_rpc"`


+ 0
- 3
app/cfg/cfg_cache_key.go Целия файл

@@ -1,3 +0,0 @@
package cfg

// 统一管理缓存

+ 2
- 0
app/cfg/init_cfg.go Целия файл

@@ -16,6 +16,7 @@ var (
RedisAddr string
RedisPassword string
DB *DBCfg
IMDB *DBCfg
MQ *MQCfg
ES *ESCfg
Log *LogCfg
@@ -44,6 +45,7 @@ func InitCfg() {
Prd = conf.Prd
Debug = conf.Debug
DB = &conf.DB
IMDB = &conf.ImDB
Log = &conf.Log
RedisAddr = conf.RedisAddr
RedisPassword = conf.RedisPassword


+ 1
- 0
app/cfg/init_task.go Целия файл

@@ -27,6 +27,7 @@ func InitTaskCfg() {
Prd = conf.Prd
Debug = conf.Debug
DB = &conf.DB
IMDB = &conf.ImDB
Log = &conf.Log
RedisAddr = conf.RedisAddr
}


+ 38
- 1
app/db/db.go Целия файл

@@ -16,7 +16,7 @@ import (

var Db *xorm.Engine

//根据DB配置文件初始化数据库
// 根据DB配置文件初始化数据库
func InitDB(c *cfg.DBCfg) error {
var (
err error
@@ -51,6 +51,43 @@ func InitDB(c *cfg.DBCfg) error {
return nil
}

var DbIm *xorm.Engine

// 根据DB配置文件初始化数据库
func InitImDB(c *cfg.DBCfg) error {
var (
err error
f *os.File
)
//创建Orm引擎
if DbIm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", c.User, c.Psw, c.Host, c.Name)); err != nil {
return err
}
DbIm.SetConnMaxLifetime(c.MaxLifetime * time.Second) //设置最长连接时间
DbIm.SetMaxOpenConns(c.MaxOpenConns) //设置最大打开连接数
DbIm.SetMaxIdleConns(c.MaxIdleConns) //设置连接池的空闲数大小
if err = DbIm.Ping(); err != nil { //尝试ping数据库
return err
}
if c.ShowLog { //根据配置文件设置日志
DbIm.ShowSQL(true) //设置是否打印sql
DbIm.Logger().SetLevel(0) //设置日志等级
//修改日志文件存放路径文件名是%s.log
path := fmt.Sprintf(c.Path, c.Name)
f, err = os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777)
if err != nil {
os.RemoveAll(c.Path)
if f, err = os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777); err != nil {
return err
}
}
logger := log.NewSimpleLogger(f)
logger.ShowSQL(true)
DbIm.SetLogger(logger)
}
return nil
}

/********************************************* 公用方法 *********************************************/

// 数据批量插入


+ 0
- 36
app/db/db_sys_cfg.go Целия файл

@@ -2,10 +2,7 @@ package db

import (
"applet/app/db/model"
"applet/app/md"
"applet/app/utils/cache"
"applet/app/utils/logx"
"fmt"
"xorm.io/xorm"
)

@@ -47,36 +44,3 @@ func SysCfgUpdate(Db *xorm.Engine, key, val, memo string) bool {
}
return true
}
func SysCfgGetWithDb(eg *xorm.Engine, masterId string, HKey string) string {
cacheKey := fmt.Sprintf(md.AppCfgCacheKey, masterId) + HKey
get, err := cache.GetString(cacheKey)
if err != nil || get == "" {
cfg, err := SysCfgGetOne(eg, HKey)
if err != nil || cfg == nil {
_ = logx.Error(err)
return ""
}

// key是否存在
cacheKeyExist := false
if cache.Exists(cacheKey) {
cacheKeyExist = true
}

// 设置缓存
_, err = cache.SetEx(cacheKey, cfg.Val, 30)
if err != nil {
_ = logx.Error(err)
return ""
}
if !cacheKeyExist { // 如果是首次设置 设置过期时间
_, err := cache.Expire(cacheKey, md.CfgCacheTime)
if err != nil {
_ = logx.Error(err)
return ""
}
}
return cfg.Val
}
return get
}

+ 1
- 0
app/db/im/db_customer_service.go Целия файл

@@ -0,0 +1 @@
package db

+ 46
- 0
app/db/im/db_sys_cfg.go Целия файл

@@ -0,0 +1,46 @@
package db

import (
"applet/app/db/model"
"applet/app/utils/logx"
"xorm.io/xorm"
)

// 系统配置get
func SysCfgGetAll(Db *xorm.Engine) (*[]model.SysCfg, error) {
var cfgList []model.SysCfg
if err := Db.Cols("key,val,memo").Find(&cfgList); err != nil {
return nil, logx.Error(err)
}
return &cfgList, nil
}

// 获取一条记录
func SysCfgGetOne(Db *xorm.Engine, key string) (*model.SysCfg, error) {
var cfgList model.SysCfg
if has, err := Db.Where("`key`=?", key).Get(&cfgList); err != nil || has == false {
return nil, logx.Error(err)
}
return &cfgList, nil
}

// 返回最后插入id
func SysCfgInsert(Db *xorm.Engine, key, val, memo string) bool {
cfg := model.SysCfg{Key: key, Val: val, Memo: memo}
_, err := Db.InsertOne(&cfg)
if err != nil {
logx.Error(err)
return false
}
return true
}

func SysCfgUpdate(Db *xorm.Engine, key, val, memo string) bool {
cfg := model.SysCfg{Key: key, Val: val, Memo: memo}
_, err := Db.Where("`key`=?", key).Cols("val,memo").Update(&cfg)
if err != nil {
logx.Error(err)
return false
}
return true
}

+ 15
- 0
app/db/im/model/customer_service.go Целия файл

@@ -0,0 +1,15 @@
package model

import "time"

// CustomerService 客服表
type CustomerService struct {
Id int64
Uid int64 // 用户id
Weight int32 // 权重
State int32 // 状态
HasUserNums int // 拥有用户数量
Memo string // 备注
CreateTime time.Time // 创建时间
UpdateTime time.Time // 更新时间
}

+ 12
- 0
app/db/im/model/emoticon.go Целия файл

@@ -0,0 +1,12 @@
package model

type Emoticon struct {
Id int64
Name string // 名称
ImgUrl string // 图片地址
Memo string // 备注
Sort int // 排序
State int // 状态0关闭,1开启
CreateAt string // 创建时间
UpdateAt string // 更新时间
}

+ 7
- 0
app/db/im/model/sys_cfg.go Целия файл

@@ -0,0 +1,7 @@
package model

type SysCfg struct {
Key string `json:"key" xorm:"not null pk comment('键') VARCHAR(127)"`
Val string `json:"val" xorm:"comment('值') TEXT"`
Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(255)"`
}

+ 18
- 0
app/db/im/model/user.go Целия файл

@@ -0,0 +1,18 @@
package model

import (
"time"
)

// User 账户
type User struct {
Id int64 // 用户id
PhoneNumber string // 手机号
Nickname string // 昵称
Sex int32 // 性别,1:男;2:女
AvatarUrl string // 用户头像
Extra string // 附加属性
CreateTime time.Time // 创建时间
UpdateTime time.Time // 更新时间
IsAutoAddedFriends int // 是否自动被添加好友
}

+ 31
- 0
app/enum/im/enum_sys_cfg.go Целия файл

@@ -0,0 +1,31 @@
package enum

type SysCfg string

const (
IsAllowAddFriends = "is_allow_add_friends"
IsAutoAddFriends = "is_auto_add_friends"
ProhibitAddGroupMembers = "prohibit_add_group_members"
ProhibitRemoveGroupMembers = "prohibit_remove_group_members"
ProhibitUpdateGroupName = "prohibit_update_group_name"
ChatSensitiveWords = "chat_sensitive_words"
)

func (gt SysCfg) String() string {
switch gt {
case IsAllowAddFriends:
return "是否允许加好友"
case IsAutoAddFriends:
return "是否自动加好友"
case ProhibitAddGroupMembers:
return "是否禁止添加群成员"
case ProhibitRemoveGroupMembers:
return "是否禁止移出群成员"
case ProhibitUpdateGroupName:
return "是否禁止修改群名称"
case ChatSensitiveWords:
return "聊天敏感词"
default:
return "未知"
}
}

+ 2
- 1
app/hdl/hdl_login.go Целия файл

@@ -1,6 +1,7 @@
package hdl

import (
"applet/app/cfg"
"applet/app/db"
"applet/app/e"
"applet/app/lib/validate"
@@ -46,7 +47,7 @@ func Login(c *gin.Context) {
return
}
ip := utils.GetIP(c.Request)
key := fmt.Sprintf(md.JwtTokenKey, ip, utils.AnyToString(admin.AdmId))
key := fmt.Sprintf(cfg.JwtTokenKey, ip, utils.AnyToString(admin.AdmId))
token, err := svc.HandleLoginToken(key, admin)
if err != nil {
e.OutErr(c, e.ERR, err.Error())


+ 85
- 0
app/hdl/im/hdl_basic.go Целия файл

@@ -0,0 +1,85 @@
package im

import (
"applet/app/e"
enum "applet/app/enum/im"
md "applet/app/md/im"
svc "applet/app/svc/im"
"github.com/gin-gonic/gin"
)

// GetBasic
// @Summary Im-基础设置(获取)
// @Tags 基础设置
// @Description 基础设置(获取)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @Success 200 {object} md.GetBasicResp "设置列表"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/getBasic [get]
func GetBasic(c *gin.Context) {
res := svc.SysCfgFindComm(enum.IsAllowAddFriends, enum.IsAutoAddFriends, enum.ProhibitAddGroupMembers, enum.ProhibitRemoveGroupMembers, enum.ProhibitUpdateGroupName, enum.ChatSensitiveWords)

resp := md.GetBasicResp{
IsAllowAddFriends: res[enum.IsAllowAddFriends],
IsAutoAddFriends: res[enum.IsAutoAddFriends],
ProhibitAddGroupMembers: res[enum.ProhibitAddGroupMembers],
ProhibitRemoveGroupMembers: res[enum.ProhibitRemoveGroupMembers],
ProhibitUpdateGroupName: res[enum.ProhibitUpdateGroupName],
ChatSensitiveWords: res[enum.ProhibitUpdateGroupName],
}

e.OutSuc(c, resp, nil)
}

// SetBasic
// @Summary Im-基础设置(更新)
// @Tags 基础设置
// @Description 基础设置(更新)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.SetBasicReq true "上传需要修改的信息"
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/setBasic [post]
func SetBasic(c *gin.Context) {
var req *md.SetBasicReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}
var isTure = true
isTure = svc.SysCfgSet(enum.IsAllowAddFriends, req.IsAllowAddFriends, enum.SysCfg.String(enum.IsAllowAddFriends))
if !isTure {
e.OutErr(c, e.ERR_DB_ORM, "更新:"+enum.SysCfg.String(enum.IsAllowAddFriends)+",失败!")
return
}
isTure = svc.SysCfgSet(enum.IsAutoAddFriends, req.IsAutoAddFriends, enum.SysCfg.String(enum.IsAutoAddFriends))
if !isTure {
e.OutErr(c, e.ERR_DB_ORM, "更新:"+enum.SysCfg.String(enum.IsAutoAddFriends)+",失败!")
return
}
isTure = svc.SysCfgSet(enum.ProhibitAddGroupMembers, req.ProhibitAddGroupMembers, enum.SysCfg.String(enum.ProhibitAddGroupMembers))
if !isTure {
e.OutErr(c, e.ERR_DB_ORM, "更新:"+enum.SysCfg.String(enum.ProhibitAddGroupMembers)+",失败!")
return
}
isTure = svc.SysCfgSet(enum.ProhibitRemoveGroupMembers, req.ProhibitRemoveGroupMembers, enum.SysCfg.String(enum.ProhibitRemoveGroupMembers))
if !isTure {
e.OutErr(c, e.ERR_DB_ORM, "更新:"+enum.SysCfg.String(enum.ProhibitAddGroupMembers)+",失败!")
return
}
isTure = svc.SysCfgSet(enum.ProhibitUpdateGroupName, req.ProhibitUpdateGroupName, enum.SysCfg.String(enum.ProhibitUpdateGroupName))
if !isTure {
e.OutErr(c, e.ERR_DB_ORM, "更新:"+enum.SysCfg.String(enum.ProhibitUpdateGroupName)+",失败!")
return
}
isTure = svc.SysCfgSet(enum.ChatSensitiveWords, req.ChatSensitiveWords, enum.SysCfg.String(enum.ChatSensitiveWords))
if !isTure {
e.OutErr(c, e.ERR_DB_ORM, "更新:"+enum.SysCfg.String(enum.ChatSensitiveWords)+",失败!")
return
}
e.OutSuc(c, "success", nil)
}

+ 111
- 0
app/hdl/im/hdl_customer_service.go Целия файл

@@ -0,0 +1,111 @@
package im

import (
"applet/app/e"
md "applet/app/md/im"
svc "applet/app/svc/im"
"github.com/gin-gonic/gin"
)

// PageCustomerService
// @Summary Im-客服(列表)
// @Tags 客服
// @Description 客服(列表)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.PageCustomerServiceReq true
// @Success 200 {object} md.GetBasicResp "设置列表"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/pageCustomerService [POST]
func PageCustomerService(c *gin.Context) {
var req *md.PageCustomerServiceReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}
err, resp := svc.PageCustomerService(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, resp, nil)
}

// AddCustomerService
// @Summary Im-客服(新增)
// @Tags 客服
// @Description 客服(新增)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.AddCustomerServiceReq true
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/addCustomerService [post]
func AddCustomerService(c *gin.Context) {
var req *md.AddCustomerServiceReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}

err := svc.AddCustomerService(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, "success", nil)
}

// SetCustomerServiceState
// @Summary Im-客服(更新状态)
// @Tags 客服
// @Description 客服(更新状态)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.SetCustomerServiceStateReq true
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/setCustomerServiceState [post]
func SetCustomerServiceState(c *gin.Context) {
var req *md.SetCustomerServiceStateReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}

err := svc.SetCustomerServiceState(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, "success", nil)
}

// UpdateCustomerServiceMemo
// @Summary Im-客服(编辑备注)
// @Tags 客服
// @Description 客服(编辑备注)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.UpdateCustomerServiceMemoReq true
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/updateCustomerServiceMemo [post]
func UpdateCustomerServiceMemo(c *gin.Context) {
var req *md.UpdateCustomerServiceMemoReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}

err := svc.UpdateCustomerServiceMemo(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, "success", nil)
}

+ 137
- 0
app/hdl/im/hdl_emoticon.go Целия файл

@@ -0,0 +1,137 @@
package im

import (
"applet/app/e"
md "applet/app/md/im"
svc "applet/app/svc/im"
"github.com/gin-gonic/gin"
)

// PageEmoticon
// @Summary Im-表情包(列表)
// @Tags 表情包
// @Description 表情包(列表)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.PageEmoticonReq true
// @Success 200 {object} md.GetBasicResp "设置列表"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/pageEmoticon [POST]
func PageEmoticon(c *gin.Context) {
var req *md.PageEmoticonReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}
err, resp := svc.PageEmoticon(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, resp, nil)
}

// AddEmoticon
// @Summary Im-表情包(新增)
// @Tags 表情包
// @Description 表情包(新增)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.AddEmoticonReq true
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/addEmoticon [post]
func AddEmoticon(c *gin.Context) {
var req *md.AddEmoticonReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}

err := svc.AddEmoticon(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, "success", nil)
}

// SetEmoticonState
// @Summary Im-表情包(更新状态)
// @Tags 表情包
// @Description 表情包(新增)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.SetEmoticonStateReq true
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/setEmoticonState [post]
func SetEmoticonState(c *gin.Context) {
var req *md.SetEmoticonStateReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}

err := svc.SetEmoticonState(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, "success", nil)
}

// UpdateEmoticon
// @Summary Im-表情包(编辑)
// @Tags 表情包
// @Description 表情包(编辑)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.UpdateEmoticonReq true
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/updateEmoticon [post]
func UpdateEmoticon(c *gin.Context) {
var req *md.UpdateEmoticonReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}

err := svc.UpdateEmoticon(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, "success", nil)
}

// DeleteEmoticon
// @Summary Im-表情包(删除)
// @Tags 表情包
// @Description 表情包(删除)
// @Accept json
// @Produce json
// @param Authorization header string true "验证参数Bearer和token空格拼接"
// @param req body md.DeleteEmoticonReq true
// @Success 200 {string} "success"
// @Failure 400 {object} md.Response "具体错误"
// @Router /api/im/deleteEmoticon [post]
func DeleteEmoticon(c *gin.Context) {
var req *md.DeleteEmoticonReq
if err1 := c.ShouldBindJSON(&req); err1 != nil {
e.OutErr(c, e.ERR_INVALID_ARGS, err1.Error())
return
}

err := svc.DeleteEmoticon(*req)
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
e.OutSuc(c, "success", nil)
}

+ 0
- 55
app/lib/qiniu/req_img_upload.go Целия файл

@@ -1,55 +0,0 @@
package qiniu

import (
"time"

"github.com/qiniu/api.v7/v7/auth/qbox"
_ "github.com/qiniu/api.v7/v7/conf"
"github.com/qiniu/api.v7/v7/storage"

"applet/app/md"
"applet/app/utils"
)

// 请求图片上传地址信息
func ReqImgUpload(f *md.FileCallback, callbackUrl string) interface{} {
if ext := utils.FileExt(f.FileName); ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "gif" || ext == "bmp" || ext == "webp" {
f.Width = "$(imageInfo.width)"
f.Height = "$(imageInfo.height)"
}
f.Provider = "qiniu"
f.FileSize = "$(fsize)"
f.Hash = "$(etag)"
f.Bucket = "$(bucket)"
f.Mime = "$(mimeType)"
f.Time = utils.Int64ToStr(time.Now().Unix())
f.Sign = Sign(f.Time)
putPolicy := storage.PutPolicy{
Scope: BUCKET + ":" + f.FileName, // 使用覆盖方式时候必须请求里面有key,否则报错
Expires: Expires,
ForceSaveKey: true,
SaveKey: f.FileName,
MimeLimit: "image/*", // 只允许上传图片
CallbackURL: callbackUrl,
CallbackBody: utils.SerializeStr(f),
CallbackBodyType: "application/json",
}
return &struct {
Method string `json:"method"`
Key string `json:"key"`
Host string `json:"host"`
Token string `json:"token"`
}{Key: f.FileName, Method: "POST", Host: BUCKET_SCHEME + "://" + BUCKET_REGION, Token: putPolicy.UploadToken(qbox.NewMac(AK, SK))}
}

/*
form表单上传
地址 : http://upload-z2.qiniup.com
header
- Content-Type : multipart/form-data

body :
- key : 文件名
- token : 生成token
- file : 待上传文件
*/

+ 19
- 0
app/md/im/md_basic.go Целия файл

@@ -0,0 +1,19 @@
package md

type GetBasicResp struct {
IsAllowAddFriends string `json:"is_allow_add_friends" example:"是否允许加好友"`
IsAutoAddFriends string `json:"is_auto_add_friends" example:"是否自动加好友"`
ProhibitAddGroupMembers string `json:"prohibit_add_group_members" example:"是否禁止添加群成员"`
ProhibitRemoveGroupMembers string `json:"prohibit_remove_group_members" example:"是否禁止移出群成员"`
ProhibitUpdateGroupName string `json:"prohibit_update_group_name" example:"是否禁止修改群名称"`
ChatSensitiveWords string `json:"chat_sensitive_words" example:"聊天敏感词"`
}

type SetBasicReq struct {
IsAllowAddFriends string `json:"is_allow_add_friends" example:"是否允许加好友"`
IsAutoAddFriends string `json:"is_auto_add_friends" example:"是否自动加好友"`
ProhibitAddGroupMembers string `json:"prohibit_add_group_members" example:"是否禁止添加群成员"`
ProhibitRemoveGroupMembers string `json:"prohibit_remove_group_members" example:"是否禁止移出群成员"`
ProhibitUpdateGroupName string `json:"prohibit_update_group_name" example:"是否禁止修改群名称"`
ChatSensitiveWords string `json:"chat_sensitive_words" example:"聊天敏感词"`
}

+ 41
- 0
app/md/im/md_customer_service.go Целия файл

@@ -0,0 +1,41 @@
package md

type PageCustomerServiceReq struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
State int `json:"state"` //状态
Memo string `json:"memo" example:"备注"`
}

type PageCustomerServiceResp struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int64 `json:"total"`
List []struct {
Id int64 `json:"id"` //记录id
Phone string `json:"phone" example:"手机号"`
Nickname string `json:"nickname" example:"昵称"`
Weight int32 `json:"weight"` // 权重
State int32 `json:"state"` // 状态(1:正常 2:冻结)
HaasUserNums int `json:"has_user_nums"` // 拥有用户数量
Memo string `json:"memo" example:"备注"` // 备注
CreateTime string `json:"create_time" example:"创建时间"` // 创建时间
UpdateTime string `json:"update_time" example:"更新时间"` // 更新时间
} `json:"list"`
}

type AddCustomerServiceReq struct {
Phone string `json:"phone" example:"手机号"`
Memo string `json:"memo" example:"备注"` // 备注
Weight int32 `json:"weight"` // 权重
}

type SetCustomerServiceStateReq struct {
Id int `json:"id"` // 拥有用户数量
State int32 `json:"state"` // 状态
}

type UpdateCustomerServiceMemoReq struct {
Id int `json:"id"` // 拥有用户数量
Memo string `json:"memo" example:"备注"` // 备注
}

+ 48
- 0
app/md/im/md_emoticon.go Целия файл

@@ -0,0 +1,48 @@
package md

type PageEmoticonReq struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
State int `json:"state"` //状态
Memo string `json:"memo" example:"备注"`
}

type PageEmoticonResp struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int64 `json:"total"`
List []struct {
Id int64 `json:"id"` //记录id
Name string `json:"name" example:"名称"`
ImgUrl string `json:"img_url" example:"图片地址"`
Sort int `json:"Sort"` // 排序
State int `json:"state"` // 状态0关闭,1开启
Memo string `json:"memo" example:"备注"` // 备注
CreateAt string `json:"create_at" example:"创建时间"` // 创建时间
UpdateAt string `json:"update_at" example:"更新时间"` // 更新时间
} `json:"list"`
}

type AddEmoticonReq struct {
Name string `json:"name" example:"名称"`
ImgUrl string `json:"img_url" example:"图片地址"`
Memo string `json:"memo" example:"备注"` // 备注
Sort int `json:"sort"` // 排序
}

type SetEmoticonStateReq struct {
Id int `json:"id"` // 拥有用户数量
State int `json:"state"` // 状态
}

type UpdateEmoticonReq struct {
Id int `json:"id"` // 拥有用户数量
Name string `json:"name" example:"名称"`
ImgUrl string `json:"img_url" example:"图片地址"`
Memo string `json:"memo" example:"备注"` // 备注
Sort int `json:"sort"` // 排序
}

type DeleteEmoticonReq struct {
Id int `json:"id"` // 拥有用户数量
}

+ 2
- 2
app/mw/mw_admin_permission.go Целия файл

@@ -1,9 +1,9 @@
package mw

import (
"applet/app/cfg"
"applet/app/e"
"applet/app/enum"
"applet/app/md"
"applet/app/svc"
"applet/app/utils"
"fmt"
@@ -18,7 +18,7 @@ func CheckPermission(c *gin.Context) {
if admin.IsSuperAdministrator == enum.IsSuperAdministratorTure {
c.Next()
} else {
rolePermissionKey := fmt.Sprintf(md.AdminRolePermissionKey, utils.AnyToString(admin.AdmId))
rolePermissionKey := fmt.Sprintf(cfg.AdminRolePermissionKey, utils.AnyToString(admin.AdmId))
isHasPermission, err := svc.CheckUserRole(c, rolePermissionKey, c.Request.RequestURI, admin.AdmId)
if err != nil {
e.OutErr(c, e.ERR, err.Error())


+ 16
- 0
app/router/router.go Целия файл

@@ -4,6 +4,7 @@ import (
"applet/app/cfg"
"applet/app/hdl"
"applet/app/hdl/comm"
"applet/app/hdl/im"
"applet/app/hdl/institutional_management/egg_energy"
"applet/app/hdl/institutional_management/public_platoon"
"applet/app/hdl/marketing_applications/new_user_red_package"
@@ -56,6 +57,7 @@ func route(r *gin.RouterGroup) {
r.POST("/login", hdl.Login)
r.Use(mw.Auth) // 以下接口需要JWT验证
rComm(r.Group("/comm"))
rIm(r.Group("/im"))
r.Use(mw.CheckPermission) // 检测权限
rInstitutionalManagement(r.Group("/institutionalManagement"))
rMarketingApplications(r.Group("/marketingApplications"))
@@ -186,6 +188,20 @@ func rMemberCenter(r *gin.RouterGroup) { // 会员中心
}
}

func rIm(r *gin.RouterGroup) {
r.GET("/getBasic", im.GetBasic)
r.POST("/setBasic", im.SetBasic)
r.POST("/pageEmoticon", im.PageEmoticon)
r.POST("/addEmoticon", im.AddEmoticon)
r.POST("/setEmoticonState", im.SetEmoticonState)
r.POST("/updateEmoticon", im.UpdateEmoticon)
r.POST("/deleteEmoticon", im.DeleteEmoticon)
r.POST("/pageCustomerService", im.PageCustomerService)
r.POST("/addCustomerService", im.AddCustomerService)
r.POST("/setCustomerServiceState", im.SetCustomerServiceState)
r.POST("/updateCustomerServiceMemo", im.UpdateCustomerServiceMemo)
}

func rComm(r *gin.RouterGroup) {
r.POST("/getMenuList", comm.MenuList) // 获取菜单栏列表
r.GET("/getOssUrl", comm.GetOssUrl) // 获取阿里云上传PutObject所需的签名URL


+ 126
- 0
app/svc/im/svc_customer_service.go Целия файл

@@ -0,0 +1,126 @@
package svc

import (
"applet/app/db"
"applet/app/db/im/model"
md "applet/app/md/im"
"errors"
"time"
)

func PageCustomerService(req md.PageCustomerServiceReq) (err error, resp md.PageCustomerServiceResp) {
sess := db.DbIm.Where("1=1")
if req.Memo != "" {
sess.And("memo LIKE ?", "%"+req.Memo+"%")
}
if req.State != 0 {
sess.And("memo = ?", req.State)
}
var mm []*model.CustomerService
resp.Total, err = sess.Limit(req.PageSize, (req.Page-1)*req.PageSize).Asc("a.id").FindAndCount(&mm)
if err != nil {
return
}
resp.Page = req.Page
resp.PageSize = req.PageSize
for _, v := range mm {
var user model.User
_, err = db.DbIm.Where("`id`=?", v.Uid).Get(&user)
if err != nil {
return
}

resp.List = append(resp.List, struct {
Id int64 `json:"id"` //记录id
Phone string `json:"phone" example:"手机号"`
Nickname string `json:"nickname" example:"昵称"`
Weight int32 `json:"weight"` // 权重
State int32 `json:"state"` // 状态
HaasUserNums int `json:"has_user_nums"` // 拥有用户数量
Memo string `json:"memo" example:"备注"` // 备注
CreateTime string `json:"create_time" example:"创建时间"` // 创建时间
UpdateTime string `json:"update_time" example:"更新时间"` // 更新时间
}{
Id: v.Id,
Phone: user.PhoneNumber,
Nickname: user.Nickname,
Weight: v.Weight,
State: v.State,
HaasUserNums: v.HasUserNums,
Memo: v.Memo,
CreateTime: v.CreateTime.Format("2006-01-02 15:04:05"),
UpdateTime: v.UpdateTime.Format("2006-01-02 15:04:05"),
})
}
return
}

func AddCustomerService(req md.AddCustomerServiceReq) (err error) {
var user model.User
has, err := db.DbIm.Where("`phone_number`=?", req.Phone).Get(&user)
if err != nil {
return
}
if !has {
return errors.New("未查询到对应手机号账号记录")
}

var customerService model.CustomerService
has, err = db.DbIm.Where("`uid`=?", user.Id).Get(&customerService)
if err != nil {
return
}
if has {
return errors.New("该账号已是客服!")
}

cfg := model.CustomerService{
Uid: user.Id,
Weight: req.Weight,
State: 1,
HasUserNums: 0,
Memo: req.Memo,
CreateTime: time.Time{},
UpdateTime: time.Time{},
}
_, err = db.DbIm.InsertOne(&cfg)
if err != nil {
return
}

return
}

func SetCustomerServiceState(req md.SetCustomerServiceStateReq) (err error) {
var customerService model.CustomerService
has, err := db.DbIm.ID(req.Id).Get(&customerService)
if err != nil {
return
}
if has {
return errors.New("未查询到对应记录!")
}
customerService.State = req.State
_, err = db.DbIm.ID(req.Id).Cols("state").Update(&customerService)
if err != nil {
return
}
return
}

func UpdateCustomerServiceMemo(req md.UpdateCustomerServiceMemoReq) (err error) {
var customerService model.CustomerService
has, err := db.DbIm.ID(req.Id).Get(&customerService)
if err != nil {
return
}
if has {
return errors.New("未查询到对应记录!")
}
customerService.Memo = req.Memo
_, err = db.DbIm.ID(req.Id).Cols("memo").Update(&customerService)
if err != nil {
return
}
return
}

+ 98
- 0
app/svc/im/svc_emoticon.go Целия файл

@@ -0,0 +1,98 @@
package svc

import (
"applet/app/db"
"applet/app/db/im/model"
md "applet/app/md/im"
"errors"
"time"
)

func PageEmoticon(req md.PageEmoticonReq) (err error, resp md.PageEmoticonResp) {
sess := db.DbIm.Where("1=1")
if req.Memo != "" {
sess.And("memo LIKE ?", "%"+req.Memo+"%")
}
if req.State != 0 {
sess.And("memo = ?", req.State)
}
var mm []*model.Emoticon
resp.Total, err = sess.Limit(req.PageSize, (req.Page-1)*req.PageSize).Asc("a.id").FindAndCount(&mm)
if err != nil {
return
}
resp.Page = req.Page
resp.PageSize = req.PageSize
for _, v := range mm {
resp.List = append(resp.List, struct {
Id int64 `json:"id"` //记录id
Name string `json:"name" example:"名称"`
ImgUrl string `json:"img_url" example:"图片地址"`
Sort int `json:"Sort"` // 权重
State int `json:"state"` // 状态0关闭,1开启
Memo string `json:"memo" example:"备注"` // 备注
CreateAt string `json:"create_at" example:"创建时间"` // 创建时间
UpdateAt string `json:"update_at" example:"更新时间"` // 更新时间
}{Id: v.Id, Name: v.Name, ImgUrl: v.ImgUrl, Sort: v.Sort, State: v.State, Memo: v.Memo, CreateAt: v.CreateAt, UpdateAt: v.UpdateAt})
}
return
}

func AddEmoticon(req md.AddEmoticonReq) (err error) {
cfg := model.Emoticon{
Name: req.Name,
ImgUrl: req.ImgUrl,
Memo: req.Memo,
Sort: req.Sort,
State: 1,
CreateAt: time.Now().Format("2006-01-02 15:04:05"),
UpdateAt: time.Now().Format("2006-01-02 15:04:05"),
}
_, err = db.DbIm.InsertOne(&cfg)
if err != nil {
return
}
return
}

func SetEmoticonState(req md.SetEmoticonStateReq) (err error) {
var customerService model.Emoticon
has, err := db.DbIm.ID(req.Id).Get(&customerService)
if err != nil {
return
}
if has {
return errors.New("未查询到对应记录!")
}
customerService.State = req.State
_, err = db.DbIm.ID(req.Id).Cols("state").Update(&customerService)
if err != nil {
return
}
return
}

func UpdateEmoticon(req md.UpdateEmoticonReq) (err error) {
var customerService model.Emoticon
has, err := db.DbIm.ID(req.Id).Get(&customerService)
if err != nil {
return
}
if has {
return errors.New("未查询到对应记录!")
}
customerService.Name = req.Name
customerService.ImgUrl = req.ImgUrl
customerService.Sort = req.Sort
customerService.Memo = req.Memo
_, err = db.DbIm.ID(req.Id).Update(&customerService)
if err != nil {
return
}
return
}

func DeleteEmoticon(req md.DeleteEmoticonReq) (err error) {
_, err = db.DbIm.Where("id = ?", req.Id).Delete(&model.Emoticon{})
return
}

+ 58
- 0
app/svc/im/svc_sys_cfg_get.go Целия файл

@@ -0,0 +1,58 @@
package svc

import (
cfgMd "applet/app/cfg"
db2 "applet/app/db"
db "applet/app/db/im"
"applet/app/utils/cache"
)

// 多条记录获取
func SysCfgFind(keys ...string) map[string]string {
tmp := SysCfgFindComm(keys...)
return tmp
}

// SysCfgFindComm get cfg by master id
func SysCfgFindComm(keys ...string) map[string]string {
res := map[string]string{}
cfgList, _ := db.SysCfgGetAll(db2.DbIm)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}

if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// SysCfgCleanCache 清理系统配置信息
func SysCfgCleanCache() {
cache.SelectDb(1) //TODO::IM统一放1号库
cache.Del(cfgMd.IM_KEY_SYS_CFG_CACHE)
}

// SysCfgSet 写入系统设置
func SysCfgSet(key, val, memo string) bool {
cfg, err := db.SysCfgGetOne(db2.DbIm, key)
if err != nil || cfg == nil {
return db.SysCfgInsert(db2.DbIm, key, val, memo)
}
if memo != "" && cfg.Memo != memo {
cfg.Memo = memo
}
SysCfgCleanCache()
return db.SysCfgUpdate(db2.DbIm, key, val, cfg.Memo)
}

+ 2
- 2
app/svc/svc_login.go Целия файл

@@ -1,8 +1,8 @@
package svc

import (
"applet/app/cfg"
"applet/app/lib/auth"
"applet/app/md"
"applet/app/utils/cache"
"applet/app/utils/logx"
"code.fnuoos.com/EggPlanet/egg_models.git/src/model"
@@ -22,7 +22,7 @@ func HandleLoginToken(cacheKey string, admin *model.Admin) (string, error) {
return "", err
}
// 缓存token
_, err = cache.SetEx(cacheKey, token, md.JwtTokenCacheTime)
_, err = cache.SetEx(cacheKey, token, cfg.JwtTokenCacheTime)
if err != nil {
return "", err
}


+ 3
- 2
app/svc/svc_role.go Целия файл

@@ -1,6 +1,7 @@
package svc

import (
"applet/app/cfg"
"applet/app/db"
"applet/app/md"
"applet/app/utils"
@@ -48,7 +49,7 @@ func CheckUserRole(c *gin.Context, cacheKey, uri string, admId int) (isHasPermis
return isHasPermission, err1
}
rolePermissionString = string(marshal)
_, err = cache.SetEx(cacheKey, rolePermissionString, md.AdminRolePermissionCacheTime)
_, err = cache.SetEx(cacheKey, rolePermissionString, cfg.AdminRolePermissionCacheTime)
}

if utils.InArr(uri, rolePermission) {
@@ -144,7 +145,7 @@ func RoleBindPermissionGroup(c *gin.Context, req md.RoleBindPermissionGroupReq)
var data []model.AdminRole
engine.Where("role_id=?", role.Id).Find(&data)
for _, v := range data {
rolePermissionKey := fmt.Sprintf(md.AdminRolePermissionKey, utils.AnyToString(v.AdmId))
rolePermissionKey := fmt.Sprintf(cfg.AdminRolePermissionKey, utils.AnyToString(v.AdmId))
cache.Del(rolePermissionKey)
}
return nil


+ 5
- 2
app/utils/cache/redis.go Целия файл

@@ -132,6 +132,10 @@ func SetEx(key string, data interface{}, ttl int) (interface{}, error) {
return Do("SETEX", key, ttl, data)
}

func SelectDb(db int) (interface{}, error) {
return Do("SELECT", db)
}

func SetJson(key string, data interface{}, ttl int) bool {
c, err := json.Marshal(data)
if err != nil {
@@ -402,8 +406,7 @@ func Scan(cursor int64, pattern string, count int64) (int64, []string, error) {
return newCursor, items, nil
}


func LPushMax(key string, data ...interface{}) (interface{}, error) {
// set
return Do("LPUSH", key, data)
}
}

+ 5
- 0
cmd/task/main.go Целия файл

@@ -25,6 +25,11 @@ func init() {
if err := db.InitDB(&baseDb); err != nil {
panic(err)
}
baseImDb := *cfg.IMDB
baseImDb.Path = fmt.Sprintf(cfg.IMDB.Path, cfg.IMDB.Name)
if err := db.InitImDB(&baseImDb); err != nil {
panic(err)
}
utils.CurlDebug = true
//cfg.InitMemCache()
}


+ 11
- 0
etc/cfg.yml Целия файл

@@ -20,6 +20,17 @@ db:
max_idle_conns: 100
path: 'tmp/%s.log'

im_db:
host: '119.23.182.117:3306'
name: 'egg'
user: 'root'
psw: 'Fnuo123com@'
show_log: true
max_lifetime: 30
max_open_conns: 100
max_idle_conns: 100
path: 'tmp/%s.log'

# 日志
log:
app_name: 'applet'


+ 3
- 0
main.go Целия файл

@@ -27,6 +27,9 @@ func init() {
if err := db.InitDB(cfg.DB); err != nil { // 主数据库初始化
panic(err)
}
if err := db.InitImDB(cfg.IMDB); err != nil { // IM主数据库初始化
panic(err)
}
}
fmt.Println("init success")



Зареждане…
Отказ
Запис