QiYiWeiXinGlobalContext.cs 8.37 KB
using Hh.Mes.Common.config;
using Hh.Mes.Common.log;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Hh.Mes.Service.QiYeWeiXin
{
    /// <summary>
    /// 企业微信消息推送 上下文
    /// </summary>
    public class QiYiWeiXinGlobalContext
    {
        public IHttpClientFactory HttpClientFactory { get; set; }

        public QiYiWeiXinGlobalContext(IHttpClientFactory httpClientFactory)
        {
            HttpClientFactory = httpClientFactory;
        }

        /// <summary>
        /// 过期时间
        /// </summary>
        public static DateTime TimeOutDate { get; set; }

        /// <summary>
        /// Token
        /// </summary>
        public static string Token { get; set; }


        /// <summary>
        /// 获取Token
        /// </summary>
        /// <returns>Item1 Token;Item2 true 成功 false 失败</returns>
        public Tuple<string, bool> GetToken()
        {
            //判断Token是否存在 以及Token是否在有效期内
            if (string.IsNullOrEmpty(Token) || TimeOutDate < DateTime.Now)
            {
                //构造请求链接
                var requestBuild = ConfigRead.GetInstance.GetAppsetConnection().TokenUrl;
                using (var wxClient = HttpClientFactory.CreateClient("WxClient"))
                {
                    var httpResponse = wxClient.GetAsync(requestBuild).Result;
                    var dynamic = JsonConvert.DeserializeObject<QiYeWeiXinGetTokenResult>(httpResponse.Content.ReadAsStringAsync().Result);
                    if (dynamic.errcode == 0)
                    {
                        Token = dynamic.access_token;
                        // 预留10分钟安全缓冲期,提前刷新Token避免临界点失效
                        var expires_in = Convert.ToDouble(dynamic.expires_in - 10 * 60);
                        TimeOutDate = DateTime.Now.AddSeconds(expires_in);
                        return Tuple.Create(Token, true);
                    }
                    else
                    {
                        var msg = $"获取Token失败,错误:{dynamic.errmsg}";
                        Log4NetHelper.Instance.Error(msg);
                        return Tuple.Create(msg, false);
                    }
                }
            }
            else
            {
                return Tuple.Create(Token, true);
            }
        }

        /// <summary>
        /// 推送 msg
        /// </summary>
        /// <returns>Item1 Token;Item2 是否成功</returns>
        public Tuple<bool, string> SendMsg(string content)
        {
            //构造请求链接
            var requestBuild = ConfigRead.GetInstance.GetAppsetConnection().PushUrl;
            var (token, issuccess) = GetToken();
            if (!issuccess) throw new Exception(token);
            requestBuild = string.Format(requestBuild, token);
            //建立HttpClient
            using (var wxClient = HttpClientFactory.CreateClient("WxClient"))
            {
                byte[] data = Encoding.UTF8.GetBytes(content);
                var bytearray = new ByteArrayContent(data);
                var httpResponse = wxClient.PostAsync(requestBuild, bytearray).Result;
                var dynamic = JsonConvert.DeserializeObject<dynamic>(httpResponse.Content.ReadAsStringAsync().Result);
                if (dynamic.errcode == 0) return Tuple.Create(true, "ok");

                var msg = $"推送失败,原因:{JsonConvert.SerializeObject(dynamic)}";
                Log4NetHelper.Instance.Error(msg);
                return Tuple.Create(false, msg);
            }
        }

        /// <summary>
        /// 获取发送内容
        /// </summary>
        /// <param name="agentid"></param>
        /// <param name="userId">用户id</param>
        /// <param name="msgtype">文本类型</param>
        /// <param name="msg">文本信息</param>
        /// <param name="fileid">通过上传临时素材接口获取到的ID</param>
        /// <returns></returns>
        public static string GetContent(int agentid, string userId, string msgtype, string msg)
        {
            if (string.IsNullOrEmpty(userId)) userId = "@all";
            dynamic obj = null;
            if (msgtype == WxMsgType.File)
            {
                obj = new
                {
                    touser = userId,
                    toparty = "",
                    totag = "",
                    msgtype = msgtype,
                    agentid = agentid,
                    file = new
                    {
                        media_id = msg  // 文件需要media_id
                    },
                    safe = 0,
                    enable_id_trans = 0,
                    enable_duplicate_check = 0,
                    duplicate_check_interval = 1800
                };
            }
            else if (msgtype == WxMsgType.Text)
            {
                obj = new
                {
                    touser = userId,
                    toparty = "",
                    totag = "",
                    msgtype = msgtype,
                    agentid = agentid,
                    text = new
                    {
                        content = msg  // 文本需要content
                    },
                    safe = 0,
                    enable_id_trans = 0,
                    enable_duplicate_check = 0,
                    duplicate_check_interval = 1800
                };
            }
            string strJson = JsonConvert.SerializeObject(obj);
            return strJson;
        }


        /// <summary>
        /// 获取 AgentId
        /// </summary>
        /// <returns></returns>
        public static int GetAgentId()
        {
            var agentId = ConfigRead.GetInstance.GetAppsetConnection().AgentId;
            return int.Parse(agentId);
        }

        public string UploadFileToWeChatWorkAsync(string filePath)
        {
            // 实现企业微信文件上传逻辑 调用企微上传临时素材接口,拿到media_id 
            Tuple<string, bool> tuple = GetToken();
            if (tuple == null || !tuple.Item2)
            {
                return null;
            }
            var accessToken = tuple.Item1;
            WebClient client = null;
            try
            {
                string url = $"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={accessToken}&type=file";

                // 使用 WebClient(更简单)
                using (client = new WebClient())
                {
                    //byte[] fileData = File.ReadAllBytes(filePath);
                    //string fileName = Path.GetFileName(filePath);

                    // 添加文件
                    client.Headers.Add("Content-Type", "application/octet-stream");
                    byte[] response = client.UploadFile(url, filePath);
                    string jsonResponse = Encoding.UTF8.GetString(response);
                    dynamic result = JsonConvert.DeserializeObject<dynamic>(jsonResponse);

                    return result.errcode == 0 ? result.media_id : null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"上传失败: {ex.Message}");
                return null;
            }
            finally
            {
                client?.Dispose();
            }
        }


        //创建企业微信信息类型枚举,枚举值对应企业微信信息类型
        public static class WxMsgType
        {
            public const string Text = "text";
            public const string File = "file";
        }

        public async Task SendFileMessage(string mediaId)
        {
            // 实现企业微信消息发送逻辑
            var userId = ConfigRead.GetInstance.GetAppsetConnection().UserId ?? "";
            var content = GetContent(GetAgentId(), userId, WxMsgType.Text, $"IOT设备故障报告:推送项目近七天【{DateTime.Today.AddDays(-7)}~{DateTime.Now}】和本月故障汇总分钟数和妥善率,附件消息稍后推送请注意查收!");
            SendMsg(content);
            //间隔5s
            await Task.Delay(5000);
            var filecontent = GetContent(GetAgentId(), userId, WxMsgType.File, mediaId);
            SendMsg(filecontent);
        }
    }
}