ArticleController.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. using Hotline.Application.FlowEngine;
  2. using Hotline.Article;
  3. using Hotline.Caching.Interfaces;
  4. using Hotline.FlowEngine.WorkflowModules;
  5. using Hotline.Permissions;
  6. using Hotline.Repository.SqlSugar.Extensions;
  7. using Hotline.Settings;
  8. using Hotline.Share.Dtos;
  9. using Hotline.Share.Dtos.Article;
  10. using Hotline.Share.Dtos.FlowEngine;
  11. using Hotline.Share.Dtos.Order;
  12. using Hotline.Share.Dtos.Users;
  13. using Hotline.Share.Enums.Article;
  14. using Hotline.Share.Requests;
  15. using Hotline.Users;
  16. using MapsterMapper;
  17. using Microsoft.AspNetCore.Mvc;
  18. using Microsoft.OpenApi.Writers;
  19. using MongoDB.Driver.Linq;
  20. using SqlSugar;
  21. using XF.Domain.Authentications;
  22. using XF.Domain.Exceptions;
  23. using XF.Domain.Repository;
  24. using XF.Utility.EnumExtensions;
  25. namespace Hotline.Api.Controllers
  26. {
  27. public class ArticleController : BaseController
  28. {
  29. private readonly IRepository<Bulletin> _bulletinRepository;
  30. private readonly IMapper _mapper;
  31. private readonly ISystemOrganizeRepository _organizeRepository;
  32. private readonly IWorkflowApplication _workflowApplication;
  33. private readonly IRepository<Circular> _circularRepository;
  34. private readonly ISessionContext _sessionContext;
  35. private readonly IRepository<CircularRecord> _circularRecordRepository;
  36. private readonly IRepository<CircularReadGroup> _circularReadGroupRepository;
  37. private readonly IRepository<User> _userRepository;
  38. private readonly ICircularRecordDomainService _circularRecordDomainService;
  39. private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
  40. public ArticleController(IRepository<Bulletin> bulletinRepository, IMapper mapper, ISystemDomainService systemDomainService, ISystemOrganizeRepository organizeRepository, IWorkflowApplication workflowApplication, IRepository<Circular> circularRepository, ISessionContext sessionContext, IRepository<CircularRecord> circularRecordRepository, IRepository<CircularReadGroup> circularReadGroupRepository, IRepository<User> userRepository, ICircularRecordDomainService circularRecordDomainService, ISystemDicDataCacheManager systemDicDataCacheManager)
  41. {
  42. _bulletinRepository = bulletinRepository;
  43. _mapper = mapper;
  44. _organizeRepository = organizeRepository;
  45. _workflowApplication = workflowApplication;
  46. _circularRepository = circularRepository;
  47. _sessionContext = sessionContext;
  48. _circularRecordRepository = circularRecordRepository;
  49. _circularReadGroupRepository = circularReadGroupRepository;
  50. _userRepository = userRepository;
  51. _circularRecordDomainService = circularRecordDomainService;
  52. _systemDicDataCacheManager = systemDicDataCacheManager;
  53. }
  54. #region 通知
  55. /// <summary>
  56. /// 获取所有用户不分页
  57. /// </summary>
  58. /// <returns></returns>
  59. [HttpGet("alluser")]
  60. public async Task<List<UserDto>> GetAllUser()
  61. {
  62. var list = await _userRepository.Queryable(includeDeleted: false)
  63. .Includes(d => d.Account)
  64. .Includes(d => d.Organization)
  65. .OrderByDescending(x => x.CreationTime)
  66. .ToListAsync();
  67. return new List<UserDto>(_mapper.Map<IReadOnlyList<UserDto>>(list));
  68. }
  69. /// <summary>
  70. /// 我的通知列表
  71. /// </summary>
  72. /// <param name="dto"></param>
  73. /// <returns></returns>
  74. [HttpGet("circular/muquery")]
  75. public async Task<PagedDto<CircularDto>> GetMyCircularList([FromQuery] QueryCircularListRequestDto dto)
  76. {
  77. var (total, items) = await _circularRepository.Queryable()
  78. .Includes(x => x.CircularReadGroups)
  79. .WhereIF(!string.IsNullOrEmpty(dto.CircularTypeId), d => d.CircularTypeId == dto.CircularTypeId)
  80. .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title))
  81. .WhereIF(dto.CircularTimeStart.HasValue, d => d.CircularTime >= dto.CircularTimeStart)
  82. .WhereIF(dto.CircularTimeEnd.HasValue, d => d.CircularTime <= dto.CircularTimeEnd)
  83. .WhereIF(dto.CircularState != null, d => d.CircularState == dto.CircularState)
  84. //.WhereIF(dto.IsRead!=null,d=>d.CircularReadGroups.Any(x=>x.IsRead == dto.IsRead) && (d.CircularReadGroups.Any(x => x.UserId == _sessionContext.RequiredUserId) || d.CircularReadGroups.Any(x => x.OrgId == _sessionContext.RequiredOrgId)))
  85. .WhereIF(dto.IsRead != null, d => (d.CircularReadGroups.Any(x => x.IsRead == dto.IsRead && x.UserId == _sessionContext.UserId)) ||
  86. (d.CircularReadGroups.Any(x => x.IsRead == dto.IsRead && x.OrgId == _sessionContext.OrgId)))
  87. //.Where(d=>d.CircularReadGroups.Any(x=> x.UserId == _sessionContext.RequiredUserId) || d.CircularReadGroups.Any(x=>x.OrgId == _sessionContext.RequiredOrgId))
  88. .OrderByDescending(d => d.CreationTime)
  89. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  90. return new PagedDto<CircularDto>(total, _mapper.Map<IReadOnlyList<CircularDto>>(items));
  91. }
  92. /// <summary>
  93. /// 查询通知列表
  94. /// </summary>
  95. /// <param name="dto"></param>
  96. /// <returns></returns>
  97. [Permission(EPermission.QueryCircularList)]
  98. [HttpGet("circular/query")]
  99. public async Task<PagedDto<CircularDto>> QueryCircularList([FromQuery] QueryCircularListRequestDto dto)
  100. {
  101. var (total, items) = await _circularRepository.Queryable()
  102. .Includes(x => x.CircularReadGroups)
  103. .WhereIF(!string.IsNullOrEmpty(dto.CircularTypeId), d => d.CircularTypeId == dto.CircularTypeId)
  104. .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title))
  105. .WhereIF(dto.CircularTimeStart.HasValue, d => d.CircularTime >= dto.CircularTimeStart)
  106. .WhereIF(dto.CircularTimeEnd.HasValue, d => d.CircularTime <= dto.CircularTimeEnd)
  107. .WhereIF(dto.CircularState != null, d => d.CircularState == dto.CircularState)
  108. .OrderByDescending(d => d.CreationTime)
  109. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  110. return new PagedDto<CircularDto>(total, _mapper.Map<IReadOnlyList<CircularDto>>(items));
  111. }
  112. /// <summary>
  113. /// 通知详情(内部)
  114. /// </summary>
  115. /// <param name="id"></param>
  116. /// <returns></returns>
  117. [Permission(EPermission.CircularEntity)]
  118. [HttpGet("circular/entity/{id}")]
  119. public async Task<CircularDto> CircularEntity(string id)
  120. {
  121. var model = await _circularRepository.Queryable()
  122. .Includes(x => x.CircularReadGroups)
  123. .FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
  124. return _mapper.Map<CircularDto>(model);
  125. }
  126. /// <summary>
  127. /// 新增通知
  128. /// </summary>
  129. /// <param name="dto"></param>
  130. /// <returns></returns>
  131. [Permission(EPermission.AddCircular)]
  132. [HttpPost("circular/add")]
  133. public async Task AddCircular([FromBody] CircularFlowDto dto)
  134. {
  135. var model = _mapper.Map<Circular>(dto.Data);
  136. model.CircularState = ECircularState.InReview;
  137. model.ReadedNum = 0;
  138. model.NeedReadNum = model.CircularReadGroups.Count;
  139. var id = await _circularRepository.AddAsync(model, HttpContext.RequestAborted);
  140. //子表
  141. var list = dto.Data.CircularReadGroups;
  142. var readGroupList = new List<CircularReadGroup>();
  143. foreach (var item in list)
  144. {
  145. var readGroup = _mapper.Map<CircularReadGroup>(item);
  146. readGroup.CircularId = id;
  147. readGroup.IsRead = false;
  148. readGroupList.Add(readGroup);
  149. }
  150. await _circularReadGroupRepository.AddRangeAsync(readGroupList);
  151. try
  152. {
  153. var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
  154. startDto.DefinitionModuleCode = WorkflowModuleConsts.CircularApply;
  155. startDto.Title = model.Title;
  156. var workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, id, cancellationToken: HttpContext.RequestAborted);
  157. model.WorkflowId = workFlowId;
  158. await _circularRepository.UpdateAsync(model, HttpContext.RequestAborted);
  159. }
  160. catch (Exception ex)
  161. {
  162. await _circularRepository.RemoveAsync(id, false, HttpContext.RequestAborted);
  163. throw new UserFriendlyException($"新增通知流程失败!,{ex.Message}", "新增通知流程失败");
  164. }
  165. }
  166. /// <summary>
  167. /// 列表页面基础信息
  168. /// </summary>
  169. /// <returns></returns>
  170. [HttpGet("circular/listbasedata")]
  171. public async Task<object> CircularBaseData()
  172. {
  173. var rsp = new
  174. {
  175. CircularType = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.CircularType)
  176. };
  177. return rsp;
  178. }
  179. /// <summary>
  180. /// 新增页面基础数据
  181. /// </summary>
  182. /// <returns></returns>
  183. [HttpGet("circular/addbasedata")]
  184. public async Task<object> CircularAddBaseData()
  185. {
  186. var rsp = new
  187. {
  188. CircularType = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.CircularType),
  189. OrgsOptions = await _organizeRepository.GetOrgJson(),
  190. CircularTypeEnum = EnumExts.GetDescriptions<ECircularType>()
  191. };
  192. return rsp;
  193. }
  194. /// <summary>
  195. /// 通知阅读(内部)
  196. /// </summary>
  197. /// <param name="id"></param>
  198. /// <returns></returns>
  199. [HttpGet("circular/read/{id}")]
  200. public async Task<CircularDto> CircularRead(string id)
  201. {
  202. var model = await _circularRepository.Queryable()
  203. .Includes(x => x.CircularReadGroups)
  204. .FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
  205. //更新阅读信息
  206. if (model.CircularType == ECircularType.Person)
  207. {
  208. //个人阅读
  209. var readGroup = model.CircularReadGroups.FirstOrDefault(x => x.UserId == _sessionContext.RequiredUserId && !x.IsRead);
  210. if (readGroup != null)
  211. {
  212. readGroup.IsRead = true;
  213. readGroup.ReadTime = DateTime.Now;
  214. if (DateTime.Now > model.LostEfficacyTime)
  215. readGroup.IsTimeOut = true;
  216. else
  217. readGroup.IsTimeOut = false;
  218. await _circularReadGroupRepository.UpdateAsync(readGroup, HttpContext.RequestAborted);
  219. model.ReadedNum++;
  220. await _circularRepository.UpdateAsync(model, HttpContext.RequestAborted);
  221. //处理计数
  222. await _circularRecordDomainService.RecordUserHandle(new List<string> { _sessionContext.RequiredUserId }, false, cancellationToken: HttpContext.RequestAborted);
  223. }
  224. }
  225. else
  226. {
  227. //部门阅读
  228. var readGroup = model.CircularReadGroups.FirstOrDefault(x => x.OrgId == _sessionContext.RequiredOrgId && !x.IsRead);
  229. if (readGroup != null)
  230. {
  231. readGroup.IsRead = true;
  232. readGroup.ReadTime = DateTime.Now;
  233. if (DateTime.Now > model.LostEfficacyTime)
  234. readGroup.IsTimeOut = true;
  235. else
  236. readGroup.IsTimeOut = false;
  237. await _circularReadGroupRepository.UpdateAsync(readGroup, HttpContext.RequestAborted);
  238. model.ReadedNum++;
  239. await _circularRepository.UpdateAsync(model, HttpContext.RequestAborted);
  240. //处理部门计数
  241. await _circularRecordDomainService.RecordOrgHandle(new List<string> { _sessionContext.RequiredOrgId }, false, cancellationToken: HttpContext.RequestAborted);
  242. }
  243. }
  244. return _mapper.Map<CircularDto>(model);
  245. }
  246. /// <summary>
  247. /// 获取小红点计数
  248. /// </summary>
  249. /// <returns></returns>
  250. [HttpGet("megcount")]
  251. public async Task<CircularRecordDto> QueryMegCount()
  252. {
  253. var list = await _circularRecordRepository.Queryable().Where(x => x.UserId == _sessionContext.UserId || x.OrgId == _sessionContext.OrgId).ToListAsync();
  254. if (list != null && list.Count > 0)
  255. {
  256. var rsp = new CircularRecordDto();
  257. rsp.OrgCount = list.FirstOrDefault(x => x.CircularType == ECircularType.Org)?.RecordCount ?? 0;
  258. rsp.PersonCount = list.FirstOrDefault(x => x.CircularType == ECircularType.Person)?.RecordCount ?? 0;
  259. return rsp;
  260. }
  261. return new CircularRecordDto() { OrgCount = 0, PersonCount = 0 };
  262. }
  263. /// <summary>
  264. /// 查询通知流程开启参数
  265. /// </summary>
  266. /// <returns></returns>
  267. [HttpGet("circular/startflow")]
  268. public async Task<NextStepsDto> GetCircularFlowStartOptions()
  269. {
  270. return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.CircularApply, HttpContext.RequestAborted);
  271. }
  272. #endregion
  273. #region 公告
  274. /// <summary>
  275. /// 查询公告列表
  276. /// </summary>
  277. /// <param name="dto"></param>
  278. /// <returns></returns>
  279. [Permission(EPermission.QueryBulletinList)]
  280. [HttpGet("bulletin/query")]
  281. public async Task<PagedDto<BulletinDto>> QueryBulletinList([FromQuery] QueryBulletinListRequestDto dto)
  282. {
  283. var (total, items) = await _bulletinRepository.Queryable()
  284. .WhereIF(!string.IsNullOrEmpty(dto.BulletinTypeId), d => d.BulletinTypeId == dto.BulletinTypeId)
  285. .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title))
  286. .WhereIF(dto.BulletinTimeStart.HasValue, d => d.BulletinTime >= dto.BulletinTimeStart)
  287. .WhereIF(dto.BulletinTimeEnd.HasValue, d => d.BulletinTime <= dto.BulletinTimeEnd)
  288. .WhereIF(dto.BulletinState != null, d => d.BulletinState == dto.BulletinState)
  289. .OrderByDescending(d => d.CreationTime)
  290. .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
  291. return new PagedDto<BulletinDto>(total, _mapper.Map<IReadOnlyList<BulletinDto>>(items));
  292. }
  293. /// <summary>
  294. /// 公告详情(内部)
  295. /// </summary>
  296. /// <param name="id"></param>
  297. /// <returns></returns>
  298. [Permission(EPermission.BulletinEntity)]
  299. [HttpGet("bulletin/entity/{id}")]
  300. public async Task<BulletinDto> BulletinEntity(string id)
  301. {
  302. var model = await _bulletinRepository.Queryable()
  303. .FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
  304. return _mapper.Map<BulletinDto>(model);
  305. }
  306. /// <summary>
  307. /// 新增公告
  308. /// </summary>
  309. /// <param name="dto"></param>
  310. /// <returns></returns>
  311. [Permission(EPermission.AddBulletin)]
  312. [HttpPost("bulletin/add")]
  313. public async Task AddBulletin([FromBody] BulletinFlowDto dto)
  314. {
  315. var model = _mapper.Map<Bulletin>(dto.Data);
  316. model.BulletinState = Share.Enums.Article.EBulletinState.InReview;
  317. model.ReadedNum = 0;
  318. var id = await _bulletinRepository.AddAsync(model, HttpContext.RequestAborted);
  319. try
  320. {
  321. var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
  322. startDto.DefinitionModuleCode = WorkflowModuleConsts.BulletinApply;
  323. startDto.Title = model.Title;
  324. string workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, id, cancellationToken: HttpContext.RequestAborted);
  325. model.WorkflowId = workFlowId;
  326. await _bulletinRepository.UpdateAsync(model, HttpContext.RequestAborted);
  327. }
  328. catch (Exception ex)
  329. {
  330. await _bulletinRepository.RemoveAsync(id, false, HttpContext.RequestAborted);
  331. throw new UserFriendlyException($"新增公告流程失败!,{ex.Message}", "新增公告流程失败");
  332. }
  333. }
  334. /// <summary>
  335. /// 列表页面基础数据
  336. /// </summary>
  337. /// <returns></returns>
  338. [HttpGet("bulletin/listbasedata")]
  339. public async Task<object> BulletinListBaseData()
  340. {
  341. var rsp = new
  342. {
  343. BulletinType = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.BulletinType)
  344. };
  345. return rsp;
  346. }
  347. /// <summary>
  348. /// 新增页面基础数据
  349. /// </summary>
  350. /// <returns></returns>
  351. [HttpGet("bulletin/addbasedata")]
  352. public async Task<object> BulletinAddBaseData()
  353. {
  354. var rsp = new
  355. {
  356. BulletinType = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.BulletinType),
  357. PushRanges = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.BulletinPushRange),
  358. OrgsOptions = await _organizeRepository.GetOrgJson(),
  359. };
  360. return rsp;
  361. }
  362. /// <summary>
  363. /// 查询公告流程开启参数
  364. /// </summary>
  365. /// <returns></returns>
  366. [HttpGet("bulletin/startflow")]
  367. public async Task<NextStepsDto> GetBulletinFlowStartOptions()
  368. {
  369. return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.BulletinApply, HttpContext.RequestAborted);
  370. }
  371. #endregion
  372. }
  373. }