using Admin.NET.Plugin.AiDOP.Dto.S8; using Admin.NET.Plugin.AiDOP.Entity.S0.Warehouse; using Admin.NET.Plugin.AiDOP.Infrastructure.S8; namespace Admin.NET.Plugin.AiDOP.Service.S8; /// /// S8 配置页:操作员(员工)↔ 系统账号绑定。 /// 仅维护 EmployeeMaster.SysUserId 的 1:1 弱关联;不动 SysUser/SysRole/SysUserRole。 /// public class S8OperatorBindingService : ITransient { private readonly SqlSugarRepository _empRep; private readonly SqlSugarRepository _sysUserRep; private readonly UserManager _userManager; public S8OperatorBindingService( SqlSugarRepository empRep, SqlSugarRepository sysUserRep, UserManager userManager) { _empRep = empRep; _sysUserRep = sysUserRep; _userManager = userManager; } public async Task> ListAsync(long? factoryRefId, string? bindStatus, string? keyword) { var emps = await _empRep.AsQueryable() .WhereIF(factoryRefId.HasValue, x => x.FactoryRefId == factoryRefId!.Value) .WhereIF(!string.IsNullOrWhiteSpace(keyword), x => x.Employee.Contains(keyword!) || (x.Name != null && x.Name.Contains(keyword!))) .Take(500) .Select(x => new { x.Id, x.Name, x.Employee, x.FactoryRefId, x.SysUserId }) .ToListAsync(); var sysUserIds = emps.Where(e => e.SysUserId.HasValue && e.SysUserId.Value > 0) .Select(e => e.SysUserId!.Value).Distinct().ToList(); var userMap = sysUserIds.Count == 0 ? new Dictionary() : (await _sysUserRep.AsQueryable() .Where(u => sysUserIds.Contains(u.Id) && u.TenantId == _userManager.TenantId) .Select(u => new { u.Id, u.RealName, u.Account }) .ToListAsync()) .ToDictionary(u => u.Id, u => string.IsNullOrWhiteSpace(u.RealName) ? u.Account : u.RealName); var rows = emps.Select(e => { var bound = e.SysUserId.HasValue && e.SysUserId.Value > 0 && userMap.ContainsKey(e.SysUserId.Value); return new AdoS8OperatorBindingRowDto { EmployeeId = e.Id, EmpCode = e.Employee, Name = e.Name, FactoryRefId = e.FactoryRefId, SysUserId = e.SysUserId, SysUserName = bound ? userMap[e.SysUserId!.Value] : null, BindStatus = bound ? "BOUND" : "UNBOUND" }; }); if (!string.IsNullOrWhiteSpace(bindStatus) && (bindStatus == "BOUND" || bindStatus == "UNBOUND")) rows = rows.Where(r => r.BindStatus == bindStatus); return rows .OrderBy(r => r.BindStatus == "BOUND" ? 0 : 1) .ThenBy(r => r.EmpCode) .ToList(); } public async Task> ListSysUsersAsync(string? keyword, long? excludeEmployeeId) { var tenantId = _userManager.TenantId; var users = await _sysUserRep.AsQueryable() .Where(u => u.TenantId == tenantId) .WhereIF(!string.IsNullOrWhiteSpace(keyword), u => u.Account.Contains(keyword!) || u.RealName.Contains(keyword!)) .Take(200) .Select(u => new { u.Id, u.Account, u.RealName, u.Status }) .ToListAsync(); if (users.Count == 0) return new(); // 标注哪些 sysUser 已被其它 employee 绑定(用于前端禁选/隐藏); // 当前 employee 自己绑定的 sysUser 在 alreadyBoundEmployeeId == excludeEmployeeId 时会被前端放行。 var ids = users.Select(u => u.Id).ToList(); var bound = await _empRep.AsQueryable() .Where(e => e.SysUserId.HasValue && ids.Contains(e.SysUserId!.Value)) .Select(e => new { e.Id, e.SysUserId }) .ToListAsync(); var boundMap = bound.GroupBy(b => b.SysUserId!.Value) .ToDictionary(g => g.Key, g => g.First().Id); return users.Select(u => new AdoS8ConfigSysUserRowDto { Id = u.Id, Account = u.Account, RealName = u.RealName, Status = (int)u.Status, AlreadyBoundEmployeeId = boundMap.TryGetValue(u.Id, out var empId) ? empId : null }).ToList(); } public async Task BindAsync(AdoS8OperatorBindingCreateDto dto) { if (dto.EmployeeId <= 0) throw new S8BizException("员工 ID 不能为空"); if (dto.SysUserId <= 0) throw new S8BizException("系统账号 ID 不能为空"); var emp = await _empRep.GetFirstAsync(x => x.Id == dto.EmployeeId) ?? throw new S8BizException("员工不存在"); var tenantId = _userManager.TenantId; var user = await _sysUserRep.GetFirstAsync(x => x.Id == dto.SysUserId && x.TenantId == tenantId) ?? throw new S8BizException("系统账号不存在或不在当前租户"); // 同一 sysUser 不允许绑定到另一个 employee var conflict = await _empRep.GetFirstAsync(x => x.SysUserId == dto.SysUserId && x.Id != dto.EmployeeId); if (conflict != null) throw new S8BizException($"系统账号 {user.Account} 已绑定至其它员工 {conflict.Name ?? conflict.Employee}"); emp.SysUserId = dto.SysUserId; emp.UpdateTime = DateTime.Now; emp.UpdateUser = _userManager.Account; await _empRep.AsUpdateable(emp) .UpdateColumns(it => new { it.SysUserId, it.UpdateTime, it.UpdateUser }) .ExecuteCommandAsync(); return new AdoS8OperatorBindingRowDto { EmployeeId = emp.Id, EmpCode = emp.Employee, Name = emp.Name, FactoryRefId = emp.FactoryRefId, SysUserId = dto.SysUserId, SysUserName = string.IsNullOrWhiteSpace(user.RealName) ? user.Account : user.RealName, BindStatus = "BOUND" }; } public async Task UnbindAsync(long employeeId) { if (employeeId <= 0) throw new S8BizException("员工 ID 不能为空"); var emp = await _empRep.GetFirstAsync(x => x.Id == employeeId) ?? throw new S8BizException("员工不存在"); if (!emp.SysUserId.HasValue) return; emp.SysUserId = null; emp.UpdateTime = DateTime.Now; emp.UpdateUser = _userManager.Account; await _empRep.AsUpdateable(emp) .UpdateColumns(it => new { it.SysUserId, it.UpdateTime, it.UpdateUser }) .ExecuteCommandAsync(); } }