feat: 전자결재 시스템 구현 (기안함, 결재함, 참조함, 문서상세)
- 기안함(DraftBox): 문서 목록, 상신/삭제, 문서작성 연결 - 결재함(ApprovalBox): 결재 대기 문서 목록, 문서상세 모달 연결 - 참조함(ReferenceBox): 참조 문서 목록, 열람/미열람 처리 - 문서작성(DocumentCreate): 품의서, 지출결의서, 지출예상내역서 폼 - 문서상세(DocumentDetail): 공유 모달, 결재선 박스, 3종 문서 뷰어 - 테이블 번호 컬럼 추가 (1번부터 시작) - sonner toast 적용 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
94
src/components/approval/DocumentCreate/ReferenceSection.tsx
Normal file
94
src/components/approval/DocumentCreate/ReferenceSection.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
'use client';
|
||||
|
||||
import { Plus, X } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import type { ApprovalPerson } from './types';
|
||||
import { MOCK_EMPLOYEES } from './types';
|
||||
|
||||
interface ReferenceSectionProps {
|
||||
data: ApprovalPerson[];
|
||||
onChange: (data: ApprovalPerson[]) => void;
|
||||
}
|
||||
|
||||
export function ReferenceSection({ data, onChange }: ReferenceSectionProps) {
|
||||
const handleAdd = () => {
|
||||
const newPerson: ApprovalPerson = {
|
||||
id: `temp-${Date.now()}`,
|
||||
department: '',
|
||||
position: '',
|
||||
name: '',
|
||||
};
|
||||
onChange([...data, newPerson]);
|
||||
};
|
||||
|
||||
const handleRemove = (index: number) => {
|
||||
onChange(data.filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
const handleChange = (index: number, employeeId: string) => {
|
||||
const employee = MOCK_EMPLOYEES.find((e) => e.id === employeeId);
|
||||
if (employee) {
|
||||
const newData = [...data];
|
||||
newData[index] = { ...employee };
|
||||
onChange(newData);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-lg border p-6">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-lg font-semibold">참조</h3>
|
||||
<Button variant="outline" size="sm" onClick={handleAdd}>
|
||||
<Plus className="w-4 h-4 mr-1" />
|
||||
추가
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm text-gray-500 mb-2">부서 / 직책 / 이름</div>
|
||||
|
||||
{data.length === 0 ? (
|
||||
<div className="text-center py-4 text-gray-400">
|
||||
참조자를 추가해주세요
|
||||
</div>
|
||||
) : (
|
||||
data.map((person, index) => (
|
||||
<div key={person.id} className="flex items-center gap-2">
|
||||
<span className="w-8 text-center text-sm text-gray-500">{index + 1}</span>
|
||||
<Select
|
||||
value={person.id.startsWith('temp-') ? '' : person.id}
|
||||
onValueChange={(value) => handleChange(index, value)}
|
||||
>
|
||||
<SelectTrigger className="flex-1">
|
||||
<SelectValue placeholder="부서명 / 직책명 / 이름 ▼" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{MOCK_EMPLOYEES.map((employee) => (
|
||||
<SelectItem key={employee.id} value={employee.id}>
|
||||
{employee.department} / {employee.position} / {employee.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-9 w-9 text-red-500 hover:text-red-700 hover:bg-red-50"
|
||||
onClick={() => handleRemove(index)}
|
||||
>
|
||||
<X className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user