171 lines
6.8 KiB
Python
171 lines
6.8 KiB
Python
import pandas as pd
|
||
from datetime import datetime
|
||
import random
|
||
|
||
# 对于表格每一列:
|
||
# i = 1 -> 时间戳
|
||
# i = 6 -> 姓名
|
||
# i = 7 -> 部门编号
|
||
# i = 8 -> 老人 / 小朋友
|
||
# i = 9~28 -> 共 20 个班次,每个班次的意愿度
|
||
# i = 29 -> 想要值班的次数
|
||
col_timestamp = 1
|
||
col_name = 6
|
||
col_department = 7
|
||
col_member = 8
|
||
col_dutystart = 9
|
||
col_dutyend = 28
|
||
col_dutyfreq = 29
|
||
|
||
index_to_departments = { # 部门编号和部门名称的对应关系
|
||
1: "电脑部",
|
||
2: "电器部",
|
||
3: "人资部",
|
||
4: "财外部",
|
||
5: "文宣部"
|
||
}
|
||
|
||
index_to_type = { # 老人 / 小朋友和对应的编号
|
||
1: "老人",
|
||
2: "小朋友"
|
||
}
|
||
|
||
def read_excel(file_path):
|
||
# 读取 Excel 文件
|
||
df = pd.read_excel(file_path)
|
||
|
||
# 待返回的所有信息。N 为学生人数,M 为班次数
|
||
index_to_name_dict = {} # 长度为 N 的字典,包含数组下标和学生姓名的对应关系
|
||
preference_mat = [] # N x M 的二维数组,表示每位学生对每个班次的满意度
|
||
want_num_array = [] # 长度为 N 的数组,表示每位学生想要值班的次数
|
||
is_new_array = [] # 长度为 N 的数组,表示每位学生是否是小朋友
|
||
is_tech_array = [] # 长度为 N 的数组,表示每位学生是否是电脑部或电器部成员
|
||
is_hr_array = [] # 长度为 N 的数组,表示每位学生是否是人资部成员
|
||
|
||
'''
|
||
考虑到原始填表信息中可能有某位同学多次提交的记录,先过滤一下冗余信息
|
||
'''
|
||
all_data = {} # 储存过滤后的数据
|
||
format = "%Y/%m/%d %H:%M:%S"
|
||
for index, row in df.iterrows():
|
||
# 读取学生姓名,比较时间戳
|
||
name = row[col_name]
|
||
time_this = datetime.strptime(row[col_timestamp], format)
|
||
if (name not in all_data) or (time_this > datetime.strptime(all_data[name][col_timestamp], format)):
|
||
info_list = row.tolist()
|
||
all_data[name] = info_list
|
||
|
||
# 遍历过滤后的数据,组建待返回的信息
|
||
for index, (name, info_list) in enumerate(all_data.items()):
|
||
# 学生姓名
|
||
index_to_name_dict[index] = name
|
||
# 意愿度
|
||
preference_mat.append(info_list[col_dutystart:col_dutyend + 1])
|
||
# 想要值班的次数
|
||
want_num_array.append(info_list[col_dutyfreq])
|
||
# 是否是小朋友
|
||
is_new_array.append(index_to_type[info_list[col_member]] == "小朋友")
|
||
# 是否是电脑部或电器部成员
|
||
is_tech_array.append(index_to_departments[info_list[col_department]] in ["电脑部", "电器部"])
|
||
# 是否是人资部成员
|
||
is_hr_array.append(index_to_departments[info_list[col_department]] == "人资部")
|
||
|
||
return all_data, index_to_name_dict, preference_mat, want_num_array, is_new_array, is_tech_array, is_hr_array
|
||
|
||
def save_to_excel(variables, all_data, index_to_name_dict, file_path):
|
||
|
||
# 用一个 list 储存每一班的值班人员,该 list 中每个元素是一个存有若干 dict 的 list,每个 dict 表示某一班的某一值班人员信息
|
||
all_result = []
|
||
max_single_class_num = 0 # 用于记录最大的班次人数,以便后写入 excel
|
||
for j in range(len(variables[0])):
|
||
on_duty_list = []
|
||
single_class_num = 0
|
||
hr_new_index = []
|
||
none_tech_new_index = []
|
||
new_index = []
|
||
all_index = []
|
||
_cnt = 0
|
||
for i in range(len(variables)):
|
||
if variables[i][j] == 1:
|
||
single_stu_info = {}
|
||
single_stu_info["name"] = index_to_name_dict[i]
|
||
single_stu_info["department"] = index_to_departments[all_data[index_to_name_dict[i]][col_department]]
|
||
single_stu_info["type"] = index_to_type[all_data[index_to_name_dict[i]][col_member]]
|
||
single_stu_info["duty_monitor"] = False
|
||
on_duty_list.append(single_stu_info)
|
||
single_class_num += 1
|
||
|
||
all_index.append(_cnt)
|
||
if single_stu_info["type"] == "小朋友":
|
||
new_index.append(_cnt)
|
||
if single_stu_info["department"] in ["人资部", "财外部", "文宣部"]:
|
||
none_tech_new_index.append(_cnt)
|
||
if single_stu_info["department"] == 3:
|
||
hr_new_index.append(_cnt)
|
||
_cnt += 1
|
||
|
||
# 为每一班的值班组长打上标记
|
||
duty_monitor_index = -1
|
||
if hr_new_index:
|
||
duty_monitor_index = random.choice(hr_new_index)
|
||
elif none_tech_new_index:
|
||
duty_monitor_index = random.choice(none_tech_new_index)
|
||
elif new_index:
|
||
duty_monitor_index = random.choice(new_index)
|
||
else:
|
||
duty_monitor_index = random.choice(all_index)
|
||
on_duty_list[duty_monitor_index]["duty_monitor"] = True
|
||
|
||
on_duty_list = sorted(on_duty_list, key=lambda x: x["department"]) # 按部门编号升序排序
|
||
all_result.append(on_duty_list)
|
||
max_single_class_num = max(max_single_class_num, single_class_num)
|
||
|
||
|
||
from openpyxl import Workbook
|
||
from openpyxl.styles import PatternFill
|
||
|
||
# 创建一个新的工作簿
|
||
wb = Workbook()
|
||
ws = wb.active
|
||
if ws is None:
|
||
ws = wb.create_sheet(title="Sheet1")
|
||
|
||
# 写入表头
|
||
width = 25
|
||
ws['B1'] = "星期一"
|
||
ws.column_dimensions['B'].width = width
|
||
ws['C1'] = "星期二"
|
||
ws.column_dimensions['C'].width = width
|
||
ws['D1'] = "星期三"
|
||
ws.column_dimensions['D'].width = width
|
||
ws['E1'] = "星期四"
|
||
ws.column_dimensions['E'].width = width
|
||
ws['F1'] = "星期五"
|
||
ws.column_dimensions['F'].width = width
|
||
ws['G1'] = "星期六"
|
||
ws.column_dimensions['G'].width = width
|
||
ws['H1'] = "星期日"
|
||
ws.column_dimensions['H'].width = width
|
||
|
||
start_index = []
|
||
ws.merge_cells(f'A2:A{2 + max_single_class_num}')
|
||
ws['A2'] = "第一班"
|
||
start_index.append(2)
|
||
ws.merge_cells(f'A{2 + max_single_class_num + 1}:A{2 + 2 * max_single_class_num + 1}')
|
||
ws[f'A{2 + max_single_class_num + 1}'] = "第二班"
|
||
start_index.append(2 + max_single_class_num + 1)
|
||
ws.merge_cells(f'A{2 + 2 * max_single_class_num + 2}:A{2 + 3 * max_single_class_num + 2}')
|
||
ws[f'A{2 + 2 * max_single_class_num + 2}'] = "第三班"
|
||
start_index.append(2 + 2 * max_single_class_num + 2)
|
||
|
||
for duty_index, duty in enumerate(all_result):
|
||
for stu_index, stu in enumerate(duty):
|
||
col = chr(ord('B') + duty_index // 3)
|
||
row = start_index[duty_index % 3] + stu_index
|
||
str_info = f"{stu['name']} {stu['department']} {stu['type']}"
|
||
if stu['duty_monitor']:
|
||
ws[col + str(row)].fill = PatternFill(fill_type='solid', start_color='FFFF00', end_color='FFFF00')
|
||
ws[col + str(row)] = str_info
|
||
|
||
# 保存文件
|
||
wb.save(file_path) |