93 lines
3.2 KiB
C#
93 lines
3.2 KiB
C#
|
|
using System.Text.Json;
|
||
|
|
using SSPCTester.Logic.Models;
|
||
|
|
|
||
|
|
namespace SSPCTester.Logic.Storage;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 项目读写:每项目一个独立文件夹,含 project.json / curves/ / report.pdf。
|
||
|
|
/// </summary>
|
||
|
|
public sealed class ProjectStore
|
||
|
|
{
|
||
|
|
private static readonly JsonSerializerOptions _jsonOpts = new()
|
||
|
|
{
|
||
|
|
WriteIndented = true,
|
||
|
|
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||
|
|
};
|
||
|
|
|
||
|
|
/// <summary>项目根目录(来自设置页)。</summary>
|
||
|
|
public string ProjectsRoot { get; set; } = "";
|
||
|
|
|
||
|
|
public IEnumerable<string> EnumerateProjectFolders()
|
||
|
|
{
|
||
|
|
if (string.IsNullOrWhiteSpace(ProjectsRoot) || !Directory.Exists(ProjectsRoot))
|
||
|
|
yield break;
|
||
|
|
foreach (var dir in Directory.EnumerateDirectories(ProjectsRoot))
|
||
|
|
{
|
||
|
|
if (File.Exists(Path.Combine(dir, "project.json")))
|
||
|
|
yield return dir;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public async Task<Project?> LoadAsync(string folder)
|
||
|
|
{
|
||
|
|
var file = Path.Combine(folder, "project.json");
|
||
|
|
if (!File.Exists(file)) return null;
|
||
|
|
await using var fs = File.OpenRead(file);
|
||
|
|
var project = await JsonSerializer.DeserializeAsync<Project>(fs, _jsonOpts);
|
||
|
|
if (project != null)
|
||
|
|
{
|
||
|
|
project.FolderPath = folder;
|
||
|
|
project.TestFunction ??= new TestFunctionNotes();
|
||
|
|
if (HasLegacyZeroBasedChannels(project))
|
||
|
|
{
|
||
|
|
project.BasicResults.Clear();
|
||
|
|
project.CurveResults.Clear();
|
||
|
|
project.PowerResults.Clear();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return project;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static bool HasLegacyZeroBasedChannels(Project project) =>
|
||
|
|
project.BasicResults.Any(x => x.Channel == 0) ||
|
||
|
|
project.CurveResults.Any(x => x.Channel == 0) ||
|
||
|
|
project.PowerResults.Any(x => x.Channel == 0);
|
||
|
|
|
||
|
|
public async Task SaveAsync(Project project)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrWhiteSpace(project.FolderPath))
|
||
|
|
{
|
||
|
|
if (string.IsNullOrWhiteSpace(ProjectsRoot))
|
||
|
|
throw new InvalidOperationException("尚未配置 ProjectsRoot。");
|
||
|
|
string safeName = MakeSafeName(project.Name);
|
||
|
|
project.FolderPath = Path.Combine(ProjectsRoot, safeName);
|
||
|
|
}
|
||
|
|
Directory.CreateDirectory(project.FolderPath);
|
||
|
|
Directory.CreateDirectory(Path.Combine(project.FolderPath, "curves"));
|
||
|
|
var file = Path.Combine(project.FolderPath, "project.json");
|
||
|
|
await using var fs = File.Create(file);
|
||
|
|
await JsonSerializer.SerializeAsync(fs, project, _jsonOpts);
|
||
|
|
}
|
||
|
|
|
||
|
|
public async Task<List<Project>> LoadAllAsync()
|
||
|
|
{
|
||
|
|
var list = new List<Project>();
|
||
|
|
foreach (var folder in EnumerateProjectFolders())
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var p = await LoadAsync(folder);
|
||
|
|
if (p != null) list.Add(p);
|
||
|
|
}
|
||
|
|
catch { /* 跳过损坏的项目 */ }
|
||
|
|
}
|
||
|
|
return list.OrderByDescending(p => p.LastTestedAt == default ? p.CreatedAt : p.LastTestedAt).ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string MakeSafeName(string name)
|
||
|
|
{
|
||
|
|
var invalid = Path.GetInvalidFileNameChars();
|
||
|
|
return string.Concat(name.Select(c => invalid.Contains(c) ? '_' : c));
|
||
|
|
}
|
||
|
|
}
|