<form_P_MO / P_ROI> - <BSSPopup>
Mô tả
BSSPopup là component React dạng Drawer (panel trượt từ bên phải màn hình), thay thế cho cơ chế mở form popup cũ qua hàm JavaScript form_P_MO() và control <Cthuvien:roi>.
Điểm nổi bật của BSSPopup:
- Panel trượt (Drawer): Thay vì mở cửa sổ popup riêng biệt (window.open) như hệ thống cũ, BSSPopup hiển thị panel trượt vào từ cạnh phải, phủ lên giao diện chính mà không làm mất ngữ cảnh làm việc.
- Backdrop mờ: Khi mở, một lớp nền bán trong suốt (
bg-slate-900/40) có hiệu ứngbackdrop-blurphủ lên phía sau panel. Click vào backdrop sẽ đóng popup. - Khóa cuộn (Scroll Lock): Tự động khóa
document.body.style.overflow = 'hidden'khi mở để ngăn người dùng cuộn nội dung phía sau. Tự động gỡ bỏ khi đóng. - Phím tắt Esc: Đăng ký listener
keydowntrênwindowđể đóng nhanh bằng phímEscape. - Responsive: Hỗ trợ 5 kích thước (
sm,md,lg,xl,full) với breakpoint tự co giãn theo viewport (mobile sẽ tự mở gần full chiều rộng).
Thuộc tính
So sánh cơ chế cũ và mới
| Cơ chế Cũ | <BSSPopup> | Mô tả / Chú ý khi chuyển đổi |
|---|---|---|
form_P_MO(url, ...) | isOpen={true} | Cũ: Gọi hàm JS mở cửa sổ popup riêng. Mới: Đơn giản bật cờ state isOpen để hiện panel. |
P_ROI('dong#url#gui#ham#id#dtuong') | onClose + logic riêng | Cũ: Chuỗi tham số gộp phân cách #. Mới: Truyền dữ liệu qua props/callback React chuẩn, không cần encode chuỗi. |
<Cthuvien:roi f_tkhao="..."> | <BSSButton onClick={...}> | Cũ: Control nhãn liên kết tự gắn sự kiện mở form. Mới: Dùng BSSButton hoặc bất kỳ element nào kết hợp state useState. |
| Cửa sổ popup (window.open) | Drawer panel (CSS transform) | Cũ: Tab/cửa sổ trình duyệt riêng biệt. Mới: Panel nằm trong cùng trang, không bị trình duyệt chặn popup. |
Các thuộc tính của <BSSPopup>
| Tên | Kiểu | Mặc định | Có thể có | Mục đích |
|---|---|---|---|---|
isOpen | bool | true / false | Trạng thái mở/đóng. Điều khiển animation trượt vào/ra và hiển thị backdrop. | |
onClose | function | () => void | Callback đóng popup (kích hoạt khi click backdrop, nhấn Esc, hoặc click nút X). | |
title | string | Tiêu đề hiển thị trên header. Tự động dịch theo ngôn ngữ. | ||
children | ReactNode | Nội dung bên trong body (có thể là form, grid, hoặc bất kỳ component nào). | ||
size | string | 'md' | 'sm', 'md', 'lg', 'xl', 'full' | Kích thước (độ rộng) của panel. |
Kích thước (size)
| Giá trị | Chiều rộng Desktop | Chiều rộng Mobile | Mục đích sử dụng |
|---|---|---|---|
sm | 320px | calc(100vw - 16px) | Ghi chú ngắn, thông tin tóm tắt |
md | 500px | calc(100vw - 16px) | Tra cứu lịch sử, form đơn giản |
lg | 850px | calc(100vw - 16px) | Danh sách lưới dữ liệu |
xl | 1100px | calc(100vw - 16px) | Form nghiệp vụ lớn, nhiều trường |
full | 100vw | 100vw | Toàn màn hình (thay thế hoàn toàn view chính) |
Hoạt động phía Client
- Mở Drawer: Khi
isOpenchuyển từfalse→true, panel trượt vào từ phải bằng CSStranslate-x-0với animationease-out 300ms. Đồng thời backdrop mờ hiện ra. - Đóng Drawer: Có 3 cách đóng:
- Click nút
Xtrên header. - Click vào vùng backdrop mờ phía sau.
- Bấm phím
Escapetrên bàn phím.
- Click nút
- Scroll Lock: Khi mở,
document.body.style.overflow = 'hidden'ngăn cuộn trang chính. Khi đóng (hoặc unmount), tự động khôi phụcoverflow = 'unset'. - Header chuẩn ERP: Header có nền xanh đậm (
#001529), chữ trắng in hoa, thanh trang trí xanh dương nhỏ bên trái tiêu đề. Hỗ trợ Dark Mode (dark:bg-slate-800).
Ví dụ
1. Popup tra cứu danh sách (size lớn):
import { useState } from 'react';
import BSSPopup from '@/components/BSSPopup';
import { BSSButton } from '@/components/BSSButton';
export default function ExamplePage() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<BSSButton onClick={() => setIsOpen(true)}>Tra cứu nhân viên</BSSButton>
<BSSPopup
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="Tra cứu nhân viên"
size="lg"
>
{/* Nội dung bên trong: Grid, Form, hoặc bất kỳ component nào */}
<div>Danh sách nhân viên sẽ hiển thị ở đây...</div>
</BSSPopup>
</>
);
}
2. Popup form nhập liệu nghiệp vụ:
<BSSPopup
isOpen={showForm}
onClose={handleClose}
title="Thêm mới hợp đồng"
size="xl"
>
<div id="dt_ct">
<BSSInput label="Số hợp đồng" name="so_hd" value={data.so_hd} onChange={handleChange} />
<BSSCalendar label="Ngày ký" name="ngay_ky" value={data.ngay_ky} onChange={handleChange} />
<BSSLke label="Nhân viên" name="ma_nv" ktra="ns_nhanvien,ma,ten" value={data.ma_nv} onChange={handleChange} />
</div>
</BSSPopup>