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
+264
View File
@@ -0,0 +1,264 @@
#!/usr/bin/env python3
"""
从本地GPS数据(G7)整合6月GPS里程,替换测试车辆实际行驶里程
测试里程 = TBOX总里程 - GPS总里程(负数为0)
重新核算6月里程考核,输出到 ./20260713_1500/
"""
import openpyxl, os, shutil
from datetime import datetime, date
from openpyxl.styles import PatternFill, Font, Alignment, Border, Side
from openpyxl.utils import get_column_letter
os.chdir('/Users/kkfluous/Downloads')
SRC = '租赁任务考核_2026年6月 (1).xlsx'
DST = '租赁任务考核_2026年6月.xlsx'
GPS_DIR = 'gps里程汇总2026年1-6月 3'
# 36辆测试车辆
TEST_PLATES = {
'粤AGE5480','粤AGF4535','粤AGG3490','粤AGG4135','粤AGG4191',
'粤AGP2033','粤AGP3080','粤AGP3663','粤AGP3676','粤AGP5139',
'粤AGP5156','粤AGP5163','粤AGP5168','粤AGP5636','粤AGP5767',
'粤AGP5768','粤AGP5796','粤AGP9733','粤AGP9786','粤AGR0298',
'粤AGR1586','粤AGR3288','粤AGR5056','粤AGR5068','粤AGR5088',
'粤AGR6869','粤AGR6877','粤AGR6879','粤AGR6881','粤AGR8506',
'粤AGR8551','粤AGR8558','粤AGR8799','粤AGR9866','粤AGR9893',
'粤AGR9899',
}
# ========== Step 1: 加载G7 GPS日里程数据 ==========
print("=" * 60)
print("Step 1: 加载G7 GPS日里程数据")
print("=" * 60)
g7_wb = openpyxl.load_workbook(f'{GPS_DIR}/G7/202606_G7.xlsx')
g7_ws = g7_wb.active
# G7格式: 车牌号(0), 机构(1), 行驶里程(2), 06月01日(3)...06月30日(32), 运行时长(33), 数据完整度说明(34)
gps_daily = {} # plate -> [day1_km, day2_km, ..., day30_km]
gps_monthly = {} # plate -> monthly_total_km
no_data_plates = set()
for row in g7_ws.iter_rows(min_row=2, values_only=True):
plate = str(row[0]).strip() if row[0] else ''
if not plate:
continue
monthly_km = float(row[2]) if row[2] else 0
daily = []
for c in range(3, 33): # 06月01日 to 06月30日
daily.append(float(row[c]) if row[c] else 0)
gps_daily[plate] = daily
gps_monthly[plate] = monthly_km
g7_wb.close()
print(f"G7加载完成: {len(gps_daily)}辆车")
# ========== Step 2: 读取源文件,执行GPS替换 ==========
print("\n" + "=" * 60)
print("Step 2: GPS里程替换")
print("=" * 60)
# 备份现有文件
BAK = '租赁任务考核_2026年6月_备份_0715.xlsx'
if os.path.exists(DST):
shutil.copy2(DST, BAK)
print(f'已备份: {BAK}')
# 从原始新文件开始
shutil.copy2(SRC, DST)
print(f'源文件: {SRC}{DST}')
wb = openpyxl.load_workbook(DST)
ws = wb['业务考核视图']
h = [c.value for c in next(ws.iter_rows(min_row=1, max_row=1))]
print(f'列数: {len(h)}')
# 读取所有记录
recs = []
for row in ws.iter_rows(min_row=2, values_only=True):
r = dict(zip(h, row))
r['row_num'] = len(recs) + 2
recs.append(r)
# 找测试车辆记录
test_recs = [r for r in recs if r['车牌号'] in TEST_PLATES]
print(f'测试车辆记录: {len(test_recs)}条 ({len(set(r["车牌号"] for r in test_recs))}辆)')
# 添加 原TBOX里程(km) 和 测试里程(km) 列
if '原TBOX里程(km)' not in h:
tbox_new_col = ws.max_column + 1
test_new_col = ws.max_column + 2
ws.cell(row=1, column=tbox_new_col, value='原TBOX里程(km)')
ws.cell(row=1, column=test_new_col, value='测试里程(km)')
h_new = [c.value for c in next(ws.iter_rows(min_row=1, max_row=1))]
else:
h_new = h
actual_idx = h_new.index('实际行驶里程(km)') + 1
tbox_idx = h_new.index('原TBOX里程(km)') + 1
test_idx = h_new.index('测试里程(km)') + 1
rate_idx = h_new.index('完成率(%)') + 1
qualified_idx = h_new.index('是否达标') + 1
yellow_fill = PatternFill(start_color='FFFF00', end_color='FFFF00', fill_type='solid')
DAYSM = {1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30}
replaced = 0
no_gps = 0
no_gps_plates = set()
for r in test_recs:
plate = r['车牌号']
rn = r['row_num']
# 获取考核起止日期
start_date = r.get('考核开始日期')
end_date = r.get('考核结束日期')
if plate not in gps_daily:
no_gps += 1
no_gps_plates.add(plate)
continue
daily = gps_daily[plate]
# 计算考核区间内的GPS总里程
if start_date and end_date:
try:
sd = start_date.date() if hasattr(start_date, 'date') else datetime.strptime(str(start_date)[:10], '%Y-%m-%d').date()
ed = end_date.date() if hasattr(end_date, 'date') else datetime.strptime(str(end_date)[:10], '%Y-%m-%d').date()
except:
sd = date(2026, 6, 1)
ed = date(2026, 6, 30)
else:
sd = date(2026, 6, 1)
ed = date(2026, 6, 30)
# 汇总考核区间内的GPS日里程(G7日数据索引: 0=6/1, 29=6/30
gps_total = 0
for day_offset in range(30):
day = date(2026, 6, 1) + date.resolution * day_offset # timedelta
from datetime import timedelta
day = date(2026, 6, 1) + timedelta(days=day_offset)
if sd <= day <= ed:
gps_total += daily[day_offset]
gps_total = round(gps_total, 1)
# 原TBOX里程 = 当前实际行驶里程
tbox_val = float(ws.cell(row=rn, column=actual_idx).value or 0)
# 测试里程 = TBOX - GPS(负数为0
test_km = max(0, round(tbox_val - gps_total, 1))
# 写入
ws.cell(row=rn, column=tbox_idx, value=tbox_val)
ws.cell(row=rn, column=test_idx, value=test_km)
ws.cell(row=rn, column=actual_idx, value=gps_total)
# 标记黄色
for c in range(1, ws.max_column + 1):
ws.cell(row=rn, column=c).fill = yellow_fill
# 重算完成率
target = float(r.get('应考核里程(km)') or 0)
pct = round(gps_total / target * 100, 2) if target > 0 else 0
qualified = '达标' if gps_total >= target and target > 0 else '未达标'
ws.cell(row=rn, column=rate_idx, value=pct)
ws.cell(row=rn, column=qualified_idx, value=qualified)
replaced += 1
print(f" {plate}: TBOX={tbox_val}, GPS={gps_total}, 测试={test_km}, 达标={qualified}")
print(f'\nGPS替换: 成功{replaced}条, 无GPS数据{no_gps}')
if no_gps_plates:
print(f'无GPS数据车牌: {sorted(no_gps_plates)}')
# ========== Step 3: TBOX回填(非测试车辆) ==========
print("\n" + "=" * 60)
print("Step 3: TBOX回填(非测试车辆)")
print("=" * 60)
filled = 0
for row_idx in range(2, ws.max_row + 1):
tbox_val = ws.cell(row=row_idx, column=tbox_idx).value
actual_val = ws.cell(row=row_idx, column=actual_idx).value
test_val = ws.cell(row=row_idx, column=test_idx).value
if (tbox_val is None or float(tbox_val) == 0):
if test_val is None or float(test_val) == 0:
ws.cell(row=row_idx, column=tbox_idx, value=float(actual_val) if actual_val else 0)
filled += 1
print(f'TBOX回填: {filled}')
# ========== Step 4: 列序排版 ==========
print("\n" + "=" * 60)
print("Step 4: 列序排版")
print("=" * 60)
target_order = [
'车牌号', '考核年份', '考核月份', '部门名称', '销售经理', '客户名称',
'合同编号', '项目名称', '考核目标ID', '考核目标', '考核开始日期', '考核结束日期',
'考核天数', '应考核里程(km)', '原TBOX里程(km)', '实际行驶里程(km)', '测试里程(km)',
'完成率(%)', '是否达标', '考核状态', '交车日期', '预计还车日期', '实际还车日期'
]
# Read all data with styles
h_cur = [c.value for c in next(ws.iter_rows(min_row=1, max_row=1))]
all_rows = []
for row_idx in range(1, ws.max_row + 1):
row_data = {}
for c in range(1, ws.max_column + 1):
row_data[h_cur[c-1]] = ws.cell(row=row_idx, column=c).value
all_rows.append(row_data)
# Clear sheet
for r in range(1, ws.max_row + 1):
for c in range(1, ws.max_column + 1):
ws.cell(row=r, column=c, value=None)
# Apply styles
thin_border = Border(left=Side(style='thin'), right=Side(style='thin'),
top=Side(style='thin'), bottom=Side(style='thin'))
header_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')
header_font = Font(name='宋体', size=10, bold=True, color='FFFFFF')
data_font = Font(name='宋体', size=10)
# Write headers
for i, col_name in enumerate(target_order):
c = i + 1
cell = ws.cell(row=1, column=c, value=col_name)
cell.font = header_font
cell.fill = header_fill
cell.alignment = Alignment(horizontal='center', vertical='center')
cell.border = thin_border
# Write data
for row_idx, row_data in enumerate(all_rows[1:], start=2):
for i, col_name in enumerate(target_order):
c = i + 1
val = row_data.get(col_name)
cell = ws.cell(row=row_idx, column=c, value=val)
cell.font = data_font
cell.alignment = Alignment(vertical='center')
cell.border = thin_border
if col_name in ['考核开始日期', '考核结束日期', '交车日期', '预计还车日期', '实际还车日期']:
cell.number_format = 'yyyy-mm-dd h:mm:ss'
# Restore yellow fill for test vehicles
if row_data.get('测试里程(km)') and float(row_data.get('测试里程(km)', 0) or 0) != 0:
cell.fill = yellow_fill
for i in range(len(target_order)):
ws.column_dimensions[get_column_letter(i+1)].width = 15
wb.save(DST)
wb.close()
print(f'列序排版完成 ({len(target_order)}列)')
print(f'已保存: {DST}')
print("\n" + "=" * 60)
print("GPS替换完成!接下来运行 main.py...")
print("=" * 60)