feat: Add VisionData panel, HW error display, and reel handler 3D model

- Add hardware error banner with priority system (motion > i/o > emergency)
- Add DIO status to HW status display with backend integration
- Remove status text from HW status, keep only LED indicators
- Add VisionDataPanel showing real-time recognized data for L/C/R ports
- Add GetVisionData API in MachineBridge with batch field support
- Add BroadcastVisionData function (250ms interval)
- Replace 3D model with detailed reel handler equipment
- Use OrthographicCamera with front view for distortion-free display
- Fix ProcessedDataPanel layout to avoid right sidebar overlap
- Show log viewer filename in error message when file not found

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-27 23:22:56 +09:00
parent 3bd35ad852
commit 86fe466b55
7 changed files with 843 additions and 569 deletions

View File

@@ -1367,7 +1367,7 @@ namespace Project.WebUI
var exename = AR.UTIL.MakePath("LogView.exe");
if (System.IO.File.Exists(exename) == false)
{
var response = new { success = false, message = "Log viewer file not found\nPlease contact support" };
var response = new { success = false, message = $"Log viewer file not found\n{exename}\nPlease contact support" };
return JsonConvert.SerializeObject(response);
}
@@ -2221,7 +2221,15 @@ namespace Project.WebUI
hwList.Add(new { name = "PLC", title = "SET", status = 0 });
}
// 9. Motion
// 9. DIO (Digital I/O)
hwList.Add(new
{
name = "DIO",
title = PUB.dio?.IsInit == true ? "ON" : "OFF",
status = PUB.dio?.IsInit == true ? 1 : 3
});
// 10. Motion
hwList.Add(new
{
name = "MOT",
@@ -2238,6 +2246,100 @@ namespace Project.WebUI
}
}
/// <summary>
/// 실시간 인식 데이터 조회 (listView21과 동일한 데이터)
/// Left/Center/Right 포트의 VisionData 정보
/// </summary>
public string GetVisionData()
{
try
{
var visdataL = PUB.Result.ItemDataL?.VisionData;
var visdataC = PUB.Result.ItemDataC?.VisionData;
var visdataR = PUB.Result.ItemDataR?.VisionData;
var result = new
{
left = new
{
cartSize = DIO.getCartSize(0).ToString(),
enabled = PUB.flag.get(eVarBool.FG_ENABLE_LEFT),
rid = visdataL?.RID ?? "",
sid = visdataL?.SID ?? "",
qty = visdataL?.QTY ?? "",
vname = visdataL?.VNAME ?? "",
vlot = visdataL?.VLOT ?? "",
mfgdate = visdataL?.MFGDATE ?? "",
partno = visdataL?.PARTNO ?? "",
reelSize = visdataL?.ReelSize.ToString() ?? "--",
batch = visdataL?.BATCH ?? "",
rid2 = visdataL?.RID2 ?? "",
sid2 = visdataL?.SID2 ?? "",
qty2 = visdataL?.QTY2 ?? "",
vname2 = visdataL?.VNAME2 ?? "",
vlot2 = visdataL?.VLOT2 ?? "",
mfgdate2 = visdataL?.MFGDATE2 ?? "",
partno2 = visdataL?.PARTNO2 ?? ""
},
center = new
{
cartSize = DIO.getCartSize(1).ToString(),
confirm = visdataC?.Confirm ?? false,
rid = visdataC?.RID ?? "",
rid_trust = visdataC?.RID_Trust ?? false,
rid_new = visdataC?.RIDNew ?? false,
sid = visdataC?.SID ?? "",
sid0 = visdataC?.SID0 ?? "",
sid_trust = visdataC?.SID_Trust ?? false,
qty = visdataC?.QTY ?? "",
qty_trust = visdataC?.QTY_Trust ?? false,
qty_rq = visdataC?.QTYRQ ?? false,
vname = visdataC?.VNAME ?? "",
vname_trust = visdataC?.VNAME_Trust ?? false,
vlot = visdataC?.VLOT ?? "",
vlot_trust = visdataC?.VLOT_Trust ?? false,
mfgdate = visdataC?.MFGDATE ?? "",
mfgdate_trust = visdataC?.MFGDATE_Trust ?? false,
partno = visdataC?.PARTNO ?? "",
partno_trust = visdataC?.PARTNO_Trust ?? false,
reelSize = visdataC?.ReelSize.ToString() ?? "--",
batch = visdataC?.BATCH ?? "",
qtymax = visdataC?.QTYMAX ?? "",
barcodeCount = visdataC?.barcodelist?.Count ?? 0,
regexCount = PUB.Result.BCDPattern?.Count ?? 0
},
right = new
{
cartSize = DIO.getCartSize(2).ToString(),
enabled = PUB.flag.get(eVarBool.FG_ENABLE_RIGHT),
rid = visdataR?.RID ?? "",
sid = visdataR?.SID ?? "",
qty = visdataR?.QTY ?? "",
vname = visdataR?.VNAME ?? "",
vlot = visdataR?.VLOT ?? "",
mfgdate = visdataR?.MFGDATE ?? "",
partno = visdataR?.PARTNO ?? "",
reelSize = visdataR?.ReelSize.ToString() ?? "--",
batch = visdataR?.BATCH ?? "",
rid2 = visdataR?.RID2 ?? "",
sid2 = visdataR?.SID2 ?? "",
qty2 = visdataR?.QTY2 ?? "",
vname2 = visdataR?.VNAME2 ?? "",
vlot2 = visdataR?.VLOT2 ?? "",
mfgdate2 = visdataR?.MFGDATE2 ?? "",
partno2 = visdataR?.PARTNO2 ?? ""
}
};
return JsonConvert.SerializeObject(result);
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Failed to get vision data: {ex.Message}");
return JsonConvert.SerializeObject(new { left = new { }, center = new { }, right = new { } });
}
}
/// <summary>
/// 인터락 목록 조회 (실시간 값 포함)
/// </summary>