diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-21 06:57:36 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-08-21 06:57:36 +0000 |
| commit | 02b1cf005cf3e1df64183d20ba42930eb2767a9f (patch) | |
| tree | e932c54d5260b0e6fda2b46be2a6ba1c3ee30434 /components/form-data/export-excel-form.tsx | |
| parent | d78378ecd7ceede1429359f8058c7a99ac34b1b7 (diff) | |
(대표님, 최겸) 설계메뉴추가, 작업사항 업데이트
설계메뉴 - 문서관리
설계메뉴 - 벤더 데이터
gtc 메뉴 업데이트
정보시스템 - 메뉴리스트 및 정보 업데이트
파일 라우트 업데이트
엑셀임포트 개선
기본계약 개선
벤더 가입과정 변경 및 개선
벤더 기본정보 - pq
돌체 오류 수정 및 개선
벤더 로그인 과정 이메일 오류 수정
Diffstat (limited to 'components/form-data/export-excel-form.tsx')
| -rw-r--r-- | components/form-data/export-excel-form.tsx | 156 |
1 files changed, 137 insertions, 19 deletions
diff --git a/components/form-data/export-excel-form.tsx b/components/form-data/export-excel-form.tsx index 64e9ea3d..1efa5819 100644 --- a/components/form-data/export-excel-form.tsx +++ b/components/form-data/export-excel-form.tsx @@ -11,7 +11,7 @@ export interface DataTableColumnJSON { label: string; type: ColumnType; options?: string[]; - shi?: boolean; // SHI-only field indicator + shi?: string | null; // Updated to support both string and boolean for backward compatibility required?: boolean; // Required field indicator // Add any other properties that might be in columnsJSON } @@ -39,6 +39,7 @@ export interface ExportExcelOptions { tableData: GenericData[]; columnsJSON: DataTableColumnJSON[]; formCode: string; + editableFieldsMap?: Map<string, string[]>; // 새로 추가 onPendingChange?: (isPending: boolean) => void; validateData?: boolean; // Option to enable/disable data validation } @@ -52,6 +53,63 @@ export interface ExportExcelResult { } /** + * Check if a field is editable for a specific TAG_NO + */ +function isFieldEditable( + column: DataTableColumnJSON, + tagNo: string, + editableFieldsMap: Map<string, string[]> +): boolean { + // SHI-only fields (shi === "OUT" or shi === null) are never editable + if (column.shi === "OUT" || column.shi === null) return false; + + // System fields are never editable + if (column.key === "TAG_NO" || column.key === "TAG_DESC" || column.key === "status") return false; + + // If no editableFieldsMap provided, assume all non-SHI fields are editable + if (!editableFieldsMap || editableFieldsMap.size === 0) return true; + + // If TAG_NO not in map, no fields are editable + if (!editableFieldsMap.has(tagNo)) return false; + + // Check if this field is in the editable fields list for this TAG_NO + const editableFields = editableFieldsMap.get(tagNo) || []; + return editableFields.includes(column.key); +} + +/** + * Get the read-only reason for a field + */ +function getReadOnlyReason( + column: DataTableColumnJSON, + tagNo: string, + editableFieldsMap: Map<string, string[]> +): string { + if (column.shi === "OUT" || column.shi === null) { + return "SHI-only field"; + } + + if (column.key === "TAG_NO" || column.key === "TAG_DESC" || column.key === "status") { + return "System field"; + } + + if (!editableFieldsMap || editableFieldsMap.size === 0) { + return "No restrictions"; + } + + if (!editableFieldsMap.has(tagNo)) { + return "No editable fields for this TAG"; + } + + const editableFields = editableFieldsMap.get(tagNo) || []; + if (!editableFields.includes(column.key)) { + return "Not editable for this TAG"; + } + + return "Editable"; +} + +/** * Validate data and collect errors */ function validateTableData( @@ -276,6 +334,7 @@ export async function exportExcelData({ tableData, columnsJSON, formCode, + editableFieldsMap = new Map(), // 새로 추가 onPendingChange, validateData = true }: ExportExcelOptions): Promise<ExportExcelResult> { @@ -346,7 +405,7 @@ export async function exportExcelData({ const columnIndex = colNumber - 1; const column = columnsJSON[columnIndex]; - if (column?.shi === true) { + if (column?.shi === "OUT" || column?.shi === null ) { // SHI-only 필드는 더 진한 음영으로 표시 cell.fill = { type: "pattern", @@ -384,24 +443,53 @@ export async function exportExcelData({ const rowErrors = errors.filter(err => err.rowIndex === rowIndex + 2); const hasErrors = rowErrors.length > 0; - // SHI-only 컬럼의 데이터 셀에도 음영 적용 + // 각 데이터 셀에 적절한 스타일 적용 dataRow.eachCell((cell, colNumber) => { const columnIndex = colNumber - 1; const column = columnsJSON[columnIndex]; + const tagNo = rowData.TAG_NO || ""; // Check if this cell has errors const cellHasError = rowErrors.some(err => err.columnKey === column.key); - if (column?.shi === true) { - // SHI-only 필드의 데이터 셀에 연한 음영 적용 + // Check if this field is editable for this specific TAG_NO + const fieldEditable = isFieldEditable(column, tagNo, editableFieldsMap); + const readOnlyReason = getReadOnlyReason(column, tagNo, editableFieldsMap); + + if (!fieldEditable) { + // Read-only field styling + let bgColor = "FFFFCCCC"; // Default light red for read-only + let fontColor = "FF666666"; // Gray text + + if (column?.shi === "OUT" || column?.shi === null ) { + // SHI-only fields get a more distinct styling + bgColor = cellHasError ? "FFFF6666" : "FFFFCCCC"; // Darker red if error + fontColor = "FF800000"; // Dark red text + } else { + // Other read-only fields (editableFieldsMap restrictions) + bgColor = cellHasError ? "FFFFAA99" : "FFFFDDCC"; // Orange-ish tint + fontColor = "FF996633"; // Brown text + } + cell.fill = { type: "pattern", pattern: "solid", - fgColor: { argb: cellHasError ? "FFFF6666" : "FFFFCCCC" }, // 에러가 있으면 더 진한 빨간색 + fgColor: { argb: bgColor }, }; - cell.font = { italic: true, color: { argb: "FF666666" } }; + cell.font = { italic: true, color: { argb: fontColor } }; + + // Add comment to explain why it's read-only + if (readOnlyReason !== "Editable") { + cell.note = { + texts: [{ text: `Read-only: ${readOnlyReason}` }], + margins: { + insetmode: "custom", + inset: [0.13, 0.13, 0.25, 0.25] + } + }; + } } else if (cellHasError) { - // 에러가 있는 셀은 연한 빨간색 배경 + // Editable field with validation error cell.fill = { type: "pattern", pattern: "solid", @@ -409,6 +497,7 @@ export async function exportExcelData({ }; cell.font = { color: { argb: "FFCC0000" } }; } + // If field is editable and has no errors, no special styling needed }); }); @@ -418,8 +507,8 @@ export async function exportExcelData({ columnsJSON.forEach((col, idx) => { const colLetter = worksheet.getColumn(idx + 1).letter; - // SHI-only 필드가 아닌 LIST 타입에만 유효성 검사 적용 - if (col.type === "LIST" && validationRanges.has(col.key) && col.shi !== true) { + // LIST 타입이고 유효성 검사 범위가 있는 경우에만 적용 + if (col.type === "LIST" && validationRanges.has(col.key)) { const validationRange = validationRanges.get(col.key)!; // 유효성 검사 정의 @@ -439,25 +528,34 @@ export async function exportExcelData({ rowIdx <= Math.min(tableData.length + 1, maxRows); rowIdx++ ) { - worksheet.getCell(`${colLetter}${rowIdx}`).dataValidation = - validation; + const cell = worksheet.getCell(`${colLetter}${rowIdx}`); + + // Only apply validation to editable cells + const rowData = tableData[rowIdx - 2]; // rowIdx is 1-based, data array is 0-based + if (rowData) { + const tagNo = rowData.TAG_NO || ""; + const fieldEditable = isFieldEditable(col, tagNo, editableFieldsMap); + + if (fieldEditable) { + cell.dataValidation = validation; + } + } } - // 빈 행에도 적용 (최대 maxRows까지) + // 빈 행에도 적용 (최대 maxRows까지) - 기본적으로 편집 가능하다고 가정 if (tableData.length + 1 < maxRows) { for ( let rowIdx = tableData.length + 2; rowIdx <= maxRows; rowIdx++ ) { - worksheet.getCell(`${colLetter}${rowIdx}`).dataValidation = - validation; + worksheet.getCell(`${colLetter}${rowIdx}`).dataValidation = validation; } } } - // SHI-only 필드의 빈 행들에도 음영 처리 적용 - if (col.shi === true) { + // Read-only 필드의 빈 행들에도 음영 처리 적용 (기본적으로 SHI-only 필드에만) + if (col.shi === "OUT" || col.shi === null ) { for (let rowIdx = tableData.length + 2; rowIdx <= maxRows; rowIdx++) { const cell = worksheet.getCell(`${colLetter}${rowIdx}`); cell.fill = { @@ -503,8 +601,9 @@ export async function exportExcelData({ legendSheet.addRow(["Red background header", "SHI-only fields that cannot be edited"]); legendSheet.addRow(["Blue background header", "Required fields (marked with *)"]); legendSheet.addRow(["Gray background header", "Regular optional fields"]); - legendSheet.addRow(["Light red background cells", "Cells with validation errors"]); - legendSheet.addRow(["Light red data cells", "Data in SHI-only fields (read-only)"]); + legendSheet.addRow(["Light red background cells", "Cells with validation errors OR SHI-only fields"]); + legendSheet.addRow(["Light orange background cells", "Fields not editable for specific TAG (based on editableFieldsMap)"]); + legendSheet.addRow(["Cell comments", "Hover over read-only cells to see the reason why they cannot be edited"]); if (errors.length > 0) { legendSheet.addRow([]); @@ -512,6 +611,25 @@ export async function exportExcelData({ const errorNoteRow = legendSheet.getRow(legendSheet.rowCount); errorNoteRow.font = { bold: true, color: { argb: "FFCC0000" } }; } + + // Add editableFieldsMap summary if available + if (editableFieldsMap.size > 0) { + legendSheet.addRow([]); + legendSheet.addRow([`Editable Fields Map Summary (${editableFieldsMap.size} TAGs):`]); + const summaryHeaderRow = legendSheet.getRow(legendSheet.rowCount); + summaryHeaderRow.font = { bold: true, color: { argb: "FF000080" } }; + + // Show first few examples + let count = 0; + for (const [tagNo, editableFields] of editableFieldsMap) { + if (count >= 5) { // Show only first 5 examples + legendSheet.addRow([`... and ${editableFieldsMap.size - 5} more TAGs`]); + break; + } + legendSheet.addRow([`${tagNo}:`, editableFields.join(", ")]); + count++; + } + } // 범례 스타일 적용 const legendHeaderRow = legendSheet.getRow(1); |
