仓库系统

仓库管理系统 — SpringBoot + Vue3前后端分离的项目:

一、项目介绍:
1.项目描述 √
为满足日益扩大的仓库管理需求,对仓库中商品进销存进行统一管理,而开发了此系统。系统主要包含:
RBAC:用户角色权限控制
1>用户管理(查询用户、添加用户、修改用户、删除用户、导出数据、批量删除、禁用/启用用户、重置密码、分配角色、更改权限)
2>角色管理(查询角色、添加角色、修改角色、删除角色、导出数据、禁用/启用角色、更改权限)
3>权限管理(查询权限、添加权限、修改权限、删除角色、禁用/启用权限)

4>商品管理(查询商品、添加商品、修改商品、商品审核等)
5>商品分类管理(商品分类的添加、商品分类的查询、商品分类的修改、商品分类的删除等)
6>采购管理(我的采购单、添加采购单、采购单的审核等)
7>入库管理(入库单、保存入库单、确认入库等)
8>出库管理(出库单、保存出库单、审核出库单等)
9>统计管理(各个仓库库存信息、仓库占有比、仓库存储走势、出入库信息统计、采购量占比、实时数据监测)
10>调货管理(调货单查询、确认调货)
11>仓库管理(查询仓库、添加仓库、修改仓库、删除仓库、导出数据)
12>供货商管理(供货商添加、供货商修改、供货商的查询等)
13>品牌管理(品牌添加、品牌修改、品牌的查询等)
14>产地管理(产地添加、产地修改、产地的查询等)
15>站内信管理(我的站内信、未读消息、站内信发送、站内信查询等)

2.技术选型 √
SpringBoot + MyBatis + MySql + Redis + Vue3 + Axios + Element-Plus + Echarts等

3.模块划分

4.个人职责 √

二、还原数据库:

三、搭建前端项目环境并启动项目:
1>安装node:
node的介绍:
node是一个基于Chrome V8引擎的JavaScript运行环境,让JavaScript运行在服务端的开发平台。

 npm包管理器的介绍:
 node安装之后一般都会默认安装npm包管理器;类似于linux的yum包管理器,可以给Vue项目下载相关插件、依赖;

 1)将安装压缩包解压就是安装

 2)配置path环境变量

 3)测试安装是否成功:
   node -v:查看node版本
   npm -v:查看npm包管理器的版本
   如果出现警告将node安装目录中的npm.cmd文件中的prefix -g改为prefix --location=global

2>给npm包管理器配置镜像加速器:
npm config set registry https://registry.npm.taobao.org
npm config get registry — 返回https://registry.npm.taobao.org,说明配置成功

3>使用npm包管理器下载安装yarn包管理器,同时配置镜像加速器:
yarn包管理器的介绍:
yarn包管理器跟npm包管理器的作用是一样的,区别就是npm包管理器是node自己的,而yarn包管理器属于第三方(facebook的);

 安装yarn包管理器:
 npm install -g yarn

 给yarn包管理器配置镜像加速器:
 yarn config set registry https://registry.npm.taobao.org 
 yarn config get registry  -- 返回https://registry.npm.taobao.org,说明配置成功

4>使用yarn包管理器为前端Vue项目下载安装所需插件:
在vue项目目录下执行命令:yarn

5>启动前端Vue项目:
在vue项目目录下执行命令:yarn dev

细节:
前端vue项目对后台项目的访问路径:
vue项目目录下的.env文件:
VITE_WAREHOUSE_CONTEXT_PATH=http://localhost:9999/warehouse
1)可以在.env文件中通过VITE_WAREHOUSE_CONTEXT_PATH变量修改设置前端Vue项目访问的后台项目的访问路径;
2)如果不做修改设置那么就要求我们的后台项目的项目路径必须是/warehouse,访问端口必须是9999;

四、搭建后台项目的环境:

1.创建个boot项目 — 划分包层次:

2.导入依赖

3.启动类配置

4.配置文件的配置

五、登录相关业务:

接口:
1.interface:表示对外暴露的规则,里面定义的全是抽象方法和全局常量。
2.api接口 url接口:请求的url地址。

1.生成验证码图片
http://localhost:9999/warehouse

/captcha/captchaImage — 服务器后台生成一张验证码图片,然后响应给前端,前端以img标签展示。

2.登录
http://localhost:3000/ — 是前端vue项目的访问地址

前端项目目录下的vite.config.js文件:
//服务端代理设置
proxy: {
//如果访问地址以”/api”开头,则自动代理到变量VITE_WAREHOUSE_CONTEXT_PATH所表示的
//服务端地址http://localhost:9999/warehouse
‘/api’: {
target: env.VITE_WAREHOUSE_CONTEXT_PATH,
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ”)
}
}

url接口/api是前端vue项目的接口,是个代理接口,代理的是后台项目的访问路径;

所以只要是前端vue项目发出的请求的地址是http://localhost:3000/api/xxx都是发给后台项目的,访问的后台向的具体的url接口;

http://localhost:3000/api/login — 访问的是后台项目的/login接口;
{
userCode:”admin”
userPwd:”123456″
verificationCode:”xax4″
}

3.登录限制

4.获取登录用户信息

5.加载权限菜单树

6.退出登录


token — 令牌 — 会话技术 — 登录成功之后,在一段时间之内不需要重复登录便可以直接访问系统资源;

常见的会话技术:
session:
弊端是只适合单体应用,不适用于分布式微服务集群的项目;

token — 令牌 — 一段字符串:
是适用于分布式微服务集群的项目的会话技术;

jwt token:

头部:
{
“alg”: “HS256”,
“typ”: “JWT”
}
载体 — 存放有用户信息:
{
“sub”: “1234567890”,
“name”: “John Doe”,
“admin”: true
}
签名:
HMACSHA256(
base64UrlEncode(header) + “.” +
base64UrlEncode(payload),
secret
)

base64UrlEncode(header) . base64UrlEncode(payload) . HMACSHA256(base64UrlEncode(header)+”.”+base64UrlEncode(payload),secret))

五、登录相关业务:

3.登录限制
必须登录成功之后才能访问系统资源。

使用过滤器实现:
在后台项目中配置一个过滤器,会拦截前端发出的所有请求,拦截之后判断用户是否已经登录
来决定是否允许访问系统资源(url接口);

回顾SpringBoot中配置原生Servlet中的过滤器:
1>自定义过滤器 — 定义一个Filter接口的实现类并重写doFilter()方法,doFilter()方法中
就是过滤器拦截到请求执行的内容;
2>向IOC容器中配置FilterRegistrationBean的bean对象,再将我们自定义的Servlet的过滤器
注册给FilterRegistrationBean的bean对象 — 注册过滤器

4.获取登录用户信息
/curr-user — 拿到前端归还的token,使用token工具类解析token的封装方法拿到从token中
解析出的用户信息并封装到的CurrentUser对象;

5.加载权限菜单树
/user/auth-list

加载用户权限菜单树的方式:
1.后台系统中是查询出用户权限下的所有菜单List,然后将用户所有菜单的List响应
给前端,前端框架就使用菜单树组件通过用户所有菜单的List中每个菜单的id和pid的关系
生成菜单树; — 菜单树是前端生成的;

2.后台系统中是查询出用户权限下的所有菜单List,然后将用户所有菜单的List转成
菜单树List,最后将菜单树List响应给前端,前端只需要做个循环迭代展示菜单树;
— 菜单树是在后端生成的; √

RBAC:用户角色权限控制
通过给用户分配不同的角色,再给角色分配不同的菜单权限,进而实现给用户分配不同的菜单权限;
实现RBAC至少设计到5张表:
1>用户表user_info:存放用户信息 userId userName…
2>角色表role:存放角色信息 roleId roleName
3>用户角色中间表user_role:存放用户角色关系的,体现了给用户分配的角色,而且用户和角色是多对多关系 userId roleId
4>菜单权限表auth_info:存放菜单信息 authId pid authName
5>角色菜单权限中间表role_auth:存放的是角色菜单关系,体现了给角色分配的菜单权限,而且角色和菜单是多对多关系 roleId menuId

6.退出登录
/logout — 从redis中删除当前登录的用户的token的键;


用户管理模块:

1.用户列表
/user/user-list?userCode=&userType=&userState=&pageSize=5&pageNum=1&totalNum=0

/user/user-list?userCode=a&userType=&userState=1&pageSize=5&pageNum=1&totalNum=0

pageNum是页码 pageSize是每页行数 — 分页查询

1)如果参数userCode userType userState没有值,是查询所有用户并分页
select * from user_info limit 起始行,每页行数;
select count(*) from user_info;

2)如果参数userCode userType userState有值,根据账号 用户状态 用户类型分页查询用户并分页
select * from user_info where user_code like ? and user_type = ? and user_state = 1 limit 起始行,每页行数;
select count(*) from user_info where user_code like ? and user_type = ? and user_state = 1

接参问题:
参数userCode userType userState使用User对象接收并封装;
参数pageNum页码 pageSize每页行数使用Page对象接收并封装;

响应数据问题:
给前端响应封装了所有分页信息的Page对象;

2.添加用户
/user/addUser
{
userCode:”zhangsan”
userName:”张三”
userPwd:”123456″
}

3.启用和禁用用户
/user/updateState
{
createBy:1
createTime:”2023-06-17 16:38:30″
getCode:”admin”
isDelete:”0″
updateBy:0
updateTime:null
userCode: “zhangsan”
userId:34 √
userName:”张三”
userPwd:”c431d451c81e75ffac75a640590ed0a1″
userState:”1″ √
userType:null
}

4.给用户分配角色
/role/role-list — 查询所有角色(展示角色出来)

/user/user-role-list/{userId} — 查询用户已分配的角色(如果是修改角色,需要回显用户已分配角色)

/user/assignRole — 给用户分配角色
{
userId:34
roleCheckList:[“调货”, “采购”, “入库”]
}

用户管理模块:

5.删除用户
/user/deleteUser/{userId} — 根据用户id删除用户

/user/deleteUserList — 根据用户ids批量删除用户
[34, 33]

update user_info set is_delete = 1 where user_id in(1,2,3…)

6.修改用户
/user/updateUser — 根据用户id修改用户昵称
{
userCode:”zhangsan”
userId:34
userName:”张三三”
}

7.重置密码
/user/updatePwd/{userId} — 将用户密码根据用户id还原为123456(加密)


角色管理模块:

1.角色列表 — 分页查询角色
/role/role-page-list?roleName=&roleCode=&roleState=&pageSize=5&pageNum=1&totalNum=0
查询所有角色并分页

role/role-page-list?roleName=a&roleCode=b&roleState=1&pageSize=5&pageNum=1&totalNum=0
根据角色名称、角色代码、角色状态查询角色并分页

2.添加角色
/role/role-add
{
roleCode:”pandian”
roleDesc:”盘点”
roleName:”盘点”
}

还需要考虑新增的角色是否已经存在 — 根据角色名称或者角色代码查询是否已有角色;

3.启用和禁用角色
/role/role-state-update
{
createBy:1
createTime:”2023-06-19 10:46:44″
getCode:”admin”
roleCode:”kuaiji”
roleDesc:”会计”
roleId:18 √
roleName:”会计”
roleState:”1″ √
}

4.给角色分配权限

/auth/auth-tree — 查询所有的权限菜单树

/role/role-auth?roleId=17 — 根据角色id查询角色已分配的所有权限

/role/auth-grant
{
roleId:”17″
authIds:[61, 62, 63, 64]
}

5.删除角色
/role/role-delete/{roleId} — 根据角色id删除角色

6.修改角色
/role/role-update
{
roleDesc:”盘点库存”
roleId:17
}


商品管理模块:
1.商品列表:
1>分页查询商品
/product/store-list — 查询所有仓库的 — 给搜索商品仓库下拉框组装数据的

 /product/brand-list -- 查询所有品牌 -- 给搜索商品皮牌下拉框组装数据的

 分页查询商品:
 /product/product-page-list?storeId=&productName=&brandName=&typeName=&supplyName=&placeName=&upDownState=&isOverDate=
 &pageSize=5&pageNum=1&totalNum=0
 查询所有商品并分页

 /product/product-page-list?storeId=1&productName=a&brandName=美的&typeName=b&supplyName=c&placeName=d&upDownState=1&isOverDate=0
 &pageSize=5&pageNum=1&totalNum=0
 根据仓库 商品名称 品牌 类型 供应商 产地 上下架状态 过期与否查询商品并分页 

 请求参数的处理:
 页码pageNum  每页行数pageSize -- Page对象接收并封装

 仓库id storeId、商品名称productName、品牌名称brandName、商品分类名称typeName、供应商名称supplyName、产地名placeName、 
 上下架状态upDownState、过期与否isOverDate -- Product对象接收并封装 -- 追加属性品牌名称brandName、商品分类名称typeName、
 供应商名称supplyName、产地名placeName、过期与否isOverDate

 商品列表展示的信息:
 仓库名称 -- Product对象还要追加属性 --- storeName
 单位 -- Product对象还要追加属性 --- unitName

商品管理模块:
1.商品列表:

2>添加商品
/product/category-tree — 查询所有分类树 — 给添加商品提供的

 /product/supply-list -- 查询所有供应商 -- 给添加商品提供的

 /product/place-list -- 查询所有产地 -- 给添加商品提供的

 /product/unit-list -- 查询所有单位 -- 给添加商品提供的


 /product/img-upload -- 上传图片
 file:上传的图片的字节数据

 /product/product-add -- 添加商品
 {
   brandId:2
   imgs:"midea_ph.jpg" --- /img/upload/midea_ph.jpg
   inPrice:"2000"
   introduce:"美的 变频  中央空调"
   memPrice:"2400"
   placeId:5
   productDate:"2023-06-20"
   productInvent:50
   productName:"中央空调"
   productNum:"midea_ph_001"
   salePrice:"2500"
   storeId:1
   suppDate:"2026-06-20"
   supplyId:5
   typeId:7
   typeName:"空调"
   unitId:6
 }

3>修改商品上下架状态
/product/state-change
{
productId:31
upDownState:1
}

4>删除商品
/product/product-delete/{productId} — 根据商品id删除单个商品

/product/product-list-delete --- 批量删除商品
[31, 25]

delete from product where product_id in(1,2,3...)

5>修改商品
/product/product-update
{
brandId:2
brandName:”美的”
createBy:1
createTime:”2023-06-20T10:07:02.000+00:00″
imgs:”/img/upload/midea_ph.jpg” “midea_zh.jpg” — 如果图片没有被修改则还是完整的访问地址,如果被修改了只有图片名称
inPrice:2000
introduce:”美的 变频 中央空调 透心凉”
isOverDate:null
memPrice:”2300″
placeId:5
placeName:”山东”
productDate:”2023-06-20″
productId:31
productInvent:50
productName:”空调”
productNum:”midea_ph_002″
salePrice:”2400″
storeId:1
storeName:”西安仓库”
suppDate:”2026-06-20″
supplyId:5
supplyName:”美的集团股份有限公司”
typeId:7
typeName:”空调”
unitId:6
unitName:”台”
upDownState:”0″
}

6>添加采购单
采购流程:
1)在商品列表针对具体的商品添加采购单 — 向采购单表buy_list表添加记录(状态是0未入库) — 预买商品
2)当商品采购到之后进行入库 — 在采购单列表做入库操作 — 向入库单表in_store表添加记录(状态是0未入库),同时修改采购单表buy_list表
由0改为1入库 — 准备入库
3)商品真正的入库 — 在入库单列表做确认入库操作 — 将入库单表in_store表的入库单状态由0改为1入库

   /purchase/purchase-add
   {
     brandId: 3
 brandName: "海尔"
 buyNum: "50" √   -- fact_buy_num实际采购数量,初值跟buyNum一致
 buyUser: "张三" √
 createBy: 1
 createTime: "2023-06-20T10:07:02.000+00:00"
 imgs: "/img/upload/midea_zh.jpg"
 inPrice: 2000
 introduce: "海尔 变频 中央空调 透心凉"
 isOverDate: null
 memPrice: 2300
 phone: "13666666666" √
 placeId: 5 √
 placeName: "山东"
 productDate: "2023-06-20"
 productId: 31  √
 productInvent: 50
 productName: "空调"
 productNum: "midea_ph_002"
 salePrice: 2400
 storeId: 1 √
 storeName: "西安仓库"
 suppDate: "2026-06-20"
 supplyId: 4  √
 supplyName: "海尔集团"
 typeId: 7
 typeName: "空调"
 unitId: 6
 unitName: "台"
 upDownState: "0"
 updateBy: 1
 updateTime: "2023-06-20T11:46:43.000+00:00"
   }

7>添加出库单
出库流程:
1)在商品列表针对具体的商品添加出库单 — 向出库单表out_store表添加出库单(状态是0未出库) — 准备出库
2)商品真正出库之后,在出库单列表做确认出库操作 — 将出库单表out_store表的出库状态由0改为1已出库

    /outstore/outstore-add
    {
     brandId: 3
 brandName: "海尔"
 createBy: 1
 createTime: "2023-06-20T10:07:02.000+00:00"
 imgs: "/img/upload/midea_zh.jpg"
 inPrice: 2000
 introduce: "海尔 变频 中央空调 透心凉"
 isOverDate: null
 memPrice: 2300
 outNum: "10" √ 
 placeId: 5
 placeName: "山东"
 productDate: "2023-06-20"
 productId: 31 √
 productInvent: 50
 productName: "空调"
 productNum: "midea_ph_002"
 salePrice: 2400 -- out_price字段出库价格给salePrice属性的值
 storeId: 1  √
 storeName: "西安仓库"
 suppDate: "2026-06-20"
 supplyId: 4
 supplyName: "海尔集团"
 typeId: 7
 typeName: "空调"
 unitId: 6
 unitName: "台"
 upDownState: "1"
 updateBy: 1
 updateTime: "2023-06-20T11:46:43.000+00:00"
    }

2.商品分类:
1>查询商品分类树
/productCategory/product-category-tree — 定义新的url接口,调用添加商品时编写的查询商品分类的业务即可;

2>添加商品分类
/productCategory/verify-type-code?typeCode=lingshi — 校验分类编码是否已存在的
select * from product_type where type_code = ? or type_name = ? — 根据分类编码或者分类名称查询商品分类,以此判断
分类编码或分类名称是否已存在

productCategory/type-add
{
  parentId:0
  typeCode: "xiaomi"
  typeDesc:"发烧  性价比高"
  typeName:"小米手机"
}

3>删除商品分类
/productCategory/type-delete/{typeId} — 根据分类id或父级分类id删除分类

4>修改商品分类
/productCategory/type-update
{
parentId:11
typeCode:”xiaomi”
typeDesc:”发烧 性价比高 拍照高清”
typeId:18
typeName:”红米手机”
}

采购单管理模块:

1.采购列表
/purchase/store-list — 查询所有仓库

/purchase/purchase-page-list?storeId=1&startTime=&endTime=&productName=&buyUser=&isIn=&pageSize=5&pageNum=1&totalNum=0
查询所有采购单并分页 或者是 根据仓库id、起止时间、商品名称、采购员、是否入库查询采购单并分页;

请求参数分析:
页码pageNum 每页行数pageSize — Page接收封装

storeId startTime endTime productName buyUser isIn — 使用Purchase对象接收并封装,但是Purchase类中没有属性startTime
endTime productName,需要追加;

采购单列表展示的数据分析:
额外需要仓库名 商品名 — 需要给Purchase追加属性storeName productName;

statr <= buyTime <= end

2.删除采购单
/purchase/purchase-delete/{buyId} — 根据id删除采购单

3.修改采购单
/purchase/purchase-update
{
buyId: 49 √
buyNum: 50 √
buyTime: “2023-06-21T09:59:39.000+00:00”
buyUser: “张三”
endTime: null
factBuyNum: “40” √
isIn: “0”
phone: “13666666666”
placeId: 5
productId: 31
productName: “空调”
startTime: null
storeId: 1
storeName: “西安仓库”
supplyId: 4
}

4.生成入库单
/purchase/in-warehouse-record-add
{
buyId: 49
buyNum: 50
buyTime: “2023-06-21T09:59:39.000+00:00”
buyUser: “张三”
endTime: null
factBuyNum: 40
isIn: “0”
phone: “13666666666”
placeId: 5
productId: 31
productName: “空调”
startTime: null
storeId: 1
storeName: “西安仓库”
supplyId: 4
}


入库单管理模块:

1.入库单列表
/instore/store-list — 查询所有仓库

/instore/instore-page-list?storeId=&productName=&startTime=&endTime=&pageSize=5&pageNum=1&totalNum=0
查询所有入库单并分页 或者 根据仓库id、商品名称、起止时间查询入库单并分页

请求参数分析:
页码pageNum 每页行数pageSize — Page对象接收并封装
storeId productName startTime endTime — InStore对象接收并封装 — InStore追加属性productName startTime endTime

入库单列表展示的信息分析:
仓库名称 商品名 入库价格 创建人 — InStore追加属性storeName productName inPrice userCode

2.确定入库
1>将入库单状态改为已入库
2>增加商品的库存
/instore/instore-confirm
{
createBy: 1
createTime: “2022-04-20T17:30:25.000+00:00”
endTime: null
inNum: 50
inPrice: 2000
insId: 35
isIn: “0”
productId: 22
productName: “空调”
startTime: null
storeId: 1
storeName: “西安仓库”
userCode: “admin”
}


出库单管理模块:

1.出库列表
/outstore/store-list — 查询所有仓库

/outstore/outstore-page-list?storeId=&productName=&startTime=&endTime=&isOut=&pageSize=5&pageNum=1&totalNum=0
查询所有出库单并分页 或者 根据仓库id 商品名称 起止时间 是否出库查询出库单并分页;

请求参数的分析:
页码pageNum 每页行数pageSize — Page对象接收并封装
storeId productName startTime endTime isOut — OutStore对象接收并封装 — OutStore类追加属性productName startTime endTime

出库单列表展示的数据的分析:
仓库名称 商品名称 创建人 — OutStore类追加属性storeName productName userCode

2.确定出库
1>将出库单状态改为1已出库
2>修改商品的库存 — 减库存

/outstore/outstore-confirm
{
createBy: 1
createTime: “2023-06-20T16:06:11.000+00:00”
endTime: null
isOut: “0”
outNum: 10
outPrice: 2400
outsId: 14
productId: 31
productName: “空调”
salePrice: null
startTime: null
storeId: 1
storeName: “西安仓库”
tallyId: null
userCode: “admin”
}


统计查询:
前端使用echarts框架,后台负责查询组装数据,然后将后台查询到的数据响应给前端,前端再以
echarts框架所需的图形结构 格式填充到图形中。

/statistics/store-invent — 查询每个仓库存储的商品的数量;

select t1.store_id, t1_store_name, ifnull(sum(product_invent),0)
from store t1, product t2
where t1.store_id = t2.store_id
group by t1.store_id, t1_store_name

博客内容均系原创,未经允许严禁转载!
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇