更新项目文档为完整的药品管理系统说明
重写README文件,将原来的简单项目概述更新为详细的药品管理系统文档, 包含技术栈介绍、系统架构图、数据库设计、功能模块说明、业务流程图和 快速开始指南等完整内容。
This commit is contained in:
407
readme.md
407
readme.md
@@ -1,27 +1,396 @@
|
|||||||
# 医药管理系统
|
# 药品管理系统 (MedicineManagerSystem)
|
||||||
|
|
||||||
## 一、概述
|
基于 **Vue 3 + Spring Boot** 的全栈药品进销存管理系统,支持采购入库、库存管理、销售/领用出库、效期预警、供应商管理及 RBAC 权限控制。
|
||||||
|
|
||||||
### (一)项目概述
|
---
|
||||||
|
|
||||||
#### 1.技术栈:
|
## 技术栈
|
||||||
|
|
||||||
| 类别 | 技术栈 | 版本 |
|
| 类别 | 技术 | 版本 |
|
||||||
| ---------- | ------------------------------ | ----------- |
|
|------|------|------|
|
||||||
| 前端 | Vue 3 + Vite | 3.5+ / 8.1+ |
|
| 前端框架 | Vue 3 (Composition API) | 3.5+ |
|
||||||
| UI 与路由 | Element Plus + Vue Router | 2.x / 4.x |
|
| 构建工具 | Vite | 8.x |
|
||||||
| 状态与请求 | Pinia + Axios | 2.x / 1.x |
|
| UI 组件库 | Element Plus | 2.x |
|
||||||
| 样式与图标 | Sass + @element-plus/icons-vue | 1.x / — |
|
| 路由 / 状态 | Vue Router 4 / Pinia 2 | 4.x / 2.x |
|
||||||
| 后端框架 | Spring Boot (含 Validation) | 4.1.0 |
|
| HTTP / 样式 | Axios 1.x / Sass | 1.x |
|
||||||
| 开发语言 | JDK | 21 |
|
| 后端框架 | Spring Boot (Web + Security + Validation) | 4.1.0 |
|
||||||
| 持久层 | MyBatis-Plus + MySQL | 3.5+ / 8.0+ |
|
| JDK | Java 21 | LTS |
|
||||||
| 安全与认证 | Spring Security + JWT (jjwt) | 6.x / 0.12+ |
|
| ORM | MyBatis-Plus | 3.5.11 |
|
||||||
| 工具库 | Hutool | 5.x |
|
| 安全认证 | Spring Security + JWT (jjwt 0.13.0) | — |
|
||||||
| 项目构建 | Maven | 3.9+ |
|
| 数据库 | MySQL 8.0 (JDBC + HikariCP) | — |
|
||||||
|
| 工具库 | Hutool 5.8 / Lombok | — |
|
||||||
|
| 构建 | Maven 3.9+ | — |
|
||||||
|
|
||||||
## 二、前端
|
---
|
||||||
|
|
||||||
## 三、后端
|
## 系统架构
|
||||||
|
|
||||||
## 四、快速开始
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
Client["🖥️ 浏览器<br/>Vue 3 + Element Plus SPA"]
|
||||||
|
|
||||||
|
subgraph Backend["☕ Spring Boot 4.1.0"]
|
||||||
|
Security["🔐 Spring Security + JWT Filter<br/>无状态认证"]
|
||||||
|
Controller["📡 Controller Layer<br/>REST API · 参数校验 · 统一响应格式 Result-T"]
|
||||||
|
Service["⚙️ Service Layer<br/>业务逻辑 · 事务管理"]
|
||||||
|
Mapper["🗄️ MyBatis-Plus Mapper<br/>分页 · 逻辑删除 · 自动填充"]
|
||||||
|
end
|
||||||
|
|
||||||
|
DB["🐬 MySQL 8.0<br/>InnoDB · utf8mb4"]
|
||||||
|
|
||||||
|
Client -->|"HTTPS + JWT Token"| Security
|
||||||
|
Security --> Controller
|
||||||
|
Controller --> Service
|
||||||
|
Service --> Mapper
|
||||||
|
Mapper -->|"JDBC"| DB
|
||||||
|
```
|
||||||
|
|
||||||
|
### 请求响应流程
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant F as 🖥️ Vue 前端
|
||||||
|
participant A as Axios 拦截器
|
||||||
|
participant SF as JWT Filter
|
||||||
|
participant C as Controller
|
||||||
|
participant SV as Service
|
||||||
|
participant M as Mapper
|
||||||
|
participant DB as MySQL
|
||||||
|
|
||||||
|
F->>A: 发起 API 请求
|
||||||
|
A->>A: 自动注入 JWT Token<br/>到 Authorization Header
|
||||||
|
A->>SF: HTTP Request (Bearer Token)
|
||||||
|
|
||||||
|
alt Token 有效
|
||||||
|
SF->>C: 放行请求
|
||||||
|
C->>C: @Valid 参数校验
|
||||||
|
C->>SV: 调用业务方法
|
||||||
|
SV->>M: 调用数据访问
|
||||||
|
M->>DB: 执行 SQL
|
||||||
|
DB-->>M: 返回结果集
|
||||||
|
M-->>SV: 返回实体对象
|
||||||
|
SV-->>C: 返回处理结果
|
||||||
|
C-->>A: "Result<T> JSON"
|
||||||
|
A->>A: 响应拦截器处理<br/>(统一错误提示 / Token 刷新)
|
||||||
|
A-->>F: 展示数据
|
||||||
|
else Token 过期或无效
|
||||||
|
SF-->>A: 401 Unauthorized
|
||||||
|
A->>A: 尝试 RefreshToken
|
||||||
|
alt 刷新失败
|
||||||
|
A->>F: 跳转登录页
|
||||||
|
end
|
||||||
|
else 权限不足
|
||||||
|
SF-->>A: 403 Forbidden
|
||||||
|
A-->>F: 提示"权限不足"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### RBAC 权限模型
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
U["👤 User"] -->|N:M| UR["user_role"]
|
||||||
|
UR -->|N:M| R["🔑 Role"]
|
||||||
|
R -->|N:M| RM["role_menu"]
|
||||||
|
RM -->|N:M| M["📋 Menu"]
|
||||||
|
|
||||||
|
M --> D["📁 目录 type=1<br/>侧边栏分组"]
|
||||||
|
M --> P["📄 菜单 type=2<br/>页面路由"]
|
||||||
|
M --> B["🔘 按钮 type=3<br/>permission_code"]
|
||||||
|
|
||||||
|
subgraph 三层权限
|
||||||
|
L1["路由守卫"] -.-> P
|
||||||
|
L2["v-permission 指令"] -.-> B
|
||||||
|
L3["@PreAuthorize"] -.-> B
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 认证流程
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant U as 👤 用户
|
||||||
|
participant F as 🖥️ Vue 前端
|
||||||
|
participant B as ☕ Spring Boot
|
||||||
|
participant DB as 🐬 MySQL
|
||||||
|
|
||||||
|
rect rgb(240, 248, 255)
|
||||||
|
Note over U,DB: === 登录阶段 ===
|
||||||
|
U->>F: 输入用户名 + 密码
|
||||||
|
F->>B: POST /api/auth/login<br/>{username, password}
|
||||||
|
B->>DB: 查询用户信息
|
||||||
|
DB-->>B: 返回用户实体
|
||||||
|
B->>B: BCrypt.matches(password, hash)
|
||||||
|
alt 验证成功
|
||||||
|
B->>B: 生成 AccessToken (有效期 24h)
|
||||||
|
B->>B: 生成 RefreshToken (有效期 7天)
|
||||||
|
B-->>F: { token, refreshToken, userInfo, menus }
|
||||||
|
F->>F: localStorage.setItem('token', ...)
|
||||||
|
F-->>U: 跳转首页,渲染菜单
|
||||||
|
else 验证失败
|
||||||
|
B-->>F: 401 "用户名或密码错误"
|
||||||
|
F-->>U: ElMessage.error 提示
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
rect rgb(255, 248, 240)
|
||||||
|
Note over U,DB: === 正常请求阶段 ===
|
||||||
|
F->>B: GET /api/medicines<br/>Authorization: Bearer <AccessToken>
|
||||||
|
B->>B: JwtFilter 解析 Token<br/>提取 userId + permissions
|
||||||
|
B->>B: SecurityContextHolder 设置认证信息
|
||||||
|
B-->>F: Result<Page<Medicine> >
|
||||||
|
end
|
||||||
|
|
||||||
|
rect rgb(255, 240, 240)
|
||||||
|
Note over U,DB: === Token 过期刷新 ===
|
||||||
|
F->>B: POST /api/auth/refresh<br/>{ refreshToken }
|
||||||
|
B->>B: 校验 RefreshToken 有效性
|
||||||
|
alt RefreshToken 有效
|
||||||
|
B->>B: 签发新 AccessToken
|
||||||
|
B-->>F: { token: "newToken" }
|
||||||
|
F->>F: 更新 localStorage
|
||||||
|
else RefreshToken 过期
|
||||||
|
B-->>F: 401
|
||||||
|
F->>F: 清空 Token,跳转登录页
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 数据库设计
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
medicine_category ||--o{ medicine : "分类"
|
||||||
|
medicine ||--o{ stock : "库存批次"
|
||||||
|
medicine ||--o{ stock_in_detail : ""
|
||||||
|
medicine ||--o{ stock_out_detail : ""
|
||||||
|
warehouse ||--o{ stock : ""
|
||||||
|
warehouse ||--o{ stock_in_record : ""
|
||||||
|
warehouse ||--o{ stock_out_record : ""
|
||||||
|
supplier ||--o{ stock_in_record : ""
|
||||||
|
customer ||--o{ stock_out_record : ""
|
||||||
|
stock_in_record ||--o{ stock_in_detail : ""
|
||||||
|
stock_out_record ||--o{ stock_out_detail : ""
|
||||||
|
user ||--o{ stock_in_record : "操作人"
|
||||||
|
user ||--o{ stock_out_record : "操作人"
|
||||||
|
user ||--o{ user_role : ""
|
||||||
|
role ||--o{ user_role : ""
|
||||||
|
role ||--o{ role_menu : ""
|
||||||
|
menu ||--o{ role_menu : ""
|
||||||
|
menu ||--o{ menu : "父子菜单"
|
||||||
|
|
||||||
|
medicine_category { bigint id PK "分类ID" varchar name "名称" varchar code UK "编码" }
|
||||||
|
medicine { bigint id PK "药品ID" varchar name "通用名称" varchar specification "规格" varchar manufacturer "厂家" varchar approval_number UK "批准文号" decimal retail_price "零售价" decimal wholesale_price "批发价" int shelf_life "有效期(月)" int warning_stock "预警阈值" }
|
||||||
|
supplier { bigint id PK "供应商ID" varchar name "名称" varchar contact_person "联系人" varchar phone "电话" tinyint status "状态" }
|
||||||
|
customer { bigint id PK "客户ID" varchar name "名称" varchar phone "电话" varchar type "类型" }
|
||||||
|
warehouse { bigint id PK "仓库ID" varchar name "名称" varchar code UK "编码" }
|
||||||
|
stock { bigint id PK "库存ID" bigint medicine_id FK "药品" bigint warehouse_id FK "仓库" varchar batch_no "批号" int quantity "数量" decimal cost_price "成本价" date expiry_date "有效期至" }
|
||||||
|
stock_in_record { bigint id PK "入库单ID" varchar record_no UK "单号" bigint supplier_id FK "供应商" decimal total_amount "总金额" date in_date "入库日期" tinyint status "0待审1已入库2已取消" }
|
||||||
|
stock_in_detail { bigint id PK bigint record_id FK bigint medicine_id FK varchar batch_no int quantity decimal cost_price "进价" decimal total_price "小计" date expiry_date }
|
||||||
|
stock_out_record { bigint id PK "出库单ID" varchar record_no UK "单号" bigint customer_id FK "客户" decimal total_amount "总金额" date out_date "出库日期" tinyint out_type "1销售2领用3报损4退货" tinyint status "0待审1已出库2已取消" }
|
||||||
|
stock_out_detail { bigint id PK bigint record_id FK bigint medicine_id FK varchar batch_no int quantity decimal unit_price "单价" decimal total_price "小计" }
|
||||||
|
user { bigint id PK "用户ID" varchar username UK "用户名" varchar password "BCrypt" varchar real_name "姓名" varchar phone "手机" tinyint status "状态" }
|
||||||
|
role { bigint id PK "角色ID" varchar name "名称" varchar code UK "编码" }
|
||||||
|
user_role { bigint id PK bigint user_id FK bigint role_id FK }
|
||||||
|
menu { bigint id PK "菜单ID" bigint parent_id "父ID" varchar name "名称" tinyint type "1目录2菜单3按钮" varchar path "路由" varchar icon "图标" varchar permission_code UK "权限编码" }
|
||||||
|
role_menu { bigint id PK bigint role_id FK bigint menu_id FK }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 功能模块
|
||||||
|
|
||||||
|
| 模块 | 功能 |
|
||||||
|
|------|------|
|
||||||
|
| 🔐 认证 | 登录 / 注册 / JWT 刷新 / 退出 |
|
||||||
|
| 📊 仪表盘 | 4 项统计卡片 · **效期预警**(<30天红 · 30-90天橙) · 最近出入库 |
|
||||||
|
| 💊 药品管理 | CRUD · 分类树管理 · 按名称/批准文号/分类搜索 · 分页 |
|
||||||
|
| 📦 库存管理 | 批次跟踪 · 效期颜色标记 · 库存盘点 |
|
||||||
|
| 📥 入库管理 | 新建入库单(供应商+动态明细行) · **审核通过自动增加库存** · 驳回 |
|
||||||
|
| 📤 出库管理 | 新建出库单(客户+库存批次选择) · **审核通过 FIFO 扣减库存** · 驳回 |
|
||||||
|
| 🏢 供应商 | CRUD · 启用/停用开关 |
|
||||||
|
| 👥 客户 | CRUD · 类型(个人/医院/药店/诊所) |
|
||||||
|
| 👤 用户管理 | CRUD · 角色分配 |
|
||||||
|
| 🔑 角色管理 | CRUD · 权限树分配 |
|
||||||
|
| 📋 菜单管理 | 菜单树 CRUD · 三级(目录/菜单/按钮) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 核心业务流程
|
||||||
|
|
||||||
|
### 入库审核
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant F as 前端
|
||||||
|
participant B as 后端
|
||||||
|
participant DB as MySQL
|
||||||
|
|
||||||
|
Note over F,DB: 1. 创建入库单
|
||||||
|
F->>B: POST /api/stock-in<br/>{ supplierId, details: [...] }
|
||||||
|
B->>DB: INSERT stock_in_record (status=0 待审核)
|
||||||
|
B->>DB: INSERT stock_in_detail (明细)
|
||||||
|
B-->>F: 入库单已创建
|
||||||
|
|
||||||
|
Note over F,DB: 2. 审核通过
|
||||||
|
F->>B: PUT /api/stock-in/{id}/status<br/>{ status: 1 }
|
||||||
|
B->>DB: 查同药品+同批号库存
|
||||||
|
alt 库存已存在
|
||||||
|
B->>DB: UPDATE stock SET quantity += N
|
||||||
|
else 新批次
|
||||||
|
B->>DB: INSERT stock (新批次)
|
||||||
|
end
|
||||||
|
B->>DB: UPDATE status=1
|
||||||
|
B-->>F: 审核通过 · 库存已更新
|
||||||
|
```
|
||||||
|
|
||||||
|
### 出库审核
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant F as 前端
|
||||||
|
participant B as 后端
|
||||||
|
participant DB as MySQL
|
||||||
|
|
||||||
|
Note over F,DB: 1. 创建出库单
|
||||||
|
F->>B: POST /api/stock-out<br/>{ customerId, details: [...] }
|
||||||
|
B->>DB: INSERT stock_out_record (status=0 待审核)
|
||||||
|
|
||||||
|
Note over F,DB: 2. 审核通过
|
||||||
|
F->>B: PUT /api/stock-out/{id}/status<br/>{ status: 1 }
|
||||||
|
B->>DB: 查可用库存 (FIFO 按效期升序)
|
||||||
|
alt 库存充足
|
||||||
|
B->>DB: UPDATE stock SET quantity -= N
|
||||||
|
B->>DB: UPDATE status=1
|
||||||
|
B-->>F: 审核通过 · 库存已扣减
|
||||||
|
else 库存不足
|
||||||
|
B-->>F: 错误: 库存不足,需要 X,可用 Y
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 环境要求
|
||||||
|
|
||||||
|
- JDK 21+ · Node.js 18+ · MySQL 8.0+ · Maven 3.9+
|
||||||
|
|
||||||
|
### 1. 初始化数据库
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mysql -u root -p < backend/src/main/resources/database/init.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 配置后端环境变量
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cp backend/.env.example backend/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
在 `backend/.env` 中填写:
|
||||||
|
|
||||||
|
```properties
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_NAME=medicine_manager
|
||||||
|
DB_USERNAME=root
|
||||||
|
DB_PASSWORD=你的数据库密码
|
||||||
|
JWT_SECRET=你的256位Base64密钥
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 启动后端
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
./mvnw spring-boot:run -DskipTests
|
||||||
|
```
|
||||||
|
|
||||||
|
> 后端运行在 `http://localhost:8080`,启动时会自动加载 `.env`
|
||||||
|
|
||||||
|
### 4. 启动前端
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
> 前端运行在 `http://localhost:5173`,API 请求自动代理到后端
|
||||||
|
|
||||||
|
### 5. 登录
|
||||||
|
|
||||||
|
| 用户名 | 密码 | 角色 | 权限范围 |
|
||||||
|
|--------|------|------|----------|
|
||||||
|
| `admin` | `admin123` | 超级管理员 | 全部 |
|
||||||
|
| `warehouse01` | `admin123` | 仓库管理员 | 出入库 + 库存 + 供应商客户查看 |
|
||||||
|
| `staff01` | `admin123` | 普通员工 | 仪表盘 + 只读查看 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
MedicineManagerSystem/
|
||||||
|
├── README.md
|
||||||
|
├── .env.example
|
||||||
|
├── projectDesigning.md # 详细架构设计文档
|
||||||
|
│
|
||||||
|
├── frontend/ # Vue 3 SPA
|
||||||
|
│ └── src/
|
||||||
|
│ ├── api/ (11) # API 模块
|
||||||
|
│ ├── directives/ (1) # v-permission
|
||||||
|
│ ├── layout/ (1) # MainLayout
|
||||||
|
│ ├── router/ (1) # 路由 + 动态菜单
|
||||||
|
│ ├── stores/ (2) # Pinia
|
||||||
|
│ ├── styles/ (1) # SCSS
|
||||||
|
│ ├── utils/ (1) # Axios 封装
|
||||||
|
│ └── views/ (16) # 页面组件
|
||||||
|
│
|
||||||
|
└── backend/ # Spring Boot
|
||||||
|
└── src/main/
|
||||||
|
├── java/com/kronecker/backend/
|
||||||
|
│ ├── common/ (4) # Result · 异常
|
||||||
|
│ ├── config/ (3) # Security · MP · CORS
|
||||||
|
│ ├── controller/ (12) # REST API
|
||||||
|
│ ├── dto/ (4) # 请求对象
|
||||||
|
│ ├── entity/ (15) # 数据库实体
|
||||||
|
│ ├── mapper/ (15) # MP Mapper
|
||||||
|
│ ├── security/ (3) # JWT
|
||||||
|
│ └── service/ (23) # 业务逻辑
|
||||||
|
└── resources/
|
||||||
|
├── application.yml
|
||||||
|
└── database/init.sql # 建表 + 种子数据
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 端点
|
||||||
|
|
||||||
|
| 模块 | 方法 | 路径 | 权限 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 认证 | `POST` | `/api/auth/login` | 公开 |
|
||||||
|
| 认证 | `POST` | `/api/auth/register` | 公开 |
|
||||||
|
| 认证 | `POST` | `/api/auth/refresh` | 公开 |
|
||||||
|
| 认证 | `GET` | `/api/auth/userinfo` | 登录 |
|
||||||
|
| 仪表盘 | `GET` | `/api/dashboard/statistics` | 登录 |
|
||||||
|
| 仪表盘 | `GET` | `/api/dashboard/expiry-warning` | 登录 |
|
||||||
|
| 药品 | `GET POST PUT DELETE` | `/api/medicines[/{id}]` | medicine:* |
|
||||||
|
| 分类 | `GET POST PUT DELETE` | `/api/categories[/{id}]` | category:* |
|
||||||
|
| 供应商 | `GET POST PUT DELETE` | `/api/suppliers[/{id}]` | supplier:* |
|
||||||
|
| 客户 | `GET POST PUT DELETE` | `/api/customers[/{id}]` | customer:* |
|
||||||
|
| 库存 | `GET` | `/api/stocks` | stock:list |
|
||||||
|
| 入库 | `GET POST` | `/api/stock-in` | stock-in:* |
|
||||||
|
| 入库 | `PUT` | `/api/stock-in/{id}/status` | stock-in:audit |
|
||||||
|
| 出库 | `GET POST` | `/api/stock-out` | stock-out:* |
|
||||||
|
| 出库 | `PUT` | `/api/stock-out/{id}/status` | stock-out:audit |
|
||||||
|
| 用户 | `GET POST PUT DELETE` | `/api/users[/{id}]` | user:* |
|
||||||
|
| 角色 | `GET POST PUT DELETE` | `/api/roles[/{id}]` | role:* |
|
||||||
|
| 菜单 | `GET POST PUT DELETE` | `/api/menus[/{id}]` | menu:* |
|
||||||
|
| 菜单 | `GET` | `/api/menus/tree` | 登录 |
|
||||||
|
|||||||
Reference in New Issue
Block a user