CompanyDailyKpiRepository.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. using AutoMapper;
  2. using OASystem.Domain.Entities.PersonnelModule;
  3. using OASystem.Domain.ViewModels.PersonnelModule;
  4. using OASystem.Infrastructure.Repositories.System;
  5. namespace OASystem.Infrastructure.Repositories.PersonnelModule
  6. {
  7. /// <summary>
  8. /// 公司日常KPI考核仓储
  9. /// </summary>
  10. public class CompanyDailyKpiRepository : BaseRepository<Pm_CompanyDailyKpi, Pm_CompanyDailyKpi>
  11. {
  12. private readonly IMapper _mapper;
  13. private JsonView _jv;
  14. public CompanyDailyKpiRepository(SqlSugarClient sqlSugar,
  15. IMapper mapper,
  16. ApprovalProcessRepository approvalProcessRep)
  17. : base(sqlSugar)
  18. {
  19. _mapper = mapper;
  20. _jv = new JsonView() { Code = StatusCodes.Status400BadRequest, Msg = "操作失败!" };
  21. }
  22. /// <summary>
  23. /// 绩效模板数据(保持原方法签名)
  24. /// </summary>
  25. public async Task<(bool isSuccess, string msg, List<KpiTempTypeInfo> data)> KpiTemplateDataAsync(string depName, string jobName)
  26. {
  27. var result = new List<KpiTempTypeInfo>();
  28. // 获取配置
  29. var config = await _sqlSugar.Queryable<Sys_SetDataType>()
  30. .Where(x => x.IsDel == 0 && x.Id == 132)
  31. .FirstAsync();
  32. if (config?.Remark == null)
  33. return (false, "绩效考核-数据类型ID存储为空", result);
  34. var typeIds = JsonSerializer.Deserialize<List<int>>(config.Remark);
  35. if (typeIds?.Any() != true)
  36. return (false, "绩效考核-数据类型ID存储为空", result);
  37. // 构建查询
  38. var query = _sqlSugar.Queryable<Sys_SetData>()
  39. .LeftJoin<Sys_SetDataType>((sd, sdt) => sd.STid == sdt.Id)
  40. .Where((sd, sdt) => sd.IsDel == 0 && typeIds.Contains(sd.STid));
  41. // 条件过滤
  42. if (!string.IsNullOrWhiteSpace(depName))
  43. query = query.Where((sd, sdt) => sdt.Name.Contains(depName));
  44. if (!string.IsNullOrWhiteSpace(jobName))
  45. query = query.Where((sd, sdt) => sdt.Name.Contains(jobName));
  46. // 查询数据
  47. var data = await query
  48. .Select((sd, sdt) => new
  49. {
  50. KpiTypeId = sd.STid,
  51. KpiTypeName = sdt.Name,
  52. KpiId = sd.Id,
  53. KpiContent = sd.Remark,
  54. KpiSort = sd.Name
  55. })
  56. .ToListAsync();
  57. if (data?.Any() != true)
  58. return (false, "绩效考核模板信息为空", result);
  59. // 分组处理
  60. result = data
  61. .GroupBy(x => new { x.KpiTypeId, x.KpiTypeName })
  62. .Select(g => new KpiTempTypeInfo()
  63. {
  64. TypeId = g.Key.KpiTypeId,
  65. TypeName = g.Key.KpiTypeName,
  66. Contents = g
  67. .OrderBy(x => int.TryParse(x.KpiSort, out int s) ? s : int.MaxValue)
  68. .ThenBy(x => x.KpiSort)
  69. .Select(x => new KpiTempContentInfo(x.KpiId, x.KpiContent, x.KpiSort))
  70. .ToList()
  71. })
  72. .Where(g => g.Contents.Any())
  73. .OrderBy(g => g.TypeId)
  74. .ToList();
  75. return (true, "操作成功", result);
  76. }
  77. /// <summary>
  78. /// 获取部门和岗位
  79. /// </summary>
  80. public async Task<object> KpiDepartmentsAndJobs()
  81. {
  82. var config = await _sqlSugar.Queryable<Sys_SetDataType>()
  83. .Where(x => x.IsDel == 0 && x.Id == 132)
  84. .FirstAsync();
  85. if (config == null) return new { Success = false, Message = "配置为空" };
  86. var typeIds = JsonSerializer.Deserialize<List<int>>(config.Remark ?? "[]");
  87. if (typeIds == null || typeIds.Count < 1)
  88. return new { Success = false, Message = "类型ID为空" };
  89. var names = await _sqlSugar.Queryable<Sys_SetData>()
  90. .LeftJoin<Sys_SetDataType>((sd, sdt) => sd.STid == sdt.Id)
  91. .Where((sd, sdt) => sd.IsDel == 0 && typeIds.Contains(sd.STid))
  92. .Select((sd, sdt) => sdt.Name)
  93. .Distinct()
  94. .ToListAsync();
  95. // 解析部门和岗位
  96. var deptJobList = names
  97. .Select(name =>
  98. {
  99. var clean = name.Split('(')[0].Trim();
  100. string dept, job;
  101. if (clean.Contains(" - "))
  102. {
  103. var parts = clean.Split(" - ");
  104. dept = parts[0].EndsWith("部") ? parts[0] : parts[0] + "部";
  105. job = parts.Length > 1 ? parts[1] : "通用";
  106. }
  107. else if (clean.Contains("-"))
  108. {
  109. var parts = clean.Split('-');
  110. dept = parts[0].EndsWith("部") ? parts[0] : parts[0] + "部";
  111. job = parts.Length > 1 ? parts[1] : "通用";
  112. }
  113. else
  114. {
  115. dept = clean.EndsWith("部") ? clean : "未分类";
  116. job = clean.EndsWith("部") ? "通用" : clean;
  117. }
  118. return new { Department = dept, Job = job };
  119. })
  120. .Where(x => x.Department != "未分类")
  121. .GroupBy(x => x.Department)
  122. .Select(g => new
  123. {
  124. Department = g.Key,
  125. Jobs = g.Select(x => x.Job).Distinct().Where(j => j != "通用").OrderBy(j => j).ToList()
  126. })
  127. .OrderBy(g => g.Department)
  128. .ToList();
  129. return new
  130. {
  131. Success = true,
  132. Departments = deptJobList.Select(g => g.Department).ToList(),
  133. DepartmentsWithJobs = deptJobList
  134. };
  135. }
  136. #region 财务部日常绩效
  137. /// <summary>
  138. /// 基础数据
  139. /// </summary>
  140. /// <returns></returns>
  141. public async Task<JsonView> FinanceInit()
  142. {
  143. var userInfos = await _sqlSugar.Queryable<Sys_Users>()
  144. .LeftJoin<Sys_JobPost>((u, jp) => u.JobPostId == jp.Id)
  145. .LeftJoin<Sys_Department>((u, jp, d) => u.DepId == d.Id)
  146. .LeftJoin<Sys_Company>((u, jp, d, c) => u.CompanyId == c.Id)
  147. .Where((u, jp, d, c) => u.IsDel == 0)
  148. .Select((u, jp, d, c) => new
  149. {
  150. UserId = u.Id,
  151. u.CompanyId,
  152. c.CompanyName,
  153. u.DepId,
  154. d.DepName,
  155. u.JobPostId,
  156. jp.JobName,
  157. UserName = u.CnName
  158. })
  159. .OrderBy(u => u.CompanyId)
  160. .ToListAsync();
  161. if (userInfos?.Any() != true)
  162. {
  163. _jv.Code = StatusCodes.Status200OK;
  164. _jv.Msg = $"暂无人员数据";
  165. return _jv;
  166. }
  167. //转换为层级结构
  168. #region 层级转换 公司 -> 部门 -> 岗位 -> 人员
  169. //var result = userInfos
  170. // .GroupBy(u => new { u.CompanyId, u.CompanyName })
  171. // .Select(companyGroup => new
  172. // {
  173. // CompanyId = companyGroup.Key.CompanyId,
  174. // CompanyName = companyGroup.Key.CompanyName,
  175. // Departments = companyGroup
  176. // .GroupBy(u => new { u.DepId, u.DepName })
  177. // .Select(departmentGroup => new
  178. // {
  179. // DepId = departmentGroup.Key.DepId,
  180. // DepartmentName = departmentGroup.Key.DepName,
  181. // JobPosts = departmentGroup
  182. // .GroupBy(u => new { u.JobPostId, u.JobName })
  183. // .Select(jobGroup => new
  184. // {
  185. // JobPostId = jobGroup.Key.JobPostId,
  186. // JobName = jobGroup.Key.JobName,
  187. // Employees = jobGroup
  188. // .Select(u => new
  189. // {
  190. // Id = u.UserId,
  191. // UserName = u.UserName,
  192. // })
  193. // .OrderBy(e => e.UserName)
  194. // .ToList()
  195. // })
  196. // .OrderBy(j => j.JobName)
  197. // .ToList()
  198. // })
  199. // .OrderBy(d => d.DepartmentName)
  200. // .ToList()
  201. // })
  202. // .OrderBy(c => c.CompanyName)
  203. // .ToList();
  204. #endregion
  205. //转换为层级结构
  206. #region 层级转换 公司 -> 部门 -> 人员
  207. // 构建树形结构
  208. var result = userInfos
  209. .GroupBy(u => new { u.CompanyId, u.CompanyName })
  210. .Select(companyGroup => new
  211. {
  212. CompanyId = companyGroup.Key.CompanyId,
  213. CompanyName = companyGroup.Key.CompanyName,
  214. Departments = companyGroup
  215. .GroupBy(u => new { u.DepId, u.DepName })
  216. .Where(deptGroup => deptGroup.Key.DepId > 0) // 过滤掉无部门的人员
  217. .Select(deptGroup => new
  218. {
  219. DepartmentId = deptGroup.Key.DepId,
  220. DepartmentName = deptGroup.Key.DepName,
  221. Users = deptGroup
  222. .Select(u => new
  223. {
  224. u.UserId,
  225. u.UserName,
  226. u.JobPostId,
  227. u.JobName
  228. })
  229. .OrderBy(u => u.UserName)
  230. .ToList()
  231. })
  232. .Where(dept => dept.Users.Any())
  233. .OrderBy(dept => dept.DepartmentName)
  234. .ToList(),
  235. // 无部门的人员(直接挂载到公司下)
  236. NoDepartmentUsers = companyGroup
  237. .Where(u => u.DepId <= 0)
  238. .Select(u => new
  239. {
  240. u.UserId,
  241. u.UserName,
  242. u.JobPostId,
  243. u.JobName
  244. })
  245. .OrderBy(u => u.UserName)
  246. .ToList()
  247. })
  248. .OrderBy(c => c.CompanyName)
  249. .ToList();
  250. #endregion
  251. _jv.Code = StatusCodes.Status200OK;
  252. _jv.Data = result;
  253. _jv.Msg = $"操作成功";
  254. return _jv;
  255. }
  256. /// <summary>
  257. /// 日常考勤详情
  258. /// </summary>
  259. /// <param name="month">月份 2025-12</param>
  260. /// <param name="userId">考核人</param>
  261. /// <returns></returns>
  262. public async Task<JsonView> FinanceInfo(string month, int evaluator)
  263. {
  264. if (string.IsNullOrEmpty(month))
  265. {
  266. _jv.Msg = $"请选择月份!";
  267. return _jv;
  268. }
  269. // 格式:2025-11
  270. const string pattern = @"^(\d{4})-(0[1-9]|1[0-2])$";
  271. if (!Regex.IsMatch(month, pattern))
  272. {
  273. _jv.Msg = $"请选择正确的月份!格式:2025-12";
  274. return _jv;
  275. }
  276. var evaluatorInfo = await _sqlSugar.Queryable<Sys_Users>()
  277. .LeftJoin<Sys_Company>((u, c) => u.CompanyId == c.Id)
  278. .LeftJoin<Sys_Department>((u, c, d) => u.DepId == d.Id)
  279. .LeftJoin<Sys_JobPost>((u, c, d, jp) => u.JobPostId == d.Id)
  280. .Where((u, c, d, jp) => u.IsDel == 0)
  281. .Select((u, c, d, jp) => new
  282. {
  283. UserId = u.Id,
  284. u.CompanyId,
  285. c.CompanyName,
  286. u.DepId,
  287. d.DepName,
  288. u.JobPostId,
  289. jp.JobName,
  290. UserName = u.CnName
  291. })
  292. .FirstAsync();
  293. if (evaluatorInfo == null)
  294. {
  295. _jv.Msg = $"请选择有效的考核人!";
  296. return _jv;
  297. }
  298. var info = await _sqlSugar
  299. .Queryable<Pm_CompanyDailyKpi>()
  300. .LeftJoin<Sys_SetData>((cdk, sd) => cdk.EvalContent == sd.Id)
  301. .LeftJoin<Sys_Users>((cdk, sd, u) => cdk.Evaluator == u.Id)
  302. .Where((cdk, sd, u) => cdk.IsDel == 0 && cdk.Evaluator == evaluator && cdk.Month.Equals(month))
  303. .Select((cdk, sd, u) => new CompanyDailyKpiView()
  304. {
  305. Id = cdk.Id,
  306. Month = cdk.Month,
  307. EvaluatorId = cdk.Evaluator,
  308. Evaluator = u.CnName,
  309. EvalContentId = cdk.EvalContent,
  310. EvalContent = sd.Remark,
  311. IsMistake = cdk.IsMistake,
  312. MistakeReason = cdk.MistakeReason
  313. })
  314. .ToListAsync();
  315. if (!info.Any())
  316. {
  317. var tempInfo = await KpiTemplateDataAsync(evaluatorInfo.DepName, evaluatorInfo.JobName);
  318. if (!tempInfo.isSuccess)
  319. {
  320. _jv.Msg = $"{evaluatorInfo.DepName} - {evaluatorInfo.JobName},未配置日常绩效考核。";
  321. return _jv;
  322. }
  323. tempInfo.data.ForEach(t =>
  324. {
  325. t.Contents.ForEach(c =>
  326. {
  327. info.Add(new CompanyDailyKpiView()
  328. {
  329. Month = month,
  330. EvaluatorId = evaluatorInfo.UserId,
  331. Evaluator = evaluatorInfo.UserName,
  332. EvalContentId = c.KpiId,
  333. EvalContent = c.KpiContent,
  334. IsMistake = false,
  335. MistakeReason = string.Empty
  336. });
  337. });
  338. });
  339. }
  340. _jv.Code = StatusCodes.Status200OK;
  341. _jv.Data = info;
  342. _jv.Msg = $"操作成功";
  343. return _jv;
  344. }
  345. #endregion
  346. }
  347. }