1
0

3 Ревизии eeedb09a65 ... 55e6b7a89b

Автор SHA1 Съобщение Дата
  xu 55e6b7a89b Merge remote-tracking branch 'origin/dev' into dev преди 6 месеца
  xu f15e38135d 仓库管理-1 преди 6 месеца
  xu fb3e5810bd 仓库管理 преди 6 месеца
променени са 49 файла, в които са добавени 2071 реда и са изтрити 171 реда
  1. 4 4
      server/api/v1/storehouse/commodity.go
  2. 4 4
      server/api/v1/storehouse/commodityGenre.go
  3. 4 0
      server/api/v1/storehouse/enter.go
  4. 56 0
      server/api/v1/storehouse/goods.go
  5. 128 0
      server/api/v1/storehouse/manifest.go
  6. 5 5
      server/api/v1/storehouse/place.go
  7. 5 5
      server/api/v1/storehouse/storageArea.go
  8. 4 4
      server/api/v1/storehouse/storageAreaGenre.go
  9. 4 4
      server/api/v1/storehouse/supplier.go
  10. 5 5
      server/api/v1/storehouse/warehouse.go
  11. 4 4
      server/api/v1/workflow/node.go
  12. 1 1
      server/config.yaml
  13. 21 0
      server/dao/godown/cargo.go
  14. 5 2
      server/dao/commodity.go
  15. 3 2
      server/dao/commodityGenre.go
  16. 76 0
      server/dao/godown/goods.go
  17. 149 0
      server/dao/godown/manifest.go
  18. 16 14
      server/dao/place.go
  19. 10 9
      server/dao/storageArea.go
  20. 2 2
      server/dao/storageAreaGenre.go
  21. 2 2
      server/dao/supplier.go
  22. 8 7
      server/dao/warehouse.go
  23. 11 7
      server/initialize/gorm.go
  24. 2 0
      server/initialize/router.go
  25. 21 0
      server/model/common/request/common.go
  26. 7 0
      server/model/common/response/common.go
  27. 2 0
      server/router/storehouse/enter.go
  28. 22 0
      server/router/storehouse/goods.go
  29. 27 0
      server/router/storehouse/manifest.go
  30. 1 1
      server/router/storehouse/storageArea.go
  31. 7 7
      server/service/storehouse/commodity.go
  32. 7 7
      server/service/storehouse/commodityGenre.go
  33. 2 0
      server/service/storehouse/enter.go
  34. 35 0
      server/service/storehouse/goods.go
  35. 41 0
      server/service/storehouse/manifest.go
  36. 8 8
      server/service/storehouse/place.go
  37. 8 8
      server/service/storehouse/storageArea.go
  38. 8 6
      server/service/storehouse/storageAreaGenre.go
  39. 7 7
      server/service/storehouse/supplier.go
  40. 8 8
      server/service/storehouse/warehouse.go
  41. 55 1
      web/src/api/storehouse.js
  42. 1 1
      web/src/utils/request.js
  43. 34 5
      web/src/view/storehouse/commodity/commodity.vue
  44. 0 11
      web/src/view/storehouse/commodityGenre/commodityGenre.vue
  45. 611 0
      web/src/view/storehouse/goods/goods.vue
  46. 178 0
      web/src/view/storehouse/manifest/manifest.vue
  47. 430 1
      web/src/view/storehouse/warehouse/place/place.vue
  48. 21 18
      web/src/view/storehouse/warehouse/storageArea/storageArea.vue
  49. 1 1
      web/src/view/storehouse/warehouse/warehouse.vue

+ 4 - 4
server/api/v1/storehouse/commodity.go

@@ -2,7 +2,7 @@ package storehouse
 
 import (
 	"github.com/gin-gonic/gin"
-	"server/dao"
+	"server/dao/godown"
 	"server/global"
 	"server/model/common/request"
 	"server/model/common/response"
@@ -43,7 +43,7 @@ func (ca *CommodityApi) QueryCommodityList(c *gin.Context) {
 }
 
 func (ca *CommodityApi) CreateCommodity(c *gin.Context) {
-	var commodity dao.Commodity
+	var commodity godown.Commodity
 	err := c.ShouldBindJSON(&commodity)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -60,7 +60,7 @@ func (ca *CommodityApi) CreateCommodity(c *gin.Context) {
 }
 
 func (ca *CommodityApi) UpdateCommodity(c *gin.Context) {
-	var commodity dao.Commodity
+	var commodity godown.Commodity
 	err := c.ShouldBindJSON(&commodity)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -77,7 +77,7 @@ func (ca *CommodityApi) UpdateCommodity(c *gin.Context) {
 }
 
 func (ca *CommodityApi) DeleteCommodity(c *gin.Context) {
-	var commodity dao.Commodity
+	var commodity godown.Commodity
 	err := c.ShouldBindJSON(&commodity)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)

+ 4 - 4
server/api/v1/storehouse/commodityGenre.go

@@ -2,7 +2,7 @@ package storehouse
 
 import (
 	"github.com/gin-gonic/gin"
-	"server/dao"
+	"server/dao/godown"
 	"server/global"
 	"server/model/common/response"
 )
@@ -20,7 +20,7 @@ func (cga *CommodityGenreApi) QueryAllCommodityGenre(c *gin.Context) {
 }
 
 func (cga *CommodityGenreApi) CreateCommodityGenre(c *gin.Context) {
-	var commodityGenre dao.CommodityGenre
+	var commodityGenre godown.CommodityGenre
 	err := c.ShouldBindJSON(&commodityGenre)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -37,7 +37,7 @@ func (cga *CommodityGenreApi) CreateCommodityGenre(c *gin.Context) {
 }
 
 func (cga *CommodityGenreApi) UpdateCommodityGenre(c *gin.Context) {
-	var commodityGenre dao.CommodityGenre
+	var commodityGenre godown.CommodityGenre
 	err := c.ShouldBindJSON(&commodityGenre)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -54,7 +54,7 @@ func (cga *CommodityGenreApi) UpdateCommodityGenre(c *gin.Context) {
 }
 
 func (cga *CommodityGenreApi) DeleteCommodityGenre(c *gin.Context) {
-	var commodityGenre dao.CommodityGenre
+	var commodityGenre godown.CommodityGenre
 	err := c.ShouldBindJSON(&commodityGenre)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)

+ 4 - 0
server/api/v1/storehouse/enter.go

@@ -10,6 +10,8 @@ type ApiGroup struct {
 	PlaceApi
 	StorageAreaApi
 	StorageAreaGenreApi
+	ManifestApi
+	GoodsApi
 }
 
 var (
@@ -20,4 +22,6 @@ var (
 	placeService            = service.ServiceGroupApp.StorehouseServiceGroup.PlaceService
 	storageAreaService      = service.ServiceGroupApp.StorehouseServiceGroup.StorageAreaService
 	storageAreaGenreService = service.ServiceGroupApp.StorehouseServiceGroup.StorageAreaGenreService
+	manifestService         = service.ServiceGroupApp.StorehouseServiceGroup.ManifestService
+	goodsService            = service.ServiceGroupApp.StorehouseServiceGroup.GoodsService
 )

+ 56 - 0
server/api/v1/storehouse/goods.go

@@ -0,0 +1,56 @@
+package storehouse
+
+import (
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"server/global"
+	"server/model/common/request"
+	"server/model/common/response"
+)
+
+type GoodsApi struct{}
+
+func (ga *GoodsApi) QueryAllGoods(c *gin.Context) {
+	goods, err := goodsService.QueryAllGoods()
+	if err != nil {
+		response.FailWithMessage("查询失败", c)
+		global.GVA_LOG.Error("QueryAllGoods ====== " + err.Error())
+		return
+	}
+	response.OkWithData(goods, c)
+}
+
+func (ga *GoodsApi) QueryGoodsList(c *gin.Context) {
+	var info request.SearchGoods
+	err := c.ShouldBindJSON(&info)
+	if err != nil {
+		response.FailWithMessage("参数错误", c)
+		global.GVA_LOG.Error("QueryGoodsList ====== " + err.Error())
+		return
+	}
+	fmt.Println(info)
+	list, total, err := goodsService.QueryGoodsList(info)
+	if err != nil {
+		response.FailWithMessage("查询失败", c)
+		global.GVA_LOG.Error("QueryGoodsList ====== " + err.Error())
+		return
+	}
+	response.OkWithDetailed(response.PageResult{
+		List:     list,
+		Total:    total,
+		Page:     info.PageInfo.Page,
+		PageSize: info.PageInfo.PageSize,
+	}, "获取成功", c)
+}
+
+func (ga *GoodsApi) GetInventory(c *gin.Context) {
+	var info request.GetInventoryRequest
+	err := c.ShouldBindJSON(&info)
+	if err != nil {
+		response.FailWithMessage("参数错误", c)
+		global.GVA_LOG.Error("QueryGoodsList ====== " + err.Error())
+		return
+	}
+	inventory := goodsService.GetInventory(info)
+	response.OkWithData(inventory, c)
+}

+ 128 - 0
server/api/v1/storehouse/manifest.go

@@ -0,0 +1,128 @@
+package storehouse
+
+import (
+	"github.com/gin-gonic/gin"
+	"server/dao/godown"
+	"server/global"
+	"server/model/common/request"
+	"server/model/common/response"
+	"strconv"
+)
+
+type ManifestApi struct{}
+
+func (ma *ManifestApi) QueryAllManifest(c *gin.Context) {
+	manifests, err := manifestService.QueryAllManifest()
+	if err != nil {
+		response.FailWithMessage("查询失败", c)
+		global.GVA_LOG.Error("QueryAllManifest ====== " + err.Error())
+		return
+	}
+	response.OkWithData(manifests, c)
+}
+
+func (ma *ManifestApi) QueryManifestList(c *gin.Context) {
+	var info request.SearchManifest
+	err := c.ShouldBindJSON(&info)
+	if err != nil {
+		response.FailWithMessage("参数错误", c)
+		global.GVA_LOG.Error("QueryManifestList ====== " + err.Error())
+		return
+	}
+	list, total, err := manifestService.QueryManifestList(info)
+	if err != nil {
+		response.FailWithMessage("查询失败", c)
+		global.GVA_LOG.Error("QueryManifestList ====== " + err.Error())
+		return
+	}
+	response.OkWithDetailed(response.PageResult{
+		List:     list,
+		Total:    total,
+		Page:     info.PageInfo.Page,
+		PageSize: info.PageInfo.PageSize,
+	}, "获取成功", c)
+}
+
+func (ma *ManifestApi) CreateManifest(c *gin.Context) {
+	var manifest godown.Manifest
+	err := c.ShouldBindJSON(&manifest)
+	if err != nil {
+		response.FailWithMessage("参数错误", c)
+		global.GVA_LOG.Error("CreateManifest ====== " + err.Error())
+		return
+	}
+	err = manifestService.CreateManifest(manifest)
+	if err != nil {
+		response.FailWithMessage("新增失败", c)
+		global.GVA_LOG.Error("CreateManifest ====== " + err.Error())
+		return
+	}
+	response.OkWithMessage("新增成功", c)
+}
+
+func (ma *ManifestApi) UpdateManifest(c *gin.Context) {
+	var manifest godown.Manifest
+	err := c.ShouldBindJSON(&manifest)
+	if err != nil {
+		response.FailWithMessage("参数错误", c)
+		global.GVA_LOG.Error("UpdateManifest ====== " + err.Error())
+		return
+	}
+	err = manifestService.UpdateManifest(manifest)
+	if err != nil {
+		response.FailWithMessage("修改失败", c)
+		global.GVA_LOG.Error("UpdateManifest ====== " + err.Error())
+		return
+	}
+	response.OkWithMessage("修改成功", c)
+}
+
+func (ma *ManifestApi) DeleteManifest(c *gin.Context) {
+	id, err := strconv.Atoi(c.Query("id"))
+	if err != nil {
+		response.FailWithMessage("参数错误", c)
+		global.GVA_LOG.Error("DeleteManifest ====== " + err.Error())
+		return
+	}
+	err = manifestService.DeleteManifest(id)
+	if err != nil {
+		response.FailWithMessage("删除失败", c)
+		global.GVA_LOG.Error("DeleteManifest ====== " + err.Error())
+		return
+	}
+	response.OkWithMessage("删除成功", c)
+}
+
+func (ma *ManifestApi) CreateInboundManifest(c *gin.Context) {
+	var manifest godown.Manifest
+	err := c.ShouldBindJSON(&manifest)
+	if err != nil {
+		response.FailWithMessage("参数错误", c)
+		global.GVA_LOG.Error("CreateManifest ====== " + err.Error())
+		return
+	}
+	err = manifestService.CreateInboundManifest(manifest)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		global.GVA_LOG.Error("CreateManifest ====== " + err.Error())
+		return
+	}
+	response.OkWithMessage("入库成功", c)
+}
+
+func (ma *ManifestApi) CreateOutboundManifest(c *gin.Context) {
+	var manifest godown.Manifest
+	err := c.ShouldBindJSON(&manifest)
+	if err != nil {
+		response.FailWithMessage("参数错误", c)
+		global.GVA_LOG.Error("CreateOutboundManifest ====== " + err.Error())
+		return
+	}
+	err = manifestService.CreateOutboundManifest(manifest)
+	if err != nil {
+		response.FailWithMessage(err.Error(), c)
+		global.GVA_LOG.Error("CreateOutboundManifest ====== " + err.Error())
+		return
+	}
+	response.OkWithMessage("出库成功", c)
+}

+ 5 - 5
server/api/v1/storehouse/place.go

@@ -2,7 +2,7 @@ package storehouse
 
 import (
 	"github.com/gin-gonic/gin"
-	"server/dao"
+	"server/dao/godown"
 	"server/global"
 	"server/model/common/request"
 	"server/model/common/response"
@@ -43,7 +43,7 @@ func (pa *PlaceApi) QueryPlaceList(c *gin.Context) {
 }
 
 func (pa *PlaceApi) CreatePlace(c *gin.Context) {
-	var place dao.Place
+	var place godown.Place
 	err := c.ShouldBindJSON(&place)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -60,7 +60,7 @@ func (pa *PlaceApi) CreatePlace(c *gin.Context) {
 }
 
 func (pa *PlaceApi) UpdatePlace(c *gin.Context) {
-	var place dao.Place
+	var place godown.Place
 	err := c.ShouldBindJSON(&place)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -77,7 +77,7 @@ func (pa *PlaceApi) UpdatePlace(c *gin.Context) {
 }
 
 func (pa *PlaceApi) SwitchPlace(c *gin.Context) {
-	var place dao.Place
+	var place godown.Place
 	err := c.ShouldBindJSON(&place)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -94,7 +94,7 @@ func (pa *PlaceApi) SwitchPlace(c *gin.Context) {
 }
 
 func (pa *PlaceApi) DeletePlace(c *gin.Context) {
-	var place dao.Place
+	var place godown.Place
 	err := c.ShouldBindJSON(&place)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)

+ 5 - 5
server/api/v1/storehouse/storageArea.go

@@ -2,7 +2,7 @@ package storehouse
 
 import (
 	"github.com/gin-gonic/gin"
-	"server/dao"
+	"server/dao/godown"
 	"server/global"
 	"server/model/common/request"
 	"server/model/common/response"
@@ -43,7 +43,7 @@ func (ssa *StorageAreaApi) QueryStorageAreaList(c *gin.Context) {
 }
 
 func (ssa *StorageAreaApi) CreateStorageArea(c *gin.Context) {
-	var area dao.StorageArea
+	var area godown.StorageArea
 	err := c.ShouldBindJSON(&area)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -60,7 +60,7 @@ func (ssa *StorageAreaApi) CreateStorageArea(c *gin.Context) {
 }
 
 func (ssa *StorageAreaApi) UpdateStorageArea(c *gin.Context) {
-	var area dao.StorageArea
+	var area godown.StorageArea
 	err := c.ShouldBindJSON(&area)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -77,7 +77,7 @@ func (ssa *StorageAreaApi) UpdateStorageArea(c *gin.Context) {
 }
 
 func (ssa *StorageAreaApi) SwitchStorageArea(c *gin.Context) {
-	var area dao.StorageArea
+	var area godown.StorageArea
 	err := c.ShouldBindJSON(&area)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -94,7 +94,7 @@ func (ssa *StorageAreaApi) SwitchStorageArea(c *gin.Context) {
 }
 
 func (ssa *StorageAreaApi) DeleteStorageArea(c *gin.Context) {
-	var area dao.StorageArea
+	var area godown.StorageArea
 	err := c.ShouldBindJSON(&area)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)

+ 4 - 4
server/api/v1/storehouse/storageAreaGenre.go

@@ -2,7 +2,7 @@ package storehouse
 
 import (
 	"github.com/gin-gonic/gin"
-	"server/dao"
+	"server/dao/godown"
 	"server/global"
 	"server/model/common/response"
 )
@@ -20,7 +20,7 @@ func (saga *StorageAreaGenreApi) QueryAllStorageAreaGenre(c *gin.Context) {
 }
 
 func (saga *StorageAreaGenreApi) CreateStorageAreaGenre(c *gin.Context) {
-	var genre dao.StorageAreaGenre
+	var genre godown.StorageAreaGenre
 	err := c.ShouldBindJSON(&genre)
 	if err != nil {
 		response.FailWithMessage("参数错误", c)
@@ -37,7 +37,7 @@ func (saga *StorageAreaGenreApi) CreateStorageAreaGenre(c *gin.Context) {
 }
 
 func (saga *StorageAreaGenreApi) UpdateStorageAreaGenre(c *gin.Context) {
-	var genre dao.StorageAreaGenre
+	var genre godown.StorageAreaGenre
 	err := c.ShouldBindJSON(&genre)
 	if err != nil {
 		response.FailWithMessage("参数错误", c)
@@ -54,7 +54,7 @@ func (saga *StorageAreaGenreApi) UpdateStorageAreaGenre(c *gin.Context) {
 }
 
 func (saga *StorageAreaGenreApi) DeleteStorageAreaGenre(c *gin.Context) {
-	var genre dao.StorageAreaGenre
+	var genre godown.StorageAreaGenre
 	err := c.ShouldBindJSON(&genre)
 	if err != nil {
 		response.FailWithMessage("参数错误", c)

+ 4 - 4
server/api/v1/storehouse/supplier.go

@@ -2,7 +2,7 @@ package storehouse
 
 import (
 	"github.com/gin-gonic/gin"
-	"server/dao"
+	"server/dao/godown"
 	"server/global"
 	"server/model/common/request"
 	"server/model/common/response"
@@ -43,7 +43,7 @@ func (sa *SupplierApi) QuerySupplierList(c *gin.Context) {
 }
 
 func (sa *SupplierApi) CreateSupplier(c *gin.Context) {
-	var supplier dao.Supplier
+	var supplier godown.Supplier
 	err := c.ShouldBindJSON(&supplier)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -60,7 +60,7 @@ func (sa *SupplierApi) CreateSupplier(c *gin.Context) {
 }
 
 func (sa *SupplierApi) UpdateSupplier(c *gin.Context) {
-	var supplier dao.Supplier
+	var supplier godown.Supplier
 	err := c.ShouldBindJSON(&supplier)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -77,7 +77,7 @@ func (sa *SupplierApi) UpdateSupplier(c *gin.Context) {
 }
 
 func (sa *SupplierApi) DeleteSupplier(c *gin.Context) {
-	var supplier dao.Supplier
+	var supplier godown.Supplier
 	err := c.ShouldBindJSON(&supplier)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)

+ 5 - 5
server/api/v1/storehouse/warehouse.go

@@ -2,7 +2,7 @@ package storehouse
 
 import (
 	"github.com/gin-gonic/gin"
-	"server/dao"
+	"server/dao/godown"
 	"server/global"
 	"server/model/common/request"
 	"server/model/common/response"
@@ -43,7 +43,7 @@ func (wa *WarehouseApi) QueryWarehouseList(c *gin.Context) {
 }
 
 func (wa *WarehouseApi) CreateWarehouse(c *gin.Context) {
-	var warehouse dao.Warehouse
+	var warehouse godown.Warehouse
 	err := c.ShouldBindJSON(&warehouse)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -60,7 +60,7 @@ func (wa *WarehouseApi) CreateWarehouse(c *gin.Context) {
 }
 
 func (wa *WarehouseApi) UpdateWarehouse(c *gin.Context) {
-	var warehouse dao.Warehouse
+	var warehouse godown.Warehouse
 	err := c.ShouldBindJSON(&warehouse)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -77,7 +77,7 @@ func (wa *WarehouseApi) UpdateWarehouse(c *gin.Context) {
 }
 
 func (wa *WarehouseApi) SwitchWarehouse(c *gin.Context) {
-	var warehouse dao.Warehouse
+	var warehouse godown.Warehouse
 	err := c.ShouldBindJSON(&warehouse)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -94,7 +94,7 @@ func (wa *WarehouseApi) SwitchWarehouse(c *gin.Context) {
 }
 
 func (wa *WarehouseApi) DeleteWarehouse(c *gin.Context) {
-	var warehouse dao.Warehouse
+	var warehouse godown.Warehouse
 	err := c.ShouldBindJSON(&warehouse)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)

+ 4 - 4
server/api/v1/workflow/node.go

@@ -104,14 +104,14 @@ func (na *NodeApi) DeleteNode(c *gin.Context) {
 	err := c.ShouldBindJSON(&node)
 	if err != nil {
 		response.FailWithMessage("参数错误", c)
-		global.GVA_LOG.Error("UpdateNode ====== " + err.Error())
+		global.GVA_LOG.Error("DeleteNode ====== " + err.Error())
 		return
 	}
 	err = nodeService.DeleteNode(node)
 	if err != nil {
-		if err.Error() == "节点被使用" {
-			response.FailWithMessage("节点被使用", c)
-			global.GVA_LOG.Error("UpdateNode ====== " + err.Error())
+		if err.Error() == "节点被使用" {
+			response.FailWithMessage("节点被使用", c)
+			global.GVA_LOG.Error("DeleteNode ====== " + err.Error())
 			return
 		}
 		response.FailWithMessage("删除失败", c)

+ 1 - 1
server/config.yaml

@@ -125,7 +125,7 @@ mysql:
     config: charset=utf8mb4&parseTime=True&loc=Local
     db-name: lc_finance
     username: root
-    password: 123456
+    password: root
     path: 127.0.0.1
     engine: ""
     log-mode: error

+ 21 - 0
server/dao/godown/cargo.go

@@ -0,0 +1,21 @@
+package godown
+
+import "server/global"
+
+type Cargo struct {
+	global.GVA_MODEL
+	CommodityId   int         `json:"commodityId" gorm:"comment:商品id"`
+	Commodity     Commodity   `json:"commodity" gorm:"foreignKey:CommodityId;references:id;"`
+	Number        int         `json:"number" gorm:"comment:数量"`
+	ManifestId    int         `json:"manifestId" gorm:"comment:货单id"`
+	WarehouseId   int         `json:"warehouseId" gorm:"comment:仓库id"`
+	Warehouse     Warehouse   `json:"warehouse" gorm:"foreignKey:WarehouseId;references:id;"`
+	StorageAreaId int         `json:"storageAreaId" gorm:"comment:库区id"`
+	StorageArea   StorageArea `json:"storageArea" gorm:"foreignKey:StorageAreaId;references:id;"`
+	PlaceId       int         `json:"placeId" gorm:"comment:库位id"`
+	Place         Place       `json:"place" gorm:"foreignKey:PlaceId;references:id;"`
+}
+
+func (Cargo) TableName() string {
+	return "cargo"
+}

+ 5 - 2
server/dao/commodity.go

@@ -1,6 +1,8 @@
-package dao
+package godown
 
-import "server/global"
+import (
+	"server/global"
+)
 
 type Commodity struct {
 	global.GVA_MODEL
@@ -10,6 +12,7 @@ type Commodity struct {
 	Genre          int            `json:"genre" form:"genre" gorm:"comment:商品类型id"`
 	CommodityGenre CommodityGenre `json:"commodityGenre" form:"commodityGenre" gorm:"foreignKey:Genre;references:id;"`
 	UnitPrice      float64        `json:"unitPrice" form:"unitPrice" gorm:"comment:单价"`
+	Unity          string         `json:"unity" form:"unity" gorm:"comment:单位"`
 	Remark         string         `json:"remark" form:"remark" gorm:"comment:备注"`
 }
 

+ 3 - 2
server/dao/commodityGenre.go

@@ -1,10 +1,11 @@
-package dao
+package godown
 
 import "server/global"
 
 type CommodityGenre struct {
 	global.GVA_MODEL
-	Name string `json:"name" form:"name" gorm:"comment:商品类目名称"`
+	Name    string `json:"name" form:"name" gorm:"comment:商品类目名称"`
+	Remarks string `json:"remarks" form:"remarks" gorm:"comment:备注"`
 }
 
 func (CommodityGenre) TableName() string {

+ 76 - 0
server/dao/godown/goods.go

@@ -0,0 +1,76 @@
+package godown
+
+import (
+	"server/global"
+)
+
+type Goods struct {
+	global.GVA_MODEL
+	CommodityId   int         `json:"commodityId" gorm:"comment:商品id"`
+	Commodity     Commodity   `json:"commodity" gorm:"foreignKey:CommodityId;references:id;"`
+	Number        int         `json:"number" gorm:"comment:数量"`
+	WarehouseId   int         `json:"warehouseId" gorm:"comment:仓库id"`
+	Warehouse     Warehouse   `json:"warehouse" gorm:"foreignKey:WarehouseId;references:id;"`
+	StorageAreaId int         `json:"storageAreaId" gorm:"comment:库区id"`
+	StorageArea   StorageArea `json:"storageArea" gorm:"foreignKey:StorageAreaId;references:id;"`
+	PlaceId       int         `json:"placeId" gorm:"comment:库位id"`
+	Place         Place       `json:"place" gorm:"foreignKey:PlaceId;references:id;"`
+}
+
+func (Goods) TableName() string {
+	return "goods"
+}
+
+func QueryAllGoods() (goods []Goods, err error) {
+	err = global.GVA_DB.Model(&Goods{}).Preload("Commodity").Preload("Warehouse").Preload("StorageArea").Preload("Place").Find(&goods).Error
+	return
+}
+
+func QueryGoodsList(limit, offset, commodityId, warehouseId, storageAreaId, placeId int) (goods []Goods, total int64, err error) {
+	// 创建db
+	db := global.GVA_DB.Model(&Goods{}).Debug()
+	// 如果有条件搜索 下方会自动创建搜索语句
+
+	if commodityId != 0 {
+		db = db.Where("commodity_id = ?", commodityId)
+	}
+	if warehouseId != 0 {
+		db = db.Where("warehouse_id = ?", warehouseId)
+	}
+	if storageAreaId != 0 {
+		db = db.Where("storage_area_id = ?", storageAreaId)
+	}
+	if placeId != 0 {
+		db = db.Where("place_id = ?", placeId)
+	}
+
+	err = db.Count(&total).Error
+	if err != nil {
+		return
+	}
+	err = db.Order("id desc").Limit(limit).Offset(offset).Preload("Commodity").Preload("Warehouse").Preload("StorageArea").Preload("Place").Find(&goods).Error
+	return goods, total, err
+}
+
+func GetInventory(commodityId, warehouseId, storageAreaId, placeId int) (goods Goods, commodity Commodity, place Place) {
+	global.GVA_DB.Model(&Goods{}).
+		Where("commodity_id = ? AND warehouse_id = ? AND storage_area_id = ? AND place_id = ?",
+			commodityId, warehouseId, storageAreaId, placeId).
+		First(&goods)
+
+	global.GVA_DB.First(&commodity, commodityId)
+	global.GVA_DB.First(&place, placeId)
+	return
+}
+
+func (g Goods) CreateGoods() error {
+	return global.GVA_DB.Create(&g).Error
+}
+
+func (g Goods) UpdateGoods() error {
+	return global.GVA_DB.Where("id = ?", g.ID).Updates(&g).Error
+}
+
+func DeleteGoods(id int) error {
+	return global.GVA_DB.Where("id = ?", id).Unscoped().Delete(&Goods{}).Error
+}

+ 149 - 0
server/dao/godown/manifest.go

@@ -0,0 +1,149 @@
+package godown
+
+import (
+	"errors"
+	"fmt"
+	"gorm.io/gorm"
+	"server/global"
+)
+
+type Manifest struct {
+	global.GVA_MODEL
+	ManifestGenre string  `json:"manifestGenre" gorm:"comment:'货单类型'"`
+	Title         string  `json:"title" gorm:"comment:'标题'"`
+	Cargos        []Cargo `json:"cargos" gorm:"foreignKey:ManifestId"`
+	Custodian     string  `json:"custodian" gorm:"comment:管理人"`
+}
+
+func (Manifest) TableName() string {
+	return "manifest"
+}
+
+func QueryAllManifest() (manifests []Manifest, err error) {
+	err = global.GVA_DB.Model(&Manifest{}).Find(&manifests).Error
+	return
+}
+
+func QueryManifestList(limit, offset int, genre, title string) (manifests []Manifest, total int64, err error) {
+	// 创建db
+	db := global.GVA_DB.Model(&Manifest{})
+	// 如果有条件搜索 下方会自动创建搜索语句
+
+	if genre != "" {
+		db = db.Where("manifest_genre LIKE ?", "%"+genre+"%")
+	}
+	if title != "" {
+		db = db.Where("title LIKE ?", "%"+title+"%")
+	}
+
+	err = db.Count(&total).Error
+	if err != nil {
+		return
+	}
+	err = db.Order("id desc").Limit(limit).Offset(offset).Preload("Cargos").Preload("Cargos.Commodity").Preload("Cargos.Warehouse").Find(&manifests).Error
+	return manifests, total, err
+}
+
+func (m Manifest) CreateManifest() error {
+	return global.GVA_DB.Create(&m).Error
+}
+
+func (m Manifest) UpdateManifest() error {
+	return global.GVA_DB.Where("id = ?", m.ID).Updates(&m).Error
+}
+
+func DeleteManifest(id int) error {
+	return global.GVA_DB.Where("id = ?", id).Unscoped().Delete(&Manifest{}).Error
+}
+
+// CreateInboundManifest 入库
+func CreateInboundManifest(manifestGenre, title, custodian string, cargos []Cargo) error {
+	// 开启事务
+	return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
+		// 1. 创建入库货单
+		manifest := Manifest{
+			ManifestGenre: manifestGenre, // 如 "采购入库"
+			Title:         title,
+			Custodian:     custodian,
+			Cargos:        cargos,
+		}
+		if err := tx.Create(&manifest).Error; err != nil {
+			return fmt.Errorf("创建货单失败: %v", err)
+		}
+
+		// 2. 更新库存(逐个货物处理)
+		for _, cargo := range manifest.Cargos {
+			// 检查是否已存在相同商品、仓库、库区、库位的记录
+			var goods Goods
+			err := tx.Where("commodity_id = ? AND warehouse_id = ? AND storage_area_id = ? AND place_id = ?",
+				cargo.CommodityId, cargo.WarehouseId, cargo.StorageAreaId, cargo.PlaceId).
+				First(&goods).Error
+
+			if err == nil {
+				// 存在记录:增加数量
+				goods.Number += cargo.Number
+				if err := tx.Save(&goods).Error; err != nil {
+					return fmt.Errorf("更新库存失败: %v", err)
+				}
+			} else if errors.Is(err, gorm.ErrRecordNotFound) {
+				// 不存在记录:新建库存
+				newGoods := Goods{
+					CommodityId:   cargo.CommodityId,
+					Number:        cargo.Number,
+					WarehouseId:   cargo.WarehouseId,
+					StorageAreaId: cargo.StorageAreaId,
+					PlaceId:       cargo.PlaceId,
+				}
+				if err := tx.Create(&newGoods).Error; err != nil {
+					return fmt.Errorf("创建库存失败: %v", err)
+				}
+			} else {
+				return fmt.Errorf("查询库存失败: %v", err)
+			}
+		}
+		return nil
+	})
+}
+
+// CreateOutboundManifest 出库
+func CreateOutboundManifest(manifestGenre, title, custodian string, cargos []Cargo) error {
+	// 开启事务
+	return global.GVA_DB.Transaction(func(tx *gorm.DB) error {
+		// 1. 检查库存是否充足(预扣减检查)
+		for _, cargo := range cargos {
+			var goods Goods
+			if err := tx.Where("commodity_id = ? AND warehouse_id = ? AND storage_area_id = ? AND place_id = ?",
+				cargo.CommodityId, cargo.WarehouseId, cargo.StorageAreaId, cargo.PlaceId).
+				First(&goods).Error; err != nil {
+				return fmt.Errorf("库存记录不存在: %v", err)
+			}
+			if goods.Number < cargo.Number {
+				return fmt.Errorf("商品 %v 库存不足(当前: %d,需要: %d)",
+					cargo.Commodity.Name, goods.Number, cargo.Number)
+			}
+		}
+
+		// 2. 创建出库货单
+		manifest := Manifest{
+			ManifestGenre: manifestGenre, // 如 "销售出库"
+			Title:         title,
+			Custodian:     custodian,
+			Cargos:        cargos,
+		}
+		if err := tx.Create(&manifest).Error; err != nil {
+			return fmt.Errorf("创建货单失败: %v", err)
+		}
+
+		// 3. 扣减库存
+		for _, cargo := range manifest.Cargos {
+			if err := tx.Model(&Goods{}).
+				Where("commodity_id = ? AND warehouse_id = ? AND storage_area_id = ? AND place_id = ?",
+					cargo.CommodityId, cargo.WarehouseId, cargo.StorageAreaId, cargo.PlaceId).
+				Update("number", gorm.Expr("number - ?", cargo.Number)).
+				Error; err != nil {
+				return fmt.Errorf("扣减库存失败: %v", err)
+			}
+		}
+		return nil
+	})
+}

+ 16 - 14
server/dao/place.go

@@ -1,19 +1,21 @@
-package dao
+package godown
 
-import "server/global"
+import (
+	"server/global"
+)
 
 type Place struct {
 	global.GVA_MODEL
-	Code             string           `json:"code" form:"code" gorm:"comment:库位编码"`
-	ShelfNumber      string           `json:"shelfNumber" form:"shelfNumber" gorm:"comment:货架号"`
-	LayerNumber      string           `json:"layerNumber" form:"layerNumber" gorm:"comment:层号"`
-	Genre            int              `json:"genre" form:"genre" gorm:"comment:库区类型"`
-	StorageAreaGenre StorageAreaGenre `json:"storageAreaGenre" form:"storageAreaGenre" gorm:"foreignKey:Genre;references:id;"`
-	StorageAreaID    int              `json:"storageAreaId" form:"storageAreaId" gorm:"comment:所属库区id"`
-	StorageArea      StorageArea      `json:"storageArea" form:"storageArea" gorm:"foreignKey:StorageAreaID;references:id;"`
-	WarehouseId      int              `json:"warehouseId" form:"warehouseId" gorm:"comment:仓库"`
-	Warehouse        Warehouse        `json:"warehouse" form:"warehouse" gorm:"foreignKey:WarehouseId;references:id;"`
-	IsEffective      bool             `json:"isEffective" form:"isEffective" gorm:"comment:是否有效;default:0"`
+	Code           string         `json:"code" form:"code" gorm:"comment:库位编码"`
+	ShelfNumber    string         `json:"shelfNumber" form:"shelfNumber" gorm:"comment:货架号"`
+	LayerNumber    string         `json:"layerNumber" form:"layerNumber" gorm:"comment:层号"`
+	Genre          int            `json:"genre" form:"genre" gorm:"comment:商品类型"`
+	CommodityGenre CommodityGenre `json:"commodityGenre" form:"commodityGenre" gorm:"foreignKey:Genre;references:id;"`
+	StorageAreaID  int            `json:"storageAreaId" form:"storageAreaId" gorm:"comment:所属库区id"`
+	StorageArea    StorageArea    `json:"storageArea" form:"storageArea" gorm:"foreignKey:StorageAreaID;references:id;"`
+	WarehouseId    int            `json:"warehouseId" form:"warehouseId" gorm:"comment:仓库"`
+	Warehouse      Warehouse      `json:"warehouse" form:"warehouse" gorm:"foreignKey:WarehouseId;references:id;"`
+	IsEffective    bool           `json:"isEffective" form:"isEffective" gorm:"comment:是否有效;default:0"`
 }
 
 func (Place) TableName() string {
@@ -39,14 +41,14 @@ func QueryPlaceList(limit, offset, genre, warehouseId, storageAreaId int, name s
 		db = db.Where("warehouse_id = ?", warehouseId)
 	}
 	if name != "" {
-		db = db.Where("name LIKE ?", "%"+name+"%")
+		db = db.Where("code LIKE ?", "%"+name+"%")
 	}
 
 	err = db.Count(&total).Error
 	if err != nil {
 		return
 	}
-	err = db.Order("id desc").Limit(limit).Offset(offset).Preload("StorageArea").Preload("Warehouse").Preload("StorageAreaGenre").Find(&places).Error
+	err = db.Order("id desc").Limit(limit).Offset(offset).Preload("StorageArea").Preload("Warehouse").Preload("CommodityGenre").Find(&places).Error
 	return places, total, err
 }
 

+ 10 - 9
server/dao/storageArea.go

@@ -1,4 +1,4 @@
-package dao
+package godown
 
 import (
 	"server/global"
@@ -6,12 +6,13 @@ import (
 
 type StorageArea struct {
 	global.GVA_MODEL
-	Name             string           `json:"name" form:"name" gorm:"comment:库区名称"`
-	Genre            int              `json:"genre" form:"genre" gorm:"comment:库区类型"`
-	StorageAreaGenre StorageAreaGenre `json:"storageAreaGenre" form:"storageAreaGenre" gorm:"foreignKey:Genre;references:id;"`
-	WarehouseId      int              `json:"warehouseId" form:"warehouseId" gorm:"comment:仓库"`
-	Warehouse        Warehouse        `json:"warehouse" form:"warehouse" gorm:"foreignKey:WarehouseId;references:id;"`
-	IsEffective      bool             `json:"isEffective" form:"isEffective" gorm:"comment:是否有效;default:0"`
+	Name           string         `json:"name" form:"name" gorm:"comment:库区名称"`
+	Genre          int            `json:"genre" form:"genre" gorm:"comment:库区类型"`
+	CommodityGenre CommodityGenre `json:"commodityGenre" form:"commodityGenre" gorm:"foreignKey:Genre;references:id;"`
+	WarehouseId    int            `json:"warehouseId" form:"warehouseId" gorm:"comment:仓库"`
+	Warehouse      Warehouse      `json:"warehouse" form:"warehouse" gorm:"foreignKey:WarehouseId;references:id;"`
+	IsEffective    bool           `json:"isEffective" form:"isEffective" gorm:"comment:是否有效;default:0"`
+	Places         []Place        `json:"places" form:"places" gorm:"foreignKey:StorageAreaID;"`
 }
 
 func (StorageArea) TableName() string {
@@ -19,7 +20,7 @@ func (StorageArea) TableName() string {
 }
 
 func QueryAllStorageArea() (storageAreas []StorageArea, err error) {
-	err = global.GVA_DB.Where("is_effective = true").Preload("StorageAreaGenre").Find(&storageAreas).Error
+	err = global.GVA_DB.Where("is_effective = true").Preload("CommodityGenre").Find(&storageAreas).Error
 	return storageAreas, err
 }
 
@@ -41,7 +42,7 @@ func QueryStorageAreaList(limit, offset, genre, warehouseId int, name string) (s
 	if err != nil {
 		return
 	}
-	err = db.Order("id desc").Limit(limit).Offset(offset).Preload("Warehouse").Preload("StorageAreaGenre").Find(&storageAreas).Error
+	err = db.Order("id desc").Limit(limit).Offset(offset).Preload("Warehouse").Preload("CommodityGenre").Find(&storageAreas).Error
 	return storageAreas, total, err
 }
 

+ 2 - 2
server/dao/storageAreaGenre.go

@@ -1,10 +1,10 @@
-package dao
+package godown
 
 import "server/global"
 
 type StorageAreaGenre struct {
 	global.GVA_MODEL
-	Name string `json:"name" form:"name" gorm:"comment:库类目名称"`
+	Name string `json:"name" form:"name" gorm:"comment:库类目名称"`
 }
 
 func (StorageAreaGenre) TableName() string {

+ 2 - 2
server/dao/supplier.go

@@ -1,4 +1,4 @@
-package dao
+package godown
 
 import "server/global"
 
@@ -25,7 +25,7 @@ func QueryAllSupplier() ([]Supplier, error) {
 
 func QuerySupplierList(limit, offset int, name string) (suppliers []Supplier, total int64, err error) {
 	// 创建db
-	db := global.GVA_DB.Model(&Supplier{}).Debug()
+	db := global.GVA_DB.Model(&Supplier{})
 	// 如果有条件搜索 下方会自动创建搜索语句
 
 	if name != "" {

+ 8 - 7
server/dao/warehouse.go

@@ -1,14 +1,15 @@
-package dao
+package godown
 
 import "server/global"
 
 type Warehouse struct {
 	global.GVA_MODEL
-	Name        string `json:"name" form:"name" gorm:"comment:库房名称"`
-	Location    string `json:"location" form:"location" gorm:"comment:库房位置"`
-	Head        string `json:"head" form:"head" gorm:"comment:负责人"`
-	Remarks     string `json:"remarks" form:"remarks" gorm:"comment:备注"`
-	IsEffective bool   `json:"isEffective" form:"isEffective" gorm:"comment:是否有效;default:0"`
+	Name         string        `json:"name" form:"name" gorm:"comment:库房名称"`
+	Location     string        `json:"location" form:"location" gorm:"comment:库房位置"`
+	Head         string        `json:"head" form:"head" gorm:"comment:负责人"`
+	Remarks      string        `json:"remarks" form:"remarks" gorm:"comment:备注"`
+	IsEffective  bool          `json:"isEffective" form:"isEffective" gorm:"comment:是否有效;default:0"`
+	StorageAreas []StorageArea `json:"storageAreas" form:"storageAreas" gorm:"foreignKey:WarehouseId"`
 }
 
 func (Warehouse) TableName() string {
@@ -16,7 +17,7 @@ func (Warehouse) TableName() string {
 }
 
 func QueryAllWarehouse() (warehouse []Warehouse, err error) {
-	err = global.GVA_DB.Where("is_effective = true").Model(&Warehouse{}).Find(&warehouse).Error
+	err = global.GVA_DB.Where("is_effective = true").Model(&Warehouse{}).Preload("StorageAreas").Preload("StorageAreas.Places").Find(&warehouse).Error
 	return warehouse, err
 }
 

+ 11 - 7
server/initialize/gorm.go

@@ -4,6 +4,7 @@ import (
 	"os"
 	"server/dao"
 	"server/dao/crm"
+	"server/dao/godown"
 	"server/dao/system"
 
 	"go.uber.org/zap"
@@ -78,13 +79,16 @@ func RegisterTables() {
 		dao.ProjectProcess{},
 		dao.ProcessNodes{},
 
-		dao.Commodity{},
-		dao.CommodityGenre{},
-		dao.Supplier{},
-		dao.Warehouse{},
-		dao.Place{},
-		dao.StorageArea{},
-		dao.StorageAreaGenre{},
+		godown.Commodity{},
+		godown.CommodityGenre{},
+		godown.Supplier{},
+		godown.Warehouse{},
+		godown.Place{},
+		godown.StorageArea{},
+		godown.StorageAreaGenre{},
+		godown.Manifest{},
+		godown.Cargo{},
+		godown.Goods{},
 
 		crm.Customer{},
 		crm.CustomerGenre{},

+ 2 - 0
server/initialize/router.go

@@ -111,6 +111,8 @@ func Routers() *gin.Engine {
 		storehouseRouter.InitPlaceRouter(PrivateGroup)
 		storehouseRouter.InitStorageAreaRouter(PrivateGroup)
 		storehouseRouter.InitStorageAreaGenreRouter(PrivateGroup)
+		storehouseRouter.InitManifestRouter(PrivateGroup)
+		storehouseRouter.InitGoodsRouter(PrivateGroup)
 
 		crmRouter.InitCustomerRouter(PrivateGroup)
 		crmRouter.InitCustomerGenreRouter(PrivateGroup)

+ 21 - 0
server/model/common/request/common.go

@@ -144,4 +144,25 @@ type SearchCustomer struct {
 	Name     string   `json:"name" form:"name"`
 }
 
+type SearchManifest struct {
+	PageInfo PageInfo `json:"pageInfo" form:"pageInfo"`
+	Genre    string   `json:"genre" form:"genre"`
+	Title    string   `json:"title" form:"title"`
+}
+
+type SearchGoods struct {
+	PageInfo      PageInfo `json:"pageInfo" form:"pageInfo"`
+	CommodityId   int      `json:"commodityId" form:"commodityId"`
+	WarehouseId   int      `json:"warehouseId" form:"warehouseId"`
+	StorageAreaId int      `json:"storageAreaId" form:"storageAreaId"`
+	PlaceId       int      `json:"placeId" form:"placeId"`
+}
+
+type GetInventoryRequest struct {
+	CommodityId   int `form:"commodityId" binding:"required"`
+	WarehouseId   int `form:"warehouseId" binding:"required"`
+	StorageAreaId int `form:"storageAreaId" binding:"required"`
+	PlaceId       int `form:"placeId" binding:"required"`
+}
+
 type Empty struct{}

+ 7 - 0
server/model/common/response/common.go

@@ -6,3 +6,10 @@ type PageResult struct {
 	Page     int         `json:"page"`
 	PageSize int         `json:"pageSize"`
 }
+
+// 响应结构体
+type InventoryResponse struct {
+	Number        int    `json:"number"`        // 当前库存数量
+	CommodityName string `json:"commodityName"` // 商品名称(可选)
+	Location      string `json:"location"`      // 位置描述(可选)
+}

+ 2 - 0
server/router/storehouse/enter.go

@@ -8,4 +8,6 @@ type RouterGroup struct {
 	PlaceRouter
 	StorageAreaRouter
 	StorageAreaGenreRouter
+	ManifestRouter
+	GoodsRouter
 }

+ 22 - 0
server/router/storehouse/goods.go

@@ -0,0 +1,22 @@
+package storehouse
+
+import (
+	"github.com/gin-gonic/gin"
+	v1 "server/api/v1"
+)
+
+type GoodsRouter struct{}
+
+func (s *GoodsRouter) InitGoodsRouter(Router *gin.RouterGroup) {
+	//goodsRouter := Router.Group("goods").Use(middleware.OperationRecord())
+	goodsRouterWithoutRecord := Router.Group("goods")
+
+	goodsApi := v1.ApiGroupApp.StorehouseApiGroup.GoodsApi
+	{
+	}
+	{
+		goodsRouterWithoutRecord.GET("queryAllGoods", goodsApi.QueryAllGoods)
+		goodsRouterWithoutRecord.POST("queryGoodsList", goodsApi.QueryGoodsList)
+		goodsRouterWithoutRecord.POST("getInventory", goodsApi.GetInventory)
+	}
+}

+ 27 - 0
server/router/storehouse/manifest.go

@@ -0,0 +1,27 @@
+package storehouse
+
+import (
+	"github.com/gin-gonic/gin"
+	v1 "server/api/v1"
+	"server/middleware"
+)
+
+type ManifestRouter struct{}
+
+func (s *ManifestRouter) InitManifestRouter(Router *gin.RouterGroup) {
+	manifestRouter := Router.Group("manifest").Use(middleware.OperationRecord())
+	manifestRouterWithoutRecord := Router.Group("manifest")
+
+	manifestApi := v1.ApiGroupApp.StorehouseApiGroup.ManifestApi
+	{
+		manifestRouter.POST("createManifest", manifestApi.CreateManifest)
+		manifestRouter.PUT("updateManifest", manifestApi.UpdateManifest)
+		manifestRouter.DELETE("deleteManifest", manifestApi.DeleteManifest)
+		manifestRouter.POST("createOutboundManifest", manifestApi.CreateOutboundManifest)
+		manifestRouter.POST("createInboundManifest", manifestApi.CreateInboundManifest)
+	}
+	{
+		manifestRouterWithoutRecord.GET("queryAllManifest", manifestApi.QueryAllManifest)
+		manifestRouterWithoutRecord.POST("queryManifestList", manifestApi.QueryManifestList)
+	}
+}

+ 1 - 1
server/router/storehouse/storageArea.go

@@ -16,7 +16,7 @@ func (sar *StorageAreaRouter) InitStorageAreaRouter(Router *gin.RouterGroup) {
 	{
 		storageAreaRouter.POST("createStorageArea", storageAreaApi.CreateStorageArea)
 		storageAreaRouter.PUT("updateStorageArea", storageAreaApi.UpdateStorageArea)
-		storageAreaRouter.POST("switchStorageArea", storageAreaApi.SwitchStorageArea)
+		storageAreaRouter.PUT("switchStorageArea", storageAreaApi.SwitchStorageArea)
 		storageAreaRouter.DELETE("deleteStorageArea", storageAreaApi.DeleteStorageArea)
 	}
 	{

+ 7 - 7
server/service/storehouse/commodity.go

@@ -1,30 +1,30 @@
 package storehouse
 
 import (
-	"server/dao"
+	"server/dao/godown"
 	"server/model/common/request"
 )
 
 type CommodityService struct{}
 
-func (cs *CommodityService) QueryAllCommodity() ([]dao.Commodity, error) {
-	return dao.QueryAllCommodity()
+func (cs *CommodityService) QueryAllCommodity() ([]godown.Commodity, error) {
+	return godown.QueryAllCommodity()
 }
 
 func (cs *CommodityService) QueryCommodityList(info request.SearchCommodityList) (list interface{}, total int64, err error) {
 	limit := info.PageInfo.PageSize
 	offset := info.PageInfo.PageSize * (info.PageInfo.Page - 1)
-	return dao.QueryCommodityList(limit, offset, info.Name)
+	return godown.QueryCommodityList(limit, offset, info.Name)
 }
 
-func (cs *CommodityService) CreateCommodity(commodity dao.Commodity) error {
+func (cs *CommodityService) CreateCommodity(commodity godown.Commodity) error {
 	return commodity.CreateCommodity()
 }
 
-func (cs *CommodityService) UpdateCommodity(commodity dao.Commodity) error {
+func (cs *CommodityService) UpdateCommodity(commodity godown.Commodity) error {
 	return commodity.UpdateCommodity()
 }
 
-func (cs *CommodityService) DeleteCommodity(commodity dao.Commodity) error {
+func (cs *CommodityService) DeleteCommodity(commodity godown.Commodity) error {
 	return commodity.DeleteCommodity()
 }

+ 7 - 7
server/service/storehouse/commodityGenre.go

@@ -2,25 +2,25 @@ package storehouse
 
 import (
 	"fmt"
-	"server/dao"
+	"server/dao/godown"
 )
 
 type CommodityGenreService struct{}
 
-func (cgs *CommodityGenreService) QueryAllCommodityGenre() ([]dao.CommodityGenre, error) {
-	return dao.QueryAllCommodityGenres()
+func (cgs *CommodityGenreService) QueryAllCommodityGenre() ([]godown.CommodityGenre, error) {
+	return godown.QueryAllCommodityGenres()
 }
 
-func (cgs *CommodityGenreService) CreateCommodityGenre(cg dao.CommodityGenre) error {
+func (cgs *CommodityGenreService) CreateCommodityGenre(cg godown.CommodityGenre) error {
 	return cg.CreateCommodityGenre()
 }
 
-func (cgs *CommodityGenreService) UpdateCommodityGenre(cg dao.CommodityGenre) error {
+func (cgs *CommodityGenreService) UpdateCommodityGenre(cg godown.CommodityGenre) error {
 	return cg.UpdateCommodityGenre()
 }
 
-func (cgs *CommodityGenreService) DeleteCommodityGenre(cg dao.CommodityGenre) error {
-	commodity, err := dao.QueryCommodityByGenre(int(cg.ID))
+func (cgs *CommodityGenreService) DeleteCommodityGenre(cg godown.CommodityGenre) error {
+	commodity, err := godown.QueryCommodityByGenre(int(cg.ID))
 	if err != nil {
 		return err
 	}

+ 2 - 0
server/service/storehouse/enter.go

@@ -8,4 +8,6 @@ type ServiceGroup struct {
 	PlaceService
 	StorageAreaService
 	StorageAreaGenreService
+	ManifestService
+	GoodsService
 }

+ 35 - 0
server/service/storehouse/goods.go

@@ -0,0 +1,35 @@
+package storehouse
+
+import (
+	"fmt"
+	"server/dao/godown"
+	"server/model/common/request"
+	"server/model/common/response"
+)
+
+type GoodsService struct {
+}
+
+func (gs *GoodsService) QueryAllGoods() ([]godown.Goods, error) {
+	return godown.QueryAllGoods()
+}
+
+func (gs *GoodsService) QueryGoodsList(info request.SearchGoods) (interface{}, int64, error) {
+	limit := info.PageInfo.PageSize
+	offset := info.PageInfo.PageSize * (info.PageInfo.Page - 1)
+	return godown.QueryGoodsList(limit, offset, info.CommodityId, info.WarehouseId, info.StorageAreaId, info.PlaceId)
+}
+
+func (gs *GoodsService) GetInventory(req request.GetInventoryRequest) response.InventoryResponse {
+	goods, commodity, place := godown.GetInventory(req.CommodityId, req.WarehouseId, req.StorageAreaId, req.PlaceId)
+
+	// 4. 返回结果
+	return response.InventoryResponse{
+		Number:        goods.Number,
+		CommodityName: commodity.Name,
+		Location: fmt.Sprintf("仓库%d-%s-货架%s",
+			req.WarehouseId,
+			place.StorageArea.Name,
+			place.Code),
+	}
+}

+ 41 - 0
server/service/storehouse/manifest.go

@@ -0,0 +1,41 @@
+package storehouse
+
+import (
+	"server/dao/godown"
+	"server/model/common/request"
+)
+
+type ManifestService struct {
+}
+
+func (ms *ManifestService) QueryAllManifest() ([]godown.Manifest, error) {
+	return godown.QueryAllManifest()
+}
+
+func (ms *ManifestService) QueryManifestList(info request.SearchManifest) (list interface{}, total int64, err error) {
+	limit := info.PageInfo.PageSize
+	offset := info.PageInfo.PageSize * (info.PageInfo.Page - 1)
+	return godown.QueryManifestList(limit, offset, info.Genre, info.Title)
+}
+
+func (ms *ManifestService) CreateManifest(manifest godown.Manifest) error {
+	return manifest.CreateManifest()
+}
+
+func (ms *ManifestService) UpdateManifest(manifest godown.Manifest) error {
+	return manifest.UpdateManifest()
+}
+
+func (ms *ManifestService) DeleteManifest(id int) error {
+	return godown.DeleteManifest(id)
+}
+
+func (ms *ManifestService) CreateInboundManifest(manifest godown.Manifest) error {
+	manifest.ManifestGenre = "入库"
+	return godown.CreateInboundManifest(manifest.ManifestGenre, manifest.Title, manifest.Custodian, manifest.Cargos)
+}
+
+func (ms *ManifestService) CreateOutboundManifest(manifest godown.Manifest) error {
+	manifest.ManifestGenre = "出库"
+	return godown.CreateOutboundManifest(manifest.ManifestGenre, manifest.Title, manifest.Custodian, manifest.Cargos)
+}

+ 8 - 8
server/service/storehouse/place.go

@@ -1,34 +1,34 @@
 package storehouse
 
 import (
-	"server/dao"
+	"server/dao/godown"
 	"server/model/common/request"
 )
 
 type PlaceService struct{}
 
-func (p *PlaceService) QueryAllPlaces() ([]dao.Place, error) {
-	return dao.QueryAllPlace()
+func (p *PlaceService) QueryAllPlaces() ([]godown.Place, error) {
+	return godown.QueryAllPlace()
 }
 
 func (p *PlaceService) QueryPlaceList(info request.SearchPlace) (list interface{}, total int64, err error) {
 	limit := info.PageInfo.PageSize
 	offset := info.PageInfo.PageSize * (info.PageInfo.Page - 1)
-	return dao.QueryPlaceList(limit, offset, info.Genre, info.WarehouseId, info.StorageAreaId, info.Name)
+	return godown.QueryPlaceList(limit, offset, info.Genre, info.WarehouseId, info.StorageAreaId, info.Name)
 }
 
-func (p *PlaceService) CreatePlace(place dao.Place) error {
+func (p *PlaceService) CreatePlace(place godown.Place) error {
 	return place.CreatePlace()
 }
 
-func (p *PlaceService) UpdatePlace(place dao.Place) error {
+func (p *PlaceService) UpdatePlace(place godown.Place) error {
 	return place.UpdatePlace()
 }
 
-func (p *PlaceService) SwitchPlace(place dao.Place) error {
+func (p *PlaceService) SwitchPlace(place godown.Place) error {
 	return place.SwitchPlace()
 }
 
-func (p *PlaceService) DeletePlace(place dao.Place) error {
+func (p *PlaceService) DeletePlace(place godown.Place) error {
 	return place.DeletePlace()
 }

+ 8 - 8
server/service/storehouse/storageArea.go

@@ -1,34 +1,34 @@
 package storehouse
 
 import (
-	"server/dao"
+	"server/dao/godown"
 	"server/model/common/request"
 )
 
 type StorageAreaService struct{}
 
-func (s *StorageAreaService) QueryAllStorageArea() ([]dao.StorageArea, error) {
-	return dao.QueryAllStorageArea()
+func (s *StorageAreaService) QueryAllStorageArea() ([]godown.StorageArea, error) {
+	return godown.QueryAllStorageArea()
 }
 
 func (s *StorageAreaService) QueryStorageAreaList(info request.SearchStorageArea) (list interface{}, total int64, err error) {
 	limit := info.PageInfo.PageSize
 	offset := info.PageInfo.PageSize * (info.PageInfo.Page - 1)
-	return dao.QueryStorageAreaList(limit, offset, info.Genre, info.WarehouseId, info.Name)
+	return godown.QueryStorageAreaList(limit, offset, info.Genre, info.WarehouseId, info.Name)
 }
 
-func (s *StorageAreaService) CreateStorageArea(storageArea dao.StorageArea) error {
+func (s *StorageAreaService) CreateStorageArea(storageArea godown.StorageArea) error {
 	return storageArea.CreateStorageArea()
 }
 
-func (s *StorageAreaService) UpdateStorageArea(storageArea dao.StorageArea) error {
+func (s *StorageAreaService) UpdateStorageArea(storageArea godown.StorageArea) error {
 	return storageArea.UpdateStorageArea()
 }
 
-func (s *StorageAreaService) SwitchStorageArea(storageArea dao.StorageArea) error {
+func (s *StorageAreaService) SwitchStorageArea(storageArea godown.StorageArea) error {
 	return storageArea.SwitchStorageArea()
 }
 
-func (s *StorageAreaService) DeleteStorageArea(storageArea dao.StorageArea) error {
+func (s *StorageAreaService) DeleteStorageArea(storageArea godown.StorageArea) error {
 	return storageArea.DeleteStorageArea()
 }

+ 8 - 6
server/service/storehouse/storageAreaGenre.go

@@ -1,21 +1,23 @@
 package storehouse
 
-import "server/dao"
+import (
+	"server/dao/godown"
+)
 
 type StorageAreaGenreService struct{}
 
-func (sags *StorageAreaGenreService) QueryAllStorageAreaGenres() ([]dao.StorageAreaGenre, error) {
-	return dao.QueryAllStorageAreaGenres()
+func (sags *StorageAreaGenreService) QueryAllStorageAreaGenres() ([]godown.StorageAreaGenre, error) {
+	return godown.QueryAllStorageAreaGenres()
 }
 
-func (sags *StorageAreaGenreService) CreateStorageAreaGenre(sg dao.StorageAreaGenre) error {
+func (sags *StorageAreaGenreService) CreateStorageAreaGenre(sg godown.StorageAreaGenre) error {
 	return sg.CreateStorageAreaGenre()
 }
 
-func (sags *StorageAreaGenreService) UpdateStorageAreaGenre(sg dao.StorageAreaGenre) error {
+func (sags *StorageAreaGenreService) UpdateStorageAreaGenre(sg godown.StorageAreaGenre) error {
 	return sg.UpdateStorageAreaGenre()
 }
 
-func (sags *StorageAreaGenreService) DeleteStorageAreaGenre(sg dao.StorageAreaGenre) error {
+func (sags *StorageAreaGenreService) DeleteStorageAreaGenre(sg godown.StorageAreaGenre) error {
 	return sg.DeleteStorageAreaGenre()
 }

+ 7 - 7
server/service/storehouse/supplier.go

@@ -1,32 +1,32 @@
 package storehouse
 
 import (
-	"server/dao"
+	"server/dao/godown"
 	"server/model/common/request"
 )
 
 type SupplierService struct {
 }
 
-func (ss *SupplierService) QueryAllSupplier() ([]dao.Supplier, error) {
-	return dao.QueryAllSupplier()
+func (ss *SupplierService) QueryAllSupplier() ([]godown.Supplier, error) {
+	return godown.QueryAllSupplier()
 }
 
 func (ss *SupplierService) QuerySupplierList(info request.SearchSupplierList) (list interface{}, total int64, err error) {
 	limit := info.PageInfo.PageSize
 	offset := info.PageInfo.PageSize * (info.PageInfo.Page - 1)
-	suppliers, total, err := dao.QuerySupplierList(limit, offset, info.Name)
+	suppliers, total, err := godown.QuerySupplierList(limit, offset, info.Name)
 	return suppliers, total, err
 }
 
-func (ss *SupplierService) CreateSupplier(supplier dao.Supplier) error {
+func (ss *SupplierService) CreateSupplier(supplier godown.Supplier) error {
 	return supplier.CreateSupplier()
 }
 
-func (ss *SupplierService) UpdateSupplier(supplier dao.Supplier) error {
+func (ss *SupplierService) UpdateSupplier(supplier godown.Supplier) error {
 	return supplier.UpdateSupplier()
 }
 
-func (ss *SupplierService) DeleteSupplier(supplier dao.Supplier) error {
+func (ss *SupplierService) DeleteSupplier(supplier godown.Supplier) error {
 	return supplier.DeleteSupplier()
 }

+ 8 - 8
server/service/storehouse/warehouse.go

@@ -1,35 +1,35 @@
 package storehouse
 
 import (
-	"server/dao"
+	"server/dao/godown"
 	"server/model/common/request"
 )
 
 type WarehouseService struct{}
 
-func (ws *WarehouseService) QueryAllWarehouse() ([]dao.Warehouse, error) {
-	return dao.QueryAllWarehouse()
+func (ws *WarehouseService) QueryAllWarehouse() ([]godown.Warehouse, error) {
+	return godown.QueryAllWarehouse()
 }
 
 func (ws *WarehouseService) QueryWarehouseList(info request.SearchWarehouse) (list interface{}, total int64, err error) {
 	limit := info.PageInfo.PageSize
 	offset := info.PageInfo.PageSize * (info.PageInfo.Page - 1)
-	warehouse, total, err := dao.QueryWarehouseList(limit, offset, info.Name)
+	warehouse, total, err := godown.QueryWarehouseList(limit, offset, info.Name)
 	return warehouse, total, err
 }
 
-func (ws *WarehouseService) CreateWarehouse(warehouse dao.Warehouse) error {
+func (ws *WarehouseService) CreateWarehouse(warehouse godown.Warehouse) error {
 	return warehouse.CreateWarehouse()
 }
 
-func (ws *WarehouseService) UpdateWarehouse(warehouse dao.Warehouse) error {
+func (ws *WarehouseService) UpdateWarehouse(warehouse godown.Warehouse) error {
 	return warehouse.UpdateWarehouse()
 }
 
-func (ws *WarehouseService) SwitchWarehouse(warehouse dao.Warehouse) error {
+func (ws *WarehouseService) SwitchWarehouse(warehouse godown.Warehouse) error {
 	return warehouse.SwitchWarehouse()
 }
 
-func (ws *WarehouseService) DeleteWarehouse(warehouse dao.Warehouse) error {
+func (ws *WarehouseService) DeleteWarehouse(warehouse godown.Warehouse) error {
 	return warehouse.DeleteWarehouse()
 }

+ 55 - 1
web/src/api/storehouse.js

@@ -150,7 +150,7 @@ export const deleteWarehouse = (data) => {
 
 export const queryAllStorageArea = () => {
   return service({
-    url: '/storageArea/queryAllStorageArea',
+    url: '/storageArea/queryAllStorageAreas',
     method: 'get'
   })
 }
@@ -272,3 +272,57 @@ export const deletePlace = (data) => {
     data: data
   })
 }
+
+export const queryAllGoods = () => {
+  return service({
+    url: '/goods/queryAllGoods',
+    method: 'get'
+  })
+}
+
+export const queryGoodsList = (data) => {
+  return service({
+    url: '/goods/queryGoodsList',
+    method: 'post',
+    data
+  })
+}
+
+export const getInventory = (data) => {
+  return service({
+    url: '/goods/getInventory',
+    method: 'post',
+    data
+  })
+}
+
+export const queryAllManifest = () => {
+  return service({
+    url: '/manifest/queryManifest',
+    method: 'get'
+  })
+}
+
+export const queryManifestList = (data) => {
+  return service({
+    url: '/manifest/queryManifestList',
+    method: 'post',
+    data
+  })
+}
+
+export const createInboundManifest = (data) => {
+  return service({
+    url: '/manifest/createInboundManifest',
+    method: 'post',
+    data
+  })
+}
+
+export const createOutboundManifest = (data) => {
+  return service({
+    url: '/manifest/createOutboundManifest',
+    method: 'post',
+    data
+  })
+}

+ 1 - 1
web/src/utils/request.js

@@ -72,7 +72,7 @@ service.interceptors.response.use(
     if (response.headers['new-token']) {
       userStore.setToken(response.headers['new-token'])
     }
-    if (response.data.code === 0 || response.headers.success === 'true' || response.status === 200) {
+    if (response.data.code === 0 || response.headers.success === 'true') {
       if (response.headers.msg) {
         response.data.msg = decodeURI(response.headers.msg)
       }

+ 34 - 5
web/src/view/storehouse/commodity/commodity.vue

@@ -136,6 +136,9 @@
                 type="number"
               />
             </el-form-item>
+            <el-form-item label="单位">
+              <el-input v-model="commodityEditData.unity" />
+            </el-form-item>
             <el-form-item label="备注">
               <el-input v-model="commodityEditData.remark" />
             </el-form-item>
@@ -197,6 +200,9 @@
                 type="number"
               />
             </el-form-item>
+            <el-form-item label="单位">
+              <el-input v-model="commodityAddData.unity" />
+            </el-form-item>
             <el-form-item label="备注">
               <el-input v-model="commodityAddData.remark" />
             </el-form-item>
@@ -233,6 +239,10 @@
               label="名称"
               prop="name"
             />
+            <el-table-column
+              label="备注"
+              prop="remarks"
+            />
             <el-table-column align="right">
               <template #header>
                 <el-input
@@ -257,13 +267,22 @@
         <el-dialog
           v-model="isOpenAddGenre"
           title="新增商品类型"
-          width="500"
+          width="300"
           align-center
         >
           <template #footer>
             <el-form>
               <el-form-item label="名称">
-                <el-input v-model="commodityGenreAddData.name" />
+                <el-input
+                  v-model="commodityGenreAddData.name"
+                  style="width: 240px;"
+                />
+              </el-form-item>
+              <el-form-item label="备注">
+                <el-input
+                  v-model="commodityGenreAddData.remarks"
+                  style="width: 240px;"
+                />
               </el-form-item>
               <el-form-item>
                 <el-button
@@ -277,14 +296,23 @@
         <!--        编辑-->
         <el-dialog
           v-model="isOpenUpdateGenre"
-          title="新增商品类型"
-          width="500"
+          title="编辑商品类型"
+          width="300"
           align-center
         >
           <template #footer>
             <el-form>
               <el-form-item label="名称">
-                <el-input v-model="commodityGenreUpdateData.name" />
+                <el-input
+                  v-model="commodityGenreUpdateData.name"
+                  style="width: 240px;"
+                />
+              </el-form-item>
+              <el-form-item label="备注">
+                <el-input
+                  v-model="commodityGenreUpdateData.remarks"
+                  style="width: 240px;"
+                />
               </el-form-item>
               <el-form-item>
                 <el-button
@@ -490,6 +518,7 @@ const commodityAddData = ref({
   genre: '',
   supplierId: '',
   unitPrice: 0,
+  unity: '',
   remark: '',
 })
 const isOpenCommodityAdd = ref(false)

+ 0 - 11
web/src/view/storehouse/commodityGenre/commodityGenre.vue

@@ -1,11 +0,0 @@
-<script setup>
-
-</script>
-
-<template>
-
-</template>
-
-<style scoped lang="scss">
-
-</style>

+ 611 - 0
web/src/view/storehouse/goods/goods.vue

@@ -0,0 +1,611 @@
+<template>
+  <el-container>
+    <el-header
+      class="gva-search-box"
+      style="line-height: 60px"
+    >
+      <el-row :gutter="20">
+        <el-col :span="18">
+          <el-form
+            :inline="true"
+            :model="searchGoods"
+            style="margin-top: 10px"
+          >
+            <el-form-item label="物品名称">
+              <el-select
+                v-model="searchGoods.commodityId"
+                filterable
+                placeholder="选择商品"
+              >
+                <el-option
+                  v-for="item in commodityData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="位置">
+              <el-select
+                v-model="searchGoods.warehouseId"
+                filterable
+                placeholder="选择仓库"
+                clearable
+                @change="warehouseChange"
+              >
+                <el-option
+                  v-for="item in warehouseData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-select
+                v-model="searchGoods.storageAreaId"
+                filterable
+                placeholder="选择库区"
+                clearable
+                @change="storageAreaChange"
+              >
+                <el-option
+                  v-for="item in storageAreaByWarehouseData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-select
+                v-model="searchGoods.placeId"
+                filterable
+                placeholder="选择库位"
+                clearable
+              >
+                <el-option
+                  v-for="item in placeByStorageAreaData"
+                  :key="item.ID"
+                  :label="item.code"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                type="primary"
+                @click="getData"
+              >查询</el-button>
+            </el-form-item>
+          </el-form>
+        </el-col>
+        <el-col :span="6">
+          <el-button @click="inboundDialog = true">
+            入库
+          </el-button>
+          <el-button @click="outboundDialog = true">
+            出库
+          </el-button>
+        </el-col>
+      </el-row>
+    </el-header>
+    <el-main class="gva-table-box">
+      <el-table
+        :data="goodsList"
+        height="600"
+      >
+        <el-table-column
+          prop="commodity.name"
+          label="物品名称"
+        />
+        <el-table-column
+          prop="number"
+          label="数量"
+        />
+        <el-table-column
+          prop="warehouse.name"
+          label="仓库"
+        />
+        <el-table-column
+          prop="storageArea.name"
+          label="库区"
+        />
+        <el-table-column
+          prop="place.shelfNumber"
+          label="货架号"
+        />
+        <el-table-column
+          prop="place.layerNumber"
+          label="层号"
+        />
+      </el-table>
+      <!--      分页-->
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="searchGoods.pageInfo.page"
+          :page-size="searchGoods.pageInfo.pageSize"
+          :page-sizes="[10, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+      <el-drawer
+        v-model="inboundDialog"
+        title="新建入库单"
+        direction="rtl"
+        size="50%"
+      >
+        <div>
+          <el-header
+            class="gva-search-box"
+            style="line-height: 60px"
+          >
+            <el-button
+              type="primary"
+              style="margin-top: 12px;"
+              @click="addInboundCargo"
+            >添加商品</el-button>
+          </el-header>
+          <el-main>
+            <el-table
+              :data="manifestInboundData.cargos"
+              height="500"
+              border
+              style="width: 100%;margin-bottom: 20px"
+            >
+              <el-table-column
+                label="商品"
+                width="300"
+              >
+                <template #default="{ row }">
+                  <el-select
+                    v-model="row.commodityId"
+                    filterable
+                    placeholder="选择商品"
+                  >
+                    <el-option
+                      v-for="item in commodityData"
+                      :key="item.ID"
+                      :label="item.name"
+                      :value="item.ID"
+                    />
+                  </el-select>
+                </template>
+              </el-table-column>
+              <el-table-column
+                label="数量"
+                width="200"
+              >
+                <template #default="{ row }">
+                  <el-input-number
+                    v-model="row.number"
+                    :min="1"
+                  />
+                </template>
+              </el-table-column>
+              <el-table-column label="仓库/库区/库位">
+                <template #default="{ row }">
+                  <el-cascader
+                    v-model="row.location"
+                    :options="warehouseOptions"
+                    :props="{
+                      value: 'value',
+                      label: 'label',
+                      children: 'children'
+                    }"
+                    placeholder="仓库/库区/库位"
+                    style="width: 100%"
+                  />
+                </template>
+              </el-table-column>
+              <el-table-column
+                label="操作"
+                width="100"
+              >
+                <template #default="scope">
+                  <el-button
+                    type="danger"
+                    size="small"
+                    @click="removeInboundCargo(scope.$index)"
+                  >删除</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+            <el-form-item
+              label="标题"
+              prop="title"
+            >
+              <el-input
+                v-model="manifestInboundData.title"
+                style="width: 200px;"
+              />
+            </el-form-item>
+            <el-form-item
+              label="管理人"
+              prop="custodian"
+            >
+              <el-input
+                v-model="manifestInboundData.custodian"
+                style="width: 200px;"
+              />
+            </el-form-item>
+
+            <el-form-item>
+              <el-button
+                type="primary"
+                @click="submitInboundForm"
+              >提交入库</el-button>
+            </el-form-item>
+          </el-main>
+        </div>
+      </el-drawer>
+      <el-drawer
+        v-model="outboundDialog"
+        title="新建出库单"
+        direction="rtl"
+        size="50%"
+      >
+        <div>
+          <el-header
+            class="gva-search-box"
+            style="line-height: 60px"
+          >
+            <el-button
+              type="primary"
+              icon="Plus"
+              class="mt-2"
+              @click="addOutboundCargo"
+            >添加商品</el-button>
+          </el-header>
+          <el-main>
+            <el-form
+              ref="outboundForm"
+              :model="manifestOutboundData"
+            >
+              <!-- 商品出库表格 -->
+              <el-table
+                :data="manifestOutboundData.cargos"
+                height="500"
+                border
+                style="width: 100%;margin-bottom: 20px"
+              >
+                <el-table-column
+                  label="商品"
+                  width="250"
+                >
+                  <template #default="{ row }">
+                    <el-select
+                      v-model.number="row.commodityId"
+                      filterable
+                      placeholder="选择商品"
+                      @change="updateCommodityInfo(row)"
+                    >
+                      <el-option
+                        v-for="item in goodsList"
+                        :key="item.commodity.ID"
+                        :label="`${item.commodity.name} (库存: ${item.number})`"
+                        :value="item.commodity.ID"
+                        :disabled="isCommoditySelected(item.commodity.ID)"
+                      />
+                    </el-select>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="出库数量"
+                  width="200"
+                >
+                  <template #default="{ row }">
+                    <el-input-number
+                      v-model="row.number"
+                      :min="1"
+                      :max="row.maxNumber || 0"
+                      :disabled="!row.commodityId"
+                    />
+                  </template>
+                </el-table-column>
+
+                <el-table-column label="出库位置">
+                  <template #default="{ row }">
+                    <el-cascader
+                      v-model="row.location"
+                      disabled
+                      :options="warehouseOptions"
+                      :props="cascaderProps"
+                      placeholder="仓库/库区/库位"
+                      style="width: 320px;"
+                    />
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="操作"
+                  width="80"
+                >
+                  <template #default="{ $index }">
+                    <el-button
+                      type="danger"
+                      icon="Delete"
+                      size="small"
+                      @click="removeOutboundCargo($index)"
+                    />
+                  </template>
+                </el-table-column>
+              </el-table>
+              <el-form-item
+                label="标题"
+                prop="title"
+              >
+                <el-input
+                  v-model="manifestOutboundData.title"
+                  style="width: 200px;"
+                />
+              </el-form-item>
+              <el-form-item
+                label="管理人"
+                prop="custodian"
+              >
+                <el-input
+                  v-model="manifestOutboundData.custodian"
+                  placeholder="请输入负责人姓名"
+                  style="width: 200px;"
+                />
+              </el-form-item>
+
+              <el-form-item>
+                <el-button
+                  type="primary"
+                  @click="submitForm"
+                >提交出库</el-button>
+                <el-button @click="resetForm">重置</el-button>
+              </el-form-item>
+            </el-form>
+          </el-main>
+
+        </div>
+      </el-drawer>
+    </el-main>
+  </el-container>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { queryAllCommodity } from '@/api/inventory'
+import {
+  createInboundManifest, createOutboundManifest, queryAllGoods,
+  queryAllPlace,
+  queryAllStorageArea,
+  queryAllWarehouse,
+  queryGoodsList
+} from '@/api/storehouse'
+import { ElMessage } from 'element-plus'
+// 数据
+const commodityData = ref()
+const warehouseData = ref()
+const storageAreaData = ref()
+const storageAreaByWarehouseData = ref()
+const placeData = ref()
+const placeByStorageAreaData = ref()
+const warehouseOptions = ref()
+const goodsList = ref()
+const goodsData = ref()
+
+const warehouseChange = (val) => {
+  if (val === undefined) {
+    searchGoods.value.placeId = undefined
+    placeByStorageAreaData.value = undefined
+    searchGoods.value.storageAreaId = undefined
+    storageAreaByWarehouseData.value = undefined
+  }
+  for (const i in warehouseData.value) {
+    if (warehouseData.value[i].ID === val) {
+      storageAreaByWarehouseData.value = warehouseData.value[i].storageAreas
+    }
+  }
+}
+
+const storageAreaChange = (val) => {
+  if (val === undefined) {
+    searchGoods.value.placeId = undefined
+    placeByStorageAreaData.value = undefined
+  }
+  for (const i in storageAreaByWarehouseData.value) {
+    if (storageAreaByWarehouseData.value[i].ID === val) {
+      placeByStorageAreaData.value = storageAreaByWarehouseData.value[i].places
+    }
+  }
+}
+
+const searchGoods = ref({
+  pageInfo: {
+    page: 1,
+    pageSize: 10
+  },
+  commodityId: undefined,
+  warehouseId: undefined,
+  storageAreaId: undefined,
+  placeId: undefined,
+})
+
+const total = ref(0)
+
+const getData = async() => {
+  await queryAllCommodity().then(res => {
+    commodityData.value = res.data
+  })
+  await queryAllWarehouse().then(res => {
+    warehouseData.value = res.data
+    warehouseOptions.value = res.data.map(warehouse => ({
+      value: warehouse.ID,
+      label: warehouse.name,
+      children: warehouse.storageAreas.map(area => ({
+        value: area.ID,
+        label: area.name,
+        children: area.places.map(place => ({
+          value: place.ID,
+          label: `${place.shelfNumber}架-${place.layerNumber}层 (${place.code})`
+        }))
+      }))
+    }))
+  })
+  await queryAllStorageArea().then(res => {
+    storageAreaData.value = res.data
+  })
+  await queryAllPlace().then(res => {
+    placeData.value = res.data
+  })
+  await queryGoodsList(searchGoods.value).then(res => {
+    goodsList.value = res.data.list
+    total.value = res.data.total
+  })
+  await queryAllGoods().then(res => {
+    goodsData.value = res.data
+  })
+}
+
+// 分页
+const handleSizeChange = (val) => {
+  searchGoods.value.pageSize = val
+  getData()
+}
+
+const handleCurrentChange = (val) => {
+  searchGoods.value.page = val
+  getData()
+}
+
+// 入库
+const manifestInboundData = ref({
+  manifestGenre: '入库',
+  title: '',
+  custodian: '',
+  cargos: [
+    { commodityId: null, number: 1, location: [] },
+  ],
+})
+
+const inboundDialog = ref(false)
+
+// 添加商品行
+const addInboundCargo = () => {
+  manifestInboundData.value.cargos.push({ commodityId: null, number: 1, location: [] })
+}
+
+// 删除商品行
+const removeInboundCargo = (index) => {
+  manifestInboundData.value.cargos.splice(index, 1)
+}
+
+// 提交表单
+const submitInboundForm = async() => {
+  await createInboundManifest({
+    ...manifestInboundData.value,
+    cargos: manifestInboundData.value.cargos.map(cargo => ({
+      commodityId: cargo.commodityId,
+      number: cargo.number,
+      warehouseId: cargo.location[0],
+      storageAreaId: cargo.location[1],
+      placeId: cargo.location[2]
+    }))
+  }).then(res => {
+    if (res.code === 0) {
+      ElMessage.success('入库单提交成功!')
+      manifestInboundData.value.cargos = [{ commodityId: null, number: 1, location: [] }]
+    }
+    inboundDialog.value = false
+    getData()
+  })
+}
+
+// 出库
+const manifestOutboundData = ref({
+  manifestGenre: '出库',
+  title: '',
+  custodian: '',
+  cargos: [
+    {
+      commodityId: null,
+      commodityName: '',
+      number: 0,
+      maxNumber: 1, // 当前最大可出库数量
+      location: [] // [warehouseId, storageAreaId, placeId]
+    },
+  ],
+})
+
+const outboundDialog = ref(false)
+
+const cascaderProps = {
+  value: 'value',
+  label: 'label',
+  children: 'children',
+}
+
+// 添加商品行
+const addOutboundCargo = () => {
+  manifestOutboundData.value.cargos.push({
+    commodityId: null,
+    number: 0,
+    maxNumber: 1,
+    location: []
+  })
+}
+
+// 删除商品行
+const removeOutboundCargo = (index) => {
+  manifestOutboundData.value.cargos.splice(index, 1)
+  console.log(manifestOutboundData.value.cargos)
+}
+
+// 提交表单
+const submitForm = async() => {
+  try {
+    await createOutboundManifest({
+      ...manifestOutboundData.value,
+      cargos: manifestOutboundData.value.cargos.map(cargo => ({
+        commodityId: cargo.commodityId,
+        number: cargo.number,
+        warehouseId: cargo.location[0],
+        storageAreaId: cargo.location[1],
+        placeId: cargo.location[2]
+      }))
+    }).then(res => {
+      if (res.code === 0) {
+        ElMessage.success('出库单提交成功!')
+      }
+      outboundDialog.value = false
+      getData()
+    })
+    resetForm()
+  } catch (error) {
+    ElMessage.error(`提交失败: ${error.message}`)
+  }
+}
+
+// 更新商品信息
+const updateCommodityInfo = (row) => {
+  const goods = goodsList.value.find(item => item.commodityId === row.commodityId)
+  if (goods) {
+    row.commodityName = goods.commodity.name
+    row.maxNumber = goods.number
+    row.location = [goods.warehouseId, goods.storageAreaId, goods.placeId]
+  }
+}
+
+const isCommoditySelected = (id) => {
+  return manifestOutboundData.value.cargos.some(cargo => cargo.commodityId === id)
+}
+
+// 重置表单
+const resetForm = () => {
+  manifestOutboundData.value.cargos = [{ commodityId: null, number: 1, location: [] }]
+  manifestOutboundData.value.custodian = ''
+}
+
+onMounted(() => {
+  getData()
+})
+</script>

+ 178 - 0
web/src/view/storehouse/manifest/manifest.vue

@@ -0,0 +1,178 @@
+<template>
+  <el-container>
+    <el-header
+      class="gva-search-box"
+      style="line-height: 60px"
+    >
+      <el-form
+        :inline="true"
+        :model="searchManifest"
+        style="margin-top: 10px"
+      >
+        <el-form-item label="类型">
+          <el-select
+            v-model="searchManifest.genre"
+            clearable
+          >
+            <el-option
+              v-for="item in genreOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="标题">
+          <el-input v-model="searchManifest.title" />
+        </el-form-item>
+        <el-form-item>
+          <el-button
+            type="primary"
+            @click="getData"
+          >查询</el-button>
+        </el-form-item>
+      </el-form>
+    </el-header>
+    <el-main class="gva-table-box">
+      <el-table
+        :data="manifestList"
+        height="600"
+      >
+        <el-table-column
+          prop="title"
+          label="标题"
+        />
+        <el-table-column
+          prop="manifestGenre"
+          label="类型"
+        />
+        <el-table-column
+          prop="custodian"
+          label="负责人"
+        />
+        <el-table-column
+          prop="CreatedAt"
+          label="创建时间"
+        >
+          <template #default="{ row }">
+            {{ dayjs(row.CreatedAt).format('YYYY-MM-DD HH:mm:ss') }}
+          </template>
+        </el-table-column>
+        <el-table-column
+          prop="cargos"
+          label="操作"
+        >
+          <template #default="{ row }">
+            <el-button
+              type="primary"
+              @click="openDialog(row.cargos)"
+            >详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!--      分页-->
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="searchManifest.pageInfo.page"
+          :page-size="searchManifest.pageInfo.pageSize"
+          :page-sizes="[10, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+      <el-drawer
+        v-model="isOpenDialog"
+        title="货单详情"
+        direction="rtl"
+        size="50%"
+      >
+        <div>
+          <el-table
+            :data="details"
+            height="800"
+            border
+            style="width: 100%;margin-bottom: 20px"
+          >
+            <el-table-column
+              prop="commodity.name"
+              label="商品名称"
+            />
+            <el-table-column
+              prop="number"
+              label="数量"
+            />
+            <el-table-column
+              prop="warehouse.name"
+              label="所属仓库"
+            />
+          </el-table>
+        </div>
+      </el-drawer>
+    </el-main>
+  </el-container>
+</template>
+<script setup>
+import { ref, onMounted } from 'vue'
+import { queryManifestList } from '@/api/storehouse'
+import { dayjs } from 'element-plus'
+
+const genreOptions = [
+  {
+    value: '入库',
+    label: '入库',
+  },
+  {
+    value: '出库',
+    label: '出库',
+  }
+]
+
+const searchManifest = ref({
+  pageInfo: {
+    page: 1,
+    pageSize: 10,
+  },
+  genre: '',
+  title: ''
+})
+
+const total = ref(0)
+
+const manifestList = ref()
+
+// 获取数据
+const getData = async() => {
+  await queryManifestList(searchManifest.value).then((res) => {
+    console.log(res.data.list)
+    manifestList.value = res.data.list
+    total.value = res.data.total
+  })
+}
+
+// 分页
+const handleSizeChange = (val) => {
+  searchManifest.value.pageSize = val
+  getData()
+}
+
+const handleCurrentChange = (val) => {
+  searchManifest.value.page = val
+  getData()
+}
+
+// 详情
+const isOpenDialog = ref(false)
+const details = ref()
+
+const openDialog = (val) => {
+  details.value = val
+  isOpenDialog.value = true
+}
+
+onMounted(() => {
+  getData()
+})
+
+</script>

+ 430 - 1
web/src/view/storehouse/warehouse/place/place.vue

@@ -1,6 +1,435 @@
 <template>
-  <div>库位</div>
+  <el-container>
+    <el-header
+      class="gva-search-box"
+      style="line-height: 60px"
+    >
+      <el-row>
+        <el-col :span="20">
+          <el-form
+            inline
+            style="margin-top: 10px"
+          >
+            <el-form-item label="名称">
+              <el-input
+                v-model="searchPlace.name"
+                placeholder="请输入名称"
+              />
+            </el-form-item>
+            <el-form-item label="物品类型">
+              <el-select
+                v-model="searchPlace.genre"
+                placeholder="请选择"
+                clearable
+                style="width: 180px"
+              >
+                <el-option
+                  v-for="item in commodityGenreAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="仓库">
+              <el-select
+                v-model="searchPlace.warehouseId"
+                placeholder="请选择"
+                clearable
+                style="width: 180px"
+              >
+                <el-option
+                  v-for="item in warehouseAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="库区">
+              <el-select
+                v-model="searchPlace.storageAreaId"
+                placeholder="请选择"
+                clearable
+                style="width: 180px"
+              >
+                <el-option
+                  v-for="item in storageAreaAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button @click="getData">搜索</el-button>
+            </el-form-item>
+          </el-form>
+        </el-col>
+        <el-col :span="4">
+          <el-button
+            type="primary"
+            @click="isOpenPlaceAdd = true"
+          >新增库位</el-button>
+        </el-col>
+      </el-row>
+    </el-header>
+    <el-main>
+      <el-table
+        :data="placeListData"
+        height="550"
+      >
+        <el-table-column
+          prop="code"
+          label="库位编码"
+        />
+        <el-table-column
+          prop="shelfNumber"
+          label="货架号"
+        />
+        <el-table-column
+          prop="layerNumber"
+          label="层号"
+        />
+        <el-table-column
+          prop="commodityGenre.name"
+          label="物品类型"
+        />
+        <el-table-column
+          prop="storageArea.name"
+          label="所属库位"
+        />
+        <el-table-column
+          prop="warehouse.name"
+          label="所属仓库"
+        />
+        <el-table-column
+          label="是否启用"
+        >
+          <template #default="scope">
+            <el-switch
+              v-model="scope.row.isEffective"
+              style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
+              @change="changeIsEffective(scope.row)"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="操作">
+          <template #default="scope">
+            <el-button
+              type="primary"
+              @click="openPlaceEdit(scope.row)"
+            >编辑</el-button>
+            <el-button
+              type="danger"
+              @click="placeDelete(scope.row)"
+            >删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!--      分页-->
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="searchPlace.pageInfo.page"
+          :page-size="searchPlace.pageInfo.pageSize"
+          :page-sizes="[10, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+      <!--      新增-->
+      <el-drawer
+        v-model="isOpenPlaceAdd"
+        title="新增库区信息"
+        direction="rtl"
+        size="30%"
+      >
+        <div>
+          <el-form
+            v-model="addPlaceData"
+            label-position="left"
+            label-width="auto"
+            style="max-width: 400px"
+          >
+            <el-form-item label="库位编码">
+              <el-input v-model="addPlaceData.code" />
+            </el-form-item>
+            <el-form-item label="货架号">
+              <el-input v-model="addPlaceData.shelfNumber" />
+            </el-form-item>
+            <el-form-item label="层号">
+              <el-input v-model="addPlaceData.layerNumber" />
+            </el-form-item>
+            <el-form-item label="物品类型">
+              <el-select
+                v-model="addPlaceData.genre"
+                placeholder="请选择"
+                style="width: 240px"
+              >
+                <el-option
+                  v-for="item in commodityGenreAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="库区">
+              <el-select
+                v-model="addPlaceData.storageAreaId"
+                placeholder="请选择"
+                style="width: 240px"
+              >
+                <el-option
+                  v-for="item in storageAreaAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="仓库">
+              <el-select
+                v-model="addPlaceData.warehouseId"
+                placeholder="请选择"
+                style="width: 240px"
+              >
+                <el-option
+                  v-for="item in warehouseAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                type="primary"
+                @click="addPlace"
+              >提交</el-button>
+              <el-button @click="isOpenPlaceAdd = false">关闭</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+      </el-drawer>
+      <!--      修改-->
+      <el-drawer
+        v-model="isOpenPlaceEdit"
+        title="修改库区信息"
+        direction="rtl"
+        size="30%"
+      >
+        <div>
+          <el-form
+            v-model="editPlaceData"
+            label-position="left"
+            label-width="auto"
+            style="max-width: 400px"
+          >
+            <el-form-item label="库位编码">
+              <el-input v-model="editPlaceData.code" />
+            </el-form-item>
+            <el-form-item label="货架号">
+              <el-input v-model="editPlaceData.shelfNumber" />
+            </el-form-item>
+            <el-form-item label="层号">
+              <el-input v-model="editPlaceData.layerNumber" />
+            </el-form-item>
+            <el-form-item label="物品类型">
+              <el-select
+                v-model="editPlaceData.genre"
+                placeholder="请选择"
+                style="width: 240px"
+              >
+                <el-option
+                  v-for="item in commodityGenreAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="库区">
+              <el-select
+                v-model="editPlaceData.storageAreaId"
+                placeholder="请选择"
+                style="width: 240px"
+              >
+                <el-option
+                  v-for="item in storageAreaAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="仓库">
+              <el-select
+                v-model="editPlaceData.warehouseId"
+                placeholder="请选择"
+                style="width: 240px"
+              >
+                <el-option
+                  v-for="item in warehouseAllData"
+                  :key="item.ID"
+                  :label="item.name"
+                  :value="item.ID"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                type="primary"
+                @click="editPlace"
+              >提交</el-button>
+              <el-button @click="isOpenPlaceEdit = false">关闭</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+      </el-drawer>
+    </el-main>
+  </el-container>
 </template>
 <script setup>
+import { ref, onMounted } from 'vue'
+import {
+  createPlace, deletePlace,
+  queryAllCommodityGenre,
+  queryAllStorageArea,
+  queryAllWarehouse,
+  queryPlaceList,
+  switchPlace, updatePlace
+} from '@/api/storehouse'
+import { ElMessage, ElMessageBox } from 'element-plus'
+
+// 数据
+const searchPlace = ref({
+  pageInfo: {
+    page: 1,
+    pageSize: 10,
+  },
+  name: '',
+  genre: undefined,
+  warehouseId: undefined,
+  storageAreaId: undefined,
+})
+
+const total = ref(0)
+
+const placeListData = ref([])
+const warehouseAllData = ref()
+const commodityGenreAllData = ref()
+const storageAreaAllData = ref()
+
+const getData = async() => {
+// 假设有接口来获取数据
+  await queryPlaceList(searchPlace.value).then(res => {
+    placeListData.value = res.data.list
+    total.value = res.data.total
+  })
+  await queryAllWarehouse().then(res => {
+    warehouseAllData.value = res.data
+  })
+  await queryAllCommodityGenre().then(res => {
+    commodityGenreAllData.value = res.data
+  })
+  await queryAllStorageArea().then(res => {
+    storageAreaAllData.value = res.data
+  })
+}
+
+// 分页
+const handleSizeChange = (val) => {
+  searchPlace.value.pageSize = val
+  getData()
+}
+
+const handleCurrentChange = (val) => {
+  searchPlace.value.page = val
+  getData()
+}
+
+const changeIsEffective = async(row) => {
+  await switchPlace(row).then(res => {
+    if (res.code === 0) {
+      ElMessage.success('切换成功')
+    }
+  })
+}
+
+// 新增
+const addPlaceData = ref({
+  code: '',
+  shelfNumber: '',
+  layerNumber: '',
+  genre: undefined,
+  storageAreaId: undefined,
+  warehouseId: undefined,
+})
+const isOpenPlaceAdd = ref(false)
+
+const addPlace = async() => {
+  await createPlace(addPlaceData.value).then(res => {
+    if (res.code === 0) {
+      ElMessage.success('新增成功')
+    }
+    isOpenPlaceAdd.value = false
+    getData()
+  })
+}
+
+// 修改
+const editPlaceData = ref()
+const isOpenPlaceEdit = ref(false)
+
+const openPlaceEdit = (val) => {
+  editPlaceData.value = val
+  isOpenPlaceEdit.value = true
+}
+
+const editPlace = async() => {
+  await updatePlace(editPlaceData.value).then(res => {
+    if (res.code === 0) {
+      ElMessage.success('修改成功')
+    }
+    isOpenPlaceEdit.value = false
+    getData()
+  })
+}
+
+// 删除
+const placeDelete = (val) => {
+  ElMessageBox.confirm(
+    '将永久删除该信息。是否继续?',
+    '删除',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(async() => {
+      await deletePlace(val).then(res => {
+        if (res.code === 0) {
+          ElMessage.success('删除成功')
+          getData()
+        } else {
+          ElMessage.error('删除失败')
+        }
+      })
+    })
+    .catch(() => {
+      ElMessage({
+        type: 'info',
+        message: '删除已取消',
+      })
+    })
+}
+
+onMounted(() => {
+  getData()
+})
 
 </script>

+ 21 - 18
web/src/view/storehouse/warehouse/storageArea/storageArea.vue

@@ -16,14 +16,15 @@
                 placeholder="请输入名称"
               />
             </el-form-item>
-            <el-form-item label="库区类型">
+            <el-form-item label="物品类型">
               <el-select
                 v-model="searchStorageArea.genre"
                 placeholder="请选择"
+                clearable
                 style="width: 180px"
               >
                 <el-option
-                  v-for="item in storageAreaGenreAllData"
+                  v-for="item in commodityGenreAllData"
                   :key="item.ID"
                   :label="item.name"
                   :value="item.ID"
@@ -34,6 +35,7 @@
               <el-select
                 v-model="searchStorageArea.warehouseId"
                 placeholder="请选择"
+                clearable
                 style="width: 180px"
               >
                 <el-option
@@ -60,15 +62,15 @@
     <el-main>
       <el-table
         :data="StorageAreaListData"
-        style="min-height: 550px;"
+        height="550"
       >
         <el-table-column
           prop="name"
           label="库区名称"
         />
         <el-table-column
-          prop="storageAreaGenre.name"
-          label="库区类型"
+          prop="commodityGenre.name"
+          label="物品类型"
         />
         <el-table-column
           prop="warehouse.name"
@@ -113,7 +115,7 @@
       <!--      修改-->
       <el-drawer
         v-model="isOpenStorageAreaEdit"
-        title="修改库信息"
+        title="修改库信息"
         direction="rtl"
         size="30%"
       >
@@ -127,14 +129,14 @@
             <el-form-item label="库区名称">
               <el-input v-model="StorageAreaEditData.name" />
             </el-form-item>
-            <el-form-item label="库区类型">
+            <el-form-item label="物品类型">
               <el-select
                 v-model="StorageAreaEditData.genre"
                 placeholder="请选择"
                 style="width: 240px"
               >
                 <el-option
-                  v-for="item in storageAreaGenreAllData"
+                  v-for="item in commodityGenreAllData"
                   :key="item.ID"
                   :label="item.name"
                   :value="item.ID"
@@ -165,9 +167,10 @@
           </el-form>
         </div>
       </el-drawer>
+      <!--      新增-->
       <el-drawer
         v-model="isOpenStorageAreaAdd"
-        title="新增库信息"
+        title="新增库信息"
         direction="rtl"
         size="30%"
       >
@@ -181,14 +184,14 @@
             <el-form-item label="库区名称">
               <el-input v-model="StorageAreaAddData.name" />
             </el-form-item>
-            <el-form-item label="库区类型">
+            <el-form-item label="物品类型">
               <el-select
                 v-model="StorageAreaAddData.genre"
                 placeholder="请选择"
                 style="width: 240px"
               >
                 <el-option
-                  v-for="item in storageAreaGenreAllData"
+                  v-for="item in commodityGenreAllData"
                   :key="item.ID"
                   :label="item.name"
                   :value="item.ID"
@@ -226,10 +229,10 @@
 import { ref, onMounted } from 'vue'
 import {
   createStorageArea,
-  deleteStorageArea, queryAllStorageAreaGenre, queryAllWarehouse,
+  deleteStorageArea, queryAllCommodityGenre, queryAllWarehouse,
   queryStorageAreaList,
   switchStorageArea,
-  updateStorageArea
+  updateStorageArea,
 } from '@/api/storehouse'
 import { ElMessage, ElMessageBox } from 'element-plus'
 
@@ -239,14 +242,14 @@ const searchStorageArea = ref({
     pageSize: 10,
   },
   name: '',
-  genre: '',
-  warehouseId: '',
+  genre: undefined,
+  warehouseId: undefined,
 })
 
 const StorageAreaListData = ref([])
 const total = ref(0)
 const warehouseAllData = ref()
-const storageAreaGenreAllData = ref()
+const commodityGenreAllData = ref()
 
 const getData = async() => {
   // 假设有接口来获取数据
@@ -257,8 +260,8 @@ const getData = async() => {
   await queryAllWarehouse().then(res => {
     warehouseAllData.value = res.data
   })
-  await queryAllStorageAreaGenre().then(res => {
-    storageAreaGenreAllData.value = res.data
+  await queryAllCommodityGenre().then(res => {
+    commodityGenreAllData.value = res.data
   })
 }
 

+ 1 - 1
web/src/view/storehouse/warehouse/warehouse.vue

@@ -34,7 +34,7 @@
     <el-main>
       <el-table
         :data="warehouseListData"
-        style="min-height: 550px;"
+        height="550"
       >
         <el-table-column
           prop="name"