正规的仓储出入库管理系统报价(工厂订单出入库信息管理系统模块2)

一、前言

工厂订单及出入库业务的趋势是客户要求越来越高,客户需要快捷、方便、简单、一站式的出入库手续。因此,货物出入库管理信息系统要简化出入库手续,减轻人员作业量,提高工作效率,助力企业数字信息化转型

之前整理过该系统的完整解决方案,有兴趣的可以参考文章:《工厂订单出入库信息管理系统》完整解决方案(含演示账号)

二、整体架构设计开发语言:
  • Golang:Go 极其地快。其性能与 Java 或 C 相似。在我们的使用中,Go 一般比 Python 要快 30 倍。
  • Vue: 轻量级框架, 大小只有几十kb, 国人开发,中文文档,不存在语言障碍,易于理解和学习。运行速度更快,相比较与react而言,同样都是操作虚拟dom,就性能而言,vue存在很大的优势。
部署方式:
  • 服务器系统:基于免安装可执行程序:支持Windows、Linux,Centos,Ubuntu操作系统
  • 数据库类型:目前已支持PostgreSQL、MySQL、Oracle、Microsoft sql Server、SQLite等,还可以定制其它类型数据库
  • 热数据缓存服务:基于Key-Value 的Redis 数据库,关键热活数据存储在Redis服务中,提高响应速率。
  • 主备双活服务器:确保稳定性,如果主服务器故障,自动切换到备服务器。热数据
  • 数据库备份:定时增量备份,定期全量备份。
三、编码实现 (基于篇幅及可读性考虑,此处展示部分关键代码)

1、模块截图

正规的仓储出入库管理系统报价(工厂订单出入库信息管理系统模块2)(1)

正规的仓储出入库管理系统报价(工厂订单出入库信息管理系统模块2)(2)

2、Go 关键代码

package models import ( "fmt" "github.com/astaxie/beego/orm" "productManage/common" writelog "productManage/log" "strconv" "time" ) type Sn struct { Sn string `orm:"column(Sn);size(255);pk" description:"唯一SN"` BoxNum int `orm:"column(BoxNum)" description:"SN所在的箱号"` BoxTotal int `orm:"column(BoxTotal)" description:"总箱数,对应order表的box_total"` CreateTime int64 `orm:"column(CreateTime)" description:"生成时间"` Ksn string `orm:"column(Ksn);size(255)" description:"唯一KSN"` OrderID string `orm:"column(OrderID);size(255)" description:"订单号,对应order表的order_id"` StatusBox int8 `orm:"column(StatusBox)" description:"装箱状态:0 未确认;1正确;2异常;"` StatusPrepare int8 `orm:"column(StatusPrepare)" description:"备货状态:0 未确认;1正确;2异常;"` StatusQc int8 `orm:"column(StatusQc)" description:"品管状态"` DevId string `orm:"column(DevId);size(255)" description:"五码合一用的"` Sim string `orm:"column(Sim);size(255)" description:"五码合一用的"` Imei string `orm:"column(Imei);size(255)" description:"五码合一用的"` RecipientID int64 `orm:"column(RecipientID);" description:"收件编号"` } type Sn2 struct { BoxNumCount int `orm:"column(BoxNumCount)" description:"SN所在的箱号的sn总数"` BoxNum int `orm:"column(BoxNum)" description:"SN所在的箱号"` } func (t *Sn) TableName() string { return "sn" } func (t *Sn) TableIndex() [][]string { return [][]string{ []string{"OrderID"}, } } func init() { orm.RegisterModel(new(Sn)) } // AddSn insert a new Sn into database and returns // last inserted Id on success. func AddSn(m *Sn) (id int64, err error) { o := orm.NewOrm() id, err = o.Insert(m) //success id == 0, err == nil return } func AddSnList(sn_list []Sn) (err error, error_sn string) { o := orm.NewOrm() o.Begin() writelog.WriteDebug("AddSnList o.Begin() count%d", len(sn_list)) _, err = o.InsertMulti(100, sn_list) if err != nil { writelog.WriteError("AddSnList 事务执行错误:err=%s", err.Error()) o.Rollback() return err, "InsertMulti" } err = o.Commit() if err != nil { writelog.WriteError("AddSnList 事务提交错误:err=%s", err.Error()) return err, "Commit" } writelog.WriteDebug("AddSnList End") return nil, "" } func DelSn(sn string) (num int64, err error) { o := orm.NewOrm() num, err = o.Delete(&Sn{Sn: sn}) return num, err } func DelSnByOrderID(OrderID string) (num int64, err error) { o := orm.NewOrm() sql := fmt.Sprintf(`DELETE FROM sn WHERE OrderID='%s'`, OrderID) res, err := o.Raw(sql).Exec() if err == nil { num, _ = res.RowsAffected() } return num, err } func GetSnList(StartTime, EndTime int64, OrderID string, Sn string, BoxNum, BoxTotal, StatusBox, Page, RowNum int) (recordcount int64, num int64, sn []Sn, err error, sql string) { if RowNum <= 0 { RowNum = common.Row_Num_Default } sql = fmt.Sprintf(`SELECT * FROM sn WHERE 1=1`) if StartTime > 0 { sql = fmt.Sprintf(` %s AND CreateTime >= %d`, sql, StartTime) } if EndTime > 0 { sql = fmt.Sprintf(` %s AND CreateTime <= %d`, sql, EndTime) } if len(OrderID) > 0 { sql = fmt.Sprintf(` %s AND OrderID like '%%%s%%'`, sql, OrderID) } if len(Sn) > 0 { sql = fmt.Sprintf(` %s AND Sn like '%%%s%%'`, sql, Sn) } if BoxNum > 0 { sql = fmt.Sprintf(` %s AND BoxNum = %d`, sql, BoxNum) } if BoxTotal > 0 { sql = fmt.Sprintf(` %s AND BoxTotal = %d`, sql, BoxTotal) } if StatusBox > 0 { sql = fmt.Sprintf(` %s AND StatusBox = %d`, sql, StatusBox) } o := orm.NewOrm() sql_num := "SELECT COUNT(*) FROM ( " sql " ) AS a" err = o.Raw(sql_num).QueryRow(&recordcount) if err != nil { //writelog.WriteDebug(sql_num) return 0, 0, sn, err, sql } if Page >= 0 { sql = sql " limit " strconv.Itoa(Page*RowNum) "," strconv.Itoa(RowNum) } writelog.WriteDebug(sql) num, err = o.Raw(sql).QueryRows(&sn) return recordcount, num, sn, err, sql } func GetSnBySn(strSn string) (v *Sn, err error) { o := orm.NewOrm() var ArraySn []Sn num, err := o.QueryTable("sn").Filter("Sn", strSn).All(&ArraySn) if err == nil { if num <= 0 { writelog.WriteDebug("没找到%s", strSn) return nil, orm.ErrNoRows } else if num > 1 { writelog.WriteDebug("多条报错%s", strSn) return nil, orm.ErrMultiRows } else { //num==1 return &ArraySn[0], nil } } return nil, err } func GetSnByKsn(strKsn string) (sn string, err error, _type string) { o := orm.NewOrm() var ArraySn []Sn num, err := o.QueryTable("sn").Filter("Ksn", strKsn).All(&ArraySn) if err == nil { if num <= 0 { writelog.WriteDebug("没找到%s", strKsn) return "", orm.ErrNoRows, "" } else if num > 1 { writelog.WriteDebug("多条报错%s", strKsn) return "", orm.ErrMultiRows, "" } else { //num==1 return ArraySn[0].Sn, nil, "ksn"//通过Ksn找到的 } } return "", err, "" } //不知道输入的是Sn还是Ksn,通过还原成Sn func GetSnBySnOrKsn(strSn string) (sn string, err error, _type string) { v, err := GetSnBySn(strSn) if err == nil && v != nil { return v.Sn, nil, "sn"//通过sn找到的 } return GetSnByKsn(strSn) } //导入sn的时候,计算每个sn对应的BoxNum func SetBoxNumInSn(OrderID string, BoxTotal, NumberPerBox int) { writelog.WriteDebug("--------%s,%d,%d", OrderID, BoxTotal, NumberPerBox) sql := fmt.Sprintf(`SELECT * FROM sn WHERE OrderID='%s'`, OrderID) o := orm.NewOrm() sql_num := "SELECT COUNT(*) FROM ( " sql " ) AS a" var recordcount int64 err := o.Raw(sql_num).QueryRow(&recordcount) if err != nil { return } Page := 0 for 1 == 1 { BoxNum := Page 1 sql_update := fmt.Sprintf(`UPDATE sn AS A INNER JOIN (SELECT Sn FROM sn WHERE OrderID='%s' LIMIT %s,%s) As B ON A.Sn=B.Sn SET A.BoxNum=%d`, OrderID, strconv.Itoa(Page*NumberPerBox), strconv.Itoa(NumberPerBox), BoxNum) writelog.WriteDebug("sn分箱 start %v", sql_update) o := orm.NewOrm() _, err = o.Raw(sql_update).Exec() if err != nil { writelog.WriteDebug("%s %s", sql_update, err.Error()) } writelog.WriteDebug("sn分箱 end") //创建box表 sql = fmt.Sprintf(`SELECT Sn FROM sn WHERE OrderID='%s' AND BoxNum=%d ORDER BY Sn`, OrderID, BoxNum) var s []Sn writelog.WriteDebug("box分箱 start") n, err := o.Raw(sql).QueryRows(&s) if err != nil { writelog.WriteDebug("%s %s", sql, err.Error()) } if n <= 0 { writelog.WriteDebug("n %d error ", n) } else { var box Box box.BoxNum = BoxNum box.OrderID = OrderID box.BoxTotal = BoxTotal box.SnStart = s[0].Sn box.SnEnd = s[n-1].Sn box.CreateTime = time.Now().Unix() _, err = AddBox(&box) if err != nil { writelog.WriteDebug("AddBox BoxNum:%s OrderID:%s, err:%s", BoxNum, OrderID, err.Error()) } writelog.WriteDebug("box分箱 end, %v, %v" , BoxNum, box.SnStart ) } Page = Page 1 time.Sleep(time.Nanosecond) if int64(Page*NumberPerBox) >= recordcount { break } } } func GetSnListByOrderIDAndBoxNum(OrderID string, BoxNum int) (num int64, sn []Sn, err error, sql string) { sql = fmt.Sprintf(`SELECT * FROM sn WHERE 1=1`) if len(OrderID) > 0 { sql = fmt.Sprintf(` %s AND OrderID='%s'`, sql, OrderID) } if BoxNum > 0 { sql = fmt.Sprintf(` %s AND BoxNum=%d`, sql, BoxNum) } //writelog.WriteDebug(sql) o := orm.NewOrm() num, err = o.Raw(sql).QueryRows(&sn) return num, sn, err, sql } func UpdateSnStatusBox( SnList []string, StatusBox int) { writelog.WriteDebug("UpdateSnStatusBox begin") sql_update := fmt.Sprintf(`UPDATE sn SET StatusBox=%d WHERE 1 = 1`, StatusBox) Len := len(SnList) if Len > 0 { sql_update = sql_update " and Sn in (" for k, v := range SnList { if k < Len-1 { sql_update = sql_update fmt.Sprintf("'%s' ,", v) } else { sql_update = sql_update fmt.Sprintf("'%s' ", v) } } sql_update = sql_update " )" } o := orm.NewOrm() _, err := o.Raw(sql_update).Exec() if err != nil { writelog.WriteDebug("%s %s", sql_update, err.Error()) } writelog.WriteDebug("UpdateSnStatusBox %s ok", sql_update) } func UpdateSnBoxStatusBySn(BoxNum int, OrderID string, Sn string, StatusBox int) { sql_update := fmt.Sprintf(`UPDATE sn SET StatusBox=%d WHERE OrderID='%s' and BoxNum=%d and Sn='%s'`, StatusBox, OrderID, BoxNum, Sn) o := orm.NewOrm() _, err := o.Raw(sql_update).Exec() if err != nil { writelog.WriteDebug("%s %s", sql_update, err.Error()) } writelog.WriteDebug("UpdateSnBoxStatusBySn %s ok", sql_update) } // 查询OrderId, BoxNum的 StatusBox 为OK的个数是否等于 NumPerBox func CountSnByBoxNumAndOrderID(BoxNum int, OrderID string) (recordcount int, err error) { o := orm.NewOrm() sql_num := fmt.Sprintf(`SELECT COUNT(*) FROM sn WHERE OrderID='%s' and BoxNum=%d `, OrderID, BoxNum) err = o.Raw(sql_num).QueryRow(&recordcount) return recordcount, err } // 查询OrderId, BoxNum的 StatusBox 为OK的个数是否等于 NumPerBox func CountSnByStatusBox(BoxNum int, OrderID string, StatusBox int) (recordcount int, err error) { o := orm.NewOrm() sql_num := fmt.Sprintf(`SELECT COUNT(*) FROM sn WHERE StatusBox=%d and OrderID='%s' and BoxNum=%d `, StatusBox, OrderID, BoxNum) err = o.Raw(sql_num).QueryRow(&recordcount) return recordcount, err } func CountSnBySnStartToSnEnd(SnStart, SnEnd string) (recordcount int, err error) { o := orm.NewOrm() sql_num := fmt.Sprintf(`SELECT COUNT(*) FROM sn WHERE Sn>='%s' AND Sn<='%s'`, SnStart, SnEnd) err = o.Raw(sql_num).QueryRow(&recordcount) writelog.WriteDebug("CountSnBySnStartToSnEnd %s %d", sql_num, recordcount) return recordcount, err } func GetKsnBySn(sn string) (s Sn, err error) { sql := fmt.Sprintf(`select Sn,Ksn from sn where Sn='%s'`, sn) o := orm.NewOrm() err = o.Raw(sql).QueryRow(&s) writelog.WriteDebug("GetKsnBySn % v" ,s) return s, err } //更新五码合一数据 func Update5Code(sn_s []Sn) { writelog.WriteDebug("% v", sn_s) for _, s := range sn_s { o := orm.NewOrm() sql := fmt.Sprintf(`Update sn set DevId='%s',Sim='%s',Imei='%s' WHERE Sn='%s'`, s.DevId, s.Sim, s.Sim, s.Sn) //writelog.WriteDebug(sql) o.Raw(sql).Exec() } } func GetSnListByRecipientID(OrderID string , RecipientID int64) (num int64, sn []Sn2, err error) { sql := fmt.Sprintf(`SELECT count(BoxNum) as BoxNumCount, BoxNum FROM sn WHERE RecipientID=%d and OrderID = '%s' group by BoxNum `, RecipientID, OrderID ) o := orm.NewOrm() num, err = o.Raw(sql).QueryRows(&sn) writelog.WriteDebug("%v, %v", sql, sn) return num, sn, err } func EditRecipientIDByOrderIDAndBox(RecipientID int64, OrderID string, BoxNum int , SnStart, SnEnd string) (num int64, err error) { o := orm.NewOrm() sql := fmt.Sprintf(`Update sn set RecipientID=%d WHERE BoxNum=%d And OrderID = '%s' And Sn >='%s' And Sn <='%s' `, RecipientID, BoxNum, OrderID, SnStart, SnEnd) writelog.WriteDebug(sql) res, err := o.Raw(sql).Exec() if err == nil { num, _ = res.RowsAffected() writelog.WriteDebug("EditRecipientIDByOrderIDAndBox ok, rows=%d", num) } else { writelog.WriteDebug("EditRecipientIDByOrderIDAndBox err:%s", err.Error()) } return num, err } func GetSnListByOrderIDAndBoxNumAndRecipientId(OrderID string, BoxNum int) (num int64, sn []Sn, err error, sql string) { sql = fmt.Sprintf(`SELECT * FROM sn WHERE RecipientId=0`) if len(OrderID) > 0 { sql = fmt.Sprintf(` %s AND OrderID='%s'`, sql, OrderID) } if BoxNum > 0 { sql = fmt.Sprintf(` %s AND BoxNum=%d`, sql, BoxNum) } //writelog.WriteDebug(sql) o := orm.NewOrm() num, err = o.Raw(sql).QueryRows(&sn) return num, sn, err, sql } func ResetSnRecipientId(RecipientID int64) (num int64, err error) { o := orm.NewOrm() sql := fmt.Sprintf(`Update sn set RecipientID=0 WHERE RecipientID=%d`, RecipientID) writelog.WriteDebug(sql) res, err := o.Raw(sql).Exec() if err == nil { num, _ = res.RowsAffected() writelog.WriteDebug("ResetSnRecipientId ok, rows=%d", num) } else { writelog.WriteDebug("ResetSnRecipientId err:%s", err.Error()) } return num, err }

正规的仓储出入库管理系统报价(工厂订单出入库信息管理系统模块2)(3)

3、vue代码

<template> <div class="page-container"> <div class="search-wrapper"> <div class="block"> <span class="label">开始时间</span> <el-date-picker v-model="searchForm.startTime" type="date" :clearable="true" format="yyyy-MM-dd 00:00:00" placeholder="选择日期"> </el-date-picker> </div> <div class="block"> <span class="label">结束时间</span> <el-date-picker v-model="searchForm.endTime" type="date" :clearable="true" format="yyyy-MM-dd 23:59:59" placeholder="选择日期"> </el-date-picker> </div> <div class="block"> <div class="label">订单号</div> <el-input v-model="searchForm.orderId"></el-input> </div> <div class="block"> <div class="label">箱号</div> <el-input v-model="searchForm.boxNum"></el-input> </div> <div class="block"> <div class="label">扫描装箱状态</div> <el-select v-model="searchForm.status" placeholder="请选择"> <el-option v-for="item in status" :key="item.id" :label="item.name" :value="item.id"> </el-option> </el-select> </div> <div class="block"> <div class="label">SN</div> <el-input v-model="searchForm.sn"></el-input> </div> <div class="operates"> <el-button type="primary" @click="searchClick">查询</el-button> <el-button type="primary" @click="resetClick">重置</el-button> </div> </div> <el-table :data="tableData" style="width:100%"> <el-table-column prop="OrderID" label="订单号" > </el-table-column> <el-table-column prop="Sn" label="SN" > </el-table-column> <el-table-column prop="Ksn" label="KSN"> </el-table-column> <el-table-column prop="BoxNum" label="箱号" > </el-table-column> <el-table-column prop="CreateTime" label="创建时间" > </el-table-column> <el-table-column prop="StatusBox" label="扫描装箱状态" > <template slot-scope="scope"> <div v-if="scope.row.StatusBox==0">无</div> <div v-if="scope.row.StatusBox==1">正确</div> <div v-if="scope.row.StatusBox==2">异常</div> <div v-if="scope.row.StatusBox==3">进行中</div> </template> </el-table-column> </el-table> <el-pagination @current-change="pageChange" :current-page.sync="pageData.Page" :page-size="pageData.RowNum" layout="total, prev, pager, next" :total="RowNum"> </el-pagination> </div> </template> <script> import {SN_API_PATH} from "../../service/api" let StatusDefinite = [{ id:0, name:"全部" },{ id:1, name:"正确" },{ id:2, name:"异常" }] export default{ data(){ return{ orderId:"", searchForm:{ startTime:new Date(new Date().toLocaleDateString()), endTime:new Date(new Date().toLocaleDateString()), boxNum:"", status:0, orderId:"", sn:"" }, tableData:[], status:StatusDefinite, RowNum:0, pageData:{ Page:1, RowNum:20 } } }, created(){ this.searchForm.orderId = this.$route.query.orderId?this.$route.query.orderId:"" this.searchForm.boxNum = this.$route.query.boxNum?this.$route.query.boxNum:"" if(this.$route.query.startTime){ this.searchForm.startTime = new Date(this.$route.query.startTime) } if(this.$route.query.endTime){ this.searchForm.endTime = new Date(this.$route.query.endTime) } this.getSnList() }, methods:{ pageChange(){ this.getSnList() }, getSnList(){ let formData = new FormData() formData.append("Token",sessionStorage.getItem("token")) formData.append("Act","GetSnList") formData.append("Box",this.searchForm.boxNum) formData.append("StatusBox",this.searchForm.status) formData.append("Page",this.pageData.Page-1) formData.append("RowNum",this.pageData.RowNum) let startTime = this.moment(this.searchForm.startTime).format("YYYY-MM-DD 00:00:00") let endTime = this.moment(this.searchForm.endTime).format("YYYY-MM-DD 23:59:59") formData.append("StartTime",new Date(startTime).getTime()/1000) formData.append("EndTime",new Date(endTime).getTime()/1000) formData.append("OrderID",this.searchForm.orderId) formData.append("Sn",this.searchForm.sn) this.$axios.post(SN_API_PATH,formData).then(res=>{ if(res.data.Ret == 0){ if(res.data.Data){ res.data.Data.map(v=>{ v.CreateTime = this.moment((v.CreateTime*1000)).format("YYYY-MM-DD HH:mm:ss") }) }else{ res.data.Data = [] } this.tableData = res.data.Data this.RowNum = res.data.Recordcount }else{ this.$message({ message:res.data.Msg, type:"error", duration:3000 }); } }) }, resetClick(){ this.searchForm = { orderId:"", startTime:new Date(new Date().toLocaleDateString()), endTime:new Date(new Date().toLocaleDateString()), sn:"" } }, searchClick(){ this.getSnList() }, repairClick(scope){ this.$prompt('SN号', '', { confirmButtonText: '确定', cancelButtonText: '取消', }).then(res=>{ }) } } } </script> <style scoped> .search-wrapper{ display:flex; justy-content:flex-start; flex-wrap:wrap; } </style>

正规的仓储出入库管理系统报价(工厂订单出入库信息管理系统模块2)(4)

四、结语

本次分享结束,欢迎来撩!

完整方案介绍:《工厂订单出入库信息管理系统》完整解决方案(含演示账号)

系统演示网址:factory http://47.113.115.218:81 演示密码:123456

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页