QiYeWeChatApiService.cs 84 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974
  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. }