fix 注释+设备密码脱敏

This commit is contained in:
2025-06-13 20:00:48 +08:00
parent 249f26fc60
commit 59dafeee40
5 changed files with 139 additions and 33 deletions

View File

@@ -182,25 +182,31 @@ public class AppointmentService : IAppointmentService
public async Task FocusLeaveAsync(long id, string reason)
{
// 根据访客预约详情ID获取记录,若不存在则抛出异常
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == id).SingleAsync();
detail.ThrowIfNull("数据不存在");
//Wait->obsolete; Arrived->FocusLeave
// 如果已进入门区且门区状态为“已到达”,则将门区状态更新为“强制离场”
if (detail.IsEnterDoorArea && detail.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
detail.DoorStatus = VisitorAppointmentDetailStatusEnumType.FocusLeave;
// 如果已进入门区且门区状态为“待到达”,则将门区状态更新为“作废”
if (detail.IsEnterDoorArea && detail.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
detail.DoorStatus = VisitorAppointmentDetailStatusEnumType.Obsolete;
// 如果已进入工作区且工作区状态为“已到达”,则将工作区状态更新为“强制离场”
if (detail.IsEnterWorkplace && detail.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
detail.WorkplaceStatus = VisitorAppointmentDetailStatusEnumType.FocusLeave;
// 如果已进入工作区且工作区状态为“待到达”,则将工作区状态更新为“作废”
if (detail.IsEnterWorkplace && detail.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Wait)
detail.WorkplaceStatus = VisitorAppointmentDetailStatusEnumType.Obsolete;
// 记录强制离场时间和原因
detail.FocusLeaveDateTime = DateTime.Now;
detail.Remark += "强制离场:" + reason;
// 生成设备任务并更新数据库
await GenerateDeviceTasksAsync(detail, true, DeviceTaskEnumType.Delete, $"强制离场:{reason}");
await _dbContext.UpdateAsync(detail);
}
@@ -370,12 +376,14 @@ public class AppointmentService : IAppointmentService
foreach (var ext in exts)
{
// 查询该外部人员最近一次通行记录的时间
DateTime? raiseDateTime = await _dbContext.Queryable<DeviceUploadLogEntity>()
.Where(x => x.UserUniqueNo == ext.Code)
.GroupBy(x => x.UserUniqueNo)
.Select(x => SqlFunc.IsNull(SqlFunc.AggregateMax(x.RaiseDateTime), default(DateTime?)))
.SingleAsync();
// 如果最近通行时间存在且超出未通行天数阈值,则自动归档该外部人员
if (raiseDateTime.HasValue && raiseDateTime.Value.AddDays(setting.NoRecordAutoResignExternalDays) < DateTime.Now)
{
try
@@ -389,6 +397,7 @@ public class AppointmentService : IAppointmentService
}
catch (Exception e)
{
// 记录自动归档异常日志
_logger.LogError(e, "自动归档外部人员异常:{msg}", e.Message);
}
}

View File

@@ -3,39 +3,51 @@ using Dlhis.Basic.Device.Response;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Basic.Device.Services;
/// <summary>
/// 例外人员权限分配
/// 例外人员权限分配服务接口,定义了对设备权限进行手动分配、查询及清理的相关操作。
/// </summary>
public interface IDevicePermissionManuallyService : IScopeDependency
{
/// <summary>
/// 获取例外分配分页
/// 获取例外分配的分页数据。
/// </summary>
/// <param name="requestDto"></param>
/// <returns></returns>
/// <param name="requestDto">分页及筛选请求参数。</param>
/// <returns>包含例外分配信息的分页结果。</returns>
Task<Pagination<DevicePermissionManuallyResponse>> GetPageAsync(DevicePermissionManuallyRequest requestDto);
/// <summary>
/// 添加例外
/// 添加新的例外分配记录。
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
/// <param name="request">例外分配添加请求参数。</param>
/// <returns>异步操作任务。</returns>
Task AddAsync(DevicePermissionManuallyAddRequest request);
/// <summary>
/// 删除例外
/// 根据主键删除指定的例外分配记录。
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <param name="id">要删除的记录主键ID。</param>
/// <returns>异步操作任务。</returns>
Task DeleteAsync(long id);
/// <summary>
/// 批量删除
/// 批量删除例外分配记录。
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
/// <param name="ids">要删除的记录主键ID集合。</param>
/// <returns>异步操作任务。</returns>
Task DeleteAsync(List<long> ids);
/// <summary>
/// 清除指定用户的所有设备例外权限。
/// </summary>
/// <param name="userNo">用户编号。</param>
/// <returns>异步操作任务。</returns>
Task ClearUserDeviceManuallyPermissionsAsync(string userNo);
/// <summary>
/// 清除指定工厂下指定用户的所有设备权限。
/// </summary>
/// <param name="factory">工厂编码。</param>
/// <param name="userCode">用户编码。</param>
/// <returns>异步操作任务。</returns>
Task ClearAllDevicePermissions(string factory, string userCode);
}

View File

@@ -42,7 +42,6 @@ public class DevicePermissionManuallyService : IDevicePermissionManuallyService
Type = d.Type
});
_logger.LogInformation(query.ToSqlString());
return await query.ToPageListAsync(requestDto);
}
@@ -88,6 +87,25 @@ public class DevicePermissionManuallyService : IDevicePermissionManuallyService
public async Task DeleteAsync(List<long> ids)
{
var data = await _dbContext.Queryable<DevicePermissionManuallyEntity>().Where(x => ids.Contains(x.Id)).ToListAsync();
await DeleteAsync(data);
}
public async Task ClearUserDeviceManuallyPermissionsAsync(string userNo)
{
var userInfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.No == userNo).Select(x => new { x.Id, x.No }).SingleAsync()
?? await _dbContext.Queryable<GainfoLeaveEntity>().Where(x => x.No == userNo).Select(x => new { Id = (long)x.IdentityUserId, x.No }).SingleAsync();
userInfo.ThrowIfNull($"{userNo}不存在");
var data = await _dbContext.Queryable<DevicePermissionManuallyEntity>().Where(x => x.UserNo == userInfo.No).ToListAsync();
if (data.Count > 0)
{
await DeleteAsync(data);
}
}
private async Task DeleteAsync(List<DevicePermissionManuallyEntity> data)
{
var deviceCodes = data.Select(x => x.DeviceCode).Distinct().ToList();
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => deviceCodes.Contains(x.Code)).ToListAsync();
@@ -122,6 +140,7 @@ public class DevicePermissionManuallyService : IDevicePermissionManuallyService
}
}
/// <inheritdoc />
public async Task ClearAllDevicePermissions(string factory, string userCode)
{

View File

@@ -14,12 +14,14 @@ using Kurisu.AspNetCore.Utils.Extensions;
using Mapster;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SqlSugar;
namespace Dlhis.Basic.Device.Services.Implements;
public class DeviceService : IDeviceService
{
private const string DefaultPassword = "********";
private const string DefaultPasswordKey = "password";
private readonly IDbContext _dbContext;
private readonly ICurrentUser _currentUser;
private readonly ITenantApi _tenantApi;
@@ -55,6 +57,26 @@ public class DeviceService : IDeviceService
}, true)
.ToPageListAsync(request);
//获取当前用户角色
var role = _currentUser.GetRole();
//如果当前用户不是管理员或租户管理员,则对设备列表中的连接信息进行脱敏处理,将密码字段替换为默认密码,防止敏感信息泄露。
if (role is not ("admin" or "tenant-admin"))
{
foreach (var item in page.Data)
{
var jObj = JObject.Parse(item.ConnectionInfo);
if (jObj.TryGetValue(DefaultPasswordKey, out var password))
{
if (password.Value<string>().IsPresent())
{
jObj[DefaultPasswordKey] = DefaultPassword;
item.ConnectionInfo = jObj.ToString();
}
}
}
}
return page;
}
@@ -71,6 +93,12 @@ public class DeviceService : IDeviceService
if (!request.Id.HasValue)
{
var password = GetJsonValue(request.ConnectionInfo, DefaultPasswordKey);
if (password.IsPresent())
{
(password == DefaultPassword).ThrowIfTrue("不支持错误的密码类型");
}
entity = request.Adapt<DeviceEntity>();
entity.UniqueNo = request.UniqueNo;
entity.Code = Guid.NewGuid();
@@ -106,6 +134,21 @@ public class DeviceService : IDeviceService
existsG.ThrowIfTrue("存在设备分组,不可修改设备类型");
}
//检查更新的密码字段是否为默认密码,如果是,则将原有密码从数据库实体中取出并替换到请求的连接信息中,防止默认密码被保存。
// 这样可以避免用户在未修改密码时,前端传递默认密码导致密码被覆盖为不可用的默认值。
var updatePassword = GetJsonValue(request.ConnectionInfo, DefaultPasswordKey);
if (updatePassword.IsPresent())
{
if (updatePassword == DefaultPassword)
{
var jObj = JObject.Parse(request.ConnectionInfo);
var password = GetJsonValue(entity.ConnectionInfo, DefaultPasswordKey);
jObj[DefaultPasswordKey] = password;
request.ConnectionInfo = jObj.ToString();
}
}
request.Adapt(entity);
await _dbContext.UpdateAsync(entity);
@@ -128,6 +171,28 @@ public class DeviceService : IDeviceService
}, "设备启用/关闭时段码功能");
}
/// <summary>
/// 获取json的字段值
/// </summary>
/// <param name="json"></param>
/// <param name="key"></param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
private static string GetJsonValue(string json, string key)
{
try
{
var jObj = JObject.Parse(json);
return jObj.TryGetValue(key, out var value)
? value.Value<string>()
: string.Empty;
}
catch (JsonReaderException)
{
throw new UserFriendlyException("连接信息参数格式不正确");
}
}
/// <summary>
/// 批量导入
/// </summary>
@@ -141,7 +206,7 @@ public class DeviceService : IDeviceService
await _dbContext.Client.Ado.BeginTranAsync();
try
{
for (int i = 0; i < request.Count; i++)
for (var i = 0; i < request.Count; i++)
{
var row = i + 1;
try
@@ -218,18 +283,18 @@ public class DeviceService : IDeviceService
/// <returns></returns>
private async Task CheckTemplateFieldAsync(Guid templateCode, string jsonContent)
{
var template = await _dbContext.Queryable<DeviceTemplateEntity>().Where(x => x.Code == templateCode).FirstAsync();
var template = await _dbContext.Queryable<DeviceTemplateEntity>().Where(x => x.Code == templateCode).SingleAsync();
template.ThrowIfNull("设备模板不存在");
try
{
var templateJobj = JObject.Parse(template.Template);
var jobj = JObject.Parse(jsonContent);
(templateJobj.Count == jobj.Count).ThrowIfFalse("连接参数字段数不一致");
var templateJObj = JObject.Parse(template.Template);
var jObj = JObject.Parse(jsonContent);
(templateJObj.Count == jObj.Count).ThrowIfFalse("连接参数字段数不一致");
foreach (var item in templateJobj)
foreach (var item in templateJObj)
{
jobj.ContainsKey(item.Key).ThrowIfFalse($"设备连接参数需要和模板一致.缺失{item.Key}");
jObj.ContainsKey(item.Key).ThrowIfFalse($"设备连接参数需要和模板一致.缺失{item.Key}");
}
}
catch (Exception ex) when (ex is JsonReaderException)

View File

@@ -267,13 +267,14 @@ public class GainfoService : IGainfoService
if (gainfo.Type == GainfoUserTypeEnumType.External)
{
//获取人员所有的访客申请
// 查询当前外部人员的访客预约明细,筛选出尚未离开门区或工作区的记录
var visitorAppointmentDetails = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
.Where(x => x.UserNo == gainfo.No)
.Where(x => (x.IsEnterDoorArea && x.DoorStatus != VisitorAppointmentDetailStatusEnumType.Leave)
|| (x.IsEnterWorkplace && x.WorkplaceStatus != VisitorAppointmentDetailStatusEnumType.Leave))
.ToListAsync();
// 对每条未离开的访客预约明细,调用预约服务进行强制离开处理
foreach (var visitorAppointment in visitorAppointmentDetails)
{
await _appointmentService.FocusLeaveAsync(visitorAppointment.Id, request.Reason);
@@ -286,7 +287,7 @@ public class GainfoService : IGainfoService
await _dbContext.Deleteable<GainfoGroupRelationshipEntity>().Where(x => x.UserNo == gainfo.No).ExecuteCommandAsync();
await _dbContext.Deleteable<DevicePermissionEntity>().Where(x => x.AssignType == AssignTypeEnumType.User && x.AssignValue == gainfo.No).ExecuteCommandAsync();
}
//先写入离职表
gainfo.IdentityUserId = (int)gainfo.Id; //记录原始id
gainfo.ResignationDate = request.Date;