Simplify Attendance export status groups to 6 categories: 正常|遲到|早退|加班|異常/缺勤|假期/請假
This commit is contained in:
+36
-22
@@ -3407,31 +3407,45 @@ async def export_excel(
|
|||||||
earliest = min((r.date for r in rows if r.date), default=None)
|
earliest = min((r.date for r in rows if r.date), default=None)
|
||||||
overview.merge_range("F7:G7", earliest.isoformat() if earliest else "-", kpi_value_fmt)
|
overview.merge_range("F7:G7", earliest.isoformat() if earliest else "-", kpi_value_fmt)
|
||||||
|
|
||||||
# Status distribution table (B10:D)
|
# Status distribution table — simplified 6-group (B10:D)
|
||||||
overview.write("B10", "出勤狀態分佈", section_fmt)
|
overview.write("B10", "出勤狀態分佈", section_fmt)
|
||||||
overview.write("B11", "Status", header_fmt_ov)
|
overview.write("B11", "Status", header_fmt_ov)
|
||||||
overview.write("C11", "數量", header_fmt_ov)
|
overview.write("C11", "數量", header_fmt_ov)
|
||||||
overview.write("D11", "百分比", header_fmt_ov)
|
overview.write("D11", "百分比", header_fmt_ov)
|
||||||
status_codes_order = ["normal", "late", "late_early", "late_ot", "early", "early_ot", "ot", "abnormal", "missing",
|
# Simplified 6-group status
|
||||||
"holiday", "al", "sl", "cl", "mixed_leave"]
|
_grp_status = {
|
||||||
status_labels = {
|
"正常": 0, "遲到": 0, "早退": 0, "加班": 0, "異常/缺勤": 0, "假期/請假": 0, "(空)": 0,
|
||||||
"normal": "正常", "late": "遲到", "late_early": "遲到+早走",
|
|
||||||
"late_ot": "遲到+加班", "early": "早走", "early_ot": "早走+加班",
|
|
||||||
"ot": "加班", "abnormal": "異常", "missing": "缺勤",
|
|
||||||
"holiday": "🏖️公假", "al": "年假 AL", "sl": "病假 SL", "cl": "補鐘 CL",
|
|
||||||
"mixed_leave": "混合假",
|
|
||||||
}
|
}
|
||||||
for i, code in enumerate(status_codes_order):
|
for r in rows:
|
||||||
count = sum(1 for r in rows if (r.status_code or "").lower() == code)
|
c = (r.status_code or "").lower()
|
||||||
overview.write(11 + i, 1, status_labels.get(code, code), cell_fmt_ov)
|
if not c.strip():
|
||||||
|
_grp_status["(空)"] += 1
|
||||||
|
elif c == "normal":
|
||||||
|
_grp_status["正常"] += 1
|
||||||
|
elif "late" in c and "early" in c:
|
||||||
|
_grp_status["遲到"] += 1
|
||||||
|
elif "late" in c:
|
||||||
|
_grp_status["遲到"] += 1
|
||||||
|
elif "early" in c:
|
||||||
|
_grp_status["早退"] += 1
|
||||||
|
elif "ot" in c:
|
||||||
|
_grp_status["加班"] += 1
|
||||||
|
elif c in ("abnormal", "missing", "", " "):
|
||||||
|
_grp_status["異常/缺勤"] += 1
|
||||||
|
else:
|
||||||
|
_grp_status["假期/請假"] += 1
|
||||||
|
_total = len(rows)
|
||||||
|
for i, (label, count) in enumerate(_grp_status.items()):
|
||||||
|
overview.write(11 + i, 1, label, cell_fmt_ov)
|
||||||
overview.write(11 + i, 2, count, cell_fmt_ov)
|
overview.write(11 + i, 2, count, cell_fmt_ov)
|
||||||
pct = (count / len(rows) * 100) if rows else 0
|
pct = (count / _total * 100) if _total else 0
|
||||||
overview.write(11 + i, 3, f"{pct:.1f}%", cell_fmt_ov)
|
overview.write(11 + i, 3, f"{pct:.1f}%", cell_fmt_ov)
|
||||||
unk = sum(1 for r in rows if not (r.status_code or "").strip())
|
_n_status_groups = len(_grp_status)
|
||||||
overview.write(11 + len(status_codes_order), 1, "(空)", cell_fmt_ov)
|
# Also update KPI counters to match simplified grouping
|
||||||
overview.write(11 + len(status_codes_order), 2, unk, cell_fmt_ov)
|
n_late_grp = _grp_status["遲到"]
|
||||||
pct_unk = (unk / len(rows) * 100) if rows else 0
|
n_early_grp = _grp_status["早退"]
|
||||||
overview.write(11 + len(status_codes_order), 3, f"{pct_unk:.1f}%", cell_fmt_ov)
|
n_ot_grp = _grp_status["加班"]
|
||||||
|
n_abn_grp = _grp_status["異常/缺勤"]
|
||||||
|
|
||||||
# Department TOP 10 table (F10:G)
|
# Department TOP 10 table (F10:G)
|
||||||
overview.write("F10", "部門記錄數 (TOP 10)", section_fmt)
|
overview.write("F10", "部門記錄數 (TOP 10)", section_fmt)
|
||||||
@@ -3449,8 +3463,8 @@ async def export_excel(
|
|||||||
status_pie = wb.add_chart({"type": "pie"})
|
status_pie = wb.add_chart({"type": "pie"})
|
||||||
status_pie.add_series({
|
status_pie.add_series({
|
||||||
"name": "出勤狀態分佈",
|
"name": "出勤狀態分佈",
|
||||||
"categories": ["總覽", 11, 1, 11 + len(status_codes_order), 1],
|
"categories": ["總覽", 11, 1, 11 + _n_status_groups, 1],
|
||||||
"values": ["總覽", 11, 2, 11 + len(status_codes_order), 2],
|
"values": ["總覽", 11, 2, 11 + _n_status_groups, 2],
|
||||||
"data_labels": {"percentage": True, "category": False, "position": "outside_end"},
|
"data_labels": {"percentage": True, "category": False, "position": "outside_end"},
|
||||||
})
|
})
|
||||||
status_pie.set_title({"name": "出勤狀態分佈 (Pie)"})
|
status_pie.set_title({"name": "出勤狀態分佈 (Pie)"})
|
||||||
@@ -3480,8 +3494,8 @@ async def export_excel(
|
|||||||
status_col_chart = wb.add_chart({"type": "column"})
|
status_col_chart = wb.add_chart({"type": "column"})
|
||||||
status_col_chart.add_series({
|
status_col_chart.add_series({
|
||||||
"name": "出勤狀態 數量",
|
"name": "出勤狀態 數量",
|
||||||
"categories": ["總覽", 11, 1, 11 + len(status_codes_order) - 1, 1],
|
"categories": ["總覽", 11, 1, 11 + _n_status_groups - 1, 1],
|
||||||
"values": ["總覽", 11, 2, 11 + len(status_codes_order) - 1, 2],
|
"values": ["總覽", 11, 2, 11 + _n_status_groups - 1, 2],
|
||||||
"fill": {"color": "#10B981"},
|
"fill": {"color": "#10B981"},
|
||||||
"border": {"color": "#065F46"},
|
"border": {"color": "#065F46"},
|
||||||
"data_labels": {"value": True},
|
"data_labels": {"value": True},
|
||||||
|
|||||||
Reference in New Issue
Block a user