using EasyCaching.Core; using Hotline.Application.ExportExcel; using Hotline.Api.Filter; using Hotline.Application.Systems; using Hotline.Caching.Interfaces; using Hotline.CallCenter.Ivrs; using Hotline.CallCenter.Tels; using Hotline.Configurations; using Hotline.FlowEngine.WorkflowModules; using Hotline.Orders; using Hotline.Permissions; using Hotline.Realtimes; using Hotline.Repository.SqlSugar.Extensions; using Hotline.Settings; using Hotline.Settings.CommonOpinions; using Hotline.Share.Dtos; using Hotline.Share.Dtos.Dic; using Hotline.Share.Dtos.Menu; using Hotline.Share.Dtos.Order; using Hotline.Share.Dtos.Settings; using Hotline.Share.Enums.Settings; using Hotline.Share.Requests; using Hotline.Share.Tools; using Hotline.Users; using Hotline.YbEnterprise.Sdk; using MapsterMapper; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using NPOI.SS.Formula.Functions; using SqlSugar; using StackExchange.Redis; using Wex.Sdk; using XF.Domain.Authentications; using XF.Domain.Cache; using XF.Domain.Exceptions; using XF.Domain.Repository; using XF.Utility.EnumExtensions; using Hotline.Tools; using Hotline.Share.Dtos.TrCallCenter; namespace Hotline.Api.Controllers { /// /// 系统管理相关接口 /// public class SysController : BaseController { private readonly IMapper _mapper; private readonly IRepository _systemSettingsRepository; private readonly ISystemMenuRepository _systemMenuRepository; private readonly IRepository _sysDicTypeRepository; private readonly IRepository _sysDicDataRepository; private readonly ISystemAreaDomainService _systemAreaDomainService; private readonly IRepository _systemAreaRepository; private readonly ISystemCommonOpinionDomainService _commonOpinionDomainService; private readonly IRepository _commonOpinionRepository; private readonly ISessionContext _sessionContext; private readonly ISystemDicDataCacheManager _systemDicDataCacheManager; private readonly IRepository _systemLogRepository; private readonly ISystemMobilAreaApplication _systemMobilAreaApplication; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IRedisCachingProvider _redisCaching; private readonly IEasyCachingProvider _easyCaching; private readonly IOptionsSnapshot _appOptions; private readonly ISystemLogApplication _systemLogApplication; private readonly IExportApplication _exportApplication; private readonly IHybridCachingProvider _hybridCaching; /// /// 系统管理相关接口 /// /// /// /// /// /// /// /// /// /// /// /// /// /// public SysController( IMapper mapper, IRepository systemSettingsRepository, ISystemMenuRepository systemMenuRepository, IRepository sysDicTypeRepository, IRepository sysDicDataRepository, ISystemAreaDomainService systemAreaDomainService, IRepository systemAreaRepository, ISystemCommonOpinionDomainService commonOpinionDomainService, IRepository commonOpinionRepository, ISessionContext sessionContext, ISystemDicDataCacheManager systemDicDataCacheManager, IRepository systemLogRepository, ISystemMobilAreaApplication systemMobilAreaApplication, IServiceScopeFactory serviceScopeFactory, IRedisCachingProvider redisCaching, IEasyCachingProvider easyCaching , IOptionsSnapshot appOptions, ISystemLogApplication systemLogApplication, IExportApplication exportApplication, IHybridCachingProvider hybridCaching) { _mapper = mapper; _systemSettingsRepository = systemSettingsRepository; _systemMenuRepository = systemMenuRepository; _sysDicTypeRepository = sysDicTypeRepository; _sysDicDataRepository = sysDicDataRepository; _systemAreaDomainService = systemAreaDomainService; _systemAreaRepository = systemAreaRepository; _commonOpinionDomainService = commonOpinionDomainService; _commonOpinionRepository = commonOpinionRepository; _sessionContext = sessionContext; _systemDicDataCacheManager = systemDicDataCacheManager; _systemLogRepository = systemLogRepository; _systemMobilAreaApplication = systemMobilAreaApplication; _serviceScopeFactory = serviceScopeFactory; _redisCaching = redisCaching; _easyCaching = easyCaching; _appOptions = appOptions; _systemLogApplication = systemLogApplication; _exportApplication = exportApplication; _hybridCaching = hybridCaching; } #region 菜单管理 /// /// 获取菜单 /// /// [Permission(EPermission.GetMenuJson)] [AllowAnonymous] [HttpGet("getmenujson")] public async Task> GetMenuJson() { //获取菜单树形 return await _systemMenuRepository.GetSystemMenus(); } /// /// 新增菜单 /// /// /// //[Permission(EPermission.AddMenu)] [HttpPost("add-menu")] public async Task AddMenu([FromBody] AddMenuDto dto) { var menu = _mapper.Map(dto); await _systemMenuRepository.AddAsync(menu, HttpContext.RequestAborted); } /// /// 修改菜单 /// /// /// //[Permission(EPermission.UpdateMenu)] [HttpPost("update-menu")] public async Task UpdateMenu([FromBody] UpdateMenuDto dto) { var menu = await _systemMenuRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (menu is null) throw UserFriendlyException.SameMessage("无效菜单"); _mapper.Map(dto, menu); await _systemMenuRepository.UpdateAsync(menu, HttpContext.RequestAborted); } /// /// 删除菜单 /// /// /// //[Permission(EPermission.RemoveMenu)] [HttpDelete("removemenu/{id}")] public async Task RemoveMenu(string id) { var menu = await _systemMenuRepository.GetAsync(id, HttpContext.RequestAborted); if (menu is null) throw UserFriendlyException.SameMessage("无效菜单"); //检查是否存在下级菜单 var ishavemenu = await _systemMenuRepository.AnyAsync(x => x.ParentId == id); if (ishavemenu) throw UserFriendlyException.SameMessage("存在下级菜单,暂时不能删除"); //检查是否存在按钮 //var ishavebutton = await _systemButtonRepository.AnyAsync(x => x.MenuId == id); //if (ishavebutton) // throw UserFriendlyException.SameMessage("存在按钮权限,暂时不能删除"); await _systemMenuRepository.RemoveAsync(id, false, HttpContext.RequestAborted); } /// /// 获取菜单对象 /// /// /// [HttpGet("menu/{id}")] public async Task GetMenu(string id) { var menu = await _systemMenuRepository.GetAsync(id, HttpContext.RequestAborted); if (menu is null) throw UserFriendlyException.SameMessage("无效菜单"); return menu; } #region 按钮管理 ///// ///// 通过菜单ID获取按钮列表 ///// ///// ///// //[HttpGet("getbuttonmenu")] //public async Task> GetButtonByMenu(string menuid) //{ // return await _systemButtonRepository.QueryAsync(x => x.MenuId == menuid); //} ///// ///// 新增按钮 ///// ///// ///// //[HttpPost("add-button")] //public async Task AddButton([FromBody] AddButtonDto dto) //{ // var button = _mapper.Map(dto); // await _systemButtonRepository.AddAsync(button); //} ///// ///// 编辑按钮 ///// ///// ///// //[HttpPost("update-button")] //public async Task UpdateButton([FromBody] UpdateButtonDto dto) //{ // var button = await _systemButtonRepository.GetAsync(dto.Id, HttpContext.RequestAborted); // if (button is null) // throw UserFriendlyException.SameMessage("无效按钮"); // _mapper.Map(dto, button); // await _systemButtonRepository.UpdateAsync(button); //} ///// ///// 删除按钮 ///// ///// ///// //[HttpDelete("removebutton/{id}")] //public async Task RemoveButton(string id) //{ // var button = await _systemButtonRepository.GetAsync(id, HttpContext.RequestAborted); // if (button is null) // throw UserFriendlyException.SameMessage("无效按钮"); // await _systemButtonRepository.RemoveAsync(id, false, HttpContext.RequestAborted); //} ///// ///// 获取按钮对象 ///// ///// ///// //[HttpGet("button/{id}")] //public async Task GetButton(string id) //{ // var button = await _systemButtonRepository.GetAsync(id, HttpContext.RequestAborted); // if (button is null) // throw UserFriendlyException.SameMessage("无效按钮"); // return button; //} #endregion #endregion #region 字典管理 /// /// 获取字典类型列表 /// /// [HttpPost("dictype-list")] public async Task> GetSysDicType() { return await _sysDicTypeRepository.Queryable().ToListAsync(); } /// /// 根据字典类型ID获取字典列表 /// /// /// [HttpGet("dictdata-type")] public async Task> GetSysDicData([FromQuery] GetSysDicDataDto dto) { return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.typeid).OrderBy(x => x.Sort)/*.WhereIF(!string.IsNullOrEmpty(dto.datavalue),x=>x.DicDataValue.Contains(dto.datavalue))*/.ToTreeAsync(x => x.Children, x => x.ParentId, ""); //return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.typeid).WhereIF(!string.IsNullOrEmpty(dto.datavalue), x => x.DicDataValue.Contains(dto.datavalue)).WhereIF(!string.IsNullOrEmpty(dto.ParentId), x => x.ParentId == dto.ParentId).ToListAsync(); } /// /// 根据字典类型ID获取字典列表 /// /// /// [HttpPost("dictdata-type/export")] [LogFilterAlpha("导出日志")] public async Task GetSysDicDataExport([FromBody] ExportExcelDto dto) { var items = await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.QueryDto.typeid).OrderBy(x => x.Sort).ToTreeAsync(x => x.Children, x => x.ParentId, ""); return _exportApplication.GetExcelFile(dto, items, "字典列表"); } /// /// 根据字典类型Code获取字典列表 /// /// /// [HttpGet("dictdata-code/{code}")] public async Task> GetSysDicDataByCode(string code) { return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeCode == code).OrderBy(x => x.Sort).ToListAsync(); } /// /// 获取字典对象 /// /// /// [HttpGet("dicdata/{id}")] public async Task SysDicDataModel(string id) { var dicData = await _sysDicDataRepository.GetAsync(id, HttpContext.RequestAborted); if (dicData is null) throw UserFriendlyException.SameMessage("无效数据"); return dicData; } /// /// 新增字典数据 /// /// /// [HttpPost("add-dicdata")] public async Task AddDicData([FromBody] AddDicDataDto dto) { var dicType = await _sysDicTypeRepository.GetAsync(dto.DicTypeId, HttpContext.RequestAborted); if (dicType is null) throw UserFriendlyException.SameMessage("无效字典类型"); var dicData = _mapper.Map(dto); dicData.DicTypeCode = dicType.DicTypeCode; dicData.IsShow = true; _systemDicDataCacheManager.RemoveSysDicDataCache(dicType.DicTypeCode); await _sysDicDataRepository.AddAsync(dicData); } /// /// 修改字典数据 /// /// /// [HttpPost("update-dicdata")] [LogFilter("修改字典数据")] public async Task UpdateDicData([FromBody] UpdateDicDataDto dto) { var dicData = await _sysDicDataRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (dicData is null) throw UserFriendlyException.SameMessage("无效字典数据"); var dicType = await _sysDicTypeRepository.GetAsync(dto.DicTypeId, HttpContext.RequestAborted); if (dicType is null) throw UserFriendlyException.SameMessage("无效字典类型"); _mapper.Map(dto, dicData); dicData.DicTypeCode = dicType.DicTypeCode; _systemDicDataCacheManager.RemoveSysDicDataCache(dicType.DicTypeCode); await _sysDicDataRepository.UpdateAsync(dicData, HttpContext.RequestAborted); } /// /// 删除字典数据 /// /// /// [HttpDelete("delete-dicdata/{id}")] [LogFilter("删除字典")] public async Task DeleteDicData(string id) { var dicData = await _sysDicDataRepository.GetAsync(id, HttpContext.RequestAborted); if (dicData is null) throw UserFriendlyException.SameMessage("无效字典数据"); var chail = await _sysDicDataRepository.AnyAsync(p => p.ParentId == id, HttpContext.RequestAborted); if (chail == true) throw UserFriendlyException.SameMessage("存在下级数据,请先删除下级数据!"); var dicType = await _sysDicTypeRepository.GetAsync(dicData.DicTypeId, HttpContext.RequestAborted); if (dicType != null) _systemDicDataCacheManager.RemoveSysDicDataCache(dicType.DicTypeCode); await _sysDicDataRepository.RemoveAsync(dicData, true, HttpContext.RequestAborted); } #endregion #region 行政区划 /// /// 获取省市区树形 /// /// [HttpGet("area/tree")] public async Task> GetAreaTree() { return await _systemAreaDomainService.GetAreaTree(_appOptions.Value.IsZiGong ? 6 : 0); } /// /// 获取省市区树形 来电弹单界面获取 /// /// [HttpGet("area/tree_accepted")] public async Task> GetAreaTree_Accepted() { return await _systemAreaDomainService.GetAreaTree(_appOptions.Value.IsZiGong ? 6 : 0, _appOptions.Value.IsLuZhou ? "510500" : "510000"); } /// /// 获取省市区树形 /// /// [HttpPost("area/tree/export")] [LogFilterAlpha("导出日志")] public async Task GetAreaTreeExport([FromBody] ExportExcelDto dto) { var items = await _systemAreaDomainService.GetAreaTree(_appOptions.Value.IsZiGong ? 6 : 0); return _exportApplication.GetExcelFile(dto, items, "行政区域"); } /// /// 新增省市区 /// /// /// [HttpPost("area")] public async Task AddArea([FromBody] AddAreaDto dto) { var model = _mapper.Map(dto); if (string.IsNullOrEmpty(model.ParentId) || model.ParentId.Length > 8) { throw UserFriendlyException.SameMessage("只允许添加乡镇、街道数据,请选择区县"); } if (model.ParentId.Substring(4, 2) == "00") { throw UserFriendlyException.SameMessage("只允许添加乡镇、街道数据,请选择区县"); } //验证重复 var area = await _systemAreaRepository.Queryable(includeDeleted: true).FirstAsync(x => x.ParentId == dto.ParentId && x.AreaName == dto.AreaName); if (area != null) { if (area.IsDeleted) { area.IsDeleted = false; await _systemAreaRepository.UpdateAsync(area, HttpContext.RequestAborted); throw UserFriendlyException.SameMessage("同目录下已存在被删除的相同数据,已重新启用"); } else { throw UserFriendlyException.SameMessage("同目录下已存在相同数据,不能重复添加"); } } //生成新Code model.Id = await _systemAreaDomainService.GenerateNewAreaCodeAsync(dto.ParentId, HttpContext.RequestAborted); model.IsCanModify = true; await _systemAreaDomainService.AddArea(model, HttpContext.RequestAborted); } /// /// 修改省市区 /// /// /// [HttpPut("area")] public async Task ModifyArea([FromBody] ModifyAreaDto dto) { var model = await _systemAreaDomainService.GetArea(dto.Id, HttpContext.RequestAborted); if (model is null) throw UserFriendlyException.SameMessage("未知数据,请刷新页面"); if (!model.IsCanModify) throw UserFriendlyException.SameMessage("系统数据,不能修改"); _mapper.Map(dto, model); //_mapper.Map(dto); //验证重复 var area = await _systemAreaRepository.Queryable(includeDeleted: true).Where(x => x.ParentId == dto.ParentId && x.AreaName == dto.AreaName).ToListAsync(); if (area.Count > 1) { throw UserFriendlyException.SameMessage("同目录下已存在相同数据,不能修改"); } await _systemAreaDomainService.ModifyArea(model, HttpContext.RequestAborted); } /// /// 删除省市区(逻辑) /// /// /// [HttpDelete("area/{id}")] public async Task DelArea(string id) { var model = await _systemAreaDomainService.GetArea(id, HttpContext.RequestAborted); if (model is null) throw UserFriendlyException.SameMessage("未知数据,请刷新页面"); if (!model.IsCanModify) throw UserFriendlyException.SameMessage("系统数据不能删除"); await _systemAreaDomainService.DelArea(id, HttpContext.RequestAborted); } /// /// 获取区域 /// /// /// [HttpGet("area/{id}")] public async Task GetArea(string id) { var model = await _systemAreaDomainService.GetArea(id, HttpContext.RequestAborted); if (model is null) throw UserFriendlyException.SameMessage("未知数据,请刷新页面"); return model; } #endregion #region 常用意见 #region 个人 /// /// 获取常用意见 /// /// [HttpGet("common-list")] public async Task> GetCommon([FromQuery] ECommonType commonType, bool isOpen) { return await _commonOpinionRepository.Queryable().Where(x => x.CommonType == commonType) .WhereIF(isOpen == true, x => (x.IsOpen == true || (x.CreatorOrgId == _sessionContext.RequiredOrgId && x.AttributionType == ECommonAttributionType.Org && x.IsOpen == false))) .WhereIF(isOpen == false, x => x.IsOpen == false && x.CreatorId == _sessionContext.RequiredUserId).ToListAsync(); } /// /// 新增常用意见 /// /// /// [HttpPost("add-common")] public async Task AddCommon([FromBody] AddCommonDto dto) { var entity = _mapper.Map(dto); await _commonOpinionDomainService.AddCommonOpinion(entity, HttpContext.RequestAborted); } /// /// 批量删除常用意见 /// /// /// [HttpPost("del-common")] public async Task DelCommon([FromBody] DelCommonDto dto) { await _commonOpinionDomainService.DelCommonOpinion(dto.Ids, HttpContext.RequestAborted); } /// /// 常用意见页面基础信息 /// /// [HttpGet("common-basepage")] public async Task CommonBasePage() { var rsp = new { CommonType = EnumExts.GetDescriptions(), }; return rsp; } #endregion #region 公开 /// /// 查询公开常用意见 /// /// [HttpGet("open-common")] public async Task> QueryOpenCommonOpinionList([FromQuery] QueryCommonDto dto) { var (total, items) = await _commonOpinionRepository.Queryable() .WhereIF(dto.IsOpen != null, x => x.IsOpen == dto.IsOpen) .WhereIF(!string.IsNullOrEmpty(dto.UserName), x => x.CreatorName.Contains(dto.UserName)) .WhereIF(dto.CommonType != null, x => x.CommonType == dto.CommonType) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, items); } /// export /// 查询公开常用意见导出 /// /// /// [HttpPost("open-common/export")] [LogFilterAlpha("导出日志")] public async Task QueryOpenCommonOpinionExport([FromBody] ExportExcelDto dto) { var query = _commonOpinionRepository.Queryable() .WhereIF(dto.QueryDto.IsOpen != null, x => x.IsOpen == dto.QueryDto.IsOpen) .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.UserName), x => x.CreatorName.Contains(dto.QueryDto.UserName)) .WhereIF(dto.QueryDto.CommonType != null, x => x.CommonType == dto.QueryDto.CommonType); var total = 0; var items = new List(); if (dto.IsExportAll) { items = await query.ToListAsync(HttpContext.RequestAborted); } else { (total, items) = await query.ToPagedListAsync(dto.QueryDto.PageIndex, dto.QueryDto.PageSize, HttpContext.RequestAborted); } dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = _mapper.Map>(items) .Select(stu => _mapper.Map(stu, typeof(SystemCommonOpinionDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "常用意见管理"); } /// /// 修改公开常用意见 /// /// /// [HttpPost("common-modify")] public async Task CommonModify([FromBody] CommonModifyDto dto) { var model = await _commonOpinionRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (model is null) throw UserFriendlyException.SameMessage("无效数据"); _mapper.Map(dto, model); await _commonOpinionRepository.UpdateAsync(model, HttpContext.RequestAborted); } #endregion #endregion #region 日志 /// /// 获取日志列表 /// /// /// [HttpGet("log_list")] public async Task> GetSystemLotItems([FromQuery] SysLogPagedKeywordRequest dto) { return (await _systemLogApplication.GetSystemLotItems(dto).ToPagedListAsync(dto)).ToPaged(); } /// /// 获取日志实体 /// /// /// [HttpGet("log/{id}")] public async Task ItemEntity(string id) { var log = await _systemLogRepository.Queryable() .FirstAsync(x => x.Id == id); return _mapper.Map(log); } [HttpPost("log")] public async Task LogAdd([FromBody] SystemLogDto dto) { var log = _mapper.Map(dto); return await _systemLogRepository.AddAsync(log, HttpContext.RequestAborted); } #endregion /// /// 验证电话外呼是否需要加0 /// /// /// [HttpGet("vaild_mobile/{mobile}")] public async Task VaildMobile(string mobile) { return await _systemMobilAreaApplication.VaildMobile(mobile); } /// /// 删除缓存 /// /// /// [HttpPut("cache/remove")] public async Task ClearCache([FromBody] CleanCacheInDto dto) { foreach (var key in dto.Keys) { await _hybridCaching.RemoveAsync(key, HttpContext.RequestAborted); } return Ok(); } /// /// 获取所有缓存的Key /// /// 不传默认: Hotline:* /// [HttpGet("cache")] public async Task> GetCache(string cacheKey = "Hotline:*") { return await _redisCaching.SearchKeysAsync(cacheKey); } /// /// 获取缓存 /// /// /// [HttpGet("cache/{key}")] public async Task> GetCacheByKey(string key) { var cacheResult = new List(); var result = await _easyCaching.GetAsync(key, cancellationToken: HttpContext.RequestAborted); if (result != null) { cacheResult.Add(result.ToJson()); } var stringResult = await _redisCaching.StringGetAsync(key); if (stringResult != null) { cacheResult.Add(stringResult); } return cacheResult; } } }