/*********************************************************************** * Project: baifenBinfa * ProjectName: 百分兵法管理系统 * Web: http://chuanyin.com * Author: * Email: * CreateTime: 202403/02 * Description: 暂无 ***********************************************************************/ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using System.Web; using CoreCms.Net.Caching.AccressToken; using CoreCms.Net.Configuration; using CoreCms.Net.IRepository.UnitOfWork; using CoreCms.Net.IServices; using CoreCms.Net.Model.Entities; using CoreCms.Net.Model.ViewModels.UI; using CoreCms.Net.Utility.Extensions; using CoreCms.Net.Utility.Helper; using CoreCms.Net.WeChat.Service.Enums; using CoreCms.Net.WeChat.Service.HttpClients; using CoreCms.Net.WeChat.Service.Options; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; using SKIT.FlurlHttpClient.Wechat.Api; using SKIT.FlurlHttpClient.Wechat.Api.Models; namespace CoreCms.Net.Services { /// /// 表单 接口实现 /// public class CoreCmsShareServices : BaseServices, ICoreCmsShareServices { private readonly IUnitOfWork _unitOfWork; private readonly IWebHostEnvironment _webHostEnvironment; private readonly string _appInterFaceUrl = AppSettingsConstVars.AppConfigAppInterFaceUrl; private readonly ICoreCmsGoodsServices _goodsServices; private readonly ICoreCmsSolitaireServices _solitaireServices; private readonly ICoreCmsUserServices _userServices; private readonly WeChatOptions _weChatOptions; private readonly WeChat.Service.HttpClients.IWeChatApiHttpClientFactory _weChatApiHttpClientFactory; public CoreCmsShareServices(IUnitOfWork unitOfWork , IWebHostEnvironment webHostEnvironment , ICoreCmsGoodsServices goodsServices , IOptions weChatOptions, IWeChatApiHttpClientFactory weChatApiHttpClientFactory, ICoreCmsSolitaireServices solitaireServices, ICoreCmsUserServices userServices) { _unitOfWork = unitOfWork; _webHostEnvironment = webHostEnvironment; _goodsServices = goodsServices; _weChatApiHttpClientFactory = weChatApiHttpClientFactory; _solitaireServices = solitaireServices; _userServices = userServices; _weChatOptions = weChatOptions.Value; } #region 二维码分享 /// /// 二维码分享 /// /// /// /// /// /// /// public async Task QrShare(int client, int page, int userShareCode, string url, JObject parameter) { var res = GetCode(client, page, userShareCode, url, parameter); if (!res.status) { return res; } return await getQr(url, res.otherData.ToString(), client); } private async Task getQr(string url, string code, int client) { var jm = new WebApiCallBack() { status = true }; switch (client) { case (int)GlobalEnumVars.UrlShareClentType.Wxmnapp: jm = await GetQrCode(code, url); break; default: var urlStr = GetUrl(url, code); urlStr = HttpUtility.UrlEncode(urlStr); break; } return jm; } #endregion #region 页面分享UrlShare /// /// 页面分享 /// /// /// /// /// /// /// public WebApiCallBack UrlShare(int client, int page, int userShareCode, string url, JObject parameter) { var res = GetCode(client, page, userShareCode, url, parameter); if (!res.status) { return res; } res.data = GetUrl(url, res.otherData.ToString()); return res; } #endregion #region 二维码生成 /// /// 二维码生成 /// /// /// /// /// /// /// /// /// public async Task GetParameterQrCode(string invite = "", int type = 1, string id = "", string groupId = "", string teamId = "", List style = null, string page = "pages/share/jump") { var jm = new WebApiCallBack() { status = false, msg = "获取失败" }; var styles = style != null && style.Any() ? string.Join("-", style.ToArray()) : ""; var nameStr = CommonHelper.Md5For32(page + invite + type + id + groupId + teamId + _weChatOptions.WxOpenAppId + styles); //QrCode 根目录 var dir = "/static/qrCode/weChat/"; //文件虚拟目录 var fileName = dir + nameStr + ".jpg"; //文件硬地址 var qrCodeDir = _webHostEnvironment.WebRootPath + dir; //QrCode 根目录 var pathFileName = qrCodeDir + nameStr + ".jpg"; //QrCode 根目录 if (File.Exists(pathFileName)) { //有这个二维码了 jm.status = true; jm.msg = "二维码获取成功"; jm.data = _appInterFaceUrl + fileName; } else { //没有去官方请求生成 var scene = string.Empty; if (type == 1) { //商品详情页 if (!string.IsNullOrEmpty(invite)) { scene = ShareHelper.share_parameter_encode("2", invite, id, ""); } else { scene = ShareHelper.share_parameter_encode("2", "", id, ""); } } else if (type == 2) { //首页 if (!string.IsNullOrEmpty(invite)) { scene = ShareHelper.share_parameter_encode("3", invite, "", ""); } else { scene = ShareHelper.share_parameter_encode("3", "", "", ""); } } else if (type == 3) { //拼团 if (!string.IsNullOrEmpty(invite)) { scene = ShareHelper.share_parameter_encode("5", invite, id, !string.IsNullOrEmpty(teamId) ? teamId : ""); } else { scene = ShareHelper.share_parameter_encode("5", "", id, !string.IsNullOrEmpty(teamId) ? teamId : ""); } } else if (type == 4) { //店铺首页 scene = ShareHelper.share_parameter_encode("9", !string.IsNullOrEmpty(invite) ? invite : "", id, ""); } else { //默认首页 scene = ShareHelper.share_parameter_encode("3", !string.IsNullOrEmpty(invite) ? invite : "", "", ""); } //没有去官方请求生成 var ms = new MemoryStream(); var accessToken = WeChatCacheAccessTokenHelper.GetWxOpenAccessToken(); var client = _weChatApiHttpClientFactory.CreateWxOpenClient(); var request = new WxaGetWxaCodeUnlimitRequest(); request.AccessToken = accessToken; request.Scene = scene; request.PagePath = page; request.LineColor = new WxaGetWxaCodeUnlimitRequest.Types.Color() { Red = 221, Blue = 51, Green = 238 }; var response = await client.ExecuteWxaGetWxaCodeUnlimitAsync(request); if (response.IsSuccessful()) { ms = new MemoryStream(response.RawBytes); } else { if (response.ErrorCode == (int)WeChatReturnCode.ReturnCode.page不正确) { jm.msg = "后台小程序配置的APPID和APPSECRET对应的小程序未发布上线,或者page没有发布,无法生成海报"; return jm; } else if (response.IsSuccessful() && response.ErrorCode == (int)WeChatReturnCode.ReturnCode.获取access_token时AppSecret错误或者access_token无效) { jm.msg = "微信小程序access_token已过期,无法为你生成海报"; return jm; } else { var enumType = EnumHelper.GetEnumberEntity(response.ErrorCode); if (enumType != null) { jm.msg = response.ErrorCode + enumType.title; } return jm; } } //QrCode 根目录 if (!Directory.Exists(qrCodeDir)) { Directory.CreateDirectory(qrCodeDir); } await using FileStream fs = System.IO.File.Create(pathFileName); await ms.CopyToAsync(fs); fs.Flush(); jm.status = true; jm.msg = "二维码生成成功"; jm.data = AppSettingsConstVars.AppConfigAppInterFaceUrl + fileName; jm.otherData = response; } return jm; } #endregion #region 小程序二维码,和业务没关系【GetQrCode】 /// /// 小程序二维码,和业务没关系 /// /// /// /// public async Task GetQrCode(string scene, string page = "pages/share/jump") { var jm = new WebApiCallBack(); jm.otherData = scene; var fileNameStr = CommonHelper.Md5For32(scene) + CommonHelper.Msectime(); //QrCode 根目录 var dir = "/static/qrCode/weChat/"; //文件虚拟目录 var fileName = dir + fileNameStr + ".jpg"; //文件硬地址 var qrCodeDir = _webHostEnvironment.WebRootPath + dir; //QrCode 文件全路径 var pathFileName = qrCodeDir + fileNameStr + ".jpg"; var fileNameMin = fileNameStr + ".jpg"; if (File.Exists(pathFileName)) { jm.status = true; jm.msg = "二维码获取成功"; jm.data = _appInterFaceUrl + fileName; jm.otherData = fileNameMin; } else { //没有去官方请求生成 var ms = new MemoryStream(); var accessToken = WeChatCacheAccessTokenHelper.GetWxOpenAccessToken(); var client = _weChatApiHttpClientFactory.CreateWxOpenClient(); var request = new WxaGetWxaCodeUnlimitRequest(); request.AccessToken = accessToken; request.Scene = scene; request.PagePath = page; request.LineColor = new WxaGetWxaCodeUnlimitRequest.Types.Color() { Red = 221, Blue = 51, Green = 238 }; var response = await client.ExecuteWxaGetWxaCodeUnlimitAsync(request); if (!response.IsSuccessful() && response.ErrorCode == (int)WeChatReturnCode.ReturnCode.page不正确) { jm.msg = "后台小程序配置的APPID和APPSECRET对应的小程序未发布上线,或者page没有发布,无法生成海报"; return jm; } else if (!response.IsSuccessful() && response.ErrorCode == (int)WeChatReturnCode.ReturnCode.获取access_token时AppSecret错误或者access_token无效) { jm.msg = "微信小程序access_token已过期,无法为你生成海报"; return jm; } else if (!response.IsSuccessful() && response.ErrorCode > 0) { var enumType = EnumHelper.GetEnumberEntity(response.ErrorCode); if (enumType != null) { jm.msg = response.ErrorCode + enumType.title; } return jm; } else { ms = new MemoryStream(response.RawBytes); } //QrCode 根目录 if (!Directory.Exists(qrCodeDir)) { Directory.CreateDirectory(qrCodeDir); } FileStream fs = new FileStream(pathFileName, FileMode.OpenOrCreate); BinaryWriter w = new BinaryWriter(fs); w.Write(ms.ToArray()); fs.Close(); ms.Close(); jm.status = true; jm.msg = "GetQrCode"; jm.data = AppSettingsConstVars.AppConfigAppInterFaceUrl + fileName; jm.otherData = response; } return jm; } #endregion #region 获得分享的Code【GetCode】 /// /// 获得分享的code /// /// /// /// /// /// /// private static WebApiCallBack GetCode(int client, int page, int userShareCode, string url, JObject parameter) { //检查params参数是否正确 WebApiCallBack result = en_params(page, parameter); if (!result.status) { return result; } var code = en_url(page, userShareCode, result.data.ToString()); result.otherData = code; return result; } #endregion #region 根据获得的code,拼接url【GetUrl】 /// /// 根据获得的code,拼接url /// /// /// /// private static string GetUrl(string url, string code) { return url + "?scene=" + code; } #endregion #region url参数加密【en_url】 /// /// url参数加密 /// /// /// /// /// private static string en_url(int page, int userShareCode, string paramsStr) { return page + "-" + userShareCode + "-" + paramsStr; } #endregion #region url参数解密【de_url】 /// /// url参数解密 /// /// /// public WebApiCallBack de_url(string code) { //3-3702-2032_0 var jm = new WebApiCallBack(); var arr = code.Split("-"); if (arr.Length != 3) { return jm; } var page = arr[0]; var userShareCode = arr[1]; var paramsResult = de_params(Convert.ToInt16(arr[0]), arr[2]); if (paramsResult.status) { jm.status = true; jm.data = new { page, userShareCode, @params = paramsResult.data }; } else { paramsResult.otherData = code; return paramsResult; } return jm; } #endregion #region 检查参数,拼接参数【en_params】 /// /// 检查参数,拼接参数 /// /// /// /// private static WebApiCallBack en_params(int page, JObject parameter) { var jm = new WebApiCallBack(); var str = ""; switch (page) { case (int)GlobalEnumVars.UrlSharePageType.Index: break; case (int)GlobalEnumVars.UrlSharePageType.Goods: if (parameter.ContainsKey("goodsId")) { str = parameter["goodsId"]?.ToString(); } else { jm.msg = "参数必须传goodsId"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.PinTuan: if (parameter.ContainsKey("teamId") && parameter.ContainsKey("groupId")) { str = parameter["groupId"] + "_" + parameter["teamId"]; } else { jm.msg = "参数必须传goodsId,teamId,groupId"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.Inv: if (parameter.ContainsKey("store")) { str = parameter["store"]?.ToString(); } else { jm.msg = "参数必须传store"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.Article: if (parameter.ContainsKey("articleId") || parameter.ContainsKey("articleType")) { str = parameter["articleId"] + "_" + parameter["articleType"]; } else { jm.msg = "参数必须传articleId,articleType"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.AddPinTuan: if (parameter.ContainsKey("groupId") && parameter.ContainsKey("teamId")) { str = parameter["groupId"] + "_" + parameter["teamId"]; } else { jm.msg = "参数必须传goodsId,groupId,teamId"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.Page: if (parameter.ContainsKey("pageCode")) { str = parameter["pageCode"]?.ToString(); } else { jm.msg = "参数必须传pageCode"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.Form: if (parameter.ContainsKey("id")) { str = parameter["id"]?.ToString(); } else { jm.msg = "参数必须传id"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.Group: if (parameter.ContainsKey("groupId")) { str = parameter["groupId"].ToString(); } else { jm.msg = "参数必须传groupId"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.Seckill: if (parameter.ContainsKey("groupId")) { str = parameter["groupId"].ToString(); } else { jm.msg = "参数必须传groupId"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.Agent: if (parameter.ContainsKey("store")) { str = parameter["store"]?.ToString(); } else { jm.msg = "参数必须传store"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.Solitaire: if (parameter.ContainsKey("id")) { str = parameter["id"]?.ToString(); } else { jm.msg = "参数必须传id"; return jm; } break; case (int)GlobalEnumVars.UrlSharePageType.ServiceGoods: if (parameter.ContainsKey("serviceGoodsId")) { str = parameter["serviceGoodsId"]?.ToString(); } else { jm.msg = "参数必须传id"; return jm; } break; default: jm.msg = GlobalErrorCodeVars.Code10000; return jm; } jm.status = true; jm.data = str; return jm; } #endregion #region 解码参数【de_params】 /// /// 解码参数 /// /// /// /// private static WebApiCallBack de_params(int page, string parameter) { var jm = new WebApiCallBack(); var arr = parameter.Split("_"); switch (page) { case (int)GlobalEnumVars.UrlSharePageType.Index: jm.status = true; break; case (int)GlobalEnumVars.UrlSharePageType.Goods: if (arr.Length == 1) { jm.data = new { goodsId = arr[0] }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.PinTuan: if (arr.Length == 2) { jm.data = new { groupId = arr[0], teamId = arr[1] }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.Inv: if (arr.Length == 1) { jm.data = new { store = arr[0] }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.Article: if (arr.Length == 2) { jm.data = new { articleId = arr[0], articleType = arr[1], }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.AddPinTuan: if (arr.Length == 2) { jm.data = new { groupId = arr[0], teamId = arr[1] }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.Page: if (arr.Length == 1) { jm.data = new { pageCode = arr[0] }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.Form: if (arr.Length == 1) { jm.data = new { id = arr[0] }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.Group: if (arr.Length == 1) { jm.data = new { groupId = arr[0], }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.Seckill: if (arr.Length == 1) { jm.data = new { groupId = arr[0], }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.Agent: if (arr.Length == 1) { jm.data = new { store = arr[0] }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.Solitaire: if (arr.Length == 1) { jm.data = new { id = arr[0] }; jm.status = true; } break; case (int)GlobalEnumVars.UrlSharePageType.ServiceGoods: if (arr.Length == 1) { jm.data = new { serviceGoodsId = arr[0] }; jm.status = true; } break; default: jm.msg = GlobalErrorCodeVars.Code10000; return jm; } return jm; } #endregion } }