Files
ewoooc/templates/system_settings.html
ogt c1b375f41c
Some checks failed
CD Pipeline / deploy (push) Failing after 6m19s
fix: harden import auth and utility page copy
2026-06-26 06:44:51 +08:00

374 lines
13 KiB
HTML
Raw 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);
}
.system-import-page .system-version-pill {
display: inline-flex;
align-items: center;
align-self: flex-start;
min-height: 24px;
padding: 4px 10px;
background: var(--momo-tag-terra-bg);
border: 1px solid var(--momo-tag-terra-border);
border-radius: var(--momo-radius-sm);
color: var(--momo-tag-terra-text);
font-family: var(--momo-font-mono, monospace);
font-size: var(--momo-text-label);
font-weight: 800;
}
@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>先補齊業績與備份,讓分析、建議與解法有可靠資料。</p>
</div>
<span class="system-version-pill">版本 {{ 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">月份業績匯總分析(標準版)</h6>
<p class="text-muted small mb-3">匯入月結業績,更新成長、毛利與品類結構判斷。</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">匯入全月即時業績,補齊當日與月度分析來源。</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-primary w-100" onclick="uploadExcel()">
<i class="fas fa-file-import 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('備份沒有完成:' + toImportActionMessage(data.message));
}
})
.catch(error => {
console.error('Error:', error);
alert('備份連線失敗,請稍後重試;若重複失敗請通知維護人員。');
});
}
}
function toImportActionMessage(message) {
const raw = String(message || '').trim();
const text = raw.toLowerCase();
if (!raw) return '請稍後重試;若重複失敗請通知維護人員。';
if (text.includes('google drive') || raw.includes('雲端') || raw.includes('授權')) {
return '請重新確認 Google Drive 授權或雲端檔案權限後再匯入。';
}
if (raw.includes('欄位') || raw.includes('格式') || raw.includes('日期') || text.includes('excel')) {
return '請改用正確的業績報表,確認包含日期、商品與業績金額後重新匯入。';
}
if (
text.includes('database') ||
text.includes('sql') ||
text.includes('table') ||
text.includes('snapshot') ||
text.includes('monthly') ||
raw.includes('資料庫')
) {
return '業績資料處理未完整完成,請重新匯入最新檔案;若重複失敗請通知維護人員。';
}
return raw;
}
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匯入後會更新月度業績判斷供成長分析與報表使用。')) {
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') {
alert('業績報表匯入成功!\n共 ' + Number(data.rows || 0).toLocaleString() + ' 筆資料已更新,可回到成長分析確認結果。');
fileInput.value = '';
} else {
alert('匯入沒有完成:' + toImportActionMessage(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共更新 ' + Number(data.rows || 0).toLocaleString() + ' 筆資料,可回到分析頁確認結果。');
fileInput.value = '';
} else {
alert('匯入沒有完成:' + toImportActionMessage(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('匯入沒有完成:' + toImportActionMessage(data.message));
}
})
.catch(error => {
console.error('Error:', error);
alert('發生連線錯誤或系統超時,請檢查背景處理狀態。');
})
.finally(() => {
btn.innerHTML = originalText;
btn.disabled = false;
progress.classList.add('d-none');
});
}
</script>
{% endblock %}