feat: add IM org and notification admin
This commit is contained in:
@@ -0,0 +1,362 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
)
|
||||
|
||||
type sSysImOrg struct{}
|
||||
|
||||
func NewSysImOrg() *sSysImOrg {
|
||||
return &sSysImOrg{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterSysImOrg(NewSysImOrg())
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) DepartmentList(ctx context.Context, in *sysin.ImOrgDepartmentListInp) (list []*sysin.ImOrgDepartmentModel, totalCount int, err error) {
|
||||
if err = in.Filter(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
db, tenant, err := resolveImTenantDB(ctx, in.TenantId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
mod := s.departmentModel(ctx, db)
|
||||
if in.DepartmentId != "" {
|
||||
mod = mod.Where("d.department_id", strings.TrimSpace(in.DepartmentId))
|
||||
}
|
||||
if in.ParentId != "" {
|
||||
mod = mod.Where("d.parent_id", strings.TrimSpace(in.ParentId))
|
||||
}
|
||||
if in.Name != "" {
|
||||
mod = mod.WhereLike("d.name", "%"+strings.TrimSpace(in.Name)+"%")
|
||||
}
|
||||
if in.State != "" {
|
||||
mod = mod.Where("d.state", strings.TrimSpace(in.State))
|
||||
}
|
||||
mod = mod.Page(in.Page, in.PerPage).OrderAsc("d.sort_order").OrderAsc("d.id")
|
||||
if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
|
||||
err = gerror.Wrap(err, "获取IM组织部门失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
for _, item := range list {
|
||||
item.TenantId = tenant.Id
|
||||
item.TenantName = tenant.Name
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) DepartmentEdit(ctx context.Context, in *sysin.ImOrgDepartmentEditInp) (err error) {
|
||||
if err = in.Filter(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
db, tenant, err := resolveImTenantDB(ctx, in.TenantId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if in.ParentId != "root" {
|
||||
if exists, err := s.departmentExists(ctx, db, in.ParentId); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return gerror.New("上级部门不存在")
|
||||
}
|
||||
}
|
||||
if in.Id > 0 {
|
||||
current, err := db.Model("im_org_departments").Safe().Ctx(ctx).Where("id", in.Id).One()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "获取IM组织部门失败,请稍后重试!")
|
||||
}
|
||||
if current.IsEmpty() {
|
||||
return gerror.New("部门不存在")
|
||||
}
|
||||
departmentId := current["department_id"].String()
|
||||
if in.ParentId == departmentId {
|
||||
return gerror.New("上级部门不能选择自身")
|
||||
}
|
||||
if err = s.ensureNoDepartmentCycle(ctx, db, departmentId, in.ParentId); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = db.Model("im_org_departments").Safe().Ctx(ctx).
|
||||
Where("id", in.Id).
|
||||
Data(g.Map{
|
||||
"name": in.Name,
|
||||
"parent_id": in.ParentId,
|
||||
"sort_order": in.SortOrder,
|
||||
"state": in.State,
|
||||
"version": gdb.Raw("version+1"),
|
||||
"updated_at": gtime.Now(),
|
||||
}).Update(); err != nil {
|
||||
return gerror.Wrap(err, "更新IM组织部门失败,请稍后重试!")
|
||||
}
|
||||
_ = writeImAdminAudit(ctx, tenant.Id, "im_org_department_update", "im_org_department", in.Id, "success", g.Map{"department_id": departmentId})
|
||||
return nil
|
||||
}
|
||||
departmentId := in.DepartmentId
|
||||
if departmentId == "" {
|
||||
departmentId = "dep_" + strings.ToLower(guid.S())
|
||||
}
|
||||
if exists, err := s.departmentExists(ctx, db, departmentId); err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
return gerror.New("部门ID已存在")
|
||||
}
|
||||
if _, err = db.Model("im_org_departments").Safe().Ctx(ctx).Data(g.Map{
|
||||
"department_id": departmentId,
|
||||
"name": in.Name,
|
||||
"parent_id": in.ParentId,
|
||||
"sort_order": in.SortOrder,
|
||||
"state": in.State,
|
||||
"version": 1,
|
||||
"created_at": gtime.Now(),
|
||||
"updated_at": gtime.Now(),
|
||||
}).Insert(); err != nil {
|
||||
return gerror.Wrap(err, "创建IM组织部门失败,请稍后重试!")
|
||||
}
|
||||
_ = writeImAdminAudit(ctx, tenant.Id, "im_org_department_create", "im_org_department", 0, "success", g.Map{"department_id": departmentId})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) DepartmentDelete(ctx context.Context, in *sysin.ImOrgDepartmentDeleteInp) (err error) {
|
||||
if err = in.Filter(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
db, tenant, err := resolveImTenantDB(ctx, in.TenantId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if in.DepartmentId == "root" {
|
||||
return gerror.New("根部门不能删除")
|
||||
}
|
||||
if exists, err := s.departmentExists(ctx, db, in.DepartmentId); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return gerror.New("部门不存在")
|
||||
}
|
||||
childCount, err := db.Model("im_org_departments").Safe().Ctx(ctx).Where("parent_id", in.DepartmentId).Count()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "检查子部门失败,请稍后重试!")
|
||||
}
|
||||
if childCount > 0 {
|
||||
return gerror.New("存在子部门,请先处理后再删除")
|
||||
}
|
||||
memberCount, err := db.Model("im_org_members").Safe().Ctx(ctx).Where("department_id", in.DepartmentId).Count()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "检查部门成员失败,请稍后重试!")
|
||||
}
|
||||
if memberCount > 0 {
|
||||
return gerror.New("存在部门成员,请先移除后再删除")
|
||||
}
|
||||
if _, err = db.Model("im_org_departments").Safe().Ctx(ctx).Where("department_id", in.DepartmentId).Delete(); err != nil {
|
||||
return gerror.Wrap(err, "删除IM组织部门失败,请稍后重试!")
|
||||
}
|
||||
_ = writeImAdminAudit(ctx, tenant.Id, "im_org_department_delete", "im_org_department", 0, "success", g.Map{"department_id": in.DepartmentId})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) MemberList(ctx context.Context, in *sysin.ImOrgMemberListInp) (list []*sysin.ImOrgMemberModel, totalCount int, err error) {
|
||||
if err = in.Filter(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
db, tenant, err := resolveImTenantDB(ctx, in.TenantId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
mod := s.memberModel(ctx, db)
|
||||
if in.DepartmentId != "" {
|
||||
mod = mod.Where("m.department_id", strings.TrimSpace(in.DepartmentId))
|
||||
}
|
||||
if in.UserId > 0 {
|
||||
mod = mod.Where("m.user_id", in.UserId)
|
||||
}
|
||||
if in.EmploymentState != "" {
|
||||
mod = mod.Where("m.employment_state", strings.TrimSpace(in.EmploymentState))
|
||||
}
|
||||
if q := strings.TrimSpace(in.Query); q != "" {
|
||||
like := "%" + q + "%"
|
||||
mod = mod.Where("(m.display_name LIKE ? OR m.mobile LIKE ? OR m.email LIKE ? OR CAST(m.user_id AS CHAR) LIKE ?)", like, like, like, like)
|
||||
}
|
||||
mod = mod.Page(in.Page, in.PerPage).OrderAsc("m.sort_order").OrderAsc("m.id")
|
||||
if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
|
||||
err = gerror.Wrap(err, "获取IM组织成员失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
for _, item := range list {
|
||||
item.TenantId = tenant.Id
|
||||
item.TenantName = tenant.Name
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) MemberEdit(ctx context.Context, in *sysin.ImOrgMemberEditInp) (err error) {
|
||||
if err = in.Filter(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
db, tenant, err := resolveImTenantDB(ctx, in.TenantId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if exists, err := s.departmentExists(ctx, db, in.DepartmentId); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return gerror.New("部门不存在")
|
||||
}
|
||||
userCount, err := db.Model("im_users").Safe().Ctx(ctx).Where("id", in.UserId).Count()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "检查IM用户失败,请稍后重试!")
|
||||
}
|
||||
if userCount == 0 {
|
||||
return gerror.New("IM用户不存在")
|
||||
}
|
||||
data := g.Map{
|
||||
"department_id": in.DepartmentId,
|
||||
"user_id": in.UserId,
|
||||
"display_name": in.DisplayName,
|
||||
"position": in.Position,
|
||||
"avatar_file_id": in.AvatarFileId,
|
||||
"mobile": in.Mobile,
|
||||
"email": in.Email,
|
||||
"employment_state": in.EmploymentState,
|
||||
"contactable": in.Contactable,
|
||||
"sort_order": in.SortOrder,
|
||||
"updated_at": gtime.Now(),
|
||||
}
|
||||
if in.Id > 0 {
|
||||
data["version"] = gdb.Raw("version+1")
|
||||
if _, err = db.Model("im_org_members").Safe().Ctx(ctx).Where("id", in.Id).Data(data).Update(); err != nil {
|
||||
return gerror.Wrap(err, "更新IM组织成员失败,请稍后重试!")
|
||||
}
|
||||
_ = writeImAdminAudit(ctx, tenant.Id, "im_org_member_update", "im_org_member", in.Id, "success", g.Map{"department_id": in.DepartmentId, "user_id": in.UserId})
|
||||
return nil
|
||||
}
|
||||
data["version"] = 1
|
||||
data["created_at"] = gtime.Now()
|
||||
if _, err = db.Model("im_org_members").Safe().Ctx(ctx).Data(data).Insert(); err != nil {
|
||||
return gerror.Wrap(err, "添加IM组织成员失败,请稍后重试!")
|
||||
}
|
||||
_ = writeImAdminAudit(ctx, tenant.Id, "im_org_member_create", "im_org_member", 0, "success", g.Map{"department_id": in.DepartmentId, "user_id": in.UserId})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) MemberDelete(ctx context.Context, in *sysin.ImOrgMemberDeleteInp) (err error) {
|
||||
if err = in.Filter(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
db, tenant, err := resolveImTenantDB(ctx, in.TenantId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
current, err := db.Model("im_org_members").Safe().Ctx(ctx).Where("id", in.Id).One()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "获取IM组织成员失败,请稍后重试!")
|
||||
}
|
||||
if current.IsEmpty() {
|
||||
return gerror.New("组织成员不存在")
|
||||
}
|
||||
if _, err = db.Model("im_org_members").Safe().Ctx(ctx).Where("id", in.Id).Delete(); err != nil {
|
||||
return gerror.Wrap(err, "删除IM组织成员失败,请稍后重试!")
|
||||
}
|
||||
_ = writeImAdminAudit(ctx, tenant.Id, "im_org_member_delete", "im_org_member", in.Id, "success", g.Map{"department_id": current["department_id"].String(), "user_id": current["user_id"].Int64()})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) Search(ctx context.Context, in *sysin.ImOrgSearchInp) (res *sysin.ImOrgSearchModel, err error) {
|
||||
if err = in.Filter(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
departments, _, err := s.DepartmentList(ctx, &sysin.ImOrgDepartmentListInp{
|
||||
PageReq: form.PageReq{Page: 1, PerPage: 20, Pagination: true},
|
||||
TenantId: in.TenantId,
|
||||
Name: in.Query,
|
||||
State: consts.ImOrgDepartmentStateActive,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
members, _, err := s.MemberList(ctx, &sysin.ImOrgMemberListInp{
|
||||
PageReq: form.PageReq{Page: 1, PerPage: 20, Pagination: true},
|
||||
TenantId: in.TenantId,
|
||||
Query: in.Query,
|
||||
EmploymentState: consts.ImOrgEmploymentStateActive,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = &sysin.ImOrgSearchModel{Departments: departments, Members: members}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) departmentModel(ctx context.Context, db gdb.DB) *gdb.Model {
|
||||
return db.Model("im_org_departments d").Safe().Ctx(ctx).Fields(
|
||||
"d.id",
|
||||
"d.department_id",
|
||||
"d.name",
|
||||
"d.parent_id",
|
||||
"d.sort_order",
|
||||
"d.version",
|
||||
"d.state",
|
||||
"d.created_at",
|
||||
"d.updated_at",
|
||||
"(SELECT COUNT(*) FROM im_org_departments child WHERE child.parent_id=d.department_id AND child.state='active') child_count",
|
||||
"(SELECT COUNT(*) FROM im_org_members m WHERE m.department_id=d.department_id) member_count",
|
||||
)
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) memberModel(ctx context.Context, db gdb.DB) *gdb.Model {
|
||||
return db.Model("im_org_members m").Safe().Ctx(ctx).
|
||||
LeftJoin("im_org_departments d", "d.department_id=m.department_id").
|
||||
Fields(
|
||||
"m.id",
|
||||
"m.department_id",
|
||||
"COALESCE(d.name,'') department_name",
|
||||
"m.user_id",
|
||||
"m.display_name",
|
||||
"m.position",
|
||||
"m.avatar_file_id",
|
||||
"m.mobile",
|
||||
"m.email",
|
||||
"m.employment_state",
|
||||
"m.contactable",
|
||||
"m.sort_order",
|
||||
"m.version",
|
||||
"m.created_at",
|
||||
"m.updated_at",
|
||||
)
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) departmentExists(ctx context.Context, db gdb.DB, departmentId string) (bool, error) {
|
||||
count, err := db.Model("im_org_departments").Safe().Ctx(ctx).Where("department_id", strings.TrimSpace(departmentId)).Count()
|
||||
if err != nil {
|
||||
return false, gerror.Wrap(err, "检查IM组织部门失败,请稍后重试!")
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (s *sSysImOrg) ensureNoDepartmentCycle(ctx context.Context, db gdb.DB, departmentId, parentId string) error {
|
||||
next := strings.TrimSpace(parentId)
|
||||
for next != "" && next != "root" {
|
||||
if next == departmentId {
|
||||
return gerror.New("上级部门不能选择自身或下级部门")
|
||||
}
|
||||
row, err := db.Model("im_org_departments").Safe().Ctx(ctx).Fields("parent_id").Where("department_id", next).One()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "检查部门层级失败,请稍后重试!")
|
||||
}
|
||||
if row.IsEmpty() {
|
||||
return gerror.New("上级部门不存在")
|
||||
}
|
||||
next = row["parent_id"].String()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user