using Nirvana.Common; using Nirvana.Common.ApiBase; using Nirvana.Data; using Senparc.Weixin.Open; using Senparc.Weixin.Open.Containers; using Senparc.Weixin.Open.WxaAPIs; using SqlSugar; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using YBDevice.Entity; namespace YBDevice.Service.DBServices { /// /// 公众号管理 /// public partial class OfficialApp : Repository { public string component_AppId = Senparc.Weixin.Config.SenparcWeixinSetting.Component_Appid; public string component_Secret = Senparc.Weixin.Config.SenparcWeixinSetting.Component_Secret; public string component_Token = Senparc.Weixin.Config.SenparcWeixinSetting.Component_Token; public string component_EncodingAESKey = Senparc.Weixin.Config.SenparcWeixinSetting.Component_EncodingAESKey; /// /// 公众号列表 /// /// /// 0-全部,1-公众号,2-小程序 /// public async Task> GetListAsync(QueryParams param, int type = 1) { RefAsync totalnum = 0; using (var dbClient = ReadDbContext.GetInstance()) { var currentUser = OperatorProvider.Provider.GetCurrent(); var temquery = dbClient.Queryable((s, c) => new JoinQueryInfos(JoinType.Left, s.authorizer_appid == c.AppId)); if (param.queryParam != null && param.queryParam.Count > 0) { List conModels = new List(); param.queryParam.ForEach(x => { if (!string.IsNullOrEmpty(x.Value)) { conModels.Add(new ConditionalModel() { FieldName = x.Name, ConditionalType = (ConditionalType)x.Type, FieldValue = x.Value.Trim() }); } }); if (conModels.Count > 0) { temquery = temquery.Where(conModels); } } if (currentUser.AccountType != (int)Entity.AccountType.platform) { temquery = temquery.Where((s, c) => c.BusinessId == currentUser.BusinessId); } if (type > 0) { temquery = temquery.Where((s, c) => s.type == type); } var query = await temquery.OrderBy((s, c) => s.lastmodifytime, OrderByType.Desc) .Select((s, c) => new OfficialListModel { authorizer_appid = s.authorizer_appid, service_type_info = s.service_type_info, createtime = s.createtime, func_info = s.func_info, head_img = s.head_img, isauthorize = s.isauthorize, Id = s.Id, lastmodifytime = s.lastmodifytime, nick_name = s.nick_name, qrcode_url = s.qrcode_url, user_name = s.user_name, verify_type_info = s.verify_type_info, BusinessId = c.BusinessId }) .Mapper((it, cache) => { var allbuss = cache.Get(list => { var ids = list.Select(x => x.BusinessId).ToList(); return dbClient.Queryable().Where(x => ids.Contains(x.Id)).ToList(); }); it.verify_type_info = $"{it.verify_type_info}{it.service_type_info}"; it.BusinessName = allbuss.FirstOrDefault(x => x.Id == it.BusinessId)?.Name; }) .ToPageListAsync(param.offset, param.limit, totalnum); return new PageParms { page = param.offset, Items = query, totalnum = totalnum, limit = param.limit }; } } /// /// 小程序模版列表 /// /// /// public async Task> GetTplListAsync(QueryParams param) { using (var dbClient = ReadDbContext.GetInstance()) { RefAsync totalnum = 0; var tempquery = dbClient.Queryable(); if (param.queryParam != null && param.queryParam.Count > 0) { List conModels = new List(); param.queryParam.ForEach(x => { if (!string.IsNullOrEmpty(x.Value)) { conModels.Add(new ConditionalModel() { FieldName = x.Name, ConditionalType = (ConditionalType)x.Type, FieldValue = x.Value.Trim() }); } }); if (conModels.Count > 0) { tempquery = tempquery.Where(conModels); } } var query = await tempquery.OrderBy(x => x.CreateTime, OrderByType.Desc) .ToPageListAsync(param.offset, param.limit, totalnum); return new PageParms { page = param.offset, Items = query, totalnum = totalnum, limit = param.limit }; } } /// /// 小程序草稿列表 /// /// /// public async Task> GetDraftListAsync(QueryParams param) { using (var dbClient = ReadDbContext.GetInstance()) { RefAsync totalnum = 0; var tempquery = dbClient.Queryable(); if (param.queryParam != null && param.queryParam.Count > 0) { List conModels = new List(); param.queryParam.ForEach(x => { if (!string.IsNullOrEmpty(x.Value)) { conModels.Add(new ConditionalModel() { FieldName = x.Name, ConditionalType = (ConditionalType)x.Type, FieldValue = x.Value.Trim() }); } }); if (conModels.Count > 0) { tempquery = tempquery.Where(conModels); } } var query = await tempquery.OrderBy(x => x.CreateTime, OrderByType.Desc) .ToPageListAsync(param.offset, param.limit, totalnum); return new PageParms { page = param.offset, Items = query, totalnum = totalnum, limit = param.limit }; } } /// /// 获取提交历史 /// /// /// public async Task> GetHistoryListAsync(QueryParams param) { using (var dbClient = ReadDbContext.GetInstance()) { RefAsync totalnum = 0; var tempquery = dbClient.Queryable(); if (param.queryParam != null && param.queryParam.Count > 0) { List conModels = new List(); param.queryParam.ForEach(x => { if (!string.IsNullOrEmpty(x.Value)) { conModels.Add(new ConditionalModel() { FieldName = x.Name, ConditionalType = (ConditionalType)x.Type, FieldValue = x.Value.Trim() }); } }); if (conModels.Count > 0) { tempquery = tempquery.Where(conModels); } } var query = await tempquery.OrderBy(x => x.CreateTime, OrderByType.Desc) .ToPageListAsync(param.offset, param.limit, totalnum); return new PageParms { page = param.offset, Items = query, totalnum = totalnum, limit = param.limit }; } } /// /// 详情 /// /// /// public async Task DetailAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { return await dbClient.Queryable().FirstAsync(x => x.Id == id); } } /// /// 同步代码模版列表 /// /// public async Task SyncTplAsync() { using (var dbClient = ReadDbContext.GetInstance()) { var token = await ComponentContainer.TryGetComponentAccessTokenAsync(component_AppId, component_Secret); var result = await CodeTemplateApi.GetTemplateListAsync(token); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } var list = result.template_list.Select(x => new YB_MiniProgramsTpl { TemplateId = x.template_id, CreateTime = x.create_time.ToDatetimeFromTimeStamp(), SyncTime = DateTime.Now, UserDesc = x.user_desc.ToStr(), UsrVersion = x.user_version.ToStr() }).ToList(); //删除所有模版列表 await dbClient.Deleteable().ExecuteCommandAsync(); //添加记录 if (list.Count > 0) { await dbClient.Insertable(list).ExecuteCommandAsync(); } return new ResultInfo(ResultState.SUCCESS, "同步完成"); } } /// /// 同步代码草稿列表 /// /// public async Task SyncDraftAsync() { using (var dbClient = ReadDbContext.GetInstance()) { var token = await ComponentContainer.TryGetComponentAccessTokenAsync(component_AppId, component_Secret); var result = await CodeTemplateApi.GetTemplateDraftListAsync(token); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } var list = result.draft_list.Select(x => new YB_MiniProgramsDraft { DraftId = x.draft_id, CreateTime = x.create_time.ToDatetimeFromTimeStamp(), SyncTime = DateTime.Now, UserDesc = x.user_desc.ToStr(), UserVersion = x.user_version.ToStr() }).ToList(); //删除所有模版列表 await dbClient.Deleteable().ExecuteCommandAsync(); //添加记录 if (list.Count > 0) { await dbClient.Insertable(list).ExecuteCommandAsync(); } return new ResultInfo(ResultState.SUCCESS, "同步完成"); } } /// /// 将草稿箱的草稿选为小程序代码模版 /// /// /// public async Task AddToTEmplateAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { var draft = await dbClient.Queryable().Where(x => x.Id == id).FirstAsync(); if (draft == null) { return new ResultInfo(ResultState.FAIL, "草稿未找到"); } var token = await ComponentContainer.TryGetComponentAccessTokenAsync(component_AppId, component_Secret); var result = await CodeTemplateApi.AddToTemplateAsync(token, draft.DraftId); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } //重新同步模版 var results = await SyncTplAsync(); if (results.code != ResultState.SUCCESS) { return new ResultInfo(ResultState.FAIL, results.message); } return new ResultInfo(ResultState.SUCCESS, "设置成功"); } } /// /// 删除模版 /// /// /// public async Task DeleteTemplateAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { var draft = await dbClient.Queryable().Where(x => x.Id == id).FirstAsync(); if (draft == null) { return new ResultInfo(ResultState.FAIL, "模版未找到"); } var token = await ComponentContainer.TryGetComponentAccessTokenAsync(component_AppId, component_Secret); var result = await CodeTemplateApi.DeleteTemplateAsync(token, draft.TemplateId); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } //删除模版 await dbClient.Deleteable().Where(x => x.Id == id).ExecuteCommandAsync(); return new ResultInfo(ResultState.SUCCESS, "删除成功"); } } /// /// 为授权的小程序帐号上传小程序代码 /// /// 模版ID /// 小程序id /// public async Task CommitAsync(int templateid, int id) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.Id == id && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var template = await dbClient.Queryable().FirstAsync(x => x.Id == templateid); if (template == null) { return new ResultInfo(ResultState.FAIL, "模版未找到"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); var json = new { extAppid = office.authorizer_appid, extEnable = true, ext= new { appid=office.authorizer_appid, name=office.nick_name } }; string ext_json = json.ToJson(); var result = await CodeApi.CommitAsync(token, template.TemplateId, ext_json, template.UsrVersion, template.UserDesc); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } //记录上传记录 await dbClient.Insertable(new YB_MiniProgramHistory { appid = office.authorizer_appid, UserDesc = template.UserDesc, UserVersion = template.UsrVersion, Status = -1,//代码已上传 ScreenShot = "", StatusRemark = "", auditid = "", CreateTime = DateTime.Now }).ExecuteCommandAsync(); return new ResultInfo(ResultState.SUCCESS, "上传成功"); } } /// /// 获取最新的提交历史状态 /// /// 小程序id /// public async Task GetLastCommitStatusAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().Where(x => x.Id == id).FirstAsync(); return await dbClient.Queryable().Where(x => x.appid == office.authorizer_appid) .OrderBy(x => x.CreateTime, OrderByType.Desc) .FirstAsync(); } } /// /// 获取小程序的体验二维码 /// /// /// 保存的文件夹 /// public async Task GetQRCodeAsync(int id, string savefolder) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.Id == id && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); var rootname = "/qrcode"; var filepath = Path.Combine($"wwwroot/{rootname}/", $"{office.authorizer_appid}.jpg"); var virualpath = Path.Combine($"{rootname}/", $"{office.authorizer_appid}.jpg"); savefolder = $"{savefolder}{rootname}"; if (!Directory.Exists(savefolder)) { Directory.CreateDirectory(savefolder); } using (Stream stream = File.Create(filepath)) { var result = await CodeApi.GetQRCodeAsync(token, stream); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } } return new ResultInfo(ResultState.SUCCESS, "success", virualpath); } } /// /// 获取小程序的第三方提交代码的页面配置 /// /// /// public async Task GetPageAsync(string appid) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.authorizer_appid == appid && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); var result = await CodeApi.GetPageAsync(token); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } return new ResultInfo(ResultState.SUCCESS, "success", result.page_list); } } /// /// 查询最新一次提交的审核状态 /// /// /// public async Task GetLatestAuditStatusAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.Id == id && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } //是否有提交记录 var data = await dbClient.Queryable().Where(x => x.appid == office.authorizer_appid).OrderBy(x => x.CreateTime, OrderByType.Desc).FirstAsync(); if (data == null) { return new ResultInfo(ResultState.FAIL, "未找到提交的版本"); } if (string.IsNullOrEmpty(data.auditid)) { return new ResultInfo(ResultState.FAIL, "请先提交审核"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); long auditid = data.auditid.ToLong(); var result = await CodeApi.GetAuditStatusAsync(token, auditid); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } //更新审核状态 var errmsg = LatestAuditStatusErrmsg(result); await dbClient.Updateable().SetColumns(x => new YB_MiniProgramHistory { Status = result.status, ScreenShot = result.screenshot.ToStr(), StatusRemark = errmsg }).Where(x => x.Id == data.Id).ExecuteCommandAsync(); if (result.status == 0) { return new ResultInfo(ResultState.SUCCESS, "审核成功"); } return new ResultInfo(ResultState.FAIL, errmsg); } } /// /// 审核状态描述 /// /// /// private string LatestAuditStatusErrmsg(GetAuditResultJson result) => (result) switch { _ when result.status == -1 => "代码已提交", _ when result.status == 0 => "审核成功", _ when result.status == 1 => result.reason, _ when result.status == 2 => "审核中", _ when result.status == 3 => "已撤回", _ => result.reason }; /// /// 将第三方提交的代码包提交审核,注意:只有上个版本被驳回,才能使用 feedback_info、feedback_stuff 这两个字段,否则忽略处理。 /// /// /// public async Task SubmitAuditAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.Id == id && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var hdata = await dbClient.Queryable().Where(x => x.appid == office.authorizer_appid).OrderBy(x => x.CreateTime, OrderByType.Desc).FirstAsync(); if (hdata == null) { return new ResultInfo(ResultState.FAIL, "未找到可用的版本"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); var result = await CodeApi.SubmitAuditAsync(token, null, null); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } //更新提交记录 var msg = LatestAuditStatusErrmsg(result); await dbClient.Updateable().SetColumns(x => new YB_MiniProgramHistory { Status = 2, StatusRemark = msg, auditid = result.auditid }).Where(x => x.Id == hdata.Id).ExecuteCommandAsync(); return new ResultInfo(ResultState.SUCCESS, "成功提交审核"); } } /// /// 修改域名 /// /// /// public async Task ModifyDomainAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.Id == id && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var wxurl = Configs.GetString("APIURL"); var cdnurl = Configs.GetString("CDNURL"); var urlList = new List {wxurl,cdnurl}; var uploadlist = urlList; var downlist = urlList; var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); var result1 = await ModifyDomainApi.ModifyDomainAsync(token, ModifyDomainAction.get, null, null, null, null); if(result1.errcode != 0) { return new ResultInfo(ResultState.FAIL, result1.errmsg); } result1.requestdomain.ForEach(x => { x = x.ToLower(); if (urlList.Contains(x)) { urlList.Remove(x); } }); result1.uploaddomain.ForEach(x => { x = x.ToLower(); if (uploadlist.Contains(x)) { uploadlist.Remove(x); } }); result1.downloaddomain.ForEach(x => { x = x.ToLower(); if (downlist.Contains(x)) { downlist.Remove(x); } }); if(urlList.Count == 0 && uploadlist.Count == 0 && downlist.Count == 0) { return new ResultInfo(ResultState.FAIL, "没有可增加的域名"); } if(urlList.Count == 0) { urlList = null; } if(uploadlist.Count == 0) { uploadlist = null; } if(downlist.Count == 0) { downlist = null; } var result = await ModifyDomainApi.ModifyDomainAsync(token, ModifyDomainAction.add, urlList, null, uploadlist, downlist); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg,new { urllist=urlList, uploadlist=uploadlist, downlist=downlist }); } return new ResultInfo(ResultState.SUCCESS, "域名修改成功"); } } /// /// 获取域名列表 /// /// /// public async Task GetDomainAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.Id == id && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); var result = await ModifyDomainApi.ModifyDomainAsync(token, ModifyDomainAction.get, null, null, null, null); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } return new ResultInfo(ResultState.SUCCESS, "success", new { requestdomain = result.requestdomain, wsrequestdomain = result.wsrequestdomain, uploaddomain = result.uploaddomain, downloaddomain = result.downloaddomain }); } } /// /// 小程序审核撤回,注意:单个帐号每天审核撤回次数最多不超过 1 次,一个月不超过 10 次 /// /// /// public async Task UndoCodeAuditAsync(string appid) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.authorizer_appid == appid && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); var result = await CodeApi.UndoCodeAuditAsync(token); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } return new ResultInfo(ResultState.SUCCESS, "撤回成功"); } } /// /// 发布已通过审核的小程序 /// /// /// public async Task ReleaseAsync(int id) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.Id == id && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); var result = await CodeApi.ReleaseAsync(token); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } return new ResultInfo(ResultState.SUCCESS, "发布成功"); } } /// /// 修改小程序线上代码的可见状态 /// /// /// /// public async Task ChangeVisitStatusAsync(string appid, int status = 1) { using (var dbClient = ReadDbContext.GetInstance()) { var office = await dbClient.Queryable().FirstAsync(x => x.authorizer_appid == appid && x.type == 2); if (office == null) { return new ResultInfo(ResultState.FAIL, "小程序未找到"); } var token = await AuthorizerContainer.TryGetAuthorizerAccessTokenAsync(component_AppId, office.authorizer_appid); ChangVisitStatusAction action = status == 1 ? ChangVisitStatusAction.open : ChangVisitStatusAction.close; var result = await CodeApi.ChangeVisitStatusAsync(token, action); if (result.errcode != 0) { return new ResultInfo(ResultState.FAIL, result.errmsg); } return new ResultInfo(ResultState.SUCCESS, status == 1 ? "版本已开启" : "版本已关闭"); } } } }