cs
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : PermConstant.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharpAlgorithms.Recursion
{
/// <summary>
/// 权限常量配置
/// </summary>
public static class PermConstant
{
/// <summary>
/// 权限Key-中文名称映射
/// </summary>
public static readonly Dictionary<string, string> PermissionMap = new Dictionary<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", "全集团数据导出"}
};
/// <summary>
/// 海外专属权限集合
/// </summary>
public static readonly HashSet<string> OverseaPermSet = new HashSet<string>()
{
"custom_declare", "foreign_exchange", "oversea_tax"
};
}
}
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : Role.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharpAlgorithms.Recursion
{
/// <summary>
/// 角色实体
/// </summary>
public class Role
{
public string RoleId { get; set; }
public string RoleName { get; set; }
public HashSet<string> Perms { get; set; }
public Role(string rid, string rname, List<string> permKeys)
{
RoleId = rid;
RoleName = rname;
Perms = new HashSet<string>(permKeys);
}
}
}
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : OrgNode.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharpAlgorithms.Recursion
{
/// <summary>
/// 组织树节点
/// </summary>
public class OrgNode
{
public string OrgId { get; set; }
public string OrgName { get; set; }
public string OrgType { get; set; }
public string ParentId { get; set; }
public bool IsJoin { get; set; } // 加盟门店隔离标记
public List<OrgNode> Children { get; set; }
public HashSet<string> Perms { get; set; } // 本组织自有权限
public List<Role> BindRoles { get; set; } // 绑定角色
public OrgNode(string oid, string oname, string otype, string pid, bool isJoin)
{
OrgId = oid;
OrgName = oname;
OrgType = otype;
ParentId = pid;
IsJoin = isJoin;
Children = new List<OrgNode>();
Perms = new HashSet<string>();
BindRoles = new List<Role>();
}
public void AddChild(OrgNode child) => Children.Add(child);
public void AddPerm(string permKey)
{
if (PermConstant.PermissionMap.ContainsKey(permKey))
Perms.Add(permKey);
}
public void BindRole(Role role) => BindRoles.Add(role);
}
}
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : Staff.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharpAlgorithms.Recursion
{
/// <summary>
/// 员工用户
/// </summary>
public class Staff
{
public string Uid { get; set; }
public string Name { get; set; }
public string BindOrgId { get; set; }
public HashSet<string> RolePerms { get; set; }
public Staff(string uid, string name, string bindOid)
{
Uid = uid;
Name = name;
BindOrgId = bindOid;
RolePerms = new HashSet<string>();
}
public void AssignPerm(string permKey)
{
if (PermConstant.PermissionMap.ContainsKey(permKey))
RolePerms.Add(permKey);
}
}
}
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : SaleOrder.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharpAlgorithms.Recursion
{
/// <summary>
/// 销售订单(行级过滤)
/// </summary>
public class SaleOrder
{
public string OrderId { get; set; }
public string ShopOrgId { get; set; }
public double Amount { get; set; }
public SaleOrder(string oid, string shopId, double amt)
{
OrderId = oid;
ShopOrgId = shopId;
Amount = amt;
}
}
}
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : AuditRow.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharpAlgorithms.Recursion
{
/// <summary>
/// 审计报表行
/// </summary>
public class AuditRow
{
public int Level { get; set; }
public string OrgName { get; set; }
public bool IsJoin { get; set; }
public List<string> OwnPermNames { get; set; }
public List<string> BindRoleNames { get; set; }
}
}
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : OrgRecursionUtil.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharpAlgorithms.Recursion
{
/// <summary>
/// 递归工具类
/// </summary>
public class OrgRecursionUtil
{
#region 基础递归查找
/// <summary>
/// 递归查找指定组织节点
/// </summary>
/// <param name="root"></param>
/// <param name="targetId"></param>
/// <returns></returns>
public OrgNode FindNode(OrgNode root, string targetId)
{
if (root.OrgId == targetId)
return root;
foreach (var child in root.Children)
{
var res = FindNode(child, targetId);
if (res != null) return res;
}
return null;
}
/// <summary>
/// 向下递归获取所有下级(加盟门店终止递归)
/// </summary>
/// <param name="root"></param>
/// <param name="targetId"></param>
/// <returns></returns>
public List<OrgNode> GetAllSubOrgs(OrgNode root, string targetId)
{
var target = FindNode(root, targetId);
var list = new List<OrgNode>();
if (target == null) return list;
DfsSub(target, list);
return list;
}
/// <summary>
///
/// </summary>
/// <param name="node"></param>
/// <param name="list"></param>
private void DfsSub(OrgNode node, List<OrgNode> list)
{
list.Add(node);
if (node.IsJoin) return;
foreach (var c in node.Children)
DfsSub(c, list);
}
/// <summary>
/// 向上递归获取整条父级链路
/// </summary>
/// <param name="root"></param>
/// <param name="targetId"></param>
/// <param name="nodeMap"></param>
/// <returns></returns>
public List<OrgNode> GetParentChain(OrgNode root, string targetId, Dictionary<string, OrgNode> nodeMap)
{
var target = FindNode(root, targetId);
var parents = new List<OrgNode>();
if (target == null || string.IsNullOrEmpty(target.ParentId))
return parents;
UpRecur(target, nodeMap, parents);
return parents;
}
/// <summary>
///
/// </summary>
/// <param name="node"></param>
/// <param name="nodeMap"></param>
/// <param name="parents"></param>
private void UpRecur(OrgNode node, Dictionary<string, OrgNode> nodeMap, List<OrgNode> parents)
{
var pid = node.ParentId;
if (string.IsNullOrEmpty(pid)) return;
if (nodeMap.TryGetValue(pid, out var pNode))
{
parents.Add(pNode);
UpRecur(pNode, nodeMap, parents);
}
}
#endregion
#region 五大扩展功能
/// <summary>
/// 扩展1:角色递归下发全集团
/// </summary>
/// <param name="node"></param>
/// <param name="role"></param>
public void RoleSyncRecursive(OrgNode node, Role role)
{
node.BindRole(role);
foreach (var child in node.Children)
RoleSyncRecursive(child, role);
}
/// <summary>
/// 扩展2:销售订单行级递归过滤
/// </summary>
/// <param name="root"></param>
/// <param name="user"></param>
/// <param name="allOrders"></param>
/// <returns></returns>
public List<SaleOrder> FilterSaleOrders(OrgNode root, Staff user, List<SaleOrder> allOrders)
{
var subs = GetAllSubOrgs(root, user.BindOrgId);
var allowIds = subs.Select(o => o.OrgId).ToHashSet();
return allOrders.Where(o => allowIds.Contains(o.ShopOrgId)).ToList();
}
/// <summary>
/// 核心:汇总用户完整权限(父级+自身+下级 + 海外权限隔离)
/// </summary>
/// <param name="root"></param>
/// <param name="user"></param>
/// <param name="nodeMap"></param>
/// <returns></returns>
public HashSet<string> GetUserTotalPerms(OrgNode root, Staff user, Dictionary<string, OrgNode> nodeMap)
{
var total = new HashSet<string>(user.RolePerms);
var targetNode = FindNode(root, user.BindOrgId);
if (targetNode == null) return total;
var parents = GetParentChain(root, user.BindOrgId, nodeMap);
var subs = GetAllSubOrgs(root, user.BindOrgId);
var allOrgs = parents.Concat(subs).ToList();
foreach (var org in allOrgs)
{
var tempPerm = new HashSet<string>(org.Perms);
// 国内组织剔除海外权限
if (org.OrgType != "海外子公司" && !org.OrgType.StartsWith("海外"))
{
foreach (var op in PermConstant.OverseaPermSet)
tempPerm.Remove(op);
}
foreach (var p in tempPerm)
total.Add(p);
}
return total;
}
/// <summary>
/// 递归打印组织树
/// </summary>
/// <param name="node"></param>
/// <param name="level"></param>
public void PrintTree(OrgNode node, int level = 0)
{
string indent = new string(' ', level * 4);
string tag = node.IsJoin ? "[加盟]" : "";
Console.WriteLine($"{indent}[{node.OrgType}]{tag} {node.OrgName} (ID:{node.OrgId})");
foreach (var child in node.Children)
PrintTree(child, level + 1);
}
/// <summary>
/// 递归批量回收权限
/// </summary>
/// <param name="node"></param>
/// <param name="permKey"></param>
public void RevokePermRecursive(OrgNode node, string permKey)
{
node.Perms.Remove(permKey);
foreach (var child in node.Children)
RevokePermRecursive(child, permKey);
}
/// <summary>
/// 扩展5:递归导出审计权限报表
/// </summary>
/// <param name="node"></param>
/// <param name="report"></param>
/// <param name="level"></param>
public void ExportReport(OrgNode node, List<AuditRow> report, int level = 0)
{
var ownPermNames = node.Perms
.Select(k => PermConstant.PermissionMap[k])
.OrderBy(x => x)
.ToList();
var roleNames = node.BindRoles.Select(r => r.RoleName).ToList();
report.Add(new AuditRow
{
Level = level,
OrgName = node.OrgName,
IsJoin = node.IsJoin,
OwnPermNames = ownPermNames,
BindRoleNames = roleNames
});
if (node.IsJoin) return;
foreach (var child in node.Children)
ExportReport(child, report, level + 1);
}
#endregion
}
}
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : JewelryGroupBuilder.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace CSharpAlgorithms.Recursion
{
/// <summary>
/// 构建珠宝集团完整组织树
/// </summary>
public static class JewelryGroupBuilder
{
/// <summary>
///
/// </summary>
/// <returns></returns>
public static (OrgNode Root, Dictionary<string, OrgNode> NodeMap) Build()
{
var nodeMap = new Dictionary<string, OrgNode>();
// 集团总部根节点
var root = new OrgNode("G001", "璀璨珠宝集团总部", "集团总部", "", false);
root.AddPerm("org_mgr");
root.AddPerm("role_global");
root.AddPerm("data_export_all");
root.AddPerm("gold_price_edit");
// 国内事业部
var domestic = new OrgNode("D001", "国内运营事业部", "事业部", "G001", false);
domestic.AddPerm("finance_stat");
domestic.AddPerm("cost_allocate");
root.AddChild(domestic);
// 华南分公司
var huanan = new OrgNode("D001-1", "华南分公司", "国内分公司", "D001", false);
huanan.AddPerm("stock_inout");
domestic.AddChild(huanan);
var szShop = new OrgNode("SH-SZ01", "深圳旗舰店", "线下门店", "D001-1", false);
szShop.AddPerm("sale_view");
szShop.AddPerm("sale_create");
huanan.AddChild(szShop);
var joinShop = new OrgNode("SH-J001", "东莞加盟门店", "加盟门店", "D001-1", true);
joinShop.AddPerm("sale_view");
huanan.AddChild(joinShop);
// 华东分公司
var huadong = new OrgNode("D001-2", "华东分公司", "国内分公司", "D001", false);
var shShop = new OrgNode("SH-SH01", "上海总店", "线下门店", "D001-2", false);
shShop.AddPerm("sale_create");
huadong.AddChild(shShop);
domestic.AddChild(huadong);
// 海外事业部
var oversea = new OrgNode("O001", "海外国际事业部", "事业部", "G001", false);
oversea.AddPerm("foreign_exchange");
root.AddChild(oversea);
// 新加坡子公司
var sgCompany = new OrgNode("O001-1", "新加坡子公司", "海外子公司", "O001", false);
sgCompany.AddPerm("custom_declare");
var sgShop = new OrgNode("SH-SG01", "新加坡乌节路门店", "海外门店", "O001-1", false);
sgShop.AddPerm("sale_view");
sgCompany.AddChild(sgShop);
oversea.AddChild(sgCompany);
// 洛杉矶子公司
var usCompany = new OrgNode("O001-2", "洛杉矶子公司", "海外子公司", "O001", false);
usCompany.AddPerm("oversea_tax");
var usShop = new OrgNode("SH-US01", "洛杉矶门店", "海外门店", "O001-2", false);
usShop.AddPerm("sale_view");
usCompany.AddChild(usShop);
oversea.AddChild(usCompany);
// 递归收集所有节点存入Map
void Collect(OrgNode n)
{
nodeMap[n.OrgId] = n;
foreach (var c in n.Children) Collect(c);
}
Collect(root);
return (root, nodeMap);
}
}
}
调用:
cs
/*
# encoding: utf-8
# 版权所有 2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Recursion Algorithm
# Author : geovindu,Geovin Du 涂聚文.
# IDE : vs2026 c# .net 10
# os : windows 10
# database : mysql 9.0 sql server 2019, postgreSQL 17.0 Oracle 21c Neo4j
# Datetime : 2026/07/04 22:16
# User : geovindu
# Product : Visual Studio 2026
# Project : CSharpDesignPattern
# File : RecursionBll.cs
*/
using System;
using System.Collections.Generic;
using System.Text;
using CSharpAlgorithms.Recursion;
namespace CSharpAlgorithms.Bll
{
/// <summary>
///
/// </summary>
public class RecursionBll
{
public void Demo()
{
var (root, nodeMap) = JewelryGroupBuilder.Build();
var util = new OrgRecursionUtil();
Console.WriteLine("========== 1. 完整组织树(含加盟门店标记) ==========");
util.PrintTree(root);
// 扩展1:角色递归下发全集团
var globalSaleRole = new Role("R001", "集团通用销售角色", new List<string> { "sale_view", "stock_view" });
util.RoleSyncRecursive(root, globalSaleRole);
Console.WriteLine("\n========== 【扩展1】角色递归下发完成:全集团绑定销售角色 ==========");
// 模拟销售订单
var allOrders = new List<SaleOrder>()
{
new SaleOrder("OD001", "SH-SZ01", 12800),
new SaleOrder("OD002", "SH-J001", 6500),
new SaleOrder("OD003", "SH-SH01", 23000),
new SaleOrder("OD004", "SH-SG01", 9600)
};
// 华南分公司管理员
var southAdmin = new Staff("U2001", "华南运营总监", "D001-1");
// 扩展2:行级订单过滤
Console.WriteLine("\n========== 【扩展2】华南管理员行级过滤后的销售订单 ==========");
var filterOrd = util.FilterSaleOrders(root, southAdmin, allOrders);
foreach (var o in filterOrd)
Console.WriteLine($"订单{o.OrderId} 门店ID:{o.ShopOrgId} 金额:{o.Amount:F0}");
// 扩展3/4:权限汇总(国内屏蔽海外权限)
Console.WriteLine("\n========== 【扩展3/4】华南管理员权限(无海外报关/外币权限) ==========");
var southPerm = util.GetUserTotalPerms(root, southAdmin, nodeMap)
.Select(k => PermConstant.PermissionMap[k])
.OrderBy(x => x)
.ToList();
foreach (var p in southPerm)
Console.WriteLine($"- {p}");
// 新加坡海外管理员
var sgAdmin = new Staff("U3001", "新加坡负责人", "O001-1");
Console.WriteLine("\n========== 海外子公司管理员权限(包含海外专属权限) ==========");
var sgPerm = util.GetUserTotalPerms(root, sgAdmin, nodeMap)
.Select(k => PermConstant.PermissionMap[k])
.OrderBy(x => x)
.ToList();
foreach (var p in sgPerm)
Console.WriteLine($"- {p}");
// 扩展5:递归导出审计报表
Console.WriteLine("\n========== 【扩展5】递归导出集团审计权限报表 ==========");
var auditReport = new List<AuditRow>();
util.ExportReport(root, auditReport);
foreach (var row in auditReport)
{
string indent = new string(' ', row.Level * 4);
string joinTag = row.IsJoin ? "【加盟】" : "";
Console.WriteLine($"{indent}{joinTag}{row.OrgName} | 自有权限:[{string.Join(",", row.OwnPermNames)}] | 绑定角色:[{string.Join(",", row.BindRoleNames)}]");
}
Console.ReadKey();
}
}
}
输出:

代码实现了一个珠宝集团的组织权限管理系统,主要功能包括:
- 构建多层级组织架构树(包含总部、事业部、分公司、门店等节点)
- 实现权限管理功能:
- 定义常量权限映射表
- 支持组织节点自有权限配置
- 支持角色绑定和递归下发
- 提供5个核心递归算法:
- 角色递归下发全集团
- 销售订单行级递归过滤
- 用户权限递归汇总(含海外权限隔离)
- 递归打印组织树
- 递归导出审计报表
系统特点:
- 支持加盟门店特殊处理
- 实现国内/海外权限隔离
- 提供完整的权限审计功能
- 使用递归算法处理树形结构数据
代码采用C#实现,包含完整的实体类和工具类,展示了递归算法在企业管理系统中的典型应用场景。