- Updated the outbound and outsourcing outbound controllers to replace `source_type` with `source_table` for improved clarity and consistency in data handling. - Enhanced the work instruction controller to include automatic migration for the `work_instruction_info` table, allowing for better management of work instruction notes. - Implemented new logic to handle material input types in the work instruction detail modal, supporting both automatic and manual input methods. - Added new routes for retrieving work instruction information, facilitating better data retrieval for editing purposes. (TASK: ERP-node-095, ERP-node-096)
83 lines
2.9 KiB
TypeScript
83 lines
2.9 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* 작업지시 인포(메모) 입력 섹션 (TASK:ERP-node-095)
|
|
*
|
|
* 작업지시 1건당 안내사항(인포)을 한 줄씩 여러 건 추가/삭제한다.
|
|
* 등록된 인포는 POP(생산현장) 화면 상단에 표시될 예정 — 등록·저장만 본 컴포넌트 담당.
|
|
* 작업지시 등록 모달 / 수정 모달 양쪽에서 공용으로 사용한다.
|
|
*/
|
|
|
|
import { Input } from "@/components/ui/input";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Plus, X } from "lucide-react";
|
|
|
|
interface WorkInstructionInfoSectionProps {
|
|
/** 인포 내용 배열 (빈 문자열 행 허용 — 저장 시 호출부에서 trim/필터) */
|
|
infos: string[];
|
|
/** 변경 콜백 */
|
|
onChange: (next: string[]) => void;
|
|
}
|
|
|
|
export function WorkInstructionInfoSection({ infos, onChange }: WorkInstructionInfoSectionProps) {
|
|
const updateAt = (idx: number, value: string) => {
|
|
onChange(infos.map((v, i) => (i === idx ? value : v)));
|
|
};
|
|
const removeAt = (idx: number) => {
|
|
onChange(infos.filter((_, i) => i !== idx));
|
|
};
|
|
const add = () => {
|
|
onChange([...infos, ""]);
|
|
};
|
|
|
|
return (
|
|
<div className="bg-muted/30 rounded-lg border p-5">
|
|
<div className="flex items-center justify-between border-b pb-2">
|
|
<h4 className="text-foreground text-[13px] font-bold">인포 (POP 상단 표시)</h4>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
size="sm"
|
|
className="h-7 gap-1 text-[11px]"
|
|
onClick={add}
|
|
>
|
|
<Plus className="h-3 w-3" /> 인포 추가
|
|
</Button>
|
|
</div>
|
|
<p className="text-muted-foreground mt-2 text-[11px]">
|
|
작업지시별 안내사항을 입력하면 POP 화면 상단에 표시됩니다. 여러 건 등록할 수 있습니다.
|
|
</p>
|
|
<div className="mt-3 space-y-2">
|
|
{infos.length === 0 ? (
|
|
<p className="text-muted-foreground text-[12px]">
|
|
등록된 인포가 없습니다. '인포 추가' 버튼으로 입력하세요.
|
|
</p>
|
|
) : (
|
|
infos.map((info, idx) => (
|
|
<div key={idx} className="flex items-center gap-2">
|
|
<span className="text-muted-foreground w-5 shrink-0 text-center font-mono text-[11px]">
|
|
{idx + 1}
|
|
</span>
|
|
<Input
|
|
value={info}
|
|
onChange={(e) => updateAt(idx, e.target.value)}
|
|
className="h-9 flex-1"
|
|
placeholder="인포 내용을 입력하세요"
|
|
/>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
className="text-muted-foreground hover:text-destructive h-8 w-8 shrink-0"
|
|
onClick={() => removeAt(idx)}
|
|
>
|
|
<X className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|