diff --git a/WGShare.API/Controllers/Frontend/HomeController.cs b/WGShare.API/Controllers/Frontend/HomeController.cs index d2b6a4d..4b5215e 100644 --- a/WGShare.API/Controllers/Frontend/HomeController.cs +++ b/WGShare.API/Controllers/Frontend/HomeController.cs @@ -1,5 +1,6 @@ using AgoraIO.Media; using AgoraIO.Rtm; +using Azure; using Mapster; using Masuit.Tools; using Microsoft.AspNetCore.Mvc; @@ -8,10 +9,12 @@ using MiniExcelLibs.Attributes; using MiniExcelLibs.OpenXml; using SqlSugar; using System.IO; +using System.Net.Http.Headers; using System.Text.RegularExpressions; using WGShare.API.Controllers.Basic; using WGShare.API.Helpers; using WGShare.Domain.Constant; +using WGShare.Domain.DTOs.MiniProgram; using WGShare.Domain.DTOs.Room; using WGShare.Domain.Entities; using WGShare.Domain.Enums; @@ -35,6 +38,7 @@ namespace WGShare.API.Controllers.Frontend private readonly AgoraHelper _agoraHelper; private readonly ILogger _logger; private readonly OssHelper _ossHelper; + private readonly MiniProgramHelper _miniProgramHelper; public HomeController( ISqlSugarClient sqlSugar, @@ -42,7 +46,8 @@ namespace WGShare.API.Controllers.Frontend IHttpClientFactory httpClientFactory, AgoraHelper agoraHelper, ILogger logger, - OssHelper ossHelper) + OssHelper ossHelper, + MiniProgramHelper miniProgramHelper) { _sqlSugar = sqlSugar; this._configuration = configuration; @@ -50,6 +55,7 @@ namespace WGShare.API.Controllers.Frontend this._agoraHelper = agoraHelper; this._logger = logger; this._ossHelper = ossHelper; + this._miniProgramHelper = miniProgramHelper; } @@ -291,5 +297,58 @@ namespace WGShare.API.Controllers.Frontend _ossHelper.UploadWithExpireTime(fileName, stream, 10); return _ossHelper.GetAccessFileUrl(fileName, 5); } + + /// + /// 获取房间二维码(缓存10mins) + /// + /// + /// + [HttpGet("r-qrcode")] + public async Task GetMiniProgramQrCode([FromQuery] string roomNum, [FromQuery] string env = "release") + { + var img = RedisHelper.Instance.Get(RedisKeyConstant.WxMiniProgram.GetRoomQrCode(roomNum, env)); + if (!string.IsNullOrWhiteSpace(img)) + { + return img; + } + + var httpClient = _httpClientFactory.CreateClient(); + var accessToken = await _miniProgramHelper.GetAccessToken(); + + var result = await httpClient.PostAsync($@"https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={accessToken}", new StringContent(new wxacodeunlimitBody + { + page = "pages/form/index", + scene = ("r=" + roomNum), + check_path = true, + env_version = env, + width = 280 + }.ToJsonString())); + if (result == null || !result.IsSuccessStatusCode) + { + _logger.LogError($@"二维码生成失败,statusCode:{(int)result.StatusCode},content:{await result.Content.ReadAsStringAsync()}"); + throw Oops.Oh("二维码生成失败!"); + } + var contentType = result.Content.Headers.ContentType?.MediaType; + // 如果是图片类型 + if (contentType != null && contentType.StartsWith("image/")) + { + // 处理图片数据 + var imageArr = await result.Content.ReadAsByteArrayAsync(); + var imgStr = Convert.ToBase64String(imageArr); + RedisHelper.Instance.Set(RedisKeyConstant.WxMiniProgram.GetRoomQrCode(roomNum, env), imgStr, TimeSpan.FromMinutes(10)); + return imgStr; + } + else if (contentType != null && contentType.Contains("json")) + { + var apiResult = await result.Content.ReadFromJsonAsync(); + if (apiResult != null) + { + _logger.LogError($"二维码生成失败,errorCode:{apiResult.errorcode},errmsg:{apiResult.errmsg}"); + throw Oops.Oh("二维码生成失败"); + } + } + _logger.LogError("返回 ContentType 未命中"); + throw Oops.Oh("二维码生成失败"); + } } } diff --git a/WGShare.API/Helpers/MiniProgramHelper.cs b/WGShare.API/Helpers/MiniProgramHelper.cs new file mode 100644 index 0000000..e0cbde0 --- /dev/null +++ b/WGShare.API/Helpers/MiniProgramHelper.cs @@ -0,0 +1,59 @@ +using WGShare.Domain.Constant; +using WGShare.Domain.DTOs.MiniProgram; +using WGShare.Domain.FriendlyException; + +namespace WGShare.API.Helpers +{ + /// + /// 小程序帮助类 + /// + public class MiniProgramHelper + { + private readonly IConfiguration _configuration; + + public MiniProgramHelper(IConfiguration configuration) + { + this._configuration = configuration; + } + + /// + /// 获取access_token + /// + /// + public async Task GetAccessToken() + { + var accessToken = RedisHelper.Instance.Get(RedisKeyConstant.WxMiniProgram.AccessTokenKey); + if (!string.IsNullOrWhiteSpace(accessToken) ) + { + return accessToken; + } + + var appId = _configuration["miniProgram:appId"]; + var secret = _configuration["miniProgram:appSecret"]; + + using var httpClient = new HttpClient(); + + var result = await httpClient.GetAsync($@"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={secret}"); + if (result == null || !result.IsSuccessStatusCode) + { + Console.WriteLine($@"微信服务器授权失败,{result.StatusCode},{await result.Content.ReadAsStringAsync()}"); + throw Oops.Oh("微信服务器授权失败"); + } + var apiResult = await result.Content.ReadFromJsonAsync(); + if (apiResult == null) + { + Console.WriteLine($@"微信服务器授权失败,接口返回数据解析失败"); + throw Oops.Oh("微信服务器授权失败"); + } + if (apiResult.errorcode != 0) + { + Console.WriteLine($@"微信服务器授权失败,errorCode:{apiResult.errorcode},errmsg:{apiResult.errmsg}"); + throw Oops.Oh("微信服务器授权失败"); + } + + RedisHelper.Instance.Set(RedisKeyConstant.WxMiniProgram.AccessTokenKey, apiResult.access_token, TimeSpan.FromSeconds(apiResult.expires_in - 60)); + return apiResult.access_token; + } + + } +} diff --git a/WGShare.API/Program.cs b/WGShare.API/Program.cs index b7ff144..21adf8f 100644 --- a/WGShare.API/Program.cs +++ b/WGShare.API/Program.cs @@ -65,6 +65,7 @@ namespace WGShare.API builder.Services.ConfigureHangfire(); builder.Services.AddSingleton(new JwtHelper(configuration)); builder.Services.AddSingleton(new AgoraHelper(configuration)); + builder.Services.AddSingleton(new MiniProgramHelper(configuration)); builder.Services.AddSingleton(new OssHelper(configuration)); builder.Services.AddHostedService(); builder.Services.AddAuth(configuration["Jwt:Issuer"], diff --git a/WGShare.API/WGShare.API.xml b/WGShare.API/WGShare.API.xml index 82721a4..4f57dab 100644 --- a/WGShare.API/WGShare.API.xml +++ b/WGShare.API/WGShare.API.xml @@ -144,6 +144,13 @@ + + + 获取房间二维码 + + + + 会议室接口 @@ -471,6 +478,17 @@ + + + 小程序帮助类 + + + + + 获取access_token + + + 获取上传url diff --git a/WGShare.Domain/Constant/RedisKeyConstant.cs b/WGShare.Domain/Constant/RedisKeyConstant.cs index 04c0f77..f267828 100644 --- a/WGShare.Domain/Constant/RedisKeyConstant.cs +++ b/WGShare.Domain/Constant/RedisKeyConstant.cs @@ -86,5 +86,12 @@ namespace WGShare.Domain.Constant { public static string MeetingRecord => "meeting_record"; } + + public class WxMiniProgram + { + public static string AccessTokenKey => $@"wx_mini_program:accessToken"; + + public static string GetRoomQrCode(string roomNum, string env) => $@"wx_mini_program:room_qrcode:{env}:{roomNum}"; + } } } diff --git a/WGShare.Domain/DTOs/MiniProgram/AccessTokenApiResult.cs b/WGShare.Domain/DTOs/MiniProgram/AccessTokenApiResult.cs new file mode 100644 index 0000000..2118cc3 --- /dev/null +++ b/WGShare.Domain/DTOs/MiniProgram/AccessTokenApiResult.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.MiniProgram +{ + public class AccessTokenApiResult : WxMiniProgramBaseApiResult + { + public string access_token { get; set; } + public int expires_in { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/MiniProgram/WxMiniProgramBaseApiResult.cs b/WGShare.Domain/DTOs/MiniProgram/WxMiniProgramBaseApiResult.cs new file mode 100644 index 0000000..53cc6a4 --- /dev/null +++ b/WGShare.Domain/DTOs/MiniProgram/WxMiniProgramBaseApiResult.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.MiniProgram +{ + public class WxMiniProgramBaseApiResult + { + public int errorcode { get; set; } + public string errmsg { get; set; } + } +} diff --git a/WGShare.Domain/DTOs/MiniProgram/wxacodeunlimitBody.cs b/WGShare.Domain/DTOs/MiniProgram/wxacodeunlimitBody.cs new file mode 100644 index 0000000..a25eba9 --- /dev/null +++ b/WGShare.Domain/DTOs/MiniProgram/wxacodeunlimitBody.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WGShare.Domain.DTOs.MiniProgram +{ + public class wxacodeunlimitBody + { + public string scene { get; set; } + public string page { get; set; } + public bool check_path { get; set; } + public string env_version { get; set; } + public int width { get; set; } + + } +}