Files
qhmes/yy-admin-master/YY.Admin.Services/Service/Print/PrintTemplateService.cs

171 lines
6.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.IO;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Configuration;
using YY.Admin.Core.Entity;
using YY.Admin.Core.Services;
namespace YY.Admin.Services.Service.Print;
public class PrintTemplateService : IPrintTemplateService
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfiguration _configuration;
private readonly object _cacheLock = new();
private List<PrintTemplate> _localCache = new();
private readonly string _cacheFilePath;
private static readonly JsonSerializerOptions JsonOpts = new()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new NullableDateTimeJsonConverter() }
};
private string BaseUrl =>
(_configuration.GetValue<string>("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/');
public PrintTemplateService(IHttpClientFactory httpClientFactory, IConfiguration configuration)
{
_httpClientFactory = httpClientFactory;
_configuration = configuration;
var appDataDir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"YY.Admin", "sync-cache");
Directory.CreateDirectory(appDataDir);
_cacheFilePath = Path.Combine(appDataDir, "print-template-cache.json");
LoadCacheFromDisk();
}
public IReadOnlyList<PrintTemplate> GetCached()
{
lock (_cacheLock)
{
return _localCache.AsReadOnly();
}
}
public async Task<PrintTemplate?> GetByCodeAsync(string templateCode, CancellationToken ct = default)
{
try
{
var client = _httpClientFactory.CreateClient("JeecgApi");
var url = $"{BaseUrl}/print/template/anon/queryByCode?code={Uri.EscapeDataString(templateCode)}";
var response = await client.GetAsync(url, ct).ConfigureAwait(false);
if (!response.IsSuccessStatusCode) return GetCachedByCode(templateCode);
var result = await response.Content.ReadFromJsonAsync<JeecgResult<PrintTemplate>>(JsonOpts, ct).ConfigureAwait(false);
return result?.Success == true ? result.Result : GetCachedByCode(templateCode);
}
catch
{
return GetCachedByCode(templateCode);
}
}
public async Task<IReadOnlyList<PrintTemplate>> ListAsync(CancellationToken ct = default)
{
try
{
return await RefreshCacheAsync(ct).ConfigureAwait(false);
}
catch
{
return GetCached();
}
}
public async Task<IReadOnlyList<PrintTemplate>> RefreshCacheAsync(CancellationToken ct = default)
{
var client = _httpClientFactory.CreateClient("JeecgApi");
var url = $"{BaseUrl}/print/template/anon/list?pageSize=200";
var response = await client.GetAsync(url, ct).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<JeecgResult<JeecgPage<PrintTemplate>>>(JsonOpts, ct).ConfigureAwait(false);
if (result?.Success != true)
throw new InvalidOperationException(result?.Message ?? "后端返回失败");
var records = result.Result?.Records ?? new List<PrintTemplate>();
lock (_cacheLock)
{
_localCache = records;
SaveCacheToDiskUnsafe();
}
return records.AsReadOnly();
}
private PrintTemplate? GetCachedByCode(string code)
{
lock (_cacheLock)
{
return _localCache.FirstOrDefault(t =>
string.Equals(t.TemplateCode, code, StringComparison.OrdinalIgnoreCase));
}
}
private void LoadCacheFromDisk()
{
try
{
if (!File.Exists(_cacheFilePath)) return;
var json = File.ReadAllText(_cacheFilePath);
var data = JsonSerializer.Deserialize<List<PrintTemplate>>(json, JsonOpts);
_localCache = data ?? new List<PrintTemplate>();
}
catch
{
_localCache = new List<PrintTemplate>();
}
}
private void SaveCacheToDiskUnsafe()
{
try
{
var json = JsonSerializer.Serialize(_localCache, JsonOpts);
File.WriteAllText(_cacheFilePath, json);
}
catch { }
}
private record JeecgResult<T>(bool Success, T? Result, string? Message);
private record JeecgPage<T>(List<T> Records, long Total);
private sealed class NullableDateTimeJsonConverter : JsonConverter<DateTime?>
{
private static readonly string[] Formats =
[
"yyyy-MM-dd HH:mm:ss",
"yyyy-MM-dd HH:mm:ss.fff",
"yyyy-MM-ddTHH:mm:ss",
"yyyy-MM-ddTHH:mm:ss.fff",
"yyyy-MM-ddTHH:mm:ssZ",
"yyyy-MM-ddTHH:mm:ss.fffZ"
];
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null) return null;
if (reader.TokenType == JsonTokenType.String)
{
var raw = reader.GetString();
if (string.IsNullOrWhiteSpace(raw)) return null;
if (DateTime.TryParseExact(raw, Formats, System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AssumeLocal, out var exact))
return exact;
if (DateTime.TryParse(raw, out var fallback)) return fallback;
}
throw new JsonException($"无法将 JSON 值转换为 DateTime?token={reader.TokenType}");
}
public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
{
if (value.HasValue) writer.WriteStringValue(value.Value.ToString("yyyy-MM-dd HH:mm:ss"));
else writer.WriteNullValue();
}
}
}