166 lines
5.4 KiB
Markdown
166 lines
5.4 KiB
Markdown
|
|
# Screen 149 필드 타입 검증 가이드
|
||
|
|
|
||
|
|
## 배경
|
||
|
|
- **화면 149**: 품목정보 (item_info 테이블) 폼
|
||
|
|
- **division 컬럼**: DB에서 `input_type = 'text'`로 변경했으나 화면에는 여전히 SELECT 드롭다운으로 표시
|
||
|
|
- **unit 컬럼**: `input_type = 'category'` → SELECT 드롭다운으로 표시되어야 함
|
||
|
|
|
||
|
|
## DB 현황 (vexplor-dev 조회 결과)
|
||
|
|
|
||
|
|
| column_name | company_code | input_type |
|
||
|
|
|-------------|--------------|------------|
|
||
|
|
| division | * | category |
|
||
|
|
| division | COMPANY_7 | **text** |
|
||
|
|
| division | COMPANY_8, 9, 10, 18, 19, 20, 21 | category |
|
||
|
|
| unit | * | text |
|
||
|
|
| unit | COMPANY_18, 19, 20, 21, 7, 8, 9 | **category** |
|
||
|
|
|
||
|
|
**주의:** `wace` 사용자는 `company_code = '*'` (최고 관리자)입니다.
|
||
|
|
- division: company * → **category** (text 아님)
|
||
|
|
- unit: company * → **text** (category 아님)
|
||
|
|
|
||
|
|
**회사별로 다릅니다.** 예: COMPANY_7의 division은 text, unit은 category.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 수동 검증 절차
|
||
|
|
|
||
|
|
### 1. 로그인
|
||
|
|
- URL: `http://localhost:9771/login`
|
||
|
|
- User ID: `wace`
|
||
|
|
- Password: `wace0909!!`
|
||
|
|
- 회사: "탑씰" (해당 회사 코드 확인 필요)
|
||
|
|
|
||
|
|
### 2. 화면 149 접속
|
||
|
|
- URL: `http://localhost:9771/screens/149`
|
||
|
|
- 페이지 로드 대기
|
||
|
|
|
||
|
|
### 3. 필드 확인
|
||
|
|
|
||
|
|
#### 구분 (division)
|
||
|
|
- **예상 (DB 기준):**
|
||
|
|
- company *: SELECT (category)
|
||
|
|
- COMPANY_7: TEXT INPUT (text)
|
||
|
|
- **실제:** TEXT INPUT 또는 SELECT 중 어느 쪽인지 확인
|
||
|
|
|
||
|
|
#### 단위 (unit)
|
||
|
|
- **예상 (DB 기준):**
|
||
|
|
- company *: TEXT INPUT (text)
|
||
|
|
- COMPANY_18~21, 7~9: SELECT (category)
|
||
|
|
- **실제:** TEXT INPUT 또는 SELECT 중 어느 쪽인지 확인
|
||
|
|
|
||
|
|
### 4. 스크린샷
|
||
|
|
- 구분, 단위 필드가 함께 보이도록 캡처
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 코드 흐름 (input_type → 렌더링)
|
||
|
|
|
||
|
|
### 1. 컬럼 메타 로드
|
||
|
|
```
|
||
|
|
DynamicComponentRenderer
|
||
|
|
→ loadColumnMeta(screenTableName)
|
||
|
|
→ GET /api/table-management/tables/item_info/columns?size=1000
|
||
|
|
→ columnMetaCache[tableName][columnName] = { inputType, ... }
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. 렌더 타입 결정 (357~369행)
|
||
|
|
```javascript
|
||
|
|
const dbInputType = columnMetaCache[screenTableName]?.[baseCol]?.inputType;
|
||
|
|
const ft = dbInputType || componentConfig?.fieldType;
|
||
|
|
|
||
|
|
if (["text", "number", ...].includes(ft)) return "v2-input"; // 텍스트 입력
|
||
|
|
if (["select", "category", "entity"].includes(ft)) return "v2-select"; // 드롭다운
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. mergeColumnMeta (81~130행)
|
||
|
|
- DB `input_type`이 화면 저장값보다 우선
|
||
|
|
- `needsSync`이면 DB 값으로 덮어씀
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 캐시 관련
|
||
|
|
|
||
|
|
### 1. 프론트엔드 (DynamicComponentRenderer)
|
||
|
|
- `columnMetaCache`: TTL 5초
|
||
|
|
- `table-columns-refresh` 이벤트 시 즉시 무효화 및 재로드
|
||
|
|
|
||
|
|
### 2. 백엔드 (tableManagementService)
|
||
|
|
- 컬럼 목록: 5분 TTL
|
||
|
|
- `updateColumnInputType` 호출 시 해당 테이블 캐시 삭제
|
||
|
|
|
||
|
|
### 3. 캐시 무효화가 필요한 경우
|
||
|
|
- 데이터 타입 관리에서 변경 후 화면이 갱신되지 않을 때
|
||
|
|
- **대응:** 페이지 새로고침 또는 `?_t=timestamp`로 API 재요청
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 가능한 원인
|
||
|
|
|
||
|
|
### 1. 회사 코드 불일치
|
||
|
|
- 로그인한 사용자 회사와 DB의 `company_code`가 다를 수 있음
|
||
|
|
- `wace`는 `company_code = '*'` → division은 category, unit은 text
|
||
|
|
|
||
|
|
### 2. 화면 레이아웃에 저장된 값
|
||
|
|
- `componentConfig.fieldType`이 있으면 DB보다 우선될 수 있음
|
||
|
|
- 코드상으로는 `dbInputType`이 우선이므로, DB가 제대로 로드되면 덮어씀
|
||
|
|
|
||
|
|
### 3. 캐시
|
||
|
|
- 백엔드 5분, 프론트 5초
|
||
|
|
- 데이터 타입 변경 후 곧바로 화면을 열면 이전 캐시가 사용될 수 있음
|
||
|
|
|
||
|
|
### 4. API 응답 구조
|
||
|
|
- `columnMetaCache`에 넣을 때 `col.column_name || col.columnName` 사용
|
||
|
|
- `mergeColumnMeta`는 `meta.input_type || meta.inputType` 사용
|
||
|
|
- 백엔드는 `inputType`(camelCase) 반환 → `columnMetaCache`에 `inputType` 유지
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 디버깅용 Console 스크립트
|
||
|
|
|
||
|
|
화면 149 로드 후 브라우저 Console에서 실행:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// 1. columnMetaCache 조회 (DynamicComponentRenderer 내부)
|
||
|
|
// React DevTools로 DynamicComponentRenderer 선택 후
|
||
|
|
// 또는 전역에 노출해 둔 경우:
|
||
|
|
const meta = window.__COLUMN_META_CACHE__?.item_info;
|
||
|
|
if (meta) {
|
||
|
|
console.log("division:", meta.division?.inputType || meta.division?.input_type);
|
||
|
|
console.log("unit:", meta.unit?.inputType || meta.unit?.input_type);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. API 직접 호출
|
||
|
|
fetch("/api/table-management/tables/item_info/columns?size=1000", {
|
||
|
|
credentials: "include"
|
||
|
|
})
|
||
|
|
.then(r => r.json())
|
||
|
|
.then(d => {
|
||
|
|
const cols = d.data?.columns || d.columns || [];
|
||
|
|
const div = cols.find(c => (c.columnName || c.column_name) === "division");
|
||
|
|
const unit = cols.find(c => (c.columnName || c.column_name) === "unit");
|
||
|
|
console.log("API division:", div?.inputType || div?.input_type);
|
||
|
|
console.log("API unit:", unit?.inputType || unit?.input_type);
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 권장 사항
|
||
|
|
|
||
|
|
1. **회사 코드 확인**
|
||
|
|
- 로그인한 사용자의 `company_code` 확인
|
||
|
|
- `division`/`unit`을 text/category로 바꾼 회사가 맞는지 확인
|
||
|
|
|
||
|
|
2. **캐시 우회**
|
||
|
|
- 데이터 타입 변경 후 페이지 새로고침
|
||
|
|
- 또는 5초 이상 대기 후 다시 접속
|
||
|
|
|
||
|
|
3. **데이터 타입 관리에서 변경 시**
|
||
|
|
- 저장 후 `table-columns-refresh` 이벤트 발생 여부 확인
|
||
|
|
- 화면 디자이너의 V2FieldConfigPanel에서 변경 시에는 이벤트가 발생함
|
||
|
|
|
||
|
|
4. **테이블 관리 UI에서 변경 시**
|
||
|
|
- `table-columns-refresh` 이벤트가 발생하는지 확인
|
||
|
|
- 없으면 해당 화면에서 수동으로 `window.dispatchEvent(new CustomEvent("table-columns-refresh"))` 호출 후 재검증
|