Files
ewoooc/templates/system_settings.html
OoO 2c869edcb1
All checks were successful
CD Pipeline / deploy (push) Successful in 1m0s
統一系統管理頁新版殼層
2026-05-14 00:43:55 +08:00

340 lines
12 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.
{% extends "ewoooc_base.html" %}
{% block title %}系統設定與資料匯入 - EwoooC{% endblock %}
{% block extra_css %}
<style>
.system-import-page {
display: grid;
gap: var(--momo-space-4, 16px);
}
.system-import-page .system-import-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--momo-space-4, 16px);
padding: var(--momo-space-4, 16px) var(--momo-space-5, 24px);
background: var(--momo-bg-surface);
border: 1px solid var(--momo-border-light);
border-radius: var(--momo-radius-md);
}
.system-import-page .system-import-head h1 {
margin: 0;
color: var(--momo-text-primary);
font-family: var(--momo-font-display);
font-size: var(--momo-text-headline);
font-weight: 700;
line-height: var(--momo-line-height-tight);
letter-spacing: 0;
}
.system-import-page .system-import-head p {
margin: var(--momo-space-1, 4px) 0 0;
color: var(--momo-text-secondary);
font-size: var(--momo-text-body-sm);
}
.system-import-page .table-container {
padding: var(--momo-space-5, 24px);
background: var(--momo-bg-surface);
border: 1px solid var(--momo-border-light);
border-radius: var(--momo-radius-md);
}
.system-import-page .table-container h5 {
color: var(--momo-text-primary);
font-family: var(--momo-font-display);
font-size: var(--momo-text-title);
font-weight: 700;
}
.system-import-page .import-panel {
padding: var(--momo-space-4, 16px);
background: var(--momo-bg-paper);
border: 1px solid var(--momo-border-light);
border-radius: var(--momo-radius-md);
}
@media (max-width: 760px) {
.system-import-page .system-import-head,
.system-import-page .table-container .d-flex {
flex-direction: column;
}
.system-import-page .table-container {
padding: var(--momo-space-4, 16px);
}
}
</style>
{% endblock %}
{% block content %}
<div class="system-import-page">
<header class="system-import-head">
<div>
<h1><i class="fas fa-cogs me-2"></i>系統設定與資料匯入</h1>
<p>集中管理備份、月總表、即時業績與一般 Excel 匯入。</p>
</div>
<span class="badge bg-primary">版本 {{ system_version }}</span>
</header>
<div class="table-container">
<h5 class="mb-3">系統維護</h5>
<div class="d-flex align-items-center justify-content-between gap-3">
<div>
<h6 class="fw-bold mb-1">完整備份</h6>
<p class="text-muted mb-0 small">將目前的系統程式碼與資料庫打包存檔。</p>
</div>
<button class="btn btn-outline-secondary" onclick="triggerBackup()">
<i class="fas fa-file-archive me-2"></i>建立備份
</button>
</div>
</div>
<div class="table-container">
<h5 class="mb-3 text-primary"><i class="fas fa-file-import me-2"></i>月份總表數據分析匯入</h5>
<div class="import-panel">
<div class="row align-items-center g-3">
<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>該月份之歷史數據,適合大批量資料。</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" 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>
<div class="table-container">
<h5 class="mb-3"><i class="fas fa-file-invoice-dollar me-2"></i>即時業績(全月)匯入</h5>
<div class="import-panel">
<div class="row align-items-center g-3">
<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>
<div class="table-container">
<h5 class="mb-3">一般 Excel 匯入 (自動建表)</h5>
<div class="row align-items-end g-3">
<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">
<button class="btn btn-success w-100" onclick="uploadExcel()">
<i class="fas fa-table me-2"></i>匯入並建立通用資料表
</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
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);
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>
{% endblock %}