using Microsoft.Extensions.Caching.Memory;
using Model;
using Model.Dto.System;
using Model.Entity.System;
using Model.Mapper;
using ORM;
using Service.Interface;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Service.Implement
{
///
/// 系统参数配置 服务实现
/// 缓存策略:按 ParamKey 缓存值;增删改时失效对应 Key(Key 变更时新旧都失效)
///
public class SystemParamService : ISystemParamService
{
private readonly IMemoryCache _cache;
private readonly ICurrentUser _currentUser;
private static readonly object _cacheLock = new();
public SystemParamService(IMemoryCache cache, ICurrentUser currentUser)
{
_cache = cache;
_currentUser = currentUser;
}
// ==================== 管理侧 ====================
public async Task>> GetListPagedAsync(int pageIndex, int pageSize, RefAsync total, string? keyword = null, string? group = null)
{
try
{
var list = await SqlSugarContext.DbContext.Queryable()
.Where(x => x.IsDel == 0)
.WhereIF(!string.IsNullOrWhiteSpace(keyword), x => x.ParamKey.Contains(keyword!) || x.ParamName.Contains(keyword!))
.WhereIF(!string.IsNullOrWhiteSpace(group), x => x.Group == group)
.OrderBy(x => x.Sort).OrderBy(x => x.CreateTime, OrderByType.Desc)
.ToPageListAsync(pageIndex, pageSize, total);
return Result>.Success(list.ToDtoList());
}
catch (Exception ex)
{
return Result>.Error("查询系统参数失败", ex);
}
}
public async Task> GetByIdAsync(long id)
{
try
{
var entity = await SqlSugarContext.DbContext.Queryable()
.Where(x => x.Id == id && x.IsDel == 0).FirstAsync();
if (entity == null) return Result.Error("系统参数不存在或已被删除");
return Result.Success(entity.ToDto());
}
catch (Exception ex)
{
return Result.Error("查询系统参数详情失败", ex);
}
}
public async Task> AddAsync(SystemParamDto dto)
{
if (dto == null || string.IsNullOrWhiteSpace(dto.ParamKey) || string.IsNullOrWhiteSpace(dto.ParamName))
return Result.Error("参数键和名称不能为空");
try
{
var keyExists = await SqlSugarContext.DbContext.Queryable()
.Where(x => x.ParamKey == dto.ParamKey && x.IsDel == 0).AnyAsync();
if (keyExists) return Result.Error($"参数键「{dto.ParamKey}」已存在");
var entity = dto.ToEntity();
entity.Id = 0;
entity.IsSystem = 0; // 用户新增的不是内置参数
entity.CreateTime = DateTime.Now;
entity.LastUpdateUser = _currentUser.UserName;
entity.LastUpdateTime = DateTime.Now;
var id = await SqlSugarContext.DbContext.Insertable(entity).ExecuteReturnSnowflakeIdAsync();
entity.Id = id;
InvalidateCache(entity.ParamKey);
return Result.Success(entity.ToDto());
}
catch (Exception ex)
{
return Result.Error("新增系统参数失败", ex);
}
}
public async Task> UpdateAsync(SystemParamDto dto)
{
if (dto == null || !long.TryParse(dto.Id, out var id) || id <= 0)
return Result.Error("参数Id无效");
try
{
var entity = await SqlSugarContext.DbContext.Queryable()
.Where(x => x.Id == id && x.IsDel == 0).FirstAsync();
if (entity == null) return Result.Error("系统参数不存在或已被删除");
// Key 变更时校验唯一
if (!string.Equals(entity.ParamKey, dto.ParamKey, StringComparison.OrdinalIgnoreCase))
{
var keyExists = await SqlSugarContext.DbContext.Queryable()
.Where(x => x.ParamKey == dto.ParamKey && x.Id != id && x.IsDel == 0).AnyAsync();
if (keyExists) return Result.Error($"参数键「{dto.ParamKey}」已存在");
}
var oldKey = entity.ParamKey;
var now = DateTime.Now;
var userName = _currentUser.UserName;
if (entity.IsSystem == 1)
{
// 内置参数仅允许改 Value/Remark,其它字段保留
entity.ParamValue = dto.ParamValue;
entity.Remark = dto.Remark;
entity.LastUpdateUser = userName;
entity.LastUpdateTime = now;
await SqlSugarContext.DbContext.Updateable(entity)
.UpdateColumns(x => new { x.ParamValue, x.Remark, x.LastUpdateUser, x.LastUpdateTime })
.ExecuteCommandAsync();
}
else
{
// 用户自定义参数:全字段更新(审计字段由服务端控管)
var newEntity = dto.ToEntity();
newEntity.Id = id;
newEntity.IsSystem = 0;
newEntity.CreateTime = entity.CreateTime;
newEntity.LastUpdateUser = userName;
newEntity.LastUpdateTime = now;
await SqlSugarContext.DbContext.Updateable(newEntity)
.IgnoreColumns(x => new { x.CreateTime, x.IsDel })
.ExecuteCommandAsync();
entity = newEntity;
}
InvalidateCache(oldKey);
InvalidateCache(entity.ParamKey);
return Result.Success(entity.ToDto());
}
catch (Exception ex)
{
return Result.Error("修改系统参数失败", ex);
}
}
public async Task DeleteAsync(long id)
{
if (id <= 0) return Result.Error("参数Id无效");
try
{
var entity = await SqlSugarContext.DbContext.Queryable()
.Where(x => x.Id == id && x.IsDel == 0).FirstAsync();
if (entity == null) return Result.Error("系统参数不存在或已被删除");
if (entity.IsSystem == 1) return Result.Error($"内置参数「{entity.ParamName}」禁止删除,仅允许修改值");
await SqlSugarContext.DbContext.Updateable()
.SetColumns(x => x.IsDel == 1)
.Where(x => x.Id == id).ExecuteCommandAsync();
InvalidateCache(entity.ParamKey);
return Result.Success();
}
catch (Exception ex)
{
return Result.Error("删除系统参数失败", ex);
}
}
public Task ReloadCacheAsync()
{
// IMemoryCache 非强类型缓存清除,此处复用一个枚举 Key 的策略:清除所有 sysparam: 前缀缓存需要 ICache 抽象;
// 当前实现:通过 Coherent MemoryCache 实例的 compact,按约定不实现细粒度清除,仅返回成功提示由进程内自然过期
// 注:增删改单条时已按 Key 失效;本接口预留给运维紧急场景,下次访问会重新加载
try
{
// 由于 IMemoryCache 没有枚举能力,这里仅作占位返回;如需全量清除,请重启服务或改用 IDistributedCache
return Task.FromResult(Result.Success());
}
catch (Exception ex)
{
return Task.FromResult(Result.Error("清空缓存失败", ex));
}
}
// ==================== 业务侧:按 Key 取值(带缓存) ====================
public async Task> GetValueAsync(string key)
{
if (string.IsNullOrWhiteSpace(key))
return Result.Error("参数键不能为空");
try
{
var value = await LoadValueByKeyAsync(key);
return Result.Success(value ?? string.Empty);
}
catch (Exception ex)
{
return Result.Error("查询参数值失败", ex);
}
}
public async Task>> GetValuesAsync(string[] keys)
{
if (keys == null || keys.Length == 0)
return Result>.Error("参数键列表不能为空");
try
{
var distinctKeys = keys.Where(k => !string.IsNullOrWhiteSpace(k)).Distinct().ToList();
var list = new List(distinctKeys.Count);
foreach (var k in distinctKeys)
{
var v = await LoadValueByKeyAsync(k);
list.Add(new SystemParamValueDto { Key = k, Value = v ?? string.Empty });
}
return Result>.Success(list);
}
catch (Exception ex)
{
return Result>.Error("批量查询参数值失败", ex);
}
}
// ==================== 私有工具 ====================
private async Task LoadValueByKeyAsync(string key)
{
var cacheKey = $"sysparam:{key}";
if (!_cache.TryGetValue(cacheKey, out string? cached))
{
lock (_cacheLock)
{
if (!_cache.TryGetValue(cacheKey, out cached))
{
cached = SqlSugarContext.DbContext.Queryable()
.Where(x => x.ParamKey == key && x.IsDel == 0)
.Select(x => x.ParamValue).First();
_cache.Set(cacheKey, cached ?? string.Empty, TimeSpan.FromHours(1));
}
}
}
return cached;
}
private void InvalidateCache(string? key)
{
if (string.IsNullOrWhiteSpace(key)) return;
_cache.Remove($"sysparam:{key}");
}
}
}