설비목록 메뉴 팝업 구성
This commit is contained in:
238
Assets/Resources/EWLK/UIToolkit/Main/EWLKEquipListContentUss.uss
Normal file
238
Assets/Resources/EWLK/UIToolkit/Main/EWLKEquipListContentUss.uss
Normal file
@@ -0,0 +1,238 @@
|
||||
/* ============================================================
|
||||
EWLKEquipListContent — 설비 목록
|
||||
필터 바 + 8컬럼 테이블
|
||||
============================================================ */
|
||||
|
||||
.ewlk-equip {
|
||||
flex-grow: 1;
|
||||
flex-direction: column;
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
/* ── 필터 바 ────────────────────────────────────────────── */
|
||||
.ewlk-equip__filter-bar {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 8px 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ── 검색 ────────────────────────────────────────────── */
|
||||
.ewlk-equip__search-wrap {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.ewlk-equip__search-icon {
|
||||
color: rgb(180, 180, 180);
|
||||
margin-right: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ewlk-equip__search-field {
|
||||
width: 300px;
|
||||
border-width: 0;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
font-size: 12px;
|
||||
color: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
.ewlk-equip .ewlk-equip__search-field .unity-text-input {
|
||||
border-width: 0;
|
||||
padding: 2px 0;
|
||||
background-color: rgb(255, 255, 255);
|
||||
color: rgb(30, 30, 30);
|
||||
--unity-cursor-color: rgb(80, 80, 80);
|
||||
}
|
||||
|
||||
.ewlk-equip .ewlk-equip__search-field--placeholder .unity-text-input {
|
||||
color: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
/* ── 필터 드롭다운 ──────────────────────────────────────── */
|
||||
.ewlk-equip__filter-dropdown {
|
||||
width: 100px;
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ewlk-equip .ewlk-equip__filter-dropdown .unity-base-popup-field__input {
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-width: 1px;
|
||||
border-color: rgb(210, 210, 210);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.ewlk-equip .ewlk-equip__filter-dropdown .unity-base-popup-field__text {
|
||||
color: rgb(77, 77, 77);
|
||||
margin-right: 0;
|
||||
padding-right: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ewlk-equip .ewlk-equip__filter-dropdown .unity-base-popup-field__arrow {
|
||||
margin-left: 2px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/* ── 테이블 헤더 ──────────────────────────────────────── */
|
||||
.ewlk-equip__header {
|
||||
flex-direction: row;
|
||||
height: 32px;
|
||||
background-color: rgb(245, 245, 250);
|
||||
border-bottom-width: 1px;
|
||||
border-color: rgb(220, 220, 220);
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ewlk-equip__header-cell {
|
||||
background-color: rgb(245, 245, 250);
|
||||
}
|
||||
|
||||
.ewlk-equip__header-cell .ewlk-equip__cell-label {
|
||||
-unity-font-style: bold;
|
||||
color: rgb(80, 80, 80);
|
||||
}
|
||||
|
||||
/* ── ScrollView ────────────────────────────────────────── */
|
||||
.ewlk-equip__list {
|
||||
flex-grow: 1;
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
/* ── 데이터 행 ─────────────────────────────────────────── */
|
||||
.ewlk-equip__row {
|
||||
flex-direction: row;
|
||||
height: 32px;
|
||||
border-bottom-width: 1px;
|
||||
border-color: rgb(240, 240, 240);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ── 셀 공통 ──────────────────────────────────────────── */
|
||||
.ewlk-equip__cell {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 2px;
|
||||
border-right-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ewlk-equip__cell-label {
|
||||
font-size: 11px;
|
||||
color: rgb(50, 50, 50);
|
||||
-unity-text-align: middle-center;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ── 컬럼 너비 ────────────────────────────────────────── */
|
||||
.ewlk-equip .col-el-no { width: 35px; flex-shrink: 0; flex-grow: 0; }
|
||||
.ewlk-equip .col-el-process { width: 100px; flex-shrink: 0; flex-grow: 0; }
|
||||
.ewlk-equip .col-el-line { width: 70px; flex-shrink: 0; flex-grow: 0; }
|
||||
.ewlk-equip .col-el-category { width: 80px; flex-shrink: 0; flex-grow: 0; }
|
||||
.ewlk-equip .col-el-equipno { width: 80px; flex-shrink: 0; flex-grow: 0; }
|
||||
.ewlk-equip .col-el-name { flex-grow: 1; }
|
||||
.ewlk-equip .col-el-status { width: 70px; flex-shrink: 0; flex-grow: 0; }
|
||||
.ewlk-equip .col-el-control { width: 80px; flex-shrink: 0; flex-grow: 0; flex-direction: row; }
|
||||
|
||||
/* ── 상태 뱃지 (타원) ─────────────────────────────────── */
|
||||
.ewlk-equip__badge {
|
||||
font-size: 10px;
|
||||
-unity-text-align: middle-center;
|
||||
padding: 2px 10px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ewlk-equip__badge--ready {
|
||||
color: rgb(30, 100, 200);
|
||||
background-color: rgb(210, 230, 255);
|
||||
border-width: 1px;
|
||||
border-color: rgb(100, 160, 230);
|
||||
}
|
||||
|
||||
.ewlk-equip__badge--error {
|
||||
color: rgb(200, 50, 40);
|
||||
background-color: rgb(255, 220, 215);
|
||||
border-width: 1px;
|
||||
border-color: rgb(230, 100, 90);
|
||||
}
|
||||
|
||||
.ewlk-equip__badge--rest {
|
||||
color: rgb(160, 120, 20);
|
||||
background-color: rgb(255, 240, 200);
|
||||
border-width: 1px;
|
||||
border-color: rgb(220, 180, 60);
|
||||
}
|
||||
|
||||
.ewlk-equip__badge--planned {
|
||||
color: rgb(100, 100, 100);
|
||||
background-color: rgb(230, 230, 230);
|
||||
border-width: 1px;
|
||||
border-color: rgb(180, 180, 180);
|
||||
}
|
||||
|
||||
/* ── 제어 토글 (읽기전용) ─────────────────────────────── */
|
||||
.ewlk-equip__toggle {
|
||||
margin: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ewlk-equip__toggle-label {
|
||||
font-size: 10px;
|
||||
color: rgb(80, 80, 80);
|
||||
margin-left: 4px;
|
||||
-unity-text-align: middle-center;
|
||||
}
|
||||
|
||||
/* ── 설비명 래퍼 (이름 + +n + ∧∨) ────────────────────── */
|
||||
.ewlk-equip__name-wrap {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* +n 뱃지 (파란색 작은 글씨) */
|
||||
.ewlk-equip__sub-count {
|
||||
font-size: 10px;
|
||||
color: rgb(30, 100, 220);
|
||||
-unity-font-style: bold;
|
||||
margin-left: 2px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 아코디언 토글 아이콘 */
|
||||
.ewlk-equip__expand-icon {
|
||||
color: rgb(120, 120, 120);
|
||||
flex-shrink: 0;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
/* ── 세부 설비 아코디언 ──────────────────────────────── */
|
||||
.ewlk-equip__accordion {
|
||||
flex-direction: column;
|
||||
margin-left: 12px;
|
||||
border-left-width: 1px;
|
||||
border-color: rgb(230, 230, 230);
|
||||
}
|
||||
|
||||
.ewlk-equip__sub-row {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: 28px;
|
||||
padding-left: 390px;
|
||||
}
|
||||
|
||||
.ewlk-equip__sub-label {
|
||||
font-size: 11px;
|
||||
color: rgb(60, 60, 60);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d49b12c27bdf8b409c0af4d005531bc
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
unsupportedSelectorAction: 0
|
||||
71
Assets/Scripts/EnglewoodLAB/Data/EWLKEquipListData.cs
Normal file
71
Assets/Scripts/EnglewoodLAB/Data/EWLKEquipListData.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UVC.EnglewoodLAB.Data
|
||||
{
|
||||
/// <summary>설비 상태</summary>
|
||||
public enum EWLKEquipStatus
|
||||
{
|
||||
/// <summary>준비 (파랑)</summary>
|
||||
Ready,
|
||||
/// <summary>이상 (빨강)</summary>
|
||||
Error,
|
||||
/// <summary>휴식 (노랑)</summary>
|
||||
Rest,
|
||||
/// <summary>계획정지 (회색)</summary>
|
||||
PlannedStop
|
||||
}
|
||||
|
||||
/// <summary>설비 목록 행 데이터</summary>
|
||||
public class EWLKEquipListRowData
|
||||
{
|
||||
/// <summary>공정 구분</summary>
|
||||
public string Process { get; internal set; } = string.Empty;
|
||||
|
||||
/// <summary>설비 라인</summary>
|
||||
public string Line { get; internal set; } = string.Empty;
|
||||
|
||||
/// <summary>설비 분류</summary>
|
||||
public string Category { get; internal set; } = string.Empty;
|
||||
|
||||
/// <summary>설비 번호</summary>
|
||||
public string EquipNo { get; internal set; } = string.Empty;
|
||||
|
||||
/// <summary>설비명</summary>
|
||||
public string EquipName { get; internal set; } = string.Empty;
|
||||
|
||||
/// <summary>상태</summary>
|
||||
public EWLKEquipStatus Status { get; internal set; } = EWLKEquipStatus.Ready;
|
||||
|
||||
/// <summary>가동 여부 (제어 토글)</summary>
|
||||
public bool IsRunning { get; internal set; }
|
||||
|
||||
/// <summary>세부 설비명 목록 (충/포장설비에 연결된 하위 설비)</summary>
|
||||
public List<string> SubEquipments { get; internal set; } = new();
|
||||
|
||||
/// <summary>세부 설비 존재 여부</summary>
|
||||
public bool HasSubEquipments => SubEquipments.Count > 0;
|
||||
|
||||
/// <summary>플레이스홀더 행 생성</summary>
|
||||
public static EWLKEquipListRowData CreatePlaceholder()
|
||||
{
|
||||
return new EWLKEquipListRowData
|
||||
{
|
||||
Process = "-",
|
||||
Line = "-",
|
||||
Category = "-",
|
||||
EquipNo = "-",
|
||||
EquipName = "-",
|
||||
Status = EWLKEquipStatus.Ready,
|
||||
IsRunning = false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>설비 목록 데이터</summary>
|
||||
public class EWLKEquipListData
|
||||
{
|
||||
/// <summary>설비 행 목록</summary>
|
||||
public List<EWLKEquipListRowData> Rows { get; } = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c70eeb78b5b62e4998d2a7bf6676e1d
|
||||
496
Assets/Scripts/EnglewoodLAB/UIToolkit/EWLKEquipListContent.cs
Normal file
496
Assets/Scripts/EnglewoodLAB/UIToolkit/EWLKEquipListContent.cs
Normal file
@@ -0,0 +1,496 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UVC.EnglewoodLAB.Data;
|
||||
using UVC.UIToolkit;
|
||||
|
||||
namespace UVC.EnglewoodLAB.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 설비 목록 컨텐츠.
|
||||
/// 검색창 + 공정/상태 필터 + 8컬럼 테이블 (ScrollView).
|
||||
/// 상태: 타원 뱃지, 제어: 가동/정지 읽기전용 토글.
|
||||
/// </summary>
|
||||
[UxmlElement]
|
||||
public partial class EWLKEquipListContent : VisualElement, IDisposable
|
||||
{
|
||||
private const string UssPath = "EWLK/UIToolkit/Main/EWLKEquipListContentUss";
|
||||
private const string SearchPlaceholder = "공정, 라인, 설비 번호, 설비명을 검색해 보세요.";
|
||||
|
||||
// 8컬럼 (상태/제어는 특수 처리)
|
||||
private static readonly (string cls, string header)[] s_Columns =
|
||||
{
|
||||
("col-el-no", "No"),
|
||||
("col-el-process", "공정 구분"),
|
||||
("col-el-line", "설비 라인"),
|
||||
("col-el-category", "설비 분류"),
|
||||
("col-el-equipno", "설비 번호"),
|
||||
("col-el-name", "설비명"),
|
||||
("col-el-status", "상태"),
|
||||
("col-el-control", "제어"),
|
||||
};
|
||||
|
||||
// 상태 → (텍스트, CSS modifier)
|
||||
private static readonly Dictionary<EWLKEquipStatus, (string text, string cls)> s_StatusMap = new()
|
||||
{
|
||||
{ EWLKEquipStatus.Ready, ("준비", "ewlk-equip__badge--ready") },
|
||||
{ EWLKEquipStatus.Error, ("이상", "ewlk-equip__badge--error") },
|
||||
{ EWLKEquipStatus.Rest, ("휴식", "ewlk-equip__badge--rest") },
|
||||
{ EWLKEquipStatus.PlannedStop, ("계획정지", "ewlk-equip__badge--planned") },
|
||||
};
|
||||
|
||||
private readonly TextField _searchField;
|
||||
private readonly DropdownField _processFilter;
|
||||
private readonly DropdownField _statusFilter;
|
||||
private readonly ScrollView _scrollView;
|
||||
private readonly VisualElement _rowContainer;
|
||||
|
||||
private string _searchText = string.Empty;
|
||||
private string _selectedProcess = "공정 전체";
|
||||
private string _selectedStatus = "상태 전체";
|
||||
private List<EWLKEquipListRowData> _allRows = new();
|
||||
private List<EWLKEquipListRowData> _displayRows = new();
|
||||
|
||||
private static readonly List<EWLKEquipListRowData> s_PlaceholderRows = CreatePlaceholderRows();
|
||||
|
||||
public EWLKEquipListContent()
|
||||
{
|
||||
var uss = Resources.Load<StyleSheet>(UssPath);
|
||||
if (uss != null) styleSheets.Add(uss);
|
||||
|
||||
AddToClassList("ewlk-equip");
|
||||
|
||||
// ── 필터 바 ──
|
||||
var filterBar = new VisualElement();
|
||||
filterBar.AddToClassList("ewlk-equip__filter-bar");
|
||||
filterBar.pickingMode = PickingMode.Position;
|
||||
|
||||
// 검색창
|
||||
var searchWrap = new VisualElement();
|
||||
searchWrap.AddToClassList("ewlk-equip__search-wrap");
|
||||
searchWrap.pickingMode = PickingMode.Position;
|
||||
|
||||
var searchIcon = new Label(UTKMaterialIcons.Search);
|
||||
searchIcon.AddToClassList("ewlk-equip__search-icon");
|
||||
UTKMaterialIcons.ApplyIconStyle(searchIcon, 16);
|
||||
searchWrap.Add(searchIcon);
|
||||
|
||||
_searchField = new TextField();
|
||||
_searchField.AddToClassList("ewlk-equip__search-field");
|
||||
_searchField.AddToClassList("ewlk-equip__search-field--placeholder");
|
||||
_searchField.focusable = true;
|
||||
_searchField.pickingMode = PickingMode.Position;
|
||||
_searchField.value = SearchPlaceholder;
|
||||
_searchField.RegisterCallback<FocusInEvent>(_ =>
|
||||
{
|
||||
if (_searchField.value == SearchPlaceholder)
|
||||
{
|
||||
_searchField.value = string.Empty;
|
||||
_searchField.RemoveFromClassList("ewlk-equip__search-field--placeholder");
|
||||
}
|
||||
});
|
||||
_searchField.RegisterCallback<FocusOutEvent>(_ =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(_searchField.value))
|
||||
{
|
||||
_searchField.value = SearchPlaceholder;
|
||||
_searchField.AddToClassList("ewlk-equip__search-field--placeholder");
|
||||
}
|
||||
});
|
||||
_searchField.RegisterCallback<ChangeEvent<string>>(evt =>
|
||||
{
|
||||
var val = evt.newValue ?? string.Empty;
|
||||
_searchText = val == SearchPlaceholder ? string.Empty : val;
|
||||
ApplyFilter();
|
||||
});
|
||||
|
||||
// TextField 내부 요소 (USS로 덮어쓸 수 없으므로 인라인 필수)
|
||||
var textInput = _searchField.Q("unity-text-input");
|
||||
if (textInput != null)
|
||||
{
|
||||
textInput.pickingMode = PickingMode.Position;
|
||||
textInput.focusable = true;
|
||||
textInput.style.backgroundColor = Color.white;
|
||||
textInput.style.borderTopWidth = 0;
|
||||
textInput.style.borderBottomWidth = 0;
|
||||
textInput.style.borderLeftWidth = 0;
|
||||
textInput.style.borderRightWidth = 0;
|
||||
}
|
||||
|
||||
searchWrap.Add(_searchField);
|
||||
filterBar.Add(searchWrap);
|
||||
|
||||
// 공정 필터
|
||||
var processChoices = new List<string>
|
||||
{
|
||||
"공정 전체", "1층 제조", "3층 생산 충/포장", "4층 생산 충/포장"
|
||||
};
|
||||
_processFilter = new DropdownField(processChoices, 0) { label = string.Empty };
|
||||
_processFilter.AddToClassList("ewlk-equip__filter-dropdown");
|
||||
_processFilter.pickingMode = PickingMode.Position;
|
||||
_processFilter.focusable = true;
|
||||
ApplyDropdownPicking(_processFilter);
|
||||
_processFilter.RegisterCallback<ChangeEvent<string>>(evt =>
|
||||
{
|
||||
_selectedProcess = evt.newValue ?? "공정 전체";
|
||||
ApplyFilter();
|
||||
});
|
||||
filterBar.Add(_processFilter);
|
||||
|
||||
// 상태 필터
|
||||
var statusChoices = new List<string>
|
||||
{
|
||||
"상태 전체", "준비", "이상", "휴식", "계획정지"
|
||||
};
|
||||
_statusFilter = new DropdownField(statusChoices, 0) { label = string.Empty };
|
||||
_statusFilter.AddToClassList("ewlk-equip__filter-dropdown");
|
||||
_statusFilter.pickingMode = PickingMode.Position;
|
||||
_statusFilter.focusable = true;
|
||||
ApplyDropdownPicking(_statusFilter);
|
||||
_statusFilter.RegisterCallback<ChangeEvent<string>>(evt =>
|
||||
{
|
||||
_selectedStatus = evt.newValue ?? "상태 전체";
|
||||
ApplyFilter();
|
||||
});
|
||||
filterBar.Add(_statusFilter);
|
||||
|
||||
Add(filterBar);
|
||||
|
||||
// ── 테이블 헤더 ──
|
||||
Add(BuildTableHeader());
|
||||
|
||||
// ── ScrollView ──
|
||||
_scrollView = new ScrollView(ScrollViewMode.Vertical);
|
||||
_scrollView.AddToClassList("ewlk-equip__list");
|
||||
_rowContainer = new VisualElement();
|
||||
_scrollView.Add(_rowContainer);
|
||||
Add(_scrollView);
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
// ── 공개 API ──
|
||||
|
||||
/// <summary>MQTT 데이터 갱신.</summary>
|
||||
public void UpdateData(EWLKEquipListData data)
|
||||
{
|
||||
_allRows = data.Rows;
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
// ── 뷰 갱신 ──
|
||||
|
||||
private void RefreshView()
|
||||
{
|
||||
_allRows = s_PlaceholderRows;
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
private void ApplyFilter()
|
||||
{
|
||||
_displayRows = new List<EWLKEquipListRowData>();
|
||||
|
||||
foreach (var row in _allRows)
|
||||
{
|
||||
// 공정 필터
|
||||
if (_selectedProcess != "공정 전체" && !Contains(row.Process, _selectedProcess))
|
||||
continue;
|
||||
|
||||
// 상태 필터
|
||||
if (_selectedStatus != "상태 전체")
|
||||
{
|
||||
var statusText = s_StatusMap.TryGetValue(row.Status, out var info) ? info.text : "";
|
||||
if (statusText != _selectedStatus) continue;
|
||||
}
|
||||
|
||||
// 검색어 필터
|
||||
if (!string.IsNullOrWhiteSpace(_searchText))
|
||||
{
|
||||
if (!Contains(row.Process, _searchText) &&
|
||||
!Contains(row.Line, _searchText) &&
|
||||
!Contains(row.EquipNo, _searchText) &&
|
||||
!Contains(row.EquipName, _searchText))
|
||||
continue;
|
||||
}
|
||||
|
||||
_displayRows.Add(row);
|
||||
}
|
||||
|
||||
RebuildRows();
|
||||
}
|
||||
|
||||
private void RebuildRows()
|
||||
{
|
||||
_rowContainer.Clear();
|
||||
for (int i = 0; i < _displayRows.Count; i++)
|
||||
{
|
||||
var row = MakeRowElement();
|
||||
BindRowElement(row, i);
|
||||
_rowContainer.Add(row);
|
||||
|
||||
// 세부 설비 아코디언 컨테이너
|
||||
var d = _displayRows[i];
|
||||
if (d.HasSubEquipments)
|
||||
{
|
||||
var accordion = new VisualElement();
|
||||
accordion.name = "sub-accordion";
|
||||
accordion.AddToClassList("ewlk-equip__accordion");
|
||||
accordion.style.display = DisplayStyle.None;
|
||||
|
||||
foreach (var subName in d.SubEquipments)
|
||||
{
|
||||
var subRow = new VisualElement();
|
||||
subRow.AddToClassList("ewlk-equip__sub-row");
|
||||
|
||||
var subLabel = new Label(subName);
|
||||
subLabel.AddToClassList("ewlk-equip__sub-label");
|
||||
subRow.Add(subLabel);
|
||||
|
||||
accordion.Add(subRow);
|
||||
}
|
||||
|
||||
_rowContainer.Add(accordion);
|
||||
|
||||
// 클릭 토글
|
||||
var capturedAccordion = accordion;
|
||||
var expandIcon = row.Q<Label>("expand-icon");
|
||||
row.RegisterCallback<ClickEvent>(_ =>
|
||||
{
|
||||
bool isOpen = capturedAccordion.style.display == DisplayStyle.Flex;
|
||||
capturedAccordion.style.display = isOpen ? DisplayStyle.None : DisplayStyle.Flex;
|
||||
if (expandIcon != null)
|
||||
expandIcon.text = isOpen ? UTKMaterialIcons.ExpandMore : UTKMaterialIcons.ExpandLess;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 행 생성/바인딩 ──
|
||||
|
||||
private static VisualElement MakeRowElement()
|
||||
{
|
||||
var row = new VisualElement();
|
||||
row.AddToClassList("ewlk-equip__row");
|
||||
|
||||
foreach (var (cls, _) in s_Columns)
|
||||
{
|
||||
var cell = new VisualElement();
|
||||
cell.AddToClassList("ewlk-equip__cell");
|
||||
cell.AddToClassList(cls);
|
||||
|
||||
if (cls == "col-el-status")
|
||||
{
|
||||
// 상태 뱃지
|
||||
var badge = new Label();
|
||||
badge.name = "status-badge";
|
||||
badge.AddToClassList("ewlk-equip__badge");
|
||||
cell.Add(badge);
|
||||
}
|
||||
else if (cls == "col-el-control")
|
||||
{
|
||||
// 제어 토글 (읽기전용)
|
||||
var toggle = new Toggle();
|
||||
toggle.name = "control-toggle";
|
||||
toggle.AddToClassList("ewlk-equip__toggle");
|
||||
toggle.SetEnabled(false); // 클릭 불가
|
||||
cell.Add(toggle);
|
||||
|
||||
var toggleLabel = new Label();
|
||||
toggleLabel.name = "control-label";
|
||||
toggleLabel.AddToClassList("ewlk-equip__toggle-label");
|
||||
cell.Add(toggleLabel);
|
||||
}
|
||||
else if (cls == "col-el-name")
|
||||
{
|
||||
// 설비명: 이름 + "+n" 뱃지 + ∧/∨ 아이콘 (세부 설비가 있을 때만 표시)
|
||||
var nameWrap = new VisualElement();
|
||||
nameWrap.name = "name-wrap";
|
||||
nameWrap.AddToClassList("ewlk-equip__name-wrap");
|
||||
|
||||
var lbl = new Label();
|
||||
lbl.AddToClassList("ewlk-equip__cell-label");
|
||||
nameWrap.Add(lbl);
|
||||
|
||||
var countBadge = new Label();
|
||||
countBadge.name = "sub-count";
|
||||
countBadge.AddToClassList("ewlk-equip__sub-count");
|
||||
countBadge.style.display = DisplayStyle.None;
|
||||
nameWrap.Add(countBadge);
|
||||
|
||||
var expandIcon = new Label(UTKMaterialIcons.ExpandMore);
|
||||
expandIcon.name = "expand-icon";
|
||||
expandIcon.AddToClassList("ewlk-equip__expand-icon");
|
||||
UTKMaterialIcons.ApplyIconStyle(expandIcon, 14);
|
||||
expandIcon.style.display = DisplayStyle.None;
|
||||
nameWrap.Add(expandIcon);
|
||||
|
||||
cell.Add(nameWrap);
|
||||
}
|
||||
else
|
||||
{
|
||||
var lbl = new Label();
|
||||
lbl.AddToClassList("ewlk-equip__cell-label");
|
||||
cell.Add(lbl);
|
||||
}
|
||||
|
||||
row.Add(cell);
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private void BindRowElement(VisualElement element, int index)
|
||||
{
|
||||
if (index >= _displayRows.Count) return;
|
||||
var d = _displayRows[index];
|
||||
|
||||
SetLabel(element, "col-el-no", (index + 1).ToString());
|
||||
SetLabel(element, "col-el-process", d.Process);
|
||||
SetLabel(element, "col-el-line", d.Line);
|
||||
SetLabel(element, "col-el-category", d.Category);
|
||||
SetLabel(element, "col-el-equipno", d.EquipNo);
|
||||
|
||||
// 설비명 + 세부 설비 "+n" 뱃지
|
||||
var nameCell = element.Q(className: "col-el-name");
|
||||
var nameLabel = nameCell?.Q<Label>(className: "ewlk-equip__cell-label");
|
||||
if (nameLabel != null)
|
||||
nameLabel.text = string.IsNullOrEmpty(d.EquipName) ? "-" : d.EquipName;
|
||||
|
||||
var subCount = element.Q<Label>("sub-count");
|
||||
var expandIcon = element.Q<Label>("expand-icon");
|
||||
if (d.HasSubEquipments)
|
||||
{
|
||||
if (subCount != null)
|
||||
{
|
||||
subCount.text = $"+{d.SubEquipments.Count}";
|
||||
subCount.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
if (expandIcon != null)
|
||||
expandIcon.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (subCount != null) subCount.style.display = DisplayStyle.None;
|
||||
if (expandIcon != null) expandIcon.style.display = DisplayStyle.None;
|
||||
}
|
||||
|
||||
// 상태 뱃지
|
||||
var badge = element.Q<Label>("status-badge");
|
||||
if (badge != null)
|
||||
{
|
||||
var (text, cls) = s_StatusMap.TryGetValue(d.Status, out var info)
|
||||
? info
|
||||
: ("준비", "ewlk-equip__badge--ready");
|
||||
|
||||
badge.text = text;
|
||||
// 이전 상태 클래스 제거
|
||||
badge.RemoveFromClassList("ewlk-equip__badge--ready");
|
||||
badge.RemoveFromClassList("ewlk-equip__badge--error");
|
||||
badge.RemoveFromClassList("ewlk-equip__badge--rest");
|
||||
badge.RemoveFromClassList("ewlk-equip__badge--planned");
|
||||
badge.AddToClassList(cls);
|
||||
}
|
||||
|
||||
// 제어 토글
|
||||
var toggle = element.Q<Toggle>("control-toggle");
|
||||
if (toggle != null)
|
||||
toggle.value = d.IsRunning;
|
||||
|
||||
var toggleLabel = element.Q<Label>("control-label");
|
||||
if (toggleLabel != null)
|
||||
toggleLabel.text = d.IsRunning ? "가동" : "정지";
|
||||
}
|
||||
|
||||
// ── 헬퍼 ──
|
||||
|
||||
private static void SetLabel(VisualElement row, string cellClass, string text)
|
||||
{
|
||||
var cell = row.Q(className: cellClass);
|
||||
var lbl = cell?.Q<Label>(className: "ewlk-equip__cell-label");
|
||||
if (lbl != null) lbl.text = string.IsNullOrEmpty(text) ? "-" : text;
|
||||
}
|
||||
|
||||
private static bool Contains(string source, string keyword) =>
|
||||
!string.IsNullOrEmpty(source) &&
|
||||
source.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
|
||||
private static void ApplyDropdownPicking(DropdownField dropdown)
|
||||
{
|
||||
var popupField = dropdown.Q(className: "unity-base-popup-field__input");
|
||||
if (popupField != null)
|
||||
popupField.pickingMode = PickingMode.Position;
|
||||
}
|
||||
|
||||
private static List<EWLKEquipListRowData> CreatePlaceholderRows()
|
||||
{
|
||||
//var rows = new List<EWLKEquipListRowData>();
|
||||
// for (int i = 0; i < 5; i++)
|
||||
// rows.Add(EWLKEquipListRowData.CreatePlaceholder());
|
||||
// return rows;
|
||||
//
|
||||
// 아래는 가데이터 ---
|
||||
return new List<EWLKEquipListRowData>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Process = "2층 생산 충/포장", Line = "01라인", Category = "충/포장설비",
|
||||
EquipNo = "P-FA-029", EquipName = "로터리 충전기",
|
||||
Status = EWLKEquipStatus.Ready, IsRunning = true,
|
||||
SubEquipments = new List<string> { "백킹 공급기", "스포이드 공급기", "용기 공급기" },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Process = "1층 제조", Line = "-", Category = "제조설비",
|
||||
EquipNo = "M-001", EquipName = "Ultra Homo Mixer50",
|
||||
Status = EWLKEquipStatus.Error, IsRunning = false,
|
||||
},
|
||||
new()
|
||||
{
|
||||
Process = "1층 제조", Line = "-", Category = "제조설비",
|
||||
EquipNo = "M-002", EquipName = "진공 유화기",
|
||||
Status = EWLKEquipStatus.Rest, IsRunning = false,
|
||||
},
|
||||
new()
|
||||
{
|
||||
Process = "3층 생산 충/포장", Line = "03라인", Category = "충/포장설비",
|
||||
EquipNo = "P-FA-031", EquipName = "다용도 로터리 충전기",
|
||||
Status = EWLKEquipStatus.PlannedStop, IsRunning = false,
|
||||
SubEquipments = new List<string> { "라벨러", "캡핑기" },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Process = "2층 생산 충/포장", Line = "01라인", Category = "충/포장설비",
|
||||
EquipNo = "P-FA-029", EquipName = "다용도 로터리 충전기",
|
||||
Status = EWLKEquipStatus.Ready, IsRunning = true,
|
||||
SubEquipments = new List<string> { "백킹 공급기", "스포이드 공급기", "용기 공급기" },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private static VisualElement BuildTableHeader()
|
||||
{
|
||||
var header = new VisualElement();
|
||||
header.AddToClassList("ewlk-equip__header");
|
||||
|
||||
foreach (var (cls, text) in s_Columns)
|
||||
{
|
||||
var cell = new VisualElement();
|
||||
cell.AddToClassList("ewlk-equip__cell");
|
||||
cell.AddToClassList("ewlk-equip__header-cell");
|
||||
cell.AddToClassList(cls);
|
||||
|
||||
var lbl = new Label(text);
|
||||
lbl.AddToClassList("ewlk-equip__cell-label");
|
||||
cell.Add(lbl);
|
||||
|
||||
header.Add(cell);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 159d902193c672842be1af8fb1d08360
|
||||
Reference in New Issue
Block a user