新增MES模块,包含供应商、客户、车辆和地磅数据记录管理功能,支持免密接口和数据同步。更新相关控制器、实体、服务和数据库配置,优化权限管理和数据字典支持,确保系统的灵活性和可扩展性。

This commit is contained in:
geht
2026-04-30 15:28:20 +08:00
parent 142a0bdaba
commit b03cbeff9b
121 changed files with 10540 additions and 424 deletions

View File

@@ -1,9 +1,8 @@
using Dm.util;
using Microsoft.Extensions.Configuration;
using SqlSugar;
using System.Globalization;
using YY.Admin.Core;
using YY.Admin.Core.SeedData;
using YY.Admin.Core.Services;
using YY.Admin.Core.Session;
using YY.Admin.Core.Util;
@@ -11,27 +10,33 @@ namespace YY.Admin.Services.Service.User
{
public class SysUserService : ISysUserService, ISingletonDependency
{
private readonly ISysOrgService _sysOrgService;
private readonly ISqlSugarClient _dbContext;
public SysUserService(ISysOrgService orgService, ISqlSugarClient dbContext)
private readonly IConfiguration _configuration;
private readonly IUserSyncOutbox _userSyncOutbox;
public SysUserService(ISqlSugarClient dbContext, IConfiguration configuration, IUserSyncOutbox userSyncOutbox)
{
_sysOrgService = orgService;
_dbContext = dbContext;
_configuration = configuration;
_userSyncOutbox = userSyncOutbox;
}
public async Task<List<SysUser>> GetUsersAsync()
{
await Task.Delay(200);
await Task.CompletedTask;
return new List<SysUser>();
}
// ── 查询 ──────────────────────────────────────────────────────────────
public async Task<SqlSugarPagedList<UserOutput>> PageAsync(PageUserInput input)
{
var sexFilter = input.Sex.HasValue ? (int?)input.Sex.Value : null;
var statusFilter = input.Status.HasValue ? (int?)input.Status.Value : null;
// 账号管理查询改为从 Jeecg 同构账号表读取
var query = _dbContext.Queryable<JeecgSysUser>().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))
@@ -39,6 +44,7 @@ namespace YY.Admin.Services.Service.User
.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;
@@ -51,35 +57,7 @@ namespace YY.Admin.Services.Service.User
}
var pageData = await query.ToPagedListAsync(input.Page, input.PageSize);
var mapped = pageData.Items.Select(u =>
{
long id = 0;
long.TryParse(u.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out id);
var sex = GenderEnum.Unknown;
if (u.Sex == 1) sex = GenderEnum.Male;
if (u.Sex == 2) sex = GenderEnum.Female;
var status = u.Status == 1 ? StatusEnum.Enable : StatusEnum.Disable;
return new UserOutput
{
Id = id,
Account = u.Username ?? string.Empty,
RealName = u.Realname ?? string.Empty,
// Jeecg 同构表无 nickname 字段,昵称回退为真实姓名,避免页面显示被“清空”
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
};
}).ToList();
var mapped = pageData.Items.Select(MapToOutput).ToList();
return new SqlSugarPagedList<UserOutput>
{
@@ -93,147 +71,205 @@ namespace YY.Admin.Services.Service.User
};
}
public async Task<int> BatchDeleteAsync(List<long> ids)
public async Task<bool> AccountExistsAsync(string account, long? excludeUserId = null)
{
int count = 0;
if (ids == null || ids.isEmpty())
var query = _dbContext.Queryable<JeecgSysUser>().ClearFilter()
.Where(u => (u.DelFlag == null || u.DelFlag == 0) && u.Username == account);
if (excludeUserId.HasValue && excludeUserId.Value != 0)
{
return count;
}
try
{
await _dbContext.AsTenant().BeginTranAsync();
count = await _dbContext.Deleteable<SysUser>().In(ids).ExecuteCommandAsync();
await _dbContext.AsTenant().CommitTranAsync();
}
catch (Exception)
{
await _dbContext.AsTenant().RollbackTranAsync();
}
return count;
}
public async Task<int> DeleteAsync(long id)
{
int count = 0;
try
{
await _dbContext.AsTenant().BeginTranAsync();
count = await _dbContext.Deleteable<SysUser>().In(id).ExecuteCommandAsync();
await _dbContext.AsTenant().CommitTranAsync();
}
catch (Exception)
{
await _dbContext.AsTenant().RollbackTranAsync();
}
return count;
}
public async Task<int> CreateAsync(SysUser sysUser)
{
long maxId = await ReadMaxIdAsync();
sysUser.Id = ++maxId;
sysUser.Password = CryptogramUtil.Encrypt(sysUser.Password);
sysUser.CardType = CardTypeEnum.IdCard;
sysUser.CultureLevel = CultureLevelEnum.Level0;
sysUser.PosId = new SysPosSeedData().HasData().ToList()[0].Id;
sysUser.TenantId = SqlSugarConst.DefaultTenantId;
sysUser.CreateTime = DateTime.Now;
sysUser.CreateUserId = AppSession.UserId;
sysUser.CreateUserName = AppSession.CurrentUser!.Account;
int count = 0;
try
{
await _dbContext.AsTenant().BeginTranAsync();
count = await _dbContext.Insertable(sysUser).ExecuteCommandAsync();
await _dbContext.AsTenant().CommitTranAsync();
}
catch (Exception)
{
await _dbContext.AsTenant().RollbackTranAsync();
}
return count;
}
public async Task<int> UpdateAsync(SysUser sysUser)
{
sysUser.UpdateUserId = AppSession.UserId; ;
sysUser.UpdateUserName = AppSession.CurrentUser!.Account;
sysUser.UpdateTime = DateTime.Now;
int count = 0;
try
{
await _dbContext.AsTenant().BeginTranAsync();
count = await _dbContext.Updateable(sysUser)
.UpdateColumns(it => new { it.RealName, it.NickName, it.Sex, it.Birthday, it.Age, it.Status, it.UpdateUserId, it.UpdateUserName, it.UpdateTime })
.ExecuteCommandAsync();
await _dbContext.AsTenant().CommitTranAsync();
}
catch (Exception)
{
await _dbContext.AsTenant().RollbackTranAsync();
}
return count;
}
public async Task<long> ReadMaxIdAsync()
{
return await _dbContext.Queryable<SysUser>().MaxAsync<long>("Id");
}
public async Task<bool> AccountExistsAsync(string account, long? excludeUserId)
{
var query = _dbContext.Queryable<SysUser>()
. Where(u => u.Account == account);
// excludeUserId不等于null && 不等于 0
if (excludeUserId.HasValue && excludeUserId != 0)
{
query = query.Where(u => u.Id != excludeUserId.Value);
var excludeIdStr = excludeUserId.Value.ToString(CultureInfo.InvariantCulture);
query = query.Where(u => u.Id != excludeIdStr);
}
return await query.AnyAsync();
}
// ── 新增 ──────────────────────────────────────────────────────────────
public async Task<int> CreateAsync(SysUser sysUser)
{
var defaultTenantId = (int?)_configuration.GetValue<long?>("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<int> 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<JeecgSysUser>()
.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<int> ToggleStatus(SysUser sysUser)
{
sysUser.UpdateUserId = AppSession.UserId; ;
sysUser.UpdateUserName = AppSession.CurrentUser!.Account;
sysUser.UpdateTime = DateTime.Now;
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;
int count = 0;
try
var affected = await _dbContext.Updateable<JeecgSysUser>()
.SetColumns(u => new JeecgSysUser
{
Status = jeecgStatus,
UpdateBy = updater,
UpdateTime = now,
})
.Where(u => u.Id == idStr)
.ExecuteCommandAsync();
if (affected > 0)
{
await _dbContext.AsTenant().BeginTranAsync();
count = await _dbContext.Updateable(sysUser)
.UpdateColumns(it => new { it.Status, it.UpdateUserId, it.UpdateUserName, it.UpdateTime })
.ExecuteCommandAsync();
await _dbContext.AsTenant().CommitTranAsync();
_ = _userSyncOutbox.EnqueueToggleStatusAsync(idStr, jeecgStatus, updater);
}
catch (Exception)
{
await _dbContext.AsTenant().RollbackTranAsync();
}
return count;
return affected;
}
// ── 删除 ──────────────────────────────────────────────────────────────
public async Task<int> DeleteAsync(long id)
{
var idStr = id.ToString(CultureInfo.InvariantCulture);
// 软删除保留记录供审计PageAsync 已过滤 del_flag=1
var affected = await _dbContext.Updateable<JeecgSysUser>()
.SetColumns(u => new JeecgSysUser { DelFlag = 1 })
.Where(u => u.Id == idStr)
.ExecuteCommandAsync();
if (affected > 0)
{
_ = _userSyncOutbox.EnqueueDeleteAsync(idStr);
}
return affected;
}
public async Task<int> BatchDeleteAsync(List<long> ids)
{
if (ids == null || ids.Count == 0)
{
return 0;
}
var idStrings = ids.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToList();
var affected = await _dbContext.Updateable<JeecgSysUser>()
.SetColumns(u => new JeecgSysUser { DelFlag = 1 })
.Where(u => idStrings.Contains(u.Id))
.ExecuteCommandAsync();
if (affected > 0)
{
_ = _userSyncOutbox.EnqueueBatchDeleteAsync(idStrings);
}
return affected;
}
// ── 辅助 ──────────────────────────────────────────────────────────────
public async Task<long> 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
};
}
}