| @ -0,0 +1,76 @@ | |||||
| | |||||
| using Forks.EnterpriseServices; | |||||
| using Forks.Utils.Configuration; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using TSingSoft.WebPluginFramework; | |||||
| namespace BWP.B3WeChat | |||||
| { | |||||
| [ConfigurationEnabled] | |||||
| public class B3WeChatConfig | |||||
| { | |||||
| public B3WeChatConfig() | |||||
| { | |||||
| ConfigurationUtil.Fill(this); | |||||
| } | |||||
| StringConfigRef mToken = new StringConfigRef(string.Empty); | |||||
| [LogicName("微信Token")] | |||||
| public StringConfigRef Token | |||||
| { | |||||
| get | |||||
| { | |||||
| return mToken; | |||||
| } | |||||
| set | |||||
| { | |||||
| mToken = value; | |||||
| } | |||||
| } | |||||
| StringConfigRef mAppID = new StringConfigRef(string.Empty); | |||||
| [LogicName("微信AppID")] | |||||
| public StringConfigRef AppID | |||||
| { | |||||
| get | |||||
| { | |||||
| return mAppID; | |||||
| } | |||||
| set | |||||
| { | |||||
| mAppID = value; | |||||
| } | |||||
| } | |||||
| StringConfigRef mAppSecret = new StringConfigRef(string.Empty); | |||||
| [LogicName("微信AppSecret")] | |||||
| public StringConfigRef AppSecret | |||||
| { | |||||
| get | |||||
| { | |||||
| return mAppSecret; | |||||
| } | |||||
| set | |||||
| { | |||||
| mAppSecret = value; | |||||
| } | |||||
| } | |||||
| StringConfigRef mSelfAppID = new StringConfigRef(string.Empty); | |||||
| [LogicName("微信SelfAppID")] | |||||
| public StringConfigRef SelfAppID | |||||
| { | |||||
| get | |||||
| { | |||||
| return mSelfAppID; | |||||
| } | |||||
| set | |||||
| { | |||||
| mSelfAppID = value; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,15 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| namespace BWP.B3WeChat.BO | |||||
| { | |||||
| class CustomerUser | |||||
| { | |||||
| public string CustomerNumber { get; set; } | |||||
| public string Username { get; set; } | |||||
| public string WeixinUsername { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,40 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using Forks.EnterpriseServices; | |||||
| using Forks.EnterpriseServices.DataForm; | |||||
| using TSingSoft.WebPluginFramework; | |||||
| using Forks.EnterpriseServices.DomainObjects2; | |||||
| namespace BWP.B3WeChat.BO | |||||
| { | |||||
| [LogicName("二维码场景信息")] | |||||
| [Serializable] | |||||
| [DFClass] | |||||
| [BOClass] | |||||
| [KeyField("ID", KeyGenType.identity)] | |||||
| public class QRCodeScene | |||||
| { | |||||
| [LogicName("场景ID")] | |||||
| public int ID { get; set; } | |||||
| [LogicName("客户")] | |||||
| [DFNotEmpty] | |||||
| public string Customer { get; set; } | |||||
| [LogicName("用户")] | |||||
| [DFNotEmpty] | |||||
| public string UserId { get; set; } | |||||
| [LogicName("微信号关注ID")] | |||||
| public int OppenId { get; set; } | |||||
| [LogicName("QRCode图片")] | |||||
| public string Path { get; set; } | |||||
| [LogicName("QRCode过期时间")] | |||||
| public DateTime? OutTime { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,13 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| public class ErrorObject | |||||
| { | |||||
| public string errcode { get; set; } | |||||
| public string errmsg { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,32 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| using System.Xml.Serialization; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| [XmlRoot("xml")] | |||||
| [Serializable] | |||||
| public class EventType | |||||
| { | |||||
| /// <summary> | |||||
| /// 事件类型,event | |||||
| /// </summary> | |||||
| [XmlElement("Event")] | |||||
| public string Event { get; set; } | |||||
| } | |||||
| /// <summary> | |||||
| /// 事件类型 | |||||
| /// </summary> | |||||
| public static class EvtType | |||||
| { | |||||
| public static string 订阅 { get { return "subscribe"; } } | |||||
| public static string 取消订阅 { get { return "unsubscribe"; } } | |||||
| public static string 扫描带参数二维码 { get { return "SCAN"; } } | |||||
| public static string 上报地理位置 { get { return "LOCATION"; } } | |||||
| public static string 点击菜单拉取消息 { get { return "CLICK"; } } | |||||
| public static string 点击菜单跳转链接 { get { return "VIEW"; } } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,35 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| /// <summary> | |||||
| /// 发送信息模板主体 | |||||
| /// </summary> | |||||
| public class MeassageBody | |||||
| { | |||||
| /// <summary> | |||||
| /// 接收者openid | |||||
| /// </summary> | |||||
| public string touser { get; set; } | |||||
| /// <summary> | |||||
| /// 模板ID | |||||
| /// </summary> | |||||
| public string template_id { get; set; } | |||||
| /// <summary> | |||||
| /// 模板跳转链接 | |||||
| /// </summary> | |||||
| public string url { get; set; } | |||||
| /// <summary> | |||||
| /// 模板数据 | |||||
| /// </summary> | |||||
| public Dictionary<string, ValueColor> data { get; set; } | |||||
| } | |||||
| public class ValueColor | |||||
| { | |||||
| public string value { get; set; } | |||||
| public string color { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,24 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| using System.Xml.Serialization; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| [XmlRoot("xml")] | |||||
| [Serializable] | |||||
| public class MessageType | |||||
| { | |||||
| /// <summary> | |||||
| /// 消息类型,event | |||||
| /// </summary> | |||||
| [XmlElement("MsgType")] | |||||
| public string MsgType { get; set; } | |||||
| } | |||||
| public static class MsgType | |||||
| { | |||||
| public static string 文本 { get { return "text"; } } | |||||
| public static string 事件 { get { return "event"; } } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,27 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| /// <summary> | |||||
| /// OpenID接收到的OpenID对象 | |||||
| /// </summary> | |||||
| public class OpenIDObject | |||||
| { | |||||
| /// <summary> | |||||
| /// 关注该公众账号的总用户数 | |||||
| /// </summary> | |||||
| public int total { get; set; } | |||||
| /// <summary> | |||||
| /// 拉取的OPENID个数,最大值为10000 | |||||
| /// </summary> | |||||
| public int count { get; set; } | |||||
| public OpenIDList data { get; set; } | |||||
| } | |||||
| public class OpenIDList | |||||
| { | |||||
| public List<string> openid { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,25 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| /// <summary> | |||||
| /// 二维码参数 | |||||
| /// </summary> | |||||
| public class QRCodeArgs | |||||
| { | |||||
| public int expire_seconds { get; set; } | |||||
| public string action_name { get; set; } | |||||
| public QRCodeScene action_info { get; set; } | |||||
| } | |||||
| public class QRCodeScene | |||||
| { | |||||
| public QRCodeSceneID scene { get; set; } | |||||
| } | |||||
| public class QRCodeSceneID | |||||
| { | |||||
| public int scene_id { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,52 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| using System.Xml.Serialization; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| /// <summary> | |||||
| /// 扫描带参数二维码信息 | |||||
| /// </summary> | |||||
| [XmlRoot("xml")] | |||||
| [Serializable] | |||||
| public class QRCodeMessage | |||||
| { | |||||
| /// <summary> | |||||
| /// 开发者微信号 | |||||
| /// </summary> | |||||
| [XmlElement("ToUserName")] | |||||
| public string ToUserName { get; set; } | |||||
| /// <summary> | |||||
| /// 发送方帐号(一个OpenID) | |||||
| /// </summary> | |||||
| [XmlElement("FromUserName")] | |||||
| public string FromUserName { get; set; } | |||||
| /// <summary> | |||||
| /// 消息创建时间 (整型) | |||||
| /// </summary> | |||||
| [XmlElement("CreateTime")] | |||||
| public string CreateTime { get; set; } | |||||
| /// <summary> | |||||
| /// 消息类型,event | |||||
| /// </summary> | |||||
| [XmlElement("MsgType")] | |||||
| public string MsgType { get; set; } | |||||
| /// <summary> | |||||
| /// 事件类型,SCAN | |||||
| /// </summary> | |||||
| [XmlElement("Event")] | |||||
| public string Event { get; set; } | |||||
| /// <summary> | |||||
| /// 创建二维码时的二维码scene_id | |||||
| /// </summary> | |||||
| [XmlElement("EventKey")] | |||||
| public string EventKey { get; set; } | |||||
| /// <summary> | |||||
| /// 二维码的ticket,可用来换取二维码图片 | |||||
| /// </summary> | |||||
| [XmlElement("Ticket")] | |||||
| public string Ticket { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,14 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| public class QRCodeResult | |||||
| { | |||||
| public string ticket { get; set; } | |||||
| public int expire_seconds { get; set; } | |||||
| public string url { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,47 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| using System.Xml.Serialization; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| /// <summary> | |||||
| /// 普通消息(文本消息) | |||||
| /// </summary> | |||||
| [XmlRoot("xml")] | |||||
| [Serializable] | |||||
| public class ReceivedMsg | |||||
| { | |||||
| /// <summary> | |||||
| /// 开发者微信号 | |||||
| /// </summary> | |||||
| [XmlElement("ToUserName")] | |||||
| public string ToUserName { get; set; } | |||||
| /// <summary> | |||||
| /// 发送方帐号(一个OpenID) | |||||
| /// </summary> | |||||
| [XmlElement("FromUserName")] | |||||
| public string FromUserName { get; set; } | |||||
| /// <summary> | |||||
| /// 消息创建时间 (整型) | |||||
| /// </summary> | |||||
| [XmlElement("CreateTime")] | |||||
| public string CreateTime { get; set; } | |||||
| /// <summary> | |||||
| /// 消息类型,event | |||||
| /// </summary> | |||||
| [XmlElement("MsgType")] | |||||
| public string MsgType { get; set; } | |||||
| /// <summary> | |||||
| /// 文本消息内容 | |||||
| /// </summary> | |||||
| [XmlElement("Content")] | |||||
| public string Content { get; set; } | |||||
| /// <summary> | |||||
| /// 消息id,64位整型 | |||||
| /// </summary> | |||||
| [XmlElement("MsgId")] | |||||
| public string MsgId { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,42 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| using System.Xml.Serialization; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| /// <summary> | |||||
| /// 回复文本消息 | |||||
| /// </summary> | |||||
| [XmlRoot("xml")] | |||||
| [Serializable] | |||||
| public class ReplyMsg | |||||
| { | |||||
| /// <summary> | |||||
| /// 接收方帐号(收到的OpenID) | |||||
| /// </summary> | |||||
| [XmlElement("ToUserName")] | |||||
| public string ToUserName { get; set; } | |||||
| /// <summary> | |||||
| /// 开发者微信号 | |||||
| /// </summary> | |||||
| [XmlElement("FromUserName")] | |||||
| public string FromUserName { get; set; } | |||||
| /// <summary> | |||||
| /// 消息创建时间 (整型) | |||||
| /// </summary> | |||||
| [XmlElement("CreateTime")] | |||||
| public string CreateTime { get; set; } | |||||
| /// <summary> | |||||
| /// 消息类型,event | |||||
| /// </summary> | |||||
| [XmlElement("MsgType")] | |||||
| public string MsgType { get; set; } | |||||
| /// <summary> | |||||
| /// 文本消息内容 | |||||
| /// </summary> | |||||
| [XmlElement("Content")] | |||||
| public string Content { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,17 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| /// <summary> | |||||
| /// 发送模板信息返回结果 | |||||
| /// </summary> | |||||
| public class SendTemplateMessageResult | |||||
| { | |||||
| public string errcode { get; set; } | |||||
| public string errmsg { get; set; } | |||||
| public int msgid { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,16 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| /// <summary> | |||||
| /// Token对象 | |||||
| /// </summary> | |||||
| public class TokenObject | |||||
| { | |||||
| public string access_token { get; set; } | |||||
| public string expires_in { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,68 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| public class UserBasicInfo | |||||
| { | |||||
| /// <summary> | |||||
| /// 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。默认为1 | |||||
| /// </summary> | |||||
| public int subscribe { get; set; } | |||||
| /// <summary> | |||||
| /// 用户的标识,对当前公众号唯一 | |||||
| /// </summary> | |||||
| public string openid { get; set; } | |||||
| /// <summary> | |||||
| /// 用户的昵称 | |||||
| /// </summary> | |||||
| public string nickname { get; set; } | |||||
| /// <summary> | |||||
| /// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 | |||||
| /// </summary> | |||||
| public int sex { get; set; } | |||||
| /// <summary> | |||||
| /// 用户所在城市 | |||||
| /// </summary> | |||||
| public string language { get; set; } | |||||
| /// <summary> | |||||
| /// 用户所在国家 | |||||
| /// </summary> | |||||
| public string city { get; set; } | |||||
| /// <summary> | |||||
| /// 用户所在省份 | |||||
| /// </summary> | |||||
| public string province { get; set; } | |||||
| /// <summary> | |||||
| /// 用户的语言,简体中文为zh_CN | |||||
| /// </summary> | |||||
| public string country { get; set; } | |||||
| /// <summary> | |||||
| /// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。 | |||||
| /// </summary> | |||||
| public string headimgurl { get; set; } | |||||
| /// <summary> | |||||
| /// 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间 | |||||
| /// </summary> | |||||
| public int subscribe_time { get; set; } | |||||
| /// <summary> | |||||
| /// 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。 | |||||
| /// </summary> | |||||
| public string unionid { get; set; } | |||||
| /// <summary> | |||||
| /// 公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注 | |||||
| /// </summary> | |||||
| public string remark { get; set; } | |||||
| /// <summary> | |||||
| /// 用户所在的分组ID(兼容旧的用户分组接口) | |||||
| /// </summary> | |||||
| public int groupid { get; set; } | |||||
| /// <summary> | |||||
| /// 用户被打上的标签ID列表 | |||||
| /// </summary> | |||||
| public List<int> tagid_list { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,12 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| namespace BWP.B3WeChat.Entities | |||||
| { | |||||
| public class WeiChartServerList | |||||
| { | |||||
| public List<string> ip_list { get; set; } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,147 @@ | |||||
| using Bwp.MainSystem.BO; | |||||
| using BWP.B3WeChat.BO; | |||||
| using BWP.B3WeChat.Utils; | |||||
| using Forks.EnterpriseServices.DomainObjects2; | |||||
| using Forks.EnterpriseServices.DomainObjects2.DQuery; | |||||
| using Forks.EnterpriseServices.JsonRpc; | |||||
| using Forks.EnterpriseServices.SqlDoms; | |||||
| using Forks.Utils; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.IO; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using TSingSoft.WebPluginFramework; | |||||
| namespace BWP.B3WeChat.Rpcs | |||||
| { | |||||
| [Rpc] | |||||
| public static class ClientRpc | |||||
| { | |||||
| static string GetDeviceNumber() | |||||
| { | |||||
| var user = BLContext.User; | |||||
| var query = new DQueryDom(new JoinAlias(typeof(DeviceAuthentication))); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("Ticket", user.UserTag.ToString("N"))); | |||||
| query.Columns.Add(DQSelectColumn.Field("DeviceNumber")); | |||||
| query.Range = SelectRange.Top(1); | |||||
| var deviceNumber = query.EExecuteScalar<string>(); | |||||
| return deviceNumber; | |||||
| } | |||||
| [Rpc] | |||||
| public static void Send(string username, string content) | |||||
| { | |||||
| string oppenid = GetOpenId(username).ToString(); | |||||
| string[] param = content.Split('|'); | |||||
| switch (param[0]) | |||||
| { | |||||
| case "SendAgentInfo": SendMessageUtil.SendAgentInfo(oppenid, param[1], param[2], param[3], param[4]); break; | |||||
| } | |||||
| } | |||||
| static int GetOpenId(string username) | |||||
| { | |||||
| string customer = GetDeviceNumber(); | |||||
| var query = new DQueryDom(new JoinAlias(typeof(QRCodeScene))); | |||||
| query.Columns.Add(DQSelectColumn.Field("OppenId")); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("Customer", customer)); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("UserId", username)); | |||||
| query.Range = SelectRange.Top(1); | |||||
| var OppenId = query.EExecuteScalar<int?>(); | |||||
| if (!OppenId.HasValue) | |||||
| { | |||||
| throw new Exception("未找到该微信用户或者" + username + "未关联微信"); | |||||
| } | |||||
| return OppenId.Value; | |||||
| } | |||||
| [Rpc] | |||||
| public static String GetQRCodeUrl(string username) | |||||
| { | |||||
| string url = string.Empty; | |||||
| string customer = GetDeviceNumber(); | |||||
| if (string.IsNullOrEmpty(customer)) | |||||
| return url; | |||||
| url = ExistQRCode(customer, username); | |||||
| if (!string.IsNullOrEmpty(url)) | |||||
| { | |||||
| return url; | |||||
| } | |||||
| int sceneId = GetSceneId(customer, username); | |||||
| string ticket = InOutMessageUtil.GenerateEQCode(30, sceneId); | |||||
| string name = DateTime.Now.Ticks.ToString() + ".jpg"; | |||||
| string path = GetQRCodeDir() + name; | |||||
| InOutMessageUtil.GetQRPic(ticket, path); | |||||
| url = "/QRCodePic/" + name; | |||||
| UpdateQRCode(sceneId, url); | |||||
| return url; | |||||
| } | |||||
| static void UpdateQRCode(int sceneId, string path) | |||||
| { | |||||
| var update = new DQUpdateDom(typeof(QRCodeScene)); | |||||
| update.Where.Conditions.Add(DQCondition.EQ("ID", sceneId)); | |||||
| update.Columns.Add(new DQUpdateColumn("Path", path)); | |||||
| update.Columns.Add(new DQUpdateColumn("OutTime", DateTime.Now.AddDays(30))); | |||||
| using (var session = Dmo.NewSession()) | |||||
| { | |||||
| session.ExecuteNonQuery(update); | |||||
| } | |||||
| } | |||||
| static string ExistQRCode(string customer, string username) | |||||
| { | |||||
| string path = string.Empty; | |||||
| var query = new DQueryDom(new JoinAlias(typeof(QRCodeScene))); | |||||
| query.Columns.Add(DQSelectColumn.Field("Path")); | |||||
| query.Columns.Add(DQSelectColumn.Field("OutTime")); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("Customer", customer)); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("UserId", username)); | |||||
| query.Range = SelectRange.Top(1); | |||||
| var result = query.EExecuteScalar<string, DateTime?>(); | |||||
| if (result.Item2.HasValue && result.Item2.Value > DateTime.Now) | |||||
| { | |||||
| path = result.Item1; | |||||
| } | |||||
| return path; | |||||
| } | |||||
| static int GetSceneId(string customer, string username) | |||||
| { | |||||
| var query = new DQueryDom(new JoinAlias(typeof(QRCodeScene))); | |||||
| query.Columns.Add(DQSelectColumn.Field("ID")); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("Customer", customer)); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("UserId", username)); | |||||
| query.Range = SelectRange.Top(1); | |||||
| var sceneId = query.EExecuteScalar<int?>(); | |||||
| if (!sceneId.HasValue) | |||||
| { | |||||
| using (var session = Dmo.NewSession()) | |||||
| { | |||||
| QRCodeScene newSence = new QRCodeScene() | |||||
| { | |||||
| Customer = customer, | |||||
| UserId = username, | |||||
| }; | |||||
| session.Insert(newSence); | |||||
| session.Commit(); | |||||
| sceneId = newSence.ID; | |||||
| } | |||||
| } | |||||
| return sceneId.Value; | |||||
| } | |||||
| static string GetQRCodeDir() | |||||
| { | |||||
| string dir = System.Environment.CurrentDirectory + "/QRCodePic/"; | |||||
| if (!Directory.Exists(dir)) | |||||
| { | |||||
| Directory.CreateDirectory(dir); | |||||
| } | |||||
| return dir; | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,101 @@ | |||||
| using Bwp.MainSystem.BO; | |||||
| using BWP.B3WeChat.BO; | |||||
| using BWP.B3WeChat.Utils; | |||||
| using Forks.EnterpriseServices.DomainObjects2; | |||||
| using Forks.EnterpriseServices.DomainObjects2.DQuery; | |||||
| using Forks.EnterpriseServices.JsonRpc; | |||||
| using Forks.EnterpriseServices.SqlDoms; | |||||
| using Forks.Utils; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.IO; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using TSingSoft.WebPluginFramework; | |||||
| namespace BWP.B3WeChat.Rpcs | |||||
| { | |||||
| [Rpc] | |||||
| public static class ClientRpc | |||||
| { | |||||
| static string GetDeviceNumber() | |||||
| { | |||||
| var user = BLContext.User; | |||||
| var query = new DQueryDom(new JoinAlias(typeof(DeviceAuthentication))); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("Ticket", user.UserTag.ToString("N"))); | |||||
| query.Columns.Add(DQSelectColumn.Field("DeviceNumber")); | |||||
| query.Range = SelectRange.Top(1); | |||||
| var deviceNumber = query.EExecuteScalar<string>(); | |||||
| return deviceNumber; | |||||
| } | |||||
| [Rpc] | |||||
| public static void Send(String message, string username) | |||||
| { | |||||
| } | |||||
| [Rpc] | |||||
| public static String GetQRCodeUrl(string username) | |||||
| { | |||||
| string url = string.Empty; | |||||
| string customer = GetDeviceNumber(); | |||||
| if (string.IsNullOrEmpty(customer)) | |||||
| return url; | |||||
| string ticket = InOutMessageUtil.GenerateEQCode(30, GetSceneId(customer, username)); | |||||
| string name=DateTime.Now.Ticks.ToString() + ".jpg"; | |||||
| string path = GetQRCodeDir() + name; | |||||
| InOutMessageUtil.GetQRPic(ticket, path); | |||||
| return url; | |||||
| } | |||||
| static string ExistQRCode(string customer, string username) | |||||
| { | |||||
| var query = new DQueryDom(new JoinAlias(typeof(QRCodeScene))); | |||||
| query.Columns.Add(DQSelectColumn.Field("Path")); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("Customer", customer)); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("UserId", username)); | |||||
| query.Where.Conditions.Add(DQCondition.GreaterThan(DQExpression.Field("OutTime"), DQExpression.Value(DateTime.Now))); | |||||
| query.Range = SelectRange.Top(1); | |||||
| var path = query.EExecuteScalar<string>(); | |||||
| return path; | |||||
| } | |||||
| static int GetSceneId(string customer, string username) | |||||
| { | |||||
| var query = new DQueryDom(new JoinAlias(typeof(QRCodeScene))); | |||||
| query.Columns.Add(DQSelectColumn.Field("ID")); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("Customer", customer)); | |||||
| query.Where.Conditions.Add(DQCondition.EQ("UserId", username)); | |||||
| query.Range = SelectRange.Top(1); | |||||
| var sceneId = query.EExecuteScalar<int?>(); | |||||
| if (!sceneId.HasValue) | |||||
| { | |||||
| using (var session = Dmo.NewSession()) | |||||
| { | |||||
| QRCodeScene newSence = new QRCodeScene() | |||||
| { | |||||
| Customer = customer, | |||||
| UserId = username, | |||||
| }; | |||||
| session.Insert(newSence); | |||||
| session.Commit(); | |||||
| sceneId = newSence.ID; | |||||
| } | |||||
| } | |||||
| return sceneId.Value; | |||||
| } | |||||
| static string GetQRCodeDir() | |||||
| { | |||||
| string dir = System.Environment.CurrentDirectory + "/QRCodePic/"; | |||||
| if (!Directory.Exists(dir)) | |||||
| { | |||||
| Directory.CreateDirectory(dir); | |||||
| } | |||||
| return dir; | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,288 @@ | |||||
| using BWP.B3WeChat; | |||||
| using BWP.B3WeChat.Entities; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.IO; | |||||
| using System.Linq; | |||||
| using System.Net; | |||||
| using System.Text; | |||||
| using System.Web; | |||||
| using System.Web.Script.Serialization; | |||||
| using System.Web.Security; | |||||
| namespace BWP.B3WeChat.Utils | |||||
| { | |||||
| public static class InOutMessageUtil | |||||
| { | |||||
| static string token; | |||||
| static string TOKEN | |||||
| { | |||||
| get | |||||
| { | |||||
| if (string.IsNullOrEmpty(token)) | |||||
| { | |||||
| token = GetToken(); | |||||
| } | |||||
| return token; | |||||
| } | |||||
| } | |||||
| public static B3WeChatConfig config = new B3WeChatConfig(); | |||||
| public static string GetToken() | |||||
| { | |||||
| string token = string.Empty; | |||||
| string uriStr = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", config.AppID, config.AppSecret); | |||||
| WebClient client = new WebClient(); | |||||
| try | |||||
| { | |||||
| byte[] bytes = client.DownloadData(uriStr); | |||||
| string responseBody = Encoding.UTF8.GetString(bytes); | |||||
| JavaScriptSerializer jsonHelper = new JavaScriptSerializer(); | |||||
| TokenObject obj = jsonHelper.Deserialize<TokenObject>(responseBody); | |||||
| if (obj != null) | |||||
| { | |||||
| token = obj.access_token; | |||||
| } | |||||
| } | |||||
| catch (Exception e) | |||||
| { | |||||
| throw e; | |||||
| } | |||||
| return token; | |||||
| } | |||||
| public static WeiChartServerList GetIPList() | |||||
| { | |||||
| WeiChartServerList result = new WeiChartServerList(); | |||||
| string uriStr = string.Format("https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token={0}", TOKEN); | |||||
| WebClient client = new WebClient(); | |||||
| try | |||||
| { | |||||
| byte[] bytes = client.DownloadData(uriStr); | |||||
| string responseBody = Encoding.UTF8.GetString(bytes); | |||||
| JavaScriptSerializer jsonHelper = new JavaScriptSerializer(); | |||||
| result = jsonHelper.Deserialize<WeiChartServerList>(responseBody); | |||||
| } | |||||
| catch (Exception e) | |||||
| { | |||||
| throw e; | |||||
| } | |||||
| return result; | |||||
| } | |||||
| public static SendTemplateMessageResult SendTemplateMessage(string openID, string templateID, Dictionary<string, ValueColor> dic, string url = "") | |||||
| { | |||||
| string uriStr = string.Format("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}", TOKEN); | |||||
| JavaScriptSerializer jsonHelper = new JavaScriptSerializer(); | |||||
| SendTemplateMessageResult result = new SendTemplateMessageResult(); | |||||
| MeassageBody body = new MeassageBody(); | |||||
| body.touser = openID; | |||||
| body.template_id = templateID; | |||||
| body.url = url; | |||||
| body.data = dic; | |||||
| string postData = jsonHelper.Serialize(body); | |||||
| string data = string.Empty; | |||||
| try | |||||
| { | |||||
| byte[] byteArray = Encoding.UTF8.GetBytes(postData); | |||||
| HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(new Uri(uriStr)); | |||||
| webRequest.Method = "post"; | |||||
| webRequest.ContentType = "application/x-www-form-urlencoded"; | |||||
| webRequest.ContentLength = byteArray.Length; | |||||
| System.IO.Stream newStream = webRequest.GetRequestStream(); | |||||
| newStream.Write(byteArray, 0, byteArray.Length); | |||||
| newStream.Close(); | |||||
| HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse(); | |||||
| data = new System.IO.StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")).ReadToEnd(); | |||||
| result = jsonHelper.Deserialize<SendTemplateMessageResult>(data); | |||||
| } | |||||
| catch (Exception e) | |||||
| { | |||||
| throw e; | |||||
| } | |||||
| return result; | |||||
| } | |||||
| public static List<string> GetOpenIDList() | |||||
| { | |||||
| string openid = string.Empty; | |||||
| string uriStr = string.Empty; | |||||
| List<string> lstOpenID = new List<string>(); | |||||
| JavaScriptSerializer jsonHelper = new JavaScriptSerializer(); | |||||
| OpenIDObject result = new OpenIDObject(); | |||||
| WebClient client = new WebClient(); | |||||
| try | |||||
| { | |||||
| do | |||||
| { | |||||
| uriStr = string.Format("https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}&next_openid={1}", TOKEN, openid); | |||||
| byte[] bytes = client.DownloadData(uriStr); | |||||
| string responseBody = Encoding.UTF8.GetString(bytes); | |||||
| result = jsonHelper.Deserialize<OpenIDObject>(responseBody); | |||||
| lstOpenID.AddRange(result.data.openid); | |||||
| openid = result.data.openid.Last(); | |||||
| } while (lstOpenID.Count < result.total); | |||||
| } | |||||
| catch (Exception e) | |||||
| { | |||||
| throw e; | |||||
| } | |||||
| return lstOpenID; | |||||
| } | |||||
| public static UserBasicInfo GetUserInfo(string openid) | |||||
| { | |||||
| string uriStr = string.Empty; | |||||
| List<string> lstOpenID = new List<string>(); | |||||
| JavaScriptSerializer jsonHelper = new JavaScriptSerializer(); | |||||
| UserBasicInfo result = new UserBasicInfo(); | |||||
| WebClient client = new WebClient(); | |||||
| try | |||||
| { | |||||
| uriStr = string.Format("https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN", TOKEN, openid); | |||||
| byte[] bytes = client.DownloadData(uriStr); | |||||
| string responseBody = Encoding.UTF8.GetString(bytes); | |||||
| result = jsonHelper.Deserialize<UserBasicInfo>(responseBody); | |||||
| } | |||||
| catch (Exception e) | |||||
| { | |||||
| throw e; | |||||
| } | |||||
| return result; | |||||
| } | |||||
| /// <summary> | |||||
| /// 接收消息 | |||||
| /// </summary> | |||||
| /// <param name="request"></param> | |||||
| /// <returns></returns> | |||||
| public static object GetMessage(HttpRequest request) | |||||
| { | |||||
| StreamReader reader = new StreamReader(request.InputStream); | |||||
| String xmlData = reader.ReadToEnd(); | |||||
| object obj = null; | |||||
| MessageType type = XmlUtil.Deserialize<MessageType>(xmlData); | |||||
| if (type.MsgType == MsgType.文本) | |||||
| { | |||||
| obj = XmlUtil.Deserialize<ReceivedMsg>(xmlData); | |||||
| } | |||||
| else if (type.MsgType == MsgType.事件) | |||||
| { | |||||
| obj = XmlUtil.Deserialize<QRCodeMessage>(xmlData); | |||||
| } | |||||
| return obj; | |||||
| } | |||||
| /// <summary> | |||||
| /// 验证微信签名 | |||||
| /// </summary> | |||||
| /// <returns></returns> | |||||
| /// * 将token、timestamp、nonce三个参数进行字典序排序 | |||||
| /// * 将三个参数字符串拼接成一个字符串进行sha1加密 | |||||
| /// * 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。 | |||||
| public static bool CheckSignature() | |||||
| { | |||||
| string WeChat_Token = config.Token;//从配置文件获取Token | |||||
| string WeChat_Key = HttpContext.Current.Request.QueryString["key"]; | |||||
| //从微信服务器接收传递过来的数据 | |||||
| string signature = HttpContext.Current.Request.QueryString["signature"]; //微信加密签名 | |||||
| string timestamp = HttpContext.Current.Request.QueryString["timestamp"];//时间戳 | |||||
| string nonce = HttpContext.Current.Request.QueryString["nonce"];//随机数 | |||||
| string[] ArrTmp = { WeChat_Token, timestamp, nonce }; | |||||
| Array.Sort(ArrTmp); //字典排序 | |||||
| string tmpStr = string.Join("", ArrTmp);//将三个字符串组成一个字符串 | |||||
| tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");//进行sha1加密 | |||||
| tmpStr = tmpStr.ToLower(); | |||||
| //加过密的字符串与微信发送的signature进行比较,一样则通过微信验证,否则失败。 | |||||
| if (tmpStr == signature) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| /// <summary> | |||||
| /// 生成临时二维码 | |||||
| /// </summary> | |||||
| /// <param name="days">二维码有效时间</param> | |||||
| /// <param name="arg">二维码参数</param> | |||||
| /// <returns></returns> | |||||
| public static string GenerateEQCode(int days, int arg) | |||||
| { | |||||
| string ticket = string.Empty; | |||||
| string uriStr = string.Format("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={0}", TOKEN); | |||||
| JavaScriptSerializer jsonHelper = new JavaScriptSerializer(); | |||||
| QRCodeResult result = new QRCodeResult(); | |||||
| QRCodeArgs body = new QRCodeArgs() | |||||
| { | |||||
| expire_seconds = 60 * 60 * 24 * days, | |||||
| action_name = "QR_SCENE", | |||||
| action_info = new QRCodeScene() | |||||
| { | |||||
| scene = new QRCodeSceneID() | |||||
| { | |||||
| scene_id = arg | |||||
| } | |||||
| } | |||||
| }; | |||||
| string postData = jsonHelper.Serialize(body); | |||||
| string data = string.Empty; | |||||
| try | |||||
| { | |||||
| byte[] byteArray = Encoding.UTF8.GetBytes(postData); | |||||
| HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(new Uri(uriStr)); | |||||
| webRequest.Method = "post"; | |||||
| webRequest.ContentType = "application/x-www-form-urlencoded"; | |||||
| webRequest.ContentLength = byteArray.Length; | |||||
| System.IO.Stream newStream = webRequest.GetRequestStream(); | |||||
| newStream.Write(byteArray, 0, byteArray.Length); | |||||
| newStream.Close(); | |||||
| HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse(); | |||||
| data = new System.IO.StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")).ReadToEnd(); | |||||
| result = jsonHelper.Deserialize<QRCodeResult>(data); | |||||
| } | |||||
| catch (Exception e) | |||||
| { | |||||
| throw e; | |||||
| } | |||||
| if (result != null && !string.IsNullOrEmpty(result.ticket)) | |||||
| { | |||||
| ticket = result.ticket; | |||||
| } | |||||
| return ticket; | |||||
| } | |||||
| /// <summary> | |||||
| /// 获取二维码图片 | |||||
| /// </summary> | |||||
| /// <param name="ticket">票据</param> | |||||
| /// <param name="path">图片保存路径</param> | |||||
| /// <returns></returns> | |||||
| public static void GetQRPic(string ticket, string path) | |||||
| { | |||||
| string uriStr = string.Format("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={0}", ticket); | |||||
| try | |||||
| { | |||||
| WebClient webClient = new WebClient(); | |||||
| webClient.DownloadFile(uriStr, path); | |||||
| } | |||||
| catch (Exception e) | |||||
| { | |||||
| throw e; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,30 @@ | |||||
| using BWP.B3WeChat.Entities; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| namespace BWP.B3WeChat.Utils | |||||
| { | |||||
| public static class SendMessageUtil | |||||
| { | |||||
| /// <summary> | |||||
| /// 发送代办信息 | |||||
| /// </summary> | |||||
| /// <param name="openid"></param> | |||||
| /// <param name="title">题目</param> | |||||
| /// <param name="todeal">事项</param> | |||||
| /// <param name="delay">未处理时间</param> | |||||
| /// <param name="remark">备注</param> | |||||
| /// <returns></returns> | |||||
| public static SendTemplateMessageResult SendAgentInfo(string openid, string title, string todeal, string delay, string remark) | |||||
| { | |||||
| Dictionary<string, ValueColor> dic = new Dictionary<string, ValueColor>(); | |||||
| dic.Add("first", new ValueColor() { value = title, color = "#173177" }); | |||||
| dic.Add("keyword1", new ValueColor() { value = todeal, color = "#173177" }); | |||||
| dic.Add("keyword2", new ValueColor() { value = delay, color = "#173177" }); | |||||
| dic.Add("remark", new ValueColor() { value = remark, color = "#173177" }); | |||||
| return InOutMessageUtil.SendTemplateMessage(openid, "uhy7GuF8zwBA6pjvjQWpn02fiKb0o9cq7dO5DWnUuMg", dic); | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,97 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.IO; | |||||
| using System.Linq; | |||||
| using System.Web; | |||||
| using System.Xml.Serialization; | |||||
| namespace BWP.B3WeChat.Utils | |||||
| { | |||||
| /// <summary> | |||||
| /// Xml序列化与反序列化 | |||||
| /// </summary> | |||||
| public class XmlUtil | |||||
| { | |||||
| #region 反序列化 | |||||
| /// <summary> | |||||
| /// 反序列化 | |||||
| /// </summary> | |||||
| /// <param name="type">类型</param> | |||||
| /// <param name="xml">XML字符串</param> | |||||
| /// <returns></returns> | |||||
| public static object Deserialize(Type type, string xml) | |||||
| { | |||||
| try | |||||
| { | |||||
| using (StringReader sr = new StringReader(xml)) | |||||
| { | |||||
| XmlSerializer xmldes = new XmlSerializer(type); | |||||
| return xmldes.Deserialize(sr); | |||||
| } | |||||
| } | |||||
| catch (Exception e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| /// <summary> | |||||
| /// 反序列化 | |||||
| /// </summary> | |||||
| /// <param name="type"></param> | |||||
| /// <param name="xml"></param> | |||||
| /// <returns></returns> | |||||
| public static object Deserialize(Type type, Stream stream) | |||||
| { | |||||
| XmlSerializer xmldes = new XmlSerializer(type); | |||||
| return xmldes.Deserialize(stream); | |||||
| } | |||||
| /// <summary> | |||||
| /// 反序列化 | |||||
| /// </summary> | |||||
| /// <typeparam name="T"></typeparam> | |||||
| /// <param name="xml"></param> | |||||
| /// <returns></returns> | |||||
| public static T Deserialize<T>(string xml) where T : class | |||||
| { | |||||
| Type type = typeof(T); | |||||
| return (Deserialize(type, xml) as T); | |||||
| } | |||||
| #endregion | |||||
| #region 序列化 | |||||
| /// <summary> | |||||
| /// 序列化 | |||||
| /// </summary> | |||||
| /// <param name="type">类型</param> | |||||
| /// <param name="obj">对象</param> | |||||
| /// <returns></returns> | |||||
| public static string Serializer(Type type, object obj) | |||||
| { | |||||
| MemoryStream Stream = new MemoryStream(); | |||||
| XmlSerializer xml = new XmlSerializer(type); | |||||
| XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces(); | |||||
| namespaces.Add(string.Empty, string.Empty); | |||||
| try | |||||
| { | |||||
| //序列化对象 | |||||
| xml.Serialize(Stream, obj, namespaces); | |||||
| } | |||||
| catch (InvalidOperationException) | |||||
| { | |||||
| throw; | |||||
| } | |||||
| Stream.Position = 0; | |||||
| StreamReader sr = new StreamReader(Stream); | |||||
| string str = sr.ReadToEnd(); | |||||
| sr.Dispose(); | |||||
| Stream.Dispose(); | |||||
| return str; | |||||
| } | |||||
| #endregion | |||||
| } | |||||
| } | |||||