缓存配置,菜单补充,导出

This commit is contained in:
马梓彭 2026-03-31 15:54:27 +08:00
parent 854d367ff1
commit 440e929311
7 changed files with 293 additions and 34 deletions

View File

@ -1,4 +1,4 @@
using Microsoft.Extensions.Caching.Memory; using EasyCaching.Core;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using YD_Event.Application.Client.Dtos; using YD_Event.Application.Client.Dtos;
@ -11,7 +11,7 @@ namespace YD_Event.Application.Client;
public class OAuthController : IDynamicApiController public class OAuthController : IDynamicApiController
{ {
private readonly ISqlSugarRepository<YD_Event.Core.Entities.AppUser> _appUserRepository; private readonly ISqlSugarRepository<YD_Event.Core.Entities.AppUser> _appUserRepository;
private readonly IMemoryCache _memoryCache; private readonly IEasyCachingProvider _cachingProvider;
private readonly IIdGenerator _idGenerator; private readonly IIdGenerator _idGenerator;
private readonly ILogger<OAuthController> _logger; private readonly ILogger<OAuthController> _logger;
@ -19,12 +19,12 @@ public class OAuthController : IDynamicApiController
public OAuthController( public OAuthController(
ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository, ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository,
IMemoryCache memoryCache, IEasyCachingProvider cachingProvider,
IIdGenerator idGenerator, IIdGenerator idGenerator,
ILogger<OAuthController> logger) ILogger<OAuthController> logger)
{ {
_appUserRepository = appUserRepository; _appUserRepository = appUserRepository;
_memoryCache = memoryCache; _cachingProvider = cachingProvider;
_idGenerator = idGenerator; _idGenerator = idGenerator;
_logger = logger; _logger = logger;
} }
@ -93,12 +93,13 @@ public class OAuthController : IDynamicApiController
public async Task<MiniProgramRegisterOutput> Register([FromBody] MiniProgramRegisterInput input) public async Task<MiniProgramRegisterOutput> Register([FromBody] MiniProgramRegisterInput input)
{ {
var cacheKey = $"{SmsCodeCachePrefix}{input.Mobile}"; var cacheKey = $"{SmsCodeCachePrefix}{input.Mobile}";
string cachedCode = null; var cachedCodeResult = _cachingProvider.Get<string>(cacheKey);
if (!_memoryCache.TryGetValue(cacheKey, out cachedCode) || cachedCode != input.VerificationCode) string cachedCode = cachedCodeResult.Value;
if (!cachedCodeResult.HasValue || cachedCode != input.VerificationCode)
{ {
throw Oops.Bah("验证码错误或已过期"); throw Oops.Bah("验证码错误或已过期");
} }
_memoryCache.Remove(cacheKey); _cachingProvider.Remove(cacheKey);
if (await _appUserRepository.IsAnyAsync(x => x.Mobile == input.Mobile)) if (await _appUserRepository.IsAnyAsync(x => x.Mobile == input.Mobile))
{ {
@ -144,12 +145,13 @@ public class OAuthController : IDynamicApiController
public async Task ResetPassword([FromBody] MiniProgramResetPasswordInput input) public async Task ResetPassword([FromBody] MiniProgramResetPasswordInput input)
{ {
var cacheKey = $"{SmsCodeCachePrefix}{input.Mobile}"; var cacheKey = $"{SmsCodeCachePrefix}{input.Mobile}";
string cachedCode = null; var cachedCodeResult = _cachingProvider.Get<string>(cacheKey);
if (!_memoryCache.TryGetValue(cacheKey, out cachedCode) || cachedCode != input.VerificationCode) string cachedCode = cachedCodeResult.Value;
if (!cachedCodeResult.HasValue || cachedCode != input.VerificationCode)
{ {
throw Oops.Bah("验证码错误或已过期"); throw Oops.Bah("验证码错误或已过期");
} }
_memoryCache.Remove(cacheKey); _cachingProvider.Remove(cacheKey);
var appUser = await _appUserRepository.GetFirstAsync(x => x.Mobile == input.Mobile); var appUser = await _appUserRepository.GetFirstAsync(x => x.Mobile == input.Mobile);
if (appUser == null) if (appUser == null)

View File

@ -1,4 +1,4 @@
using Microsoft.Extensions.Caching.Memory; using EasyCaching.Core;
using YD_Event.Application.Common.Dtos; using YD_Event.Application.Common.Dtos;
using YD_Event.Application.Sms; using YD_Event.Application.Sms;
@ -8,12 +8,12 @@ namespace YD_Event.Application.Common;
public class SmsService : IDynamicApiController, ITransient public class SmsService : IDynamicApiController, ITransient
{ {
private readonly AliyunSmsService _smsService; private readonly AliyunSmsService _smsService;
private readonly IMemoryCache _memoryCache; private readonly IEasyCachingProvider _cachingProvider;
public SmsService(AliyunSmsService smsService, IMemoryCache memoryCache) public SmsService(AliyunSmsService smsService, IEasyCachingProvider cachingProvider)
{ {
_smsService = smsService; _smsService = smsService;
_memoryCache = memoryCache; _cachingProvider = cachingProvider;
} }
[HttpPost("sendVerificationCode")] [HttpPost("sendVerificationCode")]
@ -22,7 +22,7 @@ public class SmsService : IDynamicApiController, ITransient
public async Task SendVerificationCode([FromBody] SendVerificationCodeInput input) public async Task SendVerificationCode([FromBody] SendVerificationCodeInput input)
{ {
var limitCacheKey = $"sms:code:limit:{input.Phone}"; var limitCacheKey = $"sms:code:limit:{input.Phone}";
if (_memoryCache.TryGetValue(limitCacheKey, out _)) if (_cachingProvider.Exists(limitCacheKey))
{ {
throw Oops.Bah("发送太频繁,请稍后再试"); throw Oops.Bah("发送太频繁,请稍后再试");
} }
@ -32,7 +32,7 @@ public class SmsService : IDynamicApiController, ITransient
await _smsService.SendVerificationCode(input.Phone, code); await _smsService.SendVerificationCode(input.Phone, code);
var codeCacheKey = $"sms:code:{input.Phone}"; var codeCacheKey = $"sms:code:{input.Phone}";
_memoryCache.Set(codeCacheKey, code, TimeSpan.FromMinutes(5)); _cachingProvider.Set(codeCacheKey, code, TimeSpan.FromMinutes(5));
_memoryCache.Set(limitCacheKey, "1", TimeSpan.FromMinutes(1)); _cachingProvider.Set(limitCacheKey, "1", TimeSpan.FromMinutes(1));
} }
} }

View File

@ -2,6 +2,9 @@ using YD_Event.Application.Event.Dtos;
using YD_Event.Core.Entities; using YD_Event.Core.Entities;
using MiniExcelLibs; using MiniExcelLibs;
using SqlSugar; using SqlSugar;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using System.Drawing;
namespace YD_Event.Application.Event; namespace YD_Event.Application.Event;
@ -16,6 +19,7 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
private readonly ISqlSugarRepository<EventRegistrationPerson> _personRepository; private readonly ISqlSugarRepository<EventRegistrationPerson> _personRepository;
private readonly ISqlSugarRepository<EventRegistration> _registrationRepository; private readonly ISqlSugarRepository<EventRegistration> _registrationRepository;
private readonly ISqlSugarRepository<ProjectType> _projectTypeRepository; private readonly ISqlSugarRepository<ProjectType> _projectTypeRepository;
private readonly ISqlSugarRepository<EventInfo> _eventInfoRepository;
public EventArrangementService( public EventArrangementService(
ISqlSugarRepository<EventProject> eventProjectRepository, ISqlSugarRepository<EventProject> eventProjectRepository,
@ -23,7 +27,8 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
ISqlSugarRepository<ProjectGroup> groupRepository, ISqlSugarRepository<ProjectGroup> groupRepository,
ISqlSugarRepository<EventRegistrationPerson> personRepository, ISqlSugarRepository<EventRegistrationPerson> personRepository,
ISqlSugarRepository<EventRegistration> registrationRepository, ISqlSugarRepository<EventRegistration> registrationRepository,
ISqlSugarRepository<ProjectType> projectTypeRepository) : base(projectRepository) ISqlSugarRepository<ProjectType> projectTypeRepository,
ISqlSugarRepository<EventInfo> eventInfoRepository) : base(projectRepository)
{ {
_eventProjectRepository = eventProjectRepository; _eventProjectRepository = eventProjectRepository;
_projectRepository = projectRepository; _projectRepository = projectRepository;
@ -31,6 +36,7 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
_personRepository = personRepository; _personRepository = personRepository;
_registrationRepository = registrationRepository; _registrationRepository = registrationRepository;
_projectTypeRepository = projectTypeRepository; _projectTypeRepository = projectTypeRepository;
_eventInfoRepository = eventInfoRepository;
} }
/// <summary> /// <summary>
@ -196,9 +202,95 @@ public class EventArrangementService : BaseService<YD_Event.Core.Entities.Projec
[DisplayName("导出编排")] [DisplayName("导出编排")]
public async Task<byte[]> Export(long eventId) public async Task<byte[]> Export(long eventId)
{ {
var eventInfo = await _eventInfoRepository.GetFirstAsync(x => x.Id == eventId);
var data = await Preview(eventId); var data = await Preview(eventId);
using var stream = new MemoryStream();
stream.SaveAs(data); // 设置 EPPlus 许可证上下文
return stream.ToArray(); ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
using var package = new ExcelPackage();
var worksheet = package.Workbook.Worksheets.Add("编排表");
// 第一行:赛事标题(合并单元格 A1:G1)
worksheet.Cells["A1:G1"].Merge = true;
worksheet.Cells["A1"].Value = eventInfo?.EventName ?? "赛事编排表";
// 设置标题样式
var titleStyle = worksheet.Cells["A1:G1"].Style;
titleStyle.Font.Bold = true;
titleStyle.Font.Size = 14;
titleStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center;
titleStyle.VerticalAlignment = ExcelVerticalAlignment.Center;
titleStyle.Fill.PatternType = ExcelFillStyle.Solid;
titleStyle.Fill.BackgroundColor.SetColor(Color.FromArgb(255, 217, 179)); // 浅橙色
// 第二行:列标题
string[] headers = { "时间", "参赛项目", "参赛组别", "参赛队伍", "运动员姓名", "场次", "场地" };
for (int i = 0; i < headers.Length; i++)
{
worksheet.Cells[2, i + 1].Value = headers[i];
}
// 设置列标题样式
var headerStyle = worksheet.Cells["A2:G2"].Style;
headerStyle.Font.Bold = true;
headerStyle.Font.Size = 11;
headerStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center;
headerStyle.VerticalAlignment = ExcelVerticalAlignment.Center;
headerStyle.Fill.PatternType = ExcelFillStyle.Solid;
headerStyle.Fill.BackgroundColor.SetColor(Color.FromArgb(204, 255, 204)); // 浅绿色
headerStyle.Border.Top.Style = ExcelBorderStyle.Thin;
headerStyle.Border.Bottom.Style = ExcelBorderStyle.Thin;
headerStyle.Border.Left.Style = ExcelBorderStyle.Thin;
headerStyle.Border.Right.Style = ExcelBorderStyle.Thin;
// 填充数据行
for (int i = 0; i < data.Count; i++)
{
var item = data[i];
int rowIndex = i + 3;
worksheet.Cells[rowIndex, 1].Value = item.TimeRange;
worksheet.Cells[rowIndex, 2].Value = item.ProjectName;
worksheet.Cells[rowIndex, 3].Value = item.GroupName;
worksheet.Cells[rowIndex, 4].Value = item.TeamName ?? "";
worksheet.Cells[rowIndex, 5].Value = item.AthleteName;
worksheet.Cells[rowIndex, 6].Value = item.SessionIndex;
worksheet.Cells[rowIndex, 7].Value = item.VenueIndex;
// 设置数据行样式
var rowStyle = worksheet.Cells[$"A{rowIndex}:G{rowIndex}"].Style;
rowStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center;
rowStyle.VerticalAlignment = ExcelVerticalAlignment.Center;
rowStyle.Border.Top.Style = ExcelBorderStyle.Thin;
rowStyle.Border.Bottom.Style = ExcelBorderStyle.Thin;
rowStyle.Border.Left.Style = ExcelBorderStyle.Thin;
rowStyle.Border.Right.Style = ExcelBorderStyle.Thin;
// 交替行颜色
if (i % 2 == 1)
{
rowStyle.Fill.PatternType = ExcelFillStyle.Solid;
rowStyle.Fill.BackgroundColor.SetColor(Color.FromArgb(240, 255, 240)); // 更浅的绿色
}
}
// 设置列宽
worksheet.Column(1).Width = 12; // 时间
worksheet.Column(2).Width = 18; // 参赛项目
worksheet.Column(3).Width = 15; // 参赛组别
worksheet.Column(4).Width = 25; // 参赛队伍
worksheet.Column(5).Width = 15; // 运动员姓名
worksheet.Column(6).Width = 8; // 场次
worksheet.Column(7).Width = 8; // 场地
// 设置行高
worksheet.Row(1).Height = 30; // 标题行
worksheet.Row(2).Height = 25; // 列标题行
// 冻结首行和首列
worksheet.View.FreezePanes(3, 1);
return await package.GetAsByteArrayAsync();
} }
} }

View File

@ -1,4 +1,4 @@
using Microsoft.Extensions.Caching.Memory; using EasyCaching.Core;
using YD_Event.Application.Auth; using YD_Event.Application.Auth;
using YD_Event.Application.Merchant.Dtos; using YD_Event.Application.Merchant.Dtos;
using YD_Event.Core.Entities; using YD_Event.Core.Entities;
@ -16,7 +16,7 @@ public class MerchantCertificationService : BaseService<MerchantCertification>,
private readonly ISqlSugarRepository<YD_Event.Core.Entities.Merchant> _merchantRepository; private readonly ISqlSugarRepository<YD_Event.Core.Entities.Merchant> _merchantRepository;
private readonly AuthManager _authManager; private readonly AuthManager _authManager;
private readonly IIdGenerator _idGenerator; private readonly IIdGenerator _idGenerator;
private readonly IMemoryCache _memoryCache; private readonly IEasyCachingProvider _cachingProvider;
private readonly AliyunSmsService _smsService; private readonly AliyunSmsService _smsService;
public MerchantCertificationService( public MerchantCertificationService(
@ -24,14 +24,14 @@ public class MerchantCertificationService : BaseService<MerchantCertification>,
ISqlSugarRepository<YD_Event.Core.Entities.Merchant> merchantRepository, ISqlSugarRepository<YD_Event.Core.Entities.Merchant> merchantRepository,
AuthManager authManager, AuthManager authManager,
IIdGenerator idGenerator, IIdGenerator idGenerator,
IMemoryCache memoryCache, IEasyCachingProvider cachingProvider,
AliyunSmsService smsService) : base(repository) AliyunSmsService smsService) : base(repository)
{ {
_repository = repository; _repository = repository;
_merchantRepository = merchantRepository; _merchantRepository = merchantRepository;
_authManager = authManager; _authManager = authManager;
_idGenerator = idGenerator; _idGenerator = idGenerator;
_memoryCache = memoryCache; _cachingProvider = cachingProvider;
_smsService = smsService; _smsService = smsService;
} }
@ -42,7 +42,10 @@ public class MerchantCertificationService : BaseService<MerchantCertification>,
[HttpPost("submitCertification")] [HttpPost("submitCertification")]
public async Task SubmitCertification(SubmitCertificationInput input) public async Task SubmitCertification(SubmitCertificationInput input)
{ {
if (!_memoryCache.TryGetValue($"sms:code:{input.ContactPhone}", out string? cachedCode) || cachedCode != input.VerificationCode) var cacheKey = $"sms:code:{input.ContactPhone}";
var cachedCodeResult = _cachingProvider.Get<string>(cacheKey);
string? cachedCode = cachedCodeResult.Value;
if (!cachedCodeResult.HasValue || cachedCode != input.VerificationCode)
{ {
throw Oops.Bah("验证码错误或已过期"); throw Oops.Bah("验证码错误或已过期");
} }
@ -82,7 +85,7 @@ public class MerchantCertificationService : BaseService<MerchantCertification>,
await _repository.UpdateAsync(certification); await _repository.UpdateAsync(certification);
} }
_memoryCache.Remove($"sms:code:{input.ContactPhone}"); _cachingProvider.Remove(cacheKey);
} }
/// <summary> /// <summary>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<NoWarn>1701;1702;1591</NoWarn> <NoWarn>1701;1702;1591</NoWarn>
@ -37,5 +37,6 @@
<PackageReference Include="MiniExcel" Version="1.42.0" /> <PackageReference Include="MiniExcel" Version="1.42.0" />
<PackageReference Include="MiniWord" Version="0.9.2" /> <PackageReference Include="MiniWord" Version="0.9.2" />
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.16.0" /> <PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.16.0" />
<PackageReference Include="EPPlus" Version="7.1.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -54,7 +54,7 @@
"SleepMs": 300, "SleepMs": 300,
"dbconfig": { "dbconfig": {
"ConnectionStrings": [ "ConnectionStrings": [
"127.0.0.1:6379,password=123456,defaultDatabase=0,poolsize=7" "8.153.108.90,Password=yd708090,SyncTimeout=15000,defaultDatabase=7,poolsize=50,ssl=false,writeBuffer=10240"
], ],
//"Sentinels": [ //"Sentinels": [
// "192.169.1.10:26379", // "192.169.1.10:26379",
@ -76,7 +76,7 @@
"EnableWriteDeepClone": false "EnableWriteDeepClone": false
} }
}, },
"type": "inmemory" //使用缓存类型 "type": "csredis" //使用缓存类型
}, },
//对象存储配置 文档:https://github.com/oncemi/OnceMi.AspNetCore.OSS //对象存储配置 文档:https://github.com/oncemi/OnceMi.AspNetCore.OSS
"OssConnection": { "OssConnection": {

View File

@ -1057,12 +1057,35 @@
"CreatedUserId": 1000, "CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00" "CreatedTime": "2023-06-01T00:00:00"
}, },
{
"Id": 1070,
"Name": "系统设置",
"Type": 0,
"Code": "system",
"ParentId": null,
"RouteName": "system",
"Path": "/system",
"Component": "Layout",
"Redirect": "",
"Icon": "ele-Setting",
"IsIframe": "0",
"Link": "",
"IsVisible": "1",
"IsKeepAlive": "1",
"IsFixed": "0",
"Status": 0,
"Sort": 180,
"Remark": "",
"DeleteMark": false,
"CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00"
},
{ {
"Id": 1046, "Id": 1046,
"Name": "权限管理", "Name": "权限管理",
"Type": 0, "Type": 1,
"Code": "permission", "Code": "permission",
"ParentId": null, "ParentId": 1070,
"RouteName": "permission", "RouteName": "permission",
"Path": "/permission", "Path": "/permission",
"Component": "Layout", "Component": "Layout",
@ -1074,7 +1097,7 @@
"IsKeepAlive": "1", "IsKeepAlive": "1",
"IsFixed": "0", "IsFixed": "0",
"Status": 0, "Status": 0,
"Sort": 170, "Sort": 1,
"Remark": "", "Remark": "",
"DeleteMark": false, "DeleteMark": false,
"CreatedUserId": 1000, "CreatedUserId": 1000,
@ -1310,6 +1333,144 @@
"CreatedUserId": 1000, "CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00" "CreatedTime": "2023-06-01T00:00:00"
}, },
{
"Id": 1071,
"Name": "退款配置",
"Type": 1,
"Code": "refund",
"ParentId": 1070,
"RouteName": "refund",
"Path": "/refund",
"Component": "refund/index",
"Redirect": "",
"Icon": "ele-Money",
"IsIframe": "0",
"Link": "",
"IsVisible": "1",
"IsKeepAlive": "1",
"IsFixed": "0",
"Status": 0,
"Sort": 2,
"Remark": "",
"DeleteMark": false,
"CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00"
},
{
"Id": 1072,
"Name": "编辑",
"Type": 2,
"Code": "refund:edit",
"ParentId": 1071,
"RouteName": "btn_refund_edit",
"Path": "",
"Component": "",
"Redirect": "",
"Icon": "",
"IsIframe": "0",
"Link": "",
"IsVisible": "0",
"IsKeepAlive": "1",
"IsFixed": "0",
"Status": 0,
"Sort": 1,
"Remark": "",
"DeleteMark": false,
"CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00"
},
{
"Id": 1073,
"Name": "Banner配置",
"Type": 1,
"Code": "banner",
"ParentId": 1070,
"RouteName": "banner",
"Path": "/banner",
"Component": "banner/index",
"Redirect": "",
"Icon": "ele-Picture",
"IsIframe": "0",
"Link": "",
"IsVisible": "1",
"IsKeepAlive": "1",
"IsFixed": "0",
"Status": 0,
"Sort": 3,
"Remark": "",
"DeleteMark": false,
"CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00"
},
{
"Id": 1074,
"Name": "新增",
"Type": 2,
"Code": "banner:add",
"ParentId": 1073,
"RouteName": "btn_banner_add",
"Path": "",
"Component": "",
"Redirect": "",
"Icon": "",
"IsIframe": "0",
"Link": "",
"IsVisible": "0",
"IsKeepAlive": "1",
"IsFixed": "0",
"Status": 0,
"Sort": 1,
"Remark": "",
"DeleteMark": false,
"CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00"
},
{
"Id": 1075,
"Name": "编辑",
"Type": 2,
"Code": "banner:edit",
"ParentId": 1073,
"RouteName": "btn_banner_edit",
"Path": "",
"Component": "",
"Redirect": "",
"Icon": "",
"IsIframe": "0",
"Link": "",
"IsVisible": "0",
"IsKeepAlive": "1",
"IsFixed": "0",
"Status": 0,
"Sort": 2,
"Remark": "",
"DeleteMark": false,
"CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00"
},
{
"Id": 1076,
"Name": "删除",
"Type": 2,
"Code": "banner:delete",
"ParentId": 1073,
"RouteName": "btn_banner_delete",
"Path": "",
"Component": "",
"Redirect": "",
"Icon": "",
"IsIframe": "0",
"Link": "",
"IsVisible": "0",
"IsKeepAlive": "1",
"IsFixed": "0",
"Status": 0,
"Sort": 3,
"Remark": "",
"DeleteMark": false,
"CreatedUserId": 1000,
"CreatedTime": "2023-06-01T00:00:00"
},
{ {
"Id": 1060, "Id": 1060,
"Name": "积分管理", "Name": "积分管理",
@ -1325,7 +1486,7 @@
"IsKeepAlive": "1", "IsKeepAlive": "1",
"IsFixed": "0", "IsFixed": "0",
"Status": 0, "Status": 0,
"Sort": 161, "Sort": 170,
"Remark": "", "Remark": "",
"DeleteMark": false, "DeleteMark": false,
"CreatedUserId": 1000, "CreatedUserId": 1000,