sync: 同步 v1.0.4 并脱敏配置与镜像
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
package simcardquery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
// DeptOptions 所属公司下拉项(树形)。
|
||||
//
|
||||
// 两点关键口径:
|
||||
// 1. 可见范围交给 handler.FilterAuth:顶级看全部,其他角色按自身数据范围。
|
||||
// 2. CardCount 是「含下级」的累计量,不是本部门直接挂的卡。
|
||||
// 原因:顶级公司(如示例企业)自身往往不挂卡,卡都在下级代理名下,
|
||||
// 只统计本部门会显示 0,看起来像没数据。
|
||||
func (s *Service) DeptOptions(ctx context.Context) ([]*model.SimCardQueryDeptOption, error) {
|
||||
deptColumns := dao.SysDept.Columns()
|
||||
depts := make([]*struct {
|
||||
DeptId int64 `orm:"dept_id"`
|
||||
DeptName string `orm:"dept_name"`
|
||||
ParentId int64 `orm:"parent_id"`
|
||||
}, 0, 256)
|
||||
|
||||
err := handler.Model(dao.SysDept.Ctx(ctx), &handler.Option{
|
||||
FilterTenant: true,
|
||||
FilterAuth: true,
|
||||
}).
|
||||
Fields(deptColumns.DeptId, deptColumns.DeptName, deptColumns.ParentId).
|
||||
Where(deptColumns.Status, 0).
|
||||
WhereNull(deptColumns.DeletedAt).
|
||||
OrderAsc(deptColumns.OrderNum).
|
||||
OrderAsc(deptColumns.DeptId).
|
||||
Scan(&depts)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "获取可选公司失败,请稍后重试")
|
||||
}
|
||||
if len(depts) == 0 {
|
||||
return []*model.SimCardQueryDeptOption{}, nil
|
||||
}
|
||||
|
||||
direct, err := directCardCountByDept(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
subtree := accumulateSubtreeCount(depts, direct)
|
||||
|
||||
options := make([]*model.SimCardQueryDeptOption, 0, len(depts))
|
||||
for _, dept := range depts {
|
||||
options = append(options, &model.SimCardQueryDeptOption{
|
||||
DeptId: dept.DeptId,
|
||||
DeptName: dept.DeptName,
|
||||
CardCount: subtree[dept.DeptId],
|
||||
ParentId: dept.ParentId,
|
||||
})
|
||||
}
|
||||
return options, nil
|
||||
}
|
||||
|
||||
// directCardCountByDept 按部门统计直接挂载的卡数量。
|
||||
// 卡表同样过数据权限,防止公司列表被收窄、但计数把无权卡的量带出来。
|
||||
func directCardCountByDept(ctx context.Context) (map[int64]int64, error) {
|
||||
cardColumns := dao.TSimCardInfo.Columns()
|
||||
rows := make([]*struct {
|
||||
DeptId int64 `orm:"dept_id"`
|
||||
Total int64 `orm:"total"`
|
||||
}, 0, 256)
|
||||
err := handler.Model(dao.TSimCardInfo.Ctx(ctx), &handler.Option{
|
||||
FilterTenant: true,
|
||||
FilterAuth: true,
|
||||
}).
|
||||
Fields(fmt.Sprintf("%s AS dept_id, COUNT(1) AS total", cardColumns.DeptId)).
|
||||
Group(cardColumns.DeptId).
|
||||
Scan(&rows)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "统计公司卡数量失败")
|
||||
}
|
||||
result := make(map[int64]int64, len(rows))
|
||||
for _, row := range rows {
|
||||
result[row.DeptId] = row.Total
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// accumulateSubtreeCount 把「本部门直接卡数」沿部门树向上累加,得到含下级的卡数。
|
||||
//
|
||||
// 只累加本次查询可见的部门:无权部门根本不在 depts 里,其卡数也不会被计入,
|
||||
// 因此不会通过父级汇总把无权数据带出来。
|
||||
func accumulateSubtreeCount(
|
||||
depts []*struct {
|
||||
DeptId int64 `orm:"dept_id"`
|
||||
DeptName string `orm:"dept_name"`
|
||||
ParentId int64 `orm:"parent_id"`
|
||||
},
|
||||
direct map[int64]int64,
|
||||
) map[int64]int64 {
|
||||
visible := make(map[int64]struct{}, len(depts))
|
||||
children := make(map[int64][]int64, len(depts))
|
||||
roots := make([]int64, 0, len(depts))
|
||||
for _, dept := range depts {
|
||||
visible[dept.DeptId] = struct{}{}
|
||||
}
|
||||
for _, dept := range depts {
|
||||
if _, ok := visible[dept.ParentId]; ok && dept.ParentId != dept.DeptId {
|
||||
children[dept.ParentId] = append(children[dept.ParentId], dept.DeptId)
|
||||
continue
|
||||
}
|
||||
roots = append(roots, dept.DeptId)
|
||||
}
|
||||
|
||||
subtree := make(map[int64]int64, len(depts))
|
||||
// 部门树很浅,递归深度可控;用显式栈避免深层树爆栈。
|
||||
type frame struct {
|
||||
id int64
|
||||
child int
|
||||
amount int64
|
||||
}
|
||||
for _, rootID := range roots {
|
||||
stack := []*frame{{id: rootID, amount: direct[rootID]}}
|
||||
for len(stack) > 0 {
|
||||
top := stack[len(stack)-1]
|
||||
if kids := children[top.id]; top.child < len(kids) {
|
||||
childID := kids[top.child]
|
||||
top.child++
|
||||
stack = append(stack, &frame{id: childID, amount: direct[childID]})
|
||||
continue
|
||||
}
|
||||
subtree[top.id] = top.amount
|
||||
stack = stack[:len(stack)-1]
|
||||
if len(stack) > 0 {
|
||||
stack[len(stack)-1].amount += top.amount
|
||||
}
|
||||
}
|
||||
}
|
||||
return subtree
|
||||
}
|
||||
|
||||
// deptSubtreeIDs 返回某部门及其全部下级的 dept_id 子查询。
|
||||
// 与 DeptOptions 的统计口径保持一致:选中公司即包含下级公司。
|
||||
func deptSubtreeIDs(ctx context.Context, deptId int64) *gdb.Model {
|
||||
deptColumns := dao.SysDept.Columns()
|
||||
return handler.Model(dao.SysDept.Ctx(ctx), &handler.Option{
|
||||
FilterTenant: true,
|
||||
}).Fields(deptColumns.DeptId).
|
||||
Where(fmt.Sprintf("%s = ? OR %s LIKE ?", deptColumns.DeptId, deptColumns.Ancestors),
|
||||
deptId, fmt.Sprintf("%%,%d,%%", deptId))
|
||||
}
|
||||
Reference in New Issue
Block a user