当前位置: 首页 > news >正文

Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印

 图样:

 

就可以导入了

上代码

import tkinter as tk
from tkinter import ttk
import sqlite3
from datetime import datetime
from tkinter import messagebox, filedialog
import pandas as pd
import reclass OrderSystem:def __init__(self, root):self.root = rootself.root.title("订单记录系统")# 创建数据库连接self.conn = sqlite3.connect('orders.db')self.create_table()# 创建界面self.create_ui()# 添加搜索框架self.create_search_frame()# 添加更多功能按钮self.add_function_buttons()# 加载所有订单数据self.load_all_orders()# 设置默认值self.set_default_values()def create_table(self):cursor = self.conn.cursor()cursor.execute('''CREATE TABLE IF NOT EXISTS orders (order_date TEXT,order_number TEXT,customer TEXT,product TEXT,unit TEXT,quantity REAL,price REAL,discount REAL,final_price REAL,total REAL,remarks TEXT,discount_amount REAL,discount_total REAL,delivery TEXT,payment_received REAL,end_customer TEXT,notes TEXT,business TEXT)''')self.conn.commit()def create_ui(self):# 创建主框架来容纳左右两部分main_frame = ttk.Frame(self.root)main_frame.pack(fill="both", expand=True)# 创建左侧框架left_frame = ttk.Frame(main_frame)left_frame.pack(side="left", fill="both", expand=True)# 创建右侧框架right_frame = ttk.Frame(main_frame)right_frame.pack(side="right", fill="y", padx=5)# 创建输入框架(放在左侧)input_frame = ttk.LabelFrame(left_frame, text="订单信息")input_frame.pack(padx=5, pady=5, fill="x")# 修改订单分类框架order_group_frame = ttk.LabelFrame(right_frame, text="订单查询")order_group_frame.pack(padx=5, pady=5, fill="both", expand=True)# 添加筛选框filter_frame = ttk.Frame(order_group_frame)filter_frame.pack(fill="x", padx=5, pady=5)# 单据���号筛选ttk.Label(filter_frame, text="单据编号:").grid(row=0, column=0, padx=5)self.order_number_filter = ttk.Combobox(filter_frame, width=15)self.order_number_filter.grid(row=0, column=1, padx=5)# 客户名称筛选ttk.Label(filter_frame, text="客户名称:").grid(row=0, column=2, padx=5)self.customer_filter = ttk.Combobox(filter_frame, width=15)self.customer_filter.grid(row=0, column=3, padx=5)# 筛选按钮ttk.Button(filter_frame, text="筛选", command=self.filter_orders).grid(row=0, column=4, padx=5)ttk.Button(filter_frame, text="重置", command=self.reset_filter).grid(row=0, column=5, padx=5)ttk.Button(filter_frame, text="打印", command=self.print_filtered_data).grid(row=0, column=6, padx=5)# 绑定下拉框事件self.order_number_filter.bind('<KeyRelease>', self.update_order_number_list)self.customer_filter.bind('<KeyRelease>', self.update_customer_list)# 修改订单分类的树形视图列self.group_tree = ttk.Treeview(order_group_frame, columns=["order_number", "customer", "product", "unit", "quantity", "price", "total", "remarks"], show="headings", height=15)# 设置列标题和宽度columns = [("order_number", "单据编号", 100),("customer", "客户名称", 100),("product", "品名规格", 120),("unit", "单位", 50),("quantity", "数量", 60),("price", "原价", 80),("total", "金额", 80),("remarks", "备注", 100)]for col, heading, width in columns:self.group_tree.heading(col, text=heading)self.group_tree.column(col, width=width)self.group_tree.pack(padx=5, pady=5, fill="both", expand=True)# 添加滚动条group_scrollbar = ttk.Scrollbar(order_group_frame, orient="vertical", command=self.group_tree.yview)group_scrollbar.pack(side="right", fill="y")self.group_tree.configure(yscrollcommand=group_scrollbar.set)# 绑定点击事件self.group_tree.bind('<<TreeviewSelect>>', self.on_group_select)# 修改输入字段列表,确保与数据库字段完全匹配self.entries = {}fields = [("order_date", "单据日期"), ("order_number", "单据编号"),("customer", "客户名称"), ("product", "品名规格"),("unit", "单位"),("quantity", "数量"),("price", "原价"), ("discount", "单行折扣率(%)"),("final_price", "折后价"), ("total", "金额"),("remarks", "备注"), ("discount_amount", "整单折扣率(%)"),("discount_total", "折后金额"), ("delivery", "运费"),("payment_received", "本单已收"), ("end_customer", "结算账户"),("notes", "说明"), ("business", "营业员")]for row, (field, label) in enumerate(fields):ttk.Label(input_frame, text=label).grid(row=row//2, column=(row%2)*2, padx=5, pady=2)self.entries[field] = ttk.Entry(input_frame)self.entries[field].grid(row=row//2, column=(row%2)*2+1, padx=5, pady=2, sticky="ew")# 添加按钮self.btn_frame = ttk.Frame(self.root)self.btn_frame.pack(pady=5)ttk.Button(self.btn_frame, text="保存", command=self.save_order).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="清空", command=self.clear_fields).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="导入Excel", command=self.import_from_excel).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="导出模板", command=self.export_template).pack(side="left", padx=5)# 修改表格显示,显示所有列self.tree = ttk.Treeview(self.root, columns=["order_date", "order_number", "customer", "product", "unit","quantity", "price", "discount", "final_price", "total","remarks", "discount_amount", "discount_total", "delivery","payment_received", "end_customer", "notes", "business"], show="headings")# 修改列标题定义,显示所有列columns = [("order_date", "单据日期"), ("order_number", "单据编号"),("customer", "客户名称"), ("product", "品名规格"),("unit", "单位"),("quantity", "数量"),("price", "原价"), ("discount", "单行折扣率(%)"),("final_price", "折后价"), ("total", "金额"),("remarks", "备注"),("discount_amount", "整单折扣率(%)"),("discount_total", "折后金额"),("delivery", "运费"),("payment_received", "本单已收"),("end_customer", "结算账户"),("notes", "说明"),("business", "营业员")]for col, heading in columns:self.tree.heading(col, text=heading)self.tree.column(col, width=100)self.tree.pack(padx=5, pady=5, fill="both", expand=True)# 添加滚动条scrollbar = ttk.Scrollbar(self.root, orient="vertical", command=self.tree.yview)scrollbar.pack(side="right", fill="y")self.tree.configure(yscrollcommand=scrollbar.set)# 添加自动计算绑定self.entries['quantity'].bind('<KeyRelease>', self.calculate_total)self.entries['price'].bind('<KeyRelease>', self.calculate_total)self.entries['discount'].bind('<KeyRelease>', self.calculate_total)# 在订单分类框架底部添加合计标签self.total_label = ttk.Label(order_group_frame, text="合计金额: ¥0.00")self.total_label.pack(pady=5)def calculate_total(self, event=None):"""计算折后价和金额"""try:quantity = float(self.entries['quantity'].get() or 0)price = float(self.entries['price'].get() or 0)discount = float(self.entries['discount'].get() or 100)# 计算折后价final_price = price * discount / 100self.entries['final_price'].delete(0, tk.END)self.entries['final_price'].insert(0, f"{final_price:.2f}")# 计算金额total = quantity * final_priceself.entries['total'].delete(0, tk.END)self.entries['total'].insert(0, f"{total:.2f}")except ValueError:passdef create_search_frame(self):search_frame = ttk.LabelFrame(self.root, text="搜索")search_frame.pack(padx=5, pady=5, fill="x")ttk.Label(search_frame, text="搜索条件:").pack(side="left", padx=5)self.search_entry = ttk.Entry(search_frame)self.search_entry.pack(side="left", padx=5, fill="x", expand=True)ttk.Button(search_frame, text="搜索", command=self.search_orders).pack(side="left", padx=5)def add_function_buttons(self):# 在原有btn_frame中添加更多按钮ttk.Button(self.btn_frame, text="编辑", command=self.edit_selected).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="删除", command=self.delete_selected).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="导出Excel", command=self.export_to_excel).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="统计报表", command=self.show_statistics).pack(side="left", padx=5)def validate_data(self):"""数据验证"""errors = []# 验证日期格式date = self.entries['order_date'].get().strip()if not date:errors.append("单据日期不能为空")elif not re.match(r'^\d{4}-\d{2}-\d{2}$', date):errors.append("单据日期格式错误,应为 YYYY-MM-DD")# 验证必填字段required_fields = {'order_number': '单据编号','customer': '客户名称','product': '品名规格','unit': '单位','quantity': '数量','price': '原价'}for field, name in required_fields.items():value = self.entries[field].get().strip()if not value:errors.append(f"{name}不能为空")# 验证数字字段number_fields = {'quantity': '数量','price': '原价','discount': '单行折扣率(%)','final_price': '折后价','total': '金额','discount_amount': '整单折扣率(%)','discount_total': '折后金额','payment_received': '本单已收'}for field, name in number_fields.items():value = self.entries[field].get().strip()if value:  # 如果有值才验证try:num = float(value)if field in ['quantity', 'price'] and num <= 0:errors.append(f"{name}必须大于0")elif num < 0:errors.append(f"{name}不能为负数")except ValueError:errors.append(f"{name}必须是数字")if errors:messagebox.showerror("验证错误", "\n".join(errors))return Falsereturn Truedef save_order(self):"""保存订单数据"""if not self.validate_data():returntry:# 获取所有输入值values = []fields_order = ['order_date', 'order_number', 'customer', 'product', 'unit','quantity', 'price', 'discount', 'final_price', 'total','remarks', 'discount_amount', 'discount_total', 'delivery','payment_received', 'end_customer', 'notes', 'business']for field in fields_order:value = self.entries[field].get().strip()# 对数字字段进行转换if field in ['quantity', 'price', 'discount', 'final_price', 'total', 'discount_amount', 'discount_total', 'payment_received']:try:value = float(value) if value else 0.0except ValueError:value = 0.0elif not value:  # 对非数字字段,如果为空则设为空字符串value = ''values.append(value)# 检查单据编号是否重复cursor = self.conn.cursor()cursor.execute('SELECT COUNT(*) FROM orders WHERE order_number = ?', (values[1],))if cursor.fetchone()[0] > 0:if not messagebox.askyesno("警告", "单据编号已存在是否继续保存?"):return# 插入数据try:cursor.execute('''INSERT INTO orders VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', values)self.conn.commit()# 更新表格显示self.tree.insert("", "end", values=values)# 清空输入框并设置默认值self.set_default_values()# 显示成功消息messagebox.showinfo("成功", "订单保存成功!")except sqlite3.Error as e:self.conn.rollback()messagebox.showerror("数据库错误", f"保存失败:{str(e)}")returnexcept Exception as e:messagebox.showerror("错误", f"保存过程中出错:{str(e)}")returnself.update_order_groups()def clear_fields(self):"""清空所有输入框"""for field in self.entries:self.entries[field].delete(0, tk.END)def __del__(self):self.conn.close()def search_orders(self):search_text = self.search_entry.get().strip()if not search_text:self.load_all_orders()returncursor = self.conn.cursor()cursor.execute('''SELECT * FROM orders WHERE order_date LIKE ? OR order_number LIKE ? OR customer LIKE ? OR product LIKE ?''', [f'%{search_text}%'] * 4)self.tree.delete(*self.tree.get_children())for row in cursor.fetchall():self.tree.insert("", "end", values=row)def edit_selected(self):selected = self.tree.selection()if not selected:messagebox.showwarning("提示", "请先选择一条记录")returnitem = self.tree.item(selected[0])values = item['values']# 填充表单for field, value in zip(self.entries.keys(), values):self.entries[field].delete(0, tk.END)self.entries[field].insert(0, str(value))def delete_selected(self):selected = self.tree.selection()if not selected:messagebox.showwarning("提示", "请先选择一条记录")returnif messagebox.askyesno("确认", "确定要删除中的记录吗?"):item = self.tree.item(selected[0])order_number = item['values'][1]cursor = self.conn.cursor()cursor.execute('DELETE FROM orders WHERE order_number = ?', (order_number,))self.conn.commit()self.tree.delete(selected[0])self.update_order_groups()def export_to_excel(self):"""导出数据到Excel"""try:# 先获取保存路径filename = filedialog.asksaveasfilename(defaultextension=".xlsx",filetypes=[("Excel files", "*.xlsx")])if not filename:return# 获取数据cursor = self.conn.cursor()cursor.execute('SELECT * FROM orders')data = cursor.fetchall()# 准备列名columns = ['单据日期', '单据编号', '客户名称', '品名规格','单位', '数量', '原价', '单行折扣率(%)', '折后价', '金额', '备注', '整单折扣率(%)', '折后金额', '运费','本单已收', '结算账户', '说明', '营业员']# 创建DataFramedf = pd.DataFrame(data, columns=columns)# 直接导出df.to_excel(filename, index=False)messagebox.showinfo("成功", "数据已导出到Excel文件")except PermissionError:messagebox.showerror("错误", "无法保存文件,请确保:\n1. 文件未被其他程序打开\n2. 您有写入权限")except Exception as e:messagebox.showerror("错误", f"导出过程中出错:{str(e)}")def show_statistics(self):stats_window = tk.Toplevel(self.root)stats_window.title("统计报表")cursor = self.conn.cursor()# 客户统计cursor.execute('''SELECT customer, COUNT(*) as order_count,SUM(total) as total_amount,SUM(payment_received) as total_receivedFROM orders GROUP BY customer''')# 创建统计表格tree = ttk.Treeview(stats_window, columns=["customer", "count", "amount", "received"], show="headings")tree.heading("customer", text="客户")tree.heading("count", text="订单数")tree.heading("amount", text="总金额")tree.heading("received", text="已收金额")for row in cursor.fetchall():tree.insert("", "end", values=row)tree.pack(padx=5, pady=5, fill="both", expand=True)def load_all_orders(self):"""加载所有订单到表格"""cursor = self.conn.cursor()cursor.execute('SELECT * FROM orders')self.tree.delete(*self.tree.get_children())for row in cursor.fetchall():self.tree.insert("", "end", values=row)# 更新筛选下拉列表self.update_filter_lists()self.update_order_groups()def import_from_excel(self):"""从Excel文件导入数据"""filename = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")])if not filename:returntry:# 读取Excel文件df = pd.read_excel(filename)# 数字字段列表numeric_columns = ['数量', '原价', '单行折扣率(%)', '折后价', '金额','整单折扣率(%)', '折后金额', '运费', '本单已收']# 转换数字列的数据类型for col in numeric_columns:if col in df.columns:df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)# 检查必需的列是否存在required_columns = ['单据日期', '单据编号', '客户名称', '品名规格', '单位', '数量', '原价', '单行折扣率(%)', '折后价', '金额','备注', '整单折扣率(%)', '折后金额', '运费','本单已收', '结算账户', '说明', '营业员']missing_columns = [col for col in required_columns if col not in df.columns]if missing_columns:messagebox.showerror("错误", f"Excel文件缺少以下列:\n{', '.join(missing_columns)}")return# 创建预览窗口preview_window = tk.Toplevel(self.root)preview_window.title("导入数据预览")preview_window.geometry("800x600")# 创建预览表格preview_tree = ttk.Treeview(preview_window, columns=required_columns[:10], show="headings")# 设置列标题for col in required_columns[:10]:preview_tree.heading(col, text=col)preview_tree.column(col, width=100)# 添加数据到预��表格for _, row in df.iterrows():values = [row[col] for col in required_columns[:10]]preview_tree.insert("", "end", values=values)# 添加滚动条scrollbar = ttk.Scrollbar(preview_window, orient="vertical", command=preview_tree.yview)scrollbar.pack(side="right", fill="y")preview_tree.configure(yscrollcommand=scrollbar.set)preview_tree.pack(padx=5, pady=5, fill="both", expand=True)# 添加按钮框btn_frame = ttk.Frame(preview_window)btn_frame.pack(pady=5)def confirm_import():try:# 将数据插入数据库cursor = self.conn.cursor()# 定义字段映射field_mapping = {'单据日期': 'order_date','单据编号': 'order_number','客户名称': 'customer','品名规格': 'product','单位': 'unit','数量': 'quantity','原价': 'price','单行折扣率(%)': 'discount','折后价': 'final_price','金额': 'total','备注': 'remarks','整单折扣率(%)': 'discount_amount','折后金额': 'discount_total','运费': 'delivery','本单已收': 'payment_received','结算账户': 'end_customer','说明': 'notes','营业员': 'business'}# 获取数据字段顺序db_fields = ['order_date', 'order_number', 'customer', 'product', 'unit','quantity', 'price', 'discount', 'final_price', 'total','remarks', 'discount_amount', 'discount_total', 'delivery','payment_received', 'end_customer', 'notes', 'business']for _, row in df.iterrows():values = []for field in db_fields:# 从Excel列名映射到数据库字段excel_col = [k for k, v in field_mapping.items() if v == field][0]value = row[excel_col]# 处理数值if pd.isna(value):value = 0 if field in ['quantity', 'price', 'discount', 'final_price', 'total', 'discount_amount', 'discount_total', 'payment_received'] else ''elif isinstance(value, (int, float)):value = float(value)else:value = str(value)values.append(value)try:cursor.execute('''INSERT INTO orders VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', values)except sqlite3.Error as e:self.conn.rollback()messagebox.showerror("错误", f"插入数据时出错:{str(e)}\n行数据{values}")returnself.conn.commit()self.load_all_orders()messagebox.showinfo("成功", "数据导入成功!")preview_window.destroy()except Exception as e:self.conn.rollback()messagebox.showerror("错误", f"导入过程中出错:{str(e)}")def cancel_import():preview_window.destroy()# 添加确认和取消按钮ttk.Button(btn_frame, text="确认导入", command=confirm_import).pack(side="left", padx=5)ttk.Button(btn_frame, text="取消", command=cancel_import).pack(side="left", padx=5)# 显示导入数据的总数ttk.Label(preview_window, text=f"共 {len(df)} 条数据").pack(pady=5)except Exception as e:messagebox.showerror("错误", f"导入过程中出错:{str(e)}")self.update_order_groups()def export_template(self):"""导出Excel模板"""filename = filedialog.asksaveasfilename(defaultextension=".xlsx",filetypes=[("Excel files", "*.xlsx")],initialfile="订单导出模板.xlsx")if not filename:returntry:# 创建示例数据 - 使用相同的列名sample_data = {'单据日期': ['2024-01-01'],'单据编号': ['XSD202401001'],'客户名称': ['示例客户'],'品名规格': ['示例产品'],'单位': ['个'],'数量': [1],'原价': [100],'单行折扣率(%)': [100],'折后价': [100],'金额': [100],'备注': ['备注示例'],'整单折扣率(%)': [0],'折后金额': [100],'运费': [0],'本单已收': [0],'结算账户': ['结算账户示例'],'说明': ['说明示例'],'营业员': ['营业员示例']}# 创建DataFramedf = pd.DataFrame(sample_data)# 创建Excel写入器with pd.ExcelWriter(filename, engine='openpyxl') as writer:# 写入数据df.to_excel(writer, index=False, sheet_name='订单数据')# 获取工作表worksheet = writer.sheets['订单数据']# 设置列宽for column in worksheet.columns:max_length = 0column = [cell for cell in column]for cell in column:try:if len(str(cell.value)) > max_length:max_length = len(str(cell.value))except:passadjusted_width = (max_length + 2)worksheet.column_dimensions[column[0].column_letter].width = adjusted_width# 设置样式from openpyxl.styles import PatternFill, Font, Alignment, Border, Side# 定义样式header_fill = PatternFill(start_color='CCE5FF', end_color='CCE5FF', fill_type='solid')header_font = Font(bold=True)center_aligned = Alignment(horizontal='center', vertical='center')border = Border(left=Side(style='thin'),right=Side(style='thin'),top=Side(style='thin'),bottom=Side(style='thin'))# 应用表头样式for cell in worksheet[1]:cell.fill = header_fillcell.font = header_fontcell.alignment = center_alignedcell.border = border# 应用数据行样式for row in worksheet.iter_rows(min_row=2):for cell in row:cell.alignment = center_alignedcell.border = bordermessagebox.showinfo("成功", "模板导出成功!\n请按照模板格式准备数据后再进行导。")except Exception as e:messagebox.showerror("错误", f"导出模板时出错:{str(e)}")def set_default_values(self):"""设置默认值"""# 清空所有输入框self.clear_fields()# 只设置日期和折扣率的默认值today = datetime.now().strftime('%Y-%m-%d')self.entries['order_date'].insert(0, today)  # 默认日期为今天self.entries['discount'].insert(0, '100')    # 默认折扣率为100%# 生成新的单据编号cursor = self.conn.cursor()cursor.execute('''SELECT MAX(order_number) FROM orders WHERE order_number LIKE ?''', [f'XSD{today.replace("-", "")}%'])last_number = cursor.fetchone()[0]if last_number:try:# 从最后一个单号提取序号并加1seq = int(last_number[-3:]) + 1new_number = f'XSD{today.replace("-", "")}{seq:03d}'except ValueError:new_number = f'XSD{today.replace("-", "")}001'else:new_number = f'XSD{today.replace("-", "")}001'self.entries['order_number'].insert(0, new_number)  # 设置新单据编号def update_order_groups(self):"""更新订单分类显示"""cursor = self.conn.cursor()cursor.execute('''SELECT order_number, customer, product, unit, quantity, price, total, remarks,SUM(total) OVER () as total_sumFROM orders ORDER BY order_number DESC''')# 清空现有数据self.group_tree.delete(*self.group_tree.get_children())total_sum = 0# 插入新数据for row in cursor.fetchall():formatted_row = list(row[:8])  # 只取前8列显示# 格式化数字列formatted_row[4] = f"{row[4]:.2f}"  # 数量formatted_row[5] = f"¥{row[5]:.2f}"  # 原价formatted_row[6] = f"¥{row[6]:.2f}"  # 金额self.group_tree.insert("", "end", values=formatted_row)total_sum = row[8]  # 获取合计金额# 更新合计标签self.total_label.config(text=f"合计金额: ¥{total_sum:,.2f}")def on_group_select(self, event):"""当选择订单分类时的处理"""selected = self.group_tree.selection()if not selected:return# 获取选中的单据编号order_number = self.group_tree.item(selected[0])['values'][0]# 在主表格中查找并选中对应的记录for item in self.tree.get_children():if self.tree.item(item)['values'][1] == order_number:  # 假设单据编号是第二列self.tree.selection_set(item)self.tree.see(item)  # 确保选中的项可见breakdef filter_orders(self):"""根据筛选条件过滤订单"""order_number = self.order_number_filter.get().strip()customer = self.customer_filter.get().strip()cursor = self.conn.cursor()# 构建查询条件query = '''SELECT order_number, customer, product, unit, quantity, price, total, remarks,SUM(total) OVER () as total_sumFROM orders WHERE 1=1'''params = []if order_number:query += " AND order_number LIKE ?"params.append(f"%{order_number}%")if customer:query += " AND customer LIKE ?"params.append(f"%{customer}%")query += " ORDER BY order_number DESC"cursor.execute(query, params)# 清空现有数据self.group_tree.delete(*self.group_tree.get_children())total_sum = 0# 插入新数据for row in cursor.fetchall():formatted_row = list(row[:8])  # 只取前8列显示# 格式化数字列formatted_row[4] = f"{row[4]:.2f}"  # 数量formatted_row[5] = f"¥{row[5]:.2f}"  # 原价formatted_row[6] = f"¥{row[6]:.2f}"  # 金额self.group_tree.insert("", "end", values=formatted_row)total_sum = row[8]  # 获取合计金额# 更新合计标签self.total_label.config(text=f"合计金额: ¥{total_sum:,.2f}")def reset_filter(self):"""重置筛选条件"""self.order_number_filter.delete(0, tk.END)self.customer_filter.delete(0, tk.END)self.update_order_groups()def update_order_number_list(self, event=None):"""更新单据编号下拉列表"""search_text = self.order_number_filter.get().strip()cursor = self.conn.cursor()if search_text:cursor.execute('''SELECT DISTINCT order_number FROM orders WHERE order_number LIKE ? ORDER BY order_number DESC''', [f'%{search_text}%'])else:cursor.execute('''SELECT DISTINCT order_number FROM orders ORDER BY order_number DESC''')order_numbers = [row[0] for row in cursor.fetchall()]if order_numbers:self.order_number_filter['values'] = order_numbersif search_text:self.order_number_filter.event_generate('<Down>')def update_customer_list(self, event=None):"""更新客户名称下拉列表"""search_text = self.customer_filter.get().strip()cursor = self.conn.cursor()if search_text:cursor.execute('''SELECT DISTINCT customer FROM orders WHERE customer LIKE ? ORDER BY customer''', [f'%{search_text}%'])else:cursor.execute('''SELECT DISTINCT customer FROM orders ORDER BY customer''')customers = [row[0] for row in cursor.fetchall()]if customers:self.customer_filter['values'] = customersif search_text:self.customer_filter.event_generate('<Down>')def update_filter_lists(self):"""更新所有筛选下拉列表"""cursor = self.conn.cursor()# 更新单据编号列表cursor.execute('SELECT DISTINCT order_number FROM orders ORDER BY order_number DESC')self.order_number_filter['values'] = [row[0] for row in cursor.fetchall()]# 更新客户名称列表cursor.execute('SELECT DISTINCT customer FROM orders ORDER BY customer')self.customer_filter['values'] = [row[0] for row in cursor.fetchall()]def print_filtered_data(self):"""打印筛选后的数据"""try:# 获取当前筛选条件下的数据order_number = self.order_number_filter.get().strip()customer = self.customer_filter.get().strip()# 构建查询条件query = '''SELECT order_number, customer, product, unit, quantity, price, total, remarks,SUM(total) OVER () as total_sumFROM orders WHERE 1=1'''params = []if order_number:query += " AND order_number LIKE ?"params.append(f"%{order_number}%")if customer:query += " AND customer LIKE ?"params.append(f"%{customer}%")query += " ORDER BY order_number DESC"cursor = self.conn.cursor()cursor.execute(query, params)rows = cursor.fetchall()if not rows:messagebox.showinfo("提示", "没有数据可打印")return# 生成HTML内容html_content = f"""<!DOCTYPE html><html><head><meta charset="utf-8"><title>订单查询结果</title><style>body {{ font-family: SimSun, serif; }}table {{ border-collapse: collapse; width: 100%; margin-top: 10px; }}th, td {{ border: 1px solid black; padding: 8px; text-align: center; }}th {{ background-color: #f2f2f2; }}.total {{ text-align: right;padding: 10px;font-weight: bold;}}.header-info {{margin: 10px 0;padding: 10px;border: 1px solid #ddd;background-color: #f9f9f9;}}.header-info p {{margin: 5px 0;}}@media print {{.no-print {{ display: none; }}body {{ margin: 0; }}table {{ page-break-inside: auto; }}tr {{ page-break-inside: avoid; }}}}</style></head><body><h2 style="text-align: center;">订单查询结果</h2><div class="header-info"><p><strong>单据编号:</strong>{order_number if order_number else "全部"}</p><p><strong>客户名称:</strong>{customer if customer else "全部"}</p><p><strong>打印时间:</strong>{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p></div><table><tr><th>品名规格</th><th>单位</th><th>数量</th><th>原价</th><th>金额</th><th>备注</th></tr>"""# 添加数据行for row in rows:html_content += f"""<tr><td>{row[2]}</td><td>{row[3]}</td><td>{row[4]:.2f}</td><td>¥{row[5]:.2f}</td><td>¥{row[6]:.2f}</td><td>{row[7]}</td></tr>"""# 添加合计行total_sum = rows[0][8] if rows else 0html_content += f"""</table><div class="total">合计金额: ¥{total_sum:,.2f}</div><div class="no-print" style="margin-top: 20px; text-align: center;"><button onclick="window.print()">打印</button></div></body></html>"""# 保存HTML文件temp_file = "订单查询结果.html"with open(temp_file, "w", encoding="utf-8") as f:f.write(html_content)# 在默认浏览器中打开HTML文件import webbrowserwebbrowser.open(temp_file)except Exception as e:messagebox.showerror("错误", f"打印过程中出错:{str(e)}")if __name__ == "__main__":root = tk.Tk()app = OrderSystem(root)root.mainloop()

 程序简要说明

这是一个订单管理系统,主要功能如下:

1. 基本功能:
   - 订单录入和保存
   - 订单查询和筛选
   - 数据导入导出(Excel格式)
   - 打印功能(HTML格式)

2. 界面布局:
   - 左侧:订单信息录入表单
   - 中间:订单数据列表
   - 右侧:订单查询面板(带筛选和统计)

3. 主要特点:
   - 自动生成单据编号(格式:XSD + 日期 + 3位序号)
   - 支持数字字段自动计算(数量、单价、折扣等)
   - 提供下拉选择和手动输入的组合筛选
   - 实时显示筛选结果的合计金额

4. 数据管理:
   - 使用SQLite数据库存储数据
   - 支持Excel导入导出
   - 提供数据验证和错误处理

5. 使用方法:
   ```python
   if __name__ == "__main__":
       root = tk.Tk()
       app = OrderSystem(root)
       root.mainloop()
   ```

6. 依赖库:
   - tkinter:GUI界面
   - sqlite3:数据库操作
   - pandas:Excel处理
   - datetime:日期处理
   - webbrowser:打印功能

这个程序适合小型企业或个人用于日常订单管理和记录。
 


1.1 1.1 版本

添加以下功能:

1. 程序启动时需要输入密码才能进入  

2. 默认密码为 "admin"  

3. 可以通过界面修改登录密码  

4. 数据库使用相同的密码进行加密保护

5. 密码以哈希形式存储在 config.json 文件中  (放入 db目录里)

使用说明:

1. 首次运行时,默认密码为 "admin"  

2. 登录后可以点击"修改密码"按钮更改密码

3. 新密码会同时用于程序登录和数据库加密

4. 如果忘记密码,需要删除 config.json 文件,程序会重置为默认密码  

注意事项:

1. 修改密码后,请务必记住新密码,因为它同时用于程序登录和数据库加密  

2. 建议定期备份数据库文件(数据库也放在 db目录里)

login.py

import tkinter as tk
from tkinter import ttk, messagebox
import hashlib
import json
import osclass LoginWindow:def __init__(self):self.window = tk.Tk()self.window.title("登录")self.window.geometry("300x150")self.login_success = False  # 添加登录状态标志# 居中显示self.window.update_idletasks()width = self.window.winfo_width()height = self.window.winfo_height()x = (self.window.winfo_screenwidth() // 2) - (width // 2)y = (self.window.winfo_screenheight() // 2) - (height // 2)self.window.geometry(f"{width}x{height}+{x}+{y}")# 创建登录框架frame = ttk.Frame(self.window, padding="20")frame.pack(fill="both", expand=True)ttk.Label(frame, text="请输入密码:").pack(pady=5)self.password_var = tk.StringVar()self.password_entry = ttk.Entry(frame, show="*", textvariable=self.password_var)self.password_entry.pack(pady=5, fill="x")btn_frame = ttk.Frame(frame)btn_frame.pack(pady=10)ttk.Button(btn_frame, text="登录", command=self.login).pack(side="left", padx=5)ttk.Button(btn_frame, text="修改密码", command=self.change_password).pack(side="left", padx=5)self.password_entry.bind('<Return>', lambda e: self.login())self.password_entry.focus()self.load_password()def load_password(self):"""加载保存的密码哈希"""try:if os.path.exists('db/config.json'):with open('db/config.json', 'r') as f:config = json.load(f)self.password_hash = config.get('password_hash', self.hash_password('admin'))else:# 默认密码为 'admin'self.password_hash = self.hash_password('admin')self.save_password()except Exception:self.password_hash = self.hash_password('admin')def save_password(self):"""保存密码哈希到配置文件"""config = {'password_hash': self.password_hash}with open('db/config.json', 'w') as f:json.dump(config, f)def hash_password(self, password):"""对密码进行哈希处理"""return hashlib.sha256(password.encode()).hexdigest()def login(self):"""验证密码"""if self.hash_password(self.password_var.get()) == self.password_hash:self.login_success = True  # 设置登录成功标志self.window.destroy()return Trueelse:messagebox.showerror("错误", "密码错误!")self.password_var.set("")return Falsedef change_password(self):"""修改密码"""change_window = tk.Toplevel(self.window)change_window.title("修改密码")change_window.geometry("300x400")# 居中显示change_window.update_idletasks()width = change_window.winfo_width()height = change_window.winfo_height()x = (change_window.winfo_screenwidth() // 2) - (width // 2)y = (change_window.winfo_screenheight() // 2) - (height // 2)change_window.geometry(f"{width}x{height}+{x}+{y}")frame = ttk.Frame(change_window, padding="20")frame.pack(fill="both", expand=True)# 当前密码ttk.Label(frame, text="当前密码:").pack(pady=5)current_password = ttk.Entry(frame, show="*")current_password.pack(pady=5, fill="x")# 新密码ttk.Label(frame, text="新密码:").pack(pady=5)new_password = ttk.Entry(frame, show="*")new_password.pack(pady=5, fill="x")# 确认新密码ttk.Label(frame, text="确认新密码:").pack(pady=5)confirm_password = ttk.Entry(frame, show="*")confirm_password.pack(pady=5, fill="x")def do_change():if self.hash_password(current_password.get()) != self.password_hash:messagebox.showerror("错误", "当前密码错误!")returnif new_password.get() != confirm_password.get():messagebox.showerror("错误", "两次输入的新密码不一致!")returnif not new_password.get():messagebox.showerror("错误", "新密码不能为空!")returnself.password_hash = self.hash_password(new_password.get())self.save_password()messagebox.showinfo("成功", "密码修改成功!")change_window.destroy()ttk.Button(frame, text="确认修改", command=do_change).pack(pady=10)def run(self):"""运行登录窗口"""self.window.protocol("WM_DELETE_WINDOW", self.on_closing)  # 添加窗口关闭事件处理self.window.mainloop()return self.login_success  # 返回登录状态def on_closing(self):"""窗口关闭事件处理"""if messagebox.askokcancel("退出", "确定要退出程序吗?"):self.login_success = Falseself.window.destroy() 

 主程序.py

import tkinter as tk
from tkinter import ttk
import sqlite3
from datetime import datetime
from tkinter import messagebox, filedialog
import pandas as pd
import re
import json
import sys
from login import LoginWindowclass OrderSystem:def __init__(self, root):self.root = rootself.root.title("订单记录系统")# 创建数据库连接self.db_password = self.get_db_password()  # 获取数据库密码self.conn = self.create_db_connection()self.create_table()# 创建界面self.create_ui()# 添加搜索框架self.create_search_frame()# 添加更多功能按钮self.add_function_buttons()# 加载所有订单数据self.load_all_orders()# 设置默认值self.set_default_values()def get_db_password(self):"""从配置文件获取数据库密码"""try:with open('db/config.json', 'r') as f:config = json.load(f)return config.get('password_hash', '')except Exception:return ''def create_db_connection(self):"""创建加密的数据库连接"""try:conn = sqlite3.connect('orders.db')# 设置数据库密码conn.execute(f"PRAGMA key = '{self.db_password}'")return connexcept sqlite3.Error as e:messagebox.showerror("错误", f"数据库连接失败:{str(e)}")sys.exit(1)def create_table(self):cursor = self.conn.cursor()cursor.execute('''CREATE TABLE IF NOT EXISTS orders (order_date TEXT,order_number TEXT,customer TEXT,product TEXT,unit TEXT,quantity REAL,price REAL,discount REAL,final_price REAL,total REAL,remarks TEXT,discount_amount REAL,discount_total REAL,delivery TEXT,payment_received REAL,end_customer TEXT,notes TEXT,business TEXT)''')self.conn.commit()def create_ui(self):# 创建主框架来容纳左右两部分main_frame = ttk.Frame(self.root)main_frame.pack(fill="both", expand=True)# 创建左侧框架left_frame = ttk.Frame(main_frame)left_frame.pack(side="left", fill="both", expand=True)# 创建右侧框架right_frame = ttk.Frame(main_frame)right_frame.pack(side="right", fill="y", padx=5)# 创建输入框架(放在左侧)input_frame = ttk.LabelFrame(left_frame, text="订单信息")input_frame.pack(padx=5, pady=5, fill="x")# 修改订单分类框架order_group_frame = ttk.LabelFrame(right_frame, text="订单查询")order_group_frame.pack(padx=5, pady=5, fill="both", expand=True)# 添加筛选框filter_frame = ttk.Frame(order_group_frame)filter_frame.pack(fill="x", padx=5, pady=5)# 单据编号筛选ttk.Label(filter_frame, text="单据编号:").grid(row=0, column=0, padx=5)self.order_number_filter = ttk.Combobox(filter_frame, width=15)self.order_number_filter.grid(row=0, column=1, padx=5)# 客户名称筛选ttk.Label(filter_frame, text="客户名称:").grid(row=0, column=2, padx=5)self.customer_filter = ttk.Combobox(filter_frame, width=15)self.customer_filter.grid(row=0, column=3, padx=5)# 筛选按钮ttk.Button(filter_frame, text="筛选", command=self.filter_orders).grid(row=0, column=4, padx=5)ttk.Button(filter_frame, text="重置", command=self.reset_filter).grid(row=0, column=5, padx=5)ttk.Button(filter_frame, text="打印", command=self.print_filtered_data).grid(row=0, column=6, padx=5)# 绑定下拉框事件self.order_number_filter.bind('<KeyRelease>', self.update_order_number_list)self.customer_filter.bind('<KeyRelease>', self.update_customer_list)# 修改订单分类的树形视图列self.group_tree = ttk.Treeview(order_group_frame, columns=["order_number", "customer", "product", "unit", "quantity", "price", "total", "remarks"], show="headings", height=15)# 设置列标题和宽度columns = [("order_number", "单据编号", 100),("customer", "客户名称", 100),("product", "品名规格", 120),("unit", "单位", 50),("quantity", "数量", 60),("price", "原价", 80),("total", "金额", 80),("remarks", "备注", 100)]for col, heading, width in columns:self.group_tree.heading(col, text=heading)self.group_tree.column(col, width=width)self.group_tree.pack(padx=5, pady=5, fill="both", expand=True)# 添加滚动条group_scrollbar = ttk.Scrollbar(order_group_frame, orient="vertical", command=self.group_tree.yview)group_scrollbar.pack(side="right", fill="y")self.group_tree.configure(yscrollcommand=group_scrollbar.set)# 绑定点击事件self.group_tree.bind('<<TreeviewSelect>>', self.on_group_select)# 修改输入字段列表,确保与数据库字段完全匹配self.entries = {}fields = [("order_date", "单据日期"), ("order_number", "单据编号"),("customer", "客户名称"), ("product", "品名规格"),("unit", "单位"),("quantity", "数量"),("price", "原价"), ("discount", "单行折扣率(%)"),("final_price", "折后价"), ("total", "金额"),("remarks", "备注"), ("discount_amount", "整单折扣率(%)"),("discount_total", "折后金额"), ("delivery", "运费"),("payment_received", "本单已收"), ("end_customer", "结算账户"),("notes", "说明"), ("business", "营业员")]for row, (field, label) in enumerate(fields):ttk.Label(input_frame, text=label).grid(row=row//2, column=(row%2)*2, padx=5, pady=2)self.entries[field] = ttk.Entry(input_frame)self.entries[field].grid(row=row//2, column=(row%2)*2+1, padx=5, pady=2, sticky="ew")# 添加按钮self.btn_frame = ttk.Frame(self.root)self.btn_frame.pack(pady=5)ttk.Button(self.btn_frame, text="保存", command=self.save_order).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="清空", command=self.clear_fields).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="导入Excel", command=self.import_from_excel).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="导出模板", command=self.export_template).pack(side="left", padx=5)# 修改表格显示,显示所有列self.tree = ttk.Treeview(self.root, columns=["order_date", "order_number", "customer", "product", "unit","quantity", "price", "discount", "final_price", "total","remarks", "discount_amount", "discount_total", "delivery","payment_received", "end_customer", "notes", "business"], show="headings")# 修改列标题定义,显示所有列columns = [("order_date", "单据日期"), ("order_number", "单据编号"),("customer", "客户名称"), ("product", "品名规格"),("unit", "单位"),("quantity", "数量"),("price", "原价"), ("discount", "单行折扣率(%)"),("final_price", "折后价"), ("total", "金额"),("remarks", "备注"),("discount_amount", "整单折扣率(%)"),("discount_total", "折后金额"),("delivery", "运费"),("payment_received", "本单已收"),("end_customer", "结算账户"),("notes", "说明"),("business", "营业员")]for col, heading in columns:self.tree.heading(col, text=heading)self.tree.column(col, width=100)self.tree.pack(padx=5, pady=5, fill="both", expand=True)# 添加滚动条scrollbar = ttk.Scrollbar(self.root, orient="vertical", command=self.tree.yview)scrollbar.pack(side="right", fill="y")self.tree.configure(yscrollcommand=scrollbar.set)# 添加自动计算绑定self.entries['quantity'].bind('<KeyRelease>', self.calculate_total)self.entries['price'].bind('<KeyRelease>', self.calculate_total)self.entries['discount'].bind('<KeyRelease>', self.calculate_total)# 在订单分类框架底部添加合计标签self.total_label = ttk.Label(order_group_frame, text="合计金额: ¥0.00")self.total_label.pack(pady=5)def calculate_total(self, event=None):"""计算折后价和金额"""try:quantity = float(self.entries['quantity'].get() or 0)price = float(self.entries['price'].get() or 0)discount = float(self.entries['discount'].get() or 100)# 计算折后价final_price = price * discount / 100self.entries['final_price'].delete(0, tk.END)self.entries['final_price'].insert(0, f"{final_price:.2f}")# 计算金额total = quantity * final_priceself.entries['total'].delete(0, tk.END)self.entries['total'].insert(0, f"{total:.2f}")except ValueError:passdef create_search_frame(self):search_frame = ttk.LabelFrame(self.root, text="搜索")search_frame.pack(padx=5, pady=5, fill="x")ttk.Label(search_frame, text="搜索条件:").pack(side="left", padx=5)self.search_entry = ttk.Entry(search_frame)self.search_entry.pack(side="left", padx=5, fill="x", expand=True)ttk.Button(search_frame, text="搜索", command=self.search_orders).pack(side="left", padx=5)def add_function_buttons(self):# 在原有btn_frame中添加更多按钮ttk.Button(self.btn_frame, text="编辑", command=self.edit_selected).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="删除", command=self.delete_selected).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="导出Excel", command=self.export_to_excel).pack(side="left", padx=5)ttk.Button(self.btn_frame, text="统计报表", command=self.show_statistics).pack(side="left", padx=5)def validate_data(self):"""数据验证"""errors = []# 验证日期格式date = self.entries['order_date'].get().strip()if not date:errors.append("单据日期不能空")elif not re.match(r'^\d{4}-\d{2}-\d{2}$', date):errors.append("单据日期格式错误,应为 YYYY-MM-DD")# 验证必填字段required_fields = {'order_number': '单据编号','customer': '客户名称','product': '品名规格','unit': '单位','quantity': '数量','price': '原价'}for field, name in required_fields.items():value = self.entries[field].get().strip()if not value:errors.append(f"{name}不能为空")# 验证数字字段number_fields = {'quantity': '数量','price': '原价','discount': '单行折扣率(%)','final_price': '折后价','total': '金额','discount_amount': '整单折扣率(%)','discount_total': '折后金额','payment_received': '本单已收'}for field, name in number_fields.items():value = self.entries[field].get().strip()if value:  # 如果有值才验证try:num = float(value)if field in ['quantity', 'price'] and num <= 0:errors.append(f"{name}必须大于0")elif num < 0:errors.append(f"{name}不能为负数")except ValueError:errors.append(f"{name}必须是数字")if errors:messagebox.showerror("验证错误", "\n".join(errors))return Falsereturn Truedef save_order(self):"""保存订单数据"""if not self.validate_data():returntry:# 获取所有输入值values = []fields_order = ['order_date', 'order_number', 'customer', 'product', 'unit','quantity', 'price', 'discount', 'final_price', 'total','remarks', 'discount_amount', 'discount_total', 'delivery','payment_received', 'end_customer', 'notes', 'business']for field in fields_order:value = self.entries[field].get().strip()# 对数字字段进行转换if field in ['quantity', 'price', 'discount', 'final_price', 'total', 'discount_amount', 'discount_total', 'payment_received']:try:value = float(value) if value else 0.0except ValueError:value = 0.0elif not value:  # 对非数字字段,如果为空则设为空字��串value = ''values.append(value)# 检查单据编号是否重复cursor = self.conn.cursor()cursor.execute('SELECT COUNT(*) FROM orders WHERE order_number = ?', (values[1],))if cursor.fetchone()[0] > 0:if not messagebox.askyesno("警告", "单据编号已存在是否继续保存?"):return# 插入数据try:cursor.execute('''INSERT INTO orders VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', values)self.conn.commit()# 更新表格显示self.tree.insert("", "end", values=values)# 清空输入框并设置默认值self.set_default_values()# 显示成功消息messagebox.showinfo("成功", "订单保存成功!")except sqlite3.Error as e:self.conn.rollback()messagebox.showerror("数据库错误", f"保存失败:{str(e)}")returnexcept Exception as e:messagebox.showerror("错误", f"保存过程中出错:{str(e)}")returnself.update_order_groups()def clear_fields(self):"""清空所有输入框"""for field in self.entries:self.entries[field].delete(0, tk.END)def __del__(self):self.conn.close()def search_orders(self):search_text = self.search_entry.get().strip()if not search_text:self.load_all_orders()returncursor = self.conn.cursor()cursor.execute('''SELECT * FROM orders WHERE order_date LIKE ? OR order_number LIKE ? OR customer LIKE ? OR product LIKE ?''', [f'%{search_text}%'] * 4)self.tree.delete(*self.tree.get_children())for row in cursor.fetchall():self.tree.insert("", "end", values=row)def edit_selected(self):selected = self.tree.selection()if not selected:messagebox.showwarning("提示", "请先选择一条记录")returnitem = self.tree.item(selected[0])values = item['values']# 填充表单for field, value in zip(self.entries.keys(), values):self.entries[field].delete(0, tk.END)self.entries[field].insert(0, str(value))def delete_selected(self):selected = self.tree.selection()if not selected:messagebox.showwarning("提示", "请先选择一条记录")returnif messagebox.askyesno("确认", "确定要删除中的记录吗?"):item = self.tree.item(selected[0])order_number = item['values'][1]cursor = self.conn.cursor()cursor.execute('DELETE FROM orders WHERE order_number = ?', (order_number,))self.conn.commit()self.tree.delete(selected[0])self.update_order_groups()def export_to_excel(self):"""导出数据到Excel"""try:# 先获取保存路径filename = filedialog.asksaveasfilename(defaultextension=".xlsx",filetypes=[("Excel files", "*.xlsx")])if not filename:return# 获取数据cursor = self.conn.cursor()cursor.execute('SELECT * FROM orders')data = cursor.fetchall()# 准备列名columns = ['单据日期', '单据编号', '客户名称', '品名规格','单位', '数量', '原价', '单行折扣率(%)', '折后价', '金额', '备注', '整单折扣率(%)', '折后金额', '运费','本单已收', '结算账户', '说明', '营业员']# 创建DataFramedf = pd.DataFrame(data, columns=columns)# 直接导出df.to_excel(filename, index=False)messagebox.showinfo("成功", "数据已导出到Excel文件")except PermissionError:messagebox.showerror("错误", "无法保存文件,请确保:\n1. 文件未被其他程序打开\n2. 您有写入权限")except Exception as e:messagebox.showerror("错误", f"导出过程中出错:{str(e)}")def show_statistics(self):stats_window = tk.Toplevel(self.root)stats_window.title("统计报表")cursor = self.conn.cursor()# 客户统计cursor.execute('''SELECT customer, COUNT(*) as order_count,SUM(total) as total_amount,SUM(payment_received) as total_receivedFROM orders GROUP BY customer''')# 创建统计表格tree = ttk.Treeview(stats_window, columns=["customer", "count", "amount", "received"], show="headings")tree.heading("customer", text="客户")tree.heading("count", text="订单数")tree.heading("amount", text="总金额")tree.heading("received", text="已收金额")for row in cursor.fetchall():tree.insert("", "end", values=row)tree.pack(padx=5, pady=5, fill="both", expand=True)def load_all_orders(self):"""加载所有订单到表格"""cursor = self.conn.cursor()cursor.execute('SELECT * FROM orders')self.tree.delete(*self.tree.get_children())for row in cursor.fetchall():self.tree.insert("", "end", values=row)# 更新筛选下拉列表self.update_filter_lists()self.update_order_groups()def import_from_excel(self):"""从Excel文件导入数据"""filename = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")])if not filename:returntry:# 读取Excel文件df = pd.read_excel(filename)# 数字字段列表numeric_columns = ['数量', '原价', '单行折扣率(%)', '折后价', '金额','整单折扣率(%)', '折后金额', '运费', '本单已收']# 转换数字列的数据类型for col in numeric_columns:if col in df.columns:df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)# 检查必需的列是否存在required_columns = ['单据日期', '单据编号', '客户名称', '品名规格', '单位', '数量', '原价', '单行折扣率(%)', '折后价', '金额','备注', '整单折扣率(%)', '折后金额', '运费','本单已收', '结算账户', '说明', '营业员']missing_columns = [col for col in required_columns if col not in df.columns]if missing_columns:messagebox.showerror("错误", f"Excel文件缺少以下列:\n{', '.join(missing_columns)}")return# 创建预览窗口preview_window = tk.Toplevel(self.root)preview_window.title("导入数据预览")preview_window.geometry("800x600")# 创建预览表格preview_tree = ttk.Treeview(preview_window, columns=required_columns[:10], show="headings")# 设置列标题for col in required_columns[:10]:preview_tree.heading(col, text=col)preview_tree.column(col, width=100)# 添加数据到预览表格for _, row in df.iterrows():values = [row[col] for col in required_columns[:10]]preview_tree.insert("", "end", values=values)# 添加滚动条scrollbar = ttk.Scrollbar(preview_window, orient="vertical", command=preview_tree.yview)scrollbar.pack(side="right", fill="y")preview_tree.configure(yscrollcommand=scrollbar.set)preview_tree.pack(padx=5, pady=5, fill="both", expand=True)# 添加按钮框btn_frame = ttk.Frame(preview_window)btn_frame.pack(pady=5)def confirm_import():try:# 将数据���入数据库cursor = self.conn.cursor()# 定义字段映射field_mapping = {'单据日期': 'order_date','单据编号': 'order_number','客户名称': 'customer','品名规格': 'product','单位': 'unit','数量': 'quantity','原价': 'price','单行折扣率(%)': 'discount','折后价': 'final_price','金额': 'total','备注': 'remarks','整单折扣率(%)': 'discount_amount','折后金额': 'discount_total','运费': 'delivery','本单已收': 'payment_received','结算账户': 'end_customer','说明': 'notes','营业员': 'business'}# 获取数据字段顺序db_fields = ['order_date', 'order_number', 'customer', 'product', 'unit','quantity', 'price', 'discount', 'final_price', 'total','remarks', 'discount_amount', 'discount_total', 'delivery','payment_received', 'end_customer', 'notes', 'business']for _, row in df.iterrows():values = []for field in db_fields:# 从Excel列名映射到数据库字段excel_col = [k for k, v in field_mapping.items() if v == field][0]value = row[excel_col]# 处理数值if pd.isna(value):value = 0 if field in ['quantity', 'price', 'discount', 'final_price', 'total', 'discount_amount', 'discount_total', 'payment_received'] else ''elif isinstance(value, (int, float)):value = float(value)else:value = str(value)values.append(value)try:cursor.execute('''INSERT INTO orders VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', values)except sqlite3.Error as e:self.conn.rollback()messagebox.showerror("错误", f"插入数据时出错:{str(e)}\n行数据{values}")returnself.conn.commit()self.load_all_orders()messagebox.showinfo("成功", "数据导入成功!")preview_window.destroy()except Exception as e:self.conn.rollback()messagebox.showerror("错误", f"导入过程中出错:{str(e)}")def cancel_import():preview_window.destroy()# 添加确认和取消按钮ttk.Button(btn_frame, text="确认导入", command=confirm_import).pack(side="left", padx=5)ttk.Button(btn_frame, text="取消", command=cancel_import).pack(side="left", padx=5)# 显示导入数据的总数ttk.Label(preview_window, text=f"共 {len(df)} 条数据").pack(pady=5)except Exception as e:messagebox.showerror("错误", f"导入过程中出错:{str(e)}")self.update_order_groups()def export_template(self):"""导出Excel模板"""filename = filedialog.asksaveasfilename(defaultextension=".xlsx",filetypes=[("Excel files", "*.xlsx")],initialfile="订单导出模板.xlsx")if not filename:returntry:# 创建示例数据 - 使用相同的列名sample_data = {'单据日期': ['2024-01-01'],'单据编号': ['XSD202401001'],'客户名称': ['示例客户'],'品名规格': ['示例产品'],'单位': ['个'],'数量': [1],'原价': [100],'单行折扣率(%)': [100],'折后价': [100],'金额': [100],'备注': ['备注示例'],'整单折扣率(%)': [0],'折后金额': [100],'运费': [0],'本单已收': [0],'结算账户': ['结算账户示例'],'说明': ['说明示例'],'营业员': ['营业员示例']}# 创建DataFramedf = pd.DataFrame(sample_data)# 创建Excel写入器with pd.ExcelWriter(filename, engine='openpyxl') as writer:# 写入数据df.to_excel(writer, index=False, sheet_name='订单数据')# 获取工作表worksheet = writer.sheets['订单数据']# 设置列宽for column in worksheet.columns:max_length = 0column = [cell for cell in column]for cell in column:try:if len(str(cell.value)) > max_length:max_length = len(str(cell.value))except:passadjusted_width = (max_length + 2)worksheet.column_dimensions[column[0].column_letter].width = adjusted_width# 设置样式from openpyxl.styles import PatternFill, Font, Alignment, Border, Side# 定义样式header_fill = PatternFill(start_color='CCE5FF', end_color='CCE5FF', fill_type='solid')header_font = Font(bold=True)center_aligned = Alignment(horizontal='center', vertical='center')border = Border(left=Side(style='thin'),right=Side(style='thin'),top=Side(style='thin'),bottom=Side(style='thin'))# 应用表头样式for cell in worksheet[1]:cell.fill = header_fillcell.font = header_fontcell.alignment = center_alignedcell.border = border# 应用数据行样式for row in worksheet.iter_rows(min_row=2):for cell in row:cell.alignment = center_alignedcell.border = bordermessagebox.showinfo("成功", "模板导出成功!\n请按照模板格式准备数据后再进行导。")except Exception as e:messagebox.showerror("错误", f"导出模板时出错:{str(e)}")def set_default_values(self):"""设置默认值"""# 清空所有输入框self.clear_fields()# 只设置日期和折扣率的默认值today = datetime.now().strftime('%Y-%m-%d')self.entries['order_date'].insert(0, today)  # 默认日期为今天self.entries['discount'].insert(0, '100')    # 默认折扣率为100%# 生成新的单据编号cursor = self.conn.cursor()cursor.execute('''SELECT MAX(order_number) FROM orders WHERE order_number LIKE ?''', [f'XSD{today.replace("-", "")}%'])last_number = cursor.fetchone()[0]if last_number:try:# 从最后一个单号提取序号并加1seq = int(last_number[-3:]) + 1new_number = f'XSD{today.replace("-", "")}{seq:03d}'except ValueError:new_number = f'XSD{today.replace("-", "")}001'else:new_number = f'XSD{today.replace("-", "")}001'self.entries['order_number'].insert(0, new_number)  # 设置新单据编号def update_order_groups(self):"""更新订单分类显示"""cursor = self.conn.cursor()cursor.execute('''SELECT order_number, customer, product, unit, quantity, price, total, remarks,SUM(total) OVER () as total_sumFROM orders ORDER BY order_number DESC''')# 清空现有数据self.group_tree.delete(*self.group_tree.get_children())total_sum = 0# 插入新数据for row in cursor.fetchall():formatted_row = list(row[:8])  # 只取前8列显示# 格式化数字列formatted_row[4] = f"{row[4]:.2f}"  # 数量formatted_row[5] = f"¥{row[5]:.2f}"  # 原价formatted_row[6] = f"¥{row[6]:.2f}"  # 金额self.group_tree.insert("", "end", values=formatted_row)total_sum = row[8]  # 获取合计金额# 更新合计标签self.total_label.config(text=f"合计金额: ¥{total_sum:,.2f}")def on_group_select(self, event):"""当选择订单分类时的处理"""selected = self.group_tree.selection()if not selected:return# 获取选中的单据编号order_number = self.group_tree.item(selected[0])['values'][0]# 在主表格中查找并选中对应的记录for item in self.tree.get_children():if self.tree.item(item)['values'][1] == order_number:  # 假设单据编号是第二列self.tree.selection_set(item)self.tree.see(item)  # 确保选中的项可见breakdef filter_orders(self):"""根据筛选条件过滤订单"""order_number = self.order_number_filter.get().strip()customer = self.customer_filter.get().strip()cursor = self.conn.cursor()# 构建查询条件query = '''SELECT order_number, customer, product, unit, quantity, price, total, remarks,SUM(total) OVER () as total_sumFROM orders WHERE 1=1'''params = []if order_number:query += " AND order_number LIKE ?"params.append(f"%{order_number}%")if customer:query += " AND customer LIKE ?"params.append(f"%{customer}%")query += " ORDER BY order_number DESC"cursor.execute(query, params)# 清空现有数据self.group_tree.delete(*self.group_tree.get_children())total_sum = 0# 插入新数据for row in cursor.fetchall():formatted_row = list(row[:8])  # 只取前8列显示# 格式化数字列formatted_row[4] = f"{row[4]:.2f}"  # 数量formatted_row[5] = f"¥{row[5]:.2f}"  # 原价formatted_row[6] = f"¥{row[6]:.2f}"  # 金额self.group_tree.insert("", "end", values=formatted_row)total_sum = row[8]  # 获取合计金额# 更新合计标签self.total_label.config(text=f"合计金额: ¥{total_sum:,.2f}")def reset_filter(self):"""重置筛选条件"""self.order_number_filter.delete(0, tk.END)self.customer_filter.delete(0, tk.END)self.update_order_groups()def update_order_number_list(self, event=None):"""更新单据编号下拉列表"""search_text = self.order_number_filter.get().strip()cursor = self.conn.cursor()if search_text:cursor.execute('''SELECT DISTINCT order_number FROM orders WHERE order_number LIKE ? ORDER BY order_number DESC''', [f'%{search_text}%'])else:cursor.execute('''SELECT DISTINCT order_number FROM orders ORDER BY order_number DESC''')order_numbers = [row[0] for row in cursor.fetchall()]if order_numbers:self.order_number_filter['values'] = order_numbersif search_text:self.order_number_filter.event_generate('<Down>')def update_customer_list(self, event=None):"""更新客户名称下拉列表"""search_text = self.customer_filter.get().strip()cursor = self.conn.cursor()if search_text:cursor.execute('''SELECT DISTINCT customer FROM orders WHERE customer LIKE ? ORDER BY customer''', [f'%{search_text}%'])else:cursor.execute('''SELECT DISTINCT customer FROM orders ORDER BY customer''')customers = [row[0] for row in cursor.fetchall()]if customers:self.customer_filter['values'] = customersif search_text:self.customer_filter.event_generate('<Down>')def update_filter_lists(self):"""更新所有筛选下拉列表"""cursor = self.conn.cursor()# 更新单据编号列表cursor.execute('SELECT DISTINCT order_number FROM orders ORDER BY order_number DESC')self.order_number_filter['values'] = [row[0] for row in cursor.fetchall()]# 更新客户名称列表cursor.execute('SELECT DISTINCT customer FROM orders ORDER BY customer')self.customer_filter['values'] = [row[0] for row in cursor.fetchall()]def print_filtered_data(self):"""打印筛选后的数据"""try:# 获取当前筛选条件下的数据order_number = self.order_number_filter.get().strip()customer = self.customer_filter.get().strip()# 构建查询条件query = '''SELECT order_number, customer, product, unit, quantity, price, total, remarks,SUM(total) OVER () as total_sumFROM orders WHERE 1=1'''params = []if order_number:query += " AND order_number LIKE ?"params.append(f"%{order_number}%")if customer:query += " AND customer LIKE ?"params.append(f"%{customer}%")query += " ORDER BY order_number DESC"cursor = self.conn.cursor()cursor.execute(query, params)rows = cursor.fetchall()if not rows:messagebox.showinfo("提示", "没有数据可打印")return# 生成HTML内容html_content = f"""<!DOCTYPE html><html><head><meta charset="utf-8"><title>订单查询结果</title><style>body {{ font-family: SimSun, serif; }}table {{ border-collapse: collapse; width: 100%; margin-top: 10px; }}th, td {{ border: 1px solid black; padding: 8px; text-align: center; }}th {{ background-color: #f2f2f2; }}.total {{ text-align: right;padding: 10px;font-weight: bold;}}.header-info {{margin: 10px 0;padding: 10px;border: 1px solid #ddd;background-color: #f9f9f9;}}.header-info p {{margin: 5px 0;}}@media print {{.no-print {{ display: none; }}body {{ margin: 0; }}table {{ page-break-inside: auto; }}tr {{ page-break-inside: avoid; }}}}</style></head><body><h2 style="text-align: center;">订单查询结果</h2><div class="header-info"><p><strong>单据编号:</strong>{order_number if order_number else "全部"}</p><p><strong>客户名称:</strong>{customer if customer else "全部"}</p><p><strong>��印时间:</strong>{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p></div><table><tr><th>品名规格</th><th>单位</th><th>数量</th><th>原价</th><th>金额</th><th>备注</th></tr>"""# 添加数据行for row in rows:html_content += f"""<tr><td>{row[2]}</td><td>{row[3]}</td><td>{row[4]:.2f}</td><td>¥{row[5]:.2f}</td><td>¥{row[6]:.2f}</td><td>{row[7]}</td></tr>"""# 添加合计行total_sum = rows[0][8] if rows else 0html_content += f"""</table><div class="total">合计金额: ¥{total_sum:,.2f}</div><div class="no-print" style="margin-top: 20px; text-align: center;"><button onclick="window.print()">打印</button></div></body></html>"""# 保存HTML文件temp_file = "订单查询结果.html"with open(temp_file, "w", encoding="utf-8") as f:f.write(html_content)# 在默认浏览器中打开HTML文件import webbrowserwebbrowser.open(temp_file)except Exception as e:messagebox.showerror("错误", f"打印过程中出错:{str(e)}")if __name__ == "__main__":# 显示登录窗口login = LoginWindow()if login.run():  # 只有在登录成功时才继续root = tk.Tk()app = OrderSystem(root)root.mainloop()else:sys.exit(0)  # 登录失败或关闭登录窗口时退出程序

多个文件 打包成EXE 

我可以帮你使用 PyInstaller 将这两个 Python 文件打包成一个单独的 exe 文件。以下是具体步骤:

1. 首先安装 PyInstaller:
pip install pyinstaller

2. 创建一个 spec 文件,命名为 `zhi.spec`:

# -*- mode: python ; coding: utf-8 -*-block_cipher = Nonea = Analysis(['zhi.py'],  # 主程序文件pathex=[],binaries=[],datas=[('login.py', '.'), ('config.json', '.')],  # 添加其他需要的文件hiddenimports=[],hookspath=[],hooksconfig={},runtime_hooks=[],excludes=[],win_no_prefer_redirects=False,win_private_assemblies=False,cipher=block_cipher,noarchive=False,
)pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)exe = EXE(pyz,a.scripts,a.binaries,a.zipfiles,a.datas,[],name='订单记录系统',  # exe文件名debug=False,bootloader_ignore_signals=False,strip=False,upx=True,upx_exclude=[],runtime_tmpdir=None,console=False,  # 设置为False不显示控制台窗口disable_windowed_traceback=False,target_arch=None,codesign_identity=None,entitlements_file=None,icon='icon.ico',  # 如果有图标文件的话
)

3. 在命令行中执行打包命令:

pyinstaller --clean zhi.spec
 

如果你想要更简单的方式,可以直接使用以下命令:

pyinstaller --noconfirm --onefile --windowed --icon=icon.ico --add-data "login.py;." --add-data "config.json;." zhi.py
 

注意事项:
1. 确保所有需要的依赖包都已安装
2. 如果使用了图标,需要准备一个 .ico 文件
3. 打包后的文件会在 `dist` 目录下
4. 建议在打包前测试程序是否正常运行

完整的打包步骤:

1. 准备文件:
your_project_folder/
    ├── zhi.py
    ├── login.py
    ├── config.json
    ├── icon.ico (可选)
    └── zhi.spec

2. 安装必要的包:

pip install pyinstaller
pip install pandas
pip install sqlite3

3. 执行打包命令:
pyinstaller --clean zhi.spec

4. 检查生成的文件:
- 打包完成后,在 `dist` 目录下会生成一个名为"订单记录系统.exe"的文件

-记得在"订单记录系统.exe" 同时目录 建设一个 db目录
- 这个 exe 文件包含了所有必要的依赖和资源文件
- 可以直接双击运行,不需要安装 Python 环境

1.1 版本,其它 2025年后。。。。。

相关文章:

Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印

图样&#xff1a; 就可以导入了 上代码 import tkinter as tk from tkinter import ttk import sqlite3 from datetime import datetime from tkinter import messagebox, filedialog import pandas as pd import reclass OrderSystem:def __init__(self, root):self.root r…...

【电商搜索】CRM: 具有可控条件的检索模型

【电商搜索】CRM: 具有可控条件的检索模型 目录 文章目录 【电商搜索】CRM: 具有可控条件的检索模型目录文章信息摘要研究背景问题与挑战如何解决核心创新点算法模型实验效果&#xff08;包含重要数据与结论&#xff09;相关工作后续优化方向 后记 https://arxiv.org/pdf/2412.…...

python使用pip进行库的下载

前言 现如今有太多的python编译软件&#xff0c;其库的下载也是五花八门&#xff0c;但在作者看来&#xff0c;无论是哪种方法都是万变不离其宗&#xff0c;即pip下载。 pip是python的包管理工具&#xff0c;无论你是用的什么python软件&#xff0c;都可以用pip进行库的下载。 …...

Golang 的并发优势

在如今的编程领域&#xff0c;一个程序能够同时处理多个任务的能力非常重要&#xff0c;这就是所谓的并发处理。而 Golang 在并发编程方面表现十分出色&#xff0c;具有很多独特的优势&#xff0c;简直不要太简单。 一、轻量级的协程&#xff08;Goroutine&#xff09; 在传统…...

5G学习笔记之Non-Public Network

目录 0. NPN系列 1. 概述 2. SNPN 2.1 SNPN概述 2.2 SNPN架构 2.3 SNPN部署 2.3.1 完全独立 2.3.2 共享PLMN基站 2.3.3 共享PLMN基站和PLMN频谱 3. PNI-NPN 3.1 PNI-NPN概述 3.2 PNI-NPN部署 3.2.1 UPF独立 3.2.2 完全共享 0. NPN系列 1. NPN概述 2. NPN R18 3. 【SNPN系列】S…...

SpringBoot——核心概念

文章目录 一.核心概念IoC/DI思想2.Ioc容器3.Bean 二.IoC入门案例三.DI入门案例分析四.bean基础配置五.bean的实例化&#xff08;创建&#xff09;六.bean实例化——静态工厂七.bean实例化——示例工程与FactoryBean八.bean的生命周期九.依赖注入的两种方式十.构造器注入十一.依…...

【HarmonyOs学习日志(14)】计算机网络之域名系统DNS

域名系统DNS 域名系统DNS——从域名解析出IP地址 文章目录 域名系统DNS概述域名到IP地址的解析 互联网的域名结构命名标准 域名服务器域名的解析过程 概述 域名系统DNS&#xff08;Domain Name System&#xff09;是互联网使用的命名系统&#xff0c;用来把便于人们使用的机器…...

电脑丢失bcrypt.dll文件是什么原因?找不到bcrypt.dll文件修复办法来啦!

电脑运行时常见问题及解决方案&#xff1a;文件丢失、文件损坏与系统报错 作为一名软件开发从业者&#xff0c;深知电脑在日常使用中难免会遇到各种问题&#xff0c;如文件丢失、文件损坏和系统报错等。这些问题不仅影响工作效率&#xff0c;还可能带来数据丢失的风险。今天&a…...

shell编程3

声明 学习视频来自B站UP主 泷羽sec 向脚本程序传递参数 可以向脚本程序传递一个或多参数 echo 执行的文件名是:S0 echo 第一个参数是: 1 e c h o 传递的参数作为一个字符串显示 : 1 echo 传递的参数作为一个字符串显示: 1echo传递的参数作为一个字符串显示:* echo 传递的参数…...

LAUNCHXL_F28379D_Workspace_CCS124

/// 安装 controlSUITE C:\ti\controlSUITE\device_support\F2837xD\v210 /// /// /// /// /// 删除 /// /// /// >> Compilation failure source_common/subdir_rules.mk:9: recipe for target source_common/F2837xD_Adc.obj failed "C:/ti/controlSUITE/devic…...

智慧商城:编辑切换状态,删除功能

编辑切换状态 为 编辑 注册点击事件进行状态取反&#xff0c;为该状态赋一个初始值 false 如果是非编辑状态是要进行结算的&#xff0c;否则删除 点击“编辑”状态是 要进行 “删除”&#xff0c;非编辑状态是要进行 “结算” 当 结算 时&#xff0c;希望是能 全选 进而能多卖…...

支付测试 流程

支付测试 流程 支付测试是确保支付系统安全、稳定、可靠运行的关键环节&#xff0c;以下是其一般流程&#xff1a; 测试计划阶段 明确测试目标&#xff1a;确定本次支付测试的重点和预期达到的目标&#xff0c;如测试支付功能的完整性、安全性、性能等。制定测试计划&#x…...

Ai编程从零开始全栈开发一个后台管理系统之用户登录、权限控制、用户管理-前端部分(十二)

云风网 云风笔记 云风知识库 一、创建前端部分 1、vite初始化项目 npm create vitelatest admin-frontend – --template vue-ts 2、安装必要的依赖 npm install vue-router pinia axios element-plus element-plus/icons-vue安装完成后package.json如下&#xff1a; {&qu…...

LeetCode 197. 上升的温度

LeetCode 197. 上升的温度 表&#xff1a; Weather ---------------------- | Column Name | Type | ---------------------- | id | int | | recordDate | date | | temperature | int | ---------------------- id 是该表具有唯一值的列。 没有具有相同 recordDate 的不同行。…...

ECharts散点图-气泡图,附视频讲解与代码下载

引言&#xff1a; ECharts散点图是一种常见的数据可视化图表类型&#xff0c;它通过在二维坐标系或其它坐标系中绘制散乱的点来展示数据之间的关系。本文将详细介绍如何使用ECharts库实现一个散点图&#xff0c;包括图表效果预览、视频讲解及代码下载&#xff0c;让你轻松掌握…...

【pycharm】对需要传参数以及配置文件的情况进行debug教程

【pycharm】对需要传参数以及配置文件的情况进行debug教程 例如下面这个项目&#xff0c;我们要运行需要在终端输入 python main.py -mtrain -trsr0.03 -vsr0.01其中 -m‘train’ -trsr0.03 -vsr0.01是我们需要传的参数 在终端运行如下&#xff1a; 如果我们要进行debug的话…...

three.js混合白色模型的智慧城市扫光效果

three.js混合白色模型的智慧城市扫光效果 https://threehub.cn/#/codeMirror?navigationThreeJS&classifyshader&idcityBlendLight import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls.js import { FBXLoader …...

【QT常用技术讲解】发送POST包(两种方式:阻塞方式及非阻塞方式)

前言 http/https(应用层)协议是广泛使用的网络通信协议。在很多与第三方API对接的场景中&#xff0c;通常是通过http/https协议完成&#xff0c;比如API对接时&#xff0c;通常要通过POST包获取access_token进行鉴权&#xff0c;然后再进行数据交互&#xff08;本篇也包含有对接…...

基于Python大数据的电影可视化分析系统

标题:基于 Python 大数据的电影可视化分析系统 内容:1.摘要 本文介绍了一个基于 Python 大数据的电影可视化分析系统。该系统通过收集和分析大量电影数据&#xff0c;提供了对电影市场的深入洞察。文章首先介绍了系统的背景和目的&#xff0c;然后详细描述了系统的架构和功能。…...

Vue3:uv-upload图片上传

效果图&#xff1a; 参考文档&#xff1a; Upload 上传 | 我的资料管理-uv-ui 是全面兼容vue32、nvue、app、h5、小程序等多端的uni-app生态框架 (uvui.cn) 代码&#xff1a; <view class"greenBtn_zw2" click"handleAddGroup">添加班级群</vie…...

VBA技术资料MF243:利用第三方软件复制PDF数据到EXCEL

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…...

redis使用注意哪些事项

1. 数据类型选择&#xff1a; • Redis支持多种数据类型&#xff0c;如字符串&#xff08;String&#xff09;、哈希&#xff08;Hash&#xff09;、列表&#xff08;List&#xff09;、集合&#xff08;Set&#xff09;、有序集合&#xff08;Sorted Set&#xff09;等。在选择…...

Go使用sqlx操作MySQL完整指南

# Go使用sqlx操作MySQL完整指南## 1. 安装依赖bash go get github.com/go-sql-driver/mysql go get github.com/jmoiron/sqlx2. 数据库基础操作 package mainimport ("fmt"_ "github.com/go-sql-driver/mysql""github.com/jmoiron/sqlx" )// 定…...

计算机基础复习12.23

ThreadLocal 线程隔离&#xff1a;ThreadLocal为每个线程提供了独立的变量副本&#xff0c;意味着线程之间不会相互影响&#xff0c;可以安全的在多线程环境中使用这些变量而不必担心数据竞争或同步问题 ThreadLocal的实现依赖于Thread类中的一个ThreadLocalMap字段&#xff…...

Jenkins介绍

Jenkins 是一款流行的开源自动化服务器&#xff0c;在软件开发和持续集成 / 持续交付&#xff08;CI/CD&#xff09;流程中发挥着关键作用。 一、主要功能 1.持续集成&#xff08;CI&#xff09; &#xff08;1&#xff09;.自动构建&#xff1a;Jenkins 可以配置为监听代码仓…...

RK3588 , mpp硬编码yuv, 保存MP4视频文件.

RK3588 , mpp硬编码yuv, 保存MP4视频文件. ⚡️ 传送 ➡️ Ubuntu x64 架构, 交叉编译aarch64 FFmpeg mppRK3588, FFmpeg 拉流 RTSP, mpp 硬解码转RGBRk3588 FFmpeg 拉流 RTSP, 硬解码转RGBRK3588 , mpp硬编码yuv, 保存MP4视频文件....

Delphi WebBrowser 基本操作与常见问题的解决方案

前言 WebBrowser 作为Delphi 常见的网络浏览控件&#xff0c;我这里整理了一些它的基本操作&#xff0c;遇到了一些问题&#xff0c;我梳理了一下并给出解决方案 基本操作 WebBrowser1.GoHome; //到浏览器默认主页 WebBrowser1.Refresh; //刷新 WebBrowser1.GoBack; //后退 Web…...

【更新】LLM Interview

课程链接&#xff1a;BV1o217YeELo 文章目录 LLM基础相关1. LLMs概述2. 大语言模型尺寸3. LLMs的优势与劣势4. 常见的大模型分类5. 目前主流的LLMs开源模型体系有哪些&#xff08;Prefix Decoder&#xff0c;Causal Decoder&#xff0c;Encoder-Decoder的区别是什么&#xff09…...

从零开始C++棋牌游戏开发之第一篇:C++ 游戏开发环境搭建与工具简介

前言&#xff1a;作者的感想 每一次选择开始一项新技能的学习&#xff0c;总会让人感到既兴奋又有些许忐忑。C 游戏开发&#xff0c;尤其是针对棋牌类游戏规则实现的开发&#xff0c;更是一个有趣而充满挑战的领域。作为一名开发者&#xff0c;我深知面对 C 时的那种 "既…...

Hydrogen-Web 项目常见问题解决方案

Hydrogen-Web 项目常见问题解决方案 hydrogen-web Lightweight matrix client with legacy and mobile browser support [这里是图片001] 项目地址: https://gitcode.com/gh_mirrors/hy/hydrogen-web 项目基础介绍 Hydrogen-Web 是一个轻量级的 Matrix 客户端&#xff0c;专…...

LabVIEW中的“Synchronize with Other Application Instances“

在LabVIEW中&#xff0c;“Synchronize with Other Application Instances”是一个常见的提示或错误&#xff0c;通常出现在尝试并行运行多个LabVIEW实例时&#xff0c;特别是当你打开多个VI或项目时。这个问题可能影响程序的执行流程&#xff0c;导致不同实例之间的数据同步或…...

Hslcommunication通讯调用

Vs2022选择配置属性选择高级语言运行时(/clr);符合模式选择否;引用选择Hslcommunication.dll和HslCppExtension.dll; Demo #include <iostream> using namespace HslCommunication; using namespace HslCommunication::Core::Net; using namespace HslCommunication::Mo…...

渐进式 Web 应用程序:新的 FE 系统

在企业环境中&#xff0c;我们通常认为稳定的互联网连接是理所当然的。然而&#xff0c;现实世界的条件经常挑战这一假设&#xff0c;可能会中断关键业务运营。本文详细介绍了我们如何将传统的纯在线 ERP 系统转变为具有弹性、支持离线的解决方案的更可靠的系统。通过利用基于浏…...

安科瑞能源物联网平台在老旧小区用电安全改造中的应用与优势

安科瑞 吕梦怡 一、现状 ​老旧住宅小区普遍存在建成时间久远的情况&#xff0c;其电力系统刚开始的设计标准已难以匹配当下居民不断攀升的用电需求。电力基础设施老化现象较为突出&#xff0c;例如电线的绝缘层出现破损、电表箱被锈蚀以及配电设备超期服役等问题比比皆是。小…...

[Effective C++]条款36-37 两个绝不

本文初发于 “天目中云的小站”&#xff0c;同步转载于此。 条款36 : 绝不重新定义继承而来的non-virtual函数 本条款很容易理解, 援引以前的条款就可以说明为什么 : 条款34中就提到过 : non-virtual函数意味着接口 强制性实现继承, 它不应当被改变. 重新定义继承而来的non-…...

MySQL数据库——复制表数据与结构

命令格式 create table 表名 select 字段1,字段2 from 被复制表 首先新建一个表&#xff0c;然后从被复制的表中选择字段复制到新表 举例...

一文掌握如何编写可重复执行的SQL

一文掌握如何编写可重复执行的SQL 文章已同步个人博客&#xff1a;一文掌握如何编写可重复执行的SQL 背景 先提出问题&#xff0c;这里的可重复执行是指什么&#xff1f;我们为什么要编写可重复执行的sql&#xff1f; 可重复执行是指一条sql重复多次执行都不会报错&#xf…...

编译笔记:vs 中 正在从以下位置***加载符号 C# 中捕获C/C++抛出的异常

加载符号 解决方法&#xff1a; 进入VS—工具—选项----调试----符号&#xff0c;看右边有个“Microsoft符号服务器”&#xff0c;将前面的勾去掉&#xff0c;&#xff08;可能还有删除下面的那个缓存&#xff09;。 参考 C# 中捕获C/C抛出的异常 在需要捕捉破坏性异常的函数…...

[搜广推]王树森推荐系统——Deep Retrieval 召回

Deep Retrieval 简介 Deep Retrieval 是一种推荐系统框架&#xff0c;它将物品表示为路径&#xff08;path&#xff09;&#xff0c;并在线上查找与用户最匹配的路径。 这种方法与传统的双塔模型不同&#xff0c;后者通常将用户和物品表示为向量&#xff0c;并在线上进行最近邻…...

【深入解析蓝牙dumpsys bluetooth_manager 命令输出】

了解蓝牙的工作状态以及如何在测试中利用这些信息。 1. Bluetooth Status(蓝牙状态) enabled: true state: ON address: 00:00:00:00:43:36 name: 小米手机 time since enabled: 00:15:18.492enabled: true — 蓝牙功能已启用。state: ON — 蓝牙目前是开启状态。address: …...

【三】Fast-DDS hello world!

编译hello world # 进入到源码目录 mkdir -p examples/cpp/hello_world/build cd examples/cpp/hello_world/build cmake .. && make -j4运行publisher ./hello_world publisher 运行subscriber ./hello_world subscriber 结果...

将HTML转换为PDF:使用Spire.Doc的详细指南(一) 试用版

目录 引言 1. 为什么选择 Spire.Doc&#xff1f; 1.1 主要特点 1.2 适用场景 2. 准备工作 2.1 引入 Spire.Doc 依赖 2.2 禁用 SSL 证书验证 3. 实现功能 3.1 主类结构 3.2 代码解析 4. 处理图像 5. 性能优化 5.1 异步下载图像 示例代码 5.2 批量处理优化 示例代…...

【物联网技术与应用】实验10:蜂鸣器实验

实验10 蜂鸣器实验 【实验介绍】 蜂鸣器是音频信号装置。蜂鸣器可分为有源蜂鸣器和无源蜂鸣器。 【实验组件】 ● Arduino Uno主板* 1 ● USB数据线* 1 ● 有源蜂鸣器* 1 ● 无源蜂鸣器* 1 ● 面包板* 1 ● 9V方型电池* 1 ● 跳线若干 【实验原理】 如图所示&#x…...

【python高级】342-TCP服务器开发流程

CS模式&#xff1a;客户端-服务端模式 TCP客户端开发流程介绍&#xff08;五步&#xff09;&#xff08;C端&#xff09; 1.创建客户端套接字对象 2.和服务端套接字建立连接 3.发送数据 4.接收数据 5.关闭客户端套接字 TCP服务端开发流程&#xff08;七步&#xff09;&#xf…...

C++开源项目 VLC 源代码的交叉编译以及库的裁剪方法详解

目录 1、VLC简介 2、VLC编译环境配置 2.1、编译环境 2.2、编译环境配置 2.2.1、下载安装MSYS2 2.2.2、下载mingw-w64 3、编译VLC 4、VLC库的裁剪 5、总结 C软件异常排查从入门到精通系列教程&#xff08;核心精品专栏&#xff0c;订阅量已达600多个&#xff0c;欢迎订…...

draw.io 导出svg图片插入word后模糊(不清晰 )的解决办法

通常我们将图片从draw.io导出为svg格式后插入word, 会发现字体不清晰&#xff0c;特别是使用宋体时&#xff0c;折腾了半天&#xff0c;得到如下办法&#xff1a; 方法1: 在draw.io中导出pdf文件&#xff0c;使用 PDF转SVG转换器 - SVGConverter 将其转换为svg, 完美呈现。 …...

详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用

目录 详解js柯里化原理及用法&#xff0c;探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用 一、什么是柯里化&#xff1f; 1、原理解析 2、一个直观的例子 二、如何实现柯里化&#xff1f; 1、底层实现 2、工作原理解析 3…...

Cesium材质——Material

简介&#xff1a; Cesium.Material对象的目的&#xff0c;就是生成一段名称为czm_getMaterial的函数&#xff08;示例代码如下&#xff09;&#xff0c; 这个czm_getMaterial函数&#xff0c;是shader代码&#xff0c;会被放到片元着色器中使用。 czm_material czm_getMater…...

《点点之歌》“意外”诞生记

世界是“点点”的&#xff0c;“点点”是世界的。 (笔记模板由python脚本于2024年12月23日 19:28:25创建&#xff0c;本篇笔记适合喜欢诗文的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 …...

统计某个文件中某个字符串出现的次数

要统计某个文件中某个字符串出现的次数&#xff0c;有多种方法可以实现。以下是几种常用且高效的 Linux 命令方法&#xff1a; 方法一&#xff1a;使用 grep 和 wc 命令示例&#xff1a; grep -o "字符串" 文件名 | wc -l说明&#xff1a; grep -o "字符串&…...