Tất cả
Đang mở
Đã rút
Quá hạn
Vàng + Đỏ
Chỉ vàng
Chỉ đỏ
// ==================== MAPPING VỊ TRÍ ====================
const locationMap = {
"Văn phòng": ["VP-01 (Kế toán)", "VP-02 (Nhân sự)", "VP-03 (Giám đốc)", "VP-04 (Sảnh)"],
"Xưởng A": ["XA-L01", "XA-L02", "XA-L03", "XA-KTC"],
"Xưởng B": ["XB-May01", "XB-May02", "XB-May03", "XB-HoanThien"],
"Kho": ["KHO-NL", "KHO-TP", "KHO-PHELIEU"],
"Nhà ăn": ["NA-01 (Bếp)", "NA-02 (Khu ngồi)", "NA-03 (Rửa bát)"],
"Bên ngoài": ["BN-01 (Bãi xe)", "BN-02 (Cổng)", "BN-03 (Vườn)"]
};function updateLocations() {
let area = document.getElementById('area').value;
let locSelect = document.getElementById('locationCode');
let locations = locationMap[area] || [];locSelect.innerHTML = locations.map(l => `${l}`).join('');
}// ==================== XỬ LÝ ẢNH ====================
let currentImageData = '';function previewImage(input) {
const file = input.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function (e) {
currentImageData = e.target.result;
const preview = document.getElementById('imagePreview');
preview.style.backgroundImage = `url(${currentImageData})`;
preview.style.display = 'block';
}
reader.readAsDataURL(file);
}
}// ==================== DỮ LIỆU ====================
let tags = JSON.parse(localStorage.getItem('6s_tags')) || [];function save() {
localStorage.setItem('6s_tags', JSON.stringify(tags));
updateDashboard();
}// Auto lấy tên người dùng
(function () {
let saved = localStorage.getItem('6s_user');
if (saved) document.getElementById('discoverer').value = saved;
})();// ==================== SINH MÃ THẺ ====================
function sinhMa(type) {
let prefix = type === 'Vàng' ? 'Y' : 'R';
let year = new Date().getFullYear();
let so = tags.filter(t => t.ma.startsWith(prefix + '-' + year)).length + 1;
return prefix + '-' + year + '-' + String(so).padStart(5, '0');
}// ==================== TREO THẺ ====================
function onTypeChange() {
let type = document.querySelector('input[name="tagType"]:checked').value;
let btn = document.getElementById('btnTreo');
let hint = document.getElementById('sHint');
let sSelectVang = document.getElementById('sSelectVang');
let sSelectDo = document.getElementById('sSelectDo');if (type === 'Vàng') {
btn.className = 'btn btn-vang';
btn.textContent = '🏷️ TẠO THẺ VÀNG';// Hiển thị S1-S5, ẩn S6
sSelectVang.style.display = 'block';
sSelectDo.style.display = 'none';
hint.textContent = '✅ Chọn S1 đến S5 cho thẻ Vàng và khắc phục điểm bất thường trong thời hạn 1 tuần';
hint.style.color = '#1565c0';
} else { // Thẻ Đỏ
btn.className = 'btn btn-do';
btn.textContent = '🏷️ TẠO THẺ ĐỎ';// Hiển thị S6, ẩn S1-S5
sSelectVang.style.display = 'none';
sSelectDo.style.display = 'block'; // S6 luôn hiện khi là thẻ Đỏ
hint.textContent = '🔴 Thẻ Đỏ mặc định là S6 - An toàn phải tiến hành khắc phục “NGAY” sau khi phát hiện';
hint.style.color = '#d32f2f';
}
}function onSChange() { /* Không cần xử lý gì ở đây nữa */ }function treoThe() {
let type = document.querySelector('input[name="tagType"]:checked').value;
let area = document.getElementById('area').value;
let loc = document.getElementById('locationCode').value.trim();
let desc = document.getElementById('description').value.trim();
let disc = document.getElementById('discoverer').value.trim();if (!loc) { toast('Nhập mã vị trí!'); return; }
if (!desc) { toast('Nhập mô tả!'); return; }
if (!disc) { toast('Nhập tên người phát hiện!'); return; }// Lấy S đã chọn
let sValue = '';
if (type === 'Vàng') {
sValue = document.getElementById('sSelectVang').value;
} else { // Thẻ Đỏ
sValue = 'S6'; // Luôn là S6
}let sList = [sValue]; // Đưa vào mảng để đồng bộ với cấu trúc tag// Kiểm tra logic: thẻ vàng không được chứa S6, thẻ đỏ chỉ được S6 (đã xử lý ở onTypeChange)
// if (type === 'Vàng' && sList.includes('S6')) { toast('Lỗi: Thẻ Vàng không thể chọn S6 - An toàn!'); return;}
// if (type === 'Đỏ' && (sList.length !== 1 || !sList.includes('S6'))) { toast('Lỗi: Thẻ Đỏ chỉ được chọn S6 - An toàn!'); return;}let ma = sinhMa(type);
let now = new Date();
let tag = {
ma: ma,
type: type,
area: area,
location: loc,
description: desc,
discoverer: disc,
sList: sList,
beforeImage: currentImageData,
status: 'open', // open | closed
createdAt: now.toISOString(),
closedAt: null,
solution: '',
afterImage: '',
reviewer: '',
reviewResult: ''
};tags.unshift(tag);
save();
localStorage.setItem('6s_user', disc);// Reset form
document.getElementById('description').value = '';
currentImageData = '';
document.getElementById('imagePreview').style.display = 'none';
document.getElementById('fileInput').value = '';
updateLocations(); // Reset vị trí về option đầu tiên// Hiển thị kết quả
hienThiTheMoi(tag);
renderList();
}function hienThiTheMoi(tag) {
let overlay = document.getElementById('modalOverlay');
let content = document.getElementById('modalContent');
let icon = tag.type === 'Vàng' ? '🟡' : '🔴';
let color = tag.type === 'Vàng' ? 'vang' : 'do';content.innerHTML = `
${icon} ${tag.ma}
${tag.ma}
Vị trí: ${tag.location}
Khu vực: ${tag.area}
Mô tả: ${tag.description}
Ngày treo: ${formatDate(tag.createdAt)}
Người treo: ${tag.discoverer}
Phân loại: ${tag.sList.join(', ')}
📱
QR Code sẽ hiện ở bản sau
💡 Chọn "In thẻ" để in giấy A6 treo tại hiện trường
`;
overlay.style.display = 'flex';
}function closeModal() {
document.getElementById('modalOverlay').style.display = 'none';
}// Click overlay to close
document.getElementById('modalOverlay').onclick = function (e) {
if (e.target === this) closeModal();
};// ==================== DANH SÁCH THẺ ====================
function renderList() {
let filterStatus = document.getElementById('filterStatus').value;
let filterType = document.getElementById('filterType').value;
let list = document.getElementById('tagList');let filtered = tags.filter(t => {
if (filterType !== 'all' && t.type !== filterType) return false;
if (filterStatus === 'open' && t.status !== 'open') return false;
if (filterStatus === 'closed' && t.status !== 'closed') return false;
if (filterStatus === 'quahan' && !isQuaHan(t)) return false;
return true;
});if (filtered.length === 0) {
list.innerHTML = '
📭 Chưa có thẻ nào
';
return;
}list.innerHTML = filtered.map(t => {
let isVang = t.type === 'Vàng';
let color = isVang ? 'vang' : 'do';
let badge = t.status === 'open' ? 'Đang xử lý' : 'Đã rút';
let qh = isQuaHan(t) ? ' ⚠️ Quá hạn' : '';return `
${t.ma} ${badge}${qh}
${t.description}
${t.location} · ${t.area} · ${t.sList.join(', ')}
${formatDate(t.createdAt)} · ${t.discoverer}
${t.status === 'open' ? `` : ''}
`;
}).join('');
}// ==================== XỬ LÝ / RÚT THẺ ====================
function moKhacPhuc(ma) {
let t = tags.find(x => x.ma === ma);
if (!t) return;
let overlay = document.getElementById('modalOverlay');
let content = document.getElementById('modalContent');content.innerHTML = `
🔧 Xử lý thẻ ${ma}
Mô tả: ${t.description}
Vị trí: ${t.location}
`;
overlay.style.display = 'flex';
}function thucHienRutThe(ma) {
let t = tags.find(x => x.ma === ma);
if (!t) return;let solution = document.getElementById('editSolution').value.trim();
let result = document.querySelector('input[name="reviewResult"]:checked');
let reviewer = document.getElementById('editReviewer').value.trim();if (!solution) { toast('Nhập biện pháp khắc phục!'); return; }
if (!reviewer) { toast('Nhập tên người đánh giá!'); return; }
if (!result) { toast('Chọn kết quả OK hoặc NG!'); return; }t.solution = solution;
t.reviewer = reviewer;
t.reviewResult = result.value;if (result.value === 'OK') {
t.status = 'closed';
t.closedAt = new Date().toISOString();
toast('✅ Đã rút thẻ ' + ma);
} else {
toast('❌ Trả lại xử lý cho thẻ ' + ma);
}save();
closeModal();
renderList();
}function xemChiTiet(ma) {
let t = tags.find(x => x.ma === ma);
if (!t) return;
let overlay = document.getElementById('modalOverlay');
let content = document.getElementById('modalContent');let statusText = t.status === 'open' ? '🟡 Đang xử lý' : '✅ Đã rút';
let qh = isQuaHan(t) ? '