3b1b70d57102f97c4afb4b1639c77dfbf1e9a71d
重写README文件,将原来的简单项目概述更新为详细的药品管理系统文档, 包含技术栈介绍、系统架构图、数据库设计、功能模块说明、业务流程图和 快速开始指南等完整内容。
药品管理系统 (MedicineManagerSystem)
基于 Vue 3 + Spring Boot 的全栈药品进销存管理系统,支持采购入库、库存管理、销售/领用出库、效期预警、供应商管理及 RBAC 权限控制。
技术栈
| 类别 | 技术 | 版本 |
|---|---|---|
| 前端框架 | Vue 3 (Composition API) | 3.5+ |
| 构建工具 | Vite | 8.x |
| UI 组件库 | Element Plus | 2.x |
| 路由 / 状态 | Vue Router 4 / Pinia 2 | 4.x / 2.x |
| HTTP / 样式 | Axios 1.x / Sass | 1.x |
| 后端框架 | Spring Boot (Web + Security + Validation) | 4.1.0 |
| JDK | Java 21 | LTS |
| ORM | MyBatis-Plus | 3.5.11 |
| 安全认证 | Spring Security + JWT (jjwt 0.13.0) | — |
| 数据库 | MySQL 8.0 (JDBC + HikariCP) | — |
| 工具库 | Hutool 5.8 / Lombok | — |
| 构建 | Maven 3.9+ | — |
系统架构
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
请求响应流程
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 权限模型
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
认证流程
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
数据库设计
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 · 三级(目录/菜单/按钮) |
核心业务流程
入库审核
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: 审核通过 · 库存已更新
出库审核
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. 初始化数据库
mysql -u root -p < backend/src/main/resources/database/init.sql
2. 配置后端环境变量
cp backend/.env.example backend/.env
在 backend/.env 中填写:
DB_HOST=localhost
DB_PORT=3306
DB_NAME=medicine_manager
DB_USERNAME=root
DB_PASSWORD=你的数据库密码
JWT_SECRET=你的256位Base64密钥
3. 启动后端
cd backend
./mvnw spring-boot:run -DskipTests
后端运行在
http://localhost:8080,启动时会自动加载.env
4. 启动前端
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 |
登录 |
Description
Languages
Java
47.1%
Vue
42.4%
JavaScript
8.3%
SCSS
1.4%
Dockerfile
0.6%
Other
0.2%