| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- using Admin.NET.Core.Service;
- using Admin.NET.Plugin.AiDOP.Infrastructure;
- namespace Admin.NET.Plugin.AiDOP.Controllers.S0;
- /// <summary>
- /// S0 自有的**当前租户只读组织查询**(P1-2)。
- ///
- /// 目的:让 S0 页面不再依赖平台 <c>/api/sysOrg/list</c>。
- /// 平台该路由已登记为按钮权限 <c>sysOrg:list</c>(SysMenu Id=1300200030201),
- /// 普通 S0 业务角色为了填一个隐藏的公司/工厂归属字段而被迫持有平台机构管理权限,
- /// 并因菜单祖先补全在侧边栏暴露「系统管理 / 机构管理」入口。
- /// 本路由 <c>s0:common:orgs</c> 未登记为按钮权限,走 JwtHandler「未登记即放行」分支,
- /// 普通业务角色无需任何平台机构权限即可读取本租户组织。
- ///
- /// 边界(只读 + 只当前租户 + 最小字段):
- /// - 租户来自 <see cref="AdoS0TenantScope.TryResolveRequired"/>(JWT claim),不接受 payload;
- /// - 复用 <see cref="SysOrgService.GetList"/>,与平台口径**完全一致**(含 GetUserOrgIdList
- /// 数据权限收窄与 SysOrg 全局租户过滤),不新写一套查询逻辑、不放宽可见范围;
- /// - 只返回 id / pid / name / code / type 五个字段,不暴露机构管理的任何写能力;
- /// - 额外对结果再做一次当前租户断言,作为纵深防御。
- ///
- /// 返回一律为**平铺列表**:平台 GetList 在不带 Type 条件时返回树,本接口统一拍平,
- /// 使调用方(loadOrgList)无需再关心树/平铺两种形态。
- /// </summary>
- [ApiController]
- [Route("api/s0/common/orgs")]
- [NonUnify]
- public class AdoS0OrgsController : ControllerBase
- {
- private readonly SysOrgService _sysOrgService;
- public AdoS0OrgsController(SysOrgService sysOrgService)
- {
- _sysOrgService = sysOrgService;
- }
- /// <summary>
- /// 查询当前租户的组织列表。<paramref name="type"/> 为 SysOrg.Type(S0 约定 201=公司、501=工厂,
- /// 501 沿用 S0 legacy 兼容语义,见 AdoS0OrgScope 注释);不传则返回本租户全部组织。
- /// </summary>
- [HttpGet]
- public async Task<IActionResult> GetListAsync([FromQuery] string? type)
- {
- if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!;
- var raw = await _sysOrgService.GetList(new OrgInput { Id = 0, Type = type });
- var flat = new List<SysOrg>();
- Flatten(raw, flat);
- var result = flat
- .Where(x => x.TenantId == tenantId) // 纵深防御:平台侧已按租户过滤,这里再断言一次
- .GroupBy(x => x.Id)
- .Select(g => g.First())
- .OrderBy(x => x.OrderNo).ThenBy(x => x.Id)
- .Select(x => new
- {
- id = x.Id.ToString(), // 雪花 Id 超 JS number 精度,一律以 string 下发
- pid = x.Pid.ToString(),
- name = x.Name,
- code = x.Code,
- type = x.Type,
- })
- .ToList();
- return Ok(result);
- }
- /// <summary>把可能的树形结果拍平(平台 GetList 不带条件时返回树,子节点在 Children 内)。</summary>
- private static void Flatten(List<SysOrg>? nodes, List<SysOrg> sink)
- {
- if (nodes == null) return;
- foreach (var n in nodes)
- {
- sink.Add(n);
- Flatten(n.Children, sink);
- }
- }
- }
|