前言

课程设计用的是vfp,但是我对vfp很不感冒。但是没办法,硬着头皮写吧。我这里先写个python草稿
之前接单的时候有过很类似的项目,可以说是一模一样,由于写过一次我觉得还是没有难度的

题目分析

程序必须实现的功能如下:

  1. 登陆(查)
  2. 车辆信息管理(增删改查)
  3. 驾驶员信息管理(增删改查)
  4. 投诉信息管理(表连接,增删改查)
  5. 驾驶员信息浏览(查)
  6. 投诉信息浏览(查)
  7. 用户权限管理(查)
  8. CS架构(mysql服务器作为server端,client端直接处理返回的数据即可,不必另做server端)

程序实现

登陆模块

很简单就能实现

流程图

流程图

ui设计

这里我用我自己以前接单的项目掏了一个登陆和注册ui过来,名字为"login.ui"
图片-1667876905294
登陆模块如下
登录模块
注册模块如下
注册模块
然后用pyuic转换一下,生成ui的py代码

图片-1667876970413

代码实现

ui代码

创建一个py文件,命名为main

from login import Ui_MainWindow1
from PyQt5.QtWidgets import QApplication, QMainWindow,QMessageBox,QGroupBox,QHeaderView,QMenu,QAbstractItemView
from PyQt5.QtGui import QIcon,QStandardItemModel,QStandardItem,QCursor
from PyQt5.Qt import QThread, pyqtSignal,QSize,QColor,QBrush,QMutex,QThreadPool,QCoreApplication
from PyQt5 import QtCore,QtWidgets
import sys
class mylogin(QMainWindow, Ui_MainWindow1):
    def __init__(self):
        super(mylogin, self).__init__() # 继承父类
        self.setupUi(self) # 对应Ui_MainWindow1.setupUI
if __name__ == "__main__":
    app = QApplication(sys.argv)
    loginUI = mylogin() # 实例化类
    loginUI.show() # 展示界面
    sys.exit(app.exec())

效果如下
图片-1667877396001

逻辑设计

登陆按钮的对象名为pushButton
图片-1667877464913

图片-1667877615155
由于clicked作为一个信号,直接调用connect方法即可

self.pushButton.clicked.connect(self.login)

接下来写login方法,由于需要进入数据库查询,首先得搭建个本地数据库,关于数据库的搭建方法请跳转我的csdn文章

这里直接上建表sql过程,打开powershell,输入如下命令并输入密码链接数据库

mysql -uroot -p

图片-1667878040350

CREATE DATABASE classDesign;

图片-1667878134673

USE classDesign;

图片-1667878176038

CREATE TABLE loginAccount
(
username CHAR(20) NOT NULL,
password CHAR(20) NOT NULL,
group1 CHAR(20) NOT NULL,
PRIMARY KEY(username)
);

图片-1667878307328

至此建表完成

接下来接着写login方法

import pymysql
    def login(self):
        mysqlConnect = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',               # 你的用户名
            passwd='',                 # 你的数据库密码
            db='classDesign')
        inPutUsername = self.lineEdit.text()   # 取得现在输入的用户名
        inPutPassword = self.lineEdit_2.text() # 取得现在输入的密码
        cur = mysqlConnect.cursor()
        
        if inPutUsername.strip("") == "" or inPutPassword.strip("") == "":
            QMessageBox.information(None, "提示", "请输入用户名或密码", QMessageBox.Yes)
            return
            
        try:
            cur.execute('SELECT * FROM  loginAccount WHERE username = "{}";'.format(inPutUsername))
            result = cur.fetchall()  # 返回数组[username,password]形式
            password = result[0][1]
            if inPutPassword == password: # 如果返回的密码和输入的密码正确
                QMessageBox.information(None, "提示", "登陆成功", QMessageBox.Yes)
            else:
                QMessageBox.information(None, "提示", "密码不正确", QMessageBox.Yes)
        except Exception as e:
            QMessageBox.information(None,"提示","用户名不存在",QMessageBox.Yes)  # 如果sql语句找不到username就会返回错误,这里使用了try-except捕获错误
        mysqlConnect.close()

同理写注册逻辑

    def register(self):
        mysqlConnect = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',               # 你的用户名
            passwd='',                 # 你的数据库密码
            db='classDesign')
        inPutUsername = self.lineEdit_3.text()   # 取得现在输入的用户名
        if self.lineEdit_4.text() != self.lineEdit_5.text():
            QMessageBox.information(None,"提示","两次输入的账号密码不同",QMessageBox.Yes)
        inPutPassword = self.lineEdit_4.text() # 取得现在输入的密码
        cur = mysqlConnect.cursor()
        try:

            cur.execute('INSERT INTO loginAccount (username,password)VALUES(%s,%s);',
                        [inPutUsername, inPutPassword])
            mysqlConnect.commit()
            QMessageBox.information(None, "提示", "注册成功", QMessageBox.Yes)
        except Exception as e:
            QMessageBox.information(None,"提示","用户名已存在",QMessageBox.Yes)
        mysqlConnect.close()

运行效果如下

注册

图片-1667879726747

图片-1667879770962

登陆

正确情况
图片-1667880005833

没输入用户名密码情况
图片-1667880272574
用户名不正确情况
图片-1667880289917
密码不正确情况
图片-1667880096638

自动登陆和保存账号密码

使用python自带的configparser库实现保存设置
步骤无非2个,取得数据,保存到当前文件夹的.ini文件
我这里写在了mylogin类的初始化上
图片-1667897628343

但是这样做会有个问题,如果初始化了,那么登陆过后,下面的show()方法依旧运行

图片-1667895306836

就会变成这样
那么在这里的show()加上一个判断条件即可解决
图片-1667895332640
顺便把保存做成一个接口,以后想要保存直接self.save()就可以代码复用
图片-1667895959581

main完整代码

from login import Ui_MainWindow1
from PyQt5.QtWidgets import QApplication, QMainWindow,QMessageBox,QGroupBox,QHeaderView,QMenu,QAbstractItemView
from PyQt5.QtGui import QIcon,QStandardItemModel,QStandardItem,QCursor
from PyQt5.Qt import QThread, pyqtSignal,QSize,QColor,QBrush,QMutex,QThreadPool,QCoreApplication
from PyQt5 import QtCore,QtWidgets
import sys
import pymysql
class mylogin(QMainWindow, Ui_MainWindow1):
    def __init__(self):
        super(mylogin, self).__init__() # 继承父类
        self.setupUi(self) # 对应Ui_MainWindow1.setupUI
        self.pushButton.clicked.connect(self.login) # 登陆
        self.pushButton_2.clicked.connect(self.close) # 退出
        self.pushButton_5.clicked.connect(self.register) # 注册
        self.pushButton_4.clicked.connect(self.close) # 退出

    def login(self):
        mysqlConnect = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',               # 你的用户名
            passwd='',   # 你的数据库密码
            db='classDesign')
        inPutUsername = self.lineEdit.text()   # 取得现在输入的用户名
        inPutPassword = self.lineEdit_2.text() # 取得现在输入的密码
        cur = mysqlConnect.cursor()
        if inPutUsername.strip("") == "" or inPutPassword.strip("") == "":
            QMessageBox.information(None, "提示", "请输入用户名或密码", QMessageBox.Yes)
            return
        try:
            cur.execute('SELECT * FROM  loginAccount WHERE username = "{}";'.format(inPutUsername))
            result = cur.fetchall()  # 返回数组[username,password]形式
            password = result[0][1]
            if inPutPassword == password: # 如果返回的密码和输入的密码正确
                QMessageBox.information(None, "提示", "登陆成功", QMessageBox.Yes)
            else:
                QMessageBox.information(None, "提示", "密码不正确", QMessageBox.Yes)
        except Exception as e:
            QMessageBox.information(None,"提示","用户名不存在",QMessageBox.Yes)  # 如果sql语句找不到username就会返回错误,这里使用了try-except捕获错误
        mysqlConnect.close()
    def register(self):
        mysqlConnect = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',               # 你的用户名
            passwd='',   # 你的数据库密码
            db='classDesign')
        inPutUsername = self.lineEdit_3.text()   # 取得现在输入的用户名
        if self.lineEdit_4.text() != self.lineEdit_5.text():
            QMessageBox.information(None,"提示","两次输入的账号密码不同",QMessageBox.Yes)
        inPutPassword = self.lineEdit_4.text() # 取得现在输入的密码
        cur = mysqlConnect.cursor()
        try:

            cur.execute('INSERT INTO loginAccount (username,password)VALUES(%s,%s);',
                        [inPutUsername, inPutPassword])
            mysqlConnect.commit()
            QMessageBox.information(None, "提示", "注册成功", QMessageBox.Yes)
        except Exception as e:
            QMessageBox.information(None,"提示","用户名已存在",QMessageBox.Yes)
        mysqlConnect.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    loginUI = mylogin() # 实例化类
    loginUI.show() # 展示界面
    sys.exit(app.exec())

主程序模块

实现用户权限管理

我的思路是通过新增一个表,并且在loginAccount中新增权限(group)字段,通过连接表实现权限,这是受到linux读写权限启发得来

添加权限表

表设计如下

group add delete update select editAccount
admin 1 1 1 1 1
user 0 0 0 1 0

admin权限组可以实现增删改查,user权限组只能修改自己的密码(默认权限,这里省略字段了),查询表

制作ui

创建一个新窗口
图片-1667884692553

ctrl+s保存为myMainWindow.ui
图片-1667884746822

添加tab widget,方便其他功能使用
图片-1667884801005
使用栅格布局,改变ui的观感
图片-1667884858148

改变tab1的名字,改为用户管理
图片-1667884941799

以下略

我设计ui的水瓶一般,随便看看就好
图片-1667885661134

查询按钮实现

图片-1667885916904

好懒不想写细节了,大概思路就是添加一个tableView,然后请求数据库返回的信息处理后,往tableView写数据,我这里直接在表格右键实现了添加修改删除三个功能

主要说一下遇到的麻烦

添加

主要解决添加以后直接显示添加出来数据
由于提前把刷新数据做了一个方法接口,直接在插入数据以后调用即可
图片-1667908313869

修改

修改密码倒是简单,主要解决修改用户名
用户名修改的时候有两个问题

  1. 用户名是主键,如果修改容易出事情
  2. 用户名右键修改的时候,没法获取原来的用户名

问题1我选择了删除主键,修改,然后再增加主键的做法,以前是先把这一条数据保存起来,再删除,再添加回去新修改的数据

问题2,由于我选择了删除主键,修改,没有保存原来的数据,在这里耗费了很多时间。
我在mainUI.setData()方法里添加了一个self.data用于保存原先的数据
于是问题迎刃而解了
图片-1667908490904

删除

由于删除会直接改变表格的数据条数,删除以后会导致表格存在重复项没有消去
我的解决方法是直接保存当前行所在的序号,然后删除后直接调用removeRow(index),直接删掉对应行
图片-1667908504804

修改密码按钮实现

图片-1667908632933
我直接对着改密按钮clicked信号链接到一个创建新ui,并且调用新ui的方法实现相应逻辑
问题在于修改密码以后自动登录会乱掉。比如如果密码错误,之前已经删除掉了show()方法,登陆按钮在弹出密码错误的框以后不会显示。
在login添加一个自动登陆的flag,实现相应的逻辑
图片-1667908770468

车辆信息

由于接下来要实现的功能和上面高度相似,需要注意的问题是复用表,其他的我觉得没有必要再写了,添加个标题看起来整齐点
建表sql语句

CREATE TABLE carProfile(
type char(10),
brand char(2),
engineNo char(10),
carNo char(8),
Num char(6),
PRIMARY KEY(Num)
)

主要是实现单独查询的功能,我这里给右键菜单添加了一个独特查询按键
图片-1667990917864
点进去是这样的
图片-1667990958445
如果要查询桂A23348这个车辆,那么就在这里找到他的车牌然后点击查询,会打开一个新表
图片-1667990996153

驾驶员信息

同上一模一样的功能,也是右键查询

CREATE TABLE driverProfile(
name char(12),
IDcard char(18),
address char(30),
contact char(11),
code char(6),
driverNo char(8),
PRIMARY KEY(driverNo)
)

投诉信息

CREATE TABLE issue(
carNo char(10),
reason char(50),
time datetime(0) NOT NULL DEFAULT now(),
opinion char(50),
operator char(12),
Num char(8),
PRIMARY KEY(Num)
)

这里比较重要的是实现的车辆信息必须先查询,把sql语句改一下就行了
图片-1667991438091

图片-1667991460318
这样就能查询对应的车辆是否存在违规信息

字段约束

我考虑的是在添加,修改的时候额外添加一个窗口,和之前的用表格修改区别开来
吃饭先