【2024年4月22日更新】
更新了很多功能,包括UI界面、销售功能、库存管理等。
其中微信预约、微信消息推送功能也支持,只是比较复杂,删除了此部分的功能代码,需要微信消息推送功能的朋友可以留言私信交流一下 。
慢慢探索。
打包了新的部署说明,小白也能看懂如何部署!
源码+打包成品链接:
6月14日更新链接:https://pan.baidu.com/s/1ko203jlqWTmcONwStB2Nmw?pwd=rdsk
提取码: rdsk
-------------【2023年8月9日更新】---------------------------------------------------------------------------------------------------------------------
更新内容:
1、数据库,移除本地数据库,更改成云数据库。需要更改代码中的:
[Python] 纯文本查看 复制代码
# 创建数据库连接
conn = pymysql.connect(host='你数据库IP地址', user='登录名', password='登陆密码', db='表名', connect_timeout=60)
cursor = conn.cursor()
2、增加系统设置,允许修改密码、注销、退出等
3、选择行高亮显示
4、增加按钮快捷键
5、增加冲账功能
6、优化消费逻辑,消费项目会判断是否购买了该项目,购买了就会扣减次数,如未购买则按单次价格收费
7、不记得了。。自己体验吧!
部署方法:
1、创建一台服务器,阿里云、华为云都可以。
2、导入数据库文件
3、更改源码中的链接数据库信息
[Python] 纯文本查看 复制代码
# 创建数据库连接
conn = pymysql.connect(host='你数据库IP地址', user='登录名', password='登陆密码', db='表名', connect_timeout=60)
cursor = conn.cursor()
4、打包源码成exe文件,打包命令这源码里面
[Python] 纯文本查看 复制代码
pyinstaller --onefile --noconsole --icon=icon.ico crm.py
------------------【7月27日】-----------------------------分割线--------------------------------------------------------
简单实现美容院会员管理系统
1、实现会员基本资料管理
2、实现会员充值、消费管理
3、实现美容项目管理
4、本地数据库,带有数据库备份功能
默认帐号:admin 密码:123
[Python] 纯文本查看 复制代码
import sys
from PyQt5.QtWidgets import QApplication,QDateEdit,QDialog,QMainWindow,QDateTimeEdit, QLabel, QComboBox,QGridLayout,QDialog, QWidget, QTableWidget, QTableWidgetItem, QPushButton, QVBoxLayout, QHBoxLayout, QLineEdit, QMessageBox, QTabWidget,QFileDialog
from PyQt5.QtCore import Qt,QDate
from PyQt5.QtGui import QFont
import sqlite3
import re
import os
import shutil
import openpyxl
from datetime import datetime
import glob
# 建立数据库连接
conn = sqlite3.connect('members.db')
cursor = conn.cursor()
# 创建会员表
cursor.execute('''CREATE TABLE IF NOT EXISTS members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
phone TEXT NOT NULL,
register_date TEXT NOT NULL,
last_consume_date TEXT,
birthday DATE,
balance REAL,
remark TEXT
)''')
# 创建充值/消费记录表
cursor.execute('''CREATE TABLE IF NOT EXISTS transactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
member_id INTEGER,
amount REAL,
transaction_date TEXT,
remark TEXT,
project TEXT,
balance REAL,
clerk_id INTEGER,
FOREIGN KEY (member_id) REFERENCES members (id)
)''')
# 创建美容项目表
cursor.execute('''CREATE TABLE IF NOT EXISTS beauty_projects (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
times INTEGER NOT NULL,
datetime TEXT,
remark TEXT
)''')
# 创建会员美容项目表
cursor.execute('''CREATE TABLE IF NOT EXISTS member_beauty_projects (
member_id INTEGER,
beauty_project_id INTEGER,
sessions INTEGER,
FOREIGN KEY (member_id) REFERENCES members (id),
FOREIGN KEY (beauty_project_id) REFERENCES beauty_projects (id)
)''')
#创建营业员表
cursor.execute("CREATE TABLE IF NOT EXISTS clerks (id INTEGER PRIMARY KEY, name TEXT,is_deleted INTEGER DEFAULT 0)")
search_entry = None
search_table = None
transaction_table = None
transaction_member_entry = None
#备份数据库
def backup_database():
DATABASE = 'members.db' # Replace this with your actual database file path
BACKUP_DIR = 'database_backups' # The name of the backup directory
# 获取当前运行的脚本路径
current_path = os.path.dirname(os.path.abspath(__file__))
backup_dir_path = os.path.join(current_path, BACKUP_DIR)
# Create the backup directory if it doesn't exist
os.makedirs(backup_dir_path, exist_ok=True)
# 根据当前日期时间创建备份文件名
backup_name = f"backup_{datetime.now().strftime('%Y%m%d%H%M%S')}.db"
# 拼接出备份文件的完整路径
backup_path = os.path.join(backup_dir_path, backup_name)
# 复制数据库文件到备份路径
shutil.copyfile(DATABASE, backup_path)
# 获取当前目录下所有的备份文件
all_backups = glob.glob(os.path.join(backup_dir_path, "backup_*.db"))
# 如果备份文件数量超过 30,删除最早的备份文件
if len(all_backups) > 30:
all_backups.sort()
os.remove(all_backups[0])
# 登录界面
class LoginWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("会员储值管理系统")
self.setGeometry(300, 300, 350, 200)
layout = QVBoxLayout()
username_label = QLabel("用户名:")
self.username_entry = QLineEdit()
password_label = QLabel("密码:")
self.password_entry = QLineEdit()
self.password_entry.setEchoMode(QLineEdit.Password)
login_button = QPushButton("登录")
login_button.clicked.connect(self.login)
font = QFont()
font.setBold(True)
username_label.setFont(font)
password_label.setFont(font)
login_button.setFont(font)
layout.addWidget(username_label)
layout.addWidget(self.username_entry)
layout.addWidget(password_label)
layout.addWidget(self.password_entry)
layout.addWidget(login_button)
self.setLayout(layout)
def login(self):
username = self.username_entry.text()
password = self.password_entry.text()
if username == "admin" and password == "123":
self.close() # 关闭登录窗口
self.main_window = MainWindow() # 创建主窗口
self.main_window.show() # 显示主窗口
else:
QMessageBox.warning(self, "警告", "用户名或密码错误!")
#主界面
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("会员管理系统")
self.setGeometry(20, 20, 1000, 700)
main_widget = QWidget()
self.setCentralWidget(main_widget)
# 创建Tab控件
tab_widget = QTabWidget()
# 创建会员查询界面
search_widget = QWidget()
search_layout = QVBoxLayout()
# 会员查询界面
search_label = QLabel("请输入会员姓名或手机号:")
self.search_entry = QLineEdit()
self.search_entry.returnPressed.connect(self.search_member)
search_button = QPushButton("查询")
search_button.clicked.connect(self.search_member)
search_layout.addWidget(search_label)
search_layout.addWidget(self.search_entry)
search_layout.addWidget(search_button)
# 创建按钮布局
button_layout = QHBoxLayout()
add_button = QPushButton("新增会员")
add_button.clicked.connect(self.create_add_member_window)
edit_button = QPushButton("修改会员信息")
edit_button.clicked.connect(self.edit_member)
delete_button = QPushButton("删除会员")
delete_button.clicked.connect(self.delete_member)
recharge_button = QPushButton("充值")
recharge_button.clicked.connect(self.recharge_dialog)
transaction_button = QPushButton("会员消费")
transaction_button.clicked.connect(self.create_consume_dialog)
buy_beauty_project_button = QPushButton("购买美容项目")
buy_beauty_project_button.clicked.connect(self.buy_beauty_project)
#设置CSS样式
font = QFont()
font.setBold(True)
search_label.setStyleSheet("color: red;")
search_label.setFont(font)
search_button.setFont(font)
add_button.setFont(font)
edit_button.setFont(font)
delete_button.setFont(font)
recharge_button.setFont(font)
transaction_button.setFont(font)
buy_beauty_project_button.setFont(font)
####################################################
button_layout.addWidget(add_button)
button_layout.addWidget(edit_button)
button_layout.addWidget(delete_button)
button_layout.addWidget(recharge_button)
button_layout.addWidget(transaction_button)
button_layout.addWidget(buy_beauty_project_button)
self.search_table = QTableWidget()
self.search_table.setColumnCount(8)
self.search_table.setHorizontalHeaderLabels([ "姓名", "手机号", "生日", "注册日期", "最后消费日期", "余额", "备注","ID"])
self.search_table.setSelectionBehavior(QTableWidget.SelectRows)
self.search_table.doubleClicked.connect(self.edit_member) #双击事件
self.search_table.setColumnWidth(0, 80) # 第一列宽度为80
self.search_table.setColumnWidth(1, 150)
self.search_table.setColumnWidth(2, 150)
self.search_table.setColumnWidth(3, 200)
self.search_table.setColumnWidth(4, 200)
self.search_table.setColumnWidth(5, 120)
self.search_table.setColumnWidth(6, 100)
self.search_table.setColumnWidth(7, 10)
search_layout.addLayout(button_layout)
search_layout.addWidget(self.search_table)
search_widget.setLayout(search_layout)
# 创建充值/消费记录界面
transaction_widget = QWidget()
transaction_layout = QVBoxLayout()
transaction_label = QLabel("请输入会员姓名或手机号:")
transaction_label.setStyleSheet("color: red;")
transaction_label.setFont(font)
self.transaction_member_entry = QLineEdit()
self.transaction_member_entry.returnPressed.connect(self.search_transaction)
transaction_button = QPushButton("查询")
transaction_button.clicked.connect(self.search_transaction)
export_button = QPushButton("导出")
export_button.clicked.connect(self.export_transaction_table)
self.transaction_table = QTableWidget()
self.transaction_table.setColumnCount(8)
self.transaction_table.setHorizontalHeaderLabels(["姓名", "手机号", "金额", "时间", "项目", "备注", "余额","营业员"])
self.transaction_table.setColumnWidth(0, 80) # 第一列宽度为80
self.transaction_table.setColumnWidth(1, 150)
self.transaction_table.setColumnWidth(2, 100)
self.transaction_table.setColumnWidth(3, 200)
self.transaction_table.setColumnWidth(4, 200)
self.transaction_table.setColumnWidth(5, 80)
self.transaction_table.setColumnWidth(6, 100)
self.transaction_table.setColumnWidth(7, 80)
transaction_layout.addWidget(transaction_label)
transaction_layout.addWidget(self.transaction_member_entry)
transaction_layout.addWidget(transaction_button)
transaction_layout.addWidget(self.transaction_table)
transaction_layout.addWidget(export_button)
transaction_widget.setLayout(transaction_layout)
# 创建美容项目管理界面
beauty_project_widget = QWidget()
beauty_project_layout = QVBoxLayout()
# 美容项目管理界面
beauty_project_label = QLabel("请输入美容项目名称:")
beauty_project_label.setStyleSheet("color: red;")
beauty_project_label.setFont(font)
self.beauty_project_entry = QLineEdit()
self.beauty_project_entry.returnPressed.connect(self.search_beauty_project)
beauty_project_button = QPushButton("查询")
beauty_project_button.clicked.connect(self.search_beauty_project)
beauty_project_layout.addWidget(beauty_project_label)
beauty_project_layout.addWidget(self.beauty_project_entry)
beauty_project_layout.addWidget(beauty_project_button)
# 创建按钮布局
beauty_project_button_layout = QHBoxLayout()
add_beauty_project_button = QPushButton("新增美容项目")
add_beauty_project_button.clicked.connect(self.create_add_beauty_project_window)
edit_beauty_project_button = QPushButton("修改美容项目信息")
edit_beauty_project_button.clicked.connect(self.edit_beauty_project)
delete_beauty_project_button = QPushButton("删除美容项目")
delete_beauty_project_button.clicked.connect(self.delete_beauty_project)
beauty_project_button_layout.addWidget(add_beauty_project_button)
beauty_project_button_layout.addWidget(edit_beauty_project_button)
beauty_project_button_layout.addWidget(delete_beauty_project_button)
self.beauty_project_table = QTableWidget()
self.beauty_project_table.setColumnCount(4)
self.beauty_project_table.setHorizontalHeaderLabels(["ID", "美容项目名称","次数","新建时间"])
self.beauty_project_table.setSelectionBehavior(QTableWidget.SelectRows)
self.beauty_project_table.doubleClicked.connect(self.edit_beauty_project) #双击事件
self.beauty_project_table.setColumnWidth(0, 30) # 第一列宽度为80
self.beauty_project_table.setColumnWidth(1, 250)
self.beauty_project_table.setColumnWidth(2, 100)
self.beauty_project_table.setColumnWidth(3, 200)
beauty_project_layout.addLayout(beauty_project_button_layout)
beauty_project_layout.addWidget(self.beauty_project_table)
beauty_project_widget.setLayout(beauty_project_layout)
# 创建营业员管理界面
clerks_widget = QWidget()
clerks_layout = QVBoxLayout()
# 营业员管理界面
clerks_label = QLabel("请输入营业员名称:")
clerks_label.setStyleSheet("color: red;")
clerks_label.setFont(font)
self.clerks_entry = QLineEdit()
self.clerks_entry.returnPressed.connect(self.search_clerk)
clerks_button = QPushButton("查询")
clerks_button.clicked.connect(self.search_clerk)
clerks_layout.addWidget(clerks_label)
clerks_layout.addWidget(self.clerks_entry)
clerks_layout.addWidget(clerks_button)
# 创建按钮布局
clerks_button_layout = QHBoxLayout()
add_clerks_button = QPushButton("新增营业员")
add_clerks_button.clicked.connect(self.create_add_clerk_window)
delete_clerks_button = QPushButton("删除营业员")
delete_clerks_button.clicked.connect(self.delete_clerks)
clerks_button_layout.addWidget(add_clerks_button)
clerks_button_layout.addWidget(delete_clerks_button)
self.clerks_table = QTableWidget()
self.clerks_table.setColumnCount(2)
self.clerks_table.setHorizontalHeaderLabels(["ID", "营业员名称"])
self.clerks_table.setColumnWidth(0, 80) # 第一列宽度为80
self.clerks_table.setColumnWidth(1, 200)
clerks_layout.addLayout(clerks_button_layout)
clerks_layout.addWidget(self.clerks_table)
clerks_widget.setLayout(clerks_layout)
# 创建会员美容项目次数报表界面
report_widget = QWidget()
report_layout = QVBoxLayout()
report_label = QLabel("请输入会员姓名或手机号:")
report_label.setStyleSheet("color: red;")
report_label.setFont(font)
self.report_entry = QLineEdit()
self.report_entry.returnPressed.connect(self.search_report)
report_button = QPushButton("查询")
report_button.clicked.connect(self.search_report)
self.report_table = QTableWidget()
self.report_table.setColumnCount(4)
self.report_table.setHorizontalHeaderLabels(["会员姓名", "手机号码","美容项目", "剩余次数"])
report_layout.addWidget(report_label)
report_layout.addWidget(self.report_entry)
report_layout.addWidget(report_button)
report_layout.addWidget(self.report_table)
report_widget.setLayout(report_layout)
tab_widget.addTab(search_widget, "会员查询")
tab_widget.addTab(transaction_widget, "会员充值/消费记录")
tab_widget.addTab(report_widget, "会员项目次数查询")
tab_widget.addTab(beauty_project_widget, "美容项目设置")
tab_widget.addTab(clerks_widget, "营业员设置")
main_layout = QVBoxLayout()
main_layout.addWidget(tab_widget)
main_widget.setLayout(main_layout)
self.sort_order = Qt.AscendingOrder # 初始排序顺序为升序
# 点击充值/消费记录表头进行排序
self.transaction_table.horizontalHeader().sectionClicked.connect(self.sort_transaction_table)
# 会员查询功能
def search_member(self):
keyword = self.search_entry.text()
query = f"SELECT members.name, members.phone, members.birthday, members.register_date, MAX(transactions.transaction_date), members.balance, members.remark,members.id FROM members LEFT JOIN transactions ON transactions.member_id = members.id WHERE members.name LIKE '%{keyword}%' OR members.phone LIKE '%{keyword}%' GROUP BY members.id ORDER BY MAX(transactions.transaction_date) DESC"
cursor.execute(query)
members = cursor.fetchall()
self.search_table.setRowCount(0)
for row, member in enumerate(members):
self.search_table.insertRow(row)
for col, data in enumerate(member):
item = QTableWidgetItem(str(data))
item.setFlags(Qt.ItemIsEnabled)
self.search_table.setItem(row, col, item)
# 会员新增
def create_add_member_window(self):
add_member_window = AddMemberWindow(self)
add_member_window.exec_()
# 会员修改
def edit_member(self):
selected_row = self.search_table.currentRow()
if selected_row != -1:
member_id = self.search_table.item(selected_row, 7).text()
edit_member_window = EditMemberWindow(member_id, self)
edit_member_window.exec_()
else:
QMessageBox.warning(self, "警告", "请选择要修改的会员。")
# 会员删除
def delete_member(self):
selected_row = self.search_table.currentRow()
if selected_row != -1:
member_id = self.search_table.item(selected_row, 7).text()
query = f"SELECT * FROM members WHERE id = {member_id}"
cursor.execute(query)
member = cursor.fetchone()
if member:
confirm = QMessageBox.question(self, "确认", "【警告】确定要删除该会员吗?")
if confirm == QMessageBox.Yes:
query = f"DELETE FROM members WHERE id = {member_id}"
cursor.execute(query)
conn.commit()
QMessageBox.information(self, "提示", "会员删除成功。")
self.search_member()
else:
QMessageBox.warning(self, "错误", "选择的会员不存在。")
else:
QMessageBox.warning(self, "警告", "请选择要删除的会员。")
# 会员充值
def recharge_dialog(self):
selected_row = self.search_table.currentRow()
if selected_row != -1:
member_id = self.search_table.item(selected_row, 7).text()
recharge_dialog = RechargeDialog(member_id, self)
recharge_dialog.exec_()
else:
QMessageBox.warning(self, "警告", "请选择要充值的会员。")
# 会员消费
def create_consume_dialog(self):
selected_row = self.search_table.currentRow()
if selected_row != -1:
member_id = self.search_table.item(selected_row, 7).text()
consume_dialog = ConsumeDialog(member_id, self)
consume_dialog.exec_()
else:
QMessageBox.warning(self, "警告", "请选择要消费的会员。")
# 会员购卡
def buy_beauty_project(self):
selected_row = self.search_table.currentRow()
if selected_row != -1:
member_id = self.search_table.item(selected_row, 7).text()
buy_beauty_project_dialog = BuyBeautyProjectDialog(member_id, self)
buy_beauty_project_dialog.exec_()
else:
QMessageBox.warning(self, "警告", "请选择要购买美容项目的会员。")
# 会员充值消费记录查询
def search_transaction(self):
keyword = self.transaction_member_entry.text()
query = f"SELECT members.name, members.phone, transactions.amount, strftime('%Y-%m-%d %H:%M:%S', transactions.transaction_date), transactions.project, transactions.remark, transactions.balance, clerks.name FROM transactions LEFT JOIN members ON transactions.member_id = members.id LEFT JOIN clerks ON transactions.clerk_id = clerks.id WHERE members.name LIKE '%{keyword}%' OR members.phone LIKE '%{keyword}%' ORDER BY transactions.transaction_date DESC"
cursor.execute(query)
transactions = cursor.fetchall()
self.transaction_table.setRowCount(0)
for row, transaction in enumerate(transactions):
self.transaction_table.insertRow(row)
for col, data in enumerate(transaction):
item = QTableWidgetItem(str(data))
item.setFlags(Qt.ItemIsEnabled)
self.transaction_table.setItem(row, col, item)
#导出会员充值/消费记录
def export_transaction_table(self):
workbook = openpyxl.Workbook()
sheet = workbook.active
# 添加表头
headers = ["姓名", "手机号", "金额", "时间", "项目", "备注", "余额", "营业员"]
for col_num, header in enumerate(headers, 1):
sheet.cell(row=1, column=col_num, value=header)
# 添加数据
cursor.execute("SELECT members.name, members.phone, transactions.amount, transactions.transaction_date, transactions.project, transactions.remark, transactions.balance, clerks.name FROM transactions JOIN members ON transactions.member_id = members.id JOIN clerks ON transactions.clerk_id = clerks.id")
transactions = cursor.fetchall()
for row_num, transaction in enumerate(transactions, 2):
for col_num, value in enumerate(transaction, 1):
sheet.cell(row=row_num, column=col_num, value=value)
# 选择保存路径
filename, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "Excel Files (*.xlsx)")
if filename:
workbook.save(filename)
QMessageBox.information(self, "提示", f"会员充值/消费记录表已成功导出为:{filename}")
#排序
def sort_transaction_table(self, column):
self.transaction_table.sortItems(column, self.sort_order)
self.sort_order = Qt.DescendingOrder if self.sort_order == Qt.AscendingOrder else Qt.AscendingOrder
#查询美容项目
def search_beauty_project(self):
keyword = self.beauty_project_entry.text()
query = f"SELECT id, name, times, strftime('%Y-%m-%d %H:%M:%S', datetime) FROM beauty_projects WHERE name LIKE '%{keyword}%'"
cursor.execute(query)
beauty_projects = cursor.fetchall()
self.beauty_project_table.setRowCount(0)
for row, beauty_project in enumerate(beauty_projects):
self.beauty_project_table.insertRow(row)
for col, data in enumerate(beauty_project):
item = QTableWidgetItem(str(data))
item.setFlags(Qt.ItemIsEnabled)
self.beauty_project_table.setItem(row, col, item)
#新建美容项目
def create_add_beauty_project_window(self):
add_beauty_project_window = AddBeautyProjectWindow(self)
add_beauty_project_window.exec_()
#修改美容项目
def edit_beauty_project(self):
selected_row = self.beauty_project_table.currentRow()
if selected_row != -1:
beauty_project_id = self.beauty_project_table.item(selected_row, 0).text()
edit_beauty_project_window = EditBeautyProjectWindow(beauty_project_id, self)
edit_beauty_project_window.exec_()
else:
QMessageBox.warning(self, "警告", "请选择要修改的美容项目。")
#删除美容项目
def delete_beauty_project(self):
selected_row = self.beauty_project_table.currentRow()
if selected_row != -1:
beauty_project_id = self.beauty_project_table.item(selected_row, 0).text()
query = f"SELECT * FROM beauty_projects WHERE id = {beauty_project_id}"
cursor.execute(query)
beauty_project = cursor.fetchone()
if beauty_project:
confirm = QMessageBox.question(self, "确认", "【警告】确定要删除该美容项目吗?")
if confirm == QMessageBox.Yes:
query = f"DELETE FROM beauty_projects WHERE id = {beauty_project_id}"
cursor.execute(query)
conn.commit()
QMessageBox.information(self, "提示", "美容项目删除成功。")
self.search_beauty_project()
else:
QMessageBox.warning(self, "错误", "选择的美容项目不存在。")
else:
QMessageBox.warning(self, "警告", "请选择要删除的美容项目。")
#查询营业员
def search_clerk(self):
keyword = self.clerks_entry.text()
query = f"SELECT id, name FROM clerks WHERE name LIKE '%{keyword}%' AND is_deleted = 0"
cursor.execute(query)
clerks = cursor.fetchall()
self.clerks_table.setRowCount(0)
for row, clerks in enumerate(clerks):
self.clerks_table.insertRow(row)
for col, data in enumerate(clerks):
item = QTableWidgetItem(str(data))
item.setFlags(Qt.ItemIsEnabled)
self.clerks_table.setItem(row, col, item)
#新增营业员窗口
def create_add_clerk_window(self):
add_clerk_window = AddClerkWindow(self)
add_clerk_window.exec_()
# 营业员删除
def delete_clerks(self):
selected_row = self.clerks_table.currentRow()
if selected_row != -1:
clerks_id = self.clerks_table.item(selected_row, 7).text()
query = f"SELECT * FROM clerks WHERE id = {clerks_id}"
cursor.execute(query)
clerks = cursor.fetchone()
if clerks:
confirm = QMessageBox.question(self, "确认", "【警告】确定要删除该营业员吗?")
if confirm == QMessageBox.Yes:
# 不真正删除营业员,而是将其标记为已删除
query = f"UPDATE clerks SET is_deleted = 1 WHERE id = {clerks_id}"
cursor.execute(query)
conn.commit()
QMessageBox.information(self, "提示", "营业员删除成功。")
self.search_clerk()
else:
QMessageBox.warning(self, "错误", "选择的营业员不存在。")
else:
QMessageBox.warning(self, "警告", "请选择要删除的营业员。")
#查询会员项目
def search_report(self):
keyword = self.report_entry.text()
query = f"SELECT members.name, members.phone, beauty_projects.name, member_beauty_projects.sessions FROM member_beauty_projects JOIN members ON member_beauty_projects.member_id = members.id JOIN beauty_projects ON member_beauty_projects.beauty_project_id = beauty_projects.id WHERE members.name LIKE '%{keyword}%' OR members.phone LIKE '%{keyword}%'"
cursor.execute(query)
reports = cursor.fetchall()
self.report_table.setRowCount(0)
for row, report in enumerate(reports):
self.report_table.insertRow(row)
for col, data in enumerate(report):
item = QTableWidgetItem(str(data))
item.setFlags(Qt.ItemIsEnabled)
self.report_table.setItem(row, col, item)
#新增会员对话框
class AddMemberWindow(QDialog):
def __init__(self, parent):
super().__init__(parent)
self.setWindowTitle("新增会员")
name_label = QLabel("会员姓名:")
self.name_entry = QLineEdit()
phone_label = QLabel("手机号:")
self.phone_entry = QLineEdit()
birthday_label = QLabel("生日:") # 新增
self.birthday_entry = QDateEdit() # 新增
self.birthday_entry.setCalendarPopup(True) # 新增
layout = QGridLayout()
layout.addWidget(name_label, 0, 0)
layout.addWidget(self.name_entry, 0, 1)
layout.addWidget(phone_label, 1, 0)
layout.addWidget(self.phone_entry, 1, 1)
layout.addWidget(birthday_label, 2, 0) # 新增
layout.addWidget(self.birthday_entry, 2, 1) # 新增
add_button = QPushButton("确定")
add_button.clicked.connect(self.add_member)
layout.addWidget(add_button, 3, 0, 1, 2) # 修改
self.setLayout(layout)
def validate_phone(self, phone):
pattern = r"^1[3456789]\d{9}$"
if not re.match(pattern, phone):
return False
return True
def check_phone_exists(self, phone):
query = f"SELECT * FROM members WHERE phone = '{phone}'"
cursor.execute(query)
member = cursor.fetchone()
if member:
return True
return False
def add_member(self):
name = self.name_entry.text()
phone = self.phone_entry.text()
birthday = self.birthday_entry.date().toString("yyyy-MM-dd") # 新增
if not self.validate_phone(phone):
QMessageBox.warning(self, "错误", "手机号格式不正确。")
return
if self.check_phone_exists(phone):
QMessageBox.warning(self, "错误", "手机号已存在,请输入其他手机号。")
return
query = f"INSERT INTO members (name, phone, birthday, register_date, balance) VALUES ('{name}', '{phone}', '{birthday}', '{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}', 0)" # 修改
cursor.execute(query)
conn.commit()
QMessageBox.information(self, "提示", "会员添加成功。")
self.parent().search_member()
self.close()
#修改会员信息
class EditMemberWindow(QDialog):
def __init__(self, member_id, parent):
super().__init__(parent)
self.setWindowTitle("修改会员信息")
self.member_id = member_id
query = f"SELECT * FROM members WHERE id = {self.member_id}"
cursor.execute(query)
member = cursor.fetchone()
self.old_balance = member[6]
name_label = QLabel("会员姓名:")
self.name_entry = QLineEdit()
self.name_entry.setText(member[1])
phone_label = QLabel("手机号:")
self.phone_entry = QLineEdit()
self.phone_entry.setText(member[2])
birthday_label = QLabel("生日:") # 新增
self.birthday_entry = QDateEdit() # 新增
self.birthday_entry.setCalendarPopup(True) # 新增
self.birthday_entry.setDate(QDate.fromString(member[5], "yyyy-MM-dd")) # 新增
balance_label = QLabel("余额:")
self.balance_entry = QLineEdit()
self.balance_entry.setText(str(member[6]))
layout = QGridLayout()
layout.addWidget(name_label, 0, 0)
layout.addWidget(self.name_entry, 0, 1)
layout.addWidget(phone_label, 1, 0)
layout.addWidget(self.phone_entry, 1, 1)
layout.addWidget(birthday_label, 2, 0) # 新增
layout.addWidget(self.birthday_entry, 2, 1) # 新增
layout.addWidget(balance_label, 3, 0) # 修改
layout.addWidget(self.balance_entry, 3, 1) # 修改
save_button = QPushButton("保存")
save_button.clicked.connect(self.save_member)
layout.addWidget(save_button, 4, 0, 1, 2) # 修改
self.setLayout(layout)
def validate_phone(self, phone):
pattern = r"^1[3456789]\d{9}$"
if not re.match(pattern, phone):
return False
return True
def check_phone_exists(self, phone):
query = f"SELECT * FROM members WHERE phone = '{phone}'"
cursor.execute(query)
member = cursor.fetchone()
if member:
return True
return False
def save_member(self):
name = self.name_entry.text()
phone = self.phone_entry.text()
birthday = self.birthday_entry.date().toString("yyyy-MM-dd") # 新增
balance = self.balance_entry.text()
# 检查手机号是否已经被修改
query = f"SELECT phone FROM members WHERE id = {self.member_id}"
cursor.execute(query)
old_phone = cursor.fetchone()[0]
if phone != old_phone and self.check_phone_exists(phone):
QMessageBox.warning(self, "错误", "手机号已存在,请输入其他手机号。")
return
if not self.validate_phone(phone):
QMessageBox.warning(self, "错误", "手机号格式不正确。")
return
query = f"UPDATE members SET name = '{name}', phone = '{phone}', birthday = '{birthday}', balance = {balance} WHERE id = {self.member_id}" # 修改
cursor.execute(query)
conn.commit()
query = f"SELECT * FROM members WHERE id = {self.member_id}"
cursor.execute(query)
updated_member = cursor.fetchone()
new_balance = updated_member[6]
if self.old_balance != new_balance:
amount = float(new_balance) - float(self.old_balance)
transaction_query = f"INSERT INTO transactions (member_id, amount, project,transaction_date, balance, remark) VALUES ({self.member_id}, {amount}, '无','{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}', {new_balance},'修改余额')"
cursor.execute(transaction_query)
conn.commit()
QMessageBox.information(self, "提示", "会员信息修改成功。")
self.parent().search_transaction()
self.parent().search_member()
self.close()
#会员充值
class RechargeDialog(QDialog):
def __init__(self, member_id, parent):
super().__init__(parent)
self.setWindowTitle("会员充值")
self.member_id = member_id
amount_label = QLabel("充值金额:")
self.amount_entry = QLineEdit()
clerk_label = QLabel("营业员:")
self.clerk_combo = QComboBox()
self.load_clerks()
layout = QVBoxLayout() # 定义布局
layout.addWidget(amount_label)
layout.addWidget(self.amount_entry)
layout.addWidget(clerk_label)
layout.addWidget(self.clerk_combo)
confirm_button = QPushButton("确认")
confirm_button.clicked.connect(self.confirm_recharge)
layout.addWidget(confirm_button)
self.setLayout(layout)
#读取营业员信息
def load_clerks(self):
cursor.execute("SELECT name FROM clerks")
clerks = cursor.fetchall()
for clerk in clerks:
self.clerk_combo.addItem(clerk[0])
#确认充值信息
def confirm_recharge(self):
try:
amount = float(self.amount_entry.text())
if amount > 0:
query = f"SELECT balance FROM members WHERE id = {self.member_id}"
cursor.execute(query)
member = cursor.fetchone()
if member:
current_balance = member[0]
new_balance = current_balance + amount
clerk_name = self.clerk_combo.currentText()
cursor.execute("SELECT id FROM clerks WHERE name = ?", (clerk_name,))
clerk = cursor.fetchone()
if clerk is not None:
clerk_id = clerk[0]
query = f"UPDATE members SET balance = {new_balance} WHERE id = {self.member_id}"
cursor.execute(query)
conn.commit()
transaction_query = f"INSERT INTO transactions (member_id, amount, project,transaction_date, balance, remark, clerk_id) VALUES ({self.member_id}, {amount}, '无','{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}',{new_balance}, '充值', {clerk_id})"
cursor.execute(transaction_query)
conn.commit()
QMessageBox.information(self, "提示", "充值成功。")
self.parent().search_member()
self.parent().search_transaction()
self.close()
else:
QMessageBox.information(self, "提示", "请输入营业员!")
return
else:
QMessageBox.warning(self, "错误", "选择的会员不存在。")
else:
QMessageBox.warning(self, "错误", "充值金额必须大于0。")
except ValueError:
QMessageBox.warning(self, "错误", "请输入有效的充值金额。")
#会员消费窗口
class ConsumeDialog(QDialog):
def __init__(self, member_id, parent):
super().__init__(parent)
self.setWindowTitle("会员消费")
self.member_id = member_id
amount_label = QLabel("消费金额:")
self.amount_entry = QLineEdit("0")
project_label = QLabel("美容项目:")
self.project_combo = QComboBox()
self.load_projects()
clerk_label = QLabel("营业员:")
self.clerk_combo = QComboBox()
self.load_clerks()
layout = QVBoxLayout()
layout.addWidget(clerk_label)
layout.addWidget(self.clerk_combo)
layout.addWidget(amount_label)
layout.addWidget(self.amount_entry)
layout.addWidget(project_label)
layout.addWidget(self.project_combo)
confirm_button = QPushButton("确认")
confirm_button.clicked.connect(self.confirm_consume)
layout.addWidget(confirm_button)
self.setLayout(layout)
#读取营业员信息
def load_clerks(self):
cursor.execute("SELECT name FROM clerks")
clerks = cursor.fetchall()
for clerk in clerks:
self.clerk_combo.addItem(clerk[0])
#读取会员美容项目
def load_projects(self):
self.project_combo.addItem("无") # Add "无" option
query = f"SELECT beauty_projects.name FROM beauty_projects JOIN member_beauty_projects ON beauty_projects.id = member_beauty_projects.beauty_project_id WHERE member_beauty_projects.member_id = {self.member_id}"
cursor.execute(query)
projects = cursor.fetchall()
if projects:
for project in projects:
self.project_combo.addItem(project[0])
#确认消费
def confirm_consume(self):
project_name = self.project_combo.currentText()
clerk_name = self.clerk_combo.currentText()
cursor.execute("SELECT id FROM clerks WHERE name = ?", (clerk_name,))
clerk = cursor.fetchone()
if clerk is not None:
clerk_id = clerk[0]
else:
QMessageBox.warning(self, "错误", "请输入营业员!")
return
amount = float(self.amount_entry.text())
if project_name != "无":
# 获取项目ID
cursor.execute("SELECT id FROM beauty_projects WHERE name = ?", (project_name,))
project_id = cursor.fetchone()[0]
# 使用项目ID替换项目名
query = f"SELECT * FROM member_beauty_projects WHERE member_id = {self.member_id} AND beauty_project_id = {project_id}"
cursor.execute(query)
member_project = cursor.fetchone()
if member_project:
if member_project[2] > 0: # 检查剩余次数
# 使用项目ID替换项目名
query = f"UPDATE member_beauty_projects SET sessions = sessions - 1 WHERE member_id = {self.member_id} AND beauty_project_id = {project_id}"
cursor.execute(query)
conn.commit()
QMessageBox.information(self, "提示", "消费成功。")
# 获取当前余额
query = f"SELECT balance FROM members WHERE id = {self.member_id}"
cursor.execute(query)
member = cursor.fetchone()
current_balance = member[0]
new_balance = current_balance - amount
transaction_query = f"INSERT INTO transactions (member_id, amount, project, transaction_date, balance, remark, clerk_id) VALUES ({self.member_id}, {-amount}, '{self.project_combo.currentText()}','{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}',{new_balance}, '消费', {clerk_id})"
cursor.execute(transaction_query)
conn.commit()
self.parent().search_member()
self.parent().search_transaction()
self.close()
else:
QMessageBox.warning(self, "错误", "该会员的此项目次数已用完。")
else:
QMessageBox.warning(self, "错误", "该会员没有购买此项目。")
else:
if amount > 0:
query = f"SELECT balance FROM members WHERE id = {self.member_id}"
cursor.execute(query)
member = cursor.fetchone()
if member:
current_balance = member[0]
if current_balance >= amount:
new_balance = current_balance - amount
query = f"UPDATE members SET balance = {new_balance}, last_consume_date = '{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}' WHERE id = {self.member_id}"
cursor.execute(query)
conn.commit()
transaction_query = f"INSERT INTO transactions (member_id, amount, transaction_date, balance, project, remark, clerk_id) VALUES ({self.member_id}, {-amount}, '{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}',{new_balance}, '{self.project_combo.currentText()}','消费', {clerk_id})"
cursor.execute(transaction_query)
conn.commit()
QMessageBox.information(self, "提示", "消费成功。")
self.parent().search_member()
self.parent().search_transaction()
self.close()
else:
QMessageBox.warning(self, "错误", "余额不足,无法消费。")
#会员购卡
class BuyBeautyProjectDialog(QDialog):
def __init__(self, member_id, parent):
super().__init__(parent)
self.setWindowTitle("购买美容项目")
self.member_id = member_id
project_label = QLabel("选择美容项目:")
self.project_combo = QComboBox()
self.load_beauty_projects()
clerk_label = QLabel("营业员:")
self.clerk_combo = QComboBox()
self.load_clerks()
layout = QVBoxLayout() # 定义布局
layout.addWidget(clerk_label)
layout.addWidget(self.clerk_combo)
layout.addWidget(project_label)
layout.addWidget(self.project_combo)
confirm_button = QPushButton("确认")
confirm_button.clicked.connect(self.buy_beauty_project)
layout.addWidget(confirm_button)
self.setLayout(layout)
#读取营业员信息
def load_clerks(self):
cursor.execute("SELECT name FROM clerks")
clerks = cursor.fetchall()
for clerk in clerks:
self.clerk_combo.addItem(clerk[0])
#读取美容项目
def load_beauty_projects(self):
cursor.execute("SELECT name FROM beauty_projects")
beauty_projects = cursor.fetchall()
for project in beauty_projects:
self.project_combo.addItem(project[0])
#购买美容项目
def buy_beauty_project(self):
project_name = self.project_combo.currentText()
cursor.execute("SELECT id, times FROM beauty_projects WHERE name = ?", (project_name,))
project = cursor.fetchone()
project_id = project[0]
project_times = project[1] # 获取项目的次数
# 检查会员是否已经购买了这个项目
cursor.execute("SELECT * FROM member_beauty_projects WHERE member_id = ? AND beauty_project_id = ?", (self.member_id, project_id))
if cursor.fetchone():
# 如果会员已经购买了这个项目,那么显示一个错误消息并返回
QMessageBox.warning(self, "错误", "你已经购买了这个项目。")
return
cursor.execute("INSERT INTO member_beauty_projects (member_id, beauty_project_id, sessions) VALUES (?, ?, ?)", (self.member_id, project_id, project_times))
conn.commit()
clerk_name = self.clerk_combo.currentText()
cursor.execute("SELECT id FROM clerks WHERE name = ?", (clerk_name,))
clerk_id = cursor.fetchone()[0]
transaction_query = f"INSERT INTO transactions (member_id, project, transaction_date, remark, clerk_id) VALUES ({self.member_id}, '{project_name}', '{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}', '购卡', {clerk_id})"
cursor.execute(transaction_query)
conn.commit()
QMessageBox.information(self, "提示", "购买成功。")
self.close()
#新增美容项目对话框
class AddBeautyProjectWindow(QDialog):
def __init__(self, parent):
super().__init__(parent)
self.setWindowTitle("新增美容项目")
name_label = QLabel("美容项目名称:")
self.name_entry = QLineEdit()
times_label = QLabel("次数:")
self.times_entry = QLineEdit()
datetime_label = QLabel("新建时间:")
self.datetime_entry = QDateTimeEdit(datetime.now())
self.datetime_entry.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
layout = QGridLayout()
layout.addWidget(name_label, 0, 0)
layout.addWidget(self.name_entry, 0, 1)
layout.addWidget(times_label, 1, 0)
layout.addWidget(self.times_entry, 1, 1)
layout.addWidget(datetime_label, 2, 0)
layout.addWidget(self.datetime_entry, 2, 1)
add_button = QPushButton("确定")
add_button.clicked.connect(self.add_beauty_project)
layout.addWidget(add_button, 3, 0, 1, 2)
self.setLayout(layout)
def add_beauty_project(self):
name = self.name_entry.text()
times = self.times_entry.text()
datetime = self.datetime_entry.dateTime().toString("yyyy-MM-dd HH:mm:ss")
if self.check_beauty_project_exists(name):
QMessageBox.warning(self, "错误", "美容项目已存在,请输入其他美容项目。")
return
query = f"INSERT INTO beauty_projects (name, times, datetime) VALUES ('{name}', {times}, '{datetime}')"
cursor.execute(query)
conn.commit()
QMessageBox.information(self, "提示", "美容项目添加成功。")
self.parent().search_beauty_project()
self.close()
def check_beauty_project_exists(self, name):
query = f"SELECT * FROM beauty_projects WHERE name = '{name}'"
cursor.execute(query)
beauty_project = cursor.fetchone()
if beauty_project:
return True
return False
#修改美容项目对话框
class EditBeautyProjectWindow(QDialog):
def __init__(self, beauty_project_id, parent):
super().__init__(parent)
self.setWindowTitle("修改美容项目")
self.beauty_project_id = beauty_project_id
query = f"SELECT * FROM beauty_projects WHERE id = {self.beauty_project_id}"
cursor.execute(query)
beauty_project = cursor.fetchone()
name_label = QLabel("美容项目名称:")
self.name_entry = QLineEdit()
self.name_entry.setText(beauty_project[1])
times_label = QLabel("次数:")
self.times_entry = QLineEdit()
self.times_entry.setText(str(beauty_project[2]))
layout = QGridLayout()
layout.addWidget(name_label, 0, 0)
layout.addWidget(self.name_entry, 0, 1)
layout.addWidget(times_label, 1, 0)
layout.addWidget(self.times_entry, 1, 1)
save_button = QPushButton("保存")
save_button.clicked.connect(self.save_beauty_project)
layout.addWidget(save_button, 2, 0, 1, 2)
self.setLayout(layout)
def save_beauty_project(self):
name = self.name_entry.text()
times = self.times_entry.text()
query = f"UPDATE beauty_projects SET name = '{name}', times = {times} WHERE id = {self.beauty_project_id}"
cursor.execute(query)
conn.commit()
QMessageBox.information(self, "提示", "美容项目信息修改成功。")
self.parent().search_beauty_project()
self.close()
#新增营业员对话框
class AddClerkWindow(QDialog):
def __init__(self, parent):
super().__init__(parent)
self.setWindowTitle("新增营业员")
name_label = QLabel("营业员名称:")
self.name_entry = QLineEdit()
layout = QGridLayout()
layout.addWidget(name_label, 0, 0)
layout.addWidget(self.name_entry, 0, 1)
add_button = QPushButton("确定")
add_button.clicked.connect(self.add_clerk)
layout.addWidget(add_button, 3, 0, 1, 2)
self.setLayout(layout)
def add_clerk(self):
name = self.name_entry.text()
if self.check_clerk_exists(name):
QMessageBox.warning(self, "错误", "营业员已存在,请输入其他营业员。")
return
query = f"INSERT INTO clerks (name) VALUES ('{name}')"
cursor.execute(query)
conn.commit()
QMessageBox.information(self, "提示", "营业员添加成功。")
self.parent().search_clerk()
self.close()
def check_clerk_exists(self, name):
query = f"SELECT * FROM clerks WHERE name = '{name}'"
cursor.execute(query)
clerk = cursor.fetchone()
if clerk:
return True
return False
if __name__ == "__main__":
backup_database()
app = QApplication(sys.argv)
login_window = LoginWindow()
login_window.show()
sys.exit(app.exec_())
【2023年8月9日】源码下载: https://pan.baidu.com/s/1_94DCdONpmYzRyYDC_7CRQ?pwd=9ep6 提取码: 9ep6
【旧版】成品下载:链接:https://pan.baidu.com/s/1FlupRHGkVGOZK6Z6q_gshg?pwd=o2gv提取码:o2gv