QiYeWeChatApiService.cs 84 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969
  1. using EyeSoft.Extensions;
  2. using OASystem.Domain.Dtos.QiYeWeChat;
  3. using OASystem.Domain.ViewModels.QiYeWeChat;
  4. using System.Diagnostics;
  5. using System.Net.Mail;
  6. using System.Text.Json;
  7. using System.Text.Json.Serialization;
  8. namespace OASystem.API.OAMethodLib.QiYeWeChatAPI
  9. {
  10. /// <summary>
  11. /// 聚合Api 服务
  12. /// </summary>
  13. public class QiYeWeChatApiService : IQiYeWeChatApiService
  14. {
  15. private readonly HttpClient _httpClient;
  16. //private readonly string CorpId = "wwe978bef5495a0728"; //企业Id
  17. //private readonly string PersonnelAssistant_AgentId = "3010011"; //人事助手Id
  18. //private readonly string PunchCard_AgentId = "3010185"; //打卡Id
  19. //private readonly string Email_AgentId = "1000004"; //E-Mail Id
  20. //private readonly string Approve_AgentId = "3010040"; //审批 Id
  21. //private readonly string GroupStatus_AgentId = "1000008"; //OA通知 Id
  22. /// <summary>
  23. /// 人事助手凭证密钥
  24. /// </summary>
  25. private readonly string PersonnelAssistant_Corpsecret = "ig--IJd6TxWDMJ1wT4e-RDRcRX12v5GjB359DNATwJ4"; // 人事助手凭证密钥
  26. /// <summary>
  27. /// 打卡凭证密钥
  28. /// </summary>
  29. private readonly string PunchCard_Corpsecret = "Xhrl37GOqlAjsu0VzUSJECaJdjzkDXQLbvrzRsZQb8M"; // 打卡凭证密钥
  30. /// <summary>
  31. /// E-Mail 凭证密钥
  32. /// </summary>
  33. private readonly string Email_Corpsecret = "NA1zbJM15GmgjPYwDOqz59dIo1Wnug-MbU107MeUemc"; // E-Mail 凭证密钥
  34. /// <summary>
  35. /// 通讯录同步 凭证密钥
  36. /// </summary>
  37. private readonly string AddressBook_Corpsecret = "Y1tnjh7j-BvbqAytAoXZPUbmDR6dqLTL6mXtc6PZ7fo"; // 通讯录同步 凭证密钥
  38. /// <summary>
  39. /// 审批 凭证密钥
  40. /// </summary>
  41. private readonly string Approve_Corpsecret = "k_Jo69Jw9Hqg_in-Rypbs30PNbxOYa1t4e-dxYuT-kw"; // 审批 凭证密钥
  42. /// <summary>
  43. /// OA通知Secret
  44. /// </summary>
  45. private readonly string GroupStatus_Corpsecret = "7J_ST3jTPzbZpFwl7ttToTVufjEx6O2wuApvKHxt2Ak"; // OA通知Secret
  46. private readonly string Journal_Corpsecret = "l2lZbyLfyickVLdgi2bwVTevE-0UuZWpbNPrCbNhst0"; //汇报 凭证密钥
  47. private readonly DateTime _1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0);
  48. private readonly JobPostRepository _jobPostRep;
  49. /// <summary>
  50. /// 初始化
  51. /// </summary>
  52. /// <param name="clientFactory"></param>
  53. /// <param name="jobPostRep"></param>
  54. public QiYeWeChatApiService(IHttpClientFactory clientFactory, JobPostRepository jobPostRep)
  55. {
  56. _httpClient = clientFactory.CreateClient("PublicQiYeWeChatApi"); ;
  57. _jobPostRep = jobPostRep;
  58. }
  59. /// <summary>
  60. /// 获取access_token
  61. /// </summary>
  62. /// <param name="applicationType">
  63. /// 1:人事助手
  64. /// 2:打卡
  65. /// 3:邮件
  66. /// 4:通讯录同步
  67. /// 5:审批
  68. /// 6:团组状态通知
  69. /// 7:汇报
  70. /// </param>
  71. /// <returns></returns>
  72. private async Task<Access_TokenView> GetTokenAsync(int applicationType)
  73. {
  74. Access_TokenView tokenResult = new Access_TokenView();
  75. Access_Token_Request access_Token = new Access_Token_Request();
  76. string cacheName = string.Empty;
  77. if (applicationType == 1)
  78. {
  79. access_Token.corpsecret = PersonnelAssistant_Corpsecret; //人事助手
  80. cacheName = "PersonnelAssistant_Access_Token";
  81. }
  82. else if (applicationType == 2)
  83. {
  84. access_Token.corpsecret = PunchCard_Corpsecret; //打卡
  85. cacheName = "PunchCard_Access_Token";
  86. }
  87. else if (applicationType == 3)
  88. {
  89. access_Token.corpsecret = Email_Corpsecret; //E-Mail
  90. cacheName = "Enail_Access_Token";
  91. }
  92. else if (applicationType == 4) //通讯录同步
  93. {
  94. access_Token.corpsecret = AddressBook_Corpsecret;
  95. cacheName = "AddressBook_Access_Token";
  96. }
  97. else if (applicationType == 5) //审批
  98. {
  99. access_Token.corpsecret = Approve_Corpsecret;
  100. cacheName = "Approve_Access_Token";
  101. }
  102. else if (applicationType == 6) //团组状态通知
  103. {
  104. access_Token.corpsecret = GroupStatus_Corpsecret;
  105. cacheName = "GroupStatus_Access_Token";
  106. }
  107. else if (applicationType == 7) //汇报
  108. {
  109. access_Token.corpsecret = Journal_Corpsecret;
  110. cacheName = "Journal_Access_Token";
  111. }
  112. else
  113. {
  114. tokenResult.errmsg = "未识别应用类型Id!";
  115. return tokenResult;
  116. }
  117. string access_token = await RedisRepository.RedisFactory
  118. .CreateRedisRepository()
  119. .StringGetAsync<string>(cacheName);//string 取
  120. if (string.IsNullOrEmpty(access_token))
  121. {
  122. string access_token_url = string.Format(@"/cgi-bin/gettoken?corpid={0}&corpsecret={1}", access_Token.corpid, access_Token.corpsecret);
  123. var access_tokenReq = await _httpClient.GetAsync(access_token_url);
  124. if (access_tokenReq.IsSuccessStatusCode)
  125. {
  126. var stringResponse = await access_tokenReq.Content.ReadAsStringAsync();
  127. tokenResult = System.Text.Json.JsonSerializer.Deserialize<Access_TokenView>(stringResponse,
  128. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  129. if (tokenResult.errcode == 0)
  130. {
  131. TimeSpan ts = DateTime.Now.AddMinutes(118) - DateTime.Now; //设置redis 过期时间 118分钟
  132. await RedisRepository
  133. .RedisFactory
  134. .CreateRedisRepository()
  135. .StringSetAsync<string>(cacheName, tokenResult.access_token, ts);//string 存
  136. }
  137. }
  138. else
  139. {
  140. tokenResult.errmsg = "企业微信Token未获取到!";
  141. }
  142. }
  143. else
  144. {
  145. tokenResult.errcode = 0;
  146. tokenResult.access_token = access_token;
  147. }
  148. return tokenResult;
  149. }
  150. #region 添加员工
  151. /// <summary>
  152. /// 获取成员ID列表
  153. /// </summary>
  154. /// <returns></returns>
  155. public async Task<UserIdListView> GetUserIdListAsync()
  156. {
  157. UserIdListView userIdListView = new UserIdListView();
  158. Access_TokenView access_Token = await GetTokenAsync(4);
  159. if (access_Token.errcode != 0)
  160. {
  161. userIdListView.errcode = access_Token.errcode;
  162. userIdListView.errmsg = access_Token.errmsg;
  163. return userIdListView;
  164. }
  165. string url = string.Format("/cgi-bin/user/list_id?access_token={0}&debug=1", access_Token.access_token);
  166. var jsonData = new
  167. {
  168. access_token = access_Token.access_token, //调用接口凭证
  169. };
  170. var json = System.Text.Json.JsonSerializer.Serialize(jsonData);
  171. var content = new StringContent(json, Encoding.UTF8, "application/json");
  172. var create_Req = await _httpClient.PostAsync(url, content);
  173. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  174. userIdListView = System.Text.Json.JsonSerializer.Deserialize<UserIdListView>(stringResponse,
  175. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  176. return userIdListView;
  177. }
  178. /// <summary>
  179. /// 获取成员信息
  180. /// </summary>
  181. /// <returns></returns>
  182. public async Task<QYWX_UserInfosView> GetUserInfosAsync()
  183. {
  184. QYWX_UserInfosView infoViews = new QYWX_UserInfosView();
  185. //获取员工useridList
  186. UserIdListView useridView = await GetUserIdListAsync();
  187. if (useridView.errcode != 0)
  188. {
  189. infoViews.errcode = useridView.errcode;
  190. infoViews.errmsg = useridView.errmsg;
  191. return infoViews;
  192. }
  193. Access_TokenView access_Token = await GetTokenAsync(4);
  194. if (access_Token.errcode != 0)
  195. {
  196. infoViews.errcode = access_Token.errcode;
  197. infoViews.errmsg = access_Token.errmsg;
  198. return infoViews;
  199. }
  200. List<QYWX_UserInfo> items = new List<QYWX_UserInfo>();
  201. string urlTitle = string.Format("/cgi-bin/user/get?access_token={0}", access_Token.access_token);
  202. foreach (var item in useridView.dept_user)
  203. {
  204. if (!string.IsNullOrEmpty(item.userid))
  205. {
  206. QYWX_UserInfoView _UserInfoView = new QYWX_UserInfoView();
  207. string url = string.Format("{0}&userid={1}", urlTitle, item.userid);
  208. var create_Req = await _httpClient.GetAsync(url);
  209. if (create_Req.IsSuccessStatusCode)
  210. {
  211. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  212. _UserInfoView = System.Text.Json.JsonSerializer.Deserialize<QYWX_UserInfoView>(stringResponse,
  213. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  214. if (_UserInfoView.errcode == 0)
  215. {
  216. items.Add(new QYWX_UserInfo()
  217. {
  218. userid = _UserInfoView.QYWX_User.userid,
  219. name = _UserInfoView.QYWX_User.name,
  220. mobile = _UserInfoView.QYWX_User.mobile,
  221. position = _UserInfoView.QYWX_User.position,
  222. email = _UserInfoView.QYWX_User.email,
  223. biz_mail = _UserInfoView.QYWX_User.biz_mail,
  224. });
  225. }
  226. }
  227. }
  228. }
  229. infoViews.errcode = 0;
  230. infoViews.errmsg = "操作成功!";
  231. infoViews.QYWX_Users = items;
  232. return infoViews;
  233. }
  234. /// <summary>
  235. /// 获取部门列表
  236. /// </summary>
  237. /// <param name="access_token"></param>
  238. /// <returns></returns>
  239. private async Task<DepartmentListView> GetDepartmentAsync(string access_token)
  240. {
  241. DepartmentListView result = new DepartmentListView();
  242. string dep_url = string.Format("/cgi-bin/department/list?access_token={0}&debug=1", access_token);
  243. var depReq = await _httpClient.GetAsync(dep_url);
  244. if (depReq.IsSuccessStatusCode)
  245. {
  246. var stringResponse = await depReq.Content.ReadAsStringAsync();
  247. result = System.Text.Json.JsonSerializer.Deserialize<DepartmentListView>(stringResponse,
  248. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  249. }
  250. else
  251. {
  252. result.errcode = -1;
  253. result.errmsg = "企业微信部门列表未获取到!";
  254. }
  255. return result;
  256. }
  257. /// <summary>
  258. /// 创建员工
  259. /// </summary>
  260. /// <param name="create_Request"></param>
  261. /// <returns></returns>
  262. public async Task<ResponseBase> CreateAsync(Create_Request create_Request)
  263. {
  264. ResponseBase responseBase = new ResponseBase();
  265. #region 职位
  266. string depName = string.Empty,
  267. jobName = string.Empty;
  268. List<Sys_JobPostI> jobs = await _jobPostRep.QueryJobPost(string.Empty);
  269. Sys_JobPostI jobPost = jobs.Where(it => it.IsDel == 0 && it.Id == Convert.ToInt32(create_Request.position)).FirstOrDefault();
  270. if (jobPost != null)
  271. {
  272. depName = jobPost.DepName;
  273. jobName = jobPost.JobName;
  274. }
  275. create_Request.position = jobName;
  276. if (string.IsNullOrEmpty(create_Request.biz_mail))
  277. {
  278. create_Request.biz_mail = string.Format("{0}@pan-american-intl.com", create_Request.userid);
  279. }
  280. #endregion
  281. Access_TokenView access_Token = new Access_TokenView();
  282. access_Token = await GetTokenAsync(4);
  283. if (access_Token.errcode == 0)
  284. {
  285. create_Request.access_token = access_Token.access_token;
  286. #region 处理部门
  287. Access_TokenView dep_Access_Token = await GetTokenAsync(1);
  288. if (dep_Access_Token.errcode != 0)
  289. {
  290. responseBase.errcode = dep_Access_Token.errcode;
  291. responseBase.errmsg = dep_Access_Token.errmsg;
  292. }
  293. DepartmentListView depData = await GetDepartmentAsync(dep_Access_Token.access_token);
  294. if (depData.errcode == 0)
  295. {
  296. var depData1 = depData.department.Where(x => x.name == depName).FirstOrDefault();
  297. if (depData1 != null)
  298. {
  299. create_Request.department = new List<long> { depData1.id };
  300. }
  301. else
  302. {
  303. responseBase.errcode = -1;
  304. responseBase.errmsg = "未在企业微信上找到OA内设置的部门";
  305. return responseBase;
  306. }
  307. }
  308. else
  309. {
  310. responseBase.errcode = depData.errcode;
  311. responseBase.errmsg = depData.errmsg;
  312. return responseBase;
  313. }
  314. #endregion
  315. create_Request.access_token = access_Token.access_token;
  316. string create_url = string.Format("/cgi-bin/user/create?access_token={0}", create_Request.access_token);
  317. var json = System.Text.Json.JsonSerializer.Serialize(create_Request);
  318. var content = new StringContent(json, Encoding.UTF8, "application/json");
  319. var create_Req = await _httpClient.PostAsync(create_url, content);
  320. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  321. responseBase = System.Text.Json.JsonSerializer.Deserialize<ResponseBase>(stringResponse,
  322. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  323. }
  324. else
  325. {
  326. responseBase.errcode = access_Token.errcode;
  327. responseBase.errmsg = access_Token.errmsg;
  328. }
  329. return responseBase;
  330. }
  331. #endregion
  332. #region 邮件
  333. /// <summary>
  334. /// 发送邮件
  335. /// </summary>
  336. /// <param name="dto">发送邮件的请求对象</param>
  337. /// <returns></returns>
  338. public async Task<EmailResult> EmailSendAsync(EmailRequestDto dto)
  339. {
  340. EmailResult emailResult = new();
  341. // 参数验证
  342. if (dto.ToEmails == null) return new EmailResult() { errcode = -1, errmsg = "收件人邮箱列表不能为空" };
  343. if (string.IsNullOrEmpty(dto.Subject)) return new EmailResult() { errcode = -1, errmsg = "邮件主题不能为空" };
  344. if (string.IsNullOrEmpty(dto.Body)) return new EmailResult() { errcode = -1, errmsg = "邮件内容不能为空" };
  345. // 当前内容大小
  346. long currentSize = GetUtf8ByteSize(dto.Body);
  347. // 文件处理
  348. var attachments = new List<Domain.ViewModels.QiYeWeChat.Attachment>();
  349. var files = dto.Files;
  350. if (files != null && files.Length > 0)
  351. {
  352. if (files.Length > 200) return new EmailResult() { errcode = -1, errmsg = "附件个数不能超过200个" };
  353. foreach (var file in files)
  354. {
  355. if (file == null || file.Length == 0)
  356. {
  357. return new EmailResult() { errcode = -1, errmsg = "文件不能为空" };
  358. }
  359. string base64String = string.Empty;
  360. using (var memoryStream = new MemoryStream())
  361. {
  362. await file.CopyToAsync(memoryStream);
  363. var bytes = memoryStream.ToArray();
  364. base64String = Convert.ToBase64String(bytes);
  365. }
  366. var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file.FileName);
  367. var extension = Path.GetExtension(file.FileName);
  368. var feilName = $"{fileNameWithoutExtension}{extension}";
  369. currentSize += GetUtf8ByteSize(base64String);
  370. attachments.Add(new Domain.ViewModels.QiYeWeChat.Attachment()
  371. {
  372. file_name = feilName,
  373. content = base64String
  374. });
  375. }
  376. }
  377. // 限制大小
  378. long maxSizeBytes = 50 * 1024 * 1024; // 50MB
  379. if (currentSize > maxSizeBytes)
  380. {
  381. return new EmailResult() { errcode = -1, errmsg = "邮件内容和附件总大小不能超过50MB" };
  382. }
  383. Access_TokenView access_Token = await GetTokenAsync(3);
  384. if (access_Token.errcode != 0)
  385. {
  386. emailResult.errcode = access_Token.errcode;
  387. emailResult.errmsg = string.Format("【企业微信】【获取邮件列表】【Token】【Msg】{0}", access_Token.errmsg);
  388. }
  389. string url = string.Format("/cgi-bin/exmail/app/compose_send?access_token={0}", access_Token.access_token);
  390. var reqData = new
  391. {
  392. to = new
  393. {
  394. emails = dto.ToEmails
  395. },
  396. cc = new
  397. {
  398. emails = dto.CcEmails
  399. },
  400. bcc = new
  401. {
  402. emails = dto.BccEmails
  403. },
  404. subject = dto.Subject,
  405. content = dto.Body,
  406. attachment_list = attachments
  407. };
  408. var reqContent = new StringContent(System.Text.Json.JsonSerializer.Serialize(reqData), Encoding.UTF8, "application/json");
  409. var create_Req = await _httpClient.PostAsync(url, reqContent);
  410. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  411. emailResult = System.Text.Json.JsonSerializer.Deserialize<EmailResult>(stringResponse,
  412. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  413. return emailResult;
  414. }
  415. /// <summary>
  416. /// 计算字符串的字节大小(UTF-8编码)
  417. /// </summary>
  418. private static long GetUtf8ByteSize(string text)
  419. {
  420. if (string.IsNullOrEmpty(text))
  421. {
  422. return 0;
  423. }
  424. return Encoding.UTF8.GetByteCount(text);
  425. }
  426. #endregion
  427. #region 打卡
  428. /// <summary>
  429. /// 获取企业所有打卡规则
  430. /// </summary>
  431. /// <returns></returns>
  432. public async Task<CorpCheckInRuleView> GetCheckIn_CorpCheckInOptionAsync()
  433. {
  434. CorpCheckInRuleView corpCheckInRuleView = new CorpCheckInRuleView();
  435. //获取打卡数据 token
  436. Access_TokenView access_Token = await GetTokenAsync(2);
  437. if (access_Token.errcode != 0)
  438. {
  439. corpCheckInRuleView.errcode = access_Token.errcode;
  440. corpCheckInRuleView.errmsg = string.Format("【企业微信】【获取月打卡数据】【Token】【Msg】{0}", access_Token.errmsg);
  441. return corpCheckInRuleView;
  442. }
  443. string url = string.Format("/cgi-bin/checkin/getcorpcheckinoption?access_token={0}", access_Token.access_token);
  444. var content = new StringContent(string.Empty, Encoding.UTF8, "application/json");
  445. var create_Req = await _httpClient.PostAsync(url, content);
  446. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  447. corpCheckInRuleView = System.Text.Json.JsonSerializer.Deserialize<CorpCheckInRuleView>(stringResponse,
  448. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  449. return corpCheckInRuleView;
  450. }
  451. /// <summary>
  452. /// 获取月打卡记录数据
  453. /// </summary>
  454. /// <param name="startDt"></param>
  455. /// <param name="endDt"></param>
  456. /// <returns></returns>
  457. public async Task<CheckInView> GetCheckin_MonthDataAsync1(DateTime startDt, DateTime endDt)
  458. {
  459. CheckInView checkInView = new CheckInView();
  460. //获取员工Id
  461. UserIdListView userIdListView = await GetUserIdListAsync();
  462. if (userIdListView.errcode != 0)
  463. {
  464. checkInView.errcode = userIdListView.errcode;
  465. checkInView.errmsg = string.Format("【企业微信】【获取员工IdList】【Msg】{0}", userIdListView.errmsg);
  466. return checkInView;
  467. }
  468. if (userIdListView.dept_user == null || userIdListView.dept_user.Count <= 0)
  469. {
  470. checkInView.errmsg = string.Format("【企业微信】【获取员工IdList】【Msg】未查出员工Id");
  471. return checkInView;
  472. }
  473. //获取打卡数据 token
  474. Access_TokenView access_Token = await GetTokenAsync(2);
  475. if (access_Token.errcode != 0)
  476. {
  477. checkInView.errcode = access_Token.errcode;
  478. checkInView.errmsg = string.Format("【企业微信】【获取月打卡数据】【Token】【Msg】{0}", access_Token.errmsg);
  479. return checkInView;
  480. }
  481. string url = string.Format("/cgi-bin/checkin/getcheckin_monthdata?access_token={0}", access_Token.access_token);
  482. Checkin_MonthData_Request checkInReq = new Checkin_MonthData_Request();
  483. checkInReq.access_token = access_Token.access_token;
  484. checkInReq.starttime = (uint)(startDt - _1970).TotalSeconds;
  485. checkInReq.endtime = (uint)(endDt - _1970).TotalSeconds;
  486. checkInReq.useridlist = userIdListView.dept_user.Select(it => it.userid!).ToList();
  487. var json = System.Text.Json.JsonSerializer.Serialize(checkInReq);
  488. var content = new StringContent(json, Encoding.UTF8, "application/json");
  489. var create_Req = await _httpClient.PostAsync(url, content);
  490. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  491. checkInView = System.Text.Json.JsonSerializer.Deserialize<CheckInView>(stringResponse,
  492. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  493. return checkInView;
  494. }
  495. /// <summary>
  496. /// 获取月打卡记录数据
  497. /// </summary>
  498. /// <param name="startDt"></param>
  499. /// <param name="endDt"></param>
  500. /// <returns></returns>
  501. public async Task<CheckInView> GetCheckin_MonthDataAsync(DateTime startDt, DateTime endDt)
  502. {
  503. CheckInView checkInView = new CheckInView();
  504. //获取员工Id
  505. UserIdListView userIdListView = await GetUserIdListAsync();
  506. if (userIdListView.errcode != 0)
  507. {
  508. checkInView.errcode = userIdListView.errcode;
  509. checkInView.errmsg = string.Format("【企业微信】【获取员工IdList】【Msg】{0}", userIdListView.errmsg);
  510. return checkInView;
  511. }
  512. if (userIdListView.dept_user == null || userIdListView.dept_user.Count <= 0)
  513. {
  514. checkInView.errmsg = string.Format("【企业微信】【获取员工IdList】【Msg】未查出员工Id");
  515. return checkInView;
  516. }
  517. //获取打卡数据 token
  518. Access_TokenView access_Token = await GetTokenAsync(2);
  519. if (access_Token.errcode != 0)
  520. {
  521. checkInView.errcode = access_Token.errcode;
  522. checkInView.errmsg = string.Format("【企业微信】【获取月打卡数据】【Token】【Msg】{0}", access_Token.errmsg);
  523. return checkInView;
  524. }
  525. #region 处理超31天的月报表数据
  526. string url = string.Format("/cgi-bin/checkin/getcheckin_monthdata?access_token={0}", access_Token.access_token);
  527. Checkin_MonthData_Request checkInReq = new Checkin_MonthData_Request();
  528. checkInReq.access_token = access_Token.access_token;
  529. checkInReq.useridlist = userIdListView.dept_user.Select(it => it.userid ?? "").ToList();
  530. uint starttimeOne, endtimeOne, starttimeTwo, endtimeTwo;
  531. int days = (int)(endDt - startDt).TotalDays;
  532. if (days > 32)
  533. {
  534. starttimeOne = (uint)((startDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000);
  535. endtimeOne = (uint)((startDt.AddDays(31).ToUniversalTime().Ticks - 621355968000000000) / 10000000);
  536. starttimeTwo = (uint)((startDt.AddDays(32).ToUniversalTime().Ticks - 621355968000000000) / 10000000);
  537. endtimeTwo = (uint)((endDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000);
  538. checkInReq.starttime = starttimeOne;
  539. checkInReq.endtime = endtimeOne;
  540. CheckInView checkInViewOne = new CheckInView();
  541. var jsonOne = System.Text.Json.JsonSerializer.Serialize(checkInReq);
  542. var contentOne = new StringContent(jsonOne, Encoding.UTF8, "application/json");
  543. var create_ReqOne = await _httpClient.PostAsync(url, contentOne);
  544. var stringResponseOne = await create_ReqOne.Content.ReadAsStringAsync();
  545. checkInViewOne = System.Text.Json.JsonSerializer.Deserialize<CheckInView>(stringResponseOne,
  546. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  547. if (checkInViewOne.errcode != 0)
  548. {
  549. return checkInViewOne;
  550. }
  551. checkInReq.starttime = starttimeTwo;
  552. checkInReq.endtime = endtimeTwo;
  553. CheckInView checkInViewTwo = new CheckInView();
  554. var jsonTwo = System.Text.Json.JsonSerializer.Serialize(checkInReq);
  555. var contentTwo = new StringContent(jsonTwo, Encoding.UTF8, "application/json");
  556. var create_ReqTwo = await _httpClient.PostAsync(url, contentTwo);
  557. var stringResponseTwo = await create_ReqTwo.Content.ReadAsStringAsync();
  558. checkInViewTwo = System.Text.Json.JsonSerializer.Deserialize<CheckInView>(stringResponseTwo,
  559. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  560. if (checkInViewTwo.errcode != 0)
  561. {
  562. return checkInViewTwo;
  563. }
  564. #region 整合月报表数据
  565. foreach (var item_one in checkInViewOne.datas)
  566. {
  567. foreach (var item_two in checkInViewTwo.datas)
  568. {
  569. if (item_one.base_info.acctid.Equals(item_two.base_info.acctid))
  570. {
  571. #region summary_info 汇总信息整合
  572. item_one.summary_info.work_days += item_two.summary_info.work_days; //应打卡天数
  573. item_one.summary_info.regular_days += item_two.summary_info.regular_days; //正常天数
  574. item_one.summary_info.except_days += item_two.summary_info.except_days; //异常天数
  575. item_one.summary_info.regular_work_sec += item_two.summary_info.regular_work_sec; //实际工作时长,为统计周期每日实际工作时长之和
  576. item_one.summary_info.standard_work_sec += item_two.summary_info.standard_work_sec; //标准工作时长,为统计周期每日标准工作时长之和
  577. #endregion
  578. #region exception_infos 异常状态统计信息 整合
  579. item_one.exception_infos.AddRange(item_two.exception_infos);
  580. #endregion
  581. #region sp_items 假勤统计信息整合
  582. item_one.sp_items.AddRange(item_two.sp_items);
  583. #endregion
  584. #region overwork_info 加班情况 整合
  585. item_one.overwork_info.workday_over_sec += item_two.overwork_info.workday_over_sec; //工作日加班时长
  586. item_one.overwork_info.holidays_over_sec += item_two.overwork_info.holidays_over_sec; //节假日加班时长
  587. item_one.overwork_info.restdays_over_sec += item_two.overwork_info.restdays_over_sec; //休息日加班时长
  588. #endregion
  589. break;
  590. }
  591. }
  592. }
  593. #endregion
  594. checkInView = checkInViewOne;
  595. }
  596. else
  597. {
  598. checkInReq.starttime = (uint)((startDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000);
  599. checkInReq.endtime = (uint)((endDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000);
  600. var json = System.Text.Json.JsonSerializer.Serialize(checkInReq);
  601. var content = new StringContent(json, Encoding.UTF8, "application/json");
  602. var create_Req = await _httpClient.PostAsync(url, content);
  603. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  604. checkInView = System.Text.Json.JsonSerializer.Deserialize<CheckInView>(stringResponse,
  605. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  606. }
  607. #endregion
  608. return checkInView;
  609. }
  610. /// <summary>
  611. /// 获取月打卡数据(redis缓存)
  612. /// </summary>
  613. /// <param name="startDt"></param>
  614. /// <param name="endDt"></param>
  615. /// <returns></returns>
  616. public async Task<CheckInView> GetCheckin_MonthDataRedisAsync(DateTime startDt, DateTime endDt)
  617. {
  618. CheckInView checkInView = new CheckInView();
  619. string checkInDatastring = await RedisRepository.RedisFactory
  620. .CreateRedisRepository()
  621. .StringGetAsync<string>("Checkin_MonthData");//List<T> 取
  622. if (!string.IsNullOrEmpty(checkInDatastring))
  623. {
  624. checkInView = JsonConvert.DeserializeObject<CheckInView>(checkInDatastring);
  625. return checkInView;
  626. }
  627. //获取员工Id
  628. UserIdListView userIdListView = await GetUserIdListAsync();
  629. if (userIdListView.errcode != 0)
  630. {
  631. checkInView.errcode = userIdListView.errcode;
  632. checkInView.errmsg = string.Format("【企业微信】【获取员工IdList】【Msg】{0}", userIdListView.errmsg);
  633. return checkInView;
  634. }
  635. if (userIdListView.dept_user == null || userIdListView.dept_user.Count <= 0)
  636. {
  637. checkInView.errmsg = string.Format("【企业微信】【获取员工IdList】【Msg】未查出员工Id");
  638. return checkInView;
  639. }
  640. //获取月打卡数据 token
  641. Access_TokenView access_Token = await GetTokenAsync(2);
  642. if (access_Token.errcode != 0)
  643. {
  644. checkInView.errcode = access_Token.errcode;
  645. checkInView.errmsg = string.Format("【企业微信】【获取月打卡数据】【Token】【Msg】{0}", access_Token.errmsg);
  646. return checkInView;
  647. }
  648. string url = string.Format("/cgi-bin/checkin/getcheckin_monthdata?access_token={0}", access_Token.access_token);
  649. Checkin_MonthData_Request checkInReq = new Checkin_MonthData_Request();
  650. checkInReq.access_token = access_Token.access_token;
  651. checkInReq.starttime = (uint)(startDt - _1970).TotalSeconds;
  652. checkInReq.endtime = (uint)(endDt - _1970).TotalSeconds;
  653. checkInReq.useridlist = userIdListView.dept_user.Select(it => it.userid!).ToList();
  654. var json = System.Text.Json.JsonSerializer.Serialize(checkInReq);
  655. var content = new StringContent(json, Encoding.UTF8, "application/json");
  656. var create_Req = await _httpClient.PostAsync(url, content);
  657. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  658. checkInView = System.Text.Json.JsonSerializer.Deserialize<CheckInView>(stringResponse,
  659. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  660. if (checkInView.errcode == 0)
  661. {
  662. TimeSpan ts = DateTime.Now.AddMinutes(60) - DateTime.Now; //设置redis 过期时间 60分钟
  663. await RedisRepository
  664. .RedisFactory
  665. .CreateRedisRepository()
  666. .StringSetAsync<string>("Checkin_MonthData", JsonConvert.SerializeObject(checkInView), ts);//List<T> 存
  667. }
  668. return checkInView;
  669. }
  670. public async Task<object> QueryAssessmentByUser(DateTime startDt, DateTime endDt, List<string> qiyeUidList)
  671. {
  672. AssessmentByUserListView assessmentByUserListView = new AssessmentByUserListView();
  673. List<AssessmentByUserView> AssessmentByUserView = new List<AssessmentByUserView>();
  674. assessmentByUserListView.Data = AssessmentByUserView;
  675. assessmentByUserListView.errcode = 0;
  676. assessmentByUserListView.errmsg = "成功";
  677. CheckInView? checkInView = new CheckInView();
  678. //获取打卡数据 token
  679. Access_TokenView access_Token = await GetTokenAsync(2);
  680. if (access_Token.errcode != 0)
  681. {
  682. assessmentByUserListView.errcode = access_Token.errcode;
  683. assessmentByUserListView.errmsg = string.Format("【企业微信】【获取月打卡数据】【Token】【Msg】{0}", access_Token.errmsg);
  684. return assessmentByUserListView;
  685. }
  686. string url = string.Format("/cgi-bin/checkin/getcheckin_monthdata?access_token={0}", access_Token.access_token);
  687. Checkin_MonthData_Request checkInReq = new Checkin_MonthData_Request();
  688. checkInReq.access_token = access_Token.access_token;
  689. checkInReq.starttime = (uint)(startDt - _1970).TotalSeconds;
  690. checkInReq.endtime = (uint)(endDt - _1970).TotalSeconds;
  691. checkInReq.useridlist = qiyeUidList;
  692. var json = System.Text.Json.JsonSerializer.Serialize(checkInReq);
  693. var content = new StringContent(json, Encoding.UTF8, "application/json");
  694. var create_Req = await _httpClient.PostAsync(url, content);
  695. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  696. checkInView = System.Text.Json.JsonSerializer.Deserialize<CheckInView>(stringResponse,
  697. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  698. if (checkInView == null)
  699. {
  700. assessmentByUserListView.errcode = -1;
  701. assessmentByUserListView.errmsg = "checkInView Deserialize Error";
  702. return assessmentByUserListView;
  703. }
  704. if (checkInView.errcode != 0)
  705. {
  706. assessmentByUserListView.errcode = checkInView.errcode;
  707. assessmentByUserListView.errmsg = checkInView.errmsg;
  708. return assessmentByUserListView;
  709. }
  710. var errorUserList = new List<string>();
  711. //遍历用户数据
  712. foreach (var item in checkInView.datas)
  713. {
  714. //有异常状态的情况下获取具体异常信息
  715. if (item.summary_info.except_days > 0)
  716. {
  717. errorUserList.Add(item.base_info.acctid);
  718. }
  719. assessmentByUserListView.Data.Add(new Domain.ViewModels.QiYeWeChat.AssessmentByUserView
  720. {
  721. Accid = item.base_info.acctid,
  722. Except_days = item.summary_info.except_days,
  723. Name = item.base_info.name,
  724. Regular_days = item.summary_info.regular_days,
  725. Exception_info_List = new List<Exception_info>(),
  726. Work_days = item.summary_info.work_days
  727. });
  728. }
  729. if (errorUserList.Count > 0)
  730. {
  731. var dayInfo = await GetCheckinDataAsync(errorUserList, 3, startDt, endDt);
  732. if (dayInfo.errcode != 0)
  733. {
  734. assessmentByUserListView.errcode = dayInfo.errcode;
  735. assessmentByUserListView.errmsg = dayInfo.errmsg;
  736. assessmentByUserListView.Data = new List<AssessmentByUserView>();
  737. return assessmentByUserListView;
  738. }
  739. var dic = new Dictionary<ErrorType, List<string>>()
  740. {
  741. { ErrorType.迟到 , new List<string>{ "时间异常" } },
  742. { ErrorType.缺卡 , new List<string>{ "未打卡" } },
  743. };
  744. foreach (var item in dayInfo.checkindata)
  745. {
  746. foreach (var user in assessmentByUserListView.Data)
  747. {
  748. if (user.Accid == item.userid)
  749. {
  750. //遍历异常信息
  751. if (!item.exception_type.IsNullOrWhiteSpace())
  752. {
  753. var linqFind = dic.First(x => x.Value.Contains(item.exception_type));
  754. var errinfo = new Exception_info
  755. {
  756. Date = item.checkin_time_dt,
  757. Type = linqFind.Key,
  758. Info = item.exception_type
  759. };
  760. user.Exception_info_List.Add(errinfo);
  761. }
  762. }
  763. }
  764. }
  765. }
  766. return assessmentByUserListView;
  767. }
  768. /// <summary>
  769. /// 获取打卡记录数据
  770. /// </summary>
  771. /// <param name="useridlist">需要获取打卡记录的用户列表</param>
  772. /// <param name="opencheckindatatype">打卡类型。1:上下班打卡;2:外出打卡;3:全部打卡</param>
  773. /// <param name="startDt">获取打卡记录的开始时间。Unix时间戳</param>
  774. /// <param name="endDt">获取打卡记录的结束时间。Unix时间戳</param>
  775. /// <returns></returns>
  776. public async Task<CheckInDataView> GetCheckinDataAsync(List<string> useridlist, int opencheckindatatype, DateTime startDt, DateTime endDt)
  777. {
  778. CheckInDataView checkInDataView = new CheckInDataView();
  779. //参数处理
  780. if (useridlist.Count <= 0)
  781. {
  782. checkInDataView.errmsg = "请填写企业微信用户id,可为多个!";
  783. return checkInDataView;
  784. }
  785. if (useridlist.Count > 100)
  786. {
  787. checkInDataView.errmsg = "用户列表不超过100个。若用户超过100个,请分批获取!";
  788. return checkInDataView;
  789. }
  790. //获取打卡数据 token
  791. Access_TokenView access_Token = await GetTokenAsync(2);
  792. if (access_Token.errcode != 0)
  793. {
  794. checkInDataView.errcode = access_Token.errcode;
  795. checkInDataView.errmsg = string.Format("【企业微信】【获取打卡数据】【Token】【Msg】{0}", access_Token.errmsg);
  796. return checkInDataView;
  797. }
  798. string url = string.Format("/cgi-bin/checkin/getcheckindata?access_token={0}", access_Token.access_token);
  799. DateTime centerDt = startDt.AddDays(30);
  800. long startTs = (long)(startDt - _1970).TotalSeconds;
  801. long centerTs = (long)(centerDt - _1970).TotalSeconds;
  802. long endTs = (long)(endDt - _1970).TotalSeconds;
  803. CheckInData_Request checkInData_Req = new CheckInData_Request()
  804. {
  805. access_token = access_Token.access_token,
  806. opencheckindatatype = opencheckindatatype,
  807. useridlist = useridlist,
  808. starttime = startTs,
  809. endtime = centerTs
  810. };
  811. var json = System.Text.Json.JsonSerializer.Serialize(checkInData_Req);
  812. var content = new StringContent(json, Encoding.UTF8, "application/json");
  813. var create_Req = await _httpClient.PostAsync(url, content);
  814. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  815. checkInDataView = System.Text.Json.JsonSerializer.Deserialize<CheckInDataView>(stringResponse,
  816. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  817. if (centerDt < endDt)
  818. {
  819. checkInData_Req.starttime = centerTs;
  820. checkInData_Req.endtime = endTs;
  821. var json1 = System.Text.Json.JsonSerializer.Serialize(checkInData_Req);
  822. var content1 = new StringContent(json1, Encoding.UTF8, "application/json");
  823. var create_Req1 = await _httpClient.PostAsync(url, content1);
  824. var stringResponse1 = await create_Req1.Content.ReadAsStringAsync();
  825. CheckInDataView checkInDataView1 = System.Text.Json.JsonSerializer.Deserialize<CheckInDataView>(stringResponse1,
  826. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  827. if (checkInDataView1.errcode != 0)
  828. {
  829. return checkInDataView1;
  830. }
  831. checkInDataView.checkindata.AddRange(checkInDataView1.checkindata);
  832. return checkInDataView;
  833. }
  834. return checkInDataView;
  835. }
  836. /// <summary>
  837. /// 获取打卡日报数据
  838. /// </summary>
  839. /// <param name="useridlist"></param>
  840. /// <param name="startDt"></param>
  841. /// <param name="endDt"></param>
  842. /// <returns></returns>
  843. public async Task<CheckInDayDataView> GetCheckInDayDataAsync1(List<string> useridlist, DateTime startDt, DateTime endDt)
  844. {
  845. CheckInDayDataView checkInDayDataView = new CheckInDayDataView();
  846. //参数处理
  847. if (useridlist.Count <= 0)
  848. {
  849. checkInDayDataView.errmsg = "请填写企业微信用户id,可为多个!";
  850. return checkInDayDataView;
  851. }
  852. //获取打卡数据 token
  853. Access_TokenView access_Token = await GetTokenAsync(2);
  854. if (access_Token.errcode != 0)
  855. {
  856. checkInDayDataView.errcode = access_Token.errcode;
  857. checkInDayDataView.errmsg = string.Format("【企业微信】【获取打卡日报数据】【Token】【Msg】{0}", access_Token.errmsg);
  858. return checkInDayDataView;
  859. }
  860. string url = string.Format("/cgi-bin/checkin/getcheckin_daydata?access_token={0}&debug=1", access_Token.access_token);
  861. long startTs = (startDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  862. long endTs = (endDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  863. var checkInData_Req = new
  864. {
  865. access_token = access_Token.access_token,
  866. useridlist = useridlist,
  867. starttime = startTs,
  868. endtime = endTs
  869. };
  870. var json = System.Text.Json.JsonSerializer.Serialize(checkInData_Req);
  871. var content = new StringContent(json, Encoding.UTF8, "application/json");
  872. var create_Req = await _httpClient.PostAsync(url, content);
  873. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  874. checkInDayDataView = System.Text.Json.JsonSerializer.Deserialize<CheckInDayDataView>(stringResponse,
  875. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  876. return checkInDayDataView;
  877. }
  878. /// <summary>
  879. /// 获取打卡日报数据
  880. /// </summary>
  881. /// <param name="useridlist"></param>
  882. /// <param name="startDt"></param>
  883. /// <param name="endDt"></param>
  884. /// <returns></returns>
  885. public async Task<CheckInDayDataView> GetCheckInDayDataAsync(List<string> useridlist, DateTime startDt, DateTime endDt)
  886. {
  887. CheckInDayDataView checkInDayDataView = new CheckInDayDataView();
  888. //参数处理
  889. if (useridlist.Count <= 0)
  890. {
  891. checkInDayDataView.errmsg = "请填写企业微信用户id,可为多个!";
  892. return checkInDayDataView;
  893. }
  894. //获取打卡数据 token
  895. Access_TokenView access_Token = await GetTokenAsync(2);
  896. if (access_Token.errcode != 0)
  897. {
  898. checkInDayDataView.errcode = access_Token.errcode;
  899. checkInDayDataView.errmsg = string.Format("【企业微信】【获取打卡日报数据】【Token】【Msg】{0}", access_Token.errmsg);
  900. return checkInDayDataView;
  901. }
  902. string url = string.Format("/cgi-bin/checkin/getcheckin_daydata?access_token={0}&debug=1", access_Token.access_token);
  903. int days = (int)(endDt - startDt).TotalDays;
  904. if (days > 31)
  905. {
  906. long startTs_One = (startDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  907. long endTs_One = (startDt.AddDays(31).ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  908. long startTs_Two = (startDt.AddDays(31).ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  909. long endTs_Two = (endDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  910. var checkInData_ReqOne = new
  911. {
  912. access_token = access_Token.access_token,
  913. useridlist = useridlist,
  914. starttime = startTs_One,
  915. endtime = endTs_One
  916. };
  917. var jsonOne = System.Text.Json.JsonSerializer.Serialize(checkInData_ReqOne);
  918. var contentOne = new StringContent(jsonOne, Encoding.UTF8, "application/json");
  919. var create_ReqOne = await _httpClient.PostAsync(url, contentOne);
  920. var stringResponseOne = await create_ReqOne.Content.ReadAsStringAsync();
  921. CheckInDayDataView checkInDayDataViewOne = System.Text.Json.JsonSerializer.Deserialize<CheckInDayDataView>(stringResponseOne,
  922. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  923. if (checkInDayDataViewOne.errcode != 0)
  924. {
  925. return checkInDayDataViewOne;
  926. }
  927. var checkInData_ReqTwo = new
  928. {
  929. access_token = access_Token.access_token,
  930. useridlist = useridlist,
  931. starttime = startTs_Two,
  932. endtime = endTs_Two
  933. };
  934. var jsonTwo = System.Text.Json.JsonSerializer.Serialize(checkInData_ReqTwo);
  935. var contentTwo = new StringContent(jsonTwo, Encoding.UTF8, "application/json");
  936. var create_ReqTwo = await _httpClient.PostAsync(url, contentTwo);
  937. var stringResponseTwo = await create_ReqTwo.Content.ReadAsStringAsync();
  938. CheckInDayDataView checkInDayDataViewTwo = System.Text.Json.JsonSerializer.Deserialize<CheckInDayDataView>(stringResponseTwo,
  939. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  940. if (checkInDayDataViewTwo.errcode != 0)
  941. {
  942. return checkInDayDataViewTwo;
  943. }
  944. checkInDayDataViewOne.datas.AddRange(checkInDayDataViewTwo.datas);
  945. return checkInDayDataViewOne;
  946. }
  947. else
  948. {
  949. long startTs = (startDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  950. long endTs = (endDt.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  951. var checkInData_Req = new
  952. {
  953. access_token = access_Token.access_token,
  954. useridlist = useridlist,
  955. starttime = startTs,
  956. endtime = endTs
  957. };
  958. var json = System.Text.Json.JsonSerializer.Serialize(checkInData_Req);
  959. var content = new StringContent(json, Encoding.UTF8, "application/json");
  960. var create_Req = await _httpClient.PostAsync(url, content);
  961. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  962. checkInDayDataView = System.Text.Json.JsonSerializer.Deserialize<CheckInDayDataView>(stringResponse,
  963. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  964. }
  965. return checkInDayDataView;
  966. }
  967. #endregion
  968. #region 审批
  969. /// <summary>
  970. /// 获取审批数据(旧)
  971. /// </summary>
  972. /// <param name="startDt"></param>
  973. /// <param name="endDt"></param>
  974. /// <returns></returns>
  975. public async Task<ApprovalDataView> GetApprovalDataAsync(DateTime startDt, DateTime endDt)
  976. {
  977. ApprovalDataView approvalDataView = new ApprovalDataView();
  978. //获取审批数据 token
  979. Access_TokenView access_Token = await GetTokenAsync(5);
  980. if (access_Token.errcode != 0)
  981. {
  982. approvalDataView.errcode = access_Token.errcode;
  983. approvalDataView.errmsg = string.Format("【企业微信】【获取审批数据】【Token】【Msg】{0}", access_Token.errmsg);
  984. return approvalDataView;
  985. }
  986. string url = string.Format("/cgi-bin/corp/getapprovaldata?access_token={0}", access_Token.access_token);
  987. ApprovalData_Request approvalDataReq = new ApprovalData_Request();
  988. approvalDataReq.access_token = access_Token.access_token;
  989. approvalDataReq.starttime = (uint)(startDt - _1970).TotalSeconds;
  990. approvalDataReq.endtime = (uint)(endDt - _1970).TotalSeconds;
  991. var json = System.Text.Json.JsonSerializer.Serialize(approvalDataReq);
  992. var content = new StringContent(json, Encoding.UTF8, "application/json");
  993. var create_Req = await _httpClient.PostAsync(url, content);
  994. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  995. approvalDataView = System.Text.Json.JsonSerializer.Deserialize<ApprovalDataView>(stringResponse,
  996. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  997. List<Sp_Info> sp_datas = new List<Sp_Info>();
  998. sp_datas.AddRange(approvalDataView.data);
  999. int index = 0;
  1000. //多次访问审批接口
  1001. if (approvalDataView.total >= 100)
  1002. {
  1003. approvalDataView.total -= 100;
  1004. int forTotal = approvalDataView.total % 100 == 0 ? approvalDataView.total / 100 : approvalDataView.total / 100 + 1;
  1005. long? next_spnum = approvalDataView.next_spnum;
  1006. approvalDataReq.next_spnum = next_spnum;
  1007. for (int i = 0; i < forTotal; i++)
  1008. {
  1009. index++;
  1010. var for_json = System.Text.Json.JsonSerializer.Serialize(approvalDataReq);
  1011. var for_content = new StringContent(for_json, Encoding.UTF8, "application/json");
  1012. var for_create_Req = await _httpClient.PostAsync(url, for_content);
  1013. var for_stringResponse = await for_create_Req.Content.ReadAsStringAsync();
  1014. ApprovalDataView for_approvalDataView = System.Text.Json.JsonSerializer.Deserialize<ApprovalDataView>(for_stringResponse,
  1015. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1016. approvalDataReq.next_spnum = for_approvalDataView.next_spnum; //重新定义游标
  1017. sp_datas.AddRange(for_approvalDataView.data); //追加数据
  1018. }
  1019. approvalDataView.total += 100;
  1020. }
  1021. approvalDataView.data = sp_datas;
  1022. return approvalDataView;
  1023. }
  1024. /// <summary>
  1025. /// 获取审批数据(旧)(redis缓存)
  1026. /// </summary>
  1027. /// <param name="startDt"></param>
  1028. /// <param name="endDt"></param>
  1029. /// <returns></returns>
  1030. public async Task<List<Sp_Info>> GetApprovalDatasAsync(DateTime startDt, DateTime endDt)
  1031. {
  1032. List<Sp_Info> sp_Infos = new List<Sp_Info>();
  1033. //获取所有打卡补卡,审批 数据 前后范围增加10天
  1034. DateTime sp_startDt = startDt.AddDays(-10);
  1035. DateTime sp_centerDt = sp_startDt.AddDays(30);
  1036. DateTime sp_endDt = endDt.AddDays(10);
  1037. ApprovalDataView approvalData_1 = await GetApprovalDataAsync(sp_startDt, sp_centerDt); //时间段内所有 审批数据
  1038. ApprovalDataView approvalData_2 = await GetApprovalDataAsync(sp_centerDt, sp_endDt); //时间段内所有 审批数据
  1039. if (approvalData_1.errcode != 0)
  1040. {
  1041. Log.Error("企业微信 获取 " + sp_startDt + " - " + sp_centerDt + " 内审批 Msg:" + approvalData_1.errmsg);
  1042. return sp_Infos;
  1043. }
  1044. sp_Infos.AddRange(approvalData_1.data);
  1045. if (approvalData_2.errcode != 0)
  1046. {
  1047. Log.Error("企业微信 获取 " + sp_centerDt + " - " + sp_endDt + " 内审批 Msg:" + approvalData_2.errmsg);
  1048. return sp_Infos;
  1049. }
  1050. sp_Infos.AddRange(approvalData_2.data);
  1051. sp_Infos = sp_Infos.Where(it => it.sp_status == 2).ToList(); //存储已审核的数据
  1052. return sp_Infos;
  1053. }
  1054. /// <summary>
  1055. /// 获取审批数据(旧)(redis缓存)
  1056. /// </summary>
  1057. /// <param name="startDt"></param>
  1058. /// <param name="endDt"></param>
  1059. /// <returns></returns>
  1060. public async Task<List<Sp_Info>> GetApprovalDatasRedisAsync(DateTime startDt, DateTime endDt)
  1061. {
  1062. List<Sp_Info> sp_Infos = new List<Sp_Info>();
  1063. //获取所有打卡补卡,审批 数据 前后范围增加10天
  1064. DateTime sp_startDt = startDt.AddDays(-10);
  1065. DateTime sp_centerDt = sp_startDt.AddDays(30);
  1066. DateTime sp_endDt = endDt.AddDays(10);
  1067. string redisName = "ApprovalData" + sp_startDt.ToString("yyyyMMdd") + "-" + sp_endDt.ToString("yyyyMMdd");
  1068. string sp_InfosString = string.Empty;
  1069. //sp_InfosString = await RedisRepository.RedisFactory
  1070. // .CreateRedisRepository()
  1071. // .StringGetAsync<string>(redisName);//string 取
  1072. if (string.IsNullOrEmpty(sp_InfosString))
  1073. {
  1074. ApprovalDataView approvalData_1 = await GetApprovalDataAsync(sp_startDt, sp_centerDt); //时间段内所有 审批数据
  1075. ApprovalDataView approvalData_2 = await GetApprovalDataAsync(sp_centerDt, sp_endDt); //时间段内所有 审批数据
  1076. if (approvalData_1.errcode != 0)
  1077. {
  1078. Log.Error("企业微信 获取 " + sp_startDt + " - " + sp_centerDt + " 内审批 Msg:" + approvalData_1.errmsg);
  1079. return sp_Infos;
  1080. }
  1081. sp_Infos.AddRange(approvalData_1.data);
  1082. if (approvalData_2.errcode != 0)
  1083. {
  1084. Log.Error("企业微信 获取 " + sp_centerDt + " - " + sp_endDt + " 内审批 Msg:" + approvalData_2.errmsg);
  1085. return sp_Infos;
  1086. }
  1087. sp_Infos.AddRange(approvalData_2.data);
  1088. sp_Infos = sp_Infos.Where(it => it.sp_status == 2).ToList(); //存储已审核的数据
  1089. TimeSpan ts = DateTime.Now.AddMinutes(60) - DateTime.Now; //设置redis 过期时间 60分钟
  1090. await RedisRepository
  1091. .RedisFactory
  1092. .CreateRedisRepository()
  1093. .StringSetAsync<string>(redisName, JsonConvert.SerializeObject(sp_Infos), ts);//string 存
  1094. }
  1095. else
  1096. {
  1097. sp_Infos = JsonConvert.DeserializeObject<List<Sp_Info>>(sp_InfosString);
  1098. }
  1099. return sp_Infos;
  1100. }
  1101. /// <summary>
  1102. /// 批量获取审批单号
  1103. /// </summary>
  1104. /// <param name="startDt"></param>
  1105. /// <param name="endDt"></param>
  1106. /// <param name="creator">
  1107. /// 申请人
  1108. /// </param>
  1109. /// <param name="sp_status">
  1110. /// sp_status-审批单状态(1-审批中;2-已通过;3-已驳回;4-已撤销;6-通过后撤销;7-已删除;10-已支付)
  1111. /// </param>
  1112. /// <param name="record_type">
  1113. /// record_type == 0 ALL 有值 请填写对应值
  1114. /// record_type - 审批单类型属性,1-请假;2-打卡补卡;3-出差;4-外出;5-加班; 6- 调班;7-会议室预定;8-退款审批;9-红包报销审批
  1115. /// </param>
  1116. /// <returns></returns>
  1117. private async Task<ApprovalInfoView> GetApprovalInfoAsync(DateTime startDt, DateTime endDt, string creator, int sp_status, int record_type)
  1118. {
  1119. Stopwatch sw = new Stopwatch();
  1120. sw.Start();
  1121. ApprovalInfoView approvalInfoView = new ApprovalInfoView();
  1122. //获取所有打卡补卡,审批 数据 向前增加30天 向后范围增加15天
  1123. DateTime sp_startDt = startDt.AddDays(-30);
  1124. DateTime sp_endDt = endDt.AddDays(15);
  1125. //获取审批数据 token
  1126. Access_TokenView access_Token = await GetTokenAsync(5);
  1127. if (access_Token.errcode != 0)
  1128. {
  1129. approvalInfoView.errcode = access_Token.errcode;
  1130. approvalInfoView.errmsg = string.Format("【企业微信】【批量获取审批单号】【Token】【Msg】{0}", access_Token.errmsg);
  1131. return approvalInfoView;
  1132. }
  1133. string url = string.Format("/cgi-bin/oa/getapprovalinfo?access_token={0}", access_Token.access_token);
  1134. List<Dic> filters = new List<Dic> {
  1135. new Dic() { key = "creator", value = creator }, //筛选条件 申请人
  1136. new Dic() { key = "sp_status", value = sp_status.ToString() }, //筛选条件 审核状态 2 已同意
  1137. };
  1138. if (record_type != 0)
  1139. {
  1140. filters.Add(new Dic() { key = "record_type", value = record_type.ToString() }); //筛选条件 审批单类型 请假 1
  1141. }
  1142. int days = (sp_endDt - sp_startDt).Days;
  1143. decimal runCount = days % 30;
  1144. int runCount1 = 0;
  1145. if (runCount == 0) runCount1 = (int)(days % 30.00M);
  1146. else runCount1 = (int)Math.Ceiling(days / 30.00M);
  1147. List<string> sp_no_lists = new List<string>();
  1148. for (int i = 0; i < runCount1; i++)
  1149. {
  1150. DateTime for_sp_startDt = sp_startDt;
  1151. DateTime for_sp_endDt = sp_startDt.AddDays(30);
  1152. sp_startDt = sp_startDt.AddDays(30);
  1153. if (for_sp_endDt >= sp_endDt)
  1154. {
  1155. for_sp_endDt = sp_endDt;
  1156. }
  1157. ApprovalInfo_Request approvalInfoReq = new ApprovalInfo_Request()
  1158. {
  1159. access_token = access_Token.access_token,
  1160. starttime = (uint)ConvertToTimeSpan(for_sp_startDt),
  1161. endtime = (uint)ConvertToTimeSpan(for_sp_endDt),
  1162. filters = filters.ToList(),
  1163. };
  1164. var json = System.Text.Json.JsonSerializer.Serialize(approvalInfoReq);
  1165. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1166. var create_Req = await _httpClient.PostAsync(url, content);
  1167. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1168. ApprovalInfoView approvalInfoView1 = System.Text.Json.JsonSerializer.Deserialize<ApprovalInfoView>(stringResponse,
  1169. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1170. #region 分页调用 new_next_cursor != null
  1171. string new_cursor = approvalInfoView1.new_next_cursor;
  1172. while (!string.IsNullOrEmpty(new_cursor))
  1173. {
  1174. approvalInfoReq.new_cursor = new_cursor;
  1175. var json1 = System.Text.Json.JsonSerializer.Serialize(approvalInfoReq);
  1176. var content1 = new StringContent(json, Encoding.UTF8, "application/json");
  1177. var create_Req1 = await _httpClient.PostAsync(url, content1);
  1178. var stringResponse1 = await create_Req1.Content.ReadAsStringAsync();
  1179. ApprovalInfoView approvalInfoView11 = System.Text.Json.JsonSerializer.Deserialize<ApprovalInfoView>(stringResponse1,
  1180. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1181. if (approvalInfoView11.errcode != 0)
  1182. {
  1183. return approvalInfoView1;
  1184. }
  1185. new_cursor = approvalInfoView11.new_next_cursor;
  1186. if (approvalInfoView11.sp_no_list.Count > 0 || approvalInfoView11.sp_no_list != null)
  1187. {
  1188. sp_no_lists.AddRange(approvalInfoView1.sp_no_list);
  1189. }
  1190. }
  1191. #endregion
  1192. if (approvalInfoView1.errcode != 0)
  1193. {
  1194. return approvalInfoView1;
  1195. }
  1196. if (approvalInfoView1.sp_no_list.Count > 0 || approvalInfoView1.sp_no_list != null)
  1197. {
  1198. sp_no_lists.AddRange(approvalInfoView1.sp_no_list);
  1199. }
  1200. }
  1201. approvalInfoView.errcode = 0;
  1202. if (sp_no_lists.Count > 0)
  1203. {
  1204. sp_no_lists = sp_no_lists.Distinct().ToList();
  1205. }
  1206. approvalInfoView.sp_no_list = sp_no_lists;
  1207. sw.Stop();
  1208. approvalInfoView.errmsg = approvalInfoView.errmsg + " 耗时:" + sw.Elapsed.TotalMilliseconds + "ms";
  1209. return approvalInfoView;
  1210. }
  1211. public async Task<ApprovalInfoView> GetApprovalInfoUpdateAsync(
  1212. DateTime startTime,
  1213. DateTime endTime,
  1214. string newCursor = "",
  1215. int size = 100,
  1216. List<IQiYeWeChatApiService.FilterCondition> filters = null)
  1217. {
  1218. //申请人企业微信Id验证
  1219. var creator = filters?.FirstOrDefault(f => f.key == "creator")?.value ?? "";
  1220. if (string.IsNullOrEmpty(creator))
  1221. {
  1222. return new ApprovalInfoView
  1223. {
  1224. errcode = -1,
  1225. errmsg = "OA用户信息中未填写申请人企业微信ID!"
  1226. };
  1227. }
  1228. long starttime = (long)(startTime - _1970).TotalSeconds;
  1229. long endtime = (long)(endTime - _1970).TotalSeconds;
  1230. var requestData = new
  1231. {
  1232. starttime = starttime,
  1233. endtime = endtime,
  1234. new_cursor = newCursor,
  1235. size = size,
  1236. filters = filters ?? new List<IQiYeWeChatApiService.FilterCondition>()
  1237. };
  1238. string jsonContent = JsonConvert.SerializeObject(requestData);
  1239. var httpContent = new StringContent(jsonContent, Encoding.UTF8, "application/json");
  1240. var token = await GetTokenAsync(5);
  1241. try
  1242. {
  1243. string url = "/cgi-bin/oa/getapprovalinfo?access_token=" + token.access_token;
  1244. HttpResponseMessage response = await _httpClient.PostAsync(url, httpContent);
  1245. response.EnsureSuccessStatusCode();
  1246. string responseContent = await response.Content.ReadAsStringAsync();
  1247. var result = JsonConvert.DeserializeObject<ApprovalInfoView>(responseContent);
  1248. return result;
  1249. }
  1250. catch (Exception ex)
  1251. {
  1252. ApprovalInfoView approvalInfoView = new ApprovalInfoView();
  1253. approvalInfoView.errcode = -1;
  1254. approvalInfoView.errmsg = ex.Message;
  1255. return approvalInfoView;
  1256. }
  1257. }
  1258. /// <summary>
  1259. /// 获取审批申请详情
  1260. /// </summary>
  1261. /// <param name="sp_no"></param>
  1262. /// <returns></returns>
  1263. public async Task<ApprovalDetailView> GetApprovalDetailAsync(string sp_no)
  1264. {
  1265. ApprovalDetailView ApprovalDetailView = new ApprovalDetailView();
  1266. if (string.IsNullOrEmpty(sp_no))
  1267. {
  1268. return ApprovalDetailView;
  1269. }
  1270. //获取审批数据 token
  1271. Access_TokenView access_Token = await GetTokenAsync(5);
  1272. if (access_Token.errcode != 0)
  1273. {
  1274. ApprovalDetailView.errcode = access_Token.errcode;
  1275. ApprovalDetailView.errmsg = string.Format("【企业微信】【审批申请详情】【Token】【Msg】{0}", access_Token.errmsg);
  1276. return ApprovalDetailView;
  1277. }
  1278. string url = string.Format("/cgi-bin/oa/getapprovaldetail?access_token={0}", access_Token.access_token);
  1279. ApprovalDetail_Request approvalDetail_Req = new ApprovalDetail_Request()
  1280. {
  1281. access_token = access_Token.access_token,
  1282. sp_no = sp_no,
  1283. };
  1284. var json = System.Text.Json.JsonSerializer.Serialize(approvalDetail_Req);
  1285. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1286. var create_Req = await _httpClient.PostAsync(url, content);
  1287. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1288. ApprovalDetailView = System.Text.Json.JsonSerializer.Deserialize<ApprovalDetailView>(stringResponse,
  1289. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1290. return ApprovalDetailView;
  1291. }
  1292. /// <summary>
  1293. /// 批量获取审批详情
  1294. /// </summary>
  1295. /// <param name="startDt"></param>
  1296. /// <param name="endDt"></param>
  1297. /// <param name="creator">
  1298. /// 申请人
  1299. /// </param>
  1300. /// <param name="sp_status">
  1301. /// sp_status-审批单状态(1-审批中;2-已通过;3-已驳回;4-已撤销;6-通过后撤销;7-已删除;10-已支付)
  1302. /// </param>
  1303. /// <param name="record_type">
  1304. /// record_type - 审批单类型属性,1-请假;2-打卡补卡;3-出差;4-外出;5-加班; 6- 调班;7-会议室预定;8-退款审批;9-红包报销审批
  1305. /// </param>
  1306. /// <returns></returns>
  1307. public async Task<List<Sp_Detail>> GetApprovalDetailsAsync(DateTime startDt, DateTime endDt, string creator, int sp_status, int record_type)
  1308. {
  1309. Stopwatch sw = new Stopwatch();
  1310. sw.Start();
  1311. List<Sp_Detail> details = new List<Sp_Detail>();
  1312. if (string.IsNullOrEmpty(creator))
  1313. {
  1314. return details;
  1315. }
  1316. ApprovalInfoView approvalInfoView = new ApprovalInfoView();
  1317. approvalInfoView = await GetApprovalInfoAsync(startDt, endDt, creator, sp_status, record_type);
  1318. if (approvalInfoView.errcode != 0)
  1319. {
  1320. return details;
  1321. }
  1322. //循环查询详情
  1323. foreach (var item in approvalInfoView.sp_no_list)
  1324. {
  1325. ApprovalDetailView approvalDetailView = new ApprovalDetailView();
  1326. approvalDetailView = await GetApprovalDetailAsync(item);
  1327. if (approvalDetailView.errcode != 0)
  1328. {
  1329. Log.Error("【GetApprovalDetailsAsync】 record_type:" + record_type + " ErrorMsg:" + approvalDetailView.errmsg);
  1330. break;
  1331. }
  1332. details.Add(approvalDetailView.info);
  1333. }
  1334. sw.Stop();
  1335. double hs = sw.Elapsed.TotalMilliseconds;
  1336. return details;
  1337. }
  1338. /// <summary>
  1339. /// 获取审批模板详情
  1340. /// </summary>
  1341. /// <param name="template_id">模板Id</param>
  1342. /// <returns></returns>
  1343. public async Task<TemplateDetailView> GetTemplateDetailAsync(string template_id)
  1344. {
  1345. TemplateDetailView templateDetailView = new TemplateDetailView();
  1346. if (string.IsNullOrEmpty(template_id))
  1347. {
  1348. templateDetailView.errmsg = "template_id为空!";
  1349. return templateDetailView;
  1350. }
  1351. //获取审批数据 token
  1352. Access_TokenView access_Token = await GetTokenAsync(5);
  1353. if (access_Token.errcode != 0)
  1354. {
  1355. templateDetailView.errcode = access_Token.errcode;
  1356. templateDetailView.errmsg = string.Format("【企业微信】【审批申请详情】【Token】【Msg】{0}", access_Token.errmsg);
  1357. return templateDetailView;
  1358. }
  1359. string url = string.Format("/cgi-bin/oa/gettemplatedetail?access_token={0}", access_Token.access_token);
  1360. var approvalDetail_Req = new
  1361. {
  1362. access_token = access_Token.access_token,
  1363. template_id = template_id,
  1364. };
  1365. var json = System.Text.Json.JsonSerializer.Serialize(approvalDetail_Req);
  1366. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1367. var create_Req = await _httpClient.PostAsync(url, content);
  1368. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1369. templateDetailView = System.Text.Json.JsonSerializer.Deserialize<TemplateDetailView>(stringResponse,
  1370. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1371. return templateDetailView;
  1372. }
  1373. #endregion
  1374. #region 汇报
  1375. /// <summary>
  1376. /// 批量获取汇报记录单号
  1377. /// </summary>
  1378. /// <param name="startTime">开始时间</param>
  1379. /// <param name="endTime">结束时间</param>
  1380. /// <param name="cursor"></param>
  1381. /// <param name="limit"></param>
  1382. /// <param name="filters"></param>
  1383. /// <returns></returns>
  1384. public async Task<JournalRecordListView> GetJournalRecordListAsync(DateTime startTime, DateTime endTime, int cursor = 0, int limit = 10, List<JournalFilter> filters = null)
  1385. {
  1386. JournalRecordListView result = new JournalRecordListView();
  1387. long starttime = (long)(startTime - _1970).TotalSeconds;
  1388. long endtime = (long)(endTime - _1970).TotalSeconds;
  1389. //获取汇报数据 token (Type = 7)
  1390. Access_TokenView access_Token = await GetTokenAsync(7);
  1391. if (access_Token.errcode != 0)
  1392. {
  1393. result.errcode = access_Token.errcode;
  1394. result.errmsg = string.Format("【企业微信】【获取汇报记录单号】【Token】【Msg】{0}", access_Token.errmsg);
  1395. return result;
  1396. }
  1397. string url = string.Format("/cgi-bin/oa/journal/get_record_list?access_token={0}", access_Token.access_token);
  1398. JournalRecordList_Request req = new JournalRecordList_Request()
  1399. {
  1400. starttime = starttime,
  1401. endtime = endtime,
  1402. cursor = cursor,
  1403. limit = limit,
  1404. filters = filters
  1405. };
  1406. var options = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
  1407. options.Converters.Add(new JsonStringEnumConverter());
  1408. var json = System.Text.Json.JsonSerializer.Serialize(req, options);
  1409. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1410. var create_Req = await _httpClient.PostAsync(url, content);
  1411. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1412. result = System.Text.Json.JsonSerializer.Deserialize<JournalRecordListView>(stringResponse,
  1413. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1414. return result;
  1415. }
  1416. /// <summary>
  1417. /// 获取汇报记录详情
  1418. /// </summary>
  1419. /// <param name="journaluuid"></param>
  1420. /// <returns></returns>
  1421. public async Task<JournalDetailView> GetJournalRecordDetailAsync(string journaluuid)
  1422. {
  1423. JournalDetailView result = new JournalDetailView();
  1424. if (string.IsNullOrEmpty(journaluuid))
  1425. {
  1426. result.errmsg = "journaluuid为空!";
  1427. return result;
  1428. }
  1429. //获取汇报数据 token (Type = 7)
  1430. Access_TokenView access_Token = await GetTokenAsync(7);
  1431. if (access_Token.errcode != 0)
  1432. {
  1433. result.errcode = access_Token.errcode;
  1434. result.errmsg = string.Format("【企业微信】【获取汇报详情】【Token】【Msg】{0}", access_Token.errmsg);
  1435. return result;
  1436. }
  1437. string url = string.Format("/cgi-bin/oa/journal/get_record_detail?access_token={0}", access_Token.access_token);
  1438. var req = new
  1439. {
  1440. journaluuid = journaluuid
  1441. };
  1442. var json = System.Text.Json.JsonSerializer.Serialize(req);
  1443. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1444. var create_Req = await _httpClient.PostAsync(url, content);
  1445. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1446. result = System.Text.Json.JsonSerializer.Deserialize<JournalDetailView>(stringResponse,
  1447. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1448. return result;
  1449. }
  1450. #endregion
  1451. #region hook机器人
  1452. /// <summary>
  1453. /// 发送团组信息给财务群
  1454. /// </summary>
  1455. /// <param name="msg"></param>
  1456. /// <returns></returns>
  1457. /// <exception cref="NotImplementedException"></exception>
  1458. public async Task<ResponseBase> RobotSendMsg_GroupInfo(string msg)
  1459. {
  1460. string key = "b4fe152f-a97a-48b1-830f-ab447f6d2f5f";
  1461. string url = string.Format("/cgi-bin/webhook/send?key={0}", key);
  1462. RobotSendMsg_GroupInfo_Content contentStr = new RobotSendMsg_GroupInfo_Content() { content = msg };
  1463. RobotSendMsg_GroupInfo_Param reqJson = new RobotSendMsg_GroupInfo_Param()
  1464. {
  1465. msgtype = "markdown",
  1466. markdown = contentStr
  1467. };
  1468. var json = System.Text.Json.JsonSerializer.Serialize(reqJson);
  1469. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1470. var create_Req = await _httpClient.PostAsync(url, content);
  1471. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1472. ResponseBase sendMsgView = System.Text.Json.JsonSerializer.Deserialize<ResponseBase>(stringResponse,
  1473. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1474. return sendMsgView;
  1475. }
  1476. #endregion
  1477. #region 团组状态通知
  1478. /// <summary>
  1479. /// 获取部门成员
  1480. /// </summary>
  1481. /// <param name="departmentId"></param>
  1482. /// <returns></returns>
  1483. public async Task<GroupStatus_UserSimplelistView> GroupStatus_GetUserList(int departmentId = 8402038)
  1484. {
  1485. GroupStatus_UserSimplelistView result = new GroupStatus_UserSimplelistView();
  1486. Access_TokenView access_Token = await GetTokenAsync(6);
  1487. if (access_Token.errcode != 0)
  1488. {
  1489. result.errcode = access_Token.errcode;
  1490. result.errmsg = string.Format("【企业微信】【团组状态通知】【Token】【Msg】{0}", access_Token.errmsg);
  1491. return result;
  1492. }
  1493. string url = string.Format("/cgi-bin/user/simplelist?access_token={0}&department_id={1}", access_Token.access_token, departmentId);
  1494. var simplelist_Req = await _httpClient.GetAsync(url);
  1495. if (simplelist_Req.IsSuccessStatusCode)
  1496. {
  1497. var stringResponse = await simplelist_Req.Content.ReadAsStringAsync();
  1498. result = System.Text.Json.JsonSerializer.Deserialize<GroupStatus_UserSimplelistView>(stringResponse,
  1499. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1500. }
  1501. else
  1502. {
  1503. result.errcode = -1;
  1504. result.errmsg = "企业微信部门列表未获取到!";
  1505. }
  1506. return result;
  1507. }
  1508. /// <summary>
  1509. /// 创建群聊
  1510. /// </summary>
  1511. /// <param name="chatName"></param>
  1512. /// <param name="owner"></param>
  1513. /// <param name="userList"></param>
  1514. /// <param name="chatId"></param>
  1515. /// <returns></returns>
  1516. public async Task<GroupStatus_CreateChatView> GroupStatus_CreateChat(string chatName, string owner, List<string> userList, string chatId)
  1517. {
  1518. GroupStatus_CreateChatView result = new GroupStatus_CreateChatView();
  1519. Access_TokenView access_Token = await GetTokenAsync(6);
  1520. if (access_Token.errcode != 0)
  1521. {
  1522. result.errcode = access_Token.errcode;
  1523. result.errmsg = string.Format("【企业微信】【团组状态通知】【Token】【Msg】{0}", access_Token.errmsg);
  1524. return result;
  1525. }
  1526. GroupStatus_CreateChat reqJson = new GroupStatus_CreateChat()
  1527. {
  1528. chatid = chatId,
  1529. name = chatName,
  1530. owner = owner,
  1531. userlist = userList
  1532. };
  1533. string url = string.Format("/cgi-bin/appchat/create?access_token={0}&debug=1", access_Token.access_token);
  1534. var json = System.Text.Json.JsonSerializer.Serialize(reqJson);
  1535. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1536. var create_Req = await _httpClient.PostAsync(url, content);
  1537. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1538. result = System.Text.Json.JsonSerializer.Deserialize<GroupStatus_CreateChatView>(stringResponse,
  1539. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1540. return result;
  1541. }
  1542. /// <summary>
  1543. /// 向群聊发送信息
  1544. /// </summary>
  1545. /// <param name="chatId"></param>
  1546. /// <param name="msgContent"></param>
  1547. /// <param name="msgType"></param>
  1548. /// <returns></returns>
  1549. /// <exception cref="NotImplementedException"></exception>
  1550. public async Task<ResponseBase> GroupStatus_SendChatMsg_Markdown(string chatId, string msgContent, string msgType = "markdown")
  1551. {
  1552. ResponseBase result = new ResponseBase();
  1553. Access_TokenView access_Token = await GetTokenAsync(6);
  1554. if (access_Token.errcode != 0)
  1555. {
  1556. result.errcode = access_Token.errcode;
  1557. result.errmsg = string.Format("【企业微信】【团组状态通知】【Token】【Msg】{0}", access_Token.errmsg);
  1558. return result;
  1559. }
  1560. RobotSendMsg_GroupInfo_Content markdown = new RobotSendMsg_GroupInfo_Content() { content = msgContent };
  1561. GroupStatus_AppChatSend_Markdown reqJson = new GroupStatus_AppChatSend_Markdown()
  1562. {
  1563. chatid = chatId,
  1564. msgtype = msgType,
  1565. markdown = markdown
  1566. };
  1567. string url = string.Format("/cgi-bin/appchat/send?access_token={0}", access_Token.access_token);
  1568. var json = System.Text.Json.JsonSerializer.Serialize(reqJson);
  1569. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1570. var create_Req = await _httpClient.PostAsync(url, content);
  1571. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1572. result = System.Text.Json.JsonSerializer.Deserialize<ResponseBase>(stringResponse,
  1573. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1574. return result;
  1575. }
  1576. /// <summary>
  1577. /// 向用户发送Markdown信息
  1578. /// </summary>
  1579. /// <param name="toUser"></param>
  1580. /// <param name="msgContent"></param>
  1581. /// <param name="msgType"></param>
  1582. /// <returns></returns>
  1583. /// <exception cref="NotImplementedException"></exception>
  1584. public async Task<GroupStatus_SendMessageView> GroupStatus_SendMessage_ToUser_Markdown(List<string> toUser, string msgContent, string msgType = "markdown")
  1585. {
  1586. GroupStatus_SendMessageView result = new GroupStatus_SendMessageView();
  1587. Access_TokenView access_Token = await GetTokenAsync(6);
  1588. if (access_Token.errcode != 0)
  1589. {
  1590. result.errcode = access_Token.errcode;
  1591. result.errmsg = string.Format("【企业微信】【团组状态通知】【Token】【Msg】{0}", access_Token.errmsg);
  1592. return result;
  1593. }
  1594. RobotSendMsg_GroupInfo_Content markdown = new RobotSendMsg_GroupInfo_Content() { content = msgContent };
  1595. string userIds = "";
  1596. toUser.ForEach(s => userIds += s + "|");
  1597. userIds = userIds.TrimEnd('|');
  1598. GroupStatus_AppSend_Markdown reqJson = new GroupStatus_AppSend_Markdown()
  1599. {
  1600. markdown = markdown,
  1601. touser = userIds
  1602. };
  1603. string url = string.Format("/cgi-bin/message/send?access_token={0}&debug=1", access_Token.access_token);
  1604. var json = System.Text.Json.JsonSerializer.Serialize(reqJson);
  1605. var content = new StringContent(json, Encoding.UTF8, "application/json");
  1606. var create_Req = await _httpClient.PostAsync(url, content);
  1607. var stringResponse = await create_Req.Content.ReadAsStringAsync();
  1608. result = System.Text.Json.JsonSerializer.Deserialize<GroupStatus_SendMessageView>(stringResponse,
  1609. new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
  1610. return result;
  1611. }
  1612. #endregion
  1613. public long ConvertToTimeSpan(DateTime dt)
  1614. {
  1615. return (dt.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
  1616. }
  1617. }
  1618. }