diff --git a/TODO_NEXT_STEPS.txt b/TODO_NEXT_STEPS.txt index e8b4152..76a310f 100644 --- a/TODO_NEXT_STEPS.txt +++ b/TODO_NEXT_STEPS.txt @@ -4,6 +4,10 @@ ================================================================================ 【已完成】 + - V10.151 接續前端 V3 全站 UI/UX:廠商缺貨 `/vendor-stockout/vendor-management`、`/vendor-stockout/send-email`、`/vendor-stockout/history` 改走新版 `ewoooc_base.html` shell 與 `page-vendor-tools.css`,移除舊紫藍 navbar/live route。 + - V10.151 補 `/abc_analysis/detail` 新版 ABC 詳情頁與安全 loading state,移除 raw HTML fallback,資料表維持正式快取資料來源與匯出連結。 + - V10.151 補 `/login` 新版登入頁:暖紙背景、點陣視覺、EwoooC 品牌、手機版 390px 無水平 overflow。 + - V10.151 本機全站 responsive overflow guard 通過 147/147;`?ui=legacy` 入口已不再回到舊 `dashboard.html` / `edm_dashboard.html` / vendor legacy templates。 - 新版設計系統資產已落到正式 Flask static path:`web/static/css/ewoooc-tokens.css`、`web/static/css/ewoooc-shell.css`、`web/static/css/ewoooc-dotmatrix.css`、`web/static/css/page-*.css` 與對應 `web/static/js/page-*.js`。 - V3 page-level 資產已補做設計規範清理:移除 UI 表面殘留 radial-gradient / pure-white rgba / `bg-white` header,AI 推薦頁 keyword 狀態改用語意 class。 - `ewoooc_base.html` 補 `extra_head` / `content` / `extra_scripts` 相容 block,支援新版包混用 block 命名,避免頁面空白或互動 JS 不輸出。 diff --git a/config.py b/config.py index fae4a76..8a116db 100644 --- a/config.py +++ b/config.py @@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.150" +SYSTEM_VERSION = "V10.151" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/routes/dashboard_routes.py b/routes/dashboard_routes.py index 62e9823..89f0b5c 100644 --- a/routes/dashboard_routes.py +++ b/routes/dashboard_routes.py @@ -1461,7 +1461,7 @@ def index(): data['competitor_overview'] = competitor_overview _DASHBOARD_DATA_CACHE['full_data'] = data _write_shared_full_dashboard_cache(data) - template_name = 'dashboard.html' if request.args.get('ui') == 'legacy' else 'dashboard_v2.html' + template_name = 'dashboard_v2.html' return render_template(template_name, total_products=total_products_history, diff --git a/routes/edm_routes.py b/routes/edm_routes.py index 6d8bf6f..beb93d8 100644 --- a/routes/edm_routes.py +++ b/routes/edm_routes.py @@ -374,7 +374,7 @@ def edm_dashboard(): scheduler_stats = load_scheduler_stats() now_taipei = datetime.now(TAIPEI_TZ) - template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html' + template_name = 'edm_dashboard_v2.html' return render_template(template_name, promo_pages=promo_pages, @@ -429,7 +429,7 @@ def festival_dashboard(): scheduler_stats = load_scheduler_stats() - template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html' + template_name = 'edm_dashboard_v2.html' return render_template(template_name, promo_pages=promo_pages, @@ -482,7 +482,7 @@ def mothers_day_dashboard(): scheduler_stats = load_scheduler_stats() - template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html' + template_name = 'edm_dashboard_v2.html' return render_template(template_name, promo_pages=promo_pages, @@ -535,7 +535,7 @@ def valentine_520_dashboard(): scheduler_stats = load_scheduler_stats() - template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html' + template_name = 'edm_dashboard_v2.html' return render_template(template_name, promo_pages=promo_pages, @@ -588,7 +588,7 @@ def labor_day_dashboard(): scheduler_stats = load_scheduler_stats() - template_name = 'edm_dashboard.html' if request.args.get('ui') == 'legacy' else 'edm_dashboard_v2.html' + template_name = 'edm_dashboard_v2.html' return render_template(template_name, promo_pages=promo_pages, diff --git a/routes/sales_routes.py b/routes/sales_routes.py index 627291d..c5658af 100644 --- a/routes/sales_routes.py +++ b/routes/sales_routes.py @@ -1938,45 +1938,19 @@ def abc_analysis_detail(): target_df, cols_map, err = _get_filtered_sales_data(table_name) if err: - # V-Fix: 如果自動重載也失敗,則顯示稍後再試,並引導回主頁面 - return f''' - - - - - 數據加載中 - WOOO TECH - - - -
-
-

數據準備中

-

正在自動重新加載數據,請稍後...

- -
- - - ''', 200 + return render_template( + 'abc_analysis_detail.html', + loading_state=True, + info={'title': '數據準備中', 'desc': '業績分析快取正在重新載入。'}, + items=[], + cols={}, + current_factor=0, + target_class=target_class, + total_revenue=0, + sort_col_index=0, + query_string=request.query_string.decode(), + active_page='sales', + ), 200 # 恢復欄位變數 col_name = cols_map.get('name') @@ -1995,6 +1969,7 @@ def abc_analysis_detail(): # 3. 執行 ABC 分類 items = [] total_revenue = 0 + current_factor = 0.0 if col_amount and not target_df.empty: # V-Fix: 先針對商品進行聚合,確保 ABC 分析是基於「商品總銷量」而非「單筆訂單」 agg_rules = {col_amount: 'sum'} @@ -2081,7 +2056,8 @@ def abc_analysis_detail(): cols={'name': col_name, 'amount': col_amount, 'qty': col_qty, 'cat': col_category, 'vendor': col_vendor, 'brand': col_brand, 'cost': col_cost, 'profit': col_profit, 'date': col_date, 'pid': col_pid}, # 傳遞當前查詢參數以供匯出連結使用 - query_string=request.query_string.decode()) + query_string=request.query_string.decode(), + active_page='sales') except Exception as e: sys_log.error(f"ABC Detail Error: {e}") diff --git a/routes/vendor_routes.py b/routes/vendor_routes.py index 0da4437..ec0f444 100644 --- a/routes/vendor_routes.py +++ b/routes/vendor_routes.py @@ -63,8 +63,6 @@ vendor_db = VendorDatabaseManager() def index(): """廠商缺貨系統主頁""" sys_log.info("[VendorStockout] 進入廠商缺貨系統主頁") - if request.args.get('ui') == 'legacy': - return _render_vendor_template('vendor_stockout/index.html') return render_template( 'vendor_stockout_index_v2.html', active_page='vendor_stockout', @@ -76,8 +74,6 @@ def index(): def import_page(): """Excel 匯入頁面""" sys_log.info("[VendorStockout] 進入匯入頁面") - if request.args.get('ui') == 'legacy': - return _render_vendor_template('vendor_stockout/import.html') return render_template( 'vendor_stockout_import_v2.html', active_page='vendor_stockout' @@ -88,8 +84,6 @@ def import_page(): def list_page(): """缺貨清單頁面""" sys_log.info("[VendorStockout] 進入缺貨清單頁面") - if request.args.get('ui') == 'legacy': - return _render_vendor_template('vendor_stockout/list.html') return render_template( 'vendor_stockout_list_v2.html', active_page='vendor_stockout', @@ -109,21 +103,21 @@ def list_page(): def vendor_management_page(): """廠商管理頁面""" sys_log.info("[VendorStockout] 進入廠商管理頁面") - return _render_vendor_template('vendor_stockout/vendor_management.html') + return render_template('vendor_stockout_vendor_management_v2.html', active_page='vendor_stockout') @vendor_bp.route('/send-email') def send_email_page(): """郵件發送頁面""" sys_log.info("[VendorStockout] 進入郵件發送頁面") - return _render_vendor_template('vendor_stockout/send_email.html') + return render_template('vendor_stockout_send_email_v2.html', active_page='vendor_stockout') @vendor_bp.route('/history') def history_page(): """發送歷史頁面""" sys_log.info("[VendorStockout] 進入發送歷史頁面") - return _render_vendor_template('vendor_stockout/history.html') + return render_template('vendor_stockout_history_v2.html', active_page='vendor_stockout') # ========================================== diff --git a/templates/abc_analysis_detail.html b/templates/abc_analysis_detail.html index 971ce1d..91bc9d3 100644 --- a/templates/abc_analysis_detail.html +++ b/templates/abc_analysis_detail.html @@ -1,196 +1,184 @@ - - - - - - - ABC 分析詳情 - {{ info.title }} - - - - - - - {% include 'components/_navbar.html' %} - -
-
-
-

- {{ info.title }} -

- {{ info.desc }} -
-
- -
- 補貨係數 x - - -
- - - - 匯出此類別報表 - - -
-
- -
-
- - - - - {% if cols.pid %}{% endif %} - - {% if cols.brand %}{% endif %} - {% if cols.vendor %}{% endif %} - {% if cols.cat %}{% endif %} - {% if cols.cost or cols.profit %}{% endif %} - {% if cols.qty %}{% endif %} - {% if cols.qty %}{% endif %} - {% if cols.qty %}{% endif %} - - - - - - {% for item in items %} - - - {% if cols.pid %} - - {% endif %} - - {% if cols.brand %} - - {% endif %} - {% if cols.vendor %} - - {% endif %} - {% if cols.cat %} - - {% endif %} - {% if cols.cost or cols.profit %} - - {% endif %} - {% if cols.qty %} - - {% endif %} - {% if cols.qty %} - - {% endif %} - {% if cols.qty %} - - {% endif %} - - - - {% endfor %} - -
排名商品ID商品名稱品牌廠商名稱分類毛利率平均單價銷售數量建議補貨 (x{{ current_factor }})銷售金額累積營收佔比
{{ loop.index }}{{ item[cols.pid] }} -
- {{ item[cols.name] | e }} -
-
{{ item[cols.brand] }}{{ item[cols.vendor] }}{{ item[cols.cat] }} - {% set margin = item['calculated_margin_rate'] %} - - {{ "{:.1f}%".format(margin) }} - - ${{ "{:,.0f}".format(item['avg_unit_price']) }}{{ "{:,.0f}".format(item[cols.qty]) }} - {% if item['suggested_restock'] > 0 %} - {{ "{:,.0f}".format(item['suggested_restock']) }} - {% else %} - 建議清倉 - {% endif %} - - ${{ "{:,.0f}".format(item[cols.amount]) }} - - {{ "{:.2f}%".format(item['cumulative_pct']) }} -
-
-
+{% block content %} +
+ {% if loading_state|default(false) %} +
+ +
+

數據準備中

+

正在重新載入業績分析快取,稍後會自動重試。

+
+ 回業績分析
+ {% else %} +
+
+ + + ABC Analysis + +

{{ info.title }}

+

{{ info.desc }}

+
+ + + 總營收 ${{ "{:,.0f}".format(total_revenue|default(0)) }} + + + + {{ items|length }} 個商品 + +
+
- - - - +{% else %} + + + + - - \ No newline at end of file + }, + pageLength: 25, + lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, '全部']], + order: [[sortColIndex, 'desc']], + paging: true, + info: true + }); + }); + + function applyFactor() { + const factor = document.getElementById('restockFactor').value; + const url = new URL(window.location.href); + url.searchParams.set('factor', factor); + window.location.href = url.toString(); + } + +{% endif %} +{% endblock %} diff --git a/templates/login.html b/templates/login.html index 07bad6d..563eb4c 100644 --- a/templates/login.html +++ b/templates/login.html @@ -3,224 +3,325 @@ - 登入 - WOOO TECH + 登入 - EwoooC + + + + + + -