chore: curate monthly assessment evidence and scripts

This commit is contained in:
kkfluous
2026-08-25 12:26:35 +08:00
parent 2956496fb0
commit 52dde9195a
117 changed files with 10743 additions and 179 deletions
+269
View File
@@ -0,0 +1,269 @@
#!/usr/bin/env python3
"""用新GPS数据重新生成7月干预情况说明 — 测试里程/实际里程/翻转分析全部更新"""
import openpyxl, os
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
from openpyxl.utils import get_column_letter
from collections import defaultdict
os.chdir('/Users/kkfluous/Downloads')
# ── Styles ──
hdr_blue_font = Font(name='宋体', size=11, bold=True, color='FFFFFF')
hdr_blue_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')
hdr_green_font = Font(name='宋体', size=11, bold=True, color='FFFFFF')
hdr_green_fill = PatternFill(start_color='548235', end_color='548235', fill_type='solid')
hdr_align = Alignment(horizontal='center', vertical='center', wrap_text=True)
data_font = Font(name='宋体', size=10)
data_align = Alignment(horizontal='center', vertical='center')
title_font = Font(name='宋体', size=14, bold=True)
subtitle_font = Font(name='宋体', size=10, bold=True)
yellow_fill = PatternFill(start_color='FFFF00', end_color='FFFF00', fill_type='solid')
light_yellow_fill = PatternFill(start_color='FFF2CC', end_color='FFF2CC', fill_type='solid')
thin_border = Border(left=Side('thin'), right=Side('thin'), top=Side('thin'), bottom=Side('thin'))
def set_cell(ws, row, col, value, font=None, fill=None, align=None, border=None, num_fmt=None):
cell = ws.cell(row=row, column=col, value=value)
if font: cell.font = font
if fill: cell.fill = fill
if align: cell.alignment = align
if border: cell.border = border
if num_fmt: cell.number_format = num_fmt
return cell
# ── Step 1: Extract test plates from July test list ──
print("提取测试车辆清单...")
test_file = '/Users/kkfluous/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/wxid_1704407055112_3af8/temp/RWTemp/2026-08/4340099467fbf08b4c6583c49adba4ee/7月测试车辆明细.xlsx'
wb_old = openpyxl.load_workbook(test_file, data_only=True)
ws_old = wb_old.active
test_plates = set()
for row in ws_old.iter_rows(min_row=2, values_only=True):
p = row[0]
if p: test_plates.add(str(p).strip())
test_plates.discard('粤AG37316')
wb_old.close()
print(f" 测试车辆: {len(test_plates)}")
# ── Step 2: Read NEW source data ──
print("读取新数据源...")
src_fp = '7月核算结果/租赁任务考核_2026年7月.xlsx'
src = openpyxl.load_workbook(src_fp, data_only=True)
ws_src = src['业务考核视图']
h_src = [c.value for c in next(ws_src.iter_rows(min_row=1, max_row=1))]
all_recs = []
for row in ws_src.iter_rows(min_row=2, values_only=True):
r = dict(zip(h_src, row))
if r['车牌号']:
all_recs.append(r)
src.close()
# ── Step 3: Read BACKUP for original comparison ──
print("读取备份(原始仪表盘)...")
bak = openpyxl.load_workbook('7月核算结果/租赁任务考核_2026年7月_原版备份.xlsx', data_only=True)
ws_bak = bak['业务考核视图']
h_bak = [c.value for c in next(ws_bak.iter_rows(min_row=1, max_row=1))]
bak_recs = {}
for row in ws_bak.iter_rows(min_row=2, values_only=True):
r = dict(zip(h_bak, row))
if r['车牌号']:
bak_recs[str(r['车牌号']).strip()] = r
bak.close()
# ── Step 4: Analyze ──
print("分析干预数据...")
intervention_recs = [r for r in all_recs if r['车牌号'] in test_plates]
intervention_plates = set(r['车牌号'] for r in intervention_recs)
# Stats
total_vehicles = len(set(r['车牌号'] for r in all_recs))
total_records = len(all_recs)
interv_vehicles = len(intervention_plates)
interv_records = len(intervention_recs)
total_actual = sum(float(r['实际行驶里程(km)'] or 0) for r in all_recs)
total_tbox = sum(float(r['原TBOX里程(km)'] or 0) for r in all_recs)
total_test = sum(float(r['测试里程(km)'] or 0) for r in all_recs)
interv_actual = sum(float(r['实际行驶里程(km)'] or 0) for r in intervention_recs)
interv_tbox = sum(float(r['原TBOX里程(km)'] or 0) for r in intervention_recs)
interv_test = sum(float(r['测试里程(km)'] or 0) for r in intervention_recs)
# Flip analysis: old达→new未达标
flip_recs = []
for r in intervention_recs:
plate = r['车牌号']
old_rec = bak_recs.get(plate)
if old_rec:
old_q = str(old_rec.get('是否达标', '')).strip() == '达标'
new_q = str(r.get('是否达标', '')).strip() == '达标'
if old_q and not new_q:
flip_recs.append(r)
# Group flip by target
flip_by_target = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
for r in flip_recs:
target = r.get('考核目标', '未知')
dept = r.get('部门名称', '')
sales = r.get('销售经理', '')
flip_by_target[target][dept][sales] += 1
print(f" 全量: {total_vehicles}辆/{total_records}")
print(f" 干预: {interv_vehicles}辆/{interv_records}")
print(f" 达→未达标: {len(flip_recs)}")
print(f" TBOX总计: {total_tbox:.0f}, GPS总计: {total_actual:.0f}, 测试总计: {total_test:.0f}")
# ── Step 5: Build workbook ──
wb = openpyxl.Workbook()
# ===== Sheet 1: 测试与考核情况说明 =====
ws1 = wb.active; ws1.title = '测试与考核情况说明'
for col, w in enumerate([4, 30, 18, 18, 18, 18, 18], 1):
ws1.column_dimensions[get_column_letter(col)].width = w
rn = 1
set_cell(ws1, rn, 1, '2026年7月 业务考核 — 测试与考核情况说明', title_font)
ws1.merge_cells(start_row=rn, start_column=1, end_row=rn, end_column=5); rn += 1
set_cell(ws1, rn, 1, '7月业务考核车辆中,测试车辆统一以指定GPS日里程按考核期汇总替换TBOX里程,差额作为测试里程剥离且最低取0。粤AG37316因GPS缺失,经业务确认暂按0核算。',
Font(name='宋体', size=10), light_yellow_fill)
ws1.merge_cells(start_row=rn, start_column=1, end_row=rn, end_column=5); rn += 2
# Section 1: Stats
set_cell(ws1, rn, 1, '一、7月业务考核与干预情况', subtitle_font); rn += 1
for ci, h in enumerate(['项目', '7月业务考核车辆', '涉及测试的车辆', '占比'], 1):
set_cell(ws1, rn, ci, h, hdr_blue_font, hdr_blue_fill, hdr_align, thin_border)
rn += 1
stats = [
('车辆数(辆)', total_vehicles, interv_vehicles),
('产生考核记录数(条)', total_records, interv_records),
('仪表盘里程(km)', round(total_tbox), round(interv_tbox)),
('业务考核里程 GPS(km)', round(total_actual), round(interv_actual)),
('测试里程(km)', round(total_test), round(interv_test)),
]
for label, all_v, interv_v in stats:
ratio = interv_v / all_v if all_v else 0
set_cell(ws1, rn, 1, label, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 2, all_v, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 3, interv_v, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 4, ratio, data_font, None, data_align, thin_border, '0.00%')
rn += 1
rn += 2
# Section 2: Flip details
set_cell(ws1, rn, 1, '二、干预车辆考核达标情况说明', subtitle_font); rn += 1
flip_total = len(flip_recs)
summary_text = f'{interv_records} 条考核记录涉及里程干预;替换为GPS里程后,共 {flip_total} 条考核车辆记录由"达标"转判为"未达标"。按车型分类如下:'
set_cell(ws1, rn, 1, summary_text, Font(name='宋体', size=10))
ws1.merge_cells(start_row=rn, start_column=1, end_row=rn, end_column=5); rn += 2
target_order = ['羚牛136辆4.5T冷链车', '羚牛100辆18T', '交投40辆4.5T普货', '交投190辆4.5T冷链车', '恒运50辆4.5T普货']
for target in target_order:
if target not in flip_by_target: continue
dept_sales = flip_by_target[target]
total_cnt = sum(sum(sales.values()) for sales in dept_sales.values())
set_cell(ws1, rn, 1, f'{target}{total_cnt} 辆)', subtitle_font)
ws1.merge_cells(start_row=rn, start_column=1, end_row=rn, end_column=5); rn += 1
set_cell(ws1, rn, 1, '部门', hdr_green_font, hdr_green_fill, hdr_align, thin_border)
set_cell(ws1, rn, 2, '销售经理', hdr_green_font, hdr_green_fill, hdr_align, thin_border)
set_cell(ws1, rn, 3, '数量', hdr_green_font, hdr_green_fill, hdr_align, thin_border)
set_cell(ws1, rn, 4, '部门', hdr_green_font, hdr_green_fill, hdr_align, thin_border)
set_cell(ws1, rn, 5, '销售经理', hdr_green_font, hdr_green_fill, hdr_align, thin_border)
set_cell(ws1, rn, 6, '数量', hdr_green_font, hdr_green_fill, hdr_align, thin_border)
rn += 1
items = []
for dept in sorted(dept_sales.keys()):
for sales in sorted(dept_sales[dept].keys()):
items.append((dept, sales, dept_sales[dept][sales]))
mid = (len(items) + 1) // 2
max_rows = max(mid, len(items) - mid)
for i in range(max_rows):
if i < mid:
d1, s1, c1 = items[i]
set_cell(ws1, rn, 1, d1, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 2, s1, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 3, c1, data_font, None, data_align, thin_border)
else:
for c in [1,2,3]: set_cell(ws1, rn, c, '', data_font, None, data_align, thin_border)
if i + mid < len(items):
d2, s2, c2 = items[i + mid]
set_cell(ws1, rn, 4, d2, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 5, s2, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 6, c2, data_font, None, data_align, thin_border)
else:
for c in [4,5,6]: set_cell(ws1, rn, c, '', data_font, None, data_align, thin_border)
rn += 1
rn += 1
rn += 1
# Section 3: Column source explanation
set_cell(ws1, rn, 1, '三、里程三列数据来源说明', subtitle_font); rn += 1
set_cell(ws1, rn, 1, '', hdr_blue_font, hdr_blue_fill, hdr_align, thin_border)
set_cell(ws1, rn, 2, '字段名', hdr_blue_font, hdr_blue_fill, hdr_align, thin_border)
set_cell(ws1, rn, 3, '数据来源', hdr_blue_font, hdr_blue_fill, hdr_align, thin_border)
set_cell(ws1, rn, 4, '说明', hdr_blue_font, hdr_blue_fill, hdr_align, thin_border)
rn += 1
col_descs = [
('O', '原TBOX里程(km)', '车辆 T-Box / 仪表盘读数', '当月仪表总里程(业务系统原始数据),含运营+测试+调试里程。仅干预车辆填充,非干预车辆为空'),
('P', '实际行驶里程(km)', '指定GPS日里程文件', '优先使用智能管车车辆里程日报;缺失车辆由两份里程统计日明细补充,并按考核期逐日汇总。粤AG37316经确认暂按0核算'),
('Q', '测试里程(km)', 'O P(原TBOX GPS,差额)', '仪表盘跑了但 GPS 未记录到的部分,判定为厂内测试/调试/路试等非运营里程,不计入考核。仅干预车辆填充,非干预车辆为0。若差额为负则取0'),
]
for col_letter, name, source, desc in col_descs:
set_cell(ws1, rn, 1, col_letter, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 2, name, data_font, None, Alignment(horizontal='left', vertical='center'), thin_border)
set_cell(ws1, rn, 3, source, data_font, None, data_align, thin_border)
set_cell(ws1, rn, 4, desc, data_font, None, Alignment(horizontal='left', vertical='center', wrap_text=True), thin_border)
ws1.row_dimensions[rn].height = 40
rn += 1
# ===== Sheet 2: 业务考核视图 (full data,干预标黄) =====
ws2 = wb.create_sheet('业务考核视图')
target_order_full = ['车牌号','考核年份','考核月份','部门名称','销售经理','客户名称','合同编号','项目名称',
'考核目标ID','考核目标','考核开始日期','考核结束日期','考核天数','应考核里程(km)',
'原TBOX里程(km)','实际行驶里程(km)','测试里程(km)','完成率(%)','是否达标','考核状态',
'交车日期','预计还车日期','实际还车日期']
for ci, name in enumerate(target_order_full, 1):
set_cell(ws2, 1, ci, name, hdr_blue_font, hdr_blue_fill, hdr_align, thin_border)
for ri, r in enumerate(all_recs, 2):
is_interv = r['车牌号'] in intervention_plates
for ci, name in enumerate(target_order_full, 1):
set_cell(ws2, ri, ci, r.get(name), data_font, yellow_fill if is_interv else None, data_align, thin_border)
for col, w in enumerate([12,8,8,12,10,26,18,22,10,22,13,12,10,14,16,14,14,12,10,8,12,12,12], 1):
ws2.column_dimensions[get_column_letter(col)].width = w
# ===== Sheet 3: 7月业务考核车辆总览 =====
ws3 = wb.create_sheet('7月业务考核车辆总览')
for ci, name in enumerate(target_order_full, 1):
set_cell(ws3, 1, ci, name, hdr_blue_font, hdr_blue_fill, hdr_align, thin_border)
for ri, r in enumerate(all_recs, 2):
for ci, name in enumerate(target_order_full, 1):
set_cell(ws3, ri, ci, r.get(name), data_font, None, data_align, thin_border)
for col, w in enumerate([12,8,8,12,10,26,18,22,10,22,13,12,10,14,16,14,14,12,10,8,12,12,12], 1):
ws3.column_dimensions[get_column_letter(col)].width = w
# ===== Sheet 4: 涉及测试的业务考核车辆 =====
ws4 = wb.create_sheet('涉及测试的业务考核车辆')
for ci, name in enumerate(target_order_full, 1):
set_cell(ws4, 1, ci, name, hdr_blue_font, hdr_blue_fill, hdr_align, thin_border)
for ri, r in enumerate(intervention_recs, 2):
for ci, name in enumerate(target_order_full, 1):
set_cell(ws4, ri, ci, r.get(name), data_font, yellow_fill, data_align, thin_border)
for col, w in enumerate([12,8,8,12,10,26,18,22,10,22,13,12,10,14,16,14,14,12,10,8,12,12,12], 1):
ws4.column_dimensions[get_column_letter(col)].width = w
# ── Save ──
out = '7月核算结果/租赁任务考核_2026年7月_干预情况说明.xlsx'
wb.save(out)
print(f'\n{out}')
print(f'\n概况:')
print(f' 全量: {total_vehicles}辆, {total_records}')
print(f' 干预: {interv_vehicles}辆, {interv_records}')
print(f' 达→未达标: {flip_total}')
print(f' 仪表盘里程: {total_tbox:.0f} (干预{interv_tbox:.0f})')
print(f' GPS里程: {total_actual:.0f} (干预{interv_actual:.0f})')
print(f' 测试里程: {total_test:.0f} (干预{interv_test:.0f})')