桌面端原材料入场记录完善
This commit is contained in:
@@ -57,11 +57,18 @@ public class PrintDotService : IPrintDotService
|
||||
|
||||
public async Task PrintAsync(string printerName, string pdfBase64, string jobName = "QH-MES", int copies = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(printerName))
|
||||
throw new InvalidOperationException("打印机名称不能为空");
|
||||
if (string.IsNullOrWhiteSpace(pdfBase64))
|
||||
throw new InvalidOperationException("打印内容为空,PDF 生成失败");
|
||||
|
||||
// 去掉 data: 前缀
|
||||
var content = pdfBase64.Trim();
|
||||
var comma = content.IndexOf(',');
|
||||
if (content.StartsWith("data:", StringComparison.OrdinalIgnoreCase) && comma >= 0)
|
||||
content = content[(comma + 1)..];
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
throw new InvalidOperationException("打印内容为空,PDF 生成失败");
|
||||
|
||||
var payload = new
|
||||
{
|
||||
@@ -87,14 +94,46 @@ public class PrintDotService : IPrintDotService
|
||||
{
|
||||
var response = await ReceiveTextAsync(ws, cts.Token);
|
||||
var resDoc = JsonNode.Parse(response);
|
||||
var status = resDoc?["status"]?.GetValue<string>();
|
||||
if (status == null) continue;
|
||||
if (status == "success") return;
|
||||
var rawMsg = resDoc?["message"]?.GetValue<string>() ?? "PrintDot 打印失败";
|
||||
var status = TryReadJsonString(resDoc?["status"]);
|
||||
if (string.IsNullOrWhiteSpace(status)) continue;
|
||||
if (string.Equals(status, "success", StringComparison.OrdinalIgnoreCase)) return;
|
||||
var rawMsg = TryReadJsonString(resDoc?["message"]) ?? "PrintDot 打印失败";
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【PrintDot】队列未入队超时按软成功(虚拟打印机)-----------
|
||||
if (IsPrintQueueAppearSoftSuccess(rawMsg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
//update-end---author:jiangxh ---date:20260731 for:【PrintDot】队列未入队超时按软成功(虚拟打印机)-----------
|
||||
throw new InvalidOperationException(EnhanceErrorMessage(rawMsg));
|
||||
}
|
||||
}
|
||||
|
||||
private static string? TryReadJsonString(JsonNode? node)
|
||||
{
|
||||
if (node == null) return null;
|
||||
try
|
||||
{
|
||||
if (node is JsonValue jv)
|
||||
{
|
||||
if (jv.TryGetValue<string>(out var s)) return s;
|
||||
if (jv.TryGetValue<bool>(out var b)) return b ? "true" : "false";
|
||||
return jv.ToJsonString().Trim('"');
|
||||
}
|
||||
return node.ToJsonString();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>PrintDot 队列入队超时:视为已提交(兼容旧版桥接器)。</summary>
|
||||
private static bool IsPrintQueueAppearSoftSuccess(string? rawMsg)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rawMsg)) return false;
|
||||
return rawMsg.Contains("print job not queued within", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 PrintDot 返回的部分英文错误转换为带本地处理步骤的中文提示。
|
||||
/// 与 web 端 printDotBridge.ts::enhancePrintDotErrorMessage 行为一致,方便桌面端用户自助排查。
|
||||
|
||||
@@ -159,7 +159,14 @@ public class RawMaterialEntryService : IRawMaterialEntryService, ISingletonDepen
|
||||
try
|
||||
{
|
||||
var ok = await RemoteAddAsync(local, ct).ConfigureAwait(false);
|
||||
if (ok) { UpsertLocalCache(local); return true; }
|
||||
if (ok)
|
||||
{
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】新增后回写Id/条码,避免保存并打印空引用-----------
|
||||
CopyGeneratedFieldsToEntry(entry, local);
|
||||
UpsertLocalCache(local);
|
||||
return true;
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】新增后回写Id/条码,避免保存并打印空引用-----------
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -169,8 +176,21 @@ public class RawMaterialEntryService : IRawMaterialEntryService, ISingletonDepen
|
||||
}
|
||||
|
||||
EnqueuePendingOperation(new EntryPendingOperation { OpType = EntryOpType.Add, EntryId = local.Id, Entry = local, CreatedAt = DateTime.UtcNow });
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】新增后回写Id/条码,避免保存并打印空引用-----------
|
||||
CopyGeneratedFieldsToEntry(entry, local);
|
||||
UpsertLocalCache(local);
|
||||
return true;
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】新增后回写Id/条码,避免保存并打印空引用-----------
|
||||
}
|
||||
|
||||
/// <summary>把 Clone 上生成的主键/条码/批次写回调用方 Entry,供保存并打印继续使用。</summary>
|
||||
private static void CopyGeneratedFieldsToEntry(MesXslRawMaterialEntry entry, MesXslRawMaterialEntry local)
|
||||
{
|
||||
if (entry == null || local == null) return;
|
||||
entry.Id = local.Id;
|
||||
entry.Barcode = local.Barcode;
|
||||
entry.BatchNo = local.BatchNo;
|
||||
entry.TenantId = local.TenantId;
|
||||
}
|
||||
|
||||
public async Task<bool> EditAsync(MesXslRawMaterialEntry entry, CancellationToken ct = default)
|
||||
@@ -586,7 +606,51 @@ public class RawMaterialEntryService : IRawMaterialEntryService, ISingletonDepen
|
||||
var url = $"{BaseUrl}/xslmes/mesXslRawMaterialEntry/anon/add?tenantId={DefaultTenantId}";
|
||||
var payload = Clone(entry);
|
||||
if (IsLocalTempId(payload.Id)) payload.Id = null;
|
||||
return await PostJsonAsync(url, payload, ct).ConfigureAwait(false);
|
||||
//update-begin---author:jiangxh ---date:20260731 for:【原料入场】新增后回写服务端主键-----------
|
||||
var (ok, serverId) = await PostJsonForAddAsync(url, payload, ct).ConfigureAwait(false);
|
||||
if (ok && !string.IsNullOrWhiteSpace(serverId))
|
||||
{
|
||||
entry.Id = serverId.Trim();
|
||||
}
|
||||
return ok;
|
||||
//update-end---author:jiangxh ---date:20260731 for:【原料入场】新增后回写服务端主键-----------
|
||||
}
|
||||
|
||||
/// <summary>新增接口:解析 Result.OK(msg, id) 的 result 主键。</summary>
|
||||
private async Task<(bool Ok, string? ServerId)> PostJsonForAddAsync(string url, object body, CancellationToken ct)
|
||||
{
|
||||
var content = new StringContent(JsonSerializer.Serialize(body, _jsonOpts), Encoding.UTF8, "application/json");
|
||||
using var client = CreateClient();
|
||||
var resp = await client.PostAsync(url, content, ct).ConfigureAwait(false);
|
||||
if (!resp.IsSuccessStatusCode) return (false, null);
|
||||
try
|
||||
{
|
||||
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
var codeOk = true;
|
||||
if (root.TryGetProperty("code", out var codeEl))
|
||||
codeOk = codeEl.GetInt32() == 200;
|
||||
else if (root.TryGetProperty("success", out var successEl))
|
||||
codeOk = successEl.GetBoolean();
|
||||
if (!codeOk) return (false, null);
|
||||
|
||||
string? serverId = null;
|
||||
if (root.TryGetProperty("result", out var resultEl))
|
||||
{
|
||||
serverId = resultEl.ValueKind switch
|
||||
{
|
||||
JsonValueKind.String => resultEl.GetString(),
|
||||
JsonValueKind.Object when resultEl.TryGetProperty("id", out var idEl) => idEl.GetString(),
|
||||
_ => resultEl.ToString()
|
||||
};
|
||||
}
|
||||
return (true, string.IsNullOrWhiteSpace(serverId) ? null : serverId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return (true, null);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<(bool Ok, bool IsVersionConflict)> RemoteEditAsync(MesXslRawMaterialEntry entry, CancellationToken ct)
|
||||
|
||||
Reference in New Issue
Block a user