Files
ewoooc/templates/system_settings.html
OoO 53edcc0077 refactor(templates): 統一模板目錄並移除 fallback loader
ADR-017 Phase 3f-4:根目錄模板搬入 templates/,補 trends/login_history,移除 ChoiceLoader 根目錄 fallback,搬移 components,刪除 web/templates 下的空檔/死檔與 compose 舊模板 mount。
2026-04-29 21:44:38 +08:00

342 lines
14 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>系統設定/匯入 - WOOO TECH</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
min-height: 100vh;
padding-top: 70px;
}
/* Custom Dark Navbar - 統一藍色漸層 */
.navbar.bg-custom-dark {
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%) !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.navbar.bg-custom-dark .navbar-brand {
color: #ffffff;
font-weight: 600;
}
.navbar.bg-custom-dark .navbar-nav .nav-link {
color: rgba(255, 255, 255, 0.85);
font-weight: 500;
transition: all 0.3s;
}
.navbar.bg-custom-dark .navbar-nav .nav-link:hover {
color: #ffffff;
background: rgba(255, 255, 255, 0.1);
border-radius: 6px;
}
.navbar.bg-custom-dark .navbar-nav .nav-link.active {
color: #ffffff;
background: rgba(255, 255, 255, 0.15);
border-radius: 6px;
font-weight: 600;
}
.navbar.bg-custom-dark .navbar-text {
color: rgba(255, 255, 255, 0.75);
}
.navbar {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.table-container {
background: white;
border-radius: .5rem;
box-shadow: 0 0 1px rgba(0, 0, 0, .125), 0 1px 3px rgba(0, 0, 0, .2);
padding: 1.25rem;
}
</style>
</head>
<body>
{% include 'components/_navbar.html' %}
<div class="container">
<div class="d-flex justify-content-between align-items-center mb-4 mt-4">
<h4 class="mb-0"><i class="fas fa-cogs me-2"></i>系統設定與資料匯入</h4>
</div>
<div class="table-container mb-4">
<h5 class="mb-3">系統維護</h5>
<div class="d-flex align-items-center justify-content-between">
<div>
<h6 class="fw-bold mb-1">完整備份</h6>
<p class="text-muted mb-0 small">將目前的系統程式碼與資料庫打包存檔 (目前版本: {{ system_version }})。</p>
</div>
<button class="btn btn-outline-secondary" onclick="triggerBackup()">
<i class="fas fa-file-archive me-2"></i>建立備份
</button>
</div>
</div>
<!-- ================= NEW: Monthly Summary Analysis Import ================= -->
<div class="table-container mb-4">
<h5 class="mb-3 text-primary"><i class="fas fa-file-import me-2"></i>月份總表數據分析匯入</h5>
<div class="p-4 border rounded bg-light border-primary border-opacity-25">
<div class="row align-items-center">
<div class="col-md-9">
<h6 class="fw-bold mb-1">月份業績匯總分析 (42 欄位版)</h6>
<p class="text-muted small mb-3">此功能專用於匯入「月份總表數據分析」Excel。系統會自動根據「年」與「月」欄位<strong
class="text-danger">覆蓋更新</strong>該月份之歷史數據,適合大批量資料 (如 8 萬筆+)。</p>
<input class="form-control" type="file" id="monthlySummaryFile" accept=".xlsx, .xls">
</div>
<div class="col-md-3 text-end">
<button class="btn btn-primary w-100 py-2 mt-3 mt-md-0 shadow-sm"
onclick="uploadMonthlySummary()">
<i class="fas fa-upload me-2"></i>執行大批量匯入
</button>
</div>
</div>
<div id="monthlyImportProgress" class="mt-3 d-none">
<div class="progress" style="height: 10px;">
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
style="width: 100%"></div>
</div>
<p class="text-center small text-primary mt-2 mb-0">資料處理中,請稍候...</p>
</div>
</div>
</div>
<!-- ================= OLD: Sales Report Import ================= -->
<div class="table-container mb-4">
<h5 class="mb-3"><i class="fas fa-file-invoice-dollar me-2"></i>即時業績(全月)匯入</h5>
<div class="p-4 border rounded bg-white">
<div class="row align-items-center">
<div class="col-md-9">
<h6 class="fw-bold mb-1">匯入即時業績 (全月版)</h6>
<p class="text-muted small mb-3">請上傳檔名包含「即時業績」且為「全月」版本之 Excel。資料將自動匯入至專屬分析明細表。</p>
<input class="form-control" type="file" id="salesReportFile" accept=".xlsx, .xls">
</div>
<div class="col-md-3 text-end">
<button class="btn btn-outline-primary w-100 py-2 mt-3 mt-md-0" onclick="uploadSalesReport()">
<i class="fas fa-upload me-2"></i>執行業績匯入
</button>
</div>
</div>
</div>
</div>
<!-- ================= CLARIFIED: Generic Import ================= -->
<div class="table-container mb-4">
<h5 class="mb-3">一般 Excel 匯入 (自動建表)</h5>
<div class="row align-items-end">
<div class="col-md-8">
<label for="excelFile" class="form-label text-muted small">選擇任何 Excel 檔 - 系統將依據檔名自動建立新資料表
(若表名重複將會覆蓋)</label>
<input class="form-control" type="file" id="excelFile" accept=".xlsx, .xls">
</div>
<div class="col-md-4 mt-3 mt-md-0">
<button class="btn btn-success w-100" onclick="uploadExcel()">
<i class="fas fa-table me-2"></i>匯入並建立通用資料表
</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Helper function to get CSRF token
function getCSRFToken() {
return document.querySelector('meta[name="csrf-token"]').getAttribute('content');
}
function triggerBackup() {
if (confirm('確定要執行系統完整備份嗎?\n這將會打包所有程式碼與資料庫檔案。')) {
fetch('/api/backup', {
method: 'POST',
headers: {
'X-CSRFToken': getCSRFToken()
}
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
alert(data.message);
if (data.download_url) {
window.location.href = data.download_url; // 自動觸發下載
}
} else {
alert('錯誤: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('備份請求失敗,請檢查日誌。');
});
}
}
function uploadSalesReport() {
const fileInput = document.getElementById('salesReportFile');
const file = fileInput.files[0];
if (!file) {
alert('請先選擇一個業績報表檔案');
return;
}
// 提醒使用者檔名規則
if (!file.name.includes('即時業績') || !file.name.includes('全月')) {
if (!confirm('檔案名稱似乎不符合「即時業績(全月)」的格式,確定要繼續匯入嗎?\n系統將嘗試根據檔名建立資料表。')) {
return;
}
} else if (!confirm('確定要匯入此份業績報表嗎?\n資料將會累加至 `realtime_sales_monthly` 資料表的現有內容中。')) {
return;
}
const formData = new FormData();
formData.append('file', file);
const btn = document.querySelector('button[onclick="uploadSalesReport()"]');
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>匯入中...';
btn.disabled = true;
fetch('/api/import_excel', {
method: 'POST',
headers: {
'X-CSRFToken': getCSRFToken()
},
body: formData
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
if (data.table === 'realtime_sales_monthly') {
alert('業績報表匯入成功!\n資料表: ' + data.table + '\n共 ' + data.rows + ' 筆資料已累加寫入。');
} else {
alert('匯入操作完成。\n注意: 系統偵測到的資料表名稱為「' + data.table + '」,而非預期的 `realtime_sales_monthly`。\n共寫入 ' + data.rows + ' 筆資料。');
}
fileInput.value = ''; // 清空輸入
} else {
alert('匯入失敗: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('發生系統錯誤,請檢查日誌');
})
.finally(() => {
btn.innerHTML = originalText;
btn.disabled = false;
});
}
function uploadExcel() {
const fileInput = document.getElementById('excelFile');
const file = fileInput.files[0];
if (!file) {
alert('請先選擇一個 Excel 檔案');
return;
}
if (!confirm('確定要匯入嗎?\n這將會建立一張新的資料表 (若名稱相同則會覆蓋)。')) {
return;
}
const formData = new FormData();
formData.append('file', file);
// 顯示 loading 狀態
const btn = document.querySelector('button[onclick="uploadExcel()"]');
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>處理中...';
btn.disabled = true;
fetch('/api/import_excel', {
method: 'POST',
headers: {
'X-CSRFToken': getCSRFToken()
},
body: formData
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
alert('匯入成功!\n已建立資料表: ' + data.table + '\n共寫入 ' + data.rows + ' 筆資料。');
fileInput.value = ''; // 清空輸入
} else {
alert('匯入失敗: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('發生系統錯誤,請檢查日誌');
})
.finally(() => {
btn.innerHTML = originalText;
btn.disabled = false;
});
}
function uploadMonthlySummary() {
const fileInput = document.getElementById('monthlySummaryFile');
const file = fileInput.files[0];
const progress = document.getElementById('monthlyImportProgress');
if (!file) {
alert('請先選擇一個月份總表 Excel 檔案');
return;
}
if (!confirm(`確定要匯入「${file.name}」嗎?\n資料庫將根據檔案中的年月份自動覆蓋既有數據。\n處理大量資料可能需要較長時間,請勿關閉視窗。`)) {
return;
}
const formData = new FormData();
formData.append('file', file);
const btn = document.querySelector('button[onclick="uploadMonthlySummary()"]');
const originalText = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>匯入中...';
btn.disabled = true;
progress.classList.remove('d-none');
fetch('/api/import/monthly_summary', {
method: 'POST',
headers: {
'X-CSRFToken': getCSRFToken()
},
body: formData
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
alert('🎉 ' + data.message);
fileInput.value = '';
} else {
alert('❌ 匯入失敗: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('發生連線錯誤或系統超時,請檢查背景處理狀態。');
})
.finally(() => {
btn.innerHTML = originalText;
btn.disabled = false;
progress.classList.add('d-none');
});
}
</script>
</body>
</html>