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)
}
}
输出:
