桌面端胶料快检实验标准添加
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
using Prism.Events;
|
||||
|
||||
namespace YY.Admin.Core.Events;
|
||||
|
||||
public class RubberQuickTestStdChangedPayload
|
||||
{
|
||||
public string Action { get; set; } = string.Empty;
|
||||
public string? StdId { get; set; }
|
||||
}
|
||||
|
||||
public class RubberQuickTestStdChangedEvent : PubSubEvent<RubberQuickTestStdChangedPayload> { }
|
||||
@@ -0,0 +1,13 @@
|
||||
using YY.Admin.Core.Entity;
|
||||
|
||||
namespace YY.Admin.Core.Services;
|
||||
|
||||
/// <summary>胶料快检记录操作台:密炼计划筛选、实验标准匹配、记录保存</summary>
|
||||
public interface IRubberQuickTestOperationService
|
||||
{
|
||||
Task<List<MesXslMixingProductionPlan>> GetMixingProductionPlansAsync(CancellationToken ct = default);
|
||||
|
||||
Task<MesXslRubberQuickTestStd?> GetStdByRubberMaterialNameAsync(string rubberMaterialName, CancellationToken ct = default);
|
||||
|
||||
Task<string?> SaveRecordAsync(MesXslRubberQuickTestRecord record, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using YY.Admin.Core.Entity;
|
||||
|
||||
namespace YY.Admin.Core.Services;
|
||||
|
||||
/// <summary>胶料快检实验标准(MES 只读同步)</summary>
|
||||
public interface IRubberQuickTestStdService
|
||||
{
|
||||
Task<RubberQuickTestStdPageResult> PageAsync(
|
||||
int pageNo, int pageSize,
|
||||
string? stdName = null,
|
||||
string? rubberMaterialName = null,
|
||||
string? enableStatus = null,
|
||||
CancellationToken ct = default);
|
||||
|
||||
Task<MesXslRubberQuickTestStd?> GetByIdAsync(string id, CancellationToken ct = default);
|
||||
|
||||
Task SyncFromRemoteAsync(CancellationToken ct = default);
|
||||
}
|
||||
|
||||
public record RubberQuickTestStdPageResult(
|
||||
List<MesXslRubberQuickTestStd> Records,
|
||||
long Total,
|
||||
int PageNo,
|
||||
int PageSize);
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace YY.Admin.Core.Entity;
|
||||
|
||||
/// <summary>密炼生产计划维护(桌面端快检记录筛选用)</summary>
|
||||
public class MesXslMixingProductionPlan
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public int? SortNo { get; set; }
|
||||
public string? MachineId { get; set; }
|
||||
public string? MachineName { get; set; }
|
||||
|
||||
public string? MorningPlanId { get; set; }
|
||||
public string? MorningPlanType { get; set; }
|
||||
public string? MorningOrderNo { get; set; }
|
||||
public DateTime? MorningOrderDate { get; set; }
|
||||
public string? MorningFormulaName { get; set; }
|
||||
|
||||
public string? NoonPlanId { get; set; }
|
||||
public string? NoonPlanType { get; set; }
|
||||
public string? NoonOrderNo { get; set; }
|
||||
public DateTime? NoonOrderDate { get; set; }
|
||||
public string? NoonFormulaName { get; set; }
|
||||
|
||||
public string? NightPlanId { get; set; }
|
||||
public string? NightPlanType { get; set; }
|
||||
public string? NightOrderNo { get; set; }
|
||||
public DateTime? NightOrderDate { get; set; }
|
||||
public string? NightFormulaName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace YY.Admin.Core.Entity;
|
||||
|
||||
public class MesXslRubberQuickTestRecord
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? RecordNo { get; set; }
|
||||
public string? RubberMaterialId { get; set; }
|
||||
public string? RubberMaterialName { get; set; }
|
||||
public string? StdId { get; set; }
|
||||
public string? ProdEquipmentLedgerId { get; set; }
|
||||
public string? ProdEquipmentName { get; set; }
|
||||
public DateTime? ProductionDate { get; set; }
|
||||
public string? TrainNo { get; set; }
|
||||
public string? WorkShift { get; set; }
|
||||
public int? InspectTimes { get; set; }
|
||||
public DateTime? InspectTime { get; set; }
|
||||
public string? InspectorUserId { get; set; }
|
||||
public string? InspectorUsername { get; set; }
|
||||
public string? InspectorRealname { get; set; }
|
||||
public string? InspectResult { get; set; }
|
||||
public string? ProductionPlanNo { get; set; }
|
||||
public List<MesXslRubberQuickTestRecordLine>? LineList { get; set; }
|
||||
public List<MesXslRubberQuickTestRecordRawLine>? RawLineList { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace YY.Admin.Core.Entity;
|
||||
|
||||
public class MesXslRubberQuickTestRecordLine
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? RecordId { get; set; }
|
||||
public string? DataPointId { get; set; }
|
||||
public string? InspectItem { get; set; }
|
||||
public decimal? LowerLimit { get; set; }
|
||||
public decimal? InspectValue { get; set; }
|
||||
public decimal? UpperLimit { get; set; }
|
||||
public int? SortNo { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace YY.Admin.Core.Entity;
|
||||
|
||||
/// <summary>MES 胶料快检记录原始数据明细</summary>
|
||||
public class MesXslRubberQuickTestRecordRawLine
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? RecordId { get; set; }
|
||||
public string? RowNo { get; set; }
|
||||
public string? DataPointId { get; set; }
|
||||
public string? InspectItem { get; set; }
|
||||
public decimal? LowerLimit { get; set; }
|
||||
public decimal? UpperLimit { get; set; }
|
||||
public decimal? InspectValue { get; set; }
|
||||
/// <summary>行检验结果:1合格 0不合格</summary>
|
||||
public string? RowInspectResult { get; set; }
|
||||
public int? SortNo { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace YY.Admin.Core.Entity;
|
||||
|
||||
/// <summary>MES 胶料快检实验标准主表(桌面端只读同步)</summary>
|
||||
public class MesXslRubberQuickTestStd
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? StdName { get; set; }
|
||||
public string? TestMethodId { get; set; }
|
||||
public string? TestMethodName { get; set; }
|
||||
public string? MixerType { get; set; }
|
||||
public string? RubberMaterialId { get; set; }
|
||||
public string? RubberMaterialName { get; set; }
|
||||
public string? PsCompileId { get; set; }
|
||||
public string? IssueNumber { get; set; }
|
||||
public DateTime? IssueDate { get; set; }
|
||||
public string? IssueDeptId { get; set; }
|
||||
public string? IssueDeptName { get; set; }
|
||||
public string? EnableStatus { get; set; }
|
||||
public string? AuditStatus { get; set; }
|
||||
public int? TenantId { get; set; }
|
||||
public string? SysOrgCode { get; set; }
|
||||
public string? CreateBy { get; set; }
|
||||
public DateTime? CreateTime { get; set; }
|
||||
public string? UpdateBy { get; set; }
|
||||
public DateTime? UpdateTime { get; set; }
|
||||
public List<MesXslRubberQuickTestStdLine>? LineList { get; set; }
|
||||
|
||||
public string EnableStatusText => EnableStatus == "0" ? "已停用" : EnableStatus == "1" ? "使用中" : EnableStatus ?? string.Empty;
|
||||
public string AuditStatusText => AuditStatus == "1" ? "已批准" : AuditStatus == "0" ? "草稿" : AuditStatus ?? string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace YY.Admin.Core.Entity;
|
||||
|
||||
public class MesXslRubberQuickTestStdLine
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? StdId { get; set; }
|
||||
public string? DataPointId { get; set; }
|
||||
public string? PointName { get; set; }
|
||||
public decimal? LowerLimit { get; set; }
|
||||
public decimal? UpperLimit { get; set; }
|
||||
public decimal? LowerWarn { get; set; }
|
||||
public decimal? UpperWarn { get; set; }
|
||||
public decimal? TargetValue { get; set; }
|
||||
public int? SortNo { get; set; }
|
||||
}
|
||||
@@ -48,6 +48,10 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
||||
new SysMenu{ Id=1300150011001, Pid=1300150000101, Title="库区管理", Path="/xslmes/mesXslWarehouseArea", Name="mesXslWarehouseArea", Component="WarehouseAreaListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=109 },
|
||||
// 密炼物料皮重策略
|
||||
new SysMenu{ Id=1300150011101, Pid=1300150000101, Title="密炼物料皮重策略", Path="/xslmes/mesXslMixerMaterialTareStrategy", Name="mesXslMixerMaterialTareStrategy", Component="MixerMaterialTareStrategyListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=110 },
|
||||
// 快检记录
|
||||
new SysMenu{ Id=1300150011201, Pid=1300150000101, Title="快检记录", Path="/xslmes/rubberQuickTestOperation", Name="rubberQuickTestOperation", Component="RubberQuickTestOperationView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=111 },
|
||||
// 胶料快检实验标准(桌面端只读)
|
||||
new SysMenu{ Id=1300150011301, Pid=1300150000101, Title="胶料快检实验标准", Path="/xslmes/mesXslRubberQuickTestStd", Name="mesXslRubberQuickTestStd", Component="RubberQuickTestStdListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=112 },
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ public class SysTenantMenuSeedData : ISqlSugarEntitySeedData<SysTenantMenu>
|
||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010901},
|
||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011001},
|
||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011101},
|
||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011201},
|
||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150011301},
|
||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012101},
|
||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012111},
|
||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012121},
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using YY.Admin.Core;
|
||||
using YY.Admin.Core.Entity;
|
||||
using YY.Admin.Core.Services;
|
||||
|
||||
namespace YY.Admin.Services.Service.RubberQuickTest;
|
||||
|
||||
public class RubberQuickTestOperationService : IRubberQuickTestOperationService, ISingletonDependency
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly INetworkMonitor _networkMonitor;
|
||||
private readonly ILoggerService _logger;
|
||||
|
||||
private static readonly JsonSerializerOptions _jsonOpts = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
|
||||
public RubberQuickTestOperationService(
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IConfiguration configuration,
|
||||
INetworkMonitor networkMonitor,
|
||||
ILoggerService logger)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_configuration = configuration;
|
||||
_networkMonitor = networkMonitor;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private string BaseUrl => (_configuration.GetValue<string>("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/');
|
||||
private int DefaultTenantId => (int?)_configuration.GetValue<long?>("JeecgIntegration:DefaultTenantId") ?? 1002;
|
||||
|
||||
public async Task<List<MesXslMixingProductionPlan>> GetMixingProductionPlansAsync(CancellationToken ct = default)
|
||||
{
|
||||
if (!_networkMonitor.IsOnline)
|
||||
throw new InvalidOperationException("网络未连接,无法加载密炼生产计划");
|
||||
|
||||
var result = new List<MesXslMixingProductionPlan>();
|
||||
int pageNo = 1;
|
||||
const int pageSize = 500;
|
||||
while (true)
|
||||
{
|
||||
var url = $"{BaseUrl}/xslmes/mesXslMixingProductionPlan/anon/list?pageNo={pageNo}&pageSize={pageSize}&tenantId={DefaultTenantId}";
|
||||
using var client = _httpClientFactory.CreateClient("JeecgApi");
|
||||
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
|
||||
resp.EnsureSuccessStatusCode();
|
||||
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
if (!doc.RootElement.TryGetProperty("result", out var resultEl)) break;
|
||||
if (resultEl.TryGetProperty("records", out var recordsEl))
|
||||
{
|
||||
var page = recordsEl.Deserialize<List<MesXslMixingProductionPlan>>(_jsonOpts);
|
||||
if (page != null) result.AddRange(page);
|
||||
}
|
||||
long total = 0;
|
||||
if (resultEl.TryGetProperty("total", out var totalEl)) total = totalEl.GetInt64();
|
||||
if (result.Count >= total || (resultEl.TryGetProperty("records", out var r2) && r2.GetArrayLength() < pageSize)) break;
|
||||
pageNo++;
|
||||
}
|
||||
|
||||
_logger.Information($"[快检记录] 加载密炼生产计划 {result.Count} 条");
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<MesXslRubberQuickTestStd?> GetStdByRubberMaterialNameAsync(string rubberMaterialName, CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rubberMaterialName))
|
||||
return null;
|
||||
if (!_networkMonitor.IsOnline)
|
||||
throw new InvalidOperationException("网络未连接,无法加载实验标准");
|
||||
|
||||
var encoded = Uri.EscapeDataString(rubberMaterialName.Trim());
|
||||
var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/anon/queryByRubberMaterialName?rubberMaterialName={encoded}";
|
||||
using var client = _httpClientFactory.CreateClient("JeecgApi");
|
||||
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
|
||||
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
if (!doc.RootElement.TryGetProperty("success", out var successEl) || !successEl.GetBoolean())
|
||||
{
|
||||
var msg = doc.RootElement.TryGetProperty("message", out var msgEl) ? msgEl.GetString() : "查询实验标准失败";
|
||||
_logger.Warning($"[快检记录] 实验标准查询失败: {msg}");
|
||||
return null;
|
||||
}
|
||||
if (!doc.RootElement.TryGetProperty("result", out var resultEl) || resultEl.ValueKind == JsonValueKind.Null)
|
||||
return null;
|
||||
return resultEl.Deserialize<MesXslRubberQuickTestStd>(_jsonOpts);
|
||||
}
|
||||
|
||||
public async Task<string?> SaveRecordAsync(MesXslRubberQuickTestRecord record, CancellationToken ct = default)
|
||||
{
|
||||
if (!_networkMonitor.IsOnline)
|
||||
throw new InvalidOperationException("网络未连接,无法保存快检记录");
|
||||
|
||||
var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestRecord/anon/add";
|
||||
using var client = _httpClientFactory.CreateClient("JeecgApi");
|
||||
var body = JsonSerializer.Serialize(record, _jsonOpts);
|
||||
using var content = new StringContent(body, Encoding.UTF8, "application/json");
|
||||
var resp = await client.PostAsync(url, content, ct).ConfigureAwait(false);
|
||||
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
if (!doc.RootElement.TryGetProperty("success", out var successEl) || !successEl.GetBoolean())
|
||||
{
|
||||
var msg = doc.RootElement.TryGetProperty("message", out var msgEl) ? msgEl.GetString() : "保存失败";
|
||||
throw new InvalidOperationException(msg ?? "保存失败");
|
||||
}
|
||||
_logger.Information($"[快检记录] 保存成功 recordNo={record.RecordNo}");
|
||||
return doc.RootElement.TryGetProperty("message", out var m) ? m.GetString() : "保存成功";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Prism.Events;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Web;
|
||||
using YY.Admin.Core;
|
||||
using YY.Admin.Core.Entity;
|
||||
using YY.Admin.Core.Events;
|
||||
using YY.Admin.Core.Services;
|
||||
|
||||
namespace YY.Admin.Services.Service.RubberQuickTestStd;
|
||||
|
||||
/// <summary>胶料快检实验标准:MES 只读拉取 + 本地缓存,断网读缓存,联网刷新</summary>
|
||||
public class RubberQuickTestStdService : IRubberQuickTestStdService, ISingletonDependency
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly INetworkMonitor _networkMonitor;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly ILoggerService _logger;
|
||||
private readonly SemaphoreSlim _syncLock = new(1, 1);
|
||||
private readonly object _cacheLock = new();
|
||||
private readonly string _cacheFilePath;
|
||||
private List<MesXslRubberQuickTestStd> _localCache = new();
|
||||
|
||||
private static readonly JsonSerializerOptions _jsonOpts = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
Converters = { new NullableDateTimeJsonConverter() }
|
||||
};
|
||||
|
||||
public RubberQuickTestStdService(
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IConfiguration configuration,
|
||||
INetworkMonitor networkMonitor,
|
||||
IEventAggregator eventAggregator,
|
||||
ILoggerService logger)
|
||||
{
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_configuration = configuration;
|
||||
_networkMonitor = networkMonitor;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
|
||||
var appDataDir = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"YY.Admin", "sync-cache");
|
||||
Directory.CreateDirectory(appDataDir);
|
||||
_cacheFilePath = Path.Combine(appDataDir, "mes-xsl-rubber-quick-test-std-cache.json");
|
||||
|
||||
LoadCacheFromDisk();
|
||||
_logger.Information($"[快检实验标准] 服务初始化,缓存={_localCache.Count},在线={_networkMonitor.IsOnline}");
|
||||
|
||||
_networkMonitor.StatusChanged += OnNetworkStatusChanged;
|
||||
if (_networkMonitor.IsOnline)
|
||||
_ = Task.Run(() => SyncFromRemoteAsync(CancellationToken.None));
|
||||
}
|
||||
|
||||
private string BaseUrl => (_configuration.GetValue<string>("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/');
|
||||
private int DefaultTenantId => (int?)_configuration.GetValue<long?>("JeecgIntegration:DefaultTenantId") ?? 1002;
|
||||
private HttpClient CreateClient() => _httpClientFactory.CreateClient("JeecgApi");
|
||||
|
||||
public async Task<RubberQuickTestStdPageResult> PageAsync(
|
||||
int pageNo, int pageSize,
|
||||
string? stdName = null,
|
||||
string? rubberMaterialName = null,
|
||||
string? enableStatus = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
if (_networkMonitor.IsOnline)
|
||||
{
|
||||
try
|
||||
{
|
||||
await SyncFromRemoteAsync(ct).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warning($"[快检实验标准] 列表拉取失败,使用本地缓存:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
List<MesXslRubberQuickTestStd> source;
|
||||
lock (_cacheLock)
|
||||
source = _localCache.Select(CloneMain).ToList();
|
||||
|
||||
var filtered = ApplyFilters(source, stdName, rubberMaterialName, enableStatus);
|
||||
var total = filtered.Count;
|
||||
var records = filtered
|
||||
.Skip(Math.Max(0, (pageNo - 1) * pageSize))
|
||||
.Take(pageSize)
|
||||
.ToList();
|
||||
return new RubberQuickTestStdPageResult(records, total, pageNo, pageSize);
|
||||
}
|
||||
|
||||
public async Task<MesXslRubberQuickTestStd?> GetByIdAsync(string id, CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id)) return null;
|
||||
|
||||
if (_networkMonitor.IsOnline)
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/anon/queryById?id={Uri.EscapeDataString(id)}";
|
||||
using var client = CreateClient();
|
||||
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
|
||||
if (resp.IsSuccessStatusCode)
|
||||
{
|
||||
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
if (doc.RootElement.TryGetProperty("result", out var resultEl))
|
||||
{
|
||||
var entity = resultEl.Deserialize<MesXslRubberQuickTestStd>(_jsonOpts);
|
||||
if (entity != null)
|
||||
{
|
||||
UpsertLocalCacheMain(entity);
|
||||
return CloneMain(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warning($"[快检实验标准] 详情拉取失败 id={id},回退缓存:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
lock (_cacheLock)
|
||||
{
|
||||
var found = _localCache.FirstOrDefault(x => string.Equals(x.Id, id, StringComparison.OrdinalIgnoreCase));
|
||||
return found != null ? CloneMain(found) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SyncFromRemoteAsync(CancellationToken ct = default)
|
||||
{
|
||||
await _syncLock.WaitAsync(ct).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
if (!_networkMonitor.IsOnline)
|
||||
return;
|
||||
|
||||
var query = HttpUtility.ParseQueryString(string.Empty);
|
||||
query["pageNo"] = "1";
|
||||
query["pageSize"] = "10000";
|
||||
query["tenantId"] = DefaultTenantId.ToString();
|
||||
var url = $"{BaseUrl}/xslmes/mesXslRubberQuickTestStd/anon/list?{query}";
|
||||
|
||||
using var client = CreateClient();
|
||||
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
|
||||
resp.EnsureSuccessStatusCode();
|
||||
|
||||
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
var records = doc.RootElement.GetProperty("result").GetProperty("records")
|
||||
.Deserialize<List<MesXslRubberQuickTestStd>>(_jsonOpts) ?? new();
|
||||
|
||||
lock (_cacheLock)
|
||||
{
|
||||
_localCache = records.Select(CloneMain).ToList();
|
||||
SaveCacheToDiskUnsafe();
|
||||
}
|
||||
_logger.Information($"[快检实验标准] 同步完成 count={records.Count}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warning($"[快检实验标准] 远程同步失败:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_syncLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkStatusChanged(bool isOnline)
|
||||
{
|
||||
if (!isOnline) return;
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await SyncFromRemoteAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>()
|
||||
.Publish(new RubberQuickTestStdChangedPayload { Action = "reconnect" });
|
||||
});
|
||||
}
|
||||
|
||||
private static List<MesXslRubberQuickTestStd> ApplyFilters(
|
||||
List<MesXslRubberQuickTestStd> source,
|
||||
string? stdName,
|
||||
string? rubberMaterialName,
|
||||
string? enableStatus)
|
||||
{
|
||||
IEnumerable<MesXslRubberQuickTestStd> q = source;
|
||||
if (!string.IsNullOrWhiteSpace(stdName))
|
||||
q = q.Where(x => (x.StdName ?? "").Contains(stdName.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||
if (!string.IsNullOrWhiteSpace(rubberMaterialName))
|
||||
q = q.Where(x => (x.RubberMaterialName ?? "").Contains(rubberMaterialName.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||
if (!string.IsNullOrWhiteSpace(enableStatus))
|
||||
q = q.Where(x => string.Equals(x.EnableStatus, enableStatus.Trim(), StringComparison.OrdinalIgnoreCase));
|
||||
return q.OrderByDescending(x => x.CreateTime ?? DateTime.MinValue).ToList();
|
||||
}
|
||||
|
||||
private void UpsertLocalCacheMain(MesXslRubberQuickTestStd entity)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(entity.Id)) return;
|
||||
lock (_cacheLock)
|
||||
{
|
||||
var idx = _localCache.FindIndex(x => string.Equals(x.Id, entity.Id, StringComparison.OrdinalIgnoreCase));
|
||||
var copy = CloneMain(entity);
|
||||
if (idx >= 0) _localCache[idx] = copy;
|
||||
else _localCache.Insert(0, copy);
|
||||
SaveCacheToDiskUnsafe();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCacheFromDisk()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(_cacheFilePath)) return;
|
||||
_localCache = JsonSerializer.Deserialize<List<MesXslRubberQuickTestStd>>(
|
||||
File.ReadAllText(_cacheFilePath), _jsonOpts) ?? new();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_localCache = new();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveCacheToDiskUnsafe() =>
|
||||
File.WriteAllText(_cacheFilePath, JsonSerializer.Serialize(_localCache, _jsonOpts));
|
||||
|
||||
private static MesXslRubberQuickTestStd CloneMain(MesXslRubberQuickTestStd x) => new()
|
||||
{
|
||||
Id = x.Id,
|
||||
StdName = x.StdName,
|
||||
TestMethodId = x.TestMethodId,
|
||||
TestMethodName = x.TestMethodName,
|
||||
MixerType = x.MixerType,
|
||||
RubberMaterialId = x.RubberMaterialId,
|
||||
RubberMaterialName = x.RubberMaterialName,
|
||||
PsCompileId = x.PsCompileId,
|
||||
IssueNumber = x.IssueNumber,
|
||||
IssueDate = x.IssueDate,
|
||||
IssueDeptId = x.IssueDeptId,
|
||||
IssueDeptName = x.IssueDeptName,
|
||||
EnableStatus = x.EnableStatus,
|
||||
AuditStatus = x.AuditStatus,
|
||||
TenantId = x.TenantId,
|
||||
SysOrgCode = x.SysOrgCode,
|
||||
CreateBy = x.CreateBy,
|
||||
CreateTime = x.CreateTime,
|
||||
UpdateBy = x.UpdateBy,
|
||||
UpdateTime = x.UpdateTime,
|
||||
LineList = x.LineList?.Select(l => new MesXslRubberQuickTestStdLine
|
||||
{
|
||||
Id = l.Id,
|
||||
StdId = l.StdId,
|
||||
DataPointId = l.DataPointId,
|
||||
PointName = l.PointName,
|
||||
LowerLimit = l.LowerLimit,
|
||||
UpperLimit = l.UpperLimit,
|
||||
LowerWarn = l.LowerWarn,
|
||||
UpperWarn = l.UpperWarn,
|
||||
TargetValue = l.TargetValue,
|
||||
SortNo = l.SortNo
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
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",
|
||||
"yyyy-MM-dd"
|
||||
];
|
||||
|
||||
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 dt)) return dt;
|
||||
if (DateTime.TryParse(raw, out var fb)) return fb;
|
||||
}
|
||||
throw new JsonException($"无法转换为 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using Prism.Events;
|
||||
using System.Text.Json;
|
||||
using YY.Admin.Core;
|
||||
using YY.Admin.Core.Events;
|
||||
using YY.Admin.Core.Events;
|
||||
|
||||
namespace YY.Admin.Services.Service.RubberQuickTestStd;
|
||||
|
||||
public class RubberQuickTestStdSyncCoordinator : ISingletonDependency
|
||||
{
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly ILoggerService _logger;
|
||||
|
||||
public RubberQuickTestStdSyncCoordinator(
|
||||
IEventAggregator eventAggregator,
|
||||
SyncPollManager pollManager,
|
||||
ILoggerService logger)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
|
||||
_eventAggregator.GetEvent<RemoteCommandReceivedEvent>()
|
||||
.Subscribe(OnRemoteCommand, ThreadOption.BackgroundThread);
|
||||
_eventAggregator.GetEvent<NetworkStatusChangedEvent>()
|
||||
.Subscribe(OnNetworkStatusChanged, ThreadOption.BackgroundThread);
|
||||
|
||||
pollManager.Register("胶料快检实验标准", () =>
|
||||
{
|
||||
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>()
|
||||
.Publish(new RubberQuickTestStdChangedPayload { Action = "poll" });
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
_logger.Information("[快检实验标准] RubberQuickTestStdSyncCoordinator 已启动");
|
||||
}
|
||||
|
||||
private void OnNetworkStatusChanged(NetworkStatusChangedPayload payload)
|
||||
{
|
||||
if (!payload.IsOnline) return;
|
||||
_logger.Information("[快检实验标准] 网络恢复,触发补偿刷新");
|
||||
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>()
|
||||
.Publish(new RubberQuickTestStdChangedPayload { Action = "reconnect" });
|
||||
}
|
||||
|
||||
private void OnRemoteCommand(RemoteCommandPayload payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = payload.CommandJson ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(json)) return;
|
||||
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
if (!doc.RootElement.TryGetProperty("cmd", out var cmdEl)) return;
|
||||
if (!cmdEl.GetString()?.Equals("MES_RUBBER_QUICK_TEST_STD_CHANGED", StringComparison.OrdinalIgnoreCase) ?? true)
|
||||
return;
|
||||
|
||||
doc.RootElement.TryGetProperty("action", out var actionEl);
|
||||
doc.RootElement.TryGetProperty("stdId", out var idEl);
|
||||
|
||||
var changed = new RubberQuickTestStdChangedPayload
|
||||
{
|
||||
Action = actionEl.GetString() ?? string.Empty,
|
||||
StdId = idEl.ValueKind == JsonValueKind.String ? idEl.GetString() : null
|
||||
};
|
||||
_logger.Information($"[快检实验标准] STOMP action={changed.Action}, stdId={changed.StdId}");
|
||||
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>().Publish(changed);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warning($"[快检实验标准] 处理 STOMP 命令失败:{ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,6 +174,10 @@ public class StompWebSocketService : ISignalRService
|
||||
await SendFrameAsync(
|
||||
BuildSubscribeFrame("sub-print-biz-binds", "/topic/sync/print-biz-binds"),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
// 胶料快检实验标准变更:订阅 /topic/sync/mes-rubber-quick-test-stds
|
||||
await SendFrameAsync(
|
||||
BuildSubscribeFrame("sub-mes-rubber-quick-test-stds", "/topic/sync/mes-rubber-quick-test-stds"),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// 订阅服务端 PONG 回复(应用层假在线检测)
|
||||
await SendFrameAsync(
|
||||
|
||||
@@ -18,6 +18,8 @@ using YY.Admin.Views.WarehouseArea;
|
||||
using YY.Admin.Views.RawMaterialEntry;
|
||||
using YY.Admin.Views.Print;
|
||||
using YY.Admin.Views.MixerMaterialTareStrategy;
|
||||
using YY.Admin.Views.RubberQuickTest;
|
||||
using YY.Admin.Views.RubberQuickTestStd;
|
||||
|
||||
namespace YY.Admin
|
||||
{
|
||||
@@ -95,6 +97,10 @@ namespace YY.Admin
|
||||
containerRegistry.RegisterForNavigation<WarehouseAreaListView>();
|
||||
// 密炼物料皮重策略
|
||||
containerRegistry.RegisterForNavigation<MixerMaterialTareStrategyListView>();
|
||||
// 快检记录操作台
|
||||
containerRegistry.RegisterForNavigation<RubberQuickTestOperationView>();
|
||||
// 胶料快检实验标准(只读)
|
||||
containerRegistry.RegisterForNavigation<RubberQuickTestStdListView>();
|
||||
// 打印设置
|
||||
containerRegistry.RegisterForNavigation<PrintSettingsView>();
|
||||
// 打印模板列表
|
||||
|
||||
@@ -27,6 +27,8 @@ using YY.Admin.Services.Service.Warehouse;
|
||||
using YY.Admin.Services.Service.WarehouseArea;
|
||||
using YY.Admin.Services.Service.WeightRecord;
|
||||
using YY.Admin.Services.Service.Print;
|
||||
using YY.Admin.Services.Service.RubberQuickTest;
|
||||
using YY.Admin.Services.Service.RubberQuickTestStd;
|
||||
|
||||
namespace YY.Admin.Module;
|
||||
|
||||
@@ -86,6 +88,13 @@ public class SyncModule : IModule
|
||||
containerRegistry.RegisterSingleton<PrintTemplateSyncCoordinator>();
|
||||
containerRegistry.RegisterSingleton<PrintBizTemplateBindSyncCoordinator>();
|
||||
|
||||
// 胶料快检记录操作台
|
||||
containerRegistry.RegisterSingleton<IRubberQuickTestOperationService, RubberQuickTestOperationService>();
|
||||
|
||||
// 胶料快检实验标准(MES 只读同步)
|
||||
containerRegistry.RegisterSingleton<IRubberQuickTestStdService, RubberQuickTestStdService>();
|
||||
containerRegistry.RegisterSingleton<RubberQuickTestStdSyncCoordinator>();
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddTransient<DisconnectGuardHandler>();
|
||||
serviceCollection.AddHttpClient("JeecgApi", (sp, client) =>
|
||||
@@ -156,6 +165,8 @@ public class SyncModule : IModule
|
||||
// 强制实例化打印模板同步协调器
|
||||
_ = containerProvider.Resolve<PrintTemplateSyncCoordinator>();
|
||||
_ = containerProvider.Resolve<PrintBizTemplateBindSyncCoordinator>();
|
||||
// 胶料快检实验标准只读同步协调器
|
||||
_ = containerProvider.Resolve<RubberQuickTestStdSyncCoordinator>();
|
||||
}
|
||||
|
||||
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
|
||||
|
||||
@@ -152,6 +152,16 @@ namespace YY.Admin.ViewModels.Control
|
||||
["/xslmes/mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView",
|
||||
["mesXslMixerMaterialTareStrategy"] = "MixerMaterialTareStrategyListView",
|
||||
|
||||
// 已实现页面:快检记录操作台
|
||||
["RubberQuickTestOperationView"] = "RubberQuickTestOperationView",
|
||||
["/xslmes/rubberQuickTestOperation"] = "RubberQuickTestOperationView",
|
||||
["rubberQuickTestOperation"] = "RubberQuickTestOperationView",
|
||||
|
||||
// 已实现页面:胶料快检实验标准(只读)
|
||||
["RubberQuickTestStdListView"] = "RubberQuickTestStdListView",
|
||||
["/xslmes/mesXslRubberQuickTestStd"] = "RubberQuickTestStdListView",
|
||||
["mesXslRubberQuickTestStd"] = "RubberQuickTestStdListView",
|
||||
|
||||
// 已实现页面:打印设置
|
||||
["PrintSettingsView"] = "PrintSettingsView",
|
||||
["/system/printSettings"] = "PrintSettingsView",
|
||||
|
||||
@@ -0,0 +1,755 @@
|
||||
using HandyControl.Controls;
|
||||
using LiveChartsCore;
|
||||
using LiveChartsCore.SkiaSharpView;
|
||||
using LiveChartsCore.SkiaSharpView.Painting;
|
||||
using Prism.Mvvm;
|
||||
using SkiaSharp;
|
||||
using System.Collections.ObjectModel;
|
||||
using YY.Admin.Core;
|
||||
using YY.Admin.Core.Entity;
|
||||
using YY.Admin.Core.Services;
|
||||
using YY.Admin.Core.Session;
|
||||
|
||||
namespace YY.Admin.ViewModels.RubberQuickTest;
|
||||
|
||||
/// <summary>密炼生产计划班次展开项(桌面端筛选用)</summary>
|
||||
public class MixingPlanShiftOption
|
||||
{
|
||||
public string PlanRowId { get; set; } = string.Empty;
|
||||
public string? MachineId { get; set; }
|
||||
public string? MachineName { get; set; }
|
||||
public string ShiftKey { get; set; } = string.Empty;
|
||||
public string ShiftCode { get; set; } = string.Empty;
|
||||
public string ShiftName { get; set; } = string.Empty;
|
||||
public DateTime? OrderDate { get; set; }
|
||||
public string? PlanId { get; set; }
|
||||
public string? OrderNo { get; set; }
|
||||
public string? FormulaName { get; set; }
|
||||
public string DisplayText => string.IsNullOrWhiteSpace(OrderNo)
|
||||
? FormulaName ?? string.Empty
|
||||
: $"{OrderNo} | {FormulaName}";
|
||||
}
|
||||
|
||||
public class QuickTestInspectCellViewModel : BindableBase
|
||||
{
|
||||
public string? DataPointId { get; set; }
|
||||
public string PointName { get; set; } = string.Empty;
|
||||
public decimal? LowerLimit { get; set; }
|
||||
public decimal? UpperLimit { get; set; }
|
||||
|
||||
private decimal? _value;
|
||||
public decimal? Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _value, value))
|
||||
ValueChanged?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<QuickTestInspectCellViewModel>? ValueChanged;
|
||||
}
|
||||
|
||||
public class QuickTestInspectRowViewModel : BindableBase
|
||||
{
|
||||
public string RowNo { get; set; } = string.Empty;
|
||||
public ObservableCollection<QuickTestInspectCellViewModel> Cells { get; } = new();
|
||||
|
||||
private string _inspectResultText = string.Empty;
|
||||
public string InspectResultText
|
||||
{
|
||||
get => _inspectResultText;
|
||||
set => SetProperty(ref _inspectResultText, value);
|
||||
}
|
||||
|
||||
public string InspectResultCode { get; private set; } = "0";
|
||||
|
||||
public void RecalculateResult()
|
||||
{
|
||||
if (Cells.Count == 0)
|
||||
{
|
||||
InspectResultCode = "0";
|
||||
InspectResultText = string.Empty;
|
||||
RaisePropertyChanged(nameof(InspectResultText));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Cells.Any(c => c.Value == null))
|
||||
{
|
||||
InspectResultCode = "0";
|
||||
InspectResultText = "待填写";
|
||||
RaisePropertyChanged(nameof(InspectResultText));
|
||||
return;
|
||||
}
|
||||
|
||||
var pass = Cells.All(c =>
|
||||
{
|
||||
if (c.LowerLimit != null && c.Value < c.LowerLimit) return false;
|
||||
if (c.UpperLimit != null && c.Value > c.UpperLimit) return false;
|
||||
return true;
|
||||
});
|
||||
InspectResultCode = pass ? "1" : "0";
|
||||
InspectResultText = pass ? "合格" : "不合格";
|
||||
RaisePropertyChanged(nameof(InspectResultText));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>胶料快检记录操作台 ViewModel</summary>
|
||||
public class RubberQuickTestOperationViewModel : BaseViewModel
|
||||
{
|
||||
private readonly IRubberQuickTestOperationService _operationService;
|
||||
private readonly Random _rnd = new();
|
||||
private List<MesXslMixingProductionPlan> _allPlans = new();
|
||||
private List<MixingPlanShiftOption> _allShiftOptions = new();
|
||||
private MesXslRubberQuickTestStd? _currentStd;
|
||||
private const int ChartPointCount = 5;
|
||||
|
||||
public event Action? InspectColumnsChanged;
|
||||
|
||||
public RubberQuickTestOperationViewModel(
|
||||
IRubberQuickTestOperationService operationService,
|
||||
IContainerExtension container,
|
||||
IRegionManager regionManager) : base(container, regionManager)
|
||||
{
|
||||
_operationService = operationService;
|
||||
|
||||
_inspectTimesText = "1";
|
||||
|
||||
AddInspectRowCommand = new DelegateCommand(AddInspectRow, () => DataPointColumns.Count > 0);
|
||||
RemoveInspectRowCommand = new DelegateCommand(() => RemoveInspectRow(SelectedInspectRow), () => SelectedInspectRow != null);
|
||||
SaveCommand = new DelegateCommand(async () => await SaveAsync(), () => InspectRows.Count > 0);
|
||||
RefreshPlansCommand = new DelegateCommand(async () => await LoadPlansAsync());
|
||||
RefreshChartDemoCommand = new DelegateCommand(FillRandomChartData);
|
||||
|
||||
TemperatureSeries = new ObservableCollection<ISeries>
|
||||
{
|
||||
new LineSeries<double> { Name = "上模温度", Values = UpperTempValues, GeometrySize = 4, LineSmoothness = 0.3 },
|
||||
new LineSeries<double> { Name = "下模温度", Values = LowerTempValues, GeometrySize = 4, LineSmoothness = 0.3 }
|
||||
};
|
||||
TorqueSeries = new ObservableCollection<ISeries>
|
||||
{
|
||||
new LineSeries<double> { Name = "S'(dNm)", Values = TorqueValues, GeometrySize = 4, LineSmoothness = 0.3 }
|
||||
};
|
||||
|
||||
FillRandomChartData();
|
||||
_ = LoadPlansAsync();
|
||||
}
|
||||
|
||||
/// <summary>中间库未接入时的曲线演示说明</summary>
|
||||
public string ChartDemoHint => "演示数据(中间库未接入,打开页面自动生成;接入后将显示实测曲线)";
|
||||
|
||||
public ObservableCollection<ISeries> TemperatureSeries { get; }
|
||||
public ObservableCollection<ISeries> TorqueSeries { get; }
|
||||
public ObservableCollection<double> UpperTempValues { get; } = new();
|
||||
public ObservableCollection<double> LowerTempValues { get; } = new();
|
||||
public ObservableCollection<double> TorqueValues { get; } = new();
|
||||
|
||||
public Axis[] TemperatureXAxes { get; } = BuildTimeAxis();
|
||||
public Axis[] TemperatureYAxes { get; } = BuildTempYAxis();
|
||||
public Axis[] TorqueXAxes { get; } = BuildTimeAxis();
|
||||
public Axis[] TorqueYAxes { get; } = BuildTorqueYAxis();
|
||||
|
||||
public ObservableCollection<string> MachineOptions { get; } = new();
|
||||
public ObservableCollection<WorkShiftOption> ShiftOptions { get; } = new();
|
||||
public ObservableCollection<MixingPlanShiftOption> PlanOptions { get; } = new();
|
||||
public ObservableCollection<MesXslRubberQuickTestStdLine> DataPointColumns { get; } = new();
|
||||
public ObservableCollection<QuickTestInspectRowViewModel> InspectRows { get; } = new();
|
||||
|
||||
private QuickTestInspectRowViewModel? _selectedInspectRow;
|
||||
public QuickTestInspectRowViewModel? SelectedInspectRow
|
||||
{
|
||||
get => _selectedInspectRow;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedInspectRow, value))
|
||||
RemoveInspectRowCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime _mixingDate = DateTime.Today;
|
||||
public DateTime MixingDate
|
||||
{
|
||||
get => _mixingDate;
|
||||
set
|
||||
{
|
||||
if (!SetProperty(ref _mixingDate, value)) return;
|
||||
RefreshMachineOptions();
|
||||
ClearPlanSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private string? _selectedMachine;
|
||||
public string? SelectedMachine
|
||||
{
|
||||
get => _selectedMachine;
|
||||
set
|
||||
{
|
||||
if (!SetProperty(ref _selectedMachine, value)) return;
|
||||
RefreshShiftOptions();
|
||||
ClearPlanSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private WorkShiftOption? _selectedShift;
|
||||
public WorkShiftOption? SelectedShift
|
||||
{
|
||||
get => _selectedShift;
|
||||
set
|
||||
{
|
||||
if (!SetProperty(ref _selectedShift, value)) return;
|
||||
RefreshPlanOptions();
|
||||
ClearPlanSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private MixingPlanShiftOption? _selectedPlan;
|
||||
public MixingPlanShiftOption? SelectedPlan
|
||||
{
|
||||
get => _selectedPlan;
|
||||
set
|
||||
{
|
||||
if (!SetProperty(ref _selectedPlan, value)) return;
|
||||
ApplySelectedPlan();
|
||||
}
|
||||
}
|
||||
|
||||
public string? ProductionOrderNo => _selectedPlan?.OrderNo;
|
||||
public string? MachineName => _selectedPlan?.MachineName ?? SelectedMachine;
|
||||
public string? WorkShiftDisplay => SelectedShift?.Name ?? string.Empty;
|
||||
public string? RubberMaterialName => _selectedPlan?.FormulaName;
|
||||
|
||||
private string? _trainNo;
|
||||
public string? TrainNo
|
||||
{
|
||||
get => _trainNo;
|
||||
set => SetProperty(ref _trainNo, value);
|
||||
}
|
||||
|
||||
private string? _inspectTimesText;
|
||||
/// <summary>试验次数(手填正整数)</summary>
|
||||
public string? InspectTimesText
|
||||
{
|
||||
get => _inspectTimesText;
|
||||
set => SetProperty(ref _inspectTimesText, value);
|
||||
}
|
||||
|
||||
private double _upperMoldTemp;
|
||||
public double UpperMoldTemp
|
||||
{
|
||||
get => _upperMoldTemp;
|
||||
set => SetProperty(ref _upperMoldTemp, value);
|
||||
}
|
||||
|
||||
private double _lowerMoldTemp;
|
||||
public double LowerMoldTemp
|
||||
{
|
||||
get => _lowerMoldTemp;
|
||||
set => SetProperty(ref _lowerMoldTemp, value);
|
||||
}
|
||||
|
||||
private double _torqueS;
|
||||
public double TorqueS
|
||||
{
|
||||
get => _torqueS;
|
||||
set => SetProperty(ref _torqueS, value);
|
||||
}
|
||||
|
||||
public DelegateCommand AddInspectRowCommand { get; }
|
||||
public DelegateCommand RemoveInspectRowCommand { get; }
|
||||
public DelegateCommand SaveCommand { get; }
|
||||
public DelegateCommand RefreshPlansCommand { get; }
|
||||
public DelegateCommand RefreshChartDemoCommand { get; }
|
||||
|
||||
private async Task LoadPlansAsync()
|
||||
{
|
||||
IsLoading = true;
|
||||
try
|
||||
{
|
||||
_allPlans = await _operationService.GetMixingProductionPlansAsync();
|
||||
BuildAllShiftOptions();
|
||||
RefreshMachineOptions();
|
||||
Growl.Success("密炼生产计划已刷新");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Growl.Error($"加载密炼生产计划失败:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildAllShiftOptions()
|
||||
{
|
||||
_allShiftOptions.Clear();
|
||||
foreach (var row in _allPlans)
|
||||
{
|
||||
AddShiftOption(row, "morning", "1", "早班", row.MorningPlanId, row.MorningOrderDate, row.MorningOrderNo, row.MorningFormulaName);
|
||||
AddShiftOption(row, "noon", "2", "中班", row.NoonPlanId, row.NoonOrderDate, row.NoonOrderNo, row.NoonFormulaName);
|
||||
AddShiftOption(row, "night", "3", "晚班", row.NightPlanId, row.NightOrderDate, row.NightOrderNo, row.NightFormulaName);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddShiftOption(
|
||||
MesXslMixingProductionPlan row, string shiftKey, string shiftCode, string shiftName,
|
||||
string? planId, DateTime? orderDate, string? orderNo, string? formulaName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(planId) || string.IsNullOrWhiteSpace(orderNo)) return;
|
||||
_allShiftOptions.Add(new MixingPlanShiftOption
|
||||
{
|
||||
PlanRowId = row.Id ?? string.Empty,
|
||||
MachineId = row.MachineId,
|
||||
MachineName = row.MachineName,
|
||||
ShiftKey = shiftKey,
|
||||
ShiftCode = shiftCode,
|
||||
ShiftName = shiftName,
|
||||
OrderDate = orderDate,
|
||||
PlanId = planId,
|
||||
OrderNo = orderNo,
|
||||
FormulaName = formulaName
|
||||
});
|
||||
}
|
||||
|
||||
private IEnumerable<MixingPlanShiftOption> FilteredByDate =>
|
||||
_allShiftOptions.Where(o => o.OrderDate?.Date == MixingDate.Date);
|
||||
|
||||
private void RefreshMachineOptions()
|
||||
{
|
||||
MachineOptions.Clear();
|
||||
foreach (var name in FilteredByDate.Select(o => o.MachineName).Where(n => !string.IsNullOrWhiteSpace(n)).Distinct().OrderBy(n => n))
|
||||
MachineOptions.Add(name!);
|
||||
if (SelectedMachine != null && !MachineOptions.Contains(SelectedMachine))
|
||||
SelectedMachine = null;
|
||||
if (SelectedMachine == null && MachineOptions.Count > 0)
|
||||
SelectedMachine = MachineOptions[0];
|
||||
else
|
||||
RefreshShiftOptions();
|
||||
}
|
||||
|
||||
private void RefreshShiftOptions()
|
||||
{
|
||||
ShiftOptions.Clear();
|
||||
var machine = SelectedMachine;
|
||||
var shifts = FilteredByDate
|
||||
.Where(o => string.IsNullOrWhiteSpace(machine) || o.MachineName == machine)
|
||||
.GroupBy(o => o.ShiftCode)
|
||||
.Select(g => g.First())
|
||||
.OrderBy(o => o.ShiftCode);
|
||||
foreach (var s in shifts)
|
||||
ShiftOptions.Add(new WorkShiftOption(s.ShiftCode, s.ShiftName));
|
||||
if (SelectedShift != null && !ShiftOptions.Any(x => x.Code == SelectedShift.Code))
|
||||
SelectedShift = null;
|
||||
if (SelectedShift == null && ShiftOptions.Count > 0)
|
||||
SelectedShift = ShiftOptions[0];
|
||||
else
|
||||
RefreshPlanOptions();
|
||||
}
|
||||
|
||||
private void RefreshPlanOptions()
|
||||
{
|
||||
PlanOptions.Clear();
|
||||
var machine = SelectedMachine;
|
||||
var shiftCode = SelectedShift?.Code;
|
||||
foreach (var o in FilteredByDate
|
||||
.Where(x => string.IsNullOrWhiteSpace(machine) || x.MachineName == machine)
|
||||
.Where(x => string.IsNullOrWhiteSpace(shiftCode) || x.ShiftCode == shiftCode)
|
||||
.OrderBy(x => x.OrderNo))
|
||||
PlanOptions.Add(o);
|
||||
if (SelectedPlan != null && PlanOptions.All(p => p.PlanId != SelectedPlan.PlanId))
|
||||
SelectedPlan = null;
|
||||
if (SelectedPlan == null && PlanOptions.Count > 0)
|
||||
SelectedPlan = PlanOptions[0];
|
||||
}
|
||||
|
||||
private void ClearPlanSelection()
|
||||
{
|
||||
_selectedPlan = null;
|
||||
RaisePropertyChanged(nameof(SelectedPlan));
|
||||
RaisePropertyChanged(nameof(ProductionOrderNo));
|
||||
RaisePropertyChanged(nameof(MachineName));
|
||||
RaisePropertyChanged(nameof(WorkShiftDisplay));
|
||||
RaisePropertyChanged(nameof(RubberMaterialName));
|
||||
ClearStdAndResults();
|
||||
}
|
||||
|
||||
private void ApplySelectedPlan()
|
||||
{
|
||||
RaisePropertyChanged(nameof(ProductionOrderNo));
|
||||
RaisePropertyChanged(nameof(MachineName));
|
||||
RaisePropertyChanged(nameof(WorkShiftDisplay));
|
||||
RaisePropertyChanged(nameof(RubberMaterialName));
|
||||
_ = LoadStdAsync();
|
||||
}
|
||||
|
||||
private async Task LoadStdAsync()
|
||||
{
|
||||
DataPointColumns.Clear();
|
||||
InspectRows.Clear();
|
||||
_currentStd = null;
|
||||
InspectColumnsChanged?.Invoke();
|
||||
|
||||
var rubberName = RubberMaterialName;
|
||||
if (string.IsNullOrWhiteSpace(rubberName)) return;
|
||||
|
||||
IsLoading = true;
|
||||
try
|
||||
{
|
||||
_currentStd = await _operationService.GetStdByRubberMaterialNameAsync(rubberName);
|
||||
if (_currentStd?.LineList == null || _currentStd.LineList.Count == 0)
|
||||
{
|
||||
Growl.Warning($"未找到胶料「{rubberName}」的使用中且已批准的快检实验标准");
|
||||
return;
|
||||
}
|
||||
foreach (var line in _currentStd.LineList.OrderBy(l => l.SortNo ?? 0))
|
||||
DataPointColumns.Add(line);
|
||||
InspectColumnsChanged?.Invoke();
|
||||
AddInspectRow();
|
||||
AddInspectRowCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Growl.Error($"加载实验标准失败:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearStdAndResults()
|
||||
{
|
||||
DataPointColumns.Clear();
|
||||
InspectRows.Clear();
|
||||
_currentStd = null;
|
||||
InspectColumnsChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>打开页面或中间库无数据时填充曲线演示数据(5 点对应 0~2min)</summary>
|
||||
private void FillRandomChartData()
|
||||
{
|
||||
UpperTempValues.Clear();
|
||||
LowerTempValues.Clear();
|
||||
TorqueValues.Clear();
|
||||
|
||||
for (int i = 0; i < ChartPointCount; i++)
|
||||
{
|
||||
var upper = 192 + _rnd.NextDouble() * 8;
|
||||
var lower = upper - 2 - _rnd.NextDouble() * 2;
|
||||
var torque = Math.Min(14, i * 2.5 + _rnd.NextDouble() * 2.5);
|
||||
UpperTempValues.Add(Math.Round(upper, 2));
|
||||
LowerTempValues.Add(Math.Round(lower, 2));
|
||||
TorqueValues.Add(Math.Round(torque, 2));
|
||||
}
|
||||
|
||||
UpperMoldTemp = UpperTempValues[^1];
|
||||
LowerMoldTemp = LowerTempValues[^1];
|
||||
TorqueS = TorqueValues[^1];
|
||||
}
|
||||
|
||||
private void AddInspectRow()
|
||||
{
|
||||
var rowIndex = InspectRows.Count + 1;
|
||||
var row = new QuickTestInspectRowViewModel { RowNo = $"{rowIndex}_1" };
|
||||
foreach (var col in DataPointColumns)
|
||||
{
|
||||
var cell = new QuickTestInspectCellViewModel
|
||||
{
|
||||
DataPointId = col.DataPointId,
|
||||
PointName = col.PointName ?? string.Empty,
|
||||
LowerLimit = col.LowerLimit,
|
||||
UpperLimit = col.UpperLimit
|
||||
};
|
||||
cell.ValueChanged += _ => row.RecalculateResult();
|
||||
row.Cells.Add(cell);
|
||||
}
|
||||
row.RecalculateResult();
|
||||
InspectRows.Add(row);
|
||||
SaveCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
private void RemoveInspectRow(QuickTestInspectRowViewModel? row)
|
||||
{
|
||||
if (row == null) return;
|
||||
InspectRows.Remove(row);
|
||||
SelectedInspectRow = null;
|
||||
SaveCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
private async Task SaveAsync()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(TrainNo))
|
||||
{
|
||||
Growl.Warning("请填写车次");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(ProductionOrderNo))
|
||||
{
|
||||
Growl.Warning("请选择密炼计划以带出生产订单号");
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(RubberMaterialName))
|
||||
{
|
||||
Growl.Warning("请先选择密炼计划以带出胶料名称");
|
||||
return;
|
||||
}
|
||||
if (_currentStd == null)
|
||||
{
|
||||
Growl.Warning("未加载实验标准,无法保存");
|
||||
return;
|
||||
}
|
||||
|
||||
if (InspectRows.Any(r => r.InspectResultText == "待填写" || string.IsNullOrWhiteSpace(r.InspectResultText)))
|
||||
{
|
||||
Growl.Warning("请手填全部检验行的检测值后再保存");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryParseInspectTimes(out var inspectTimes, out var inspectTimesError))
|
||||
{
|
||||
Growl.Warning(inspectTimesError);
|
||||
return;
|
||||
}
|
||||
|
||||
var lineList = BuildAveragedLineList();
|
||||
if (lineList.Count == 0)
|
||||
{
|
||||
Growl.Warning("无法根据试验结果计算明细数据");
|
||||
return;
|
||||
}
|
||||
|
||||
var rawLineList = BuildRawLineList();
|
||||
if (rawLineList.Count == 0)
|
||||
{
|
||||
Growl.Warning("无法生成试验结果原始数据");
|
||||
return;
|
||||
}
|
||||
|
||||
var user = AppSession.CurrentUser;
|
||||
IsLoading = true;
|
||||
try
|
||||
{
|
||||
var record = BuildSaveRecord(lineList, rawLineList, inspectTimes, user);
|
||||
await _operationService.SaveRecordAsync(record);
|
||||
Growl.Success("快检记录已保存到 MES");
|
||||
InspectRows.Clear();
|
||||
SaveCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Growl.Error($"保存失败:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryParseInspectTimes(out int value, out string error)
|
||||
{
|
||||
error = string.Empty;
|
||||
var text = string.IsNullOrWhiteSpace(InspectTimesText) ? "1" : InspectTimesText.Trim();
|
||||
if (!int.TryParse(text, out var n) || n <= 0)
|
||||
{
|
||||
error = "试验次数须填写正整数";
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>试验结果各数据点检测值取平均,写入快检记录明细</summary>
|
||||
private List<MesXslRubberQuickTestRecordLine> BuildAveragedLineList()
|
||||
{
|
||||
var lines = new List<MesXslRubberQuickTestRecordLine>();
|
||||
for (int i = 0; i < DataPointColumns.Count; i++)
|
||||
{
|
||||
var col = DataPointColumns[i];
|
||||
var values = InspectRows
|
||||
.Where(r => i < r.Cells.Count && r.Cells[i].Value != null)
|
||||
.Select(r => r.Cells[i].Value!.Value)
|
||||
.ToList();
|
||||
if (values.Count == 0)
|
||||
continue;
|
||||
|
||||
var avg = values.Average(v => (double)v);
|
||||
var avgDecimal = Math.Round((decimal)avg, 6);
|
||||
|
||||
var line = new MesXslRubberQuickTestRecordLine { SortNo = i };
|
||||
if (!string.IsNullOrWhiteSpace(col.DataPointId))
|
||||
line.DataPointId = col.DataPointId;
|
||||
if (!string.IsNullOrWhiteSpace(col.PointName))
|
||||
line.InspectItem = col.PointName;
|
||||
if (col.LowerLimit != null)
|
||||
line.LowerLimit = col.LowerLimit;
|
||||
if (col.UpperLimit != null)
|
||||
line.UpperLimit = col.UpperLimit;
|
||||
line.InspectValue = avgDecimal;
|
||||
lines.Add(line);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
/// <summary>试验结果全部检测值写入原始数据明细</summary>
|
||||
private List<MesXslRubberQuickTestRecordRawLine> BuildRawLineList()
|
||||
{
|
||||
var rawLines = new List<MesXslRubberQuickTestRecordRawLine>();
|
||||
int sort = 0;
|
||||
foreach (var row in InspectRows)
|
||||
{
|
||||
for (int i = 0; i < row.Cells.Count; i++)
|
||||
{
|
||||
var cell = row.Cells[i];
|
||||
if (cell.Value == null)
|
||||
continue;
|
||||
|
||||
var raw = new MesXslRubberQuickTestRecordRawLine { SortNo = sort++ };
|
||||
if (!string.IsNullOrWhiteSpace(row.RowNo))
|
||||
raw.RowNo = row.RowNo;
|
||||
if (!string.IsNullOrWhiteSpace(cell.DataPointId))
|
||||
raw.DataPointId = cell.DataPointId;
|
||||
if (!string.IsNullOrWhiteSpace(cell.PointName))
|
||||
raw.InspectItem = cell.PointName;
|
||||
if (cell.LowerLimit != null)
|
||||
raw.LowerLimit = cell.LowerLimit;
|
||||
if (cell.UpperLimit != null)
|
||||
raw.UpperLimit = cell.UpperLimit;
|
||||
raw.InspectValue = cell.Value;
|
||||
raw.RowInspectResult = row.InspectResultCode;
|
||||
rawLines.Add(raw);
|
||||
}
|
||||
}
|
||||
return rawLines;
|
||||
}
|
||||
|
||||
/// <summary>主表检验结果:任一行不合格则不合格</summary>
|
||||
private static string JudgeInspectResultFromRows(IEnumerable<QuickTestInspectRowViewModel> rows)
|
||||
{
|
||||
if (!rows.Any())
|
||||
return "0";
|
||||
return rows.Any(r => r.InspectResultCode != "1") ? "0" : "1";
|
||||
}
|
||||
|
||||
private MesXslRubberQuickTestRecord BuildSaveRecord(
|
||||
List<MesXslRubberQuickTestRecordLine> lineList,
|
||||
List<MesXslRubberQuickTestRecordRawLine> rawLineList,
|
||||
int inspectTimes,
|
||||
SysUser? user)
|
||||
{
|
||||
var record = new MesXslRubberQuickTestRecord
|
||||
{
|
||||
LineList = lineList,
|
||||
RawLineList = rawLineList,
|
||||
InspectTime = DateTime.Now,
|
||||
InspectResult = JudgeInspectResultFromRows(InspectRows)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_currentStd?.RubberMaterialId))
|
||||
record.RubberMaterialId = _currentStd.RubberMaterialId;
|
||||
if (!string.IsNullOrWhiteSpace(RubberMaterialName))
|
||||
record.RubberMaterialName = RubberMaterialName;
|
||||
if (!string.IsNullOrWhiteSpace(_currentStd?.Id))
|
||||
record.StdId = _currentStd.Id;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_selectedPlan?.MachineId))
|
||||
record.ProdEquipmentLedgerId = _selectedPlan.MachineId;
|
||||
if (!string.IsNullOrWhiteSpace(MachineName))
|
||||
record.ProdEquipmentName = MachineName;
|
||||
|
||||
record.ProductionDate = MixingDate;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(TrainNo))
|
||||
record.TrainNo = TrainNo.Trim();
|
||||
|
||||
if (SelectedShift != null && !string.IsNullOrWhiteSpace(SelectedShift.Code))
|
||||
record.WorkShift = SelectedShift.Code;
|
||||
|
||||
record.InspectTimes = inspectTimes;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ProductionOrderNo))
|
||||
record.ProductionPlanNo = ProductionOrderNo;
|
||||
|
||||
var inspectorId = user?.JeecgBizUserId ?? (user != null ? user.Id.ToString() : null);
|
||||
if (!string.IsNullOrWhiteSpace(inspectorId))
|
||||
record.InspectorUserId = inspectorId;
|
||||
if (!string.IsNullOrWhiteSpace(user?.Account))
|
||||
record.InspectorUsername = user.Account;
|
||||
if (!string.IsNullOrWhiteSpace(user?.RealName))
|
||||
record.InspectorRealname = user.RealName;
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
private static Axis[] BuildTimeAxis() => new[]
|
||||
{
|
||||
new Axis
|
||||
{
|
||||
Name = "时间(min)",
|
||||
MinLimit = 0,
|
||||
MaxLimit = 2,
|
||||
Labels = new[] { "0", "0.5", "1", "1.5", "2" },
|
||||
LabelsPaint = new SolidColorPaint(SKColors.Gray),
|
||||
NamePaint = new SolidColorPaint(SKColors.Gray)
|
||||
}
|
||||
};
|
||||
|
||||
private static Axis[] BuildTempYAxis() => new[]
|
||||
{
|
||||
new Axis
|
||||
{
|
||||
Name = "温度(℃)",
|
||||
MinLimit = 189,
|
||||
MaxLimit = 201,
|
||||
Labeler = v => v switch
|
||||
{
|
||||
189 => "189",
|
||||
192 => "192",
|
||||
195 => "195",
|
||||
198 => "198",
|
||||
201 => "201",
|
||||
_ => string.Empty
|
||||
},
|
||||
LabelsPaint = new SolidColorPaint(SKColors.Gray),
|
||||
NamePaint = new SolidColorPaint(SKColors.Gray)
|
||||
}
|
||||
};
|
||||
|
||||
private static Axis[] BuildTorqueYAxis() => new[]
|
||||
{
|
||||
new Axis
|
||||
{
|
||||
Name = "S'(dNm)",
|
||||
MinLimit = 0,
|
||||
MaxLimit = 14,
|
||||
Labeler = v => v switch
|
||||
{
|
||||
0 => "0",
|
||||
3 => "3",
|
||||
6 => "6",
|
||||
8 => "8",
|
||||
11 => "11",
|
||||
14 => "14",
|
||||
_ => string.Empty
|
||||
},
|
||||
LabelsPaint = new SolidColorPaint(SKColors.Gray),
|
||||
NamePaint = new SolidColorPaint(SKColors.Gray)
|
||||
}
|
||||
};
|
||||
|
||||
public new void Destroy() => base.Destroy();
|
||||
}
|
||||
|
||||
public class WorkShiftOption
|
||||
{
|
||||
public WorkShiftOption(string code, string name)
|
||||
{
|
||||
Code = code;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Code { get; }
|
||||
public string Name { get; }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using HandyControl.Tools.Extension;
|
||||
using Prism.Commands;
|
||||
using System.Collections.ObjectModel;
|
||||
using YY.Admin.Core.Entity;
|
||||
using YY.Admin.ViewModels;
|
||||
|
||||
namespace YY.Admin.ViewModels.RubberQuickTestStd;
|
||||
|
||||
public class RubberQuickTestStdDetailDialogViewModel : BaseViewModel, IDialogResultable<bool>
|
||||
{
|
||||
private MesXslRubberQuickTestStd? _std;
|
||||
public MesXslRubberQuickTestStd? Std
|
||||
{
|
||||
get => _std;
|
||||
private set => SetProperty(ref _std, value);
|
||||
}
|
||||
|
||||
public ObservableCollection<MesXslRubberQuickTestStdLine> Lines { get; } = new();
|
||||
|
||||
private bool _result;
|
||||
public bool Result { get => _result; set => SetProperty(ref _result, value); }
|
||||
public Action? CloseAction { get; set; }
|
||||
|
||||
public RubberQuickTestStdDetailDialogViewModel(
|
||||
IContainerExtension container,
|
||||
IRegionManager regionManager) : base(container, regionManager)
|
||||
{
|
||||
CloseCommand = new DelegateCommand(() => CloseAction?.Invoke());
|
||||
}
|
||||
|
||||
public DelegateCommand CloseCommand { get; }
|
||||
|
||||
public void Initialize(MesXslRubberQuickTestStd std)
|
||||
{
|
||||
Std = std;
|
||||
Lines.Clear();
|
||||
foreach (var line in std.LineList ?? [])
|
||||
Lines.Add(line);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
using HandyControl.Controls;
|
||||
using HandyControl.Tools.Extension;
|
||||
using Prism.Events;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using YY.Admin.Core;
|
||||
using YY.Admin.Core.Entity;
|
||||
using YY.Admin.Core.Events;
|
||||
using YY.Admin.Core.Helper;
|
||||
using YY.Admin.Core.Services;
|
||||
using YY.Admin.Services.Service;
|
||||
using YY.Admin.Views.RubberQuickTestStd;
|
||||
|
||||
namespace YY.Admin.ViewModels.RubberQuickTestStd;
|
||||
|
||||
public class RubberQuickTestStdListViewModel : BaseViewModel
|
||||
{
|
||||
private readonly IRubberQuickTestStdService _stdService;
|
||||
private readonly IJeecgDictSyncService _dictSyncService;
|
||||
private SubscriptionToken? _changedToken;
|
||||
|
||||
private ObservableCollection<MesXslRubberQuickTestStd> _items = new();
|
||||
public ObservableCollection<MesXslRubberQuickTestStd> Items
|
||||
{
|
||||
get => _items;
|
||||
set => SetProperty(ref _items, value);
|
||||
}
|
||||
|
||||
private long _total;
|
||||
public long Total { get => _total; set => SetProperty(ref _total, value); }
|
||||
|
||||
private int _pageNo = 1;
|
||||
public int PageNo { get => _pageNo; set => SetProperty(ref _pageNo, value); }
|
||||
|
||||
private int _pageSize = 20;
|
||||
public int PageSize { get => _pageSize; set => SetProperty(ref _pageSize, value); }
|
||||
|
||||
private string? _filterStdName;
|
||||
public string? FilterStdName { get => _filterStdName; set => SetProperty(ref _filterStdName, value); }
|
||||
|
||||
private string? _filterRubberMaterialName;
|
||||
public string? FilterRubberMaterialName { get => _filterRubberMaterialName; set => SetProperty(ref _filterRubberMaterialName, value); }
|
||||
|
||||
private string? _filterEnableStatus;
|
||||
public string? FilterEnableStatus { get => _filterEnableStatus; set => SetProperty(ref _filterEnableStatus, value); }
|
||||
|
||||
public ObservableCollection<KeyValuePair<string, string>> EnableStatusOptions { get; } = new();
|
||||
|
||||
public DelegateCommand SearchCommand { get; }
|
||||
public DelegateCommand ResetCommand { get; }
|
||||
public DelegateCommand<MesXslRubberQuickTestStd> ViewDetailCommand { get; }
|
||||
public DelegateCommand PrevPageCommand { get; }
|
||||
public DelegateCommand NextPageCommand { get; }
|
||||
|
||||
public RubberQuickTestStdListViewModel(
|
||||
IRubberQuickTestStdService stdService,
|
||||
IJeecgDictSyncService dictSyncService,
|
||||
IContainerExtension container,
|
||||
IRegionManager regionManager) : base(container, regionManager)
|
||||
{
|
||||
_stdService = stdService;
|
||||
_dictSyncService = dictSyncService;
|
||||
|
||||
SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); });
|
||||
ResetCommand = new DelegateCommand(async () =>
|
||||
{
|
||||
FilterStdName = null;
|
||||
FilterRubberMaterialName = null;
|
||||
FilterEnableStatus = null;
|
||||
PageNo = 1;
|
||||
await LoadAsync();
|
||||
});
|
||||
ViewDetailCommand = new DelegateCommand<MesXslRubberQuickTestStd>(async x => await ShowDetailAsync(x));
|
||||
PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } });
|
||||
NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } });
|
||||
|
||||
_changedToken = _eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>()
|
||||
.Subscribe(async _ => await LoadAsync(), ThreadOption.UIThread);
|
||||
|
||||
_ = InitializeAsync();
|
||||
}
|
||||
|
||||
private async Task InitializeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadDictOptionsAsync();
|
||||
await UIHelper.WaitForRenderAsync();
|
||||
await LoadAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"快检实验标准列表初始化失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadDictOptionsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var opts = await _dictSyncService.GetDictOptionsAsync("xslmes_rubber_quick_test_std_enable_status", includeAll: true);
|
||||
EnableStatusOptions.Clear();
|
||||
foreach (var item in opts) EnableStatusOptions.Add(item);
|
||||
}
|
||||
catch
|
||||
{
|
||||
EnableStatusOptions.Clear();
|
||||
EnableStatusOptions.Add(new KeyValuePair<string, string>("全部", ""));
|
||||
EnableStatusOptions.Add(new KeyValuePair<string, string>("使用中", "1"));
|
||||
EnableStatusOptions.Add(new KeyValuePair<string, string>("已停用", "0"));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task LoadAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
var result = await _stdService.PageAsync(
|
||||
PageNo, PageSize, FilterStdName, FilterRubberMaterialName, FilterEnableStatus);
|
||||
Items = new ObservableCollection<MesXslRubberQuickTestStd>(result.Records);
|
||||
Total = result.Total;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Growl.Error($"加载快检实验标准失败:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ShowDetailAsync(MesXslRubberQuickTestStd? row)
|
||||
{
|
||||
if (row?.Id == null) return;
|
||||
try
|
||||
{
|
||||
var detail = await _stdService.GetByIdAsync(row.Id);
|
||||
if (detail == null)
|
||||
{
|
||||
Growl.Warning("未找到该实验标准,可能已被删除");
|
||||
await LoadAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await HandyControl.Controls.Dialog.Show<RubberQuickTestStdDetailDialogView>()
|
||||
.Initialize<RubberQuickTestStdDetailDialogViewModel>(vm => vm.Initialize(detail))
|
||||
.GetResultAsync<bool>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Growl.Error($"打开详情失败:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CleanUp()
|
||||
{
|
||||
base.CleanUp();
|
||||
if (_changedToken != null)
|
||||
{
|
||||
_eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>().Unsubscribe(_changedToken);
|
||||
_changedToken = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
<UserControl x:Class="YY.Admin.Views.RubberQuickTest.RubberQuickTestOperationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<Style x:Key="SectionBorderStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="Background" Value="{DynamicResource ThirdlyRegionBrush}"/>
|
||||
<Setter Property="Padding" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,0,10"/>
|
||||
</Style>
|
||||
<Style x:Key="SectionTitleStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}"/>
|
||||
<Setter Property="Margin" Value="8,0,0,0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="64"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="56"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 标题 -->
|
||||
<Border Grid.Row="0" Background="{DynamicResource RegionBrush}"
|
||||
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="0,0,0,1" Margin="-12,0,-12,8">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="20,0">
|
||||
<Border Width="40" Height="40" CornerRadius="8" Background="{DynamicResource PrimaryBrush}" Margin="0,0,12,0">
|
||||
<md:PackIcon Kind="Flask" Width="22" Height="22" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<StackPanel>
|
||||
<TextBlock Text="快检记录" FontSize="18" FontWeight="Bold"/>
|
||||
<TextBlock Text="密炼快检试验操作台" FontSize="12" Foreground="{DynamicResource SecondaryTextBrush}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 主体 2:1 -->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="12"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 左侧:曲线 + 试验结果 -->
|
||||
<ScrollViewer Grid.Column="0" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
<Border Style="{StaticResource SectionBorderStyle}">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<Border Width="4" Height="18" CornerRadius="2" Background="#1890ff"/>
|
||||
<TextBlock Text="温度(℃)曲线" Style="{StaticResource SectionTitleStyle}"/>
|
||||
<Button Content="刷新演示" Command="{Binding RefreshChartDemoCommand}" Style="{StaticResource ButtonDefault}" Height="28" Padding="10,0" Margin="12,0,0,0"/>
|
||||
</StackPanel>
|
||||
<TextBlock Text="{Binding ChartDemoHint}" FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,0,0,6"/>
|
||||
<Border Height="220" CornerRadius="4">
|
||||
<lvc:CartesianChart Series="{Binding TemperatureSeries}"
|
||||
XAxes="{Binding TemperatureXAxes}"
|
||||
YAxes="{Binding TemperatureYAxes}"
|
||||
LegendPosition="Top"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Style="{StaticResource SectionBorderStyle}">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<Border Width="4" Height="18" CornerRadius="2" Background="#1890ff"/>
|
||||
<TextBlock Text="S'(dNm)曲线" Style="{StaticResource SectionTitleStyle}"/>
|
||||
</StackPanel>
|
||||
<Border Height="200" CornerRadius="4">
|
||||
<lvc:CartesianChart Series="{Binding TorqueSeries}"
|
||||
XAxes="{Binding TorqueXAxes}"
|
||||
YAxes="{Binding TorqueYAxes}"
|
||||
LegendPosition="Top"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Style="{StaticResource SectionBorderStyle}">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,0,0,8">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border Width="4" Height="18" CornerRadius="2" Background="#1890ff"/>
|
||||
<TextBlock Text="试验结果" Style="{StaticResource SectionTitleStyle}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="新增检验行" Command="{Binding AddInspectRowCommand}" Style="{StaticResource ButtonPrimary}" Height="28" Padding="10,0" Margin="0,0,8,0"/>
|
||||
<Button Content="删除选中行" Command="{Binding RemoveInspectRowCommand}" Style="{StaticResource ButtonDanger}" Height="28" Padding="10,0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<DataGrid x:Name="InspectResultGrid"
|
||||
ItemsSource="{Binding InspectRows}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
CanUserDeleteRows="False"
|
||||
HeadersVisibility="Column"
|
||||
MinHeight="160"
|
||||
SelectionMode="Single"
|
||||
IsReadOnly="False"
|
||||
SelectionChanged="InspectResultGrid_SelectionChanged">
|
||||
</DataGrid>
|
||||
<TextBlock Text="请手填各数据点检测值,系统将根据数据标准上下限自动判定合格/不合格" FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,6,0,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- 右侧 -->
|
||||
<ScrollViewer Grid.Column="2" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
<!-- 实时数据 -->
|
||||
<Border Style="{StaticResource SectionBorderStyle}">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,12">
|
||||
<Border Width="4" Height="18" CornerRadius="2" Background="#52c41a"/>
|
||||
<TextBlock Text="实时数据" Style="{StaticResource SectionTitleStyle}"/>
|
||||
</StackPanel>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="上模温度(℃)" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,0,0,4"/>
|
||||
<TextBlock Grid.Row="1" Text="{Binding UpperMoldTemp, StringFormat={}{0:N2}}" FontSize="28" FontWeight="Bold" FontFamily="Consolas"/>
|
||||
<TextBlock Grid.Column="1" Text="下模温度(℃)" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,0,0,4"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding LowerMoldTemp, StringFormat={}{0:N2}}" FontSize="28" FontWeight="Bold" FontFamily="Consolas"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="S'(dNm)" Foreground="{DynamicResource SecondaryTextBrush}" Margin="0,12,0,4"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,32,0,0" Text="{Binding TorqueS, StringFormat={}{0:N2}}" FontSize="28" FontWeight="Bold" FontFamily="Consolas"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 试验信息 -->
|
||||
<Border Style="{StaticResource SectionBorderStyle}">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,0,0,12">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border Width="4" Height="18" CornerRadius="2" Background="#1890ff"/>
|
||||
<TextBlock Text="试验信息" Style="{StaticResource SectionTitleStyle}"/>
|
||||
</StackPanel>
|
||||
<Button Content="刷新计划" Command="{Binding RefreshPlansCommand}"
|
||||
Style="{StaticResource ButtonDefault}" Height="26" Padding="8,0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
|
||||
<hc:Row Gutter="10">
|
||||
<!-- 密炼日期 -->
|
||||
<hc:Col Span="12">
|
||||
<hc:DatePicker SelectedDate="{Binding MixingDate}"
|
||||
hc:InfoElement.Title="密炼日期"
|
||||
hc:InfoElement.TitleWidth="90"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.Necessary="True"
|
||||
hc:InfoElement.Symbol="*"
|
||||
Margin="0,0,0,8"/>
|
||||
</hc:Col>
|
||||
<!-- 密炼机台 -->
|
||||
<hc:Col Span="12">
|
||||
<hc:ComboBox ItemsSource="{Binding MachineOptions}"
|
||||
SelectedItem="{Binding SelectedMachine}"
|
||||
hc:InfoElement.Title="密炼机台"
|
||||
hc:InfoElement.TitleWidth="90"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.Placeholder="请先选择密炼日期"
|
||||
hc:InfoElement.Necessary="True"
|
||||
hc:InfoElement.Symbol="*"
|
||||
Margin="0,0,0,8"/>
|
||||
</hc:Col>
|
||||
<!-- 班次 -->
|
||||
<hc:Col Span="12">
|
||||
<hc:ComboBox ItemsSource="{Binding ShiftOptions}"
|
||||
SelectedItem="{Binding SelectedShift}"
|
||||
DisplayMemberPath="Name"
|
||||
hc:InfoElement.Title="班次"
|
||||
hc:InfoElement.TitleWidth="90"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.Placeholder="请先选择机台"
|
||||
hc:InfoElement.Necessary="True"
|
||||
hc:InfoElement.Symbol="*"
|
||||
Margin="0,0,0,8"/>
|
||||
</hc:Col>
|
||||
<!-- 密炼生产计划 -->
|
||||
<hc:Col Span="24">
|
||||
<hc:ComboBox ItemsSource="{Binding PlanOptions}"
|
||||
SelectedItem="{Binding SelectedPlan}"
|
||||
DisplayMemberPath="DisplayText"
|
||||
hc:InfoElement.Title="密炼计划"
|
||||
hc:InfoElement.TitleWidth="90"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.Placeholder="按日期、机台、班次筛选后选择"
|
||||
hc:InfoElement.Necessary="True"
|
||||
hc:InfoElement.Symbol="*"
|
||||
Margin="0,0,0,8"/>
|
||||
</hc:Col>
|
||||
<!-- 生产订单号 -->
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding ProductionOrderNo, Mode=OneWay}"
|
||||
IsReadOnly="True"
|
||||
hc:InfoElement.Title="生产订单号"
|
||||
hc:InfoElement.TitleWidth="90"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.Placeholder="选择计划后自动带出"
|
||||
hc:InfoElement.Necessary="True"
|
||||
hc:InfoElement.Symbol="*"
|
||||
Margin="0,0,0,8"/>
|
||||
</hc:Col>
|
||||
<!-- 胶料名称 -->
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding RubberMaterialName, Mode=OneWay}"
|
||||
IsReadOnly="True"
|
||||
hc:InfoElement.Title="胶料名称"
|
||||
hc:InfoElement.TitleWidth="90"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.Placeholder="选择计划后自动带出"
|
||||
Margin="0,0,0,8"/>
|
||||
</hc:Col>
|
||||
<!-- 车次 -->
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding TrainNo, UpdateSourceTrigger=PropertyChanged}"
|
||||
hc:InfoElement.Title="车次"
|
||||
hc:InfoElement.TitleWidth="90"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.Placeholder="手填车次"
|
||||
hc:InfoElement.Necessary="True"
|
||||
hc:InfoElement.Symbol="*"
|
||||
hc:InfoElement.ShowClearButton="True"
|
||||
Margin="0,0,0,8"/>
|
||||
</hc:Col>
|
||||
<!-- 试验次数 -->
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding InspectTimesText, UpdateSourceTrigger=PropertyChanged}"
|
||||
hc:InfoElement.Title="试验次数"
|
||||
hc:InfoElement.TitleWidth="90"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.Placeholder="默认 1,可修改"
|
||||
hc:InfoElement.Necessary="True"
|
||||
hc:InfoElement.Symbol="*"
|
||||
hc:InfoElement.ShowClearButton="True"
|
||||
Margin="0,0,0,0"/>
|
||||
</hc:Col>
|
||||
</hc:Row>
|
||||
|
||||
<TextBlock Text="按密炼日期 → 机台 → 班次筛选生产计划;胶料名称用于匹配快检实验标准"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource SecondaryTextBrush}"
|
||||
Margin="0,8,0,0"
|
||||
TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 数据标准 -->
|
||||
<Border Style="{StaticResource SectionBorderStyle}">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<Border Width="4" Height="18" CornerRadius="2" Background="#faad14"/>
|
||||
<TextBlock Text="数据标准" Style="{StaticResource SectionTitleStyle}"/>
|
||||
</StackPanel>
|
||||
<DataGrid ItemsSource="{Binding DataPointColumns}"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column"
|
||||
MaxHeight="240">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="数据点" Binding="{Binding PointName}" Width="*"/>
|
||||
<DataGridTextColumn Header="下限值" Binding="{Binding LowerLimit}" Width="70"/>
|
||||
<DataGridTextColumn Header="上限值" Binding="{Binding UpperLimit}" Width="70"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!-- 底部操作 -->
|
||||
<Border Grid.Row="2" Background="{DynamicResource RegionBrush}" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="0,1,0,0" Margin="-12,8,-12,-12">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="20,0">
|
||||
<Button Content="保存快检记录" Command="{Binding SaveCommand}" Style="{StaticResource ButtonPrimary}" Height="36" Width="140"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Windows.Controls;
|
||||
using YY.Admin.ViewModels.RubberQuickTest;
|
||||
|
||||
namespace YY.Admin.Views.RubberQuickTest;
|
||||
|
||||
public partial class RubberQuickTestOperationView : UserControl
|
||||
{
|
||||
private RubberQuickTestOperationViewModel? _vm;
|
||||
|
||||
public RubberQuickTestOperationView()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += OnDataContextChanged;
|
||||
}
|
||||
|
||||
private void OnDataContextChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (_vm != null)
|
||||
_vm.InspectColumnsChanged -= RebuildInspectColumns;
|
||||
_vm = DataContext as RubberQuickTestOperationViewModel;
|
||||
if (_vm != null)
|
||||
{
|
||||
_vm.InspectColumnsChanged += RebuildInspectColumns;
|
||||
RebuildInspectColumns();
|
||||
}
|
||||
}
|
||||
|
||||
private void RebuildInspectColumns()
|
||||
{
|
||||
if (_vm == null) return;
|
||||
|
||||
InspectResultGrid.Columns.Clear();
|
||||
InspectResultGrid.Columns.Add(new DataGridTextColumn
|
||||
{
|
||||
Header = "编号",
|
||||
Binding = new System.Windows.Data.Binding("RowNo"),
|
||||
IsReadOnly = true,
|
||||
Width = 80
|
||||
});
|
||||
|
||||
for (int i = 0; i < _vm.DataPointColumns.Count; i++)
|
||||
{
|
||||
var col = _vm.DataPointColumns[i];
|
||||
var binding = new System.Windows.Data.Binding($"Cells[{i}].Value")
|
||||
{
|
||||
UpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
|
||||
Mode = System.Windows.Data.BindingMode.TwoWay
|
||||
};
|
||||
InspectResultGrid.Columns.Add(new DataGridTextColumn
|
||||
{
|
||||
Header = col.PointName ?? $"点{i + 1}",
|
||||
Binding = binding,
|
||||
Width = 90,
|
||||
IsReadOnly = false
|
||||
});
|
||||
}
|
||||
|
||||
InspectResultGrid.Columns.Add(new DataGridTextColumn
|
||||
{
|
||||
Header = "实验结果",
|
||||
Binding = new System.Windows.Data.Binding("InspectResultText"),
|
||||
IsReadOnly = true,
|
||||
Width = 90
|
||||
});
|
||||
}
|
||||
|
||||
private void InspectResultGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (_vm == null) return;
|
||||
_vm.SelectedInspectRow = InspectResultGrid.SelectedItem as QuickTestInspectRowViewModel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<UserControl x:Class="YY.Admin.Views.RubberQuickTestStd.RubberQuickTestStdDetailDialogView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
mc:Ignorable="d"
|
||||
Width="900"
|
||||
MinHeight="520">
|
||||
|
||||
<Grid Background="{DynamicResource ThirdlyRegionBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<hc:SimplePanel Margin="20">
|
||||
<TextBlock FontSize="18" Foreground="{DynamicResource PrimaryTextBrush}"
|
||||
Text="胶料快检实验标准详情" HorizontalAlignment="Left"/>
|
||||
<Button Width="22" Height="22" Command="hc:ControlCommands.Close"
|
||||
Style="{StaticResource ButtonIcon}" Foreground="{DynamicResource PrimaryBrush}"
|
||||
hc:IconElement.Geometry="{StaticResource ErrorGeometry}"
|
||||
Padding="0" HorizontalAlignment="Right" VerticalAlignment="Top"/>
|
||||
</hc:SimplePanel>
|
||||
|
||||
<hc:ScrollViewer Grid.Row="1" IsInertiaEnabled="True">
|
||||
<StackPanel Margin="20,0,20,0">
|
||||
<hc:Row Gutter="10">
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding Std.StdName, Mode=OneWay}" IsReadOnly="True"
|
||||
hc:InfoElement.Title="标准名称" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
|
||||
Margin="0,0,0,12"/>
|
||||
</hc:Col>
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding Std.TestMethodName, Mode=OneWay}" IsReadOnly="True"
|
||||
hc:InfoElement.Title="实验方法" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
|
||||
Margin="0,0,0,12"/>
|
||||
</hc:Col>
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding Std.RubberMaterialName, Mode=OneWay}" IsReadOnly="True"
|
||||
hc:InfoElement.Title="胶料名称" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
|
||||
Margin="0,0,0,12"/>
|
||||
</hc:Col>
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding Std.IssueNumber, Mode=OneWay}" IsReadOnly="True"
|
||||
hc:InfoElement.Title="发行编号" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
|
||||
Margin="0,0,0,12"/>
|
||||
</hc:Col>
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding Std.IssueDate, Mode=OneWay, StringFormat={}{0:yyyy-MM-dd}}" IsReadOnly="True"
|
||||
hc:InfoElement.Title="发行日期" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
|
||||
Margin="0,0,0,12"/>
|
||||
</hc:Col>
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding Std.IssueDeptName, Mode=OneWay}" IsReadOnly="True"
|
||||
hc:InfoElement.Title="发行部门" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
|
||||
Margin="0,0,0,12"/>
|
||||
</hc:Col>
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding Std.EnableStatusText, Mode=OneWay}" IsReadOnly="True"
|
||||
hc:InfoElement.Title="启用状态" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
|
||||
Margin="0,0,0,12"/>
|
||||
</hc:Col>
|
||||
<hc:Col Span="12">
|
||||
<hc:TextBox Text="{Binding Std.AuditStatusText, Mode=OneWay}" IsReadOnly="True"
|
||||
hc:InfoElement.Title="审核状态" hc:InfoElement.TitleWidth="90" hc:InfoElement.TitlePlacement="Left"
|
||||
Margin="0,0,0,12"/>
|
||||
</hc:Col>
|
||||
</hc:Row>
|
||||
|
||||
<TextBlock Text="标准明细(数据点上下限)" FontWeight="SemiBold" Margin="0,8,0,8"/>
|
||||
<DataGrid ItemsSource="{Binding Lines}"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column"
|
||||
MaxHeight="280"
|
||||
CanUserAddRows="False">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="数据点" Binding="{Binding PointName}" Width="*"/>
|
||||
<DataGridTextColumn Header="下限值" Binding="{Binding LowerLimit}" Width="90"/>
|
||||
<DataGridTextColumn Header="下警告" Binding="{Binding LowerWarn}" Width="90"/>
|
||||
<DataGridTextColumn Header="目标值" Binding="{Binding TargetValue}" Width="90"/>
|
||||
<DataGridTextColumn Header="上警告" Binding="{Binding UpperWarn}" Width="90"/>
|
||||
<DataGridTextColumn Header="上限值" Binding="{Binding UpperLimit}" Width="90"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</StackPanel>
|
||||
</hc:ScrollViewer>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="20">
|
||||
<Button Content="关闭" Command="{Binding CloseCommand}" Style="{StaticResource ButtonPrimary}" Width="100"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace YY.Admin.Views.RubberQuickTestStd;
|
||||
|
||||
public partial class RubberQuickTestStdDetailDialogView : UserControl
|
||||
{
|
||||
public RubberQuickTestStdDetailDialogView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<UserControl x:Class="YY.Admin.Views.RubberQuickTestStd.RubberQuickTestStdListView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Style="{StaticResource BaseViewStyle}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" CornerRadius="4" Margin="0 0 -10 0">
|
||||
<hc:Row>
|
||||
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||
<hc:TextBox Text="{Binding FilterStdName, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="0 0 10 10"
|
||||
hc:InfoElement.Title="标准名称"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.TitleWidth="75"
|
||||
hc:InfoElement.Placeholder="实验标准名称"
|
||||
hc:InfoElement.ShowClearButton="True"/>
|
||||
</hc:Col>
|
||||
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||
<hc:TextBox Text="{Binding FilterRubberMaterialName, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="0 0 10 10"
|
||||
hc:InfoElement.Title="胶料名称"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.TitleWidth="75"
|
||||
hc:InfoElement.Placeholder="胶料名称"
|
||||
hc:InfoElement.ShowClearButton="True"/>
|
||||
</hc:Col>
|
||||
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||
<hc:ComboBox SelectedValuePath="Value"
|
||||
DisplayMemberPath="Key"
|
||||
ItemsSource="{Binding EnableStatusOptions}"
|
||||
SelectedValue="{Binding FilterEnableStatus}"
|
||||
Margin="0 0 10 10"
|
||||
hc:InfoElement.Title="启用状态"
|
||||
hc:InfoElement.TitlePlacement="Left"
|
||||
hc:InfoElement.TitleWidth="75"
|
||||
hc:InfoElement.Placeholder="全部"
|
||||
hc:InfoElement.ShowClearButton="True"/>
|
||||
</hc:Col>
|
||||
</hc:Row>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Margin="0,10">
|
||||
<hc:UniformSpacingPanel Spacing="10">
|
||||
<Button Style="{StaticResource ButtonPrimary}" Command="{Binding SearchCommand}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<md:PackIcon Kind="Search"/>
|
||||
<TextBlock Text="搜索" Style="{StaticResource IconButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Style="{StaticResource ButtonDefault}" Command="{Binding ResetCommand}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<md:PackIcon Kind="Refresh"/>
|
||||
<TextBlock Text="重置" Style="{StaticResource IconButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<TextBlock Text="数据来自 MES,桌面端只读;断网时显示本地缓存"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource SecondaryTextBrush}"
|
||||
FontSize="12"/>
|
||||
</hc:UniformSpacingPanel>
|
||||
</Border>
|
||||
|
||||
<DataGrid Grid.Row="2"
|
||||
ItemsSource="{Binding Items}"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
CanUserAddRows="False"
|
||||
SelectionMode="Single"
|
||||
GridLinesVisibility="Horizontal"
|
||||
HorizontalGridLinesBrush="#FFEDEDED"
|
||||
VerticalGridLinesBrush="Transparent"
|
||||
HeadersVisibility="All"
|
||||
ColumnHeaderStyle="{StaticResource CusDataGridColumnHeaderStyle}"
|
||||
Style="{StaticResource CusDataGridStyle}"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Auto">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="实验标准名称" Binding="{Binding StdName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="180"/>
|
||||
<DataGridTextColumn Header="实验方法" Binding="{Binding TestMethodName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="140"/>
|
||||
<DataGridTextColumn Header="胶料名称" Binding="{Binding RubberMaterialName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="140"/>
|
||||
<DataGridTextColumn Header="发行编号" Binding="{Binding IssueNumber}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
|
||||
<DataGridTextColumn Header="发行部门" Binding="{Binding IssueDeptName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
|
||||
<DataGridTextColumn Header="启用状态" Binding="{Binding EnableStatusText}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="90"/>
|
||||
<DataGridTextColumn Header="审核状态" Binding="{Binding AuditStatusText}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="90"/>
|
||||
<DataGridTextColumn Header="创建人" Binding="{Binding CreateBy}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="100"/>
|
||||
<DataGridTextColumn Header="创建时间" Binding="{Binding CreateTime, StringFormat={}{0:yyyy-MM-dd HH:mm}}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="150"/>
|
||||
<DataGridTemplateColumn Header="操作" Width="100" CellStyle="{StaticResource CusOperDataGridCellStyle}">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Border Style="{DynamicResource DataGridOpeButtonStyle}">
|
||||
<Border.InputBindings>
|
||||
<MouseBinding Command="{Binding DataContext.ViewDetailCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"
|
||||
CommandParameter="{Binding}" MouseAction="LeftClick"/>
|
||||
</Border.InputBindings>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<md:PackIcon Kind="EyeOutline" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="详情" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
|
||||
<TextBlock Text="{Binding Total, StringFormat=共 {0} 条}" VerticalAlignment="Center" Margin="0,0,16,0"
|
||||
Foreground="{DynamicResource SecondaryTextBrush}"/>
|
||||
<Button Content="上一页" Command="{Binding PrevPageCommand}" Style="{StaticResource ButtonDefault}" Margin="0,0,4,0" Width="80"/>
|
||||
<TextBlock Text="{Binding PageNo, StringFormat=第 {0} 页}" VerticalAlignment="Center" Margin="8,0"
|
||||
Foreground="{DynamicResource PrimaryTextBrush}"/>
|
||||
<Button Content="下一页" Command="{Binding NextPageCommand}" Style="{StaticResource ButtonDefault}" Width="80"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace YY.Admin.Views.RubberQuickTestStd;
|
||||
|
||||
public partial class RubberQuickTestStdListView : UserControl
|
||||
{
|
||||
public RubberQuickTestStdListView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user