- ItemFieldController API 수정 - ItemFieldSeedingService 로직 개선 - Flow Tester 상세 화면 개선 - 레이아웃 및 프로젝트 상세 화면 수정 - 테이블 정렬 JS 추가
368 lines
11 KiB
PHP
368 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Admin;
|
|
|
|
use App\Constants\SystemFieldDefinitions;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Services\ItemFieldSeedingService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\View\View;
|
|
|
|
/**
|
|
* 품목기준 필드 관리 API 컨트롤러 (HTMX)
|
|
*/
|
|
class ItemFieldController extends Controller
|
|
{
|
|
public function __construct(
|
|
private ItemFieldSeedingService $service
|
|
) {}
|
|
|
|
/**
|
|
* 시딩 상태 조회 (HTMX partial)
|
|
*/
|
|
public function seedingStatus(Request $request): View
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
Log::info('seedingStatus called', [
|
|
'tenantId' => $tenantId,
|
|
'session' => session()->all(),
|
|
]);
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return view('item-fields.partials.seeding-status', [
|
|
'statuses' => [],
|
|
'error' => '테넌트를 선택해주세요.',
|
|
]);
|
|
}
|
|
|
|
$statuses = $this->service->getSeedingStatus($tenantId);
|
|
|
|
Log::info('seedingStatus result', [
|
|
'statuses_count' => count($statuses),
|
|
'statuses' => $statuses,
|
|
]);
|
|
|
|
return view('item-fields.partials.seeding-status', compact('statuses'));
|
|
}
|
|
|
|
/**
|
|
* 단일 테이블 시딩
|
|
*/
|
|
public function seed(Request $request): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '테넌트를 선택해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$sourceTable = $request->input('source_table');
|
|
|
|
if (! $sourceTable) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '소스 테이블을 지정해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$result = $this->service->seedTable($tenantId, $sourceTable);
|
|
|
|
return response()->json($result);
|
|
}
|
|
|
|
/**
|
|
* 전체 테이블 시딩
|
|
*/
|
|
public function seedAll(Request $request): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '테넌트를 선택해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$result = $this->service->seedAll($tenantId);
|
|
|
|
return response()->json($result);
|
|
}
|
|
|
|
/**
|
|
* 단일 테이블 초기화
|
|
*/
|
|
public function reset(Request $request): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '테넌트를 선택해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$sourceTable = $request->input('source_table');
|
|
|
|
if (! $sourceTable) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '소스 테이블을 지정해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$result = $this->service->resetTable($tenantId, $sourceTable);
|
|
|
|
return response()->json($result);
|
|
}
|
|
|
|
/**
|
|
* 전체 테이블 초기화
|
|
*/
|
|
public function resetAll(Request $request): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '테넌트를 선택해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$result = $this->service->resetAll($tenantId);
|
|
|
|
return response()->json($result);
|
|
}
|
|
|
|
/**
|
|
* 필드 목록 (HTMX partial) - 시스템 + 커스텀
|
|
*/
|
|
public function customFields(Request $request): View
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return view('item-fields.partials.custom-fields', [
|
|
'fields' => collect([]),
|
|
'sourceTables' => SystemFieldDefinitions::SOURCE_TABLES,
|
|
'error' => '테넌트를 선택해주세요.',
|
|
]);
|
|
}
|
|
|
|
// getFields() 메서드 사용 (시스템 + 커스텀 모두 조회, 시스템 필드 우선 정렬)
|
|
$fields = $this->service->getFields($tenantId, $request->all());
|
|
|
|
return view('item-fields.partials.custom-fields', [
|
|
'fields' => $fields,
|
|
'sourceTables' => SystemFieldDefinitions::SOURCE_TABLES,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 커스텀 필드 추가
|
|
*/
|
|
public function storeCustomField(Request $request): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '테넌트를 선택해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'source_table' => 'required|string',
|
|
'field_key' => 'required|string|max:100|regex:/^[a-zA-Z0-9_]+$/',
|
|
'field_name' => 'required|string|max:255',
|
|
'field_type' => 'required|string|in:textbox,number,dropdown,checkbox,date,textarea',
|
|
'is_required' => 'nullable|boolean',
|
|
'default_value' => 'nullable|string',
|
|
'options' => 'nullable|array',
|
|
]);
|
|
|
|
$result = $this->service->createCustomField($tenantId, $validated);
|
|
|
|
return response()->json($result, $result['success'] ? 200 : 400);
|
|
}
|
|
|
|
/**
|
|
* 커스텀 필드 수정
|
|
*/
|
|
public function updateCustomField(Request $request, int $id): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '테넌트를 선택해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'source_table' => 'nullable|string',
|
|
'field_key' => 'nullable|string|max:100|regex:/^[a-zA-Z0-9_]+$/',
|
|
'field_name' => 'required|string|max:255',
|
|
'field_type' => 'required|string|in:textbox,number,dropdown,checkbox,date,textarea',
|
|
'is_required' => 'nullable|boolean',
|
|
'default_value' => 'nullable|string',
|
|
'options' => 'nullable|array',
|
|
]);
|
|
|
|
$result = $this->service->updateCustomField($tenantId, $id, $validated);
|
|
|
|
return response()->json($result, $result['success'] ? 200 : 400);
|
|
}
|
|
|
|
/**
|
|
* 커스텀 필드 삭제
|
|
*/
|
|
public function destroyCustomField(int $id): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '테넌트를 선택해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$result = $this->service->deleteCustomField($tenantId, $id);
|
|
|
|
return response()->json($result, $result['success'] ? 200 : 400);
|
|
}
|
|
|
|
/**
|
|
* 커스텀 필드 일괄 삭제
|
|
*/
|
|
public function destroyCustomFields(Request $request): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
|
|
if (! $tenantId || $tenantId === 'all') {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '테넌트를 선택해주세요.',
|
|
], 400);
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'ids' => 'required|array',
|
|
'ids.*' => 'required|integer',
|
|
]);
|
|
|
|
$result = $this->service->deleteCustomFields($tenantId, $validated['ids']);
|
|
|
|
return response()->json($result);
|
|
}
|
|
|
|
/**
|
|
* 소스 테이블 목록 (JSON)
|
|
*/
|
|
public function sourceTables(): JsonResponse
|
|
{
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => SystemFieldDefinitions::SOURCE_TABLES,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 오류 로그 조회 (HTMX partial)
|
|
*/
|
|
public function errorLogs(): View
|
|
{
|
|
$errorLogs = $this->service->getErrorLogs();
|
|
|
|
return view('item-fields.partials.error-logs', compact('errorLogs'));
|
|
}
|
|
|
|
/**
|
|
* 오류 로그 초기화
|
|
*/
|
|
public function clearErrorLogs(): JsonResponse
|
|
{
|
|
$this->service->clearErrorLogs();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => '오류 로그가 초기화되었습니다.',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* AI 문의용 오류 보고서 생성
|
|
*/
|
|
public function generateErrorReport(): JsonResponse
|
|
{
|
|
$tenantId = session('selected_tenant_id');
|
|
$errorLogs = $this->service->getErrorLogs();
|
|
|
|
if (empty($errorLogs)) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => '저장된 오류 로그가 없습니다.',
|
|
]);
|
|
}
|
|
|
|
$latestError = $errorLogs[0];
|
|
|
|
// 보고서 생성
|
|
$report = $this->buildErrorReport($latestError, $tenantId);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'report' => $report,
|
|
'error_count' => count($latestError['errors'] ?? []),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 오류 보고서 텍스트 생성
|
|
*/
|
|
protected function buildErrorReport(array $errorLog, ?int $tenantId): string
|
|
{
|
|
$errors = $errorLog['errors'] ?? [];
|
|
$sourceTable = $errorLog['source_table'] ?? 'unknown';
|
|
$timestamp = $errorLog['timestamp'] ?? now()->toDateTimeString();
|
|
|
|
$report = "## 품목기준 필드 시딩 오류 보고서\n\n";
|
|
$report .= "### 기본 정보\n";
|
|
$report .= "- **발생 시각**: {$timestamp}\n";
|
|
$report .= "- **테넌트 ID**: {$tenantId}\n";
|
|
$report .= "- **소스 테이블**: {$sourceTable}\n";
|
|
$report .= '- **오류 수**: '.count($errors)."건\n\n";
|
|
|
|
$report .= "### 오류 상세\n";
|
|
foreach ($errors as $index => $error) {
|
|
$num = $index + 1;
|
|
$report .= "\n#### 오류 #{$num}\n";
|
|
$report .= "- **필드 키**: `{$error['field_key']}`\n";
|
|
$report .= "- **필드명**: {$error['field_name']}\n";
|
|
$report .= "- **오류 코드**: {$error['error_code']}\n";
|
|
$report .= "- **오류 메시지**:\n```\n{$error['error_message']}\n```\n";
|
|
}
|
|
|
|
$report .= "\n### 환경 정보\n";
|
|
$report .= "- **애플리케이션**: MNG (품목기준 필드 관리)\n";
|
|
$report .= "- **DB 테이블**: item_fields\n";
|
|
$report .= "- **관련 파일**: `app/Services/ItemFieldSeedingService.php`\n";
|
|
|
|
$report .= "\n### 요청 사항\n";
|
|
$report .= "위 오류의 원인을 분석하고 해결 방법을 제시해 주세요.\n";
|
|
|
|
return $report;
|
|
}
|
|
}
|