feat: [bending] 절곡품 전용 테이블 분리 API
- bending_items 전용 테이블 생성 (items.options → 정규 컬럼 승격) - bending_models 전용 테이블 생성 (가이드레일/케이스/하단마감재 통합) - bending_data JSON 통합 (별도 테이블 → bending_items.bending_data 컬럼) - bending_item_mappings 테이블 DROP (bending_items.code에 흡수) - BendingItemService/BendingCodeService → BendingItem 모델 전환 - GuiderailModelService component 이미지 자동 복사 - ItemsFileController bending_items/bending_models 폴백 지원 - Swagger 스키마 업데이트
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 절곡 기초관리 전용 테이블
|
||||
*
|
||||
* 기존: items(item_category='BENDING') + options JSON
|
||||
* 변경: bending_items 전용 테이블 + 정규 컬럼
|
||||
*
|
||||
* 이유:
|
||||
* - options JSON 검색 불가 (하장바 등 레거시 검색 누락)
|
||||
* - 인덱싱/정렬/NULL 관리 불가
|
||||
* - bending_item_mappings 테이블 흡수 (code에 통합)
|
||||
*
|
||||
* code 체계: {제품Code}{종류Code}{YYMMDD}
|
||||
* 예: CP260319 = 케이스(C) 점검구(P) 2026-03-19
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('bending_items', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
|
||||
|
||||
// 코드 체계 (LOT 코드 = 제품Code + 종류Code + YYMMDD)
|
||||
$table->string('code', 50)->comment('LOT: {제품}{종류}{YYMMDD} 예: CP260319');
|
||||
$table->string('legacy_code', 50)->nullable()->comment('이전 BD-LEGACY-* / BD-{품명}-* 코드');
|
||||
$table->unsignedInteger('legacy_bending_id')->nullable()->comment('chandj.bending.id 참조');
|
||||
|
||||
// 기본 정보 (기존 options에서 정규 컬럼으로 승격)
|
||||
$table->string('item_name', 100)->comment('품명');
|
||||
$table->string('item_sep', 20)->nullable()->comment('대분류: 스크린/철재');
|
||||
$table->string('item_bending', 50)->nullable()->comment('중분류: 가이드레일/케이스/하단마감재');
|
||||
$table->string('material', 50)->nullable()->comment('재질: SUS 1.2T / EGI 1.55T');
|
||||
$table->string('item_spec', 100)->nullable()->comment('규격: 120*70');
|
||||
$table->string('model_name', 50)->nullable()->comment('소속 모델: KSS01');
|
||||
$table->string('model_UA', 20)->nullable()->comment('인정여부: 인정/비인정');
|
||||
|
||||
// 절곡 전용 속성
|
||||
$table->decimal('rail_width', 10, 2)->nullable()->comment('레일폭');
|
||||
$table->string('exit_direction', 20)->nullable()->comment('출구방향 (케이스 전용)');
|
||||
$table->decimal('box_width', 10, 2)->nullable()->comment('박스폭 (케이스 전용)');
|
||||
$table->decimal('box_height', 10, 2)->nullable()->comment('박스높이 (케이스 전용)');
|
||||
$table->decimal('front_bottom', 10, 2)->nullable()->comment('전면밑 (케이스 전용)');
|
||||
$table->string('inspection_door', 20)->nullable()->comment('점검구 (케이스 전용)');
|
||||
|
||||
// 메타 (비정형 속성만 — 검색/필터 대상 아닌 것)
|
||||
$table->json('options')->nullable()->comment('memo, author, search_keyword, modified_by 등');
|
||||
$table->boolean('is_active')->default(true)->comment('활성 상태');
|
||||
$table->unsignedBigInteger('created_by')->nullable()->comment('생성자');
|
||||
$table->unsignedBigInteger('updated_by')->nullable()->comment('수정자');
|
||||
$table->unsignedBigInteger('deleted_by')->nullable()->comment('삭제자');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
// 인덱스
|
||||
$table->index('tenant_id', 'idx_bi_tenant');
|
||||
$table->index('item_name', 'idx_bi_item_name');
|
||||
$table->index('item_sep', 'idx_bi_item_sep');
|
||||
$table->index('item_bending', 'idx_bi_item_bending');
|
||||
$table->index('material', 'idx_bi_material');
|
||||
$table->index('model_name', 'idx_bi_model_name');
|
||||
$table->index('code', 'idx_bi_code');
|
||||
$table->index('legacy_code', 'idx_bi_legacy_code');
|
||||
$table->unique(['tenant_id', 'code', 'deleted_at'], 'uk_bi_tenant_code');
|
||||
|
||||
// 외래키
|
||||
$table->foreign('tenant_id')->references('id')->on('tenants');
|
||||
});
|
||||
|
||||
\DB::statement("ALTER TABLE bending_items COMMENT = '절곡 기초관리 마스터 (items 테이블에서 분리)'");
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('bending_items');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 절곡 전개도 데이터 테이블
|
||||
*
|
||||
* 기존: items.options.bendingData JSON 배열
|
||||
* [{no:1, input:10, rate:"", sum:10, color:true, aAngle:false}, ...]
|
||||
*
|
||||
* 변경: bending_data 정규 테이블 (bending_items 1:N)
|
||||
*
|
||||
* 이유:
|
||||
* - JSON 배열은 개별 행 수정/검색 불가
|
||||
* - sort_order로 열 순서 보장
|
||||
* - 정규 컬럼으로 타입 안전성 확보
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('bending_data', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('bending_item_id')->comment('FK → bending_items.id');
|
||||
$table->smallInteger('sort_order')->unsigned()->comment('열 순서 (1,2,3,...)');
|
||||
|
||||
// 전개도 행 데이터
|
||||
$table->decimal('input', 10, 2)->default(0)->comment('입력 치수');
|
||||
$table->string('rate', 10)->nullable()->comment('연신율: ""(없음), "-1"(하향), "1"(상향)');
|
||||
$table->decimal('after_rate', 10, 2)->nullable()->comment('연신율 적용 후 값 (input + rate)');
|
||||
$table->decimal('sum', 10, 2)->nullable()->comment('누적 합계');
|
||||
$table->boolean('color')->default(false)->comment('음영 마킹 (파란/노란 배경)');
|
||||
$table->boolean('a_angle')->default(false)->comment('A각 표시');
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// 인덱스
|
||||
$table->index('bending_item_id', 'idx_bd_bending_item');
|
||||
$table->unique(['bending_item_id', 'sort_order'], 'uk_bd_item_order');
|
||||
|
||||
// 외래키
|
||||
$table->foreign('bending_item_id')
|
||||
->references('id')
|
||||
->on('bending_items')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
|
||||
\DB::statement("ALTER TABLE bending_data COMMENT = '절곡 전개도 행 데이터 (bending_items 1:N)'");
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('bending_data');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* bending_data 별도 테이블 → bending_items.bending_data JSON 컬럼으로 통합
|
||||
*
|
||||
* 전개도 데이터는 항상 통째로 읽고/쓰기 하므로 JSON이 적합
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// 1. bending_items에 bending_data JSON 컬럼 추가
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->json('bending_data')->nullable()->after('inspection_door')
|
||||
->comment('전개도 데이터 [{no, input, rate, sum, color, aAngle}, ...]');
|
||||
});
|
||||
|
||||
// 2. bending_data 테이블 → bending_items.bending_data JSON으로 이관
|
||||
$items = DB::table('bending_data')
|
||||
->select('bending_item_id')
|
||||
->distinct()
|
||||
->pluck('bending_item_id');
|
||||
|
||||
foreach ($items as $itemId) {
|
||||
$rows = DB::table('bending_data')
|
||||
->where('bending_item_id', $itemId)
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
|
||||
$json = $rows->map(fn ($r) => [
|
||||
'no' => $r->sort_order,
|
||||
'input' => (float) $r->input,
|
||||
'rate' => $r->rate ?? '',
|
||||
'sum' => $r->sum !== null ? (float) $r->sum : null,
|
||||
'color' => (bool) $r->color,
|
||||
'aAngle' => (bool) $r->a_angle,
|
||||
])->values()->toArray();
|
||||
|
||||
DB::table('bending_items')
|
||||
->where('id', $itemId)
|
||||
->update(['bending_data' => json_encode($json)]);
|
||||
}
|
||||
|
||||
// 3. bending_data 테이블 DROP
|
||||
Schema::dropIfExists('bending_data');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// bending_data 테이블 재생성
|
||||
Schema::create('bending_data', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('bending_item_id');
|
||||
$table->smallInteger('sort_order')->unsigned();
|
||||
$table->decimal('input', 10, 2)->default(0);
|
||||
$table->string('rate', 10)->nullable();
|
||||
$table->decimal('after_rate', 10, 2)->nullable();
|
||||
$table->decimal('sum', 10, 2)->nullable();
|
||||
$table->boolean('color')->default(false);
|
||||
$table->boolean('a_angle')->default(false);
|
||||
$table->timestamps();
|
||||
$table->index('bending_item_id', 'idx_bd_bending_item');
|
||||
$table->unique(['bending_item_id', 'sort_order'], 'uk_bd_item_order');
|
||||
$table->foreign('bending_item_id')->references('id')->on('bending_items')->onDelete('cascade');
|
||||
});
|
||||
|
||||
// bending_items.bending_data 컬럼 삭제
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->dropColumn('bending_data');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* bending_items.bending_data JSON → bending_data 별도 테이블로 분리
|
||||
*
|
||||
* 전개도 데이터는 행 수 가변 + 정규화가 적합
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// 1. bending_data 테이블 재생성
|
||||
Schema::create('bending_data', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('bending_item_id')->comment('FK → bending_items.id');
|
||||
$table->smallInteger('sort_order')->unsigned()->comment('열 순서 (1,2,3,...)');
|
||||
|
||||
$table->decimal('input', 10, 2)->default(0)->comment('입력 치수');
|
||||
$table->string('rate', 10)->nullable()->comment('연신율: ""(없음), "-1"(하향), "1"(상향)');
|
||||
$table->decimal('after_rate', 10, 2)->nullable()->comment('연신율 적용 후 값');
|
||||
$table->decimal('sum', 10, 2)->nullable()->comment('누적 합계');
|
||||
$table->boolean('color')->default(false)->comment('음영 마킹');
|
||||
$table->boolean('a_angle')->default(false)->comment('A각 표시');
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('bending_item_id', 'idx_bd_bending_item');
|
||||
$table->unique(['bending_item_id', 'sort_order'], 'uk_bd_item_order');
|
||||
$table->foreign('bending_item_id')->references('id')->on('bending_items')->onDelete('cascade');
|
||||
});
|
||||
|
||||
// 2. bending_items.bending_data JSON → bending_data rows 분해
|
||||
$items = DB::table('bending_items')
|
||||
->whereNotNull('bending_data')
|
||||
->select('id', 'bending_data')
|
||||
->get();
|
||||
|
||||
foreach ($items as $item) {
|
||||
$rows = json_decode($item->bending_data, true);
|
||||
if (empty($rows) || ! is_array($rows)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($rows as $i => $row) {
|
||||
$input = (float) ($row['input'] ?? 0);
|
||||
$rate = $row['rate'] ?? '';
|
||||
$afterRate = ($rate !== '' && $rate !== null) ? $input + (float) $rate : $input;
|
||||
|
||||
DB::table('bending_data')->insert([
|
||||
'bending_item_id' => $item->id,
|
||||
'sort_order' => $row['no'] ?? ($i + 1),
|
||||
'input' => $input,
|
||||
'rate' => $rate !== '' ? $rate : null,
|
||||
'after_rate' => $afterRate,
|
||||
'sum' => $row['sum'] ?? null,
|
||||
'color' => (bool) ($row['color'] ?? false),
|
||||
'a_angle' => (bool) ($row['aAngle'] ?? $row['a_angle'] ?? false),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. bending_items.bending_data JSON 컬럼 삭제
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->dropColumn('bending_data');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// bending_items에 bending_data JSON 컬럼 복원
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->json('bending_data')->nullable()->after('inspection_door');
|
||||
});
|
||||
|
||||
// bending_data rows → JSON 복원
|
||||
$itemIds = DB::table('bending_data')->distinct()->pluck('bending_item_id');
|
||||
foreach ($itemIds as $itemId) {
|
||||
$rows = DB::table('bending_data')
|
||||
->where('bending_item_id', $itemId)
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
|
||||
$json = $rows->map(fn ($r) => [
|
||||
'no' => $r->sort_order,
|
||||
'input' => (float) $r->input,
|
||||
'rate' => $r->rate ?? '',
|
||||
'sum' => $r->sum !== null ? (float) $r->sum : null,
|
||||
'color' => (bool) $r->color,
|
||||
'aAngle' => (bool) $r->a_angle,
|
||||
])->values()->toArray();
|
||||
|
||||
DB::table('bending_items')->where('id', $itemId)->update([
|
||||
'bending_data' => json_encode($json),
|
||||
]);
|
||||
}
|
||||
|
||||
Schema::dropIfExists('bending_data');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* bending_item_mappings 테이블 제거
|
||||
*
|
||||
* LOT 코드 매핑이 bending_items.legacy_code로 흡수됨
|
||||
* BendingCodeService.resolveItem()도 bending_items 직접 조회로 변경됨
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::dropIfExists('bending_item_mappings');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::create('bending_item_mappings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id');
|
||||
$table->string('prod_code', 2);
|
||||
$table->string('spec_code', 2);
|
||||
$table->string('length_code', 2);
|
||||
$table->unsignedBigInteger('item_id');
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->timestamps();
|
||||
$table->unique(['tenant_id', 'prod_code', 'spec_code', 'length_code'], 'bim_tenant_prod_spec_length_unique');
|
||||
$table->index(['tenant_id', 'is_active']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* bending_items에 length_code, length_mm 컬럼 추가
|
||||
* 유니크 인덱스를 (tenant_id, code, length_code, deleted_at)로 변경
|
||||
*
|
||||
* 같은 제품+종류(RS)라도 원자재 길이(24,30,35...)가 다르면 별도 품목
|
||||
* code = RS260319, length_code = 30 → RS260319 + 3000mm
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// 1. 컬럼 추가
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->string('length_code', 5)->nullable()->after('inspection_door')->comment('원자재 길이코드: 24,30,35,40,42,43 등');
|
||||
$table->integer('length_mm')->nullable()->after('length_code')->comment('원자재 길이(mm): 2438,3000,3500...');
|
||||
});
|
||||
|
||||
// 2. items.options에서 length_code/length_mm 복사
|
||||
DB::statement("
|
||||
UPDATE bending_items bi
|
||||
JOIN items i ON i.code = bi.legacy_code AND i.item_category = 'BENDING' AND i.tenant_id = bi.tenant_id
|
||||
SET bi.length_code = JSON_UNQUOTE(JSON_EXTRACT(i.options, '$.length_code')),
|
||||
bi.length_mm = CAST(JSON_UNQUOTE(JSON_EXTRACT(i.options, '$.length_mm')) AS UNSIGNED)
|
||||
WHERE JSON_EXTRACT(i.options, '$.length_code') IS NOT NULL
|
||||
");
|
||||
|
||||
// 3. legacy_code에서 length_code 추출 (BD-RS-30 → 30)
|
||||
DB::statement("
|
||||
UPDATE bending_items
|
||||
SET length_code = SUBSTRING(legacy_code, -2)
|
||||
WHERE legacy_code REGEXP '^BD-[A-Z]{2}-[0-9]{2}$'
|
||||
AND length_code IS NULL
|
||||
");
|
||||
|
||||
// 4. code에서 -XX 접미사 제거 (RS260319-30 → RS260319)
|
||||
DB::statement("
|
||||
UPDATE bending_items
|
||||
SET code = SUBSTRING(code, 1, LENGTH(code) - 3)
|
||||
WHERE code REGEXP '^[A-Z]{2}[0-9]{6}-[0-9]{2}$'
|
||||
");
|
||||
|
||||
// 5. 유니크 인덱스 변경
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->dropUnique('uk_bi_tenant_code');
|
||||
$table->unique(['tenant_id', 'code', 'length_code', 'deleted_at'], 'uk_bi_tenant_code_length');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->dropUnique('uk_bi_tenant_code_length');
|
||||
$table->unique(['tenant_id', 'code', 'deleted_at'], 'uk_bi_tenant_code');
|
||||
$table->dropColumn(['length_code', 'length_mm']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 절곡품 모델 전용 테이블 (가이드레일/케이스/하단마감재 통합)
|
||||
*
|
||||
* 기존: items (item_category = GUIDERAIL_MODEL / SHUTTERBOX_MODEL / BOTTOMBAR_MODEL) + options JSON
|
||||
* 변경: bending_models 전용 테이블 + 정규 컬럼
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('bending_models', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('tenant_id');
|
||||
$table->string('model_type', 30)->comment('GUIDERAIL_MODEL / SHUTTERBOX_MODEL / BOTTOMBAR_MODEL');
|
||||
$table->string('code', 100);
|
||||
$table->string('name', 255);
|
||||
$table->string('legacy_code', 100)->nullable();
|
||||
$table->unsignedInteger('legacy_num')->nullable()->comment('chandj 원본 num');
|
||||
|
||||
// 공통
|
||||
$table->string('model_name', 50)->nullable();
|
||||
$table->string('model_UA', 20)->nullable();
|
||||
$table->string('item_sep', 20)->nullable();
|
||||
$table->string('finishing_type', 20)->nullable();
|
||||
$table->string('author', 50)->nullable();
|
||||
$table->text('remark')->nullable();
|
||||
|
||||
// 가이드레일
|
||||
$table->string('check_type', 30)->nullable();
|
||||
$table->decimal('rail_width', 10, 2)->nullable();
|
||||
$table->decimal('rail_length', 10, 2)->nullable();
|
||||
|
||||
// 케이스
|
||||
$table->string('exit_direction', 20)->nullable();
|
||||
$table->decimal('front_bottom_width', 10, 2)->nullable();
|
||||
$table->decimal('box_width', 10, 2)->nullable();
|
||||
$table->decimal('box_height', 10, 2)->nullable();
|
||||
|
||||
// 하단마감재
|
||||
$table->decimal('bar_width', 10, 2)->nullable();
|
||||
$table->decimal('bar_height', 10, 2)->nullable();
|
||||
|
||||
// 부품 조합
|
||||
$table->json('components')->nullable();
|
||||
$table->json('material_summary')->nullable();
|
||||
|
||||
// 메타
|
||||
$table->string('search_keyword', 100)->nullable();
|
||||
$table->date('registration_date')->nullable();
|
||||
$table->json('options')->nullable();
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->unsignedBigInteger('created_by')->nullable();
|
||||
$table->unsignedBigInteger('updated_by')->nullable();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index('tenant_id', 'idx_bm_tenant');
|
||||
$table->index('model_type', 'idx_bm_type');
|
||||
$table->index('model_name', 'idx_bm_model_name');
|
||||
$table->index('item_sep', 'idx_bm_item_sep');
|
||||
$table->unique(['tenant_id', 'code', 'deleted_at'], 'uk_bm_tenant_code');
|
||||
$table->foreign('tenant_id')->references('id')->on('tenants');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('bending_models');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* bending_data 테이블 → bending_items.bending_data JSON 컬럼으로 통합
|
||||
*
|
||||
* 전개도 데이터는 항상 통째로 읽기/쓰기, 개별 행 검색 없음 → JSON이 적합
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// 1. bending_items에 bending_data JSON 컬럼 추가
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->json('bending_data')->nullable()->after('inspection_door')
|
||||
->comment('전개도 [{no, input, rate, sum, color, aAngle}]');
|
||||
});
|
||||
|
||||
// 2. bending_data rows → JSON 변환
|
||||
$itemIds = DB::table('bending_data')->distinct()->pluck('bending_item_id');
|
||||
|
||||
foreach ($itemIds as $itemId) {
|
||||
$rows = DB::table('bending_data')
|
||||
->where('bending_item_id', $itemId)
|
||||
->orderBy('sort_order')
|
||||
->get();
|
||||
|
||||
$json = $rows->map(fn ($r) => [
|
||||
'no' => $r->sort_order,
|
||||
'input' => (float) $r->input,
|
||||
'rate' => $r->rate ?? '',
|
||||
'sum' => $r->sum !== null ? (float) $r->sum : null,
|
||||
'color' => (bool) $r->color,
|
||||
'aAngle' => (bool) $r->a_angle,
|
||||
])->values()->toArray();
|
||||
|
||||
DB::table('bending_items')
|
||||
->where('id', $itemId)
|
||||
->update(['bending_data' => json_encode($json)]);
|
||||
}
|
||||
|
||||
// 3. bending_data 테이블 DROP
|
||||
Schema::dropIfExists('bending_data');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::create('bending_data', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('bending_item_id');
|
||||
$table->smallInteger('sort_order')->unsigned();
|
||||
$table->decimal('input', 10, 2)->default(0);
|
||||
$table->string('rate', 10)->nullable();
|
||||
$table->decimal('after_rate', 10, 2)->nullable();
|
||||
$table->decimal('sum', 10, 2)->nullable();
|
||||
$table->boolean('color')->default(false);
|
||||
$table->boolean('a_angle')->default(false);
|
||||
$table->timestamps();
|
||||
$table->index('bending_item_id', 'idx_bd_bending_item');
|
||||
$table->unique(['bending_item_id', 'sort_order'], 'uk_bd_item_order');
|
||||
$table->foreign('bending_item_id')->references('id')->on('bending_items')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::table('bending_items', function (Blueprint $table) {
|
||||
$table->dropColumn('bending_data');
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user