'use client'; import React, { useState, useEffect } from 'react'; import { FinishingService } from '@/types'; import { Scissors, Plus, Edit2, Trash2, X, RefreshCw } from 'lucide-react'; export const FinishingManager: React.FC = () => { const [services, setServices] = useState([]); const [loading, setLoading] = useState(true); const [editingService, setEditingService] = useState | null>(null); const [isModalOpen, setIsModalOpen] = useState(false); const fetchServices = async () => { try { setLoading(true); const res = await fetch('/api/finishing'); const data = await res.json(); if (Array.isArray(data)) setServices(data); } catch (err) { console.error(err); } finally { setLoading(false); } }; useEffect(() => { fetchServices(); }, []); const handleOpenAdd = () => { setEditingService({ code: `FIN_${Date.now().toString().slice(-4)}`, name: 'Dịch vụ gia công ', category: 'can_mang', calcType: 'per_product', unitPrice: 150, minPrice: 50000, setupFee: 0, wastePercent: 1.0, wasteSheets: 10, isActive: true, }); setIsModalOpen(true); }; const handleOpenEdit = (s: FinishingService) => { setEditingService({ ...s }); setIsModalOpen(true); }; const handleSave = async (e: React.FormEvent) => { e.preventDefault(); if (!editingService) return; const isUpdate = Boolean(editingService.id); const method = isUpdate ? 'PUT' : 'POST'; try { const res = await fetch('/api/finishing', { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(editingService), }); if (res.ok) { setIsModalOpen(false); setEditingService(null); fetchServices(); } } catch (err) { console.error(err); } }; const handleDelete = async (id: number) => { if (!confirm('Bạn có chắc chắn muốn xóa dịch vụ gia công này?')) return; try { const res = await fetch(`/api/finishing?id=${id}`, { method: 'DELETE' }); if (res.ok) fetchServices(); } catch (err) { console.error(err); } }; return (

Bảng Giá Gia Công Sau In (Post-Press)

Cán màng, cấn, bế demi/đứt, ép kim, dập nổi, UV định hình, đóng ghim, dán hộp...

{loading ? ( ) : ( services.map((s) => ( )) )}
Tên Công Đoạn Phân Loại Cách Tính Đơn Giá Mở Máy Min Tiền Khuôn Bù Hao Thao Tác
Đang tải dữ liệu gia công...
{s.name} {s.category} {s.calcType === 'per_m2' ? 'Theo m²' : s.calcType === 'die_cut' ? 'Khuôn + Công bế' : s.calcType === 'per_sheet' ? 'Theo tờ in' : s.calcType === 'fixed' ? 'Cố định' : 'Theo cái'} {s.unitPrice.toLocaleString('vi-VN')}đ {s.minPrice > 0 ? `${s.minPrice.toLocaleString('vi-VN')}đ` : '-'} {s.setupFee > 0 ? `${s.setupFee.toLocaleString('vi-VN')}đ` : '-'} +{s.wastePercent}% ({s.wasteSheets} tờ)
{/* Modal Thêm/Sửa */} {isModalOpen && editingService && (

{editingService.id ? 'Cập Nhật Công Đoạn Gia Công' : 'Thêm Mới Công Đoạn'}

setEditingService({ ...editingService, name: e.target.value })} className="w-full border border-slate-300 rounded-lg p-2 focus:ring-1 focus:ring-blue-500" />
setEditingService({ ...editingService, unitPrice: Number(e.target.value) })} className="w-full border border-slate-300 rounded-lg p-2 focus:ring-1 focus:ring-blue-500" />
setEditingService({ ...editingService, minPrice: Number(e.target.value) })} className="w-full border border-slate-300 rounded-lg p-2 focus:ring-1 focus:ring-blue-500" />
setEditingService({ ...editingService, setupFee: Number(e.target.value) })} className="w-full border border-slate-300 rounded-lg p-2 focus:ring-1 focus:ring-blue-500" />
setEditingService({ ...editingService, wastePercent: Number(e.target.value) })} className="w-full border border-slate-300 rounded-lg p-2 focus:ring-1 focus:ring-blue-500" />
setEditingService({ ...editingService, wasteSheets: Number(e.target.value) })} className="w-full border border-slate-300 rounded-lg p-2 focus:ring-1 focus:ring-blue-500" />
)}
); };