feat: 품목관리 파일 업로드 기능 개선

- 파일 업로드 API에 field_key, file_id 파라미터 추가
- ItemMaster 타입에 files 필드 추가 (새 API 구조 지원)
- DynamicItemForm에서 files 객체 파싱 로직 추가
- 시방서/인정서 파일 UI 개선: 파일명 표시 + 다운로드/수정/삭제 버튼
- 기존 API 구조와 새 API 구조 모두 지원 (폴백 처리)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
byeongcheolryu
2025-12-12 18:35:43 +09:00
parent ded0bc2439
commit c026130a65
19 changed files with 772 additions and 331 deletions

View File

@@ -178,10 +178,10 @@ export function ConditionalDisplayUI({
({condition.targetFieldIds?.length || 0} ):
</Label>
<div className="space-y-1 max-h-40 overflow-y-auto bg-white rounded p-2">
{availableFields.map(field => {
{availableFields.map((field, fieldIdx) => {
const fieldIdStr = String(field.id);
return (
<label key={field.id} className="flex items-center gap-2 p-2 hover:bg-gray-50 rounded cursor-pointer">
<label key={`condition-${conditionIndex}-field-${field.id}-${fieldIdx}`} className="flex items-center gap-2 p-2 hover:bg-gray-50 rounded cursor-pointer">
<input
type="checkbox"
checked={condition.targetFieldIds?.includes(fieldIdStr) || false}
@@ -284,10 +284,10 @@ export function ConditionalDisplayUI({
({condition.targetSectionIds?.length || 0} ):
</Label>
<div className="space-y-1 max-h-40 overflow-y-auto bg-white rounded p-2">
{availableSections.map(section => {
{availableSections.map((section, sectionIdx) => {
const sectionIdStr = String(section.id);
return (
<label key={section.id} className="flex items-center gap-2 p-2 hover:bg-gray-50 rounded cursor-pointer">
<label key={`condition-${conditionIndex}-section-${section.id}-${sectionIdx}`} className="flex items-center gap-2 p-2 hover:bg-gray-50 rounded cursor-pointer">
<input
type="checkbox"
checked={condition.targetSectionIds?.includes(sectionIdStr) || false}

View File

@@ -209,9 +209,9 @@ export function FieldDialog({
</p>
) : (
<div className="space-y-2">
{itemMasterFields.map(field => (
{itemMasterFields.map((field, index) => (
<div
key={field.id}
key={`dialog-${field.id}-${index}`}
className={`p-3 border rounded cursor-pointer transition-colors ${
selectedMasterFieldId === String(field.id)
? 'bg-blue-50 border-blue-300'

View File

@@ -185,9 +185,9 @@ export function FieldDrawer({
</p>
) : (
<div className="space-y-2">
{itemMasterFields.map(field => (
{itemMasterFields.map((field, index) => (
<div
key={field.id}
key={`drawer-${field.id}-${index}`}
className={`p-3 border rounded cursor-pointer transition-colors ${
selectedMasterFieldId === String(field.id)
? 'bg-blue-50 border-blue-300'

View File

@@ -185,9 +185,9 @@ export function TemplateFieldDialog({
</p>
) : (
<div className="space-y-2">
{itemMasterFields.map(field => (
{itemMasterFields.map((field, index) => (
<div
key={field.id}
key={`master-${field.id}-${index}`}
className={`p-3 border rounded cursor-pointer transition-colors ${
selectedMasterFieldId === String(field.id)
? 'bg-blue-50 border-blue-300'

View File

@@ -442,7 +442,7 @@ export function HierarchyTab({
.sort((a, b) => (a.order_no ?? 0) - (b.order_no ?? 0))
.map((field, fieldIndex) => (
<DraggableField
key={field.id}
key={`${section.id}-${field.id}-${fieldIndex}`}
field={field}
index={fieldIndex}
moveField={(dragFieldId, hoverFieldId) => moveField(section.id, dragFieldId, hoverFieldId)}

View File

@@ -80,8 +80,8 @@ export function MasterFieldTab({
</div>
) : (
<div className="space-y-2">
{itemMasterFields.map((field) => (
<div key={field.id} className="flex items-center justify-between p-4 border rounded hover:bg-gray-50 transition-colors">
{itemMasterFields.map((field, index) => (
<div key={`masterfield-${field.id}-${index}`} className="flex items-center justify-between p-4 border rounded hover:bg-gray-50 transition-colors">
<div className="flex-1">
<div className="flex items-center gap-2">
<span>{field.field_name}</span>

View File

@@ -240,9 +240,9 @@ export function SectionsTab({
</div>
) : (
<div className="space-y-2">
{template.fields.map((field, _index) => (
{template.fields.map((field, index) => (
<div
key={field.id}
key={`${template.id}-${field.id}-${index}`}
className="flex items-center justify-between p-3 border rounded hover:bg-gray-50 transition-colors"
>
<div className="flex-1">