'use client'; import React, { useState, useEffect } from 'react'; import { DigitalMachine, DigitalPrintGiaCong, DigitalPrintKemGiay, OffsetMachine } from '@/types'; import { Cpu, Printer, Edit2, Check, RefreshCw, Layers, FileText, Info, Save, X } from 'lucide-react'; export const MachineManager: React.FC = () => { const [activeTab, setActiveTab] = useState<'giacong' | 'kem_giay' | 'offset'>('giacong'); const [offsetMachines, setOffsetMachines] = useState([]); const [digitalMachines, setDigitalMachines] = useState([]); const [digitalPricingGiaCong, setDigitalPricingGiaCong] = useState([]); const [digitalPricingKemGiay, setDigitalPricingKemGiay] = useState([]); const [loading, setLoading] = useState(true); // Editing state const [editingOffset, setEditingOffset] = useState(null); const [editingGiaCong, setEditingGiaCong] = useState(null); const [editingKemGiay, setEditingKemGiay] = useState(null); // Filter for INTC paper const [paperFilter, setPaperFilter] = useState<'all' | 'C' | 'I' | 'F'>('all'); const fetchMachines = async () => { try { setLoading(true); const res = await fetch('/api/machines'); const data = await res.json(); if (data.offsetMachines) setOffsetMachines(data.offsetMachines); if (data.digitalMachines) setDigitalMachines(data.digitalMachines); if (data.digitalPricingGiaCong) setDigitalPricingGiaCong(data.digitalPricingGiaCong); if (data.digitalPricingKemGiay) setDigitalPricingKemGiay(data.digitalPricingKemGiay); } catch (err) { console.error(err); } finally { setLoading(false); } }; useEffect(() => { fetchMachines(); }, []); const handleSaveOffset = async (m: OffsetMachine) => { try { const res = await fetch('/api/machines', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'offset', ...m }), }); if (res.ok) { setEditingOffset(null); fetchMachines(); } } catch (err) { console.error(err); } }; const handleSaveGiaCong = async (item: DigitalPrintGiaCong) => { try { const res = await fetch('/api/machines', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'digital_giacong', ...item }), }); if (res.ok) { setEditingGiaCong(null); fetchMachines(); } } catch (err) { console.error(err); } }; const handleSaveKemGiay = async (item: DigitalPrintKemGiay) => { try { const res = await fetch('/api/machines', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'digital_kem_giay', ...item }), }); if (res.ok) { setEditingKemGiay(null); fetchMachines(); } } catch (err) { console.error(err); } }; const filteredKemGiay = digitalPricingKemGiay.filter((item) => { if (paperFilter === 'all') return true; if (paperFilter === 'C') return item.paperCode.startsWith('C'); if (paperFilter === 'I') return item.paperCode.startsWith('I'); if (paperFilter === 'F') return item.paperCode.startsWith('F'); return true; }); return (
{/* Top Header & Navigation Tabs */}

Quản Lý Bảng Giá In Ấn

Cập nhật biểu giá In nhanh gia công (Konica C12000), In nhanh kèm giấy (INTC) và Máy in Offset

{/* TAB 1: BẢNG GIÁ IN GIA CÔNG KONICA C12000 (TRANG 2 PDF 26.02.2026) */} {activeTab === 'giacong' && (
Trang 2 PDF 26.02.2026

MÁY IN KONICA MINOLTA C12000 / C12010S 5 MÀU

Đơn giá in gia công (chưa gồm giấy) theo 5 kích thước tiêu chuẩn & 7 nhóm chất liệu.

{/* Quy tắc phụ phí & lưu ý */}
Phụ phí số lượng ít: < 50 tờ: +30.000đ | < 100 tờ: +20.000đ | ≥ 100 tờ: Miễn phí
Quy ước tính mặt in: Đơn giá hiển thị dưới đây là đơn giá in 1 mặt. In 2 mặt được tính nhân đôi (×2).
{digitalPricingGiaCong.map((row) => { const isEditing = editingGiaCong?.id === row.id; const cur = isEditing ? editingGiaCong : row; return ( {/* Giấy <249gsm */} {/* Giấy 250-349gsm */} {/* Giấy 350-450gsm */} {/* Decal giấy nhựa */} {/* Decal trong */} {/* Giấy nhựa <280 */} {/* Nhựa PVC */} {/* Nút hành động */} ); })}
Khổ in Giấy <249gsm Giấy 250-349gsm Giấy 350-450gsm Decal (Giấy-nhựa) Decal trong Giấy nhựa <280gsm Nhựa PVC Thao tác
{row.sheetSize} {row.widthMm} × {row.heightMm} mm {isEditing ? ( setEditingGiaCong({ ...cur, paperLt249: Number(e.target.value) })} /> ) : ( {row.paperLt249.toLocaleString('vi-VN')}đ )} {isEditing ? ( setEditingGiaCong({ ...cur, paper250To349: Number(e.target.value) })} /> ) : ( {row.paper250To349.toLocaleString('vi-VN')}đ )} {isEditing ? ( setEditingGiaCong({ ...cur, paper350To450: Number(e.target.value) })} /> ) : ( {row.paper350To450.toLocaleString('vi-VN')}đ )} {isEditing ? ( setEditingGiaCong({ ...cur, decalPaperPlastic: Number(e.target.value) })} /> ) : ( {row.decalPaperPlastic.toLocaleString('vi-VN')}đ )} {isEditing ? ( setEditingGiaCong({ ...cur, decalClear: Number(e.target.value) })} /> ) : ( {row.decalClear.toLocaleString('vi-VN')}đ )} {isEditing ? ( setEditingGiaCong({ ...cur, syntheticPaper: Number(e.target.value) })} /> ) : ( {row.syntheticPaper.toLocaleString('vi-VN')}đ )} {isEditing ? ( setEditingGiaCong({ ...cur, pvcPlastic: Number(e.target.value) })} /> ) : ( {row.pvcPlastic > 0 ? `${row.pvcPlastic.toLocaleString('vi-VN')}đ` : '—'} )} {isEditing ? (
) : ( )}
)} {/* TAB 2: BẢNG GIÁ IN NHANH KÈM GIẤY INTC (PDF 14.03.2026) */} {activeTab === 'kem_giay' && (
Bảng Giá INTC 14.03.2026

BẢNG GIÁ IN NHANH KÈM GIẤY (TRỌN GÓI)

Đơn giá trọn gói đã bao gồm tiền giấy và công in. Khổ in 325 × 430 mm và 325 × 355 mm.

{/* Bộ lọc loại giấy */}
{/* Phụ phí */}
Quy định phụ phí số lượng ít: Số lượng < 50 tờ: +30.000đ | < 100 tờ: +20.000đ | ≥ 100 tờ: Miễn phí phụ phí
{filteredKemGiay.map((row) => { const isEditing = editingKemGiay?.id === row.id; const cur = isEditing ? editingKemGiay : row; return ( {/* Đơn giá 1 mặt */} {/* Đơn giá 2 mặt */} {/* Nút thao tác */} ); })}
Mã Chất liệu & Định lượng Khổ in In 1 mặt (+ Giấy) In 2 mặt (+ Giấy) Thao tác
{row.paperCode} {row.paperName} Định lượng: {row.gsm} gsm {row.sheetSize} mm {isEditing ? ( setEditingKemGiay({ ...cur, price1Side: Number(e.target.value) })} /> ) : ( {row.price1Side.toLocaleString('vi-VN')}đ )} {isEditing ? ( setEditingKemGiay({ ...cur, price2Side: Number(e.target.value) })} /> ) : ( {row.price2Side.toLocaleString('vi-VN')}đ )} {isEditing ? (
) : ( )}
)} {/* TAB 3: MÁY IN OFFSET */} {activeTab === 'offset' && (

Cấu Hình Máy In Offset & Gói In Trọn Gói Gồm Kẽm

Khổ 65 × 86 cm (bắt nhíp chiều 86): 1.200.000đ | Khổ nhỏ dưới 65 × 43 cm: 900.000đ (Dưới 3.000 lượt in đã bao gồm 4 kẽm)

{offsetMachines.map((m) => { const isEditing = editingOffset?.id === m.id; const current = isEditing ? editingOffset : m; return (
{current.name}
Khổ in max: {isEditing ? (
setEditingOffset({ ...current, maxWidthMm: Number(e.target.value) })} /> setEditingOffset({ ...current, maxHeightMm: Number(e.target.value) })} />
) : ( {current.maxWidthMm} × {current.maxHeightMm} mm )}
Giá kẽm CTP / lá: {isEditing ? ( setEditingOffset({ ...current, platePrice: Number(e.target.value) })} /> ) : ( {current.platePrice.toLocaleString('vi-VN')}đ )}
Mở máy (≤{current.baseImpressions || 3000} lượt): {isEditing ? ( setEditingOffset({ ...current, setupCost: Number(e.target.value) })} /> ) : (
{current.setupCost.toLocaleString('vi-VN')}đ {current.includesPlate && ( Đã gồm kẽm )}
)}
Lũy tiến / 1.000 lượt: {isEditing ? ( setEditingOffset({ ...current, stepCost: Number(e.target.value) })} /> ) : ( {current.stepCost.toLocaleString('vi-VN')}đ )}
Bù hao kẹp nhíp: {isEditing ? ( setEditingOffset({ ...current, gripperMarginMm: Number(e.target.value) })} /> ) : ( {current.gripperMarginMm || 10} mm )}
Bù hao giấy in: {isEditing ? ( setEditingOffset({ ...current, defaultWasteSheets: Number(e.target.value) })} /> ) : ( {current.defaultWasteSheets} tờ )}
{isEditing && (
)}
); })}
)}
); };