using System.Net.Http.Headers; using System.Text; using Dlhis.Middle.Entities; using Dlhis.Middle.Response; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.UnifyResultAndValidation; using Kurisu.AspNetCore.Utils.Extensions; using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; namespace Dlhis.Middle.Services.Implements; public class BalanceRecordCheckBackgroundService : BackgroundService { private readonly IServiceProvider _serviceProvider; private readonly ILogger _logger; private readonly IMemoryCache _memoryCache; private readonly IHttpClientFactory _httpClientFactory; private readonly IHealthCheckService _healthCheckService; private readonly string _factory; private readonly string _hostName; public BalanceRecordCheckBackgroundService(IServiceProvider serviceProvider, ILogger logger, IMemoryCache memoryCache, IHttpClientFactory httpClientFactory, IHealthCheckService healthCheckService, IConfiguration configuration) { _serviceProvider = serviceProvider; _logger = logger; _memoryCache = memoryCache; _httpClientFactory = httpClientFactory; _healthCheckService = healthCheckService; _factory = configuration.GetSection("Factory").Value; _hostName = configuration.GetSection("HostName").Value; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { if (!_healthCheckService.GetIsOffline()) { var now = DateTime.Now; using var scope = _serviceProvider.CreateScope(); var db = scope.ServiceProvider.GetService(); var ds = scope.ServiceProvider.GetService(); foreach (var factory in _factory.Split(',')) { try { var balanceRecords = await db.Queryable().Where(x => x.TenantId == factory).Where(x => !x.IsSync).ToListAsync(stoppingToken); if (balanceRecords.Any()) { _logger.LogInformation("上传离线订单"); foreach (var balanceRecord in balanceRecords) { //事务 await db.Client.Ado.BeginTranAsync(); try { //设置为已同步 balanceRecord.IsSync = true; await db.UpdateAsync(balanceRecord); var r = await UploadAsync(balanceRecord); if (r.Code != ApiStateCode.Success) { throw new Exception(r.Msg); } var d = r.Data; //更新本地余额表 await db.Updateable() .SetColumns(x => x.Balance == d.Balance) .Where(x => x.UserCode == d.UserCode) .ExecuteCommandAsync(stoppingToken); await db.Client.Ado.CommitTranAsync(); } catch (Exception e) { _logger.LogError(e, "{factory}上传离线消费失败:{message}", factory, e.Message); await db.Client.Ado.RollbackTranAsync(); } } } } catch (Exception e) { _logger.LogError(e, "{factory}同步离线数据失败:{message}", factory, e.Message); } } if (now is { Hour: 4, Minute: 1 } && !_healthCheckService.GetIsOffline() && !await db.Queryable().Where(x => !x.IsSync).AnyAsync()) { await ds.InitAsync(_factory); } else if (now is { Hour: 15, Minute: 1 } && !_healthCheckService.GetIsOffline() && !await db.Queryable().Where(x => !x.IsSync).AnyAsync()) { await ds.InitAsync(_factory); } else if (now is { Hour: 20, Minute: 1 } && !_healthCheckService.GetIsOffline() && !await db.Queryable().Where(x => !x.IsSync).AnyAsync()) { await ds.InitAsync(_factory); } } await Task.Delay(60 * 1000, stoppingToken); } } public async Task> UploadAsync(LocalBalanceRecordEntity entity) { var token = await AuthAsync(); var httpClient = _httpClientFactory.CreateClient("face"); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var url = $"https://{_hostName}/api/canteen/middle/upload"; var json = entity.ToJson(); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await httpClient.PostAsync(url, content); var responseJson = await response.Content.ReadAsStringAsync(); return responseJson.ToObject>(); } private async Task AuthAsync() { var httpClient = _httpClientFactory.CreateClient("face"); if (_memoryCache.TryGetValue("token", out string token)) return token; var tokenResponse = await httpClient.PostAsync($"https://{_hostName}/api/User/OAuth2/clientgrant", new StringContent(JsonConvert.SerializeObject(new { ClientId = "e509c2aaa98e300c", ClientSecret = "6184d8979fc48105" }), Encoding.UTF8, "application/json")); var tokenJson = await tokenResponse.Content.ReadAsStringAsync(); var tokenInfo = JsonConvert.DeserializeObject>(tokenJson); token = tokenInfo.Data.AccessToken; _memoryCache.Set("token", token, TimeSpan.FromSeconds(tokenInfo.Data.Expires)); return token; } }