跳转至

项目实战5-现代风格界面

点击这里,观看视频讲解

这个实战项目 是开发一个 制药公司的 客户订单管理系统, 包括 客户/产品/订单的 增删改查 和 工作流操作。

锻炼的是开发 CS架构的 前端系统

项目简介

这个实战项目 是开发一个 制药公司的 客户订单管理系统, 包括 客户/产品/订单的 增删改查 和 工作流操作。

锻炼的是开发 CS架构的 前端系统


这个实战要求你作为前端开发人员, 开发其中的 前端系统 ,该系统的功能界面如下


锻炼本项目实战,需要具备的基础知识点包括:

  • 比较扎实的 Python语言基础

  • 有一定的 Python Qt 图形界面编程能力

项目锻炼重点

  • 现代风格的界面:类似Web界面

  • 定制控件: 时间线, 富文本编辑框 等

  • 界面开发组件化,模块化

  • 项目代码的组织结构

可以微信咨询 byhy44 ,参加实战班 或者 购买视频讲解和代码 。

您需要高效学习,找工作? 点击咨询 报名实战班

点击查看学员就业情况

实战 01 登录界面

实现登录界面, 具体要求点击这里查看视频说明


本次练习的:

参考代码点击这里下载

视频讲解点击这里观看

实战 02 登录到系统服务端

实现登录界面, 具体要求点击这里查看视频说明

先点击这里 阅读理解 BYSMS 系统的 登录/客户/药品/订单 相关的接口。

本次实战练习要求大家实现:

根据接口文档的登录接口规范,发送 HTTP 登录请求给后端,如果返回登录成功,切换到主界面;如果登录失败,在登录界面显示错误原因。

这里主界面只要先实现一个空白窗口即可。


本次练习要运行服务端,

游客 请点击这里,根据教程提示,下载白月SMS系统,并运行即可。

实战班学员 请根据老师发给你的实战说明, 从网盘下载运行 学员定制服务端 和 一些图标资源 。


本次练习的:

视频讲解点击这里观看

预备知识:HTTP 客户端访问

说到 发送 HTTP 请求,可能大家立即会想到 requests 这个库。

但是 requests 库 在 Qt 中使用有2个问题:

  1. 为了等待服务端响应时不阻塞界面, 需要后台线程运行

  2. requests 库的性能比较差


所以这里更推荐使用 Qt 的 QNetworkAccessManager 这个库。

用法示例如下:

from PySide6.QtWidgets import QApplication, QFrame, QHBoxLayout, QPushButton
from PySide6.QtNetwork import QNetworkAccessManager,  QNetworkProxy, \
    QNetworkRequest,QNetworkReply
from PySide6.QtCore import QUrl

class LoginWindow(QFrame):
    def __init__(self):
        super().__init__() 

        self.setFixedSize(800, 600)
        layout = QHBoxLayout(self)

        getBtn = QPushButton('get 请求')
        layout.addWidget(getBtn)
        getBtn.clicked.connect(self.get)

        postBtn = QPushButton('post请求')
        layout.addWidget(postBtn)
        postBtn.clicked.connect(self.post)

        # 创建网络访问管理器对象
        self.nam  = QNetworkAccessManager(None)

        # 使用代理,通常为了抓包调试
        # proxy = QNetworkProxy(QNetworkProxy.HttpProxy, "127.0.0.1", 8888)
        # self.nam.setProxy(proxy)

    def get(self):

        # 构建请求对象
        request = QNetworkRequest(QUrl('http://httpbin.org/get?name=baiyue&age=18'))

        # 发送请求
        getReply = self.nam.get(request) 

        # 定义响应回调函数
        def getFinished():
            if getReply.error() == QNetworkReply.NoError:
                dataBytes = getReply.readAll() # 返回对象类型是: QByteArray
                data = str(dataBytes, 'utf-8') # QByteArray 转换成 str  
                print('--------------') 
                print(data)
            else:
                print(getReply.errorString())

        # 设置响应回调
        getReply.finished.connect(getFinished) 


    def post(self):

        # 构建请求对象
        request = QNetworkRequest(QUrl('http://httpbin.org/post'))

        # 设置请求消息头
        request.setHeader(QNetworkRequest.ContentTypeHeader, 
                          'application/x-www-form-urlencoded')

        # 设置消息体, 不能是字符串类型,可以是bytes类型
        body = b'param1=baiyue&param2=heiyu'

        # 发送请求
        postReply = self.nam.post(request, body)

        # 定义响应回调函数
        def postFinished():
            if postReply.error() == QNetworkReply.NoError:
                dataBytes = postReply.readAll() # 返回对象类型是: QByteArray
                data = str(dataBytes, 'utf-8')  # QByteArray 转换成 str   
                print('--------------') 
                print(data)
            else:
                print(postReply.errorString())

        # 设置响应回调
        postReply.finished.connect(postFinished)

app = QApplication()
lw = LoginWindow()
lw.show()
app.exec()

实战 03 主界面大体布局

实现主体界面的大体布局, 内容如果超过应用窗口边界,能够有滚动条滚动看到所有区域。

具体要求见视频讲解

实战 04 展示一页客户数据

根据接口文档,从服务端获取第一页的客户数据,展示在界面上

具体要求见视频讲解

实战 05 添加一个客户数据

根据接口文档,实现添加一个客户的功能

具体要求见视频讲解

预备知识:清空 Layout

如果这个 layout 直接对应一个widget, 可以删除其对应的 widget,就会清除layout所有内容。

当然这样做,layout也同时被清除了。


如果我们不想删除layout本身,比如 这个 layout 是某个layout的子layout,

要清空它, 包括所有的子控件和子layout

可以这样

from PySide6.QtWidgets import QLayoutItem

def clearLayout(layout):
    while layout.count():
        # takeAt 取出,就从layout中去除了
        child:QLayoutItem = layout.takeAt(0)

        # 如果是子控件,要删除该控件
        if child.widget():
            child.widget().deleteLater()

        # 如果是子 spacerItem, 删除 
        elif child.spacerItem():
            si = child.spacerItem()
            del si

        # 如果是子Layout,递归删除子layout
        elif child.layout():
            clearLayout(child.layout())
            child.layout().deleteLater()

        del child

实战 06 搜索关键字,翻页

根据接口文档,实现 搜索关键字,翻页,刷新 的功能

具体要求见视频讲解

实战 07 修改,删除客户记录

根据接口文档,实现 修改 和 删除 客户记录 的功能

具体要求见视频讲解

实战 08 药品管理

根据接口文档,实现 药品管理 的功能

具体要求见视频讲解

实战 09 订单页面

根据接口文档,实现 订单页面 的功能

具体要求见视频讲解

实战 10 头像,退出登录

根据接口文档,实现 导航栏右边头像,登录名显示 和 退出登录 的功能

具体要求见视频讲解

实战 11 药品送检 工作流 - 列出

实现 药品送检 工作流 界面 里面的 列出工作流记录 功能

如果 工作流记录 当前状态为

  • 完成: 该记录正常显示

  • 中止: 该记录为 灰色字体

  • 其它状态: 未完成的状态,该记录为 蓝色字体,右边显示一个邮件图标

如果当前用户有权限 创建送检工作流,上方显示一个 创建按钮, 否则不显示

本次练习需要使用 新接口文档 里面的 药品送检工作流 1 部分的接口

具体要求见视频讲解



实战 12 时间线控件开发

实现一个通用的时间线控件开发,为后续显示一个工作流具体信息 做准备

具体要求见视频讲解

实战 13 工作流详细信息查看

实现可以双击工作流列表中的一条记录,查看这个工作流的详细信息

具体要求见视频讲解

实战 14 工作流创建和执行动作

实现创建一个工作流的功能 和 执行一条未完成工作流的后续操作

具体要求见视频讲解

实战 15 通用的富文本编辑控件

实现一个通用的富文本编辑控件, 作为控件库里面的一个控件, 为后续 工作流中富文本字段编辑做准备

该控件可以在Qt QTextEdit 的基础上扩展, 编辑的富文本内容保存为 HTML格式

任务详细说明 见这里的视频


测试富文本控件,可以使用下面的HTML代码

test_text = '''
<p>from PySideQtGui import abc.py.ppp.ccc.ddd.fff </p>
<p><span style=" color:#ff0000;">import # 这个试试看</span> </p>        
<img src="https://doc.qt.io/qtforpython/_images/windows-pushbutton.png" /> 
<br />
<img src="https://doc.qt.io/qtforpython/_images/windows-pushbutton.png" /> 
<p><br /></p>
<img src="https://doc.qt.io/qtforpython/_images/windows-pushbutton.png" /> 
<br />
<img src="https://www.byhy.net/cdn2/imgs/gh/36462795_53060289-ec24a580-34f4-11e9-83e6-1f5ce2e0454d.png" />
<p><br /></p>
<p>所有 <span style=" color:#ff0000;">红色</span>  <span style=" color:#ff0000;">绿色</span>  <span style=" color:#ff0000;">蓝色</span>  都不是</p>

<p>其它文本 </p> 
'''

具体要求见视频讲解

实战 16 送检工作流 2

实现 送检工作流 2 功能。

该工作流和 送检工作流 1 几乎一模一样,除了有些 纯文本的 PlainTextEdit 替换为 富文本的 RichTextEdit


送检工作流2 提交操作时, 里面里面的富文本字段中的图片 需要先上传到服务端,

上传图片使用需要接口文档中的 上传图片接口 ,然后根据服务端返回的图片url地址,更新 富文本内容, 再提交数据。

具体要求见视频讲解