using Microsoft.Extensions.Configuration; using SqlSugar; using System.Globalization; using YY.Admin.Core; using YY.Admin.Core.Services; using YY.Admin.Core.Session; using YY.Admin.Core.Util; namespace YY.Admin.Services.Service.User { public class SysUserService : ISysUserService, ISingletonDependency { private readonly ISqlSugarClient _dbContext; private readonly IConfiguration _configuration; private readonly IUserSyncOutbox _userSyncOutbox; public SysUserService(ISqlSugarClient dbContext, IConfiguration configuration, IUserSyncOutbox userSyncOutbox) { _dbContext = dbContext; _configuration = configuration; _userSyncOutbox = userSyncOutbox; } public async Task> GetUsersAsync() { await Task.CompletedTask; return new List(); } // ── 查询 ────────────────────────────────────────────────────────────── public async Task> PageAsync(PageUserInput input) { var sexFilter = input.Sex.HasValue ? (int?)input.Sex.Value : null; var statusFilter = input.Status.HasValue ? (int?)input.Status.Value : null; var query = _dbContext.Queryable().ClearFilter() // 只显示未软删除的记录 .Where(u => u.DelFlag == null || u.DelFlag == 0) .WhereIF(input.TenantId > 0, u => u.LoginTenantId == input.TenantId) .WhereIF(!string.IsNullOrWhiteSpace(input.Account), u => u.Username != null && u.Username.Contains(input.Account)) .WhereIF(!string.IsNullOrWhiteSpace(input.RealName), u => u.Realname != null && u.Realname.Contains(input.RealName)) .WhereIF(!string.IsNullOrWhiteSpace(input.Phone), u => u.Phone != null && u.Phone.Contains(input.Phone)) .WhereIF(input.BeginTime.HasValue, u => u.CreateTime >= input.BeginTime) .WhereIF(input.EndTime.HasValue, u => u.CreateTime <= input.EndTime) .OrderBy(u => SqlFunc.Desc(u.CreateTime)); if (sexFilter.HasValue) { var sexValue = sexFilter.Value; query = query.Where(u => u.Sex == sexValue); } if (statusFilter.HasValue) { var statusValue = statusFilter.Value; query = query.Where(u => u.Status == statusValue); } var pageData = await query.ToPagedListAsync(input.Page, input.PageSize); var mapped = pageData.Items.Select(MapToOutput).ToList(); return new SqlSugarPagedList { Page = pageData.Page, PageSize = pageData.PageSize, Items = mapped, Total = pageData.Total, TotalPages = pageData.TotalPages, HasNextPage = pageData.HasNextPage, HasPrevPage = pageData.HasPrevPage }; } public async Task AccountExistsAsync(string account, long? excludeUserId = null) { var query = _dbContext.Queryable().ClearFilter() .Where(u => (u.DelFlag == null || u.DelFlag == 0) && u.Username == account); if (excludeUserId.HasValue && excludeUserId.Value != 0) { var excludeIdStr = excludeUserId.Value.ToString(CultureInfo.InvariantCulture); query = query.Where(u => u.Id != excludeIdStr); } return await query.AnyAsync(); } // ── 新增 ────────────────────────────────────────────────────────────── public async Task CreateAsync(SysUser sysUser) { var defaultTenantId = (int?)_configuration.GetValue("JeecgIntegration:DefaultTenantId") ?? 1002; var now = DateTime.Now; var jeecgUser = new JeecgSysUser { // 用毫秒时间戳生成本地唯一 ID(数值型字符串,与 PageAsync 的 long.TryParse 兼容) Id = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture), Username = sysUser.Account, Realname = sysUser.RealName, // 本地创建账号使用 CryptogramUtil 加密,无 salt;登录时走 CryptogramUtil 路径 Password = string.IsNullOrWhiteSpace(sysUser.Password) ? string.Empty : CryptogramUtil.Encrypt(sysUser.Password), Salt = null, Sex = ToJeecgSex(sysUser.Sex), Birthday = sysUser.Birthday, Phone = sysUser.Phone, Email = sysUser.Email, Status = 1, // 默认启用 DelFlag = 0, LoginTenantId = defaultTenantId, CreateBy = AppSession.CurrentUser?.Account, CreateTime = now, UpdateTime = now, }; var affected = await _dbContext.Insertable(jeecgUser).ExecuteCommandAsync(); if (affected > 0) { _ = _userSyncOutbox.EnqueueCreateAsync( jeecgUser.Id, jeecgUser.Username ?? string.Empty, jeecgUser.Realname, jeecgUser.Sex, jeecgUser.Birthday, jeecgUser.Phone, jeecgUser.Email, jeecgUser.Status ?? 1, jeecgUser.CreateBy); } return affected; } // ── 修改 ────────────────────────────────────────────────────────────── public async Task UpdateAsync(SysUser sysUser) { var idStr = sysUser.Id.ToString(CultureInfo.InvariantCulture); var now = DateTime.Now; var updater = AppSession.CurrentUser?.Account; var jeecgStatus = sysUser.Status == StatusEnum.Enable ? 1 : 2; var jeecgSex = ToJeecgSex(sysUser.Sex); var account = (sysUser.Account ?? string.Empty).Trim(); var affected = await _dbContext.Updateable() .SetColumns(u => new JeecgSysUser { Username = account, Realname = sysUser.RealName, Sex = jeecgSex, Birthday = sysUser.Birthday, Phone = sysUser.Phone, Email = sysUser.Email, Status = jeecgStatus, UpdateBy = updater, UpdateTime = now, }) .Where(u => u.Id == idStr) .ExecuteCommandAsync(); if (affected > 0) { _ = _userSyncOutbox.EnqueueUpdateAsync(idStr, account, sysUser.RealName, jeecgSex, sysUser.Birthday, sysUser.Phone, sysUser.Email, jeecgStatus, updater); } return affected; } // ── 状态切换 ────────────────────────────────────────────────────────── public async Task ToggleStatus(SysUser sysUser) { var idStr = sysUser.Id.ToString(CultureInfo.InvariantCulture); // Jeecg 约定:1=正常,2=冻结 var jeecgStatus = sysUser.Status == StatusEnum.Enable ? 1 : 2; var now = DateTime.Now; var updater = AppSession.CurrentUser?.Account; var affected = await _dbContext.Updateable() .SetColumns(u => new JeecgSysUser { Status = jeecgStatus, UpdateBy = updater, UpdateTime = now, }) .Where(u => u.Id == idStr) .ExecuteCommandAsync(); if (affected > 0) { _ = _userSyncOutbox.EnqueueToggleStatusAsync(idStr, jeecgStatus, updater); } return affected; } // ── 删除 ────────────────────────────────────────────────────────────── public async Task DeleteAsync(long id) { var idStr = id.ToString(CultureInfo.InvariantCulture); // 软删除:保留记录供审计,PageAsync 已过滤 del_flag=1 var affected = await _dbContext.Updateable() .SetColumns(u => new JeecgSysUser { DelFlag = 1 }) .Where(u => u.Id == idStr) .ExecuteCommandAsync(); if (affected > 0) { _ = _userSyncOutbox.EnqueueDeleteAsync(idStr); } return affected; } public async Task BatchDeleteAsync(List ids) { if (ids == null || ids.Count == 0) { return 0; } var idStrings = ids.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToList(); var affected = await _dbContext.Updateable() .SetColumns(u => new JeecgSysUser { DelFlag = 1 }) .Where(u => idStrings.Contains(u.Id)) .ExecuteCommandAsync(); if (affected > 0) { _ = _userSyncOutbox.EnqueueBatchDeleteAsync(idStrings); } return affected; } // ── 辅助 ────────────────────────────────────────────────────────────── public async Task ReadMaxIdAsync() { // jeecg_sys_user 使用字符串ID,此方法不再适用;保留签名兼容旧调用 await Task.CompletedTask; return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); } private static UserOutput MapToOutput(JeecgSysUser u) { long.TryParse(u.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var id); var sex = u.Sex == 1 ? GenderEnum.Male : u.Sex == 2 ? GenderEnum.Female : GenderEnum.Unknown; var status = u.Status == 1 ? StatusEnum.Enable : StatusEnum.Disable; return new UserOutput { Id = id, Account = u.Username ?? string.Empty, RealName = u.Realname ?? string.Empty, NickName = string.IsNullOrWhiteSpace(u.Realname) ? (u.Username ?? string.Empty) : u.Realname, Avatar = u.Avatar, Sex = sex, Birthday = u.Birthday, Phone = u.Phone, Email = u.Email, OfficePhone = u.Telephone, Status = status, CreateTime = u.CreateTime, OrgName = u.OrgCode ?? string.Empty, PosName = u.PositionType ?? string.Empty, RoleName = string.Empty, AccountType = AccountTypeEnum.NormalUser }; } private static int? ToJeecgSex(GenderEnum? sex) => sex switch { GenderEnum.Male => 1, GenderEnum.Female => 2, _ => null }; } }