Đăng Nhập Hệ Thống

Sử dụng tài khoản được cấp bởi Quản trị viên

', '' ].join('\n'); } function assembleHostingerFrontendFilesArray(rawFilesMap, gasWebAppUrl) { var indexTpl = rawFilesMap['Index.html'] || ''; var viewDash = rawFilesMap['View_Dashboard_Admin.html'] || ''; var viewHc = rawFilesMap['View_HanhChinh.html'] || ''; var viewKt = rawFilesMap['View_KeToan.html'] || ''; var jsCtrl = rawFilesMap['JS_Controller.html'] || ''; // Gộp toàn bộ các thẻ <?!= include('...'); ?> thành 1 file index.html hoàn chỉnh chạy độc lập trên Hostinger var mergedHtml = indexTpl .replace(/<\?!=\s*include\(\s*['"]View_Dashboard_Admin['"]\s*\);\s*\?>/g, function() { return viewDash; }) .replace(/<\?!=\s*include\(\s*['"]View_HanhChinh['"]\s*\);\s*\?>/g, function() { return viewHc; }) .replace(/<\?!=\s*include\(\s*['"]View_KeToan['"]\s*\);\s*\?>/g, function() { return viewKt; }) .replace(/<\?!=\s*include\(\s*['"]JS_Controller['"]\s*\);\s*\?>/g, function() { return jsCtrl; }); var headBridgeScript = buildStandaloneHostingerBridgeHeadScript(gasWebAppUrl); if (mergedHtml.indexOf('') !== -1) { mergedHtml = mergedHtml.replace('', headBridgeScript + '\n'); } else { mergedHtml = headBridgeScript + '\n' + mergedHtml; } var nowStr = formatDateTimeVN(new Date().toISOString()); var configJsContent = [ '/**', ' * CẤU HÌNH TỰ ĐỘNG KẾT NỐI HOSTINGER <-> GOOGLE APPS SCRIPT BACKEND', ' * Hệ thống Quản trị Doanh nghiệp Toàn diện ERP v4.0 - An Ninh Việt Nam', ' * Đóng gói tự động lúc: ' + nowStr, ' * Không cần chỉnh sửa bất kỳ thông số nào - Giải nén lên Hostinger là dùng ngay!', ' */', 'window.__ERP_HOSTINGER_CONFIG__ = {', ' GAS_WEB_APP_URL: ' + JSON.stringify(String(gasWebAppUrl || '').trim()) + ',', ' PARALLEL_MODE: true,', ' GENERATED_AT: ' + JSON.stringify(nowStr), '};', '' ].join('\n'); var htaccessContent = [ '# Cấu hình chuẩn Hostinger cho Hệ thống ERP v4.0 - An Ninh Việt Nam', 'DirectoryIndex index.html', 'AddDefaultCharset UTF-8', '', '', ' RewriteEngine On', ' RewriteBase /', ' RewriteCond %{REQUEST_FILENAME} !-f', ' RewriteCond %{REQUEST_FILENAME} !-d', ' RewriteRule . /index.html [L]', '', '', '', ' Header set Access-Control-Allow-Origin "*"', '', '' ].join('\n'); var readmeContent = [ '================================================================================', ' BỘ CÀI ĐẶT FRONTEND HOSTINGER (CHẠY SONG SONG VỚI GOOGLE APPS SCRIPT)', ' HỆ THỐNG QUẢN TRỊ DOANH NGHIỆP TOÀN DIỆN ERP v4.0 - AN NINH VIỆT NAM', '================================================================================', '', '1. TRẠNG THÁI CẤU HÌNH TỰ ĐỘNG:', ' - URL Backend Google Apps Script đã được nhúng tự động vào bộ cài:', ' ' + (gasWebAppUrl || '(Chưa có URL GAS)'), ' - Thời điểm đóng gói: ' + nowStr, ' - Tương thích 100%: Không cần cấu hình hay sửa code bất kỳ điều gì.', '', '2. CÁCH ĐƯA LÊN HOSTINGER (CHỈ MẤT 30 GIÂY):', ' - Bước 1: Đăng nhập vào hPanel của Hostinger -> mở "Trình quản lý tệp" (File Manager).', ' - Bước 2: Mở thư mục gốc của tên miền (thường là thư mục public_html).', ' - Bước 3: Tải file nén này lên hoặc giải nén toàn bộ các file bên trong', ' (index.html, config.js, .htaccess) trực tiếp vào trong public_html.', ' - Bước 4: Mở ngay tên miền Hostinger của anh để sử dụng!', '', '3. CƠ CHẾ CHẠY SONG SONG:', ' - Dữ liệu nhập/sửa/xóa trên Hostinger và trên Google Apps Script dùng chung', ' 100% cùng một Backend Google Apps Script & Google Sheets theo thời gian thực.', '================================================================================', '' ].join('\n'); return [ { name: 'index.html', content: mergedHtml }, { name: 'config.js', content: configJsContent }, { name: '.htaccess', content: htaccessContent }, { name: 'HUONG_DAN_UP_HOSTINGER.txt', content: readmeContent } ]; } function finalizeAndTriggerHostingerZipDownload(rawFilesMap, gasWebAppUrl) { showUploadProgressUI( 'Đang Đóng Gói Bộ Cài Hostinger (.ZIP)...', 85, 'Đang nhúng sẵn URL Backend GAS & nén thành file .ZIP tương thích Hostinger...', gasWebAppUrl || 'Chạy song song GAS + Hostinger' ); var hostingerFiles = assembleHostingerFrontendFilesArray(rawFilesMap, gasWebAppUrl); var zipBlob = buildErpZipArchiveBlob(hostingerFiles); var zipUrl = URL.createObjectURL(zipBlob); var a = document.createElement('a'); a.href = zipUrl; a.download = 'Bo_Cai_Hostinger_ERP_v4_AnNinhVietNam.zip'; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(function() { URL.revokeObjectURL(zipUrl); }, 2500); setTimeout(function() { showUploadProgressUI( 'Đang Đóng Gói Bộ Cài Hostinger (.ZIP)...', 100, 'Đã tải xuống bộ cài Hostinger (.ZIP) thành công! Giải nén lên public_html là dùng được ngay.', 'Hoàn tất 100%' ); hideUploadProgressUI(500); showToast('Đã tải xuống Bo_Cai_Hostinger_ERP_v4_AnNinhVietNam.zip (Đã gắn sẵn URL Backend GAS — giải nén up lên Hostinger là dùng ngay)!', 'success'); }, 350); } function downloadHostingerFrontendBundleZip() { var inp = document.getElementById('cfg_gas_webapp_url'); var gasUrl = (inp && inp.value && inp.value.trim()) ? inp.value.trim() : detectGasWebAppUrlFromEnvironment(); if (gasUrl && inp && !inp.value) { inp.value = gasUrl; } showUploadProgressUI( 'Đang Đóng Gói Bộ Cài Hostinger (.ZIP)...', 20, 'Đang trích xuất toàn bộ giao diện Frontend & tự động gắn URL Google Apps Script...', gasUrl || 'Đang kiểm tra URL Google Apps Script...' ); // Ưu tiên lấy trực tiếp 5 file HTML từ Server Google Apps Script (hàm getHostingerFrontendBundlePayload) if (window.google && window.google.script && window.google.script.run) { window.google.script.run .withSuccessHandler(function(res) { if (res && res.success && res.files && res.files['Index.html']) { var finalGasUrl = (res.gasWebAppUrl && String(res.gasWebAppUrl).trim()) || gasUrl || detectGasWebAppUrlFromEnvironment(); if (finalGasUrl) { APP_DATA.gasWebAppUrl = finalGasUrl; if (inp) inp.value = finalGasUrl; try { localStorage.setItem('ERP_GAS_WEBAPP_URL', finalGasUrl); } catch (e) {} syncDetectedGasWebAppUrlState(); } finalizeAndTriggerHostingerZipDownload(res.files, finalGasUrl); } else { fallbackCollectFrontendFilesAndDownloadHostingerZip(gasUrl); } }) .withFailureHandler(function() { fallbackCollectFrontendFilesAndDownloadHostingerZip(gasUrl); }) .getHostingerFrontendBundlePayload(gasUrl); return; } fallbackCollectFrontendFilesAndDownloadHostingerZip(gasUrl); } function fallbackCollectFrontendFilesAndDownloadHostingerZip(gasUrl) { var htmlFileNames = [ 'Index.html', 'View_Dashboard_Admin.html', 'View_HanhChinh.html', 'View_KeToan.html', 'JS_Controller.html' ]; var memMap = window.__ERP_SOURCE_FILES_CONTENT__ || {}; var promises = htmlFileNames.map(function(fName) { if (memMap[fName]) { return Promise.resolve({ name: fName, content: memMap[fName] }); } return fetch('/erp_build/' + fName) .then(function(r) { return r.ok ? r.text() : ''; }) .then(function(txt) { return { name: fName, content: txt }; }) .catch(function() { return { name: fName, content: '' }; }); }); Promise.all(promises).then(function(list) { var map = {}; list.forEach(function(item) { map[item.name] = item.content || ''; }); finalizeAndTriggerHostingerZipDownload(map, gasUrl || detectGasWebAppUrlFromEnvironment()); }); } setTimeout(syncDetectedGasWebAppUrlState, 600);