summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/[lng]/serp/layout.tsx5
-rw-r--r--app/[lng]/serp/page.tsx69
-rw-r--r--app/api/s-erp-import/rpa/route.ts135
3 files changed, 209 insertions, 0 deletions
diff --git a/app/[lng]/serp/layout.tsx b/app/[lng]/serp/layout.tsx
new file mode 100644
index 00000000..9f048854
--- /dev/null
+++ b/app/[lng]/serp/layout.tsx
@@ -0,0 +1,5 @@
+export default function SapImportLayout({ children }: { children: React.ReactNode }) {
+ return <>{children}</>
+}
+
+
diff --git a/app/[lng]/serp/page.tsx b/app/[lng]/serp/page.tsx
new file mode 100644
index 00000000..0c9e0d3f
--- /dev/null
+++ b/app/[lng]/serp/page.tsx
@@ -0,0 +1,69 @@
+import * as React from 'react'
+import { ImportButton } from '@/components/s-erp-import/import-card'
+import { getSapTableCounts } from '@/lib/s-erp-import/actions'
+
+export const dynamic = 'force-dynamic'
+
+const TABLES = [
+ 'TB_SAP_EquipInfo',
+ 'TB_SAP_Order',
+ 'TB_SAP_OrderConfirm',
+ 'TB_SAP_OrderNotice',
+ 'TB_SAP_OrderBreakdown',
+ 'TB_SAP_MainternanceBOM',
+ 'TB_SAP_MaterialRepair',
+ 'TB_SAP_MaterialInfo',
+ 'TB_SAP_MaterialStock',
+ 'TB_SAP_MaterialRelease',
+ 'TB_SAP_MaterialReceiving',
+ 'TB_SAP_MaterialPurchase',
+]
+
+export default async function Page() {
+ const counts = await getSapTableCounts(TABLES)
+
+ return (
+ <div className="container py-8" data-testid="s-erp-import-page">
+ <h1 className="text-2xl font-bold mb-2" data-testid="page-title">S-ERP 데이터 임포트</h1>
+ <p className='text-sm mb-6' data-testid="page-description">버튼을 클릭하여 엑셀 파일을 업로드 해주세요.</p>
+
+ {/* RPA 가이드 정보 */}
+ <div
+ className="mb-6 p-4 bg-gray-50 border rounded"
+ data-testid="rpa-guide"
+ style={{ display: 'none' }} // RPA가 필요할 때만 표시
+ >
+ <h3 className="font-semibold mb-2" data-testid="rpa-guide-title">RPA 사용 가이드</h3>
+ <div className="text-sm space-y-1" data-testid="rpa-guide-content">
+ <div data-testid="rpa-selector-info">
+ <strong>셀렉터:</strong> [data-testid="upload-button-TABLE_NAME"]
+ </div>
+ <div data-testid="rpa-file-input-info">
+ <strong>파일 입력:</strong> [data-testid="file-input-TABLE_NAME"]
+ </div>
+ <div data-testid="rpa-status-info">
+ <strong>상태 확인:</strong> [data-testid="status-message-TABLE_NAME"]
+ </div>
+ <div data-testid="rpa-table-list-info">
+ <strong>테이블 목록:</strong> [data-testid="table-list"]
+ </div>
+ </div>
+ </div>
+
+ <div className="flex flex-col gap-6" data-testid="table-list">
+ {TABLES.map((name, index) => (
+ <div
+ key={name}
+ data-testid={`table-row-${name}`}
+ data-table-name={name}
+ data-table-index={index}
+ >
+ <ImportButton tableName={name} count={counts[name] ?? 0} />
+ </div>
+ ))}
+ </div>
+ </div>
+ )
+}
+
+
diff --git a/app/api/s-erp-import/rpa/route.ts b/app/api/s-erp-import/rpa/route.ts
new file mode 100644
index 00000000..749de90f
--- /dev/null
+++ b/app/api/s-erp-import/rpa/route.ts
@@ -0,0 +1,135 @@
+import { NextRequest, NextResponse } from 'next/server'
+import { getSapTableCounts, importExcel, exportTemplate } from '@/lib/s-erp-import/actions'
+
+// RPA용 API 엔드포인트
+export async function GET(request: NextRequest) {
+ try {
+ const { searchParams } = new URL(request.url)
+ const action = searchParams.get('action')
+ const tableName = searchParams.get('tableName')
+
+ switch (action) {
+ case 'get-counts':
+ // 모든 테이블의 데이터 건수 조회
+ const TABLES = [
+ 'TB_SAP_EquipInfo',
+ 'TB_SAP_Order',
+ 'TB_SAP_OrderConfirm',
+ 'TB_SAP_OrderNotice',
+ 'TB_SAP_OrderBreakdown',
+ 'TB_SAP_MainternanceBOM',
+ 'TB_SAP_MaterialRepair',
+ 'TB_SAP_MaterialInfo',
+ 'TB_SAP_MaterialStock',
+ 'TB_SAP_MaterialRelease',
+ 'TB_SAP_MaterialReceiving',
+ 'TB_SAP_MaterialPurchase',
+ ]
+ const counts = await getSapTableCounts(TABLES)
+ return NextResponse.json({
+ success: true,
+ data: counts,
+ timestamp: new Date().toISOString()
+ })
+
+ case 'get-template':
+ // 템플릿 다운로드
+ if (!tableName) {
+ return NextResponse.json({
+ success: false,
+ message: 'tableName is required'
+ }, { status: 400 })
+ }
+
+ const templateBuffer = await exportTemplate(tableName)
+ return new NextResponse(templateBuffer, {
+ headers: {
+ 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'Content-Disposition': `attachment; filename="${tableName}_template.xlsx"`
+ }
+ })
+
+ case 'get-table-info':
+ // 테이블 정보 조회
+ const tableInfo = {
+ 'TB_SAP_EquipInfo': { title: '장비 정보', category: '장비 관리', description: 'SAP 장비 마스터 데이터' },
+ 'TB_SAP_Order': { title: '작업 주문', category: '작업 관리', description: '유지보수 작업 주문 정보' },
+ 'TB_SAP_OrderConfirm': { title: '주문 확인', category: '작업 관리', description: '작업 주문 확인 및 완료 정보' },
+ 'TB_SAP_OrderNotice': { title: '주문 통지', category: '작업 관리', description: '작업 주문 통지 및 알림 정보' },
+ 'TB_SAP_OrderBreakdown': { title: '주문 고장', category: '고장 관리', description: '장비 고장 및 수리 정보' },
+ 'TB_SAP_MainternanceBOM': { title: '유지보수 BOM', category: '부품 관리', description: '유지보수용 부품 목록' },
+ 'TB_SAP_MaterialRepair': { title: '자재 수리', category: '자재 관리', description: '자재 수리 및 교체 정보' },
+ 'TB_SAP_MaterialInfo': { title: '자재 정보', category: '자재 관리', description: '자재 마스터 데이터' },
+ 'TB_SAP_MaterialStock': { title: '자재 재고', category: '자재 관리', description: '자재 재고 현황' },
+ 'TB_SAP_MaterialRelease': { title: '자재 출고', category: '자재 관리', description: '자재 출고 내역' },
+ 'TB_SAP_MaterialReceiving': { title: '자재 입고', category: '자재 관리', description: '자재 입고 내역' },
+ 'TB_SAP_MaterialPurchase': { title: '자재 구매', category: '자재 관리', description: '자재 구매 요청 정보' }
+ }
+
+ if (tableName) {
+ return NextResponse.json({
+ success: true,
+ data: tableInfo[tableName as keyof typeof tableInfo] || null
+ })
+ } else {
+ return NextResponse.json({
+ success: true,
+ data: tableInfo
+ })
+ }
+
+ default:
+ return NextResponse.json({
+ success: false,
+ message: 'Invalid action. Supported actions: get-counts, get-template, get-table-info'
+ }, { status: 400 })
+ }
+ } catch (error: any) {
+ console.error('RPA API Error:', error)
+ return NextResponse.json({
+ success: false,
+ message: error.message || 'Internal server error',
+ timestamp: new Date().toISOString()
+ }, { status: 500 })
+ }
+}
+
+// RPA용 파일 업로드 엔드포인트
+export async function POST(request: NextRequest) {
+ try {
+ const formData = await request.formData()
+ const tableName = formData.get('tableName') as string
+ const file = formData.get('file') as File
+
+ if (!tableName || !file) {
+ return NextResponse.json({
+ success: false,
+ message: 'tableName and file are required'
+ }, { status: 400 })
+ }
+
+ // 파일 업로드 처리
+ const result = await importExcel(tableName, file)
+
+ return NextResponse.json({
+ success: result.success,
+ data: {
+ tableName,
+ fileName: file.name,
+ fileSize: file.size,
+ inserted: result.inserted || 0,
+ message: result.message,
+ unknownHeaders: (result as any).unknownHeaders,
+ errors: (result as any).errors
+ },
+ timestamp: new Date().toISOString()
+ })
+ } catch (error: any) {
+ console.error('RPA Upload Error:', error)
+ return NextResponse.json({
+ success: false,
+ message: error.message || 'Upload failed',
+ timestamp: new Date().toISOString()
+ }, { status: 500 })
+ }
+}