400 lines
13 KiB
Go
400 lines
13 KiB
Go
package sys
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"hotgo/internal/consts"
|
|
"hotgo/internal/model/input/form"
|
|
"hotgo/internal/model/input/sysin"
|
|
"hotgo/internal/service"
|
|
"hotgo/utility/convert"
|
|
"hotgo/utility/excel"
|
|
"net/url"
|
|
"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/gctx"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
"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
|
|
}
|
|
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
|
|
if err != nil {
|
|
return
|
|
}
|
|
values := addPageQuery(url.Values{}, in.Page, in.PerPage)
|
|
if in.DepartmentId != "" {
|
|
values.Set("department_id", strings.TrimSpace(in.DepartmentId))
|
|
}
|
|
if in.ParentId != "" {
|
|
values.Set("parent_id", strings.TrimSpace(in.ParentId))
|
|
}
|
|
if in.Name != "" {
|
|
values.Set("name", strings.TrimSpace(in.Name))
|
|
}
|
|
if in.State != "" {
|
|
values.Set("state", strings.TrimSpace(in.State))
|
|
}
|
|
return imAdminQueryList[sysin.ImOrgDepartmentModel](ctx, tenant,
|
|
"/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/org/departments",
|
|
values,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (s *sSysImOrg) DepartmentExport(ctx context.Context, in *sysin.ImOrgDepartmentListInp) (err error) {
|
|
list, totalCount, err := s.DepartmentList(ctx, in)
|
|
if err != nil {
|
|
return
|
|
}
|
|
tags, err := convert.GetEntityDescTags(sysin.ImOrgDepartmentExportModel{})
|
|
if err != nil {
|
|
return
|
|
}
|
|
var exports []sysin.ImOrgDepartmentExportModel
|
|
if err = gconv.Scan(list, &exports); err != nil {
|
|
return
|
|
}
|
|
fileName := "导出IM组织部门-" + gctx.CtxId(ctx)
|
|
sheetName := fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, form.CalPageCount(totalCount, in.PerPage), in.Page, len(list))
|
|
if len(list) > 0 {
|
|
_ = writeImAdminAudit(ctx, list[0].TenantId, "im_org_department_export", "im_org_department", 0, "success", g.Map{"count": len(list)})
|
|
}
|
|
return excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
|
|
}
|
|
|
|
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
|
|
}
|
|
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
|
|
if err != nil {
|
|
return
|
|
}
|
|
values := addPageQuery(url.Values{}, in.Page, in.PerPage)
|
|
if in.DepartmentId != "" {
|
|
values.Set("department_id", strings.TrimSpace(in.DepartmentId))
|
|
}
|
|
if in.UserId > 0 {
|
|
values.Set("user_id", int64ToString(in.UserId))
|
|
}
|
|
if in.EmploymentState != "" {
|
|
values.Set("employment_state", strings.TrimSpace(in.EmploymentState))
|
|
}
|
|
if in.Query != "" {
|
|
values.Set("q", strings.TrimSpace(in.Query))
|
|
}
|
|
return imAdminQueryList[sysin.ImOrgMemberModel](ctx, tenant,
|
|
"/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/org/members",
|
|
values,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
func (s *sSysImOrg) MemberExport(ctx context.Context, in *sysin.ImOrgMemberListInp) (err error) {
|
|
list, totalCount, err := s.MemberList(ctx, in)
|
|
if err != nil {
|
|
return
|
|
}
|
|
tags, err := convert.GetEntityDescTags(sysin.ImOrgMemberExportModel{})
|
|
if err != nil {
|
|
return
|
|
}
|
|
var exports []sysin.ImOrgMemberExportModel
|
|
if err = gconv.Scan(list, &exports); err != nil {
|
|
return
|
|
}
|
|
fileName := "导出IM组织成员-" + gctx.CtxId(ctx)
|
|
sheetName := fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, form.CalPageCount(totalCount, in.PerPage), in.Page, len(list))
|
|
if len(list) > 0 {
|
|
_ = writeImAdminAudit(ctx, list[0].TenantId, "im_org_member_export", "im_org_member", 0, "success", g.Map{"count": len(list), "department_id": in.DepartmentId})
|
|
}
|
|
return excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
|
|
}
|
|
|
|
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
|
|
}
|