程序的作用:
跟踪大货,全程监控excel表中设置的工作安排
程序的缺陷:
1.在跟踪的订单多的情况下,弹框数量会很多,因为用了并发式弹框,需要更进程序的体验
2.黑窗口操作,最用户不友好
3.其他没有发现的bug
注意事项
程序的启动模块为main.py文件
注意导入的文件一定要与程序在同一文件夹下
注意导入的数据一定要符合sainty文件中的模板格式,否则会出错
本脚本程序,暂时只有导入excel文件,查询订单,以及订单追踪功能
当订单多的时候,线程会呈指数增长,该版本解决了该问题
excel_to_sql.py:将excel表导入数据库模块
import os
import time
import pymysql
import xlrd
import prettytable
class DB(object):
# 读取时间常量
LOADING_TIME = 3
def __init__(self, db_name):
"""初始化操作"""
self.db = DB.mysql_link(db_name) # 打开数据库连接
self.cursor = self.db.cursor() # 使用 cursor() 方法创建一个游标对象 cursor
@staticmethod
def mysql_link(de_name):
"""连接数据库"""
try:
db = pymysql.connect(host="localhost", user="root",
passwd="root",
db=de_name,
charset='utf8')
return db
except:
print("连接数据库时出错")
@staticmethod
def open_excel(excel_file):
"""手动打开excel文件"""
try:
# excel_file = input("请输入文件名[xxx]:") + ".xlsx"
book = xlrd.open_workbook(excel_file) # 文件名,把文件与py文件放在同一目录下
return book
except:
print("打开excel文件失败")
def atuo_open_excel(self):
"""自动检索excel文件名"""
print("正在获取当前目录的excel文件中...")
time.sleep(DB.LOADING_TIME)
current_path = os.getcwd() # 获取当前文件路径
# 获取指定目录下包含的文件和目录
dirs = os.listdir(current_path)
for file in dirs:
# 判断文件是否是以xlsx或xls结尾
if file.endswith("xlsx") or file.endswith("xls"):
book = DB.open_excel(file)
print("获取excel数据成功")
return book
def type_change(self):
"""检测导入的excel数据类型"""
pass
def del_sql_table(self):
"""删除数据库表操作"""
sql = """drop table sainty;"""
print("重构原数据库表中...")
time.sleep(DB.LOADING_TIME)
self.cursor.execute(sql)
def create_sql_table(self):
"""创建数据库表操作"""
sql = """create table sainty (
id int(100) not null,
category_num varchar(40) not null,
guest varchar(40) not null,
total_quantity int(100) not null,
factory_name varchar(40) not null,
start_order_date date not null,
delivery_date date not null,
sailing_date date not null,
pp_sample date default null,
sealed_sample date default null,
reserved_sample date default null,
golden_sealed date default null,
inspection_time date default null,
is_del varchar(1) default 0,
primary key(id, category_num)
); """
print("初始化表格中...")
time.sleep(DB.LOADING_TIME) # 减缓插入速度
self.cursor.execute(sql)
def store_to(self):
"""存储excel数据进入sql
把文件与py文件放在同一目录下
"""
try:
self.del_sql_table()
self.create_sql_table()
except:
self.create_sql_table()
# book = DB.open_excel() # 手动打开excel文件
book = self.atuo_open_excel() # 自动打开excel文件
sheets = book.sheet_names() # 获取所有sheet表名
for sheet in sheets:
sh = book.sheet_by_name(sheet) # 打开每一张表
row_num = sh.nrows
data_list = list() # 定义列表用来存放数据
# 第一行是标题名,对应表中的字段名所以应该从第二行开始
# 计算机以0开始计数,所以值是1
for i in range(1, row_num):
# if sh.row_values(i)
row_data = sh.row_values(i) # 按行获取excel的值
value = (row_data[0], row_data[1], row_data[2], row_data[3],
row_data[4], row_data[5], row_data[6], row_data[7],
row_data[8], row_data[9], row_data[10], row_data[11], row_data[12], row_data[13])
data_list.append(value) # 将数据暂存在列表
# 调用插入操作方法
self.insert_into(data_list, sheet, row_num)
# 调用close关闭cursor和connection
self.close()
def insert_into(self, data_list, sheet, row_num):
"""插入操作"""
sql = """INSERT IGNORE INTO sainty (id,category_num,
guest,total_quantity,factory_name,start_order_date,delivery_date,
sailing_date,pp_sample,sealed_sample,reserved_sample,
golden_sealed,inspection_time,is_del) VALUES (%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s, %s, %s)"""
print("插入订单数据中...")
time.sleep(DB.LOADING_TIME) # 减缓插入速度
self.cursor.executemany(sql, data_list) # 执行sql语句
self.db.commit() # 提交
data_list.clear() # 清空list
print("表格: " + sheet + " 已经被插入 " + str(row_num) + " 数据!")
def query_sql(self, input_num):
"""查询操作"""
# 创建列表用来存储每行的下单时间,交货期,船期,验货时间 元祖
date_list = list()
sql = """select * from sainty where is_del='0'"""
# 执行sql语句
self.cursor.execute(sql)
# 创建表头
order_sheet = prettytable.PrettyTable(["po号", "品类数", "客人", "总数量", "工厂名",
"下单日", "交期", "船期", "产前样", "签字封样",
"留样", "客人封样", "验货时间", "是否出运"])
# 获取所有记录
results = self.cursor.fetchall()
for row_data in results:
# 获取每行的每个字段的值
id = row_data[0]
category_num = row_data[1]
guest = row_data[2]
total_quantity = row_data[3]
factory_name = row_data[4]
start_order_date = row_data[5]
delivery_date = row_data[6]
sailing_date = row_data[7]
pp_sample = row_data[8]
sealed_sample = row_data[9]
reserved_sample = row_data[10]
golden_sealed = row_data[11]
inspection_time = row_data[12]
is_del = row_data[13]
# 创建一个元祖用来存储下单时间,交货期,船期,验货时间等时间
date_value = (pp_sample, sealed_sample, reserved_sample, golden_sealed,
start_order_date, delivery_date, sailing_date, inspection_time,
id, category_num, factory_name, guest)
date_list.append(date_value) # 将时间变量存入列表
# 如果用户输入时2,则将数据放入prettyTable的表格内
if input_num == "2":
order_sheet.add_row([id, category_num, guest, total_quantity,
factory_name, start_order_date, delivery_date,
sailing_date, pp_sample, sealed_sample, reserved_sample,
golden_sealed, inspection_time, is_del])
# 判断用户输入,如果是查询,则数据的表格被打印
if input_num == "2":
print("\n")
print("=" * 170)
print("查询数据库")
print(order_sheet)
self.close()
# 返回日期列表
return date_list
def update_sql(self):
"""修改操作"""
print("\n")
print("=" * 50)
print("修改数据功能维护中...")
def del_sql(self):
"""删除操作"""
print("")
print("="* 50)
print("删除已经出运的数据")
sql = """update sainty set is_del='1' where id=%s"""
# 创建临时列表用来存储用户输入
temp_po_list = list()
while True:
po_num = input("请输入需要删除的订单PO号[回车退出删除]:")
if po_num == "":
break
else:
print(po_num, "订单信息将被删除...")
temp_po_list.append(po_num)
self.cursor.executemany(sql, temp_po_list)
self.db.commit() # 提交
temp_po_list.clear() # 清空list
print("数据已经删除")
self.close()
def close(self):
"""关闭资源"""
self.cursor.close()
self.db.close()
if __name__ == '__main__':
db = DB("sainty")
db.store_to()
order.py:订单模块
import time
import excel_to_sql
class Order(object):
"""订单类"""
# 读取时间常量
LOADING_TIME = 3
def __init__(self):
"""初始化"""
print("订单操作程序启动中...")
time.sleep(Order.LOADING_TIME)
print("订单操作系统已经启动...")
@staticmethod
def menu():
"""界面"""
print("\n")
print("功能界面")
print("=" * 50)
print("欢迎使用大货跟踪程序V1.20200731")
print("1.导入EXCEL表文件")
print("2.查询订单详情(未出运)")
print("3.修改订单信息")
print("4.删除订单")
print("0.退出程序")
print("=" * 50)
@staticmethod
def input_order_data():
"""输入数据"""
# 创建数据库类
db = excel_to_sql.DB("sainty")
# 调用插入方法
db.store_to()
print("EXCCEL数据已经导入进数据库")
@staticmethod
def retrieve_order_data(input_num):
"""查询操作"""
# 创建数据库类
db = excel_to_sql.DB("sainty")
db.query_sql(input_num)
@staticmethod
def exit_order():
"""退出订单操作"""
print("退出程序中...")
time.sleep(Order.LOADING_TIME)
print("订单操作程序已经退出,欢迎再次使用O(∩_∩)O~")
exit()
def user_select(self):
user_input = input("请输入需要操作的功能序号[1 2 3 4 0]:\n")
if user_input == "1":
Order.input_order_data()
elif user_input == "2":
Order.retrieve_order_data(user_input)
elif user_input == "3":
self.update_order_data()
elif user_input == "4":
self.del_order_data()
elif user_input == "0":
Order.exit_order()
else:
print("输入有误,请重新输入")
def update_order_data(self):
"""修改日期操作"""
# 创建数据库类
db = excel_to_sql.DB("sainty")
db.update_sql()
def del_order_data(self):
"""删除订单数据(通过isdel实现)"""
# 创建数据库类
db = excel_to_sql.DB("sainty")
db.del_sql()
def start(self):
while True:
Order.menu() # 菜单界面
self.user_select() # 用户输入
order_clock.py:订单备忘闹钟模块
import time
import datetime
import tkinter
import threading
import excel_to_sql
"""
时钟备忘功能的思路:
1.从数据库获取数据,下单时间,交货期,船期,验货时间
2.从系统获取时间
3.进行时间的判断
系统时间 - 下单时间 >= 15天---> 弹出事务提醒框:内容显示poxxxx的xxx玩具产前样工厂未寄送
船期 - 系统时间 <= 20天---> 弹出事务提醒框:内容显示POXXX的XXX玩具寄客人样工厂未寄送
---> 弹出事务提醒框:内容显示POXXX的XXX玩具留样样工厂未寄送
验货时间 - 系统时间 <= 20天--->弹出事务提醒框:内容显示POXXX的XXX玩具签字样工厂未寄送
如果验货时间为空,则不弹出
解决线程过多问题:如果后面订单中品类与包装与之前订单相同,则无需要产前样,封样,留样
"""
class Clock(object):
"""备忘时钟类"""
# 是否在屏幕打印表格的标记
INPUT_NUM = "1"
# 读取时间常量
LOADING_TIME = 3
# 刷新监听时间为 【3小时一次】
FLUSH_TIME = 60 * 60 * 3
def __init__(self):
""""""
self.__init_msg()
self.excel_to_sql = excel_to_sql.DB("sainty")
@staticmethod
def __init_msg():
"""初始化消息"""
print("备忘时钟功能开启中...")
time.sleep(Clock.LOADING_TIME)
print("备忘时钟程序已开启...")
@staticmethod
def ring():
"""弹框时候的声音"""
print("\a")
@staticmethod
def msg_box(factory_name, id_number, guest, sample_type, days):
"""消息提示框功能"""
root = tkinter.Tk()
# root.wm_attributes('-topmost', 1) # 窗口始终在前面
root.title("订单跟踪") # 标题
root.geometry('400x200') # 窗口尺寸
root.resizable(False, False) # 固定窗体
tkinter.Button(root, text="""【%s-%s-%s-%s】工厂还没有寄送
距离下单日已经过去【%d天】
""" %
(factory_name, id_number, guest, sample_type,
days), font=50,
width=400, height=200).pack()
root.mainloop()
@staticmethod
def start_handle_thread(factory_name, id_number, guest, sample_type, days):
"""开启一个监听线程"""
threading.Thread(target=Clock.msg_box,
args=(factory_name, id_number,
guest, sample_type, days)).start()
def get_data(self):
"""获取数据"""
# 调用excel_to_sql模块的query_sql方法,获取日期列表
date_time = self.excel_to_sql.query_sql(Clock.INPUT_NUM)
# 获取系统时间
sys_date = datetime.date.today()
return date_time, sys_date
def handle_time(self):
"""监听时间"""
while True:
time.sleep(Clock.LOADING_TIME) # 开辟多线程间的开启时间间隔,与订单线程错开
# 调用方法,获取数据
date_time = self.get_data()[0]
sys_date = self.get_data()[1]
# 遍历日期列表获取值
for time_tple in date_time:
pp_sample_date = time_tple[0] # 获取产前样确定时间
sealed_sample_date = time_tple[1] # 获取封样时间
reserved_sample_date = time_tple[2] # 获取留样时间
golden_sealed_date = time_tple[3] # 获取寄客人样时间
start_order_date_date = time_tple[4] # 获取下单时间
delivery_date_date = time_tple[5] # 获取交期
sailing_date_date = time_tple[6] # 获取船期
inspection_time_date = time_tple[7] # 获取验货时间
id_number = time_tple[8] # po号
cate = time_tple[9] # 玩具品名
factory_name = time_tple[10] # 工厂名
guest = time_tple[11] # 客人名
##################################################################################################################
try:
pp_sample_date_day = pp_sample_date.day
except:
pp_sample_date = ""
# 判断时间并监听
# 系统时间 - 下单时间 >= 15天---> 弹出事务提醒框:内容显示poxxxx的xxx玩具[产前样]工厂未寄送
if pp_sample_date == "":
if (sys_date - start_order_date_date).days >= 15:
# print("【%s-%s-%s产前样】工厂还没有寄送" % (factory_name, id_number, guest))
# print("距离下单日已经过去【%d天】" % (sys_date - start_order_date_date).days)
# print("-" * 50)
# 调用线程监听数据方法,做到同时弹出事务框
Clock.start_handle_thread(factory_name, id_number, guest, "产前样",
(sys_date - start_order_date_date).days)
##################################################################################################################
try:
golden_sealed_date_day = golden_sealed_date.day
sealed_sample_date_day = sealed_sample_date.day
except:
golden_sealed_date = ""
sealed_sample_date = ""
# 船期 - 系统时间 <= 20天---> 弹出事务提醒框:内容显示POXXX的XXX玩具[寄客人样]工厂未寄送
# ---> 弹出事务提醒框:内容显示POXXX的XXX玩具[留样]工厂未寄送
if golden_sealed_date == "" or sealed_sample_date == "":
if 0 < (sailing_date_date - sys_date).days <= 20:
# print("【%s-%s-%s寄客人样与留样】工厂还没有寄送" % (factory_name, id_number, guest))
# print("距离下单日已经过去【%d天】" % (sailing_date_date - sys_date).days)
# print("-" * 50)
# 调用线程监听数据方法,做到同时弹出事务框
Clock.start_handle_thread(factory_name, id_number, guest, "寄客人样/留样",
(sailing_date_date - sys_date).days)
##################################################################################################################
# 验货时间 - 系统时间 <= 20天--->弹出事务提醒框:内容显示POXXX的XXX玩具签字样工厂未寄送
# 如果验货时间为空,则不弹出
try:
if 0 < (inspection_time_date - sys_date).days <= 25:
# print("【%s-%s-%s签字样】工厂还没有寄送" % (factory_name, id_number, guest))
# print("距离下单日已经过去【%d天】" % (sailing_date_date - sys_date).days)
# print("-" * 50)
# 调用线程监听数据方法,做到同时弹出事务框
Clock.start_handle_thread(factory_name, id_number, guest, "签字封样",
(sailing_date_date - sys_date).days)
except:
pass
time.sleep(Clock.FLUSH_TIME) # 每3小时刷新一次数据
##################################################################################################################
def start(self):
"""开始程序"""
try:
self.handle_time()
except:
print("程序出错")
main.py:主模块
import order
import order_clock
import threading
"""
Order类负责:
订单数据的CRUD
Clock类负责:
订单事件的监听
Main类负责:
整体框架的控制
"""
class Main(object):
def __init__(self):
# 调用权限方法
Main.access()
# 创建对象
self.__create_object()
@staticmethod
def access():
# 输入权限
username = input("请输入用户名:")
password = input("请输入密码:")
if username == "root" and password == "123456":
print("登录成功!欢迎您 %s" % username)
else:
raise Exception("用户名或密码错误!")
def __create_object(self):
""""""
self.order_clock = order_clock.Clock()
self.order = order.Order()
def thread_order(self):
# 订单信息功能
t_order = threading.Thread(target=self.order.start, args=())
# self.order.start()
t_order.start()
def thread_order_clock(self):
# 闹钟备忘功能
t_order_clock = threading.Thread(target=self.order_clock.start, args=())
# self.order_clock.start()
t_order_clock.start()
def run_program(self):
"""整体框架"""
self.thread_order()
self.thread_order_clock()
if __name__ == "__main__":
try:
main = Main()
main.run_program()
except Exception as ret:
print("错误:", ret)
声明:技术有限,请大佬不要见怪!谢谢!有不足之处请各位朋友指出!