[Python] 纯文本查看 复制代码
import subprocess
import string
import glob
import os
import openpyxl
from openpyxl import load_workbook
from docx import Document
from docx.oxml.ns import qn
from docx.shared import Pt
import datetime
from datetime import datetime, timedelta
# 用户输入日期字符串
# 提示用户输入日期,并存储为字符串
def get_valid_date():
while True:
valid_date = input(" 请输入统计时间(例如:2024.7.19): ")
try:
# 尝试将输入转换为日期格式
date_obj111 = datetime.strptime(valid_date, "%Y.%m.%d")
return date_obj111.date()
except ValueError:
# 如果转换失败,说明输入格式不正确,提示用户重新输入
print("")
print("输入的日期格式不正确,请按照示例重新输入!\n")
date_str = get_valid_date() # 调用函数获取有效日期
user_input_date = date_str.strftime("%Y.%m.%d") # 以字符串形式输出日期,使用 strftime 方法
tjr = '张三' # 统计人姓名
# 将用户输入的日期字符串转换为datetime对象
try:
date_obj = datetime.strptime(user_input_date, "%Y.%m.%d")
tjsj = f"{date_obj.year}年{date_obj.month}月{date_obj.day}日" # 将datetime对象格式化为中文日期格式: 2024年12月12日
gzbm = date_obj.strftime("%Y%m%d") # 将datetime对象格式化为工作表名格式: 20241212
wjm = f"{date_obj.year}.{date_obj.month}" # 将datetime对象格式化为文件名格式: 2024.12
four_days_ago = date_obj - timedelta(days=4) # 计算四天前的日期
four_days_ago_str = f"{four_days_ago.year}年{four_days_ago.month}月{four_days_ago.day}日" # 将四天前的日期格式化为中文日期格式: 2024年12月8日
# 如果日期格式错误,捕获ValueError异常并给出提示
except ValueError:
print("输入的日期格式不正确,请按照 YYYY.M.D 的格式重新输入!")
# 定义一个函数来查找指定日期的Excel文件
def find_excel_file(date_str):
# 构造文件模式
file_pattern = f"工作日报{date_str}.xlsx"
directory = 'D:\工作日报'
# 使用指定的目录
# matching_files = glob.glob(os.path.join(os.getcwd(), file_pattern)) # 原来的代码
matching_files = glob.glob(os.path.join(directory, file_pattern)) # 修改后的代码
# 检查找到的文件数量
if len(matching_files) == 1:
# 如果只有一个文件,返回文件路径
return matching_files[0]
elif len(matching_files) > 1:
# 如果找到多个文件,抛出异常
print(" ")
print("找到多个匹配的文件,请检查是否有重复命名的文件。")
input("按回车键继续。")
raise Exception
else:
# 如果没有找到文件,抛出文件未找到异常
print(" ")
print(f"未找到匹配的文件:“{file_pattern}”\n \n请检查文件是否存在此目录下:“{directory}”\n")
input("按回车键继续。")
raise FileNotFoundError
# 尝试查找Excel文件
try:
excel_file_path = find_excel_file(wjm) # 调用find_excel_file函数
workbook = openpyxl.load_workbook(excel_file_path) # 加载工作簿
sheet_name = gzbm # 获取指定名称的工作表
if sheet_name in workbook.sheetnames:
# 获取工作表索引
sheet_index = workbook.sheetnames.index(sheet_name)
# 检查工作表前后是否有足够的工作表
if sheet_index >= 4:
# 选取目标工作表前4个工作表
selected_sheets = workbook.worksheets[sheet_index-4:sheet_index+1]
#print(f"选取的工作表为:{selected_sheets}")
else:
# 如果工作表前不足四个工作表,抛出异常
print(" ")
print(f"警告:在选定的工作表“{sheet_name}”前不足四个工作表,请重新输入。\n")
input("按回车键继续。")
raise IndexError
else:
# 如果未找到指定的工作表,抛出异常
print(" ")
print(f"未找到指定的工作表“{sheet_name}”,请检查您的输入是否正确。\n")
input("按回车键继续。")
raise ValueError
except (IndexError, ValueError) as e:
# 输出异常信息
print(e)
# input("按回车键继续。")
# 可以在此处添加重新尝试的逻辑或直接退出程序
# 定义工作类别选项和优先级顺序
options = ["故障维修", "耗材配送", "设备安装与调试", "例行巡检", "软件安装"]
preferred_order = ["例行巡检", "故障维修", "设备安装与调试", "耗材配送", "软件安装"]
# 初始化分类工作字典
categorized_work = {}
# 遍历选定的工作表
for worksheet in selected_sheets:
# 初始化非空单元格数量
last_row = 0
# 遍历B列,计算最后一行
#统计一个工作表中第2列从第4行开始的非空单元格的数量
for row in worksheet.iter_rows(min_row=4, min_col=2, max_col=2, values_only=True):
# 如果单元格不为空,则增加非空单元格数量
if row[0] is not None:
# 更新非空单元格数量
last_row += 1
# 遍历B列和D列,处理工作类别为空的情况
# 遍历工作表中的B列和D列,如果D列为空,让用户选择工作类别
for row in worksheet.iter_rows(min_row=4, max_row=last_row, min_col=2, max_col=4):
# 获取B列和D列的值
b_column_value = row[0].value
d_column_value = row[2].value
# 如果D列工作类别为空,让用户选择工作类别
if d_column_value is None:
print(f"\n工作内容为: {b_column_value}")
print("\n工作类别为空,选择一个工作类别:")
for i, option in enumerate(options, start=1):
print(f"{i}. {option}")
# 循环直到用户输入有效的选项
while True:
print("")
choice = input("请输入选项序号:")
try:
choice = int(choice)
if 1 <= choice <= len(options):
d_column_value = options[choice - 1]
break
else:
print("")
print("无效的选项,请重新输入。")
except ValueError:
print("")
print("无效的输入,请输入数字序号。")
# 更新D列的值
row[2].value = d_column_value
# 创建目录(如果不存在)
directory = 'D:\工作日报'
if not os.path.exists(directory):
os.makedirs(directory)
# 保存修改后的Excel文件
file_name = f"{directory}/工作日报{wjm}.xlsx"
workbook.save(filename=file_name)
# 再次遍历选定的工作表,收集工作内容和类别
for worksheet in selected_sheets:
# 初始化变量,用于记录工作表中有效数据的最后一行行号
last_row = 0
# 第一次遍历,从第四行开始,仅读取第二列的数据,以确定有效数据的结束行
for row in worksheet.iter_rows(min_row=4, min_col=2, max_col=2, values_only=True):
# 如果该单元格有值,更新last_row计数器
if row[0] is not None:
last_row += 1
# 手动修正last_row的值,增加2以包含可能遗漏的两行数据
last_row += 2
#print("最后一行是:", last_row)
# 第二次遍历,从第四行开始至修正后的最后一行,读取第二列至第四列的数据
for row in worksheet.iter_rows(min_row=4, max_row=last_row, min_col=2, max_col=4, values_only=True):
# 分别获取B列和D列的值
b_column_value = row[0]
# 将B列的值中的所有小写字母转换为大写字母
#b_column_value = b_column_value.upper()
if b_column_value is not None:
b_column_value = b_column_value.upper()
d_column_value = row[2]
# 检查D列的值是否已存在于categorized_work字典中
if d_column_value not in categorized_work:
# 若不存在,创建一个新的集合
categorized_work[d_column_value] = set()
# 将B列的值添加到对应D列值的集合中
categorized_work[d_column_value].add(b_column_value)
# 将收集到的集合转换为列表并排序
for category in categorized_work:
categorized_work[category] = list(categorized_work[category])
categorized_work[category].sort()
# 定义类别映射
category_mapping = {
"例行巡检": "日常巡检类",
"故障维修": "故障处理及维修类",
"设备安装与调试": "设备安装与调试类",
"耗材配送": "耗材配送",
"软件安装": "软件安装"
}
# 加载Word模板文件
template_file = 'D:\生成新周报程序\模板.docx'
doc = Document(template_file)
# 获取文档中的第一个表格
table = doc.tables[0]
# 根据优先级顺序和实际存在的类别构建实际顺序列表
actual_order = [category for category in preferred_order if category in categorized_work]
# 定义中文数字列表
chinese_digits = list(string.digits[:10].translate(str.maketrans("0123456789", "零一二三四五六七八九")))[1:] + ['十']
# 构建编号类别字典
numbered_categories = {}
for idx, category in enumerate(actual_order):
chinese_number = chinese_digits[idx] if idx < len(chinese_digits) else str(idx + 1)
numbered_categories[category] = f"{chinese_number}、{category_mapping[category]}"
# 替换表格中的统计信息
for row in table.rows:
for cell in row.cells:
if '统计的人' in cell.text:
cell.text = ''
p = cell.add_paragraph()
run = p.add_run(f"{tjr}")
font = run.font
font.name = '仿宋'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
font.size = Pt(12)
elif '统计的时间' in cell.text:
cell.text = ''
p = cell.add_paragraph()
run = p.add_run(f"{tjsj}")
font = run.font
font.name = '仿宋'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
font.size = Pt(12)
elif '统计时间段' in cell.text:
cell.text = ''
p = cell.add_paragraph()
run = p.add_run(f'{four_days_ago_str}-{tjsj}')
font = run.font
font.name = '仿宋'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
font.size = Pt(12)
# 删除表格单元格中的空行
for row in table.rows:
for cell in row.cells:
paragraphs_to_remove = [p for p in cell.paragraphs if p.text.strip() == ""]
for paragraph in paragraphs_to_remove:
p = paragraph._element
p.getparent().remove(p)
p._p = p._element = None
# 遍历表格的每一行
for row in table.rows:
# 遍历行中的每一个单元格
for cell in row.cells:
# 检查单元格文本是否包含“工作内容和类别”
if '工作内容和类别' in cell.text:
# 清空单元格文本
cell.text = ''
# 移除单元格内所有段落元素
for paragraph in cell.paragraphs:
p = paragraph._element
p.getparent().remove(p)
paragraph = cell.add_paragraph()
run = paragraph.add_run("工作量统计:")
run.font.size = Pt(12)
run.font.name = '仿宋'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
# 遍历实际工作类别顺序
for idx, category in enumerate(actual_order):
# 获取显示的类别
display_category = numbered_categories[category]
# 添加一个新的段落
p = cell.add_paragraph()
# 添加类别文本
run = p.add_run(display_category)
# 设置字体样式
font = run.font
font.name = '仿宋'
# 设置字体为中文样式
run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
# 设置字体大小
font.size = Pt(14)
# 设置字体加粗
font.bold = True
# 初始化计数器
counter = 1
# 遍历该类别下的所有工作内容
for content in categorized_work[category]:
# 添加一个新的段落
p = cell.add_paragraph()
# 添加工作内容文本
run = p.add_run(f"{counter}. {content}")
# 设置字体样式
font = run.font
font.name = '仿宋'
# 设置字体为中文样式
run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋')
# 设置字体大小
font.size = Pt(12)
# 增加计数器
counter += 1
# 获取当前的日期
today = datetime.now()
# 创建一个datetime对象,表示本月的第一天
first_day_of_month = datetime(today.year, today.month, 1)
# 计算本月的第一个星期一
first_monday_of_month = first_day_of_month - timedelta(days=first_day_of_month.isoweekday() % 7)
# 计算今天是本月的第几周
weeks_into_month = ((today - first_monday_of_month).days + 6) // 7
# 定义输出文件名,只保留年月:2024年7月
scwjm = f"{date_obj.year}年{date_obj.month}月"
# 指定输出文件的完整路径
output_file = f'D:\周报统计\周工作量统计({scwjm}第{weeks_into_month}周) .docx'
# 创建目录(如果不存在)
output_dir = os.path.dirname(output_file)
os.makedirs(output_dir, exist_ok=True)
# 保存文档至输出文件
doc.save(output_file)
# 打印成功写入文件的信息
print(f"\n")
print(f"周报已生成:{output_file}\n")
input("请按回车键继续,周报即将自动打开。")
# 使用系统默认程序打开输出文件
os.startfile(output_file)