PlanController.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. using MapsterMapper;
  2. using Microsoft.AspNetCore.Mvc;
  3. using XF.Domain.Authentications;
  4. using XF.Domain.Repository;
  5. using Hotline.Application.Planlibrary;
  6. using Hotline.Share.Dtos.Planlibrary;
  7. using SqlSugar;
  8. using Hotline.Planlibrary;
  9. using XF.Domain.Exceptions;
  10. using Hotline.Share.Dtos;
  11. using Hotline.Share.Tools;
  12. using Hotline.Share.Enums.Planlibrary;
  13. using Hotline.Application.ExportWord;
  14. using Hotline.Application.Tools;
  15. using Hotline.KnowledgeBase;
  16. using Hotline.Share.Dtos.Knowledge;
  17. using System.Data;
  18. namespace Hotline.Api.Controllers
  19. {
  20. /// <summary>
  21. /// 预案库
  22. /// </summary>
  23. public class PlanController : BaseController
  24. {
  25. #region 注入
  26. private readonly IMapper _mapper;
  27. private readonly ISessionContext _sessionContext;
  28. private readonly IPlanApplication _planApplication;
  29. private readonly IRepository<PlanType> _planTypeRepository;
  30. private readonly IRepository<PlanList> _planListRepository;
  31. private readonly IRepository<PlanCollect> _planCollectRepository;
  32. private readonly IWordHelperService _wordHelperService;
  33. public PlanController(
  34. IMapper mapper,
  35. ISessionContext sessionContext,
  36. IPlanApplication planApplication,
  37. IRepository<PlanType> planTypeRepository,
  38. IRepository<PlanList> planListRepository,
  39. IRepository<PlanCollect> planCollectRepository,
  40. IWordHelperService wordHelperService)
  41. {
  42. _mapper = mapper;
  43. _sessionContext = sessionContext;
  44. _planApplication = planApplication;
  45. _planTypeRepository = planTypeRepository;
  46. _planListRepository = planListRepository;
  47. _planCollectRepository = planCollectRepository;
  48. _wordHelperService = wordHelperService;
  49. }
  50. #endregion
  51. #region 预案库类型管理
  52. /// <summary>
  53. /// 获取列表层级分类
  54. /// </summary>
  55. /// <param name="IsEnable">是否启用</param>
  56. /// <returns></returns>
  57. [HttpGet("type/treelist")]
  58. public async Task<List<PlanTypeDto>> QueryAllTreeList(bool? IsEnable)
  59. {
  60. return await _planTypeRepository.Queryable()
  61. .WhereIF(IsEnable.HasValue, x => x.IsEnable == IsEnable)
  62. .Where(x => SqlFunc.Subqueryable<PlanTypeOrg>().Where(to => to.TypeId == x.Id).Any() ||
  63. SqlFunc.Subqueryable<PlanTypeOrg>().Where(to => to.TypeId == x.Id).NotAny()
  64. )
  65. .Select(x => new PlanTypeDto()
  66. {
  67. Id = x.Id.SelectAll()
  68. }
  69. )
  70. .OrderBy(x => x.Sort).ToTreeAsync(it => it.children, it => it.ParentId, null, it => it.Id);
  71. }
  72. /// <summary>
  73. /// 新增
  74. /// </summary>
  75. /// <param name="dto"></param>
  76. /// <returns></returns>
  77. [HttpPost("type/add")]
  78. public async Task<string> AddType([FromBody] AddPlanTypeDto dto)
  79. {
  80. return await _planApplication.AddTypeAsync(dto, HttpContext.RequestAborted);
  81. }
  82. /// <summary>
  83. /// 编辑
  84. /// </summary>
  85. /// <param name="dto"></param>
  86. /// <returns></returns>
  87. [HttpPut("type/update")]
  88. public async Task UpdateType([FromBody] UpdatePlanTypeDto dto)
  89. {
  90. await _planApplication.UpdateTypeAsync(dto, HttpContext.RequestAborted);
  91. }
  92. /// <summary>
  93. /// 查询详情
  94. /// </summary>
  95. /// <param name="Id"></param>
  96. /// <returns></returns>
  97. [HttpGet("type/info/{Id}")]
  98. public async Task<PlanType> GetType(string Id)
  99. {
  100. var types = await _planTypeRepository.Queryable()
  101. .Includes(x => x.PlanTypeOrgs) // 填充子对象
  102. .Where(x => x.Id == Id)
  103. .FirstAsync(HttpContext.RequestAborted);
  104. if (types is null)
  105. throw UserFriendlyException.SameMessage("查询失败!");
  106. return types;
  107. }
  108. /// <summary>
  109. /// 删除
  110. /// </summary>
  111. /// <param name="Id"></param>
  112. /// <returns></returns>
  113. [HttpDelete("type/remove/{Id}")]
  114. public async Task RemoveType(string Id)
  115. {
  116. await _planApplication.RemoveTypeAsync(Id, HttpContext.RequestAborted);
  117. }
  118. #endregion
  119. #region 预案库管理
  120. /// <summary>
  121. /// 预案库分类列表
  122. /// </summary>
  123. /// <param name="IsEnable"></param>
  124. /// <returns></returns>
  125. [HttpGet("list/treelist")]
  126. public async Task<List<PlanTypeDto>> QueryAllPlanTypeTreeList(bool? IsEnable)
  127. {
  128. return await _planTypeRepository.Queryable()
  129. .WhereIF(IsEnable.HasValue, x => x.IsEnable == IsEnable)
  130. .Where(x => SqlFunc.Subqueryable<PlanTypeOrg>().Where(to => to.TypeId == x.Id).Any() ||
  131. SqlFunc.Subqueryable<PlanTypeOrg>().Where(to => to.TypeId == x.Id).NotAny()
  132. )
  133. .Select(x => new PlanTypeDto()
  134. {
  135. Id = x.Id.SelectAll(),
  136. PlanNum = SqlFunc.Subqueryable<PlanRelationType>().LeftJoin<PlanList>((kr, k) => kr.PlanId == k.Id)
  137. .Where((kr, k) => kr.PlanTypeSpliceName.StartsWith(x.SpliceName))
  138. .DistinctCount(kr => kr.PlanId)
  139. }
  140. )
  141. .OrderBy(x => x.Sort).ToTreeAsync(it => it.children, it => it.ParentId, null, it => it.Id);
  142. }
  143. /// <summary>
  144. /// 预案库列表
  145. /// </summary>
  146. /// <param name="pagedDto"></param>
  147. /// <returns></returns>
  148. [HttpGet("list")]
  149. public async Task<PagedDto<PlanDataDto>> QueryAllPlanList([FromQuery] PlanListDto pagedDto)
  150. {
  151. return (await _planApplication.QueryAllPlanListAsync(pagedDto, HttpContext.RequestAborted)).ToPaged();
  152. }
  153. /// <summary>
  154. /// 预案库草稿
  155. /// </summary>
  156. /// <param name="dto"></param>
  157. /// <returns></returns>
  158. [HttpPost("list/draft")]
  159. public async Task<string> PlanDraft([FromBody] AddPlanListDto dto)
  160. {
  161. dto.Status = EPlanStatus.NewDrafts;
  162. return await _planApplication.AddPlanAsync(dto, HttpContext.RequestAborted);
  163. }
  164. /// <summary>
  165. /// 预案库草稿修改
  166. /// </summary>
  167. /// <param name="dto"></param>
  168. /// <returns></returns>
  169. [HttpPut("list/draftupdate")]
  170. public async Task UpdatePlanDraft([FromBody] UpdatePlanListDto dto)
  171. {
  172. dto.Status = EPlanStatus.NewDrafts;
  173. await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
  174. }
  175. /// <summary>
  176. /// 预案库草稿上架到审核
  177. /// </summary>
  178. /// <param name="dto"></param>
  179. /// <returns></returns>
  180. [HttpPut("list/draftadd")]
  181. public async Task AddPlanDraft([FromBody] UpdatePlanListDto dto)
  182. {
  183. dto.ApplyStatus = EPlanApplyStatus.Add;
  184. dto.Status = EPlanStatus.Auditing;
  185. await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
  186. }
  187. /// <summary>
  188. /// 预案库新增到审核
  189. /// </summary>
  190. /// <param name="dto"></param>
  191. /// <returns></returns>
  192. [HttpPost("list/add")]
  193. public async Task<string> AddPlan([FromBody] AddPlanListDto dto)
  194. {
  195. dto.ApplyStatus = EPlanApplyStatus.Add;
  196. dto.Status = EPlanStatus.Auditing;
  197. return await _planApplication.AddPlanAsync(dto, HttpContext.RequestAborted);
  198. }
  199. /// <summary>
  200. /// 预案库编辑提交到审核
  201. /// </summary>
  202. /// <param name="dto"></param>
  203. /// <returns></returns>
  204. [HttpPut("list/update")]
  205. public async Task UpdatePlan([FromBody] UpdatePlanListDto dto)
  206. {
  207. dto.ApplyStatus = EPlanApplyStatus.Update;
  208. dto.Status = EPlanStatus.Auditing;
  209. await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
  210. }
  211. /// <summary>
  212. /// 预案库下架
  213. /// </summary>
  214. /// <param name="Id">预案库ID</param>
  215. /// <returns></returns>
  216. [HttpGet("list/offshelf/{Id}")]
  217. public async Task OffshelfPlan(string Id)
  218. {
  219. UpdatePlanListDto dto = new UpdatePlanListDto();
  220. dto.Id = Id;
  221. dto.ApplyStatus = EPlanApplyStatus.Offshelf;
  222. dto.Status = EPlanStatus.Auditing;
  223. await _planApplication.AuditPlanAsync(dto, HttpContext.RequestAborted);
  224. }
  225. /// <summary>
  226. /// 预案库审核(新增、修改、下架)
  227. /// </summary>
  228. /// <param name="dto"></param>
  229. /// <returns></returns>
  230. [HttpPut("list/examin")]
  231. public async Task ExaminPlan([FromBody] AuditPlanListDto dto)
  232. {
  233. var plan = await _planListRepository.GetAsync(dto.Id);
  234. if (plan == null)
  235. throw UserFriendlyException.SameMessage("预案库查询失败");
  236. var planDto = _mapper.Map<UpdatePlanListDto>(plan);
  237. if (dto.State == 0)
  238. {//不同意
  239. planDto.Status = EPlanStatus.Revert;
  240. }
  241. else if (dto.State == 1)
  242. {//同意
  243. if (planDto.ApplyStatus == EPlanApplyStatus.Add)
  244. {
  245. planDto.Status = EPlanStatus.OnShelf;
  246. }
  247. if (planDto.ApplyStatus == EPlanApplyStatus.Update)
  248. {
  249. planDto.Status = EPlanStatus.OnShelf;
  250. planDto.UpdateTime = DateTime.Now;
  251. }
  252. if (planDto.ApplyStatus == EPlanApplyStatus.Offshelf)
  253. {
  254. planDto.Status = EPlanStatus.OffShelf;
  255. }
  256. }
  257. planDto.Id = dto.Id;
  258. planDto.ExaminTime = DateTime.Now;
  259. planDto.ExaminManId = _sessionContext.UserId;
  260. planDto.ExaminOrganizeId = _sessionContext.OrgId;
  261. await _planApplication.AuditPlanAsync(planDto, HttpContext.RequestAborted);
  262. }
  263. /// <summary>
  264. /// 预案库详情
  265. /// </summary>
  266. /// <param name="dto"></param>
  267. /// <returns></returns>
  268. [HttpGet("list/info")]
  269. public async Task<PlanInfoDto> GetPlan([FromBody] PvPlanListDto dto)
  270. {
  271. return await _planApplication.GetPlanAsync(dto.Id, dto.IsAddPv, HttpContext.RequestAborted);
  272. }
  273. /// <summary>
  274. /// 预案库评分
  275. /// </summary>
  276. /// <param name="dto"></param>
  277. /// <returns></returns>
  278. [HttpPut("list/score")]
  279. public async Task ScorePlan([FromBody] PvPlanListDto dto)
  280. {
  281. var collect = await _planCollectRepository.GetAsync(x => x.PlanId == dto.Id && x.CreatorId == _sessionContext.UserId);
  282. if (collect != null)
  283. {
  284. if (collect.Score > 0)
  285. throw UserFriendlyException.SameMessage("当前知识已经评分");
  286. collect.Score = dto.Score;
  287. await _planCollectRepository.UpdateAsync(collect, HttpContext.RequestAborted);
  288. }
  289. else
  290. {
  291. collect = new PlanCollect();
  292. collect.PlanId = dto.Id;
  293. collect.Score = dto.Score;
  294. await _planCollectRepository.AddAsync(collect, HttpContext.RequestAborted);
  295. }
  296. //计算总分
  297. var sugar = _planCollectRepository.Queryable().Where(x => x.PlanId == dto.Id);
  298. var count = await sugar.CountAsync();
  299. var collects = await sugar.SumAsync(x => x.Score);
  300. var scoreTemp = collects / count;
  301. var plan = await _planListRepository.GetAsync(x => x.Id == dto.Id);
  302. if (plan != null)
  303. {
  304. plan.Score = decimal.Round(scoreTemp.Value, 1);
  305. await _planListRepository.UpdateAsync(plan, HttpContext.RequestAborted);
  306. }
  307. }
  308. /// <summary>
  309. /// 预案库查重
  310. /// </summary>
  311. /// <param name="dto"></param>
  312. /// <returns></returns>
  313. [HttpPost("list/exist")]
  314. public async Task<bool> ExistPlan([FromBody] PlanExistDto dto)
  315. {
  316. var any = await _planListRepository.Queryable()
  317. .Where(x => x.Status == EPlanStatus.Auditing || x.Status >= EPlanStatus.OnShelf)
  318. .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Equals(dto.Title))
  319. .WhereIF(!string.IsNullOrEmpty(dto.Content), x => x.Content.Equals(dto.Content))
  320. .WhereIF(!string.IsNullOrEmpty(dto.Id), x => x.Id != dto.Id)
  321. .AnyAsync();
  322. return any;
  323. }
  324. /// <summary>
  325. /// 预案库导出
  326. /// </summary>
  327. /// <param name="dto"></param>
  328. /// <returns></returns>
  329. [HttpPost("list/info/export")]
  330. public async Task<IActionResult> PlanInfoExport([FromBody] PlanInfoExportDto dto)
  331. {
  332. if (dto.Ids.Length > 1)
  333. {
  334. var streams = await _planApplication.PlanInfoListExportAsync(dto, HttpContext.RequestAborted);
  335. byte[] fileBytes = _wordHelperService.ConvertZipStream(streams);
  336. var name = DateTime.Now.ToString("yyyyMMddHHmmss");
  337. return File(fileBytes, "application/octet-stream", $"{name}.zip");
  338. }
  339. var info = await _planListRepository.GetAsync(dto.Ids[0]) ?? throw UserFriendlyException.SameMessage("预案不存在");
  340. return info.Content.HtmlToStream(dto.FileType).GetFileStreamResult(dto.FileType, info.Title, false);
  341. }
  342. #endregion
  343. #region 预案库检索
  344. /// <summary>
  345. /// 预案库列表前10
  346. /// </summary>
  347. /// <returns></returns>
  348. [HttpGet("list/top10")]
  349. public async Task<List<PlanPageViewDto>> QueryTop10PlanList()
  350. {
  351. return await _planListRepository.Queryable()
  352. .Take(10)
  353. .Where(x => x.Status == EPlanStatus.OnShelf)
  354. .Select(x => new PlanPageViewDto
  355. {
  356. Id = x.Id,
  357. Title = x.Title,
  358. PageView = x.PageView
  359. })
  360. .OrderBy(x => x.PageView, OrderByType.Desc)
  361. .ToListAsync();
  362. }
  363. #endregion
  364. }
  365. }