diff --git a/src/Web/wwwroot/js/pid.js b/src/Web/wwwroot/js/pid.js
index 0277e0d..1064b66 100644
--- a/src/Web/wwwroot/js/pid.js
+++ b/src/Web/wwwroot/js/pid.js
@@ -354,14 +354,22 @@ function pidTogglePrefixPanel() {
}
const CATEGORY_META = {
- instrument: { label: 'Instrument', badge: 'ok' },
- power_equipment: { label: 'Power Equipment', badge: 'warn' },
- storage_equipment: { label: 'Storage Equipment', badge: 'inf' },
- process_equipment: { label: 'Process Equipment', badge: '' },
- utility_equipment: { label: 'Utility Equipment', badge: 'warn' },
- pipings: { label: 'Pipings', badge: 'ok' }
+ // ── instrument 가상 분할 (DB category='instrument', tag_dcs로 구분) ──
+ instrument_dcs: { label: 'DCS 태그', badge: 'warn', dbCat: 'instrument', tagDcs: true },
+ instrument_field: { label: '현장 계기', badge: 'ok', dbCat: 'instrument', tagDcs: false },
+ // ── 그 외 equipment / pipings ──
+ power_equipment: { label: 'Power Equipment', badge: 'warn', dbCat: 'power_equipment', tagDcs: false },
+ storage_equipment:{ label: 'Storage Equipment', badge: 'inf', dbCat: 'storage_equipment', tagDcs: false },
+ process_equipment:{ label: 'Process Equipment', badge: '', dbCat: 'process_equipment', tagDcs: false },
+ utility_equipment:{ label: 'Utility Equipment', badge: 'warn', dbCat: 'utility_equipment', tagDcs: false },
+ pipings: { label: 'Pipings', badge: 'ok', dbCat: 'pipings', tagDcs: false },
+ // ── 장비 테이블 배지용 (equipment 목록의 r.category 값과 매핑) ──
+ instrument: { label: 'Instrument', badge: 'ok' },
};
-const CATEGORY_ORDER = ['instrument', 'power_equipment', 'storage_equipment', 'process_equipment', 'utility_equipment', 'pipings'];
+const CATEGORY_ORDER = [
+ 'instrument_dcs', 'instrument_field',
+ 'power_equipment', 'storage_equipment', 'process_equipment', 'utility_equipment', 'pipings'
+];
function pidCategoryBadge(cat) {
return CATEGORY_META[cat] ? CATEGORY_META[cat].badge : '';
@@ -383,50 +391,60 @@ async function pidRefreshPrefixRules() {
return;
}
+ // instrument → tag_dcs 기준으로 가상 분할
const grouped = {};
for (const r of items) {
- if (!grouped[r.category]) grouped[r.category] = [];
- grouped[r.category].push(r);
+ let key = r.category;
+ if (r.category === 'instrument') {
+ key = r.tagDcs ? 'instrument_dcs' : 'instrument_field';
+ }
+ if (!grouped[key]) grouped[key] = [];
+ grouped[key].push(r);
}
let html = '';
- for (const cat of CATEGORY_ORDER) {
- const rules = grouped[cat];
- if (!rules) continue;
- const meta = CATEGORY_META[cat] || { label: cat, badge: '' };
- rules.sort((a, b) => a.sortOrder - b.sortOrder);
+ for (const vcat of CATEGORY_ORDER) {
+ const rules = grouped[vcat];
+ const meta = CATEGORY_META[vcat] || { label: vcat, badge: '', dbCat: vcat, tagDcs: false };
+ rules?.sort((a, b) => a.sortOrder - b.sortOrder);
- html += `
+ // 그룹 헤더: 규칙이 0건이어도 추가 입력행은 항상 표시
+ const count = rules ? rules.length : 0;
+ const isInstr = vcat === 'instrument_dcs' || vcat === 'instrument_field';
+
+ html += `
`;
@@ -438,12 +456,21 @@ async function pidRefreshPrefixRules() {
}
}
-async function pidAddPrefixRule(category) {
+// 가상 카테고리 키 → { DB category, tagDcs } 변환
+function pidResolveCat(vcat) {
+ const meta = CATEGORY_META[vcat];
+ return {
+ category: meta?.dbCat ?? vcat,
+ tagDcs: meta?.tagDcs ?? false
+ };
+}
+
+async function pidAddPrefixRule(vcat) {
const row = event.target.closest('.pid-cat-add');
const prefix = row.querySelector('.pid-cat-prefix-input').value.trim();
- const desc = row.querySelector('.pid-cat-desc-input').value.trim();
- const order = parseInt(row.querySelector('.pid-cat-order-input').value) || 10;
- const tagDcs = row.querySelector('.pid-cat-dcs-input')?.checked ?? false;
+ const desc = row.querySelector('.pid-cat-desc-input').value.trim();
+ const order = parseInt(row.querySelector('.pid-cat-order-input').value) || 10;
+ const { category, tagDcs } = pidResolveCat(vcat); // 그룹이 tagDcs 결정
if (!prefix) { alert('Prefix를 입력하세요.'); return; }
@@ -466,14 +493,17 @@ async function pidAddPrefixRule(category) {
}
async function pidUpdatePrefixRule(id, btn) {
- const row = btn.closest('.pid-cat-row');
+ const row = btn.closest('.pid-cat-row');
const group = btn.closest('.pid-cat-group');
- const catIdx = [...group.parentElement.children].indexOf(group);
- const cat = CATEGORY_ORDER[catIdx];
+ const vcat = group.dataset.vcat; // data-vcat 속성으로 가상 키 읽기
+ const { category } = pidResolveCat(vcat);
const prefix = row.querySelector('.pid-cat-prefix-input').value.trim();
- const desc = row.querySelector('.pid-cat-desc-input').value.trim();
- const order = parseInt(row.querySelector('.pid-cat-order-input').value) || 10;
- const tagDcs = row.querySelector('.pid-cat-dcs-input')?.checked ?? false;
+ const desc = row.querySelector('.pid-cat-desc-input').value.trim();
+ const order = parseInt(row.querySelector('.pid-cat-order-input').value) || 10;
+ // instrument 행에는 DCS 토글이 있음 → 체크 상태로 tagDcs 결정 (그룹 이동 가능)
+ // 그 외 행에는 토글 없음 → 그룹 기본값 사용
+ const dcsInput = row.querySelector('.pid-cat-dcs-input');
+ const tagDcs = dcsInput ? dcsInput.checked : (CATEGORY_META[vcat]?.tagDcs ?? false);
if (!prefix) { alert('Prefix를 입력하세요.'); return; }
@@ -481,7 +511,7 @@ async function pidUpdatePrefixRule(id, btn) {
const res = await fetch(`/api/pid/prefix-rules/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ prefix, category: cat, tagDcs, description: desc, sortOrder: order })
+ body: JSON.stringify({ prefix, category, tagDcs, description: desc, sortOrder: order })
});
if (!res.ok) {
const err = await res.json().catch(() => ({ error: res.statusText }));