summaryrefslogtreecommitdiff
path: root/lib/forms
diff options
context:
space:
mode:
Diffstat (limited to 'lib/forms')
-rw-r--r--lib/forms/services.ts140
1 files changed, 90 insertions, 50 deletions
diff --git a/lib/forms/services.ts b/lib/forms/services.ts
index 8f40162c..0fbe68a6 100644
--- a/lib/forms/services.ts
+++ b/lib/forms/services.ts
@@ -10,6 +10,7 @@ import {
formEntries,
formMetas,
forms,
+ tagClassAttributes,
tagClasses,
tags,
tagSubfieldOptions,
@@ -154,23 +155,85 @@ export async function revalidateForms(contractItemId: number) {
}
}
+export interface EditableFieldsInfo {
+ tagNo: string;
+ editableFields: string[]; // 편집 가능한 필드 키 목록
+}
+
+// TAG별 편집 가능 필드 조회 함수
+async function getEditableFieldsByTag(
+ contractItemId: number,
+ projectId: number
+): Promise<Map<string, string[]>> {
+ try {
+ // 1. 해당 contractItemId의 모든 태그 조회
+ const tagList = await db
+ .select({
+ tagNo: tags.tagNo,
+ tagClass: tags.class
+ })
+ .from(tags)
+ .where(eq(tags.contractItemId, contractItemId));
+
+ const editableFieldsMap = new Map<string, string[]>();
+
+ // 2. 각 태그별로 편집 가능 필드 계산
+ for (const tag of tagList) {
+ try {
+ // 2-1. tagClasses에서 해당 class(label)와 projectId로 tagClass 찾기
+ const tagClassResult = await db
+ .select({ id: tagClasses.id })
+ .from(tagClasses)
+ .where(
+ and(
+ eq(tagClasses.label, tag.tagClass),
+ eq(tagClasses.projectId, projectId)
+ )
+ )
+ .limit(1);
+
+ if (tagClassResult.length === 0) {
+ console.warn(`No tagClass found for class: ${tag.tagClass}, projectId: ${projectId}`);
+ editableFieldsMap.set(tag.tagNo, []); // 편집 불가능
+ continue;
+ }
+
+ // 2-2. tagClassAttributes에서 편집 가능한 필드 목록 조회
+ const editableAttributes = await db
+ .select({ attId: tagClassAttributes.attId })
+ .from(tagClassAttributes)
+ .where(eq(tagClassAttributes.tagClassId, tagClassResult[0].id))
+ .orderBy(tagClassAttributes.seq);
+
+ // 2-3. attId 목록 저장
+ const editableFields = editableAttributes.map(attr => attr.attId);
+ editableFieldsMap.set(tag.tagNo, editableFields);
+
+ } catch (error) {
+ console.error(`Error processing tag ${tag.tagNo}:`, error);
+ editableFieldsMap.set(tag.tagNo, []); // 에러 시 편집 불가능
+ }
+ }
+
+ return editableFieldsMap;
+ } catch (error) {
+ console.error('Error getting editable fields by tag:', error);
+ return new Map();
+ }
+}
/**
* "가장 최신 1개 row"를 가져오고,
* data가 배열이면 그 배열을 반환,
* 그리고 이 로직 전체를 unstable_cache로 감싸 캐싱.
*/
export async function getFormData(formCode: string, contractItemId: number) {
- // 고유 캐시 키 (formCode + contractItemId)
const cacheKey = `form-data-${formCode}-${contractItemId}`;
console.log(cacheKey, "getFormData")
try {
- // 1) unstable_cache로 전체 로직을 감싼다
const result = await unstable_cache(
async () => {
- // --- 기존 로직 시작 (projectId 고려하도록 수정) ---
-
- // (0) contractItemId로부터 projectId 조회
+ // 기존 로직으로 projectId, columns, data 가져오기
const contractItemResult = await db
.select({
projectId: projects.id
@@ -183,12 +246,11 @@ export async function getFormData(formCode: string, contractItemId: number) {
if (contractItemResult.length === 0) {
console.warn(`[getFormData] No contract item found with ID: ${contractItemId}`);
- return { columns: null, data: [] };
+ return { columns: null, data: [], editableFieldsMap: new Map() };
}
const projectId = contractItemResult[0].projectId;
- // (1) form_metas 조회 - 이제 projectId도 조건에 포함
const metaRows = await db
.select()
.from(formMetas)
@@ -204,10 +266,9 @@ export async function getFormData(formCode: string, contractItemId: number) {
const meta = metaRows[0] ?? null;
if (!meta) {
console.warn(`[getFormData] No form meta found for formCode: ${formCode} and projectId: ${projectId}`);
- return { columns: null, data: [] };
+ return { columns: null, data: [], editableFieldsMap: new Map() };
}
- // (2) form_entries에서 (formCode, contractItemId)에 해당하는 "가장 최신" 한 행
const entryRows = await db
.select()
.from(formEntries)
@@ -222,19 +283,11 @@ export async function getFormData(formCode: string, contractItemId: number) {
const entry = entryRows[0] ?? null;
- // columns: DB에 저장된 JSON (DataTableColumnJSON[])
let columns = meta.columns as DataTableColumnJSON[];
-
- // 제외할 key들 정의
const excludeKeys = ['CLS_ID', 'BF_TAG_NO', 'TAG_TYPE_ID', 'PIC_NO'];
-
- // 제외할 key들을 가진 컬럼들을 필터링해서 제거
columns = columns.filter(col => !excludeKeys.includes(col.key));
columns.forEach((col) => {
- // 이미 displayLabel이 있으면 그대로 두고,
- // 없으면 uom이 있으면 "label (uom)" 형태,
- // 둘 다 없으면 label만 쓴다.
if (!col.displayLabel) {
if (col.uom) {
col.displayLabel = `${col.label} (${col.uom})`;
@@ -244,39 +297,35 @@ export async function getFormData(formCode: string, contractItemId: number) {
}
});
- // data: 만약 entry가 없거나, data가 아닌 형태면 빈 배열
let data: Array<Record<string, any>> = [];
if (entry) {
if (Array.isArray(entry.data)) {
data = entry.data;
} else {
- console.warn(
- "formEntries data was not an array. Using empty array."
- );
+ console.warn("formEntries data was not an array. Using empty array.");
}
}
- return { columns, data, projectId }; // projectId도 반환 (필요시)
- // --- 기존 로직 끝 ---
+ // *** 새로 추가: 편집 가능 필드 정보 계산 ***
+ const editableFieldsMap = await getEditableFieldsByTag(contractItemId, projectId);
+
+ return { columns, data, editableFieldsMap };
},
- [cacheKey], // 캐시 키 의존성
+ [cacheKey],
{
- revalidate: 60, // 1분 캐시
- tags: [cacheKey], // 캐시 태그
+ revalidate: 60,
+ tags: [cacheKey],
}
)();
return result;
} catch (cacheError) {
console.error(`[getFormData] Cache operation failed:`, cacheError);
-
- // --- fallback: 캐시 문제 시 직접 쿼리 시도 ---
+
+ // Fallback logic (기존과 동일하게 editableFieldsMap 추가)
try {
- console.log(
- `[getFormData] Fallback DB query for (${formCode}, ${contractItemId})`
- );
+ console.log(`[getFormData] Fallback DB query for (${formCode}, ${contractItemId})`);
- // (0) contractItemId로부터 projectId 조회
const contractItemResult = await db
.select({
projectId: projects.id
@@ -289,12 +338,11 @@ export async function getFormData(formCode: string, contractItemId: number) {
if (contractItemResult.length === 0) {
console.warn(`[getFormData] Fallback: No contract item found with ID: ${contractItemId}`);
- return { columns: null, data: [] };
+ return { columns: null, data: [], editableFieldsMap: new Map() };
}
const projectId = contractItemResult[0].projectId;
- // (1) form_metas - projectId 고려
const metaRows = await db
.select()
.from(formMetas)
@@ -310,10 +358,9 @@ export async function getFormData(formCode: string, contractItemId: number) {
const meta = metaRows[0] ?? null;
if (!meta) {
console.warn(`[getFormData] Fallback: No form meta found for formCode: ${formCode} and projectId: ${projectId}`);
- return { columns: null, data: [] };
+ return { columns: null, data: [], editableFieldsMap: new Map() };
}
- // (2) form_entries
const entryRows = await db
.select()
.from(formEntries)
@@ -329,17 +376,10 @@ export async function getFormData(formCode: string, contractItemId: number) {
const entry = entryRows[0] ?? null;
let columns = meta.columns as DataTableColumnJSON[];
-
- // 제외할 key들 정의
const excludeKeys = ['CLS_ID', 'BF_TAG_NO', 'TAG_TYPE_ID', 'PIC_NO'];
-
- // 제외할 key들을 가진 컬럼들을 필터링해서 제거
columns = columns.filter(col => !excludeKeys.includes(col.key));
columns.forEach((col) => {
- // 이미 displayLabel이 있으면 그대로 두고,
- // 없으면 uom이 있으면 "label (uom)" 형태,
- // 둘 다 없으면 label만 쓴다.
if (!col.displayLabel) {
if (col.uom) {
col.displayLabel = `${col.label} (${col.uom})`;
@@ -354,21 +394,21 @@ export async function getFormData(formCode: string, contractItemId: number) {
if (Array.isArray(entry.data)) {
data = entry.data;
} else {
- console.warn(
- "formEntries data was not an array. Using empty array (fallback)."
- );
+ console.warn("formEntries data was not an array. Using empty array (fallback).");
}
}
- return { columns, data, projectId }; // projectId도 반환 (필요시)
+ // Fallback에서도 편집 가능 필드 정보 계산
+ const editableFieldsMap = await getEditableFieldsByTag(contractItemId, projectId);
+
+ return { columns, data, projectId, editableFieldsMap };
} catch (dbError) {
console.error(`[getFormData] Fallback DB query failed:`, dbError);
- return { columns: null, data: [] };
+ return { columns: null, data: [], editableFieldsMap: new Map() };
}
}
}
-
-/**
+/**1
* contractId와 formCode(itemCode)를 사용하여 contractItemId를 찾는 서버 액션
*
* @param contractId - 계약 ID