根据execl报表数据及汇总报表模板生成当月汇总数据

一、报表数据格式及模板格式

        所有文件:

.py文件执行程序;

output.txt程序执行的日志;

run.bat双击自动执行.py文件;

两个  11月25日  的问题数报表数据样例;

最后一个是汇总文件模板;

        报表数据格式样例:

        汇总报表格式样例:

二、参考代码

2.1 run.bat

CALL C:\ProgramData\anaconda3\Scripts\activate.bat C:\ProgramData\anaconda3
@echo off
python detect_statistics.py > output.txt 2>&1
echo

2.2 .py执行脚本

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time        :2024/11/25 10:19
# @Author      :weiz
# @ProjectName :weizTools
# @File        :detect_statistics.py
# @Description :
import openpyxl
import pandas as pd
import re
from openpyxl import load_workbook
import os
from datetime import datetime
import json
import shutil


def readLineTXT(path):
    """
    按行读取txt文件
    :param path:
    :return:
    """
    txtLines = []
    file = open(path)
    for line in file:
        line = line.strip('\n')
        txtLines.append(line)
    file.close()
    return txtLines


def get_month():
    now = datetime.now()
    current_month = now.strftime('%m')
    return current_month


def num_to_excel_col(n):
    """
    将数字索引转换为Excel列的字母表示。
    :param n: 数字索引(从1开始)
    :return: Excel列的字母表示
    """
    result = ""
    while n > 0:
        n, remainder = divmod(n - 1, 26)
        result = chr(65 + remainder) + result
    return result


def excel_filterAndSummary(table_data, error_list_type, detect_result_name="检测结果", detect_result_name_value="NOK"):
    table_data_values = table_data.values

    ind_detect_result_name = -1
    ind_car_type = -1
    ind_error_type = -1
    ind_error_detail = -1
    ind_VIN = -1

    for ind, column_name_tmp in enumerate(table_data.head(1)):
        if column_name_tmp == detect_result_name:
            ind_detect_result_name = ind
        if column_name_tmp == "车型":
            ind_car_type = ind
        if column_name_tmp == "错误类型":
            ind_error_type = ind
        if column_name_tmp == "错误详情":
            ind_error_detail = ind
        if column_name_tmp == "VIN":
            ind_VIN = ind

    if ((ind_detect_result_name < 0) or (ind_car_type < 0) or (ind_error_type < 0) or (ind_error_detail < 0) or
            (ind_VIN < 0)):
        print("execl表中的未查询到[{},{},{},{},{}]中的其中一种".format(detect_result_name, "车型", "错误类型",
                                                                       "错误详情", "VIN"))
        return {}

    dest_excel_data = table_data_values[table_data_values[:, ind_detect_result_name] == detect_result_name_value]

    vin_statistics_nok = {}
    vin_statistics_ok = {}
    for table_line in table_data_values:
        nok_and_ok = table_line[ind_detect_result_name]
        vin = table_line[ind_VIN]
        car_type = table_line[ind_car_type]
        error_type = table_line[ind_error_type]
        error_detail = table_line[ind_error_detail]

        vin_new = vin + ' ' + car_type
        if nok_and_ok == detect_result_name_value:
            if vin_new in vin_statistics_nok:  # 统计单个vin码有多少错误类型
                if error_type in vin_statistics_nok[vin_new]:
                    vin_statistics_nok[vin_new][error_type] = vin_statistics_nok[vin_new][error_type] + 1
                else:
                    vin_statistics_nok[vin_new][error_type] = 1
            else:
                vin_statistics_nok[vin_new] = {}
                vin_statistics_nok[vin_new][error_type] = 1
        else:
            if vin_new in vin_statistics_ok:
                vin_statistics_ok[vin_new] = vin_statistics_ok[vin_new] + 1
            else:
                vin_statistics_ok[vin_new] = 1

    total_number_nok = len(vin_statistics_nok)
    total_number = total_number_nok + len(vin_statistics_ok)
    print("   过滤结果:{} {}项,vin码归并后有 {} 项, vin总项为 {} 项".format(detect_result_name_value,
                                                       len(dest_excel_data), total_number_nok, total_number))

    table_data_statistics_not = {}
    for dict_key in vin_statistics_nok:
        error_type = ""
        is_find_error_type = False
        for error_type_tmp in error_list_type:  # 遍历错误类型确定最终的错误
            for error_type_tmp_tmp in error_type_tmp:
                if error_type_tmp_tmp in vin_statistics_nok[dict_key]:
                    # print(ind, error_type_tmp)
                    error_type = error_type_tmp[-1]
                    is_find_error_type = True
                    break

            if is_find_error_type:
                break

        if error_type:
            vin, car_type = dict_key.split(' ')
            if car_type in table_data_statistics_not:
                if error_type in table_data_statistics_not[car_type]:
                    table_data_statistics_not[car_type][error_type] = table_data_statistics_not[car_type][error_type] + 1
                else:
                    table_data_statistics_not[car_type][error_type] = 1
            else:
                table_data_statistics_not[car_type] = {}
                table_data_statistics_not[car_type][error_type] = 1

        else:
            print("数据标注出现未知的错误类型:{}".format(vin_statistics_nok[dict_key]))

    table_data_statistics_ok = {}
    for dict_key in vin_statistics_ok:
        vin, car_type = dict_key.split(' ')
        if car_type in table_data_statistics_ok:
            table_data_statistics_ok[car_type] = table_data_statistics_ok[car_type] + 1
        else:
            table_data_statistics_ok[car_type] = 1

    # print(table_data_statistics)
    return table_data_statistics_not, table_data_statistics_ok


def read_summary_execl(summary_table_path, summary_sheet_ind):
    # 读取Excel文件
    wb = load_workbook(summary_table_path)
    sheet = wb.worksheets[summary_sheet_ind]
    # print(sheet)

    # 获取合并单元格的信息
    merged_cells = sheet.merged_cells.ranges
    # print(merged_cells)

    # 读取数据到Pandas DataFrame
    data = []
    for row in sheet.iter_rows(values_only=True):
        data.append(list(row))

    df = pd.DataFrame(data[1:], columns=data[0])

    # 处理合并单元格
    for merged_cell in merged_cells:
        min_col, min_row, max_col, max_row = merged_cell.bounds
        value = sheet.cell(row=min_row, column=min_col).value
        for row in range(min_row, max_row + 1):
            for col in range(min_col, max_col + 1):
                df.iat[row - 2, col - 1] = value  # 注意索引从0开始

    # 显示处理后的数据
    # print(df.values)

    return df.values, sheet, wb


def find_time_ind(summary_data_values, time_day):
    """
    找时间的索引
    :param summary_data_values:
    :return:
    """
    time_ind = -1
    is_find = False
    for ind_x, table_line in enumerate(summary_data_values):
        for ind, value in enumerate(table_line):
            if value == time_day:
                is_find = True
                time_ind = ind
                break

        if is_find:
            break

    if is_find:
        return time_ind
    else:
        print("未找到对应时间索引{}".format(time_day))
        exit(1)


def error_count_summary(factory_floor_flag, car_type, error_type, num, time_ind, summary_data_values, special_items=None):
    """
    错误类型的数量写入summary_data_values中
    :param factory_floor_flag:
    :param car_type:
    :param error_type:
    :param num:
    :param time_ind:
    :param summary_data_values:
    :param special_items:
    :return:
    """
    fix_item = ""
    if special_items is None:
        for ind, error_type_tmp in enumerate(g_error_list_type[:-1]):
            if error_type in error_type_tmp:
                fix_item = g_count_class_list[ind]
                break
    else:
        fix_item = special_items

    is_ok = False
    for ind_x, table_line in enumerate(summary_data_values):
        if factory_floor_flag == table_line[0] and car_type == table_line[1] and fix_item == table_line[2]:
            summary_data_values[ind_x][time_ind] = summary_data_values[ind_x][time_ind] + num
            is_ok = True
            # print("----错误类型是:{},厂:{},车型:{},数量:{}".format(error_type, factory_floor_flag, car_type,num))
            # print("----table_line[0]:{} table_line[1]:{} table_line[2]:{}".format(table_line[0],table_line[1],table_line[2]))

    if not is_ok:
        print("    标准错误项:{}".format(fix_item), end='')
        print("    对应错误类型未写入统计总表,该错误类型是:{},厂:{},车型:{},数量:{}".format(error_type,
                                                                                                   factory_floor_flag,
                                                                                                   car_type,num))


def data_records(table_path, factory_floor_list, is_save=None):
    data_records_name = "data_records.json"
    data_records_name_path = os.path.join(os.path.dirname(table_path), data_records_name)
    data_records = {}
    if os.path.exists(data_records_name_path):
        with open(data_records_name_path, 'r', encoding='utf-8') as file:
            data_records = json.load(file)

    factory_floor_flag = os.path.basename(table_path)[:2]

    day_summary = ""
    month_summary = ""

    is_find_ok = False
    for factory_floor_list_tmp in factory_floor_list:
        if factory_floor_flag in factory_floor_list_tmp:
            factory_floor_flag = factory_floor_list_tmp[-1]
            is_find_ok = True
            break
    if not is_find_ok:
        print("该 {} 不是标准格式命名文件".format(os.path.basename(table_path)))
        # print("    标准格式命名文件: xx厂xx月xx日检测结果记录")
        return False, factory_floor_flag, month_summary, day_summary

    file_path = os.path.basename(table_path)
    file_month_ind = file_path.find("月")
    if file_month_ind > 2:
        month_summary = "{:02d}".format(int(file_path[2:file_month_ind]))
    else:
        print("    该 {} 不是标准格式命名文件".format(os.path.basename(table_path)))
        # print("    标准格式命名文件: xx厂xx月xx日检测结果记录")
        return False, factory_floor_flag, month_summary, day_summary

    pattern = r'月(\d+)日'
    match = re.search(pattern, table_path)
    if match:
        day_summary = str(int(match.group(1))) + '日'
    else:
        print("    该 {} 不是标准格式命名文件".format(os.path.basename(table_path)))
        # print("    标准格式命名文件: xx厂xx月xx日检测结果记录")
        return False, factory_floor_flag, month_summary, day_summary

    time_key = month_summary + "{:02d}".format(int(match.group(1)))
    if time_key in data_records:
        if factory_floor_flag in data_records[time_key]:
            print("    该 {} 文件已经被执行,所以忽略".format(os.path.basename(table_path)))
            return False, factory_floor_flag, month_summary, day_summary
        else:
            data_records[time_key].append(factory_floor_flag)
    else:
        data_records[time_key] = []
        data_records[time_key].append(factory_floor_flag)

    if is_save:
        with open(data_records_name_path, 'w', encoding='utf-8') as file:
            json.dump(data_records, file, indent=4, ensure_ascii=False)
    else:
        print("厂:{} 时间:{}".format(factory_floor_flag, month_summary + "月" + day_summary))

    return True, factory_floor_flag, month_summary, day_summary


def find_template(folder_path):
    """
    寻找总表模板文件
    :param folder_path:
    :return:
    """
    folder_path = os.path.dirname(table_path)
    file_name_list = os.listdir(folder_path)

    count_num = 0
    template_name = ""
    for file_name in file_name_list:
        if "xx月合格率统计表模板" in file_name:
            template_name = file_name
            count_num = count_num + 1

    if count_num == 0:
        print("未找到总表模板文件 eg:防错项目xx月合格率统计表模板.xlsx")
        return False, template_name
    elif count_num > 1:
        print("找到多个总表模板文件 ")
        return False, template_name

    return True, template_name



def main(table_path, table_sheet_ind, summary_sheet_ind, error_list_type, factory_floor_list):
    is_ok, factory_floor_flag, month_summary, day_summary = data_records(table_path, factory_floor_list)
    if not is_ok:
        return
    # print(factory_floor_flag)

    is_ok, summary_table_name = find_template(table_path) # "奇瑞防错项目xx月合格率统计表模板.xlsx"
    if not is_ok:
        return
    summary_table_path = os.path.join(os.path.dirname(table_path),
                                          summary_table_name.replace("xx", month_summary).replace("模板", ""))

    if not os.path.exists(os.path.join(os.path.dirname(table_path),summary_table_name)):
        print("     奇瑞防错项目xx月合格率统计表模板.xlsx 该文件未找到")
        return

    if not os.path.exists(summary_table_path):
        shutil.copy(os.path.join(os.path.dirname(table_path),summary_table_name), summary_table_path)

    table_data = pd.read_excel(io=table_path, sheet_name=table_sheet_ind)

    table_data_statistics_nok, table_data_statistics_ok = excel_filterAndSummary(table_data, error_list_type)
    print("    nok项数据详情:", table_data_statistics_nok, end='')
    print("     ok项数据详情:", table_data_statistics_ok)

    summary_data_values, summary_data, wb = read_summary_execl(summary_table_path, summary_sheet_ind)

    time_ind = find_time_ind(summary_data_values, day_summary)

    # 处理NOK数据
    nok_number = {}
    for car_type in table_data_statistics_nok:
        total_number_tmp = 0
        for error_type in table_data_statistics_nok[car_type]:
            num = table_data_statistics_nok[car_type][error_type]
            total_number_tmp = total_number_tmp + num
            error_count_summary(factory_floor_flag, car_type, error_type, num, time_ind, summary_data_values,
                                special_items=None)

        error_count_summary(factory_floor_flag, car_type, "", total_number_tmp, time_ind, summary_data_values,
                            special_items="NG总数")

        if car_type in nok_number:
            nok_number[car_type] = nok_number[car_type] + total_number_tmp
        else:
            nok_number[car_type] = total_number_tmp

    # 处理OK数据
    for car_type in table_data_statistics_ok:
        total_number_tmp = table_data_statistics_ok[car_type]
        if car_type in nok_number:
            total_number_tmp = nok_number[car_type] + total_number_tmp

        error_count_summary(factory_floor_flag, car_type, "", total_number_tmp, time_ind,
                            summary_data_values, special_items="总检数")

    # 准备保存数据
    # print(summary_data_values)
    for ind_x, table_line in enumerate(summary_data_values):
        if table_line[2] in g_count_class_list:
            for ind_y, value in enumerate(table_line):
                if ind_y > 2:
                    execl_xy = num_to_excel_col(ind_y+1) + str(ind_x+2)
                    summary_data[execl_xy] = value
                    # print(execl_xy)

    # print(table_line)
    # print(summary_data[ind_x])
    # 保存文件
    wb.save(summary_table_path)
    data_records(table_path, factory_floor_list, True)


g_table_path = r"C:\Users\Administrator\Desktop\detect_statistics\超一11月24日检测结果记录.xls"
g_table_sheet_ind = 1  # Excel数据所在页索引
g_summary_table_path = r"C:\Users\Administrator\Desktop\detect_statistics\奇瑞防错项目11月合格率统计表.xlsx"  # 总表路径
g_summary_sheet_ind = 2  # Excel数据所在页索引
# 错误类型,越靠前表示问题权重越大 与g_count_class_list有联动,不要轻易更改它们的顺序
g_error_list_type = [["错漏装"], ["测试误报"], ["新物料","新物料\新零件号", "新零件号","新物料/新零件号"], ["人工问题"], ["设备问题"],
                     ["模型问题", "模型问题(结构件)","模型问题(结构件)"],["近似色问题"],["其他"]]
g_factory_floor_list = [["超一"], ["22线", "二总"], ["青岛"]]
g_count_class_list = ["检出NG总数","测试误报NG总数","新物料NG总数","车辆操作NG总数","设备问题NG总数","模型问题(结构件)NG总数",
                      "近似色NG总数","总检数","NG总数","漏检总数","视觉系统NG总数","有效检测数"]
# 三厂的xx厂xx月xx日检测结果记录所有记录,总表也可以放在里面。注意一个厂只能放一天的否则会累计
g_table_folder_path = os.getcwd() # r"C:\Users\Administrator\Desktop\detect_statistics"
if __name__ == "__main__":
    # main(g_table_path, g_table_sheet_ind, g_summary_table_path, g_summary_sheet_ind, g_error_list_type, g_factory_floor_list)

    folder_name_list = os.listdir(g_table_folder_path)
    for folder_name in folder_name_list:
        table_path = os.path.join(g_table_folder_path, folder_name)
        main(table_path, g_table_sheet_ind, g_summary_sheet_ind, g_error_list_type, g_factory_floor_list)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值