学期结束,“物品复活软件”也进行了迭代,谈谈我的心得体会

news/2025/1/7 16:12:11/文章来源:https://www.cnblogs.com/Jingyu-Dai/p/18654144

软件工程作业:“物品复活“软件开发之PSP数据的统计

大学生经常有些物品觉得扔掉可惜,不处理又觉得浪费自己的地方。请你编写一个物品“复活”软件

该程序允许添加物品的信息(物品名称,物品描述,联系人信息),删除物品的信息,显示物品列表,也允许查找物品的信息

加分功能需求:

1、物品有公共的信息(物品名称,物品说明,物品所在地址,联系人手机,邮箱)。为了便于管理和查询,物品可以分成不同的类别(例如食品、书籍、工具等),不同类别的物品可能有不同的属性(例如食品有保质期,数量;书籍有作者,出版社等)。

2、物品复活系统有两种类型的用户:管理员和普通用户。

管理员可以设置新的物品类型(定义物品类型的名称和各个属性),修改物品类型。
普通用户在添加物品时先选择物品类型,然后再填入物品信息。普通用户搜寻物品时,需要先选择类型,再输入关键字,关键字可以再用户名称和说明中进行匹配。
普通用户需要注册(填入基本信息,包括住址,联系方式等),管理员批准后才能成为正式用户。

3、为了便于使用上述功能,软件需要提供GUI。

计划(Planning)

Estimate
明确需求和其他相关因素,指明时间成本和依赖关系
需求:

  1. 实现物品类
  2. 实现物品管理器类,管理物品列表,实现添加物品、删除物品、显示物品、查找物品等功能
  3. 实现用户类
  4. 实现用户管理器类,管理用户列表,实现用户批准等功能

时间成本:
由于本人是初学者,计划用20个小时完成代码的编写和测试,10个小时完成GUI设计和测试,5个小时用于集成测试和微小修改。

依赖关系:

  1. 实现物品对象可以在添加物品时完成
  2. 删除物品需要查找物品的功能作为基础

开发(Development)

Analysis
分析需求
本次作业的需求比较简单,使用Python内置的数据结构就可以完成,不需要第三方库及其接口。只有GUI设计需要第三方库,本次设计选用了PyQt5库。

Design Spec
生成设计文档

物品复活软件设计文档

项目概述

物品复活软件是一个简单的管理工具,允许用户添加、删除、显示和查找物品。该软件使用 Python 和 PyQt5 库构建,提供一个友好的用户界面,以便用户进行交互。

功能需求

1. 添加物品

  • 用户可以输入物品的名称、描述和联系信息。
  • 如果物品已存在,则返回提示信息。

2. 删除物品

  • 用户可以通过物品名称删除已存在的物品。
  • 如果物品不存在,则返回提示信息。

3. 显示所有物品

  • 用户可以查看所有已添加的物品列表。

4. 查找物品

  • 用户可以通过名称中的子字符串搜索物品。
  • 如果没有找到匹配的物品,则返回提示信息。

技术栈

  • 编程语言: Python
  • : PyQt5(可选,用于数据可视化)
  • 数据存储: 使用内存中的列表和字典来存储物品信息

数据结构

本软件使用面向对象设计,类图如下:

Design Review
设计复审(和同事审核设计文档)
本项目为个人独立完成,所以省略此步骤。

Coding Standard
代码规范(为目前的开发制定合适的规范)

  1. 缩进和对齐:

    • 使用四个空格进行缩进,而不是使用制表符(Tab)。这有助于保持代码在不同编辑器中的一致性。
  2. 行长度:

    • 每行代码的长度应尽量不超过 79 个字符,以提高可读性。
  3. 空行:

    • 函数之间使用一个空行进行分隔,以便更清晰地分辨不同功能。
  4. 注释:

    • 使用注释来解释复杂的逻辑或提供额外的信息。注释应简洁明了,并保持与代码的相关性。
    • 重要的功能或复杂的部分应有文档字符串(docstring)来说明其用途和参数。
  5. 异常处理:

    • 在可能出现错误的地方使用异常处理,以便优雅地处理错误并提供反馈。
  6. 变量和函数命名:

    • 采用小写字母和下划线(snake_case)命名法。例:
      • add_item
      • delete_item
      • display_items
      • search_items
  7. 参数命名:

    • 参数名称应简洁且具有描述性。例如:
      • namedescriptioncontact,这些参数名称明确表达了其内容。
  8. 模块和文件命名:

    • 文件和模块名应使用驼峰命名法,以便于识别和使用。例如:
      • MainWindow.py

Design
具体设计

  • 普通用户

    • 参与的用例:
      • 登录:普通用户可以登录系统。
      • 注册:普通用户可以注册成为新用户。
      • 添加物品:普通用户可以添加物品。
      • 删除物品:普通用户可以删除自己的物品。
      • 查询物品:普通用户可以查询物品。
      • 退出登录:普通用户可以退出系统。
      • 展示所有物品:普通用户可以查看所有物品。
      • 注销账号:普通用户可以注销自己的账号。
  • 管理员用户

    • 参与的用例:
      • 登录:管理员用户也可以登录系统。
      • 注册成为管理员:管理员用户可以通过注册成为管理员来获得更高权限。
      • 添加物品:管理员用户可以添加物品。
      • 删除物品:管理员用户可以删除物品。
      • 查询物品:管理员用户可以查询物品。
      • 展示所有物品:管理员用户可以查看所有物品。
      • 添加或修改物品类型和属性:管理员用户可以添加或修改物品的类型及其属性。
      • 批准普通用户登录:管理员用户可以批准普通用户的登录请求。
      • 退出登录:管理员用户可以退出系统。
      • 注销账号:管理员用户可以注销自己的账号。

Coding
具体编码

GUI设计

1. 主页面的初始化

class MainWindow(QMainWindow):def __init__(self):super().__init__()self.item_manager = ItemManager()self.user_manager = UserManager()self.setWindowTitle("物品复活系统")self.setGeometry(100, 100, 1000, 800)# 创建一个 QStackedWidget 实现顺序模式self.stacked_widget = QStackedWidget()self.setCentralWidget(self.stacked_widget)# 添加选项卡self.registration_tab = self.create_registration_tab()  # 用户注册self.stacked_widget.addWidget(self.registration_tab)self.login_tab = self.create_login_tab()  # 用户登录self.stacked_widget.addWidget(self.login_tab)self.main_tab = self.create_main_tab()  # 主界面self.stacked_widget.addWidget(self.main_tab)# 初始显示用户注册界面self.stacked_widget.setCurrentWidget(self.registration_tab)

2. 创建注册界面

# 创建用户注册界面def create_registration_tab(self):tab = QWidget()layout = QVBoxLayout()self.username_input = QLineEdit()self.password_input = QLineEdit()self.address_input = QLineEdit()self.phone_input = QLineEdit()self.email_input = QLineEdit()self.register_button = QPushButton("注册用户")self.register_button.clicked.connect(self.register_user)self.go_to_login_button = QPushButton("去登录")self.go_to_login_button.clicked.connect(self.go_to_login)# 注册成为管理员按钮self.register_as_admin_button = QPushButton("注册成为管理员")self.register_as_admin_button.clicked.connect(self.register_as_admin)layout.addWidget(QLabel("用户名"))layout.addWidget(self.username_input)layout.addWidget(QLabel("密码"))layout.addWidget(self.password_input)layout.addWidget(QLabel("地址"))layout.addWidget(self.address_input)layout.addWidget(QLabel("电话"))layout.addWidget(self.phone_input)layout.addWidget(QLabel("邮箱"))layout.addWidget(self.email_input)layout.addWidget(self.register_button)layout.addWidget(self.register_as_admin_button)layout.addWidget(self.go_to_login_button)tab.setLayout(layout)return tab

3. 创建用户登录界面

def create_login_tab(self):tab = QWidget()layout = QVBoxLayout()self.login_username_input = QLineEdit()self.login_password_input = QLineEdit()self.login_button = QPushButton("登录")self.login_button.clicked.connect(self.login_user)self.go_to_register_button = QPushButton("去注册")self.go_to_register_button.clicked.connect(self.go_to_register)layout.addWidget(QLabel("用户名"))layout.addWidget(self.login_username_input)layout.addWidget(QLabel("密码"))layout.addWidget(self.login_password_input)layout.addWidget(self.login_button)layout.addWidget(self.go_to_register_button)tab.setLayout(layout)return tab

4. 创建主界面(包括物品管理、账户管理、管理员)

# 创建主界面def create_main_tab(self):tab = QWidget()layout = QVBoxLayout()self.tabs = QTabWidget()self.item_management_tab = self.create_item_management_tab()self.account_management_tab = self.create_account_management_tab()self.tabs.addTab(self.item_management_tab, "物品管理")self.tabs.addTab(self.account_management_tab, "账户管理")layout.addWidget(self.tabs)tab.setLayout(layout)return tab# 创建主界面中的物品管理界面选项卡def create_item_management_tab(self):tab = QWidget()layout = QVBoxLayout()self.item_name_input = QLineEdit()self.item_description_input = QLineEdit()self.item_address_input = QLineEdit()self.item_phone_input = QLineEdit()self.item_email_input = QLineEdit()self.item_type_combo = QComboBox()self.item_type_combo.addItems(self.item_manager.item_types)self.item_type_combo.currentIndexChanged.connect(self.update_extra_fields)# 初始选择为“食品”self.item_type_combo.setCurrentText("食品")self.extra_layout = QFormLayout()# 初始显示食品类型的所有属性attributes = self.item_manager.get_item_type_attributes("食品")for attr in attributes:input_field = QLineEdit()self.extra_layout.addRow(attr, input_field)# 添加物品按钮self.add_item_button = QPushButton("添加物品")self.add_item_button.clicked.connect(self.add_item)# 删除物品按钮self.delete_item_button = QPushButton("删除物品")self.delete_item_button.clicked.connect(self.delete_item)# 查询物品按钮self.search_item_button = QPushButton("查询物品")self.search_item_button.clicked.connect(self.search_item_dialog)# 展示全部物品按钮self.show_all_items_button = QPushButton("展示全部物品")self.show_all_items_button.clicked.connect(self.show_all_items)# 物品列表self.item_list_table = QTableWidget()self.item_list_table.setColumnCount(8)self.item_list_table.setHorizontalHeaderLabels(["物品名称", "描述", "地址", "联系人手机", "邮箱", "物品类型", "发布者姓名", "删除"])layout.addWidget(QLabel("物品名称"))layout.addWidget(self.item_name_input)layout.addWidget(QLabel("物品描述"))layout.addWidget(self.item_description_input)layout.addWidget(QLabel("物品地址"))layout.addWidget(self.item_address_input)layout.addWidget(QLabel("联系人电话"))layout.addWidget(self.item_phone_input)layout.addWidget(QLabel("联系人邮箱"))layout.addWidget(self.item_email_input)layout.addWidget(QLabel("物品类型"))layout.addWidget(self.item_type_combo)layout.addLayout(self.extra_layout)layout.addWidget(self.add_item_button)layout.addWidget(self.show_all_items_button)layout.addWidget(self.search_item_button)layout.addWidget(self.item_list_table)tab.setLayout(layout)return tab# 创建主界面中的账户管理界面选项卡def create_account_management_tab(self):tab = QWidget()layout = QVBoxLayout()self.logout_button = QPushButton("退出登录")self.logout_button.clicked.connect(self.logout)self.delete_account_button = QPushButton("注销账号")self.delete_account_button.clicked.connect(self.delete_account)self.admin_channel_button = QPushButton("管理员通道")self.admin_channel_button.clicked.connect(self.open_admin_channel)layout.addWidget(self.logout_button)layout.addWidget(self.delete_account_button)layout.addWidget(self.admin_channel_button)tab.setLayout(layout)return tab# 创建主界面中的管理员选项卡def create_admin_tab(self):# 隐藏“管理员通道”按钮,防止重复点击self.admin_channel_button.setVisible(False)tab = QWidget()layout = QVBoxLayout()self.show_all_users_button = QPushButton("展示所有用户")self.show_all_users_button.clicked.connect(self.update_user_list)# 物品类型管理按钮self.manage_item_type_button = QPushButton("管理物品类型")self.manage_item_type_button.clicked.connect(self.open_item_type_management)user_list_table = QTableWidget()user_list_table.setColumnCount(7)user_list_table.setHorizontalHeaderLabels(["用户名", "地址", "电话", "邮箱", "账户类型", "状态", "操作"])self.user_list_table = user_list_table  # 保持对user_list_table的引用layout.addWidget(self.show_all_users_button)layout.addWidget(self.manage_item_type_button)layout.addWidget(user_list_table)tab.setLayout(layout)return tab

具体功能设计

1. 注册(普通用户、管理员用户)

# 注册用户def register_user(self):username = self.username_input.text()password = self.password_input.text()address = self.address_input.text()phone = self.phone_input.text()email = self.email_input.text()# 检查输入是否为空if not username or not password or not address or not phone or not email:QMessageBox.warning(self, '错误', "所有字段不能为空,请完整填写信息!")return# 检查用户名是否已被占用if self.user_manager.is_username_taken(username):QMessageBox.warning(self, '错误', "该用户名已被占用,请选择其他用户名。")return# 创建并添加用户user = OrdinaryUser(username, password, address, phone, email)self.user_manager.add_user(user)QMessageBox.information(self, '注册成功', f"{username} 注册成功,等待管理员批准!")# 注册成为管理员    def register_as_admin(self):username = self.username_input.text()# 检查用户名是否已被占用if self.user_manager.is_username_taken(username):QMessageBox.warning(self, '错误', "该用户名已被占用,请选择其他用户名。")return# 弹出对话框输入邀请码dialog = QDialog(self)dialog.setWindowTitle("输入邀请码")layout = QVBoxLayout()self.invite_code_input = QLineEdit()submit_button = QPushButton("提交")cancel_button = QPushButton("取消")layout.addWidget(QLabel("请输入邀请码"))layout.addWidget(self.invite_code_input)layout.addWidget(submit_button)layout.addWidget(cancel_button)dialog.setLayout(layout)submit_button.clicked.connect(self.check_invite_code)cancel_button.clicked.connect(dialog.reject)dialog.exec_()# 检查邀请码是否正确def check_invite_code(self):invite_code = self.invite_code_input.text()if invite_code == "SJTUCS3331":username = self.username_input.text()password = self.password_input.text()address = self.address_input.text()phone = self.phone_input.text()email = self.email_input.text()user = AdministratorUser(username, password, address, phone, email)self.user_manager.add_user(user)QMessageBox.information(self, "注册成功", f"{username} 注册成功,您已成为管理员。")else:QMessageBox.warning(self, "邀请码错误", "邀请码错误!")

2. 对账户的一系列操作(登录、退出登录、注销账号等)

# 用户登录def login_user(self):username = self.login_username_input.text()password = self.login_password_input.text()# 检查用户名是否为空if not username:QMessageBox.warning(self, '错误', "用户名不能为空!")return# 检查用户是否已经登录if self.item_manager.current_user is not None and self.item_manager.current_user.username == username:QMessageBox.warning(self, '错误', f"用户 {username} 已经登录,请勿重复登录。")return# 用户登录验证user = self.user_manager.authenticate_user(username, password)if user:# 检查是否是普通用户且是否被管理员批准if isinstance(user, OrdinaryUser) and not user.is_approved:QMessageBox.warning(self, '登录失败', f"用户 {username} 尚未被管理员批准,无法登录。")returnself.item_manager.current_user = userQMessageBox.information(self, '登录成功', f"欢迎 {username}!")# 登录成功后,切换到主界面self.stacked_widget.setCurrentWidget(self.main_tab)else:QMessageBox.warning(self, '登录失败', "用户名或密码错误,请重试。")# 退出登录def logout(self):reply = QMessageBox.question(self, '确认退出',"你确定要退出登录吗?",QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.Yes:if hasattr(self, 'admin_tab') and self.admin_tab is not None:self.tabs.removeTab(2)self.admin_tab = None  # 清除管理员选项卡的引用self.item_manager.current_user = Noneself.stacked_widget.setCurrentWidget(self.login_tab)# 恢复“管理员通道”按钮的可见性self.admin_channel_button.setVisible(True)# 注销账号def delete_account(self):reply = QMessageBox.question(self, '确认注销',"你确定要注销账号吗?",QMessageBox.Yes | QMessageBox.No, QMessageBox.No)if reply == QMessageBox.Yes:if hasattr(self, 'admin_tab') and self.admin_tab is not None:self.tabs.removeTab(2)self.admin_tab = None  # 清除管理员选项卡的引用self.user_manager.delete_user(self.item_manager.current_user.username)self.stacked_widget.setCurrentWidget(self.registration_tab)self.item_manager.current_user = None# 恢复“管理员通道”按钮的可见性self.admin_channel_button.setVisible(True)

3. 添加物品

# 添加物品到物品列表def add_item(self):# 获取用户输入的物品信息item_name = self.item_name_input.text()item_description = self.item_description_input.text()item_address = self.item_address_input.text()item_phone = self.item_phone_input.text()item_email = self.item_email_input.text()item_type = self.item_type_combo.currentText()# 检查是否有空字段if not item_name or not item_description or not item_address or not item_phone or not item_email:QMessageBox.warning(self, '错误', "所有字段不能为空,请完整填写物品信息!")return# 根据物品类型创建物品属性字典item_attributes = {}attributes = self.item_manager.get_item_type_attributes(item_type)for i, attr in enumerate(attributes):input_field = self.extra_layout.itemAt(i*2 + 1).widget()item_attributes[attr] = input_field.text()item = Item(item_name, item_description, item_address, item_phone, item_email, item_type, item_attributes)# 添加物品到物品管理器self.item_manager.add_item(item)# 展示全部物品self.show_all_items()# 清空输入框self.item_name_input.clear()self.item_description_input.clear()self.item_address_input.clear()self.item_phone_input.clear()self.item_email_input.clear()# 重置额外属性输入框self.update_extra_fields()
# 更新不同物品类型的额外字段def update_extra_fields(self):# 清除之前的额外字段index = 0while True:item = self.extra_layout.itemAt(index)if item is None:  # 如果找不到更多的项breakwidget = item.widget()if widget:widget.deleteLater()index += 1# 根据物品类型,显示不同的额外属性item_type = self.item_type_combo.currentText()attributes = self.item_manager.get_item_type_attributes(item_type)for attr in attributes:input_field = QLineEdit()self.extra_layout.addRow(attr, input_field)# 确保布局更新以反映更改self.extra_layout.update()  # 强制更新布局self.extra_layout.parent().update()  # 强制更新父布局# 展示给定的物品列表def show_items(self, items):self.item_list_table.setRowCount(len(items))  # 设置表格行数for row, item in enumerate(items):# 设置物品的各项信息self.item_list_table.setItem(row, 0, QTableWidgetItem(item.name))self.item_list_table.setItem(row, 1, QTableWidgetItem(item.description))self.item_list_table.setItem(row, 2, QTableWidgetItem(item.address))self.item_list_table.setItem(row, 3, QTableWidgetItem(item.phone))self.item_list_table.setItem(row, 4, QTableWidgetItem(item.email))self.item_list_table.setItem(row, 5, QTableWidgetItem(item.item_type))self.item_list_table.setItem(row, 6, QTableWidgetItem(self.item_manager.current_user.username))# 添加“删除”按钮delete_button = QPushButton("删除")delete_button.clicked.connect(lambda checked, row=row: self.delete_item(row))self.item_list_table.setCellWidget(row, 7, delete_button)

4. 删除物品

# 删除某一件物品    def delete_item(self, selected_row):if selected_row != -1:item_name = self.item_list_table.item(selected_row, 0).text()item_owner_name = self.item_list_table.item(selected_row, 6).text()if self.item_manager.current_user.username != item_owner_name and not self.item_manager.current_user.is_admin:QMessageBox.warning(self, "警告", "普通用户不能删除其他人发布的物品。")elif self.item_manager.current_user.username != item_owner_name and self.item_manager.current_user.is_admin:self.item_manager.delete_item(item_name)  # 删除物品self.show_all_items()  # 更新物品列表QMessageBox.information(self, "成功删除", "管理员用户可以删除其他人发布的物品。")else:self.item_manager.delete_item(item_name)  # 删除物品self.show_all_items()  # 更新物品列表QMessageBox.information(self, "成功删除", "该物品已成功删除。")else:QMessageBox.warning(self, "警告", "请选择要删除的物品!")

5. 查询物品(弹出一个对话框)

# 查询物品对话框def search_item_dialog(self):dialog = QDialog(self)dialog.setWindowTitle("查询物品")layout = QVBoxLayout()# 物品类型选择框item_type_combo = QComboBox()item_type_combo.addItems(self.item_manager.item_types)# 查询字段输入框query_input = QLineEdit()submit_button = QPushButton("查询")cancel_button = QPushButton("取消")layout.addWidget(QLabel("选择物品类型"))layout.addWidget(item_type_combo)layout.addWidget(QLabel("输入查询字段"))layout.addWidget(query_input)layout.addWidget(submit_button)layout.addWidget(cancel_button)dialog.setLayout(layout)submit_button.clicked.connect(lambda: self.search_item(item_type_combo.currentText(), query_input.text(), dialog))cancel_button.clicked.connect(dialog.reject)dialog.exec_()# 执行查询物品def search_item(self, item_type, query_text, dialog):if not query_text:QMessageBox.warning(self, "警告", "请输入查询关键字!")return# 进行查询filtered_items = self.item_manager.search_item(item_type, query_text)if filtered_items:self.show_items(filtered_items)else:QMessageBox.information(self, "无结果", "没有找到匹配的物品。")dialog.accept()

6. 展示全部物品

# 展示全部物品    def show_all_items(self):all_items = self.item_manager.get_all_items()self.show_items(all_items)

7. 管理员批准普通用户登录(先进入管理员通道,在用户列表上操作)

# 管理员通道def open_admin_channel(self):if self.item_manager.current_user and self.item_manager.current_user.is_admin:self.admin_tab = self.create_admin_tab()self.tabs.addTab(self.admin_tab, "管理员")else:QMessageBox.warning(self, "权限不足", "您不是管理员,无法访问管理员通道。")# 更新用户列表def update_user_list(self):# 更新用户列表,展示所有用户user_list_table = self.user_list_tableuser_list_table.setRowCount(0)  # 清空当前表格内容for user in self.user_manager.get_all_users():row = user_list_table.rowCount()user_list_table.insertRow(row)user_list_table.setItem(row, 0, QTableWidgetItem(user.username))user_list_table.setItem(row, 1, QTableWidgetItem(user.address))user_list_table.setItem(row, 2, QTableWidgetItem(user.phone))user_list_table.setItem(row, 3, QTableWidgetItem(user.email))user_list_table.setItem(row, 4, QTableWidgetItem("普通用户" if not user.is_admin else "管理员"))user_list_table.setItem(row, 5, QTableWidgetItem("待批准" if isinstance(user, OrdinaryUser) and not user.is_approved else "已批准"))if isinstance(user, OrdinaryUser) and not user.is_approved:approve_button = QPushButton("批准")approve_button.clicked.connect(lambda _, u=user: self.approve_user(u))user_list_table.setCellWidget(row, 6, approve_button)# 批准普通用户登录def approve_user(self, user):if isinstance(user, OrdinaryUser):self.user_manager.approve_user(user.username)QMessageBox.information(self, '成功', f"{user.username} 已经批准成为正式用户。")# 在 user_list_table 中找到该用户的行,并更新“状态”列为“已批准”for row in range(self.user_list_table.rowCount()):if self.user_list_table.item(row, 0).text() == user.username:  # 查找用户名self.user_list_table.setItem(row, 5, QTableWidgetItem("已批准"))  # 更新“状态”列

8. 管理物品类型:添加新的类型或更新新的类型对话框

管理员新增的物品类型必须更新到ItemManager类的item_type属性,并且GUI的“物品管理界面”必须被更新。

# 管理物品类型:添加新的类型或更新新的类型对话框def open_item_type_management(self):dialog = QDialog(self)dialog.setWindowTitle("管理物品类型")layout = QVBoxLayout()# 输入框self.new_item_type_name = QLineEdit()self.new_item_type_name.setPlaceholderText("物品类型名称")self.new_item_type_attributes = QLineEdit()self.new_item_type_attributes.setPlaceholderText("属性列表,用逗号分隔")submit_button = QPushButton("提交")cancel_button = QPushButton("取消")layout.addWidget(QLabel("请输入物品类型名称"))layout.addWidget(self.new_item_type_name)layout.addWidget(QLabel("请输入属性列表"))layout.addWidget(self.new_item_type_attributes)layout.addWidget(submit_button)layout.addWidget(cancel_button)dialog.setLayout(layout)submit_button.clicked.connect(self.add_or_update_item_type)cancel_button.clicked.connect(dialog.reject)dialog.exec_()# 添加新的类型或更新新的类型def add_or_update_item_type(self):type_name = self.new_item_type_name.text()attributes = self.new_item_type_attributes.text().split(',')if not type_name or not attributes:QMessageBox.warning(self, "错误", "物品类型名称和属性不能为空!")returnif type_name in self.item_manager.item_types:self.item_manager.update_item_type(type_name, attributes)QMessageBox.information(self, "成功", f"物品类型 {type_name} 已更新!")else:self.item_manager.add_item_type(type_name, attributes)QMessageBox.information(self, "成功", f"物品类型 {type_name} 已添加!")# 更新物品类型选择框self.item_type_combo.addItem(type_name)# 重新更新额外属性输入框self.update_extra_fields()

完整代码已按照教师要求上传到GitHub。

Code Review
代码复审
找到了一些小BUG,修改了返回字符串的措辞。不再赘述。

Test
测试(包括自测,修改代码,提交修改)
测试上述功能,发现BUG后再修改代码。

记录用时(Record Time Spent)

比预计的时间稍长一些,实际用30个小时完成代码的编写和GUI设计和测试,2个小时用于集成测试和微小修改。

测试报告(Test Report)

物品复活软件测试报告

项目概述

物品复活软件是一款使用 Python 和 PyQt5 库开发的应用程序,允许用户添加、删除、显示和查找物品。该软件通过用户友好的图形界面简化了物品管理的过程。

测试报告:物品复活软件

1. 测试目的

本次测试的目的是验证物品复活软件在不同操作场景下的功能和稳定性。通过模拟用户与系统交互,确保各个功能模块的正常运行,并确保用户界面(GUI)操作符合预期的行为和要求。

2. 测试环境

  • 操作系统:Windows 10
  • 软件版本:v1.0
  • 开发框架:PyQt5
  • 数据库:无(使用内存数据存储)
  • 测试工具:手动测试
  • 目标硬件:普通PC

3. 测试用例

以下是主要的GUI操作测试用例,涵盖了用户的常见操作流程,包括登录、注册、物品添加、查询、删除等。

3.1 登录操作

  • 步骤
    1. 用户点击“登录”按钮。
    2. 在弹出的登录窗口中,输入用户名和密码,点击“登录”。
  • 输入
    • 用户名:testuser
    • 密码:password123
  • 预期输出
    • 用户成功登录,进入主界面,显示“欢迎,testuser”。

3.2 注册操作

  • 步骤
    1. 用户点击“注册”按钮。
    2. 在弹出的注册窗口中,输入用户名、密码、地址、电话等信息,点击“注册”。
  • 输入
    • 用户名:newuser
    • 密码:newpassword123
    • 地址:Shanghai
    • 电话:123456789
    • 邮箱:newuser@example.com
  • 预期输出
    • 用户注册成功,提示“注册成功”,用户自动登录并进入主界面。

3.3 添加物品操作

  • 步骤
    1. 用户点击“添加物品”按钮。
    2. 在弹出的物品添加窗口中,输入物品名称、描述、联系方式等信息,点击“提交”。
  • 输入
    • 物品名称:旧书
    • 描述:一本二手书
    • 联系电话:987654321
    • 邮箱:oldbook@example.com
  • 预期输出
    • 物品添加成功,弹出提示框“物品添加成功”。

3.4 删除物品操作

  • 步骤
    1. 用户点击“删除物品”按钮。
    2. 在弹出的删除物品窗口中,选择要删除的物品,点击“删除”按钮。
  • 输入
    • 选择删除物品:旧书
  • 预期输出
    • 物品成功删除,弹出提示框“物品删除成功”。

3.5 查询物品操作

  • 步骤
    1. 用户点击“查询物品”按钮。
    2. 在弹出的查询窗口中,输入查询条件并点击“查询”按钮。
  • 输入
    • 查询条件:
  • 预期输出
    • 显示所有匹配条件的物品列表,如“旧书”。

3.6 展示所有物品操作

  • 步骤
    1. 用户点击“展示所有物品”按钮。
  • 输入
  • 预期输出
    • 显示所有物品的列表,包括所有已添加的物品。

3.7 注销账号操作

  • 步骤
    1. 用户点击“注销账号”按钮。
    2. 在弹出的确认框中,点击“确认注销”。
  • 输入
  • 预期输出
    • 用户账号成功注销,返回到注册/登录界面。

3.8 退出登录操作

  • 步骤
    1. 用户点击“退出登录”按钮。
  • 输入
  • 预期输出
    • 用户成功退出登录,返回到登录界面。

3.9 注册成为管理员

  • 步骤
    1. 用户点击“申请成为管理员”按钮。
    2. 输入邀请码并提交申请。
  • 输入
    • 邀请码:admininvite
  • 预期输出
    • 显示“管理员申请已提交,等待审批”。

4. 测试用例表

用例编号 操作 输入 预期输出
TC01 登录操作 用户名: testuser, 密码: password123 成功登录,显示“欢迎,testuser”
TC02 注册操作 用户名: newuser, 密码: newpassword123,地址: Shanghai, 电话: 123456789, 邮箱: newuser@example.com 注册成功,显示“注册成功”,并自动登录进入主界面
TC03 添加物品操作 物品名称: 旧书, 描述: 一本二手书, 电话: 987654321, 邮箱: oldbook@example.com 物品添加成功,弹出提示框“物品添加成功”
TC04 删除物品操作 物品名称: 旧书 物品删除成功,弹出提示框“物品删除成功”
TC05 查询物品操作 查询条件: 显示所有匹配条件的物品列表,如“旧书”
TC06 展示所有物品操作 显示所有物品的列表
TC07 注销账号操作 用户成功注销账号,返回到注册/登录界面
TC08 退出登录操作 用户成功退出登录,返回到登录界面
TC09 注册成为管理员操作 邀请码: admininvite 显示“管理员申请已提交,等待审批”

结论

所有测试用例均通过,物品复活软件功能正常,符合预期。Gradio 用户界面友好,所有输入与输出均能准确响应。

计算工作量(Size Measurement)

一共有5个模块:

  • MainWindow.py: 620行代码;
  • Item.py: 18行代码;
  • ItemManager.py: 49行代码;
  • User.py: 27行代码;
  • UserManager.py: 41行代码;

事后总结(Postmortem)

由于我是第一次使用软件工程课上学到的软件开发生命过程来开发软件的,所以即使这是一个很小的项目,依然显得不太熟练。在最一开始设计设计文档的时候总是图快捷图简便,想尽快上手写代码,导致我的设计文档其实最一开始是不全的。以至于很多功能明明在一开始设计的时候就能想到,但是一定要到测试的时候才能发现问题。

今后在设计的过程应该一定要记住,磨刀不误砍柴工。设计文档写的完全,那么在今后的工作量就会减少,不用反复的修改bug。

提出过程改进计划(Process Improvement Plan)

2.6 尚未解决的问题

  1. 数据持久化
  • 问题 :当前系统未涉及数据持久化,所有的用户、物品和设置数据仅在内存中存储。即便系统的功能设计完备,一旦系统关闭,所有数据都会丢失。

  • 解决方案:为了将系统转化为一个可用的应用,必须加入数据库支持,确保数据可以持久化存储。常见的解决方案包括使用关系型数据库(如MySQL或SQLite)来存储用户信息、物品信息等,或者使用文件系统存储(例如JSON、XML或CSV格式)。

  1. 用户验证与安全
  • 问题 :虽然有登录功能,但未涉及用户的密码加密、安全认证、账户安全等问题。普通用户和管理员权限的验证较为简单,且没有防止恶意用户滥用系统的安全措施。

  • 解决方案:应考虑实现用户密码加密存储(如使用哈希算法如SHA-256),以及更复杂的身份验证机制(如OAuth、双重认证等)。此外,还应加入账户锁定机制、防止SQL注入等安全防护措施,确保系统的安全性。

  1. 界面与用户体验
  • 问题 :系统当前的界面设计可能较为简陋,尤其是对于复杂操作和数据展示(如物品列表、用户管理等),用户的体验可能不佳。

  • 解决方案:需要进一步优化UI设计,提高系统的易用性。例如,可以为每个功能添加更多的提示信息和反馈消息,使用户能够更加方便地理解操作。此外,还可以考虑使用现代UI框架(如Qt、React等)来提升系统界面的美观度和响应性。

  1. 权限管理
  • 问题 :目前系统的管理员权限管理过于简单,管理员可以执行多种操作,但没有明确的权限控制机制(如分级管理员、特定功能权限等)。

  • 解决方案:应进一步细化权限管理,允许为不同的用户分配不同的权限。例如,可以设置不同级别的管理员权限,或者将某些操作权限限制在特定的用户组或角色上。可以采用基于角色的访问控制(RBAC)来实现这一功能。

  1. 异常处理与日志记录
  • 问题 :系统的异常处理不够完善,错误和异常没有足够的捕捉和反馈机制。此外,系统的操作日志和错误日志也未记录,这可能在发生问题时导致调试困难。

  • 解决方案:需要加入完善的异常处理机制,确保系统在出现问题时能够友好地反馈给用户,并避免系统崩溃。同时,需要实现日志记录功能,记录用户的操作行为和系统运行的异常,以便开发人员进行调试和维护。

  1. 系统扩展性与维护
  • 问题 :目前系统的架构看起来相对简单,可能在未来随着功能扩展而变得难以维护和扩展。例如,物品类型和属性的管理可能在后续增加新特性时显得不够灵活。

  • 解决方案:可以通过模块化设计提高系统的扩展性,确保系统能够随着需求变化进行灵活扩展。通过采用设计模式(如工厂模式、策略模式等)来管理不同功能模块,提升代码的可维护性和可扩展性。

  1. 性能优化
  • 问题 :随着用户量和物品量的增加,系统可能面临性能瓶颈,特别是在展示所有物品或查询物品时,若数据量过大,响应时间可能变长。

  • 解决方案:需要考虑数据库优化(如索引、查询缓存等)和前端性能优化(如分页加载、大数据量处理等)。还可以通过引入异步处理和并行计算来提高系统的响应速度。

  1. 测试与质量保障
  • 问题 :当前的系统并未体现出测试框架,系统的质量保障机制较弱,可能导致在开发过程中出现错误未被及时发现。

  • 解决方案:应增加单元测试、集成测试和系统测试等自动化测试手段,确保系统在不同条件下的可靠性。同时,应加入持续集成(CI)和持续交付(CD)机制,保证代码的高质量和稳定性。

  1. 跨平台支持
  • 问题 :当前系统是否可以在不同的操作系统上运行未提及。若是使用特定平台的技术(如Windows的某些库),可能导致系统无法在其他平台(如Linux或MacOS)上运行。

  • 解决方案:如果要实现跨平台支持,应选择适合跨平台开发的框架(如Qt或Electron)进行开发,或通过容器化技术(如Docker)确保系统在不同平台上的一致性。

  1. API与第三方集成
  • 问题 :目前系统没有提到与外部服务或API的集成,例如与支付系统、电子邮件发送服务或其他系统的集成。

  • 解决方案:可以在系统中加入与第三方服务的集成功能(如通过API与外部支付平台或通知系统进行通信),这将使系统功能更加丰富,提升用户体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/864810.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《深入理解Mybatis原理》MyBatis的sqlSession执行流程

sqlSessionFactory 与 SqlSession 正如其名,Sqlsession对应着一次数据库会话。由于数据库会话不是永久的,因此Sqlsession的生命周期也不应该是永久的,相反,在你每次访问数据库时都需要创建它(当然并不是说在Sqlsession里只能执行一次sql,你可以执行多次,当一旦关闭了Sql…

将 EasySQLite 从 .NET 8 升级到 .NET 9

前言 EasySQLite是一个.NET 8操作SQLite入门到实战的详细教程,主要是对学校班级,学生信息进行管理维护。今天咱们的主要内容是将EasySQLite从.NET 8升级到.NET 9。GitHub开源地址:https://github.com/YSGStudyHards/EasySQLite选型、开发详细教程第一天 SQLite 简介 第二天 …

IDA Pro 9.0 (macOS, Linux, Windows) - 强大的反汇编程序、反编译器和多功能调试器

IDA Pro 9.0 (macOS, Linux, Windows) - 强大的反汇编程序、反编译器和多功能调试器IDA Pro 9.0 (macOS, Linux, Windows) - 强大的反汇编程序、反编译器和多功能调试器 A powerful disassembler, decompiler and a versatile debugger. In one tool. 请访问原文链接:https://…

使用DockerCompose部署服务

由于格式或图片解析问题,为了更好的阅读体验,可前往 阅读原文以前我们总是用命令管理每个容器的启动、停止等等,若有多个容器时可能还存在启动优先级的问题,那就要等到指定的容器启动后再去启动另一个容器,对于整体的应用服务管理极其不方便,简单的docker run命令更适合初…

读数据保护:工作负载的可恢复性27传统的数据保护方案

传统的数据保护方案1. 传统的数据保护方案 1.1. 备份行业有一个比较特殊的地方在于,10年或20年前设计的一些产品至今仍然有许多人在用 1.2. 在20年前,市面上的所有备份方案都是我们现在称之为传统备份产品的那种方案1.2.1. 必须自己动手把上百个UNIX系统里的数据各自备份到单…

DateTimeExtensions:一个轻量C#的开源DateTime扩展方法库

推荐一个专门为System.DateTime编写的扩展方法库。 01 项目简介 该项目主要是为System.DateTime和System.DateTimeOffset的编写的扩展方法,包括自然日期差值的文本表示(精确和人性化四舍五入)、多个时区的节假日和工作日计算。 核心扩展方法有: 1、DateTimeOffset和DateTim…

OpenVX的基本操作与支持树莓派联合开发

OpenVX支持树莓派联合开发 Khronos集团和树莓派共同致力于OpenVX的开源实现™11.3,通过了树莓派的一致性。通过一致性配置文件,开源实现了树莓派上OpenVX 1.3中指定的视觉、增强视觉和神经网络。 当Khronos标准在目标系统上可用时,应用程序开发人员可以始终自由使用这些标准…

推荐4本书《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》

4本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该…

技术架构典型技术选型

技术架构由多种技术组成,过程中可能涉及非常多的具体技术【图】技术架构核心技术 下面我们就技术架构中核心的流量调度、服务治理、监控体系、消息列队、微服务技术框架等进一步展开介绍。 一、流量调度 流量调度是技术架构中的核心技术,包括负载均衡、API网关、配置中心,以…

什么是单向认证与双向认证

什么是SSL双向认证,与单向认证证书有什么区别 SSL/TLS 证书是用于用户浏览器和网站服务器之间的数据传输加密,实现互联网传输安全保护,大多数情况下指的是服务器证书。服务器证书是用于向浏览器客户端验证服务器,这种是属于单向认证的SSL证书。但是,如果服务器需要对客户端…

「杂文」日常 11

基于手机相册的 2024 年度总结好像一年的开头是考试周来着非常卓越的年轻就是好啊,骑车跨越半个城区去吃包子当时还是狂热粥批 给春节活动攒了大量抽嫖同学的桌游寒假打了不少生稀盐酸看起来还挺有精神的()被 jbbai 带着入坑铲了 当时那个段位乱 D 凑大羁绊就爽吃了因为看到…

块存储、文件存储、对象存储的比较分析

【摘要】本文从从应用角度比较块存储、文件存储、对象存储,对三者的层次关系进行了清晰的解读,并比较了分布式存储在块存储、文件存储、对象存储的应用成效。 一、块存储、文件存储、对象存储三者的本质差别 1.1 块存储 典型设备:磁盘阵列,硬盘 块存储主要是将裸磁盘空间整…