Initial commit: Daily News App

企業內部新聞彙整與分析系統
- 自動新聞抓取 (Digitimes, 經濟日報, 工商時報)
- AI 智慧摘要 (OpenAI/Claude/Ollama)
- 群組管理與訂閱通知
- 已清理 Python 快取檔案

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
donald
2025-12-03 23:53:24 +08:00
commit db0f0bbfe7
50 changed files with 11883 additions and 0 deletions

981
ui-preview.html Normal file
View File

@@ -0,0 +1,981 @@
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>每日報導 APP - UI 預覽</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Microsoft JhengHei", Arial, sans-serif;
background: #f5f5f5;
color: #333;
line-height: 1.6;
}
/* 導航列 */
.navbar {
background: #2c3e50;
color: white;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.navbar h1 {
font-size: 1.5rem;
}
.navbar-actions {
display: flex;
gap: 1rem;
align-items: center;
}
.lang-switch {
background: rgba(255,255,255,0.1);
border: 1px solid rgba(255,255,255,0.2);
color: white;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
}
.user-menu {
display: flex;
align-items: center;
gap: 0.5rem;
}
.btn {
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
}
.btn-primary {
background: #3498db;
color: white;
}
.btn-primary:hover {
background: #2980b9;
}
.btn-secondary {
background: #95a5a6;
color: white;
}
.btn-success {
background: #27ae60;
color: white;
}
.btn-danger {
background: #e74c3c;
color: white;
}
/* 容器 */
.container {
max-width: 1200px;
margin: 2rem auto;
padding: 0 1rem;
}
/* 卡片 */
.card {
background: white;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 2px solid #ecf0f1;
}
.card-title {
font-size: 1.3rem;
font-weight: 600;
color: #2c3e50;
}
/* 表格 */
.table {
width: 100%;
border-collapse: collapse;
}
.table th,
.table td {
padding: 0.75rem;
text-align: left;
border-bottom: 1px solid #ecf0f1;
}
.table th {
background: #f8f9fa;
font-weight: 600;
color: #2c3e50;
}
.table tr:hover {
background: #f8f9fa;
}
/* 標籤 */
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: 12px;
font-size: 0.85rem;
font-weight: 500;
}
.badge-success {
background: #d4edda;
color: #155724;
}
.badge-warning {
background: #fff3cd;
color: #856404;
}
.badge-danger {
background: #f8d7da;
color: #721c24;
}
.badge-info {
background: #d1ecf1;
color: #0c5460;
}
/* 表單 */
.form-group {
margin-bottom: 1.5rem;
}
.form-label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: #2c3e50;
}
.form-control {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1rem;
}
.form-control:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
}
/* 分頁 */
.pagination {
display: flex;
gap: 0.5rem;
justify-content: center;
margin-top: 1.5rem;
}
.page-link {
padding: 0.5rem 1rem;
border: 1px solid #ddd;
background: white;
color: #3498db;
text-decoration: none;
border-radius: 4px;
}
.page-link:hover {
background: #f8f9fa;
}
.page-link.active {
background: #3498db;
color: white;
border-color: #3498db;
}
/* 頁面切換 */
.page {
display: none;
}
.page.active {
display: block;
}
/* 標籤頁 */
.tabs {
display: flex;
border-bottom: 2px solid #ecf0f1;
margin-bottom: 1.5rem;
}
.tab {
padding: 1rem 1.5rem;
cursor: pointer;
border: none;
background: none;
font-size: 1rem;
color: #7f8c8d;
border-bottom: 3px solid transparent;
transition: all 0.3s;
}
.tab:hover {
color: #3498db;
}
.tab.active {
color: #3498db;
border-bottom-color: #3498db;
font-weight: 600;
}
/* 統計卡片 */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.stat-card {
background: white;
padding: 1.5rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.stat-value {
font-size: 2rem;
font-weight: 700;
color: #3498db;
}
.stat-label {
color: #7f8c8d;
font-size: 0.9rem;
margin-top: 0.5rem;
}
/* 響應式 */
@media (max-width: 768px) {
.navbar {
flex-direction: column;
gap: 1rem;
}
.container {
padding: 0 0.5rem;
}
.stats-grid {
grid-template-columns: 1fr;
}
}
/* 摘要區塊 */
.summary-box {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 8px;
border-left: 4px solid #3498db;
margin: 1rem 0;
}
/* 文章列表 */
.article-item {
padding: 1rem;
border-bottom: 1px solid #ecf0f1;
display: flex;
justify-content: space-between;
align-items: center;
}
.article-item:last-child {
border-bottom: none;
}
.article-info {
flex: 1;
}
.article-title {
font-weight: 600;
margin-bottom: 0.5rem;
}
.article-meta {
color: #7f8c8d;
font-size: 0.9rem;
}
/* 切換按鈕 */
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #3498db;
}
input:checked + .slider:before {
transform: translateX(26px);
}
</style>
</head>
<body>
<!-- 導航列 -->
<nav class="navbar">
<h1>📰 每日報導 APP</h1>
<div class="navbar-actions">
<button class="lang-switch" onclick="toggleLanguage()">🌐 中文 / English</button>
<div class="user-menu">
<span>👤 張三 (專員)</span>
<button class="btn btn-secondary" onclick="showPage('logout')">登出</button>
</div>
</div>
</nav>
<div class="container">
<!-- 頁面選單 -->
<div class="tabs">
<button class="tab active" onclick="showPage('dashboard')">儀表板</button>
<button class="tab" onclick="showPage('reports')">報告管理</button>
<button class="tab" onclick="showPage('groups')">群組管理</button>
<button class="tab" onclick="showPage('users')">用戶管理</button>
<button class="tab" onclick="showPage('settings')">系統設定</button>
</div>
<!-- 儀表板頁面 -->
<div id="dashboard" class="page active">
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value">12</div>
<div class="stat-label">今日新聞</div>
</div>
<div class="stat-card">
<div class="stat-value">5</div>
<div class="stat-label">待審核報告</div>
</div>
<div class="stat-card">
<div class="stat-value">3</div>
<div class="stat-label">已發布報告</div>
</div>
<div class="stat-card">
<div class="stat-value">42</div>
<div class="stat-label">訂閱讀者</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h2 class="card-title">今日待審核報告</h2>
<button class="btn btn-primary" onclick="showPage('reports')">查看全部</button>
</div>
<table class="table">
<thead>
<tr>
<th>報告標題</th>
<th>群組</th>
<th>文章數</th>
<th>狀態</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>半導體日報 - 2025/01/27</td>
<td>半導體</td>
<td>8</td>
<td><span class="badge badge-warning">待審核</span></td>
<td>
<button class="btn btn-primary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">審核</button>
</td>
</tr>
<tr>
<td>面板日報 - 2025/01/27</td>
<td>面板</td>
<td>5</td>
<td><span class="badge badge-warning">待審核</span></td>
<td>
<button class="btn btn-primary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">審核</button>
</td>
</tr>
<tr>
<td>車用電子日報 - 2025/01/27</td>
<td>車用電子</td>
<td>6</td>
<td><span class="badge badge-success">已發布</span></td>
<td>
<button class="btn btn-secondary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">查看</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 報告管理頁面 -->
<div id="reports" class="page">
<div class="card">
<div class="card-header">
<h2 class="card-title">報告管理</h2>
<div>
<input type="date" class="form-control" style="width: auto; display: inline-block; margin-right: 0.5rem;">
<select class="form-control" style="width: auto; display: inline-block;">
<option>全部群組</option>
<option>半導體</option>
<option>面板</option>
<option>車用電子</option>
</select>
</div>
</div>
<div class="card" style="margin-top: 1rem;">
<h3 style="margin-bottom: 1rem;">半導體日報 - 2025/01/27</h3>
<div style="display: flex; gap: 1rem; margin-bottom: 1rem;">
<span class="badge badge-info">半導體</span>
<span class="badge badge-warning">待審核</span>
<span>8 篇文章</span>
</div>
<div class="summary-box">
<h4 style="margin-bottom: 0.5rem;">AI 摘要</h4>
<p>根據今日新聞分析半導體產業呈現以下趨勢台積電宣布擴大先進製程產能預期將帶動相關供應鏈成長。記憶體價格持續上漲DRAM 與 NAND Flash 需求強勁。中國半導體自主化政策持續推進,但技術突破仍面臨挑戰...</p>
</div>
<div style="margin-top: 1.5rem;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
<h4 style="margin: 0;">相關新聞</h4>
<button class="btn btn-primary" onclick="toggleManualUpload()" style="padding: 0.5rem 1rem; font-size: 0.9rem;">+ 手動上傳新聞</button>
</div>
<!-- 手動上傳新聞表單 -->
<div id="manual-upload-form" style="display: none; background: #f8f9fa; padding: 1.5rem; border-radius: 8px; margin-bottom: 1rem; border: 2px dashed #3498db;">
<h5 style="margin-bottom: 1rem; color: #2c3e50;">手動上傳純文字新聞</h5>
<div class="form-group" style="margin-bottom: 1rem;">
<label class="form-label">新聞標題 *</label>
<input type="text" class="form-control" id="manual-title" placeholder="輸入新聞標題...">
</div>
<div class="form-group" style="margin-bottom: 1rem;">
<label class="form-label">新聞來源</label>
<select class="form-control" id="manual-source" style="max-width: 200px;">
<option value="manual">手動輸入</option>
<option value="digitimes">Digitimes</option>
<option value="udn">經濟日報</option>
<option value="ctee">工商時報</option>
</select>
</div>
<div class="form-group" style="margin-bottom: 1rem;">
<label class="form-label">來源 URL選填</label>
<input type="url" class="form-control" id="manual-url" placeholder="https://...">
</div>
<div class="form-group" style="margin-bottom: 1rem;">
<label class="form-label">發布時間</label>
<input type="datetime-local" class="form-control" id="manual-date" style="max-width: 250px;">
</div>
<div class="form-group" style="margin-bottom: 1rem;">
<label class="form-label">新聞內容 *</label>
<textarea class="form-control" id="manual-content" rows="8" placeholder="貼上或輸入新聞全文內容..."></textarea>
<small style="color: #7f8c8d; margin-top: 0.25rem; display: block;">支援純文字格式,建議至少 100 字</small>
</div>
<div style="display: flex; gap: 0.5rem;">
<button class="btn btn-success" onclick="addManualArticle()">新增到報告</button>
<button class="btn btn-secondary" onclick="toggleManualUpload()">取消</button>
</div>
</div>
<div class="article-item">
<div class="article-info">
<div class="article-title">台積電宣布擴大 3 奈米產能</div>
<div class="article-meta">Digitimes | 2025-01-27 08:30</div>
</div>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
<div class="article-item">
<div class="article-info">
<div class="article-title">記憶體價格持續上漲DRAM 需求強勁</div>
<div class="article-meta">經濟日報 | 2025-01-27 09:15</div>
</div>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
</div>
<div class="article-item">
<div class="article-info">
<div class="article-title">中國半導體自主化面臨技術挑戰</div>
<div class="article-meta">工商時報 | 2025-01-27 10:00</div>
</div>
<label class="switch">
<input type="checkbox">
<span class="slider"></span>
</label>
</div>
</div>
<div style="margin-top: 1.5rem; display: flex; gap: 1rem;">
<button class="btn btn-primary">編輯摘要</button>
<button class="btn btn-success">發布報告</button>
<button class="btn btn-secondary">重新產生摘要</button>
<button class="btn btn-secondary">匯出 PDF</button>
</div>
</div>
</div>
</div>
<!-- 群組管理頁面 -->
<div id="groups" class="page">
<div class="card">
<div class="card-header">
<h2 class="card-title">群組管理</h2>
<button class="btn btn-primary">新增群組</button>
</div>
<table class="table">
<thead>
<tr>
<th>群組名稱</th>
<th>分類</th>
<th>關鍵字數</th>
<th>訂閱數</th>
<th>狀態</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>半導體</td>
<td>產業別</td>
<td>15</td>
<td>28</td>
<td><span class="badge badge-success">啟用</span></td>
<td>
<button class="btn btn-primary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">編輯</button>
</td>
</tr>
<tr>
<td>面板</td>
<td>產業別</td>
<td>12</td>
<td>18</td>
<td><span class="badge badge-success">啟用</span></td>
<td>
<button class="btn btn-primary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">編輯</button>
</td>
</tr>
<tr>
<td>車用電子</td>
<td>產業別</td>
<td>10</td>
<td>15</td>
<td><span class="badge badge-success">啟用</span></td>
<td>
<button class="btn btn-primary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">編輯</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 群組編輯表單 -->
<div class="card">
<h3 class="card-title" style="margin-bottom: 1rem;">編輯群組:半導體</h3>
<div class="form-group">
<label class="form-label">群組名稱</label>
<input type="text" class="form-control" value="半導體">
</div>
<div class="form-group">
<label class="form-label">描述</label>
<textarea class="form-control" rows="3">半導體產業相關新聞與分析</textarea>
</div>
<div class="form-group">
<label class="form-label">關鍵字</label>
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.5rem;">
<span class="badge badge-info" style="padding: 0.5rem 1rem;">台積電 <button style="background: none; border: none; margin-left: 0.5rem; cursor: pointer;">×</button></span>
<span class="badge badge-info" style="padding: 0.5rem 1rem;">半導體 <button style="background: none; border: none; margin-left: 0.5rem; cursor: pointer;">×</button></span>
<span class="badge badge-info" style="padding: 0.5rem 1rem;">晶圓 <button style="background: none; border: none; margin-left: 0.5rem; cursor: pointer;">×</button></span>
<span class="badge badge-info" style="padding: 0.5rem 1rem;">DRAM <button style="background: none; border: none; margin-left: 0.5rem; cursor: pointer;">×</button></span>
</div>
<input type="text" class="form-control" placeholder="新增關鍵字...">
</div>
<div class="form-group">
<label class="form-label">AI 摘要背景資訊</label>
<textarea class="form-control" rows="4" placeholder="提供給 AI 的背景資訊,幫助產生更準確的摘要...">半導體產業是台灣重要的支柱產業,主要關注台積電、聯發科等龍頭企業動態,以及全球半導體供應鏈變化。</textarea>
</div>
<div class="form-group">
<label class="form-label">AI 摘要方向</label>
<textarea class="form-control" rows="4" placeholder="指定 AI 摘要的重點方向...">請重點分析產業趨勢、技術發展、市場動態與供應鏈變化。</textarea>
</div>
<div style="display: flex; gap: 1rem;">
<button class="btn btn-primary">儲存</button>
<button class="btn btn-secondary">取消</button>
</div>
</div>
</div>
<!-- 用戶管理頁面 -->
<div id="users" class="page">
<div class="card">
<div class="card-header">
<h2 class="card-title">用戶管理</h2>
<button class="btn btn-primary">新增用戶</button>
</div>
<div style="margin-bottom: 1rem;">
<input type="text" class="form-control" placeholder="搜尋用戶..." style="max-width: 300px; display: inline-block;">
<select class="form-control" style="width: auto; display: inline-block; margin-left: 0.5rem;">
<option>全部角色</option>
<option>管理員</option>
<option>專員</option>
<option>讀者</option>
</select>
</div>
<table class="table">
<thead>
<tr>
<th>帳號</th>
<th>顯示名稱</th>
<th>Email</th>
<th>角色</th>
<th>認證方式</th>
<th>狀態</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>admin</td>
<td>系統管理員</td>
<td>admin@company.com</td>
<td><span class="badge badge-danger">管理員</span></td>
<td>本地</td>
<td><span class="badge badge-success">啟用</span></td>
<td>
<button class="btn btn-primary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">編輯</button>
</td>
</tr>
<tr>
<td>editor01</td>
<td>張三</td>
<td>editor01@company.com</td>
<td><span class="badge badge-warning">專員</span></td>
<td>AD</td>
<td><span class="badge badge-success">啟用</span></td>
<td>
<button class="btn btn-primary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">編輯</button>
</td>
</tr>
<tr>
<td>user001</td>
<td>李四</td>
<td>user001@company.com</td>
<td><span class="badge badge-info">讀者</span></td>
<td>AD</td>
<td><span class="badge badge-success">啟用</span></td>
<td>
<button class="btn btn-primary" style="padding: 0.25rem 0.75rem; font-size: 0.85rem;">編輯</button>
</td>
</tr>
</tbody>
</table>
<div class="pagination">
<a href="#" class="page-link">上一頁</a>
<a href="#" class="page-link active">1</a>
<a href="#" class="page-link">2</a>
<a href="#" class="page-link">3</a>
<a href="#" class="page-link">下一頁</a>
</div>
</div>
</div>
<!-- 系統設定頁面 -->
<div id="settings" class="page">
<div class="card">
<h2 class="card-title" style="margin-bottom: 1.5rem;">系統設定</h2>
<!-- LLM 設定 -->
<div style="margin-bottom: 2rem;">
<h3 style="margin-bottom: 1rem; color: #2c3e50;">LLM 設定</h3>
<div class="form-group">
<label class="form-label">LLM 提供者</label>
<select class="form-control">
<option>Google Gemini</option>
<option>OpenAI</option>
<option>Ollama (地端)</option>
</select>
</div>
<div class="form-group">
<label class="form-label">API Key</label>
<input type="password" class="form-control" placeholder="輸入 API Key...">
<small style="color: #7f8c8d; margin-top: 0.25rem; display: block;">API Key 將加密儲存</small>
</div>
<div class="form-group">
<label class="form-label">模型版本</label>
<select class="form-control">
<option>gemini-1.5-pro</option>
<option>gemini-1.5-flash</option>
<option>gemini-1.0-pro</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Temperature</label>
<input type="number" class="form-control" value="0.7" step="0.1" min="0" max="1">
</div>
<div class="form-group">
<label class="form-label">Max Tokens</label>
<input type="number" class="form-control" value="2048">
</div>
<button class="btn btn-primary">測試連線</button>
<button class="btn btn-success" style="margin-left: 0.5rem;">儲存設定</button>
</div>
<!-- PDF 模板設定 -->
<div style="margin-bottom: 2rem; padding-top: 2rem; border-top: 2px solid #ecf0f1;">
<h3 style="margin-bottom: 1rem; color: #2c3e50;">PDF 模板設定</h3>
<div class="form-group">
<label class="form-label">公司 Logo</label>
<input type="file" class="form-control" accept="image/png,image/jpeg,image/svg+xml">
<small style="color: #7f8c8d; margin-top: 0.25rem; display: block;">支援 PNG、JPEG、SVG 格式,建議大小 200x60px</small>
</div>
<div class="form-group">
<label class="form-label">頁首文字</label>
<input type="text" class="form-control" value="每日報導">
</div>
<div class="form-group">
<label class="form-label">頁尾文字</label>
<input type="text" class="form-control" value="本報告僅供內部參考使用">
</div>
<button class="btn btn-success">儲存設定</button>
</div>
<!-- SMTP 設定 -->
<div style="margin-bottom: 2rem; padding-top: 2rem; border-top: 2px solid #ecf0f1;">
<h3 style="margin-bottom: 1rem; color: #2c3e50;">SMTP 設定</h3>
<div class="form-group">
<label class="form-label">SMTP 伺服器</label>
<input type="text" class="form-control" placeholder="smtp.example.com">
</div>
<div class="form-group">
<label class="form-label">SMTP 埠號</label>
<input type="number" class="form-control" value="587">
</div>
<div class="form-group">
<label class="form-label">SMTP 帳號</label>
<input type="text" class="form-control" placeholder="smtp@example.com">
</div>
<div class="form-group">
<label class="form-label">SMTP 密碼</label>
<input type="password" class="form-control" placeholder="輸入密碼...">
</div>
<div class="form-group">
<label class="form-label">寄件者 Email</label>
<input type="email" class="form-control" placeholder="noreply@example.com">
</div>
<div class="form-group">
<label class="form-label">寄件者名稱</label>
<input type="text" class="form-control" value="每日報導系統">
</div>
<button class="btn btn-primary">測試連線</button>
<button class="btn btn-success" style="margin-left: 0.5rem;">儲存設定</button>
</div>
</div>
</div>
<!-- 登出確認 -->
<div id="logout" class="page">
<div class="card" style="text-align: center; max-width: 400px; margin: 5rem auto;">
<h2 style="margin-bottom: 1rem;">確認登出</h2>
<p style="margin-bottom: 2rem; color: #7f8c8d;">您確定要登出系統嗎?</p>
<div style="display: flex; gap: 1rem; justify-content: center;">
<button class="btn btn-danger" onclick="showPage('dashboard')">確認登出</button>
<button class="btn btn-secondary" onclick="showPage('dashboard')">取消</button>
</div>
</div>
</div>
</div>
<script>
// 頁面切換
function showPage(pageId) {
// 隱藏所有頁面
document.querySelectorAll('.page').forEach(page => {
page.classList.remove('active');
});
// 顯示選中的頁面
document.getElementById(pageId).classList.add('active');
// 更新標籤頁狀態
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
// 根據頁面 ID 設定對應標籤為 active
const tabMap = {
'dashboard': 0,
'reports': 1,
'groups': 2,
'users': 3,
'settings': 4
};
if (tabMap[pageId] !== undefined) {
document.querySelectorAll('.tab')[tabMap[pageId]].classList.add('active');
}
}
// 語言切換
let currentLang = 'zh';
function toggleLanguage() {
currentLang = currentLang === 'zh' ? 'en' : 'zh';
const btn = document.querySelector('.lang-switch');
btn.textContent = currentLang === 'zh' ? '🌐 中文 / English' : '🌐 Chinese / 英文';
// 這裡可以實作實際的語言切換邏輯
console.log('切換語言至:', currentLang);
}
// 手動上傳新聞表單切換
function toggleManualUpload() {
const form = document.getElementById('manual-upload-form');
if (form.style.display === 'none') {
form.style.display = 'block';
// 設定預設時間為今天
const now = new Date();
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
document.getElementById('manual-date').value = now.toISOString().slice(0, 16);
} else {
form.style.display = 'none';
// 清空表單
document.getElementById('manual-title').value = '';
document.getElementById('manual-url').value = '';
document.getElementById('manual-content').value = '';
document.getElementById('manual-source').value = 'manual';
}
}
// 新增手動上傳的新聞
function addManualArticle() {
const title = document.getElementById('manual-title').value.trim();
const content = document.getElementById('manual-content').value.trim();
const source = document.getElementById('manual-source').value;
const url = document.getElementById('manual-url').value.trim();
const date = document.getElementById('manual-date').value;
if (!title || !content) {
alert('請填寫新聞標題和內容');
return;
}
if (content.length < 100) {
if (!confirm('新聞內容少於 100 字,確定要新增嗎?')) {
return;
}
}
// 模擬新增新聞到列表
const articleList = document.querySelector('.article-item').parentElement;
const newArticle = document.createElement('div');
newArticle.className = 'article-item';
const sourceNames = {
'manual': '手動輸入',
'digitimes': 'Digitimes',
'udn': '經濟日報',
'ctee': '工商時報'
};
const dateStr = date ? new Date(date).toLocaleString('zh-TW') : new Date().toLocaleString('zh-TW');
newArticle.innerHTML = `
<div class="article-info">
<div class="article-title">${title}</div>
<div class="article-meta">${sourceNames[source]} | ${dateStr}</div>
</div>
<label class="switch">
<input type="checkbox" checked>
<span class="slider"></span>
</label>
`;
// 插入到列表最前面
articleList.insertBefore(newArticle, articleList.firstChild);
// 關閉表單並清空
toggleManualUpload();
alert('新聞已新增到報告中');
}
// 模擬資料載入
console.log('UI 預覽頁面已載入');
console.log('這是靜態預覽頁面,不連接資料庫');
</script>
</body>
</html>