## 题目:
### 港口堆存费管理系统
姓名:纪学磊
班级:软件204
学号:2020082407
## 一、项目架构:
项目技术栈:Go + Vue3+ PgSQL
开发工具:Goland+VScode
后端语言:Go
后端框架:Gin+Gorm
前端语言:Vue3
前端框架:ElementUI Plus
数据库:PostgresSQL
### VScode
![enter image description here](https://lexiangla.com/assets/f9ef8354e74511ecac786a39a20d48e9)
VSCode 全称 Visual Studio Code,是微软出的一款轻量级代码编辑器,免费、开源而且功能强大。它支持几乎所有主流的程序语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比 Diff、GIT 等特性,支持插件扩展,并针对网页开发和云端应用开发做了优化。软件跨平台支持 Win、Mac 以及 Linux。 对于它来说,写MarkDown 简直是小菜一碟。
### Goland
![enter image description here](https://lexiangla.com/assets/68fc0e84e74611ecb5a47e9ae9391b06)
JetBrains 公司出品的 IDE,在业界有着良好的口碑,比如 Clion for C/C++、IntellijI IDEA for Java、PyCharm for Python、PhpStorm for PHP、WebStorm for JavaScript 等。Goland 一经推出,受到了广大 Gopher 的喜爱,建议大家将其作为 Go 的首选 IDE。
### GO语言
![enter image description here](https://lexiangla.com/assets/1344c7e6e74711ecbea6cec162bed327)
Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。
Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。
### Vue3
![enter image description here](https://lexiangla.com/assets/5bf423ece74711ec923e7a5ff5bb4dd0)
Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架。
Vue 只关注视图层, 采用自底向上增量开发的设计。
Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。
### ElementUI Plus
![enter image description here](https://lexiangla.com/assets/06c71798e74811ecb2487e9ae9391b06)
基于Vue3 面向设计者的与开发者的组件库
### PostgreSQL
![enter image description here](https://lexiangla.com/assets/ab738718e74811ec91ec2e3eacf6da57)
PostgreSQL是一个功能强大的开源对象关系型数据库系统,他使用和扩展了SQL语言,并结合了许多安全存储和扩展最复杂数据工作负载的功能。PostgreSQL的起源可以追溯到1986年,作为加州大学伯克利分校POSTGRES项目的一部分,并且在核心平台上进行了30多年的积极开发。
## 二、项目gitee地址
[Mr. (aleilei12138) - Gitee.com](https://gitee.com/aleilei12138)
![enter image description here](https://lexiangla.com/assets/512701a8e74911eca0e2ae1e3d40b672)
[DB_course_design: 数据库系统课程设计](https://gitee.com/aleilei12138/db_course_design)
![enter image description here](https://lexiangla.com/assets/9fe95fc4e74a11ecb12bfe39e79ca7f2)
- backend: 后端项目
- frontend: 前端项目
- database:数据库脚本
- README.md: 项目介绍
## 三、ER图及数据库脚本
ER图:
![enter image description here](https://lexiangla.com/assets/b54d462ce74b11ec8015fe39e79ca7f2)
货物表:
```
create table goods
(
gid varchar(15) not null --货物id
constraint goods_pk
primary key,//作为主键
num double precision not null,--货物数量
car varchar(7),//运输车牌
state boolean default false --货物是否已经入库
);
```
仓库表:
```
create table deports
(
did varchar not null --仓库号
constraint deport_pk
primary key,
volume double precision --仓库剩余的容量
);
```
仓储信息:
```
create table storage
(
sid varchar not null --仓储信息编号
constraint storage_pk
primary key,
gid varchar --存储的货物号
constraint storage_goods_gid_fk
references goods,
num double precision, --存储的数量
did varchar --仓库号
constraint storage_deports_did_fk
references deports,
in_time date not null--这一批次货物入库时间
);
```
订单表:
```
create table orders
(
oid varchar not null--订单号
constraint orders_pk
primary key,
num double precision not null,--订购数量
state boolean default false,--订单状态
remain double precision--剩余没有发货的数量
);
```
出库信息表:
```
create table out_load
(
id varchar not null --出库信息id
constraint out_load_pk
primary key,
out_time date not null,--出库时间
num double precision not null,--出库的数量
sid varchar --操作的仓储信息标识
constraint out_load_storage_sid_fk
references storage,
fee double precision, --堆存费
oid varchar --处理的订单号
constraint out_load_orders_oid_fk
references orders
);
```
### 后端项目结构:
![enter image description here](https://lexiangla.com/assets/cb1e2f3ce74d11eca3d33a20310007a7)
- 与前端进行交互的接口函数
部分代码:
```
func Getmessage(c *gin.Context) { //获取某个仓库详细信息
page := -1
if arg := c.Query("page"); arg != "" {
page = com.StrTo(arg).MustInt()
}
limit := -1
if arg := c.Query("limit"); arg != "" { //获取请求查询的信息
limit = com.StrTo(arg).MustInt()
}
searchText := ""
if arg := c.Query("searchText"); arg != "" {
searchText = arg
}
storageParam := map[string]interface{}{ //将请求信息整合
"page": page,
"limit": limit,
"searchText": searchText,
}
err, info, total := models.GetDetail(storageParam) //调用对应的取数函数
if err != nil {
fmt.Println(err.Error()) //后端显示错误
app.Error(c, e.ERROR, err, err.Error())
return
}
app.Ok(c, map[string]interface{}{"value": info, "total": total}, "OK") //将数据发送到对应的端口
}
```
```
func AddGoods(c *gin.Context) { //添加货物入库
err, info := models.Add(c)
if err != nil {
fmt.Println(err.Error()) //后端显示错误
app.Error(c, e.ERROR, err, err.Error()) //返回错误
return
}
app.Ok(c, info, "ok")
}
```
![enter image description here](https://lexiangla.com/assets/58e4fc6ae74e11ec9fe4ae1e3d40b672)
- 中间件解决跨域问题
![enter image description here](https://lexiangla.com/assets/85f58418e74e11ec942eea3403dcd543)
- 数据库操作
部分代码:
```
func AddGoods(c *gin.Context) (error, Good) { //添加货物
var goodData Good
err := c.ShouldBindJSON(&goodData) //货物添加的货物信息
if err != nil {
fmt.Println(err.Error()) //后端查看错误
}
err = db.Table("goods").Select("gid", "num", "car").Create(&goodData).Error //添加货物数据库操作
return err, goodData
}
```
```
func UpGoods(c *gin.Context) (error, Good) { //更新货物
var goodData Good
err := c.ShouldBindJSON(&goodData) //信息绑定到结构体中
err = db.Table("goods").Where("gid = ?", goodData.Gid).Updates(&goodData).Error
return err, goodData
}
```
![enter image description here](https://lexiangla.com/assets/326be548e74f11ecb40c221f92ded91c)
- 处理路由与前端交互的通道
部分代码:
```
func AreaRouter(r *gin.RouterGroup) {
r.GET("/", areamanger.GetVolume) //获取仓储信息与仓库对应容量
r.POST("/", areamanger.AddGoods) //入库处理
r.PUT("/", areamanger.TakeGoods) //出库处理
r.GET("/message", areamanger.Getmessage)
r.GET("/outload", areamanger.Getoutload)
}
```
```
func InitRouter() *gin.Engine {
r := gin.New() //自定义一个新的路由引擎
r.Use(gin.Logger()) //使用logger中间件
r.Use(gin.Recovery())
r.Use(middleWare.Cors()) //全局注册中间件
g := r.Group("/area")
f := r.Group("/goods")
h := r.Group("/firm")
//SyBaseRouter(g) //基本的路由
AreaRouter(g) //仓库处理
GoodsRouter(f) //商品处理
FirmRouter(h)
return r
}
```
##项目功能展示:
添加货物:
![enter image description here](https://lexiangla.com/assets/4c69c842e75011ec94426a39a20d48e9)
![enter image description here](https://lexiangla.com/assets/6d7694b6e75011ec879b2a500f7d4d84)
货物入库:
![enter image description here](https://lexiangla.com/assets/8d5c0fc2e75011ecb389fafb818aa086)
输入仓储信息编号之后在菜单选择货物进入的仓库。货物入库后修改编辑等按钮禁用。
![enter image description here](https://lexiangla.com/assets/3477125ce75111ecb8f46e142fd1ea40)
删除货物:
![enter image description here](https://lexiangla.com/assets/9df9a85ce75111ecb5c96aaf1d56807c)
点击确定按钮删除货物信息已经入库的货物不能删除
查看仓储信息:
在仓库管理界面点击查看查看详情按钮在弹窗中可以查看当前仓库的仓储信息,信息按日期排序,为能让处理人员向出库最先入库的货物。
![enter image description here](https://lexiangla.com/assets/4840e802e75211ec9fe57a5ff5bb4dd0)
![enter image description here](https://lexiangla.com/assets/5741f04ee75211ec82900e0efc7a6705)
查看订单信息:
在订单管理界面可以查看订单信息
![enter image description here](https://lexiangla.com/assets/7b7490fce75211eca6fb4e069e2914c4)
还可以实现对订单的增删改查点击出库按钮出现如下弹窗:
![enter image description here](https://lexiangla.com/assets/ffdd8060e75211eca025c6bd727fe010)
选择要出库的商品之后出现如下界面
![enter image description here](https://lexiangla.com/assets/16309668e75311ecb6a0d261efdc9fed)
填写完出库数量与出库数量点击确认出库按钮完成出库,在这之后可以在出库明细中查看出口库信息与堆存费
![enter image description here](https://lexiangla.com/assets/5997a004e75311ecb50aae1e3d40b672)
还可以查询对应订单每次的出库明细。
## 堆存费算法
```
package models
import "fmt"
func Calculate(category string) {
var instorage []InStorage
err := db.Table("in_storage").Where("category like ?", category).Order("intime ASC").Find(&instorage).Error //取入库表信息
if err != nil {
fmt.Println(err.Error())
}
var outstorage []OutStorage
err = db.Table("out_storage").Where("category like ?", category).Order("out_time ASC").Find(&outstorage).Error //取出库表信息
if err != nil {
fmt.Println(err.Error())
}
i := 0
flag := false
var state float32
for _, out := range outstorage {
tons := out.Tons //暂存需要出库的吨数
out.Fee = 0
for tons != 0 {
if instorage[i].Tons >= tons {
state = float32((out.OutTime.Sub(instorage[i].InTime).Hours()) / 24)
if state < 0 {
flag = true //是否库存不足
break
}
state = state - 13 //堆存的天数
if state <= 0 {
} else {
out.Fee = out.Fee + (state * 0.5 * tons)
}
instorage[i].Tons -= tons
tons = 0
} else {
if instorage[i].Tons == 0 {
i++
}
state = float32((out.OutTime.Sub(instorage[i].InTime).Hours()) / 24) //计算时间差
if state < 0 {
flag = true //是否库存不足
break
}
state = state - 13 //堆存的天数
if state <= 0 {
} else {
out.Fee = out.Fee + (state * 0.5 * instorage[i].Tons)
}
tons -= instorage[i].Tons
instorage[i].Tons = 0
i++
}
}
if !flag {
db.Table("out_storage").Where("outid = ?", out.Outid).Update("fee", out.Fee)
} else {
db.Table("out_storage").Where("outid = ?", out.Outid).Update("text", "库存不足!!!")
db.Table("out_storage").Where("outid = ?", out.Outid).Update("fee", 0)
flag = false
}
}
}
```
## 项目部署地址:
[堆存费管理系统](http://8.130.101.16:3000/)
## 总结:
这是我第一次独立完成一个前后端分离的网站开发,两周多的时间我从一个对web开发一无所知的“小白”,成为了一个能写出一个还算能看的界面的“大白”(真的还差的远呢),真正的接触了才知道,原来我们需要去了解的知识还有那么那么多,第一看到老师给的题目的时候,我的内心别提有多忐忑了:那么多没有听说过的知识,vue是什么东西?,到底从哪里入手做这个东西。日报markdown又该怎么写。不得不说这是对我们动手能力的一次十分重大的考验。老师让用的东西都没用过,本来想要系统的学习一下该怎么样去编写程序,但是看看好像真的没有时间。这貌似是我来到民大,面临的最大的一次考验。于是便有了一个个的凌晨两点,便有了一个个痛并快乐的夜晚。虽然每天做课设饭都吃不上,日益消瘦,但是我的心灵感觉到了充实。总的来说在老师严格要求的压力下,这几天课设做的确实是不怎么舒服,但是经过这次课设,我学会了很多知识,也学会了很多获取知识的方法。感谢同学老师的帮助,也感谢凌晨学习的自己,但是自己的力量毕竟渺小,同学们互相帮助才有我项目成型的机会。以后看到这里的学弟们,加油相信自己,没学过的东西就去学没有什么好怕的。