设备申请模块 — 产品需求文档(PRD)
设备申请模块 — 产品需求文档(PRD)
| 项 | 内容 |
|---|---|
| 文档版本 | v1.0 |
| 创建日期 | 2026-07-09 |
| 所属系统 | LabManagementSystem(实验室预约系统) |
| 关联模块 | 实验室预约(已实现)、用户管理、消息通知 |
| 文档状态 | 待评审 |
修订记录
| 版本 | 日期 | 作者 | 说明 |
|---|---|---|---|
| v1.0 | 2026-07-09 | — |
初稿:基于现有 UI 与数据模型差距分析 |
1. 背景与目标
1.1 背景
实验室预约系统已支持机房时段预约的全流程。设备申请页面(/equipment)已完成视觉与交互设计,师生可浏览设备并填写申请表单,但数据仅存于浏览器内存,管理员无法在后台审核,刷新页面后申请记录丢失。
后端已具备 devices(设备台账)与 device_bookings(借用申请)数据表及种子数据,具备快速打通的技术基础。
1.2 产品目标
师生可浏览真实设备库存并提交借用申请,数据持久化至数据库。
管理员可在后台查看、搜索、通过/拒绝设备申请。
师生可在「我的申请」查看审批状态、拒绝原因,并可撤回待审申请。
与实验室预约保持一致的交互范式与状态定义,降低学习成本。
1.3 成功指标(P0)
| 指标 | 目标 |
|---|---|
| 申请提交成功率 | 合法表单提交后 100% 落库 |
| 审核闭环 | 管理员操作后用户端列表状态实时一致(刷新后) |
| 数据一致性 | 同一设备待审+已通过数量不超过 available_quantity(P0 可先校验,P1 自动扣减) |
| 页面无 Mock 依赖 | 设备列表与我的申请均来自 API |
2. 用户角色
| 角色 | 说明 | 核心诉求 |
|---|---|---|
| 学生 | 主要申请人 | 快速找到可借设备、提交申请、跟踪进度 |
| 教师 | 可申请设备或作为指导教师 | 为学生项目借仪器/电脑 |
| 实验室管理员 | 审核与设备台账维护 | 控制出借、查看申请理由、拒绝不合规申请 |
| 超级管理员 | 系统配置 | 设备主数据维护(P1) |
3. 用户场景(User Stories)
3.1 学生 — 借用笔记本电脑
作为计算机专业学生,我需要在毕设期间借用一台高性能笔记本一周,以便在实验室外完成模型训练。
路径: 首页 → 设备申请 → 筛选「笔记本电脑」→ 选择可用设备 → 填写借用日期与事由 → 提交 → 在「我的申请」查看「待审批」。
3.2 教师 — 拒绝后重新申请
作为指导教师,我帮学生提交仪器借用申请,因事由描述不清被管理员拒绝,我需要看到拒绝原因并修改后重新提交。
路径: 我的申请 → 查看详情(拒绝原因)→ 重新选择设备 → 再次提交。
3.3 管理员 — 审核设备申请
作为实验室管理员,我需要在后台集中处理待审的设备申请,对合理申请点击通过,对资料不全的填写拒绝原因。
路径: 后台管理 → 设备借用 → 筛选待审 → 通过 / 拒绝 → 列表状态更新。
3.4 学生 — 撤回误操作申请
作为学生,我误提交了错误的借用日期,在管理员审批前希望撤回申请。
路径: 我的申请 → 待审批记录 → 撤回申请 → 状态变为「已取消」。
4. 业务流程
4.1 主流程
4.2 状态机
与实验室预约保持一致:
| status | 名称 |
用户端文案 | 可执行操作(用户) | 可执行操作(管理员) |
|---|---|---|---|---|
| 0 | 待审核 | 待审批 | 查看详情、撤回 | 通过、拒绝 |
| 1 | 已通过 | 已通过 | 查看详情 | 查看详情 |
| 2 | 已拒绝 | 已拒绝 | 查看详情(含拒绝原因) | 查看详情 |
| 3 | 已取消 | 已取消 | 查看详情 | 查看详情 |
状态流转规则:
0 → 1:管理员通过0 → 2:管理员拒绝(必填reject_reason)0 → 3:用户撤回1/2/3不可再变为其他状态(P0 不支持「重新审核」)
5. 功能需求
5.1 用户端 — 设备申请 Tab
页面: frontend/src/views/EquipmentView.vue(/equipment)
| 编号 | 功能 | 描述 | 优先级 |
|---|---|---|---|
| F-U-01 | 设备列表加载 |
进入页面调用 GET /api/devices,替换硬编码 deviceListByCategory |
P0 |
| F-U-02 | 类别筛选 |
侧栏类别与后端 category 映射:笔记本→0、手机→1、智能仪器→2、软件→3 |
P0 |
| F-U-03 | 关键词搜索 | 按设备名称、序列号、型号、描述模糊搜索(前端过滤或后端 q 参数) |
P0 |
| F-U-04 | 品牌筛选 | 基于 manufacturer 字段筛选;无厂商时归「其他」 |
P1 |
| F-U-05 | 可借状态展示 | available_quantity > 0 且 status==0 显示「选择」,否则「已借出」并禁用 |
P0 |
| F-U-06 | 分页 | 列表分页,默认每页 20 条,与现 UI 一致 | P0 |
| F-U-07 | 打开申请弹窗 | 点击「选择」打开 EquipmentApplyModal,带入设备信息 |
P0 |
| F-U-08 | 申请表单校验 | 必填:电话、负责教师、借用起止日期、事由;结束日期 ≥ 开始日期 | P0 |
| F-U-09 | 提交申请 | 调用 POST /api/device-bookings,成功后展示成功弹窗 |
P0 |
| F-U-10 | 提交失败提示 | 接口错误时 alert 或 Toast 展示后端 detail |
P0 |
5.2 用户端 — 我的申请 Tab
| 编号 | 功能 | 描述 | 优先级 |
|---|---|---|---|
| F-U-11 | 申请列表 | GET /api/device-bookings,替换 Mock 数据 |
P0 |
| F-U-12 | 状态筛选 | 全部 / 待审批 / 已通过 / 已拒绝 | P0 |
| F-U-13 | 日期筛选 |
按申请日期(created_at)区间过滤 |
P0 |
| F-U-14 | 查看详情 | 打开 EquipmentApplicationDetailModal,展示完整字段含拒绝原因 |
P0 |
| F-U-15 | 撤回申请 | 待审状态可撤回,调用 PATCH /api/device-bookings/{id}/cancel |
P0 |
| F-U-16 | 刷新 | 重新请求列表 API(不仅重置筛选) | P0 |
| F-U-17 | 按用户过滤 | 登录体系接入后,仅展示当前用户申请 | P1 |
5.3 管理端 — 设备借用
页面: 新建 AdminDeviceBookingsView.vue,替换 AdminSectionView 占位。
| 编号 | 功能 | 描述 | 优先级 |
|---|---|---|---|
| F-A-01 | 申请列表 | GET /api/device-bookings,表格展示 |
P0 |
| F-A-02 | 搜索 | 支持设备名、申请人、学号、事由关键字 q |
P0 |
| F-A-03 | 日期筛选 | 按借用开始日期或申请日期 | P0 |
| F-A-04 | 分页 | 与 AdminAppointmentsView 一致 |
P0 |
| F-A-05 | 通过 | PATCH .../review,action=approve,可填管理员备注 |
P0 |
| F-A-06 | 拒绝 | action=reject,必填拒绝原因 |
P0 |
| F-A-07 | 查看详情 | 弹窗展示申请完整信息 | P0 |
| F-A-08 | 状态标签 | 待审/已通过/已拒绝/已取消配色与预约模块一致 | P0 |
5.4 管理端 — 设备管理(P1)
页面: /admin/devices
| 编号 | 功能 | 描述 | 优先级 |
|---|---|---|---|
| F-A-09 | 设备 CRUD | 增删改查 devices 表记录 |
P1 |
| F-A-10 | 库存维护 | 修改 total_quantity、available_quantity |
P1 |
| F-A-11 | 状态维护 | 正常/维修中/报废 | P1 |
6. 数据需求
6.1 设备表 devices(已有,列表 API 只读)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int | 主键 |
| name | string | 设备名称 |
| serial_number | string | 序列号/编号(对应 UI code) |
| category | smallint | 0电脑 1手机 2实验器材 3软件 |
| manufacturer | string | 制造商/品牌 |
| model | string | 型号 |
| description | text | 描述(对应 UI spec 摘要) |
| location | string | 存放位置 |
| department | string | 所属部门 |
| total_quantity | int | 总数量 |
| available_quantity | int | 可借数量 |
| status | smallint | 0正常 1维修中 2报废 |
| manager | string | 设备管理员 |
| icon | string | 图标 URL |
6.2 设备申请表 device_bookings(需扩展)
已有字段: device_id, quantity, start_date, end_date, reason, special_requirement, user_id, user_name, openid, status, created_at
P0 建议新增字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| device_name | string | 冗余设备名 |
| serial_number | string | 冗余设备编号 |
| student_id | string | 学号/工号 |
| class_name | string | 班级 |
| major | string | 专业 |
| phone | string | 联系电话 |
| teacher_id | string | 指导教师 ID |
| teacher_name | string | 指导教师姓名 |
| admin_remark | text | 管理员备注(用户不可见) |
| reject_reason | text | 拒绝原因(用户可见) |
6.3 类别映射
| UI 类别 key | UI 文案 | DB category |
|---|---|---|
| laptop | 笔记本电脑 | 0 |
| phone | 手机 | 1 |
| instrument | 智能仪器 | 2 |
| software | 软件 | 3 |
7. 接口需求(REST API)
统一前缀:/api,响应格式与 appointments 模块保持一致。
7.1 设备
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/devices |
设备列表。Query:category、q、page、page_size。仅返回 status=0 且可用于展示的记录 |
| GET | /api/devices/{id} |
单设备详情 |
列表项响应示例:
1 | { |
status对外暴露为字符串:available(可借)/unavailable(不可借)/maintenance/retired,由devices.status+available_quantity计算。
7.2 设备申请
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/device-bookings |
申请列表。Query:q、status、date_from、date_to、page、page_size |
| POST | /api/device-bookings |
创建申请 |
| PATCH | /api/device-bookings/{id}/review |
管理员审核:`action=approve |
| PATCH | /api/device-bookings/{id}/cancel |
用户撤回(仅 status=0) |
POST 请求体:
1 | { |
POST 响应:
1 | { "ok": true, "id": 42 } |
7.3 业务校验(后端)
| 规则 | 说明 |
|---|---|
| V-01 | deviceId 必须存在且 status==0 |
| V-02 | available_quantity >= quantity(P0 仅校验,不扣减) |
| V-03 | borrowEnd >= borrowStart |
| V-04 | reason、phone 非空 |
| V-05 | 拒绝时 rejectReason 必填 |
| V-06 | 仅 status=0 可撤回 |
| V-07 | 同一用户同一设备同一日期区间不可有重复待审申请(P1) |
8. 交互与 UI 规范
8.1 保持与现有 UI 一致
视觉:沿用
EquipmentView已实现的 Rice 色系、字体层级(font-headline/font-body)弹窗:复用
EquipmentApplyModal、EquipmentApplicationDetailModal、BookAppointmentSuccessModal管理端:表格、筛选栏、审核按钮布局对齐
AdminAppointmentsView
8.2 需改造的 UI 点
| 位置 | 改造 |
|---|---|
EquipmentView |
删除 deviceListByCategory 硬编码;onEquipmentApplySubmit 改调 API |
EquipmentView |
refreshMyApplications 改为重新 GET 列表 |
EquipmentView |
「撤回申请」绑定 cancel API |
frontend/src/api/index.js |
新增设备相关 API 方法 |
admin/router |
device-bookings 路由指向新页面 |
8.3 空态与错误态
| 场景 | 展示 |
|---|---|
| 无设备 | 「暂无符合条件的设备,试试调整筛选或搜索关键词」 |
| 无申请记录 | 「暂无符合条件的申请记录」 |
| API 失败 | 列表区展示错误提示 + 重试按钮 |
| 提交成功 | 成功弹窗 → 可跳转「我的申请」 |
9. 权限与安全
| 项 | P0 | P1 |
|---|---|---|
| API 认证 | 无(与预约模块一致,全开放) | JWT / Session |
| 我的申请数据隔离 | 返回全量(与预约一致) | 按 user_id / openid 过滤 |
| 审核接口 | 无角色校验 | 仅管理员可调用 review |
| 输入消毒 | 字符串 trim、长度限制 | 防 XSS、SQL 注入(ORM 已规避) |
10. 非功能需求
| 类别 | 要求 |
|---|---|
| 性能 | 设备列表 < 500ms(100 条以内);申请提交 < 1s |
| 兼容性 | 与现有 Vue 3 前端、FastAPI 后端、MySQL 8.0 一致 |
| 可维护性 | API 路由文件 device_bookings.py、devices.py;复用 appointments 分页/审核模式 |
| 日志 | 审核、撤回操作记录到应用日志(P1 可写审计表) |
| 部署 | 无新增中间件;迁移通过 init_db 补列或 Alembic(若后续引入) |
11. 消息通知(P1 预留-暂时不用做)
审核完成后写入 messages 表:
| 字段 | 值 |
|---|---|
| type | device_booking |
| receiver_openid | 申请人 openid |
| appointment_id | 可复用字段存 device_booking.id 或新增 device_booking_id |
| title | 「设备申请已通过」/ 「设备申请未通过」 |
| content | 含设备名、借用区间、拒绝原因 |
12. 实施计划
12.1 里程碑
| 阶段 | 交付物 | 预估 |
|---|---|---|
| M1 后端 | 模型补列、devices + device-bookings API、种子数据补充 |
2–3 人日 |
| M2 用户端 | API 对接、去掉 Mock、撤回功能 | 2 人日 |
| M3 管理端 | AdminDeviceBookingsView 审核页 |
1–2 人日 |
| M4 联调验收 | 端到端测试、文档更新 | 1 人日 |
12.2 依赖项
| 依赖 | 说明 |
|---|---|
| MySQL 运行 | Docker 或本地实例 |
| 实验室预约模块 | 参照实现模式,无强耦合 |
| 用户认证 | 非 P0 阻塞项 |
13. 验收标准(P0)
| 编号 | 验收项 | 通过条件 |
|---|---|---|
| AC-01 | 设备列表 | /equipment 展示数据库中的设备,非硬编码 |
| AC-02 | 提交申请 | 填写合法表单提交后,device_bookings 表新增记录,status=0 |
| AC-03 | 我的申请 | 提交后「我的申请」可见该记录;刷新页面仍在 |
| AC-04 | 管理端列表 | /admin/device-bookings 可见待审记录 |
| AC-05 | 审核通过 | 管理员通过后,用户端状态变为「已通过」 |
| AC-06 | 审核拒绝 | 拒绝后用户端显示拒绝原因 |
| AC-07 | 撤回 | 待审状态可撤回,变为「已取消」 |
| AC-08 | 不可借设备 | available_quantity=0 或维修/报废设备不可提交 |
| AC-09 | 错误处理 | 非法设备 ID、缺少必填项返回 4xx 及明确错误信息 |
14. 风险与对策
| 风险 | 影响 | 对策 |
|---|---|---|
| 模型字段不足 | 前后端对不齐 | PRD 已定义扩展字段,开发前先迁移 |
| 无认证导致数据串读 | 用户看到他人申请 | P0 接受与预约一致;P1 同步上线认证 |
| 库存超借 | 多人同时申请最后一台 | P0 提交时校验数量;P1 事务扣减 |
| UI 类别与 DB 不一致 | 筛选错误 | 统一映射表,API 支持 category 参数 |
| 教师列表假数据 | 指导教师信息不可信 | P1 从 users 表 user_type=1 拉取 |
15. 附录
15.1 相关代码文件
| 模块 | 路径 |
|---|---|
| 用户端页面 | frontend/src/views/EquipmentView.vue |
| 申请弹窗 | frontend/src/components/EquipmentApplyModal.vue |
| 详情弹窗 | frontend/src/components/EquipmentApplicationDetailModal.vue |
| 前端 API | frontend/src/api/index.js |
| 设备模型 | backend/app/models/device.py |
| 申请模型 | backend/app/models/device_booking.py |
| 参照实现 | backend/app/api/routes/appointments.py |
| 管理端参照 | admin/src/views/AdminAppointmentsView.vue |
| 系统实现方案 | docs/implementation-plan.md |