Files
ewoooc/templates/dashboard_v2.html
OoO cf52b07809
All checks were successful
CD Pipeline / deploy (push) Successful in 1m5s
perf: 外部化商品看板前端資源
2026-05-18 00:22:10 +08:00

525 lines
37 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 %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/page-dashboard-v2.css') }}">
{% endblock %}
{% block ewooo_content %}
<div class="dashboard-v2-stack">
{% set overview = competitor_overview | default({}) %}
<section>
<div class="dashboard-section-label">
<span class="num momo-mono">01</span>
<span class="title">比價監控總覽</span>
<span class="meta momo-mono">LIVE · 更新於 {{ datetime_now }}</span>
</div>
<div class="dashboard-kpi-grid">
<div class="dashboard-kpi">
<div class="dashboard-kpi-label momo-mono">比對覆蓋率</div>
<div class="dashboard-kpi-value momo-mono">{{ overview.match_rate | default(0) }}%</div>
<div class="dashboard-kpi-sub momo-mono">{{ overview.matched_count | default(0) | number_format }} / {{ overview.total_active | default(total_products) | number_format }} ACTIVE</div>
</div>
<div class="dashboard-kpi is-accent">
<div class="dashboard-kpi-label momo-mono">PChome 優勢</div>
<div class="dashboard-kpi-value momo-mono">{{ overview.pchome_advantage_count | default(0) | number_format }}</div>
<div class="dashboard-kpi-sub momo-mono">平均價差 +{{ overview.avg_advantage_gap | default(0) }}%</div>
</div>
<div class="dashboard-kpi">
<div class="dashboard-kpi-label momo-mono">MOMO 威脅</div>
<div class="dashboard-kpi-value momo-mono is-danger">{{ overview.momo_threat_count | default(0) | number_format }}</div>
<div class="dashboard-kpi-sub momo-mono">MOMO 價格低於 PChome</div>
</div>
<div class="dashboard-kpi">
<div class="dashboard-kpi-label momo-mono">AI 挑品</div>
<div class="dashboard-kpi-value momo-mono is-success">{{ overview.ai_pick_count | default(0) | number_format }}</div>
<div class="dashboard-kpi-sub momo-mono">
<a class="dashboard-kpi-sub-link" href="{{ url_for('dashboard.index', filter='ai_picks', category=current_category, q=search_query, sort_by='timestamp', order='desc') }}">查看 {{ ai_pick_list_limit }} 品清單</a>
</div>
</div>
<div class="dashboard-kpi">
<div class="dashboard-kpi-label momo-mono">待比對</div>
<div class="dashboard-kpi-value momo-mono is-warning">{{ overview.pending_match_count | default(0) | number_format }}</div>
<div class="dashboard-kpi-sub momo-mono">高價品項優先補抓</div>
</div>
<div class="dashboard-kpi">
<div class="dashboard-kpi-label momo-mono">資料新鮮度</div>
<div class="dashboard-kpi-value momo-mono is-small">{{ '已更新' if overview.last_pchome_crawled else '待更新' }}</div>
<div class="dashboard-kpi-sub momo-mono">{{ overview.last_pchome_crawled or '尚無 PChome 抓取紀錄' }}</div>
</div>
</div>
</section>
<section>
<div class="dashboard-section-label">
<span class="num momo-mono">02</span>
<span class="title">比價決策焦點</span>
<span class="meta momo-mono">{{ today_date }}</span>
</div>
<div class="dashboard-focus-grid">
<div class="dashboard-focus-card">
<div class="dashboard-focus-label momo-mono">今日優先銷售</div>
{% if overview.top_picks %}
<div class="dashboard-focus-list">
{% for pick in overview.top_picks %}
<div class="dashboard-focus-row">
<a class="dashboard-focus-row-title momo-tracked-link" href="{{ pick.momo_url or '#' }}" data-momo-original-url="{{ pick.momo_url or '#' }}" target="_blank" rel="noopener noreferrer"
data-track-platform="momo"
data-track-source="dashboard-v2-overview-top-picks"
data-track-product-id="{{ pick.sku }}"
data-track-icode="{{ pick.sku }}"
data-track-product-name="{{ pick.name|e }}">{{ pick.name }}</a>
<div class="dashboard-focus-row-meta momo-mono">
<span class="dashboard-focus-chip is-win">AI {{ (pick.confidence * 100) | round(0) | int if pick.confidence else 0 }}%</span>
<span>證據 {{ pick.evidence_quality | round(0) | int }}%</span>
<span>機會 {{ pick.opportunity_score | round(0) | int }}</span>
<span>MOMO ${{ pick.momo_price | int | number_format }}</span>
<span>PChome ${{ pick.pchome_price | int | number_format }}</span>
<span>+{{ pick.gap_pct | round(1) }}%</span>
</div>
{% if pick.missing_evidence %}
<div class="dashboard-ai-evidence-line">
{% for evidence in pick.missing_evidence[:2] %}
<span class="dashboard-ai-evidence-chip">{{ evidence }}</span>
{% endfor %}
</div>
{% endif %}
<div class="dashboard-focus-row-links">
<a class="dashboard-platform-link is-momo momo-tracked-link" href="{{ pick.momo_url or '#' }}" data-momo-original-url="{{ pick.momo_url or '#' }}" target="_blank" rel="noopener noreferrer"
data-track-platform="momo"
data-track-source="dashboard-v2-overview-top-picks"
data-track-product-id="{{ pick.sku }}"
data-track-icode="{{ pick.sku }}"
data-track-product-name="{{ pick.name|e }}">MOMO {{ pick.sku }}</a>
{% if pick.pchome_url %}
<a class="dashboard-platform-link is-pchome" href="{{ pick.pchome_url }}" target="_blank" rel="noopener noreferrer">PChome {{ pick.pchome_id }}</a>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="dashboard-focus-title">尚無 AI 挑品</div>
<div class="dashboard-focus-sub momo-mono">請先讓 PChome 比對與挑品 Agent 累積資料</div>
{% endif %}
</div>
<div class="dashboard-focus-card">
<div class="dashboard-focus-label momo-mono">價格威脅</div>
{% if overview.top_momo_threats %}
<div class="dashboard-focus-list">
{% for item in overview.top_momo_threats %}
<div class="dashboard-focus-row">
<a class="dashboard-focus-row-title momo-tracked-link" href="{{ item.momo_url or '#' }}" data-momo-original-url="{{ item.momo_url or '#' }}" target="_blank" rel="noopener noreferrer"
data-track-platform="momo"
data-track-source="dashboard-v2-overview-top-momo-threats"
data-track-product-id="{{ item.sku }}"
data-track-icode="{{ item.sku }}"
data-track-product-name="{{ item.name|e }}">{{ item.name }}</a>
<div class="dashboard-focus-row-meta momo-mono">
<span class="dashboard-focus-chip is-risk">{{ item.gap_pct | round(1) }}%</span>
<span>MOMO ${{ item.momo_price | int | number_format }}</span>
<span>PChome ${{ item.pchome_price | int | number_format }}</span>
</div>
<div class="dashboard-focus-row-links">
<a class="dashboard-platform-link is-momo momo-tracked-link" href="{{ item.momo_url or '#' }}" data-momo-original-url="{{ item.momo_url or '#' }}" target="_blank" rel="noopener noreferrer"
data-track-platform="momo"
data-track-source="dashboard-v2-overview-top-momo-threats"
data-track-product-id="{{ item.sku }}"
data-track-icode="{{ item.sku }}"
data-track-product-name="{{ item.name|e }}">MOMO {{ item.sku }}</a>
{% if item.pchome_url %}
<a class="dashboard-platform-link is-pchome" href="{{ item.pchome_url }}" target="_blank" rel="noopener noreferrer">PChome {{ item.pchome_id }}</a>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="dashboard-focus-title">尚無明顯威脅</div>
<div class="dashboard-focus-sub momo-mono">目前沒有 MOMO 低於 PChome 5% 以上的配對商品</div>
{% endif %}
</div>
<div class="dashboard-focus-card">
<div class="dashboard-focus-label momo-mono">補資料優先</div>
{% if overview.pending_priority %}
<div class="dashboard-focus-list">
{% for item in overview.pending_priority %}
<div class="dashboard-focus-row">
<a class="dashboard-focus-row-title momo-tracked-link" href="{{ item.momo_url or '#' }}" data-momo-original-url="{{ item.momo_url or '#' }}" target="_blank" rel="noopener noreferrer"
data-track-platform="momo"
data-track-source="dashboard-v2-overview-pending-priority"
data-track-product-id="{{ item.sku }}"
data-track-icode="{{ item.sku }}"
data-track-product-name="{{ item.name|e }}">{{ item.name }}</a>
<div class="dashboard-focus-row-meta momo-mono">
<span class="dashboard-focus-chip is-neutral">待比對</span>
<span>MOMO ${{ item.momo_price | int | number_format }}</span>
<span>{{ item.category or '未分類' }}</span>
</div>
<div class="dashboard-focus-row-links">
<a class="dashboard-platform-link is-momo momo-tracked-link" href="{{ item.momo_url or '#' }}" data-momo-original-url="{{ item.momo_url or '#' }}" target="_blank" rel="noopener noreferrer"
data-track-platform="momo"
data-track-source="dashboard-v2-overview-pending-priority"
data-track-product-id="{{ item.sku }}"
data-track-icode="{{ item.sku }}"
data-track-product-name="{{ item.name|e }}">MOMO {{ item.sku }}</a>
<span class="dashboard-platform-muted">PChome 待比對</span>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="dashboard-focus-title">待比對清單已清空</div>
<div class="dashboard-focus-sub momo-mono">目前 ACTIVE 商品都有有效 PChome 配對或尚無最新 MOMO 價格</div>
{% endif %}
</div>
</div>
</section>
<section>
<div class="dashboard-section-label">
<span class="num momo-mono">03</span>
<span class="title">篩選</span>
</div>
<div class="dashboard-filter-card">
<form class="dashboard-filter-form" method="GET" action="/">
<input class="dashboard-search" type="text" name="q" value="{{ search_query }}" placeholder="搜尋商品名稱或品號...">
<select class="dashboard-select" name="category" onchange="this.form.submit()">
<option value="all">所有分類</option>
{% for cat in categories %}
<option value="{{ cat }}" {% if current_category == cat %}selected{% endif %}>{{ cat }}</option>
{% endfor %}
</select>
<input type="hidden" name="filter" value="{{ current_filter }}">
<input type="hidden" name="sort_by" value="{{ current_sort }}">
<input type="hidden" name="order" value="{{ current_order }}">
<button class="dashboard-action-button" type="submit">
<i class="fas fa-search"></i> 搜尋
</button>
<div class="dashboard-segmented">
<a class="{% if current_filter == 'all' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='all', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">全部</a>
<a class="{% if current_filter == 'ai_picks' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='ai_picks', category=current_category, q=search_query, sort_by='timestamp', order='desc') }}">AI挑品</a>
<a class="{% if current_filter == 'new' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='new', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">新上架</a>
<a class="{% if current_filter == 'increase' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='increase', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">漲價</a>
<a class="{% if current_filter == 'decrease' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='decrease', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">降價</a>
<a class="{% if current_filter == 'delisted' %}is-active{% endif %}" href="{{ url_for('dashboard.index', filter='delisted', category=current_category, q=search_query, sort_by=current_sort, order=current_order) }}">下架</a>
</div>
<button class="dashboard-action-button" type="button" onclick="triggerTask()">
<i class="fas fa-rotate"></i> 更新
</button>
<button class="dashboard-action-button is-primary" type="button" onclick="triggerNotification()">
<i class="fas fa-bell"></i> 發送通知
</button>
</form>
</div>
</section>
<section>
<div class="dashboard-table-card">
<div class="dashboard-table-head">
<span class="momo-mono" style="font-size:11px;font-weight:800;color:var(--momo-text-tertiary);letter-spacing:.08em;">04</span>
<span class="dashboard-table-title">{{ 'AI 挑品清單' if current_filter == 'ai_picks' else '商品列表' }}</span>
<span class="dashboard-table-meta momo-mono">
{% if current_filter == 'ai_picks' %}
{{ total_items | number_format }} / {{ ai_pick_list_limit }} 品
{% else %}
{{ total_items | number_format }} 筆
{% endif %}
</span>
<div class="momo-topbar-spacer"></div>
<a class="dashboard-action-link" href="/api/export/excel/all">
<i class="fas fa-download"></i> 匯出全部
</a>
<a class="dashboard-action-link" href="/api/export/excel/changes">
<i class="fas fa-arrow-trend-up"></i> 匯出漲跌
</a>
{% if current_filter == 'ai_picks' %}
<a class="dashboard-action-link" href="/api/export/excel/ai-picks">
<i class="fas fa-file-excel"></i> 匯出 AI 挑品
</a>
{% endif %}
</div>
{% if current_filter == 'ai_picks' and ai_pick_summary %}
<div class="dashboard-ai-summary-grid">
<div class="dashboard-ai-summary-item">
<div class="dashboard-ai-summary-label">PICK COUNT</div>
<div class="dashboard-ai-summary-value momo-mono">{{ ai_pick_summary.count | number_format }}</div>
<div class="dashboard-ai-summary-sub">目前清單上限 {{ ai_pick_list_limit }} 品</div>
</div>
<div class="dashboard-ai-summary-item">
<div class="dashboard-ai-summary-label">AVG CONFIDENCE</div>
<div class="dashboard-ai-summary-value momo-mono">{{ (ai_pick_summary.avg_confidence * 100) | round(0) | int }}%</div>
<div class="dashboard-ai-summary-sub">高信心 {{ ai_pick_summary.high_confidence_count | number_format }} 品</div>
</div>
<div class="dashboard-ai-summary-item">
<div class="dashboard-ai-summary-label">EVIDENCE</div>
<div class="dashboard-ai-summary-value momo-mono">{{ ai_pick_summary.avg_evidence_quality | round(0) | int }}%</div>
<div class="dashboard-ai-summary-sub">需補證據 {{ ai_pick_summary.needs_evidence_count | number_format }} 品</div>
</div>
<div class="dashboard-ai-summary-item">
<div class="dashboard-ai-summary-label">AVG GAP</div>
<div class="dashboard-ai-summary-value momo-mono">+{{ ai_pick_summary.avg_gap_pct | round(1) }}%</div>
<div class="dashboard-ai-summary-sub">PChome 相對 MOMO 價差</div>
</div>
<div class="dashboard-ai-summary-item">
<div class="dashboard-ai-summary-label">BEST GAP</div>
<div class="dashboard-ai-summary-value momo-mono">+{{ ai_pick_summary.max_gap_pct | round(1) }}%</div>
<div class="dashboard-ai-summary-sub">清單內最大價格優勢</div>
</div>
<div class="dashboard-ai-summary-item">
<div class="dashboard-ai-summary-label">EVIDENCE GAP</div>
<div class="dashboard-ai-summary-value momo-mono">
{% if ai_pick_summary.top_missing_evidence %}
{{ ai_pick_summary.top_missing_evidence[0].count | number_format }}
{% else %}
0
{% endif %}
</div>
<div class="dashboard-ai-summary-sub">
{% if ai_pick_summary.top_missing_evidence %}
{{ ai_pick_summary.top_missing_evidence[0].label }}
{% else %}
暫無待補證據
{% endif %}
</div>
</div>
</div>
{% endif %}
<div class="dashboard-table-wrap">
<table class="dashboard-table {% if current_filter == 'ai_picks' %}is-ai-picks{% endif %}">
<thead>
<tr>
<th>分類</th>
<th>商品名稱</th>
<th class="text-end">
<a href="{{ url_for('dashboard.index', page=1, sort_by='price', order='asc' if current_sort == 'price' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">MOMO 價格</a>
</th>
<th class="text-end">PChome 價格</th>
<th>競價判讀</th>
{% if current_filter == 'ai_picks' %}
<th>AI 建議</th>
{% endif %}
<th class="text-end">
<a href="{{ url_for('dashboard.index', page=1, sort_by='yesterday_change', order='asc' if current_sort == 'yesterday_change' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">昨日漲跌</a>
</th>
<th class="text-end">
<a href="{{ url_for('dashboard.index', page=1, sort_by='week_change', order='asc' if current_sort == 'week_change' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">週漲跌</a>
</th>
<th class="text-end">
<a href="{{ url_for('dashboard.index', page=1, sort_by='timestamp', order='asc' if current_sort == 'timestamp' and current_order == 'desc' else 'desc', category=current_category, filter=current_filter, q=search_query) }}">更新時間</a>
</th>
<th class="text-end">上架時間</th>
</tr>
</thead>
<tbody>
{% for item in items %}
{% set product = item.record.product %}
{% set competitor = item.pchome_competitor %}
{% set decision = item.competitor_decision %}
{% set image_url = product.image_url or ('https://m.momoshop.com.tw/moscdn/goods/' ~ product.i_code ~ '_m.webp') %}
<tr class="is-history-enabled" data-product-id="{{ product.id }}" data-product-name="{{ product.name|e }}" title="點擊查看歷史價格圖表">
<td><span class="dashboard-category">{{ product.category or '未分類' }}</span></td>
<td>
<div class="dashboard-product-cell">
<img class="dashboard-product-thumb" src="{{ image_url }}" alt="{{ product.name }}" loading="lazy" referrerpolicy="no-referrer">
{% set safe_product_url = item.safe_momo_url or '#' %}
<a class="dashboard-product-name momo-tracked-link" href="{{ safe_product_url or '#' }}" target="_blank" rel="noopener noreferrer"
data-momo-original-url="{{ safe_product_url or '#' }}"
data-track-platform="momo"
data-track-source="dashboard-v2-table-main"
data-track-product-id="{{ product.id }}"
data-track-icode="{{ product.i_code }}"
data-track-product-name="{{ product.name|e }}">{{ product.name }}</a>
<div>
<div class="dashboard-platform-links">
<a class="dashboard-platform-link is-momo momo-tracked-link" href="{{ safe_product_url or '#' }}" target="_blank" rel="noopener noreferrer"
data-momo-original-url="{{ safe_product_url or '#' }}"
data-track-platform="momo"
data-track-source="dashboard-v2-table-main"
data-track-product-id="{{ product.id }}"
data-track-icode="{{ product.i_code }}"
data-track-product-name="{{ product.name|e }}">
MOMO {{ product.i_code }}
</a>
{% if competitor and competitor.product_url %}
<a class="dashboard-platform-link is-pchome" href="{{ competitor.product_url }}" target="_blank" rel="noopener noreferrer">
PChome {{ competitor.product_id }}
</a>
{% elif competitor and competitor.product_id %}
<span class="dashboard-platform-muted">PChome {{ competitor.product_id }}</span>
{% else %}
<span class="dashboard-platform-muted">PChome 待比對</span>
{% endif %}
</div>
{% if competitor and competitor.product_name %}
<div class="dashboard-product-id momo-mono" title="{{ competitor.product_name }}">PChome{{ competitor.product_name }}</div>
{% endif %}
{% if item.ai_pick %}
<div class="dashboard-product-id momo-mono" title="{{ item.ai_pick.reason }}">
AI挑品 #{{ item.ai_pick.rank }} · 信心 {{ (item.ai_pick.confidence * 100) | round(0) | int }}% · 證據 {{ item.ai_pick.evidence_quality | round(0) | int }}% · 價差 {{ item.ai_pick.gap_pct | round(1) }}%
</div>
{% endif %}
</div>
</div>
</td>
<td class="text-end">
<button
class="dashboard-history-button"
type="button"
data-history-trigger
data-product-id="{{ product.id }}"
data-product-name="{{ product.name|e }}"
aria-label="查看歷史價格圖表"
>
<span class="dashboard-price momo-mono">${{ item.record.price | int | number_format }}</span>
<i class="fas fa-chart-line" aria-hidden="true"></i>
</button>
</td>
<td class="text-end momo-mono">
{% if competitor and competitor.price %}
<div class="dashboard-pchome-price">${{ competitor.price | int | number_format }}</div>
{% if competitor.match_score %}
<div class="dashboard-price-sub">match {{ (competitor.match_score * 100) | round(0) | int }}%</div>
{% endif %}
{% else %}
<span style="color:var(--momo-text-tertiary);">待比對</span>
{% endif %}
</td>
<td>
<div class="dashboard-competition-card">
<span class="dashboard-competition-badge is-{{ decision.tone }}">{{ decision.label }}</span>
{% if decision.gap_pct is not none %}
<span class="dashboard-competition-meta momo-mono">
MOMO - PChome
{% if decision.gap_amount > 0 %}+{% endif %}${{ decision.gap_amount | round(0) | int | number_format }}
/ {% if decision.gap_pct > 0 %}+{% endif %}{{ decision.gap_pct | round(1) }}%
</span>
{% endif %}
<span class="dashboard-competition-meta">{{ decision.summary }}</span>
</div>
</td>
{% if current_filter == 'ai_picks' %}
<td>
{% if item.ai_pick %}
<div class="dashboard-ai-pick-card">
<div class="dashboard-ai-pick-head">
<span class="dashboard-ai-pick-rank">#{{ item.ai_pick.rank }}</span>
<span class="dashboard-ai-pick-confidence is-{{ item.ai_pick.confidence_band | replace('_', '-') }}">信心 {{ (item.ai_pick.confidence * 100) | round(0) | int }}%</span>
</div>
<div class="dashboard-ai-evidence-line">
<span>機會 {{ item.ai_pick.opportunity_score | round(0) | int }}</span>
<span>證據 {{ item.ai_pick.evidence_quality | round(0) | int }}%</span>
{% if item.ai_pick.margin_rate is not none %}
<span>毛利 {{ item.ai_pick.margin_rate | round(1) }}%</span>
{% endif %}
</div>
<div class="dashboard-ai-pick-reason">{{ item.ai_pick.reason }}</div>
{% if item.ai_pick.missing_evidence %}
<div class="dashboard-ai-evidence-line" title="{{ item.ai_pick.missing_evidence_text }}">
{% for evidence in item.ai_pick.missing_evidence[:3] %}
<span class="dashboard-ai-evidence-chip">{{ evidence }}</span>
{% endfor %}
</div>
{% endif %}
</div>
{% else %}
<span style="color:var(--momo-text-tertiary);">尚無建議理由</span>
{% endif %}
</td>
{% endif %}
<td class="text-end momo-mono">
{% if item.yesterday_diff > 0 %}
<span class="dashboard-change-up">▲ +{{ item.yesterday_diff | abs | int | number_format }}</span>
{% elif item.yesterday_diff < 0 %}
<span class="dashboard-change-down">▼ -{{ item.yesterday_diff | abs | int | number_format }}</span>
{% else %}
<span style="color:var(--momo-text-tertiary);">--</span>
{% endif %}
</td>
<td class="text-end momo-mono">
{% set week_diff = item.stats.get('7d_diff', 0) %}
{% if week_diff > 0 %}
<span class="dashboard-change-up">+{{ week_diff | int | number_format }}</span>
{% elif week_diff < 0 %}
<span class="dashboard-change-down">-{{ week_diff | abs | int | number_format }}</span>
{% else %}
<span style="color:var(--momo-text-tertiary);">--</span>
{% endif %}
</td>
<td class="text-end momo-mono" style="color:var(--momo-text-secondary);">
{{ item.record.timestamp.strftime('%m-%d %H:%M') if item.record.timestamp else '--' }}
</td>
<td class="text-end momo-mono" style="color:var(--momo-text-secondary);">
{{ item.safe_created_at.strftime('%m-%d %H:%M') if item.safe_created_at else '--' }}
</td>
</tr>
{% else %}
<tr>
<td colspan="{{ 10 if current_filter == 'ai_picks' else 9 }}">
<div class="dashboard-empty">
{% if search_query %}
找不到與「{{ search_query }}」相關的商品
{% else %}
目前沒有符合條件的商品
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if total_pages > 1 %}
<div class="dashboard-pagination">
{% if current_page > 1 %}
<a class="dashboard-action-link" href="{{ url_for('dashboard.index', page=current_page - 1, category=current_category, filter=current_filter, q=search_query, sort_by=current_sort, order=current_order) }}">上一頁</a>
{% endif %}
<span class="dashboard-table-meta momo-mono">第 {{ current_page }} / {{ total_pages }} 頁</span>
{% if current_page < total_pages %}
<a class="dashboard-action-link" href="{{ url_for('dashboard.index', page=current_page + 1, category=current_category, filter=current_filter, q=search_query, sort_by=current_sort, order=current_order) }}">下一頁</a>
{% endif %}
</div>
{% endif %}
</div>
</section>
</div>
<div class="modal fade dashboard-history-modal" id="historyModal" tabindex="-1" aria-labelledby="historyModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<div>
<h5 class="modal-title" id="historyModalLabel">歷史價格走勢</h5>
<div class="dashboard-history-subtitle momo-mono" id="historyModalSubtitle">真實價格紀錄</div>
<div class="dashboard-history-range" aria-label="價格歷史區間">
<button type="button" data-history-range="week"></button>
<button class="is-active" type="button" data-history-range="month"></button>
<button type="button" data-history-range="quarter"></button>
<button type="button" data-history-range="year"></button>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="關閉"></button>
</div>
<div class="modal-body">
<div class="dashboard-chart-shell">
<div class="dashboard-chart-state" id="historyChartState">載入價格歷史中...</div>
<canvas class="dashboard-chart-canvas is-hidden" id="priceChart"></canvas>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/page-dashboard-v2.js') }}"></script>
{% endblock %}