go: Recursion Algorithm

Go 复制代码
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/7/16 22:41
# User      :  geovindu
# Product   : GoLand
# Project   : goalgorithms
# File      : recursion.go
*/
package recursion
 
import (
    "fmt"
    "sort"
)
 
// ===================== 1. 权限常量定义 =====================
var PERMISSION = map[string]string{
    // 门店基础
    "sale_view":     "销售单据查看",
    "sale_create":   "开单销售",
    "stock_view":    "库存查询",
    "stock_inout":   "金饰玉石出入库",
    "member_manage": "会员管理",
    // 国内分公司财务
    "finance_stat":    "财务报表",
    "cost_allocate":   "区域成本分摊",
    "gold_price_edit": "金价调整",
    // 海外专属权限
    "custom_declare":   "海外报关",
    "foreign_exchange": "外币对账",
    "oversea_tax":      "境外税务核算",
    // 集团顶层
    "org_mgr":         "组织架构编辑",
    "role_global":     "全局角色配置",
    "data_export_all": "全集团数据导出",
}
 
// 海外权限集合
var OVERSEA_PERM_SET = map[string]bool{
    "custom_declare":   true,
    "foreign_exchange": true,
    "oversea_tax":      true,
}
 
// ===================== 2. 角色结构体 =====================
type Role struct {
    RoleID   string
    RoleName string
    Perms    map[string]bool
}
 
func NewRole(rid, rname string, perms []string) *Role {
    p := make(map[string]bool)
    for _, k := range perms {
        p[k] = true
    }
    return &Role{
        RoleID:   rid,
        RoleName: rname,
        Perms:    p,
    }
}
 
// ===================== 3. 组织节点 OrgNode 树形结构 =====================
type OrgNode struct {
    OrgID     string
    OrgName   string
    OrgType   string
    ParentID  string
    IsJoin    bool            // 是否加盟门店,隔离递归
    Children  []*OrgNode      // 子组织
    Perms     map[string]bool // 本组织自有权限
    BindRoles []*Role         // 绑定角色
}
 
func NewOrgNode(oid, oname, otype, pid string, isJoin bool) *OrgNode {
    return &OrgNode{
        OrgID:    oid,
        OrgName:  oname,
        OrgType:  otype,
        ParentID: pid,
        IsJoin:   isJoin,
        Perms:    make(map[string]bool),
    }
}
 
// 添加子节点
func (o *OrgNode) AddChild(child *OrgNode) {
    o.Children = append(o.Children, child)
}
 
// 添加自有权限
func (o *OrgNode) AddPerm(key string) {
    if _, ok := PERMISSION[key]; ok {
        o.Perms[key] = true
    }
}
 
// 绑定角色
func (o *OrgNode) BindRole(r *Role) {
    o.BindRoles = append(o.BindRoles, r)
}
 
// ===================== 4. 员工用户 =====================
type Staff struct {
    UID       string
    Name      string
    BindOrgID string
    RolePerms map[string]bool // 用户直接分配权限
}
 
func NewStaff(uid, name, bindOid string) *Staff {
    return &Staff{
        UID:       uid,
        Name:      name,
        BindOrgID: bindOid,
        RolePerms: make(map[string]bool),
    }
}
 
func (s *Staff) AssignPerm(key string) {
    if _, ok := PERMISSION[key]; ok {
        s.RolePerms[key] = true
    }
}
 
// ===================== 5. 销售订单(行级过滤) =====================
type SaleOrder struct {
    OrderID   string
    ShopOrgID string
    Amount    float64
}
 
// ===================== 6. 递归工具工具类 =====================
type OrgUtil struct{}
 
// 6.1 递归查找节点
func (u *OrgUtil) FindNode(root *OrgNode, targetID string) *OrgNode {
    if root.OrgID == targetID {
        return root
    }
    for _, child := range root.Children {
        res := u.FindNode(child, targetID)
        if res != nil {
            return res
        }
    }
    return nil
}
 
// 6.2 向下递归获取所有下级(加盟门店终止递归)
func (u *OrgUtil) GetAllSubOrgs(root *OrgNode, targetID string) []*OrgNode {
    target := u.FindNode(root, targetID)
    if target == nil {
        return nil
    }
    var list []*OrgNode
    var dfs func(node *OrgNode)
    dfs = func(node *OrgNode) {
        list = append(list, node)
        if node.IsJoin {
            return
        }
        for _, c := range node.Children {
            dfs(c)
        }
    }
    dfs(target)
    return list
}
 
// 6.3 向上递归获取整条父级链路
func (u *OrgUtil) GetParentChain(root *OrgNode, targetID string, nodeMap map[string]*OrgNode) []*OrgNode {
    target := u.FindNode(root, targetID)
    if target == nil || target.ParentID == "" {
        return nil
    }
    var parents []*OrgNode
    var upRecur func(n *OrgNode)
    upRecur = func(n *OrgNode) {
        pid := n.ParentID
        if pid == "" {
            return
        }
        pNode, ok := nodeMap[pid]
        if ok {
            parents = append(parents, pNode)
            upRecur(pNode)
        }
    }
    upRecur(target)
    return parents
}
 
// 6.4 扩展1:角色递归下发全集团
func (u *OrgUtil) RoleSyncRecursive(node *OrgNode, r *Role) {
    node.BindRole(r)
    for _, child := range node.Children {
        u.RoleSyncRecursive(child, r)
    }
}
 
// 6.5 扩展2:销售订单行级递归过滤
func (u *OrgUtil) FilterSaleOrders(root *OrgNode, user *Staff, all []*SaleOrder) []*SaleOrder {
    subList := u.GetAllSubOrgs(root, user.BindOrgID)
    allowShop := make(map[string]bool)
    for _, o := range subList {
        allowShop[o.OrgID] = true
    }
    var res []*SaleOrder
    for _, ord := range all {
        if allowShop[ord.ShopOrgID] {
            res = append(res, ord)
        }
    }
    return res
}
 
// 6.6 核心:汇总用户完整权限(父级+自身+下级 + 海外权限隔离)
func (u *OrgUtil) GetUserTotalPerms(root *OrgNode, user *Staff, nodeMap map[string]*OrgNode) map[string]bool {
    total := make(map[string]bool)
    // 1. 用户自身角色权限
    for k := range user.RolePerms {
        total[k] = true
    }
    targetNode := u.FindNode(root, user.BindOrgID)
    if targetNode == nil {
        return total
    }
    // 2. 所有父组织 + 所有下级组织
    parentList := u.GetParentChain(root, user.BindOrgID, nodeMap)
    subList := u.GetAllSubOrgs(root, user.BindOrgID)
    allOrgs := append(parentList, subList...)
 
    for _, org := range allOrgs {
        // 复制组织权限
        tmpPerm := make(map[string]bool)
        for k := range org.Perms {
            tmpPerm[k] = true
        }
        // 国内组织剔除海外权限
        if org.OrgType != "海外子公司" && !containsOversea(org.OrgType) {
            for k := range OVERSEA_PERM_SET {
                delete(tmpPerm, k)
            }
        }
        // 合并到总权限
        for k := range tmpPerm {
            total[k] = true
        }
    }
    return total
}
 
func containsOversea(s string) bool {
    return len(s) >= 2 && s[:2] == "海外"
}
 
// 6.7 递归打印组织树
func (u *OrgUtil) PrintTree(node *OrgNode, level int) {
    indent := ""
    for i := 0; i < level; i++ {
        indent += "    "
    }
    tag := ""
    if node.IsJoin {
        tag = "[加盟]"
    }
    fmt.Printf("%s[%s]%s %s (ID:%s)\n", indent, node.OrgType, tag, node.OrgName, node.OrgID)
    for _, child := range node.Children {
        u.PrintTree(child, level+1)
    }
}
 
// 6.8 递归回收权限
func (u *OrgUtil) RevokePermRecursive(node *OrgNode, permKey string) {
    delete(node.Perms, permKey)
    for _, child := range node.Children {
        u.RevokePermRecursive(child, permKey)
    }
}
 
// 6.9 扩展5:递归导出审计报表
type AuditRow struct {
    Level        int
    OrgID        string
    OrgType      string
    OrgName      string
    IsJoin       bool
    OwnPermNames []string
    RoleNames    []string
}
 
func (u *OrgUtil) ExportReport(node *OrgNode, report *[]AuditRow, level int) {
    // 权限名称
    var ownPerms []string
    for k := range node.Perms {
        ownPerms = append(ownPerms, PERMISSION[k])
    }
    sort.Strings(ownPerms)
    // 角色名称
    var roles []string
    for _, r := range node.BindRoles {
        roles = append(roles, r.RoleName)
    }
    row := AuditRow{
        Level:        level,
        OrgID:        node.OrgID,
        OrgType:      node.OrgType,
        OrgName:      node.OrgName,
        IsJoin:       node.IsJoin,
        OwnPermNames: ownPerms,
        RoleNames:    roles,
    }
    *report = append(*report, row)
    if node.IsJoin {
        return
    }
    for _, child := range node.Children {
        u.ExportReport(child, report, level+1)
    }
}
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/7/16 22:42
# User      :  geovindu
# Product   : GoLand
# Project   : goalgorithms
# File      : recursionbll.go
*/
package bll
 
import (
    "fmt"
    "goalgorithms/recursion"
    "sort"
)
 
// ===================== 构建珠宝集团完整组织树 =====================
func buildGroup() (*recursion.OrgNode, map[string]*recursion.OrgNode) {
    root := recursion.NewOrgNode("G001", "璀璨珠宝集团总部", "集团总部", "", false)
    root.AddPerm("org_mgr")
    root.AddPerm("role_global")
    root.AddPerm("data_export_all")
    root.AddPerm("gold_price_edit")
 
    // 国内事业部
    domestic := recursion.NewOrgNode("D001", "国内运营事业部", "事业部", "G001", false)
    domestic.AddPerm("finance_stat")
    domestic.AddPerm("cost_allocate")
    root.AddChild(domestic)
 
    // 华南分公司
    huanan := recursion.NewOrgNode("D001-1", "华南分公司", "国内分公司", "D001", false)
    huanan.AddPerm("stock_inout")
    domestic.AddChild(huanan)
 
    szShop := recursion.NewOrgNode("SH-SZ01", "深圳旗舰店", "线下门店", "D001-1", false)
    szShop.AddPerm("sale_view")
    szShop.AddPerm("sale_create")
    huanan.AddChild(szShop)
 
    joinShop := recursion.NewOrgNode("SH-J001", "东莞加盟门店", "加盟门店", "D001-1", true)
    joinShop.AddPerm("sale_view")
    huanan.AddChild(joinShop)
 
    // 华东分公司
    huadong := recursion.NewOrgNode("D001-2", "华东分公司", "国内分公司", "D001", false)
    shShop := recursion.NewOrgNode("SH-SH01", "上海总店", "线下门店", "D001-2", false)
    shShop.AddPerm("sale_create")
    huadong.AddChild(shShop)
    domestic.AddChild(huadong)
 
    // 海外事业部
    oversea := recursion.NewOrgNode("O001", "海外国际事业部", "事业部", "G001", false)
    oversea.AddPerm("foreign_exchange")
    root.AddChild(oversea)
 
    sgCompany := recursion.NewOrgNode("O001-1", "新加坡子公司", "海外子公司", "O001", false)
    sgCompany.AddPerm("custom_declare")
    sgShop := recursion.NewOrgNode("SH-SG01", "新加坡乌节路门店", "海外门店", "O001-1", false)
    sgShop.AddPerm("sale_view")
    sgCompany.AddChild(sgShop)
    oversea.AddChild(sgCompany)
 
    usCompany := recursion.NewOrgNode("O001-2", "洛杉矶子公司", "海外子公司", "O001", false)
    usCompany.AddPerm("oversea_tax")
    usShop := recursion.NewOrgNode("SH-US01", "洛杉矶门店", "海外门店", "O001-2", false)
    usShop.AddPerm("sale_view")
    usCompany.AddChild(usShop)
    oversea.AddChild(usCompany)
 
    // 构建ID映射表
    nodeMap := make(map[string]*recursion.OrgNode)
    var collect func(n *recursion.OrgNode)
    collect = func(n *recursion.OrgNode) {
        nodeMap[n.OrgID] = n
        for _, c := range n.Children {
            collect(c)
        }
    }
    collect(root)
    return root, nodeMap
}
 
func RecursionMain() {
    root, nodeMap := buildGroup()
    util := &recursion.OrgUtil{}
 
    fmt.Println("========== 1. 完整组织树(含加盟门店标记) ==========")
    util.PrintTree(root, 0)
 
    // 扩展1:角色递归下发全集团
    globalSaleRole := recursion.NewRole("R001", "集团通用销售角色", []string{"sale_view", "stock_view"})
    util.RoleSyncRecursive(root, globalSaleRole)
    fmt.Println("\n========== 【扩展1】角色递归下发完成:全集团绑定销售角色 ==========")
 
    // 模拟订单
    allOrders := []*recursion.SaleOrder{
        {"OD001", "SH-SZ01", 12800},
        {"OD002", "SH-J001", 6500},
        {"OD003", "SH-SH01", 23000},
        {"OD004", "SH-SG01", 9600},
    }
 
    // 华南管理员
    southAdmin := recursion.NewStaff("U2001", "华南运营总监", "D001-1")
 
    // 扩展2:行级过滤订单
    fmt.Println("\n========== 【扩展2】华南管理员行级过滤后的销售订单 ==========")
    filterOrd := util.FilterSaleOrders(root, southAdmin, allOrders)
    for _, o := range filterOrd {
        fmt.Printf("订单%s 门店ID:%s 金额:%.0f\n", o.OrderID, o.ShopOrgID, o.Amount)
    }
 
    // 扩展3/4:权限汇总(国内屏蔽海外权限)
    fmt.Println("\n========== 【扩展3/4】华南管理员权限(无海外报关/外币权限) ==========")
    southPerm := util.GetUserTotalPerms(root, southAdmin, nodeMap)
    var southList []string
    for k := range southPerm {
        southList = append(southList, recursion.PERMISSION[k])
    }
    sort.Strings(southList)
    for _, name := range southList {
        fmt.Printf("- %s\n", name)
    }
 
    // 新加坡海外管理员
    sgAdmin := recursion.NewStaff("U3001", "新加坡负责人", "O001-1")
    fmt.Println("\n========== 海外子公司管理员权限(包含海外专属权限) ==========")
    sgPerm := util.GetUserTotalPerms(root, sgAdmin, nodeMap)
    var sgList []string
    for k := range sgPerm {
        sgList = append(sgList, recursion.PERMISSION[k])
    }
    sort.Strings(sgList)
    for _, name := range sgList {
        fmt.Printf("- %s\n", name)
    }
 
    // 扩展5:递归导出审计报表
    fmt.Println("\n========== 【扩展5】递归导出集团审计权限报表 ==========")
    var report []recursion.AuditRow
    util.ExportReport(root, &report, 0)
    for _, row := range report {
        indent := ""
        for i := 0; i < row.Level; i++ {
            indent += "    "
        }
        joinTag := ""
        if row.IsJoin {
            joinTag = "【加盟】"
        }
        fmt.Printf("%s%s%s | 自有权限:%v | 绑定角色:%v\n", indent, joinTag, row.OrgName, row.OwnPermNames, row.RoleNames)
    }
}

输出:

相关推荐
用户2930750976691 小时前
深入理解 RAG 文档切割:从知识库到向量数据库的关键一步
后端
geovindu1 小时前
CSharp: Composite Pattern
开发语言·后端·c#·组合模式·结构型模式
消失的旧时光-19431 小时前
KMP Web 开发实战(二):js、wasmJs、browser、executable 到底是什么意思?
开发语言·前端·javascript·跨平台·kmp
宇图SHARE1 小时前
别再用 Python 写 Agent 前端了!Vue3 + NestJS + TypeScript 全栈方案,开发效率翻倍
前端·后端
吃饱了得干活1 小时前
Spring Cloud Gateway限流:从Redis到Sentinel的三种方案
后端·spring cloud
sycmancia1 小时前
Qt——线程的生命期问题
开发语言·qt
IT_陈寒1 小时前
Python的GIL让我以为CPU跑满了,结果...
前端·人工智能·后端
影寂ldy1 小时前
C# 多线程进阶知识点(线程优先级、多委托传参、线程锁、死锁)
开发语言·数据库·c#
国服第二切图仔1 小时前
09-搜索工具Grep与Glob
开发语言·javascript·ecmascript