Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions client/src/views/telegram/media/externalLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,10 @@ const handleCurrentChange = (page: number) => {
const handleCreateExternalLink = async () => {
try {
await externalLinkApi.getExternalLinkStatus();
ElMessage.success("外部链接添加成功");
loadTableData();
ElMessage.success("外链生成任务已提交,正在后台处理...");
setTimeout(() => {
loadTableData();
}, 5000);
} catch (error) {
console.error("添加外部链接失败:", error);
ElMessage.error("添加外部链接失败");
Expand Down
106 changes: 64 additions & 42 deletions src/DFApp.Web/Background/LotteryResultJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,27 +115,24 @@ private async Task StartWork(string lotteryType, string lotteryTypeEng, string c
if (result1 == null || result1.Count <= 0)
{
_logger.LogInformation("今天没有数据,开始获取最新数据");
_lotteryResultRepository.BeginTran();

_logger.LogInformation("开始更新奖级信息");
try
{
_logger.LogInformation("开始更新奖级信息");
await UpdatePrizegrades(lotteryType, lotteryTypeEng);

_logger.LogInformation("获取最新一期开奖结果作为起始点");
LotteryResult lotteryResult = _resultReadOnly.GetQueryable().OrderByDescending(x => x.Code).First();
string dayStart = (lotteryResult.Date!.Split('('))[0];
_logger.LogInformation("从 {DayStart} 开始获取最新数据", dayStart);

await GetCurrentLotteryResult(dayStart, 0, lotteryTypeEng);
_lotteryResultRepository.CommitTran();
_logger.LogInformation("最新数据获取完成并提交事务");
}
catch (Exception ex)
{
_logger.LogError(ex, "获取最新数据时发生异常");
_lotteryResultRepository.RollbackTran();
throw;
_logger.LogError(ex, "更新奖级信息时发生异常,继续获取最新数据");
}

_logger.LogInformation("获取最新一期开奖结果作为起始点");
LotteryResult lotteryResult = _resultReadOnly.GetQueryable().OrderByDescending(x => x.Code).First();
string dayStart = (lotteryResult.Date!.Split('('))[0];
_logger.LogInformation("从 {DayStart} 开始获取最新数据", dayStart);

await GetCurrentLotteryResult(dayStart, 0, lotteryTypeEng);
_logger.LogInformation("最新数据获取完成");
}
else
{
Expand All @@ -152,30 +149,67 @@ private async Task StartWork(string lotteryType, string lotteryTypeEng, string c
}
}

private async Task GetCurrentLotteryResult(string dayStart, int pageNo, string lotteryType)
/// <summary>
/// 逐条处理开奖结果,每条独立写入数据库,某条失败不影响其他条目
/// </summary>
private async Task ProcessResultsIndividually(List<DFApp.Lottery.ResultItemDto> items)
{
string dayEnd = DateTime.Now.ToString("yyyy-MM-dd");
_logger.LogInformation("获取当前彩票结果 - 起始日期: {DayStart}, 结束日期: {DayEnd}, 彩票类型: {LotteryType}, 页码: {PageNo}", dayStart, dayEnd, lotteryType, pageNo);

LotteryInputDto dto = await GetLotteryResult(dayStart, dayEnd, pageNo, lotteryType);
int successCount = 0;
int skipCount = 0;
int failCount = 0;

if (dto.Result != null && dto.Result.Count > 0)
foreach (var item in items)
{
_logger.LogInformation("获取到 {Count} 条数据,开始映射并保存到数据库", dto.Result.Count);
List<LotteryResult> result = dto.Result.Select(item => _mapper.MapToEntityFromExternalResultItem(item)).ToList();

try
{
await _lotteryResultRepository.InsertAsync(result);
_logger.LogInformation("成功保存 {Count} 条彩票结果到数据库", result.Count);
// 按期号+彩票类型去重检查
bool exists = await _resultReadOnly.AnyAsync(r => r.Code == item.Code && r.Name == item.Name);
if (exists)
{
_logger.LogDebug("跳过已存在的记录 - 彩票类型: {Name}, 期号: {Code}", item.Name, item.Code);
skipCount++;
continue;
}

LotteryResult entity = _mapper.MapToEntityFromExternalResultItem(item);
await _lotteryResultRepository.InsertAsync(entity);
successCount++;

// 同时写入该条结果对应的奖级信息
if (item.Prizegrades != null && item.Prizegrades.Count > 0)
{
var prizeEntities = item.Prizegrades.Select(pg =>
{
var prizeEntity = _mapper.MapToEntityFromExternalPrizegradesItem(pg);
prizeEntity.LotteryResultId = entity.Id;
return prizeEntity;
}).ToList();

await _lotteryPrizegradesRepository.InsertAsync(prizeEntities);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "保存彩票结果到数据库时发生异常");
throw;
failCount++;
_logger.LogError(ex, "逐条写入失败 - 彩票类型: {Name}, 期号: {Code},继续处理下一条", item.Name, item.Code);
}
}

_logger.LogInformation("逐条处理完成 - 成功: {Success}, 跳过(已存在): {Skip}, 失败: {Fail}", successCount, skipCount, failCount);
}

private async Task GetCurrentLotteryResult(string dayStart, int pageNo, string lotteryType)
{
string dayEnd = DateTime.Now.ToString("yyyy-MM-dd");
_logger.LogInformation("获取当前彩票结果 - 起始日期: {DayStart}, 结束日期: {DayEnd}, 彩票类型: {LotteryType}, 页码: {PageNo}", dayStart, dayEnd, lotteryType, pageNo);

LotteryInputDto dto = await GetLotteryResult(dayStart, dayEnd, pageNo, lotteryType);

if (dto.Result != null && dto.Result.Count > 0)
{
_logger.LogInformation("获取到 {Count} 条数据,开始逐条处理", dto.Result.Count);
await ProcessResultsIndividually(dto.Result);

// 检查是否需要获取下一页数据
if (dto.PageNo < dto.PageNum)
{
_logger.LogInformation("当前页 {PageNo} 小于总页数 {PageNum},继续获取下一页数据", dto.PageNo, dto.PageNum);
Expand All @@ -200,21 +234,9 @@ private async Task GetAllLotteryResults(string dayStart, string dayEnd, int page

if (dto.Result != null && dto.Result.Count > 0)
{
_logger.LogInformation("获取到 {Count} 条历史数据,开始映射并保存到数据库", dto.Result.Count);
List<LotteryResult> result = dto.Result.Select(item => _mapper.MapToEntityFromExternalResultItem(item)).ToList();

try
{
await _lotteryResultRepository.InsertAsync(result);
_logger.LogInformation("成功保存 {Count} 条历史彩票结果到数据库", result.Count);
}
catch (Exception ex)
{
_logger.LogError(ex, "保存历史彩票结果到数据库时发生异常");
throw;
}
_logger.LogInformation("获取到 {Count} 条历史数据,开始逐条处理", dto.Result.Count);
await ProcessResultsIndividually(dto.Result);

// 检查是否需要获取下一页数据
if (dto.PageNo < dto.PageNum)
{
_logger.LogInformation("当前页 {PageNo} 小于总页数 {PageNum},继续获取下一页历史数据", dto.PageNo, dto.PageNum);
Expand Down
20 changes: 20 additions & 0 deletions src/DFApp.Web/Services/Media/ExternalLinkService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using DFApp.Web.Permissions;
using DFApp.Web.Queue;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace DFApp.Web.Services.Media;

Expand Down Expand Up @@ -107,6 +108,7 @@ public Task<bool> GetExternalLink()
var mediaInfoRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<MediaInfo, long>>();
var externalLinkRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<MediaExternalLink, long>>();
var mediaExternalLinkMediaIdRepository = scope.ServiceProvider.GetRequiredService<ISqlSugarRepository<MediaExternalLinkMediaIds, long>>();
var logger = scope.ServiceProvider.GetRequiredService<ILogger<ExternalLinkService>>();

var returnDownloadUrlPrefix = await configurationInfoRepository.GetConfigurationInfoValue("ReturnDownloadUrlPrefix", MediaBackgroudConst.ModuleName);
if (string.IsNullOrWhiteSpace(returnDownloadUrlPrefix))
Expand All @@ -127,9 +129,12 @@ public Task<bool> GetExternalLink()

if (temp == null || temp.Count <= 0)
{
logger.LogWarning("没有符合条件的外链生成媒体(IsExternalLinkGenerated=false 且 IsDownloadCompleted=true)");
return;
}

logger.LogInformation("找到 {Count} 条符合条件的外链生成媒体,开始处理", temp.Count);

string datetimeName = DateTime.Now.ToString("yyyyMMddHHmmss");
string zipPhotoName = $"{datetimeName}.zip";
string zipPhotoPathName = Path.Combine(Path.GetDirectoryName(photoSavePath)!, zipPhotoName);
Expand All @@ -155,6 +160,11 @@ public Task<bool> GetExternalLink()
continue;
}

if (!File.Exists(mediaInfo.SavePath))
{
logger.LogWarning("媒体文件不存在,跳过:{SavePath}(MediaId={MediaId})", mediaInfo.SavePath, mediaInfo.Id);
}

stringBuilder.AppendLine($"{Path.Combine(returnDownloadUrlPrefix, mediaInfo.SavePath.Replace(replaceUrlPrefix, string.Empty).Replace("\\", "/"))}");
mediaInfo.IsExternalLinkGenerated = true;
}
Expand Down Expand Up @@ -202,6 +212,16 @@ public Task<bool> GetExternalLink()
}

await externalLinkRepository.InsertAsync(mediaExternalLink);

// 插入后获取外链 ID,为子记录赋值并批量插入
foreach (var item in mediaExternalLinkMediaIds)
{
item.MediaExternalLinkId = mediaExternalLink.Id;
}
await mediaExternalLinkMediaIdRepository.InsertAsync(mediaExternalLinkMediaIds);

logger.LogInformation("外链生成完成,ID={Id},包含 {Count} 条媒体记录,耗时 {ElapsedMs}ms",
mediaExternalLink.Id, mediaExternalLinkMediaIds.Count, stopwatch.ElapsedMilliseconds);
}
});

Expand Down
Loading