/* # 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); } } }调用:
/* # 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#实现,包含完整的实体类和工具类,展示了递归算法在企业管理系统中的典型应用场景。