1 Commits

Author SHA1 Message Date
kkfluous
4c43c00e73 feat: 车辆考核追踪sheet美化
- 达标月份绿底✓,未达标红底✗
- 累计达标/未达标加粗+颜色
- 有发放的行金底高亮
- 奖金池已发期数蓝底加粗,显示为"N/12"格式
- 车辆基本信息列浅灰底色区分
- 冻结首行+首列,支持滚动查看
- 开启自动筛选
- 优化列宽

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:02:50 +08:00

View File

@@ -341,18 +341,33 @@ def write_salesperson_sheet(wb, person, dept, settle_month, D, G, month_data, ve
def write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info): def write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info):
ws = wb.create_sheet('车辆考核追踪') ws = wb.create_sheet('车辆考核追踪')
wrap_align = Alignment(wrap_text=True, vertical='top') from calc_engine import VEHICLE_TARGET_MAP
# 表头:每月用一列"业务员/里程/目标/达标"(多人换行) wrap_top = Alignment(wrap_text=True, vertical='top')
headers = ['车牌号','车架号','归属公司','车型','考核目标','月度奖励金额'] center_top = Alignment(horizontal='center', vertical='top')
# 颜色
green_font = Font(color='006100')
green_fill = PatternFill(start_color='C6EFCE', end_color='C6EFCE', fill_type='solid')
red_font = Font(color='9C0006')
red_fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')
grey_fill = PatternFill(start_color='F2F2F2', end_color='F2F2F2', fill_type='solid')
blue_fill = PatternFill(start_color='DAEEF3', end_color='DAEEF3', fill_type='solid')
gold_fill = PatternFill(start_color='FFF2CC', end_color='FFF2CC', fill_type='solid')
# 表头
headers = ['车牌号','车架号','归属公司','车型','考核目标','月度奖励']
month_start_col = len(headers) # 月度考核开始列(0-indexed)
for m in range(1, settle_month+1): for m in range(1, settle_month+1):
headers.append(f'{m}月考核明细') headers.append(f'{m}月考核明细')
cum_start_col = len(headers)
if settle_month >= 2: if settle_month >= 2:
headers += ['累计里程/目标','累计达标'] headers += ['累计里程/目标','累计达标']
headers += ['本月发放明细','累计已发期数','累计已发金额','剩余可发期数'] pay_start_col = len(headers)
headers += ['本月发放明细','已发期数','已发金额','剩余期数']
WH(ws, headers) WH(ws, headers)
from calc_engine import VEHICLE_TARGET_MAP, RULES # 冻结首行+首列
ws.freeze_panes = 'B2'
rn=2 rn=2
for mv in master_vehicles: for mv in master_vehicles:
@@ -360,7 +375,6 @@ def write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_p
info=vehicle_info.get(plate, {}) info=vehicle_info.get(plate, {})
pays=vehicle_payments.get(plate, []) pays=vehicle_payments.get(plate, [])
# 补全缺失的考核目标
target_name = info.get('考核目标','') target_name = info.get('考核目标','')
monthly_bonus = info.get('月度奖励',0) monthly_bonus = info.get('月度奖励',0)
if not target_name: if not target_name:
@@ -374,46 +388,98 @@ def write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_p
target_name or '',monthly_bonus or ''] target_name or '',monthly_bonus or '']
cum_t=0; cum_a=0 cum_t=0; cum_a=0
month_qualified = {} # {月份: bool}
for m in range(1, settle_month+1): for m in range(1, settle_month+1):
mgs=[(k,g) for k,g in G.get(m,{}).items() if k[0]==plate] mgs=[(k,g) for k,g in G.get(m,{}).items() if k[0]==plate]
if mgs: if mgs:
# 每个(车牌,销售)组一行,换行显示
lines = [] lines = []
any_q = False
for _,g in sorted(mgs, key=lambda x: x[0][1]): for _,g in sorted(mgs, key=lambda x: x[0][1]):
t=g['应考核']; a=g['实际'] t=g['应考核']; a=g['实际']
cum_t+=t; cum_a+=a cum_t+=t; cum_a+=a
q='达标' if g['有达标'] else '未达标' q = g['有达标']
if q: any_q = True
sd = g['部门'].replace('业务','') if '业务' in g.get('部门','') else g.get('部门','') sd = g['部门'].replace('业务','') if '业务' in g.get('部门','') else g.get('部门','')
lines.append(f"{sd}-{g['销售']}: {R(a,0)}/{R(t,0)} {q}") lines.append(f"{sd}-{g['销售']}: {R(a,0)}/{R(t,0)} {'' if q else ''}")
row.append('\n'.join(lines)) row.append('\n'.join(lines))
month_qualified[m] = any_q
else: else:
row.append('') row.append('')
month_qualified[m] = None # 无数据
cum_q = False
if settle_month>=2: if settle_month>=2:
cum_q='达标' if (cum_a>=cum_t and cum_t>0) else '未达标' cum_q = cum_a>=cum_t and cum_t>0
row+=[f'{R(cum_a,0)}/{R(cum_t,0)}', cum_q] row+=[f'{R(cum_a,0)}/{R(cum_t,0)}', '✓ 达标' if cum_q else '✗ 未达标']
# 本月发放明细(多人多类型换行) # 本月发放
tp=[p for p in pays if p['结算月']==settle_month] tp=[p for p in pays if p['结算月']==settle_month]
if tp: if tp:
pay_lines = [] pay_lines = []
for p in sorted(tp, key=lambda x: x['业务员']): for p in sorted(tp, key=lambda x: x['业务员']):
pd = p.get('部门','').replace('业务','') if '业务' in p.get('部门','') else p.get('部门','') pd = p.get('部门','').replace('业务','') if '业务' in p.get('部门','') else p.get('部门','')
pay_lines.append(f"{pd}-{p['业务员']}: {R(p['金额'])}({p['类型']})") pay_lines.append(f"{pd}-{p['业务员']}: {R(p['金额'])}({p['类型']})")
row.append('\n'.join(pay_lines)) row.append('\n'.join(pay_lines))
else: else:
row.append('') row.append('')
# 奖金池截至settle_month
pays_to_date=[p for p in pays if p['结算月']<=settle_month] pays_to_date=[p for p in pays if p['结算月']<=settle_month]
tp_count=len(pays_to_date); tp_amt=sum(p['金额'] for p in pays_to_date) tp_count=len(pays_to_date); tp_amt=sum(p['金额'] for p in pays_to_date)
row+=[tp_count,R(tp_amt) if tp_amt>0 else 0,12-tp_count] row+=[f'{tp_count}/12', R(tp_amt) if tp_amt>0 else 0, 12-tp_count]
WR(ws,rn,row) WR(ws,rn,row)
# 对含换行的单元格设置自动换行
for ci in range(len(row)): # --- 美化 ---
cell = ws.cell(row=rn, column=ci+1) # 车辆基本信息列:浅灰底色
if isinstance(cell.value, str) and '\n' in cell.value: for ci in range(1, month_start_col+1):
cell.alignment = wrap_align ws.cell(row=rn, column=ci).fill = grey_fill
# 月度考核列:达标绿底/未达标红底
for mi, m in enumerate(range(1, settle_month+1)):
col = month_start_col + mi + 1
cell = ws.cell(row=rn, column=col)
cell.alignment = wrap_top
if month_qualified.get(m) == True:
cell.fill = green_fill; cell.font = green_font
elif month_qualified.get(m) == False:
cell.fill = red_fill; cell.font = red_font
# 累计列
if settle_month >= 2:
cum_cell = ws.cell(row=rn, column=cum_start_col+2) # 累计达标列
if cum_q:
cum_cell.fill = green_fill; cum_cell.font = Font(bold=True, color='006100')
elif cum_t > 0:
cum_cell.fill = red_fill; cum_cell.font = Font(bold=True, color='9C0006')
# 发放列:有发放金底
pay_cell = ws.cell(row=rn, column=pay_start_col+1)
pay_cell.alignment = wrap_top
if tp:
pay_cell.fill = gold_fill
# 奖金池:已发期数列
period_cell = ws.cell(row=rn, column=pay_start_col+2)
period_cell.alignment = center_top
if tp_count > 0:
period_cell.fill = blue_fill; period_cell.font = Font(bold=True)
rn+=1 rn+=1
AW(ws)
# 列宽
col_widths = {'A':12,'B':20,'C':20,'D':12,'E':20,'F':8}
for col_letter, w in col_widths.items():
ws.column_dimensions[col_letter].width = w
# 月度考核列宽
for mi in range(settle_month):
col_letter = chr(ord('G') + mi)
ws.column_dimensions[col_letter].width = 30
# 剩余列自动
remaining_start = ord('G') + settle_month
for i in range(8):
cl = chr(remaining_start + i)
if cl <= 'Z':
ws.column_dimensions[cl].width = 16
# 自动筛选
ws.auto_filter.ref = f"A1:{chr(ord('A')+len(headers)-1)}1"