refactor(p1-01b): app.py 文字/顏色/數字工具抽到 utils/text_helpers.py
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m7s
- slugify, get_color_for_string, extract_snapshot_date_from_filename, number_format
- @app.template_filter('number_format') 保留為 Jinja 註冊薄殼,實作走 utils
- app.py: 7,206 → 7,187 (-19)
This commit is contained in:
39
app.py
39
app.py
@@ -496,10 +496,8 @@ for _bp_module, _bp_name in [
|
||||
except Exception as _e:
|
||||
sys_log.error(f"[Blueprint] ❌ {_bp_name} 註冊失敗: {_e}")
|
||||
|
||||
# V-Fix: 註冊 slugify 函數供模板使用,解決 'slugify is undefined' 錯誤
|
||||
def slugify(text):
|
||||
if not text: return ""
|
||||
return str(text).replace(' ', '_').replace(':', '').replace('!', '').replace('?', '').replace('/', '').replace('&', '').replace('(', '').replace(')', '').replace('+', '_').replace('.', '_').replace('%', '').replace("'", "")
|
||||
# V-Fix: 註冊 slugify 函數供模板使用(實作搬至 utils/text_helpers.py)
|
||||
from utils.text_helpers import slugify # noqa: E402
|
||||
|
||||
LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log')
|
||||
public_url = "服務啟動中..."
|
||||
@@ -552,35 +550,18 @@ def load_scheduler_stats():
|
||||
|
||||
# ================= 🛠️ 數據處理核心 (封裝) =================
|
||||
|
||||
def get_color_for_string(s):
|
||||
"""為字串生成一個穩定且美觀的 HSL 顏色"""
|
||||
if not s: return "hsl(0, 0%, 85%)" # 預設灰色
|
||||
# 使用 md5 hash 確保顏色穩定,並映射到 HSL 色彩空間以獲得柔和色彩
|
||||
hash_val = int(hashlib.md5(s.encode('utf-8'), usedforsecurity=False).hexdigest(), 16)
|
||||
hue = hash_val % 360
|
||||
return f"hsl({hue}, 60%, 88%)"
|
||||
# 純工具:實作已搬至 utils/text_helpers.py
|
||||
from utils.text_helpers import ( # noqa: E402
|
||||
get_color_for_string,
|
||||
extract_snapshot_date_from_filename,
|
||||
number_format as _number_format,
|
||||
)
|
||||
|
||||
def extract_snapshot_date_from_filename(filename):
|
||||
"""從檔名提取日期:即時業績_當日_20260111.xlsx → 2026-01-11"""
|
||||
match = re.search(r'(\d{8})', filename)
|
||||
if match:
|
||||
date_str = match.group(1) # '20260111'
|
||||
try:
|
||||
# 轉換為 YYYY-MM-DD 格式
|
||||
year = date_str[:4]
|
||||
month = date_str[4:6]
|
||||
day = date_str[6:8]
|
||||
return f"{year}-{month}-{day}"
|
||||
except:
|
||||
return None
|
||||
return None
|
||||
|
||||
@app.template_filter('number_format')
|
||||
def number_format_filter(value):
|
||||
"""V9.61: 將數字格式化,加上千分位符號。"""
|
||||
if isinstance(value, (int, float)):
|
||||
return "{:,.0f}".format(value)
|
||||
return value
|
||||
"""Jinja filter wrapper — 實作見 utils.text_helpers.number_format。"""
|
||||
return _number_format(value)
|
||||
|
||||
# V-Refactor: 將 find_col 移至全域,方便多個函式共用
|
||||
from utils.df_helpers import find_col # noqa: E402
|
||||
|
||||
58
utils/text_helpers.py
Normal file
58
utils/text_helpers.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""文字 / 顏色 / 檔名 / 數字格式化工具。
|
||||
|
||||
從 app.py 抽出的純函數,無外部副作用。
|
||||
"""
|
||||
import hashlib
|
||||
import re
|
||||
|
||||
|
||||
def slugify(text):
|
||||
"""將任意字串轉為適合用於 HTML id / URL 的 slug。"""
|
||||
if not text:
|
||||
return ""
|
||||
return (
|
||||
str(text)
|
||||
.replace(' ', '_')
|
||||
.replace(':', '')
|
||||
.replace('!', '')
|
||||
.replace('?', '')
|
||||
.replace('/', '')
|
||||
.replace('&', '')
|
||||
.replace('(', '')
|
||||
.replace(')', '')
|
||||
.replace('+', '_')
|
||||
.replace('.', '_')
|
||||
.replace('%', '')
|
||||
.replace("'", "")
|
||||
)
|
||||
|
||||
|
||||
def get_color_for_string(s):
|
||||
"""為字串生成一個穩定且美觀的 HSL 顏色(柔和淺色,適合背景)。"""
|
||||
if not s:
|
||||
return "hsl(0, 0%, 85%)" # 預設灰色
|
||||
hash_val = int(hashlib.md5(s.encode('utf-8'), usedforsecurity=False).hexdigest(), 16)
|
||||
hue = hash_val % 360
|
||||
return f"hsl({hue}, 60%, 88%)"
|
||||
|
||||
|
||||
def extract_snapshot_date_from_filename(filename):
|
||||
"""從檔名提取 8 碼日期:即時業績_當日_20260111.xlsx → 2026-01-11。"""
|
||||
match = re.search(r'(\d{8})', filename)
|
||||
if not match:
|
||||
return None
|
||||
date_str = match.group(1)
|
||||
try:
|
||||
year = date_str[:4]
|
||||
month = date_str[4:6]
|
||||
day = date_str[6:8]
|
||||
return f"{year}-{month}-{day}"
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def number_format(value):
|
||||
"""將數字格式化,加上千分位符號(無小數)。非數字直接回傳原值。"""
|
||||
if isinstance(value, (int, float)):
|
||||
return "{:,.0f}".format(value)
|
||||
return value
|
||||
Reference in New Issue
Block a user