xu 6 months ago
parent
commit
1616a48f41

+ 28 - 0
server/api/v1/admin/file.go

@@ -176,3 +176,31 @@ func (fa *FileApi) FileDownload(c *gin.Context) {
 	c.Header("Content-Transfer-Encoding", "binary")               // 表示传输过程中的编码形式,乱码问题可能就是因为它
 	c.File(path)
 }
+
+func (fa *FileApi) FilePreview(c *gin.Context) {
+	path := c.Query("path")
+	name := c.Query("name")
+
+	// 验证或清理文件路径(这里只是一个简单的示例)
+	if strings.Contains(path, "..") {
+		response.FailWithMessage("无效的路径", c)
+		log.Println("检测到可能的路径遍历攻击尝试")
+		return
+	}
+
+	_, err := os.Stat(path)
+	if err != nil {
+		// 如果出现错误,可能是文件或目录不存在
+		if os.IsNotExist(err) {
+			c.JSON(http.StatusNotFound, gin.H{"error": "文件不存在"})
+			return
+		}
+		// 其他错误处理
+		c.AbortWithError(http.StatusInternalServerError, err)
+		return
+	}
+
+	c.Header("Content-Disposition", "inline; filename="+name) // 用来指定下载下来的文件名
+	c.Header("Content-Transfer-Encoding", "binary")           // 表示传输过程中的编码形式,乱码问题可能就是因为它
+	c.File(path)
+}

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

@@ -21,7 +21,7 @@ func (sa *SupplierApi) QueryAllSupplier(c *gin.Context) {
 }
 
 func (sa *SupplierApi) QuerySupplierList(c *gin.Context) {
-	var info request.PageInfo
+	var info request.SearchSupplierList
 	err := c.ShouldBindJSON(&info)
 	if err != nil {
 		response.FailWithMessage("参数解析失败", c)
@@ -37,8 +37,8 @@ func (sa *SupplierApi) QuerySupplierList(c *gin.Context) {
 	response.OkWithDetailed(response.PageResult{
 		List:     list,
 		Total:    total,
-		Page:     info.Page,
-		PageSize: info.PageSize,
+		Page:     info.PageInfo.Page,
+		PageSize: info.PageInfo.PageSize,
 	}, "获取成功", c)
 }
 

+ 6 - 2
server/dao/supplier.go

@@ -23,11 +23,15 @@ func QueryAllSupplier() ([]Supplier, error) {
 	return suppliers, err
 }
 
-func QuerySupplierList(limit, offset int) (suppliers []Supplier, total int64, err error) {
+func QuerySupplierList(limit, offset int, name string) (suppliers []Supplier, total int64, err error) {
 	// 创建db
-	db := global.GVA_DB.Model(&Supplier{})
+	db := global.GVA_DB.Model(&Supplier{}).Debug()
 	// 如果有条件搜索 下方会自动创建搜索语句
 
+	if name != "" {
+		db = db.Where("name LIKE ?", "%"+name+"%")
+	}
+
 	err = db.Count(&total).Error
 	if err != nil {
 		return

+ 5 - 0
server/initialize/gorm.go

@@ -75,6 +75,11 @@ func RegisterTables() {
 		dao.Description{},
 		dao.ProjectProcess{},
 		dao.ProcessNodes{},
+
+		dao.Commodity{},
+		dao.CommodityGenre{},
+		dao.Supplier{},
+		dao.Warehouse{},
 	)
 	if err != nil {
 		global.GVA_LOG.Error("register table failed", zap.Error(err))

+ 6 - 0
server/initialize/router.go

@@ -44,6 +44,7 @@ func Routers() *gin.Engine {
 	exampleRouter := router.RouterGroupApp.Example
 	adminRouter := router.RouterGroupApp.Admin
 	workflowRouter := router.RouterGroupApp.Workflow
+	storehouseRouter := router.RouterGroupApp.Storehouse
 	// 如果想要不使用nginx代理前端网页,可以修改 web/.env.production 下的
 	// VUE_APP_BASE_API = /
 	// VUE_APP_BASE_PATH = http://localhost
@@ -101,6 +102,11 @@ func Routers() *gin.Engine {
 		workflowRouter.InitProcessRouter(PrivateGroup)
 		workflowRouter.InitDescriptionRouter(PrivateGroup)
 		workflowRouter.InitProjectProcessRouter(PrivateGroup)
+
+		storehouseRouter.InitSupplierRouter(PrivateGroup)
+		storehouseRouter.InitWarehouseRouter(PrivateGroup)
+		storehouseRouter.InitCommodityRouter(PrivateGroup)
+		storehouseRouter.InitCommodityGenreRouter(PrivateGroup)
 	}
 
 	global.GVA_LOG.Info("router register success")

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

@@ -98,6 +98,11 @@ type SearchProjectProcess struct {
 	UserId   int      `json:"userId" form:"userId"`
 }
 
+type SearchSupplierList struct {
+	PageInfo PageInfo `json:"pageInfo" form:"pageInfo"`
+	Name     string   `json:"name" form:"name"`
+}
+
 type CreateProcess struct {
 	Process      dao.Process        `json:"process" form:"process"`
 	ProcessNodes []dao.ProcessNodes `json:"processNodes" form:"processNodes"`

+ 6 - 4
server/router/enter.go

@@ -3,15 +3,17 @@ package router
 import (
 	"server/router/admin"
 	"server/router/example"
+	"server/router/storehouse"
 	"server/router/system"
 	"server/router/workflow"
 )
 
 type RouterGroup struct {
-	System   system.RouterGroup
-	Example  example.RouterGroup
-	Admin    admin.RouterGroup
-	Workflow workflow.RouterGroup
+	System     system.RouterGroup
+	Example    example.RouterGroup
+	Admin      admin.RouterGroup
+	Workflow   workflow.RouterGroup
+	Storehouse storehouse.RouterGroup
 }
 
 var RouterGroupApp = new(RouterGroup)

+ 2 - 1
server/router/storehouse/supplier.go

@@ -15,11 +15,12 @@ func (r *SupplierRouter) InitSupplierRouter(Router *gin.RouterGroup) {
 
 	{
 		supplierRouter.POST("createSupplier", supplierApi.CreateSupplier)
-		supplierRouter.POST("updateSupplier", supplierApi.UpdateSupplier)
+		supplierRouter.PUT("updateSupplier", supplierApi.UpdateSupplier)
 		supplierRouter.DELETE("deleteSupplier", supplierApi.DeleteSupplier)
 	}
 
 	{
 		supplierRouterWithoutRecord.GET("queryAllSupplier", supplierApi.QueryAllSupplier)
+		supplierRouterWithoutRecord.POST("querySupplierList", supplierApi.QuerySupplierList)
 	}
 }

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

@@ -12,10 +12,10 @@ func (ss *SupplierService) QueryAllSupplier() ([]dao.Supplier, error) {
 	return dao.QueryAllSupplier()
 }
 
-func (ss *SupplierService) QuerySupplierList(info request.PageInfo) (list interface{}, total int64, err error) {
-	limit := info.PageSize
-	offset := info.PageSize * (info.Page - 1)
-	suppliers, total, err := dao.QuerySupplierList(limit, offset)
+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)
 	return suppliers, total, err
 }
 

+ 103 - 0
web/src/api/storehouse.js

@@ -0,0 +1,103 @@
+import service from '@/utils/request'
+// 获取项目列表
+export const querySupplierList = (data) => {
+  return service({
+    url: '/supplier/querySupplierList',
+    method: 'post',
+    data: data
+  })
+}
+
+export const queryAllSupplier = () => {
+  return service({
+    url: '/supplier/queryAllSupplier',
+    method: 'get'
+  })
+}
+
+export const createSupplier = (data) => {
+  return service({
+    url: '/supplier/createSupplier',
+    method: 'post',
+    data: data
+  })
+}
+
+export const updateSupplier = (data) => {
+  return service({
+    url: '/supplier/updateSupplier',
+    method: 'put',
+    data: data
+  })
+}
+
+export const deleteSupplier = (data) => {
+  return service({
+    url: '/supplier/deleteSupplier',
+    method: 'delete',
+    data: data
+  })
+}
+
+export const queryAllCommodityGenre = () => {
+  return service({
+    url: '/commodityGenre/queryAllCommodityGenre',
+    method: 'get',
+  })
+}
+
+export const createCommodityGenre = (data) => {
+  return service({
+    url: '/commodityGenre/createCommodityGenre',
+    method: 'post',
+    data: data
+  })
+}
+
+export const updateCommodityGenre = (data) => {
+  return service({
+    url: '/commodityGenre/updateCommodityGenre',
+    method: 'put',
+    data: data
+  })
+}
+
+export const deleteCommodityGenre = (data) => {
+  return service({
+    url: '/commodityGenre/deleteCommodityGenre',
+    method: 'delete',
+    data: data
+  })
+}
+
+export const queryCommodityList = (data) => {
+  return service({
+    url: '/commodity/queryCommodityList',
+    method: 'post',
+    data: data
+  })
+}
+
+export const createCommodity = (data) => {
+  return service({
+    url: '/commodity/createCommodity',
+    method: 'post',
+    data: data
+  })
+}
+
+export const updateCommodity = (data) => {
+  return service({
+    url: '/commodity/updateCommodity',
+    method: 'put',
+    data: data
+  })
+}
+
+export const deleteCommodity = (data) => {
+  return service({
+    url: '/commodity/deleteCommodity',
+    method: 'delete',
+    data: data
+  })
+}

+ 204 - 0
web/src/view/storehouse/commodity/commodity.vue

@@ -0,0 +1,204 @@
+<template>
+  <el-container>
+    <el-header
+      class="gva-search-box"
+      style="line-height: 60px"
+    >
+      <el-row>
+        <el-col :span="8" />
+        <el-col :span="8" />
+        <el-col :span="8">
+          <el-button
+            type="primary"
+            @click="isOpenCommodityGenre = true"
+          >商品类型</el-button>
+        </el-col>
+      </el-row>
+    </el-header>
+    <el-main class="gva-table-box">
+      <!--      商品类型-->
+      <el-drawer
+        v-model="isOpenCommodityGenre"
+        title="商品类型"
+        direction="rtl"
+        size="50%"
+      >
+        <el-header>
+          <el-button @click="isOpenAddGenre = true">新增商品类型</el-button>
+        </el-header>
+        <el-main>
+          <el-table :data="filterTableData">
+            <el-table-column
+              label="ID"
+              prop="ID"
+            />
+            <el-table-column
+              label="名称"
+              prop="name"
+            />
+            <el-table-column align="right">
+              <template #header>
+                <el-input v-model="searchCommodityGenre" />
+              </template>
+              <template #default="scope">
+                <el-button @click="openUpdateGenre(scope.row)">编辑</el-button>
+                <el-button @click="commodityGenreDeleteSubmit(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-main>
+        <!--        新增-->
+        <el-dialog
+          v-model="isOpenAddGenre"
+          title="新增商品类型"
+          width="500"
+          align-center
+        >
+          <template #footer>
+            <el-form>
+              <el-form-item label="名称">
+                <el-input v-model="commodityGenreAddData.name" />
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  type="primary"
+                  @click="commodityGenreAddSubmit"
+                >提交</el-button>
+              </el-form-item>
+            </el-form>
+          </template>
+        </el-dialog>
+        <!--        编辑-->
+        <el-dialog
+          v-model="isOpenUpdateGenre"
+          title="新增商品类型"
+          width="500"
+          align-center
+        >
+          <template #footer>
+            <el-form>
+              <el-form-item label="名称">
+                <el-input v-model="commodityGenreUpdateData.name" />
+              </el-form-item>
+              <el-form-item>
+                <el-button
+                  type="primary"
+                  @click="commodityGenreUpdateSubmit"
+                >提交</el-button>
+              </el-form-item>
+            </el-form>
+          </template>
+        </el-dialog>
+      </el-drawer>
+    </el-main>
+  </el-container>
+</template>
+
+<script setup>
+import { ref, onMounted, computed } from 'vue'
+import {
+  createCommodityGenre,
+  deleteCommodityGenre,
+  queryAllCommodityGenre,
+  updateCommodityGenre
+} from '@/api/storehouse'
+import { ElMessage, ElMessageBox } from 'element-plus'
+
+// 数据
+const commodityGenreAllData = ref()
+const getData = async() => {
+  await queryAllCommodityGenre().then(res => {
+    commodityGenreAllData.value = res.data
+  })
+}
+
+// 商品类型
+const isOpenCommodityGenre = ref(false)
+
+const searchCommodityGenre = ref()
+
+const filterTableData = computed(() =>
+  commodityGenreAllData.value.filter(
+    (data) =>
+      !searchCommodityGenre.value ||
+            data.name.toLowerCase().includes(searchCommodityGenre.value.toLowerCase())
+  )
+)
+
+const commodityGenreAddData = ref({
+  name: '',
+})
+const isOpenAddGenre = ref(false)
+
+const commodityGenreAddSubmit = async() => {
+  if (!commodityGenreAddData.value.name) {
+    ElMessage.error('名称不能为空')
+    return
+  }
+  await createCommodityGenre(commodityGenreAddData.value).then(res => {
+    if (res.code === 0) {
+      ElMessage.success('新增成功')
+    } else {
+      ElMessage.error('新增失败')
+    }
+    isOpenAddGenre.value = false
+    getData()
+  })
+}
+
+const commodityGenreUpdateData = ref()
+const isOpenUpdateGenre = ref(false)
+
+const openUpdateGenre = (val) => {
+  isOpenUpdateGenre.value = true
+  commodityGenreUpdateData.value = val
+}
+
+const commodityGenreUpdateSubmit = async() => {
+  if (!commodityGenreUpdateData.value.name) {
+    ElMessage.error('名称不能为空')
+    return
+  }
+  await updateCommodityGenre(commodityGenreUpdateData.value).then(res => {
+    if (res.code === 0) {
+      ElMessage.success('编辑成功')
+    } else {
+      ElMessage.error('编辑失败')
+    }
+    isOpenUpdateGenre.value = false
+    getData()
+  })
+}
+
+const commodityGenreDeleteSubmit = (val) => {
+  ElMessageBox.confirm(
+    '将永久删除该信息。是否继续?',
+    '删除',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(async() => {
+      await deleteCommodityGenre(val).then(res => {
+        if (res.code === 0) {
+          ElMessage.success('删除成功')
+          getData()
+        } else {
+          ElMessage.error('删除失败')
+        }
+      })
+    })
+    .catch(() => {
+      ElMessage({
+        type: 'info',
+        message: '删除已取消',
+      })
+    })
+}
+
+onMounted(() => {
+  getData()
+})
+</script>

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

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

+ 23 - 0
web/src/view/storehouse/index.vue

@@ -0,0 +1,23 @@
+<template>
+  <div>
+    <router-view v-slot="{ Component }">
+      <transition
+          mode="out-in"
+          name="el-fade-in-linear"
+      >
+        <keep-alive :include="routerStore.keepAliveRouters">
+          <component :is="Component" />
+        </keep-alive>
+      </transition>
+    </router-view>
+  </div>
+</template>
+
+<script setup>
+import { useRouterStore } from '@/pinia/modules/router'
+const routerStore = useRouterStore()
+
+defineOptions({
+  name: 'Storehouse'
+})
+</script>

+ 315 - 0
web/src/view/storehouse/supplier/supplier.vue

@@ -0,0 +1,315 @@
+<template>
+  <el-container>
+    <el-header
+      class="gva-search-box"
+      style="line-height: 60px"
+    >
+      <el-row>
+        <el-col :span="8">
+          <el-form
+            inline
+            style="margin-top: 10px"
+          >
+            <el-form-item label="名称">
+              <el-input
+                v-model="searchSupplierList.name"
+                placeholder="请输入名称"
+              />
+            </el-form-item>
+            <el-form-item>
+              <el-button @click="getData">搜索</el-button>
+            </el-form-item>
+          </el-form>
+
+        </el-col>
+        <el-col :span="8" />
+        <el-col :span="8">
+          <el-button
+            type="primary"
+            @click="openSupplierAdd"
+          >新增</el-button>
+        </el-col>
+      </el-row>
+    </el-header>
+    <el-main
+      class="gva-table-box"
+    >
+      <el-table
+        :data="supplierList"
+        style="height: 600px"
+      >
+        <el-table-column
+          label="供应商名称"
+          prop="name"
+          align="center"
+        />
+        <el-table-column
+          label="负责人"
+          prop="contactName"
+          align="center"
+        />
+        <el-table-column
+          label="城市"
+          prop="city"
+          align="center"
+        />
+        <el-table-column
+          label="地址"
+          prop="address"
+          align="center"
+        />
+        <el-table-column
+          label="邮箱"
+          prop="email"
+          align="center"
+        />
+        <el-table-column
+          label="电话"
+          prop="phone"
+          align="center"
+        />
+        <el-table-column
+          label="备注"
+          prop="remarks"
+          align="center"
+        />
+        <el-table-column
+          label="操作"
+          width="150"
+          align="center"
+        >
+          <template #default="scope">
+            <el-button
+              size="small"
+              type="primary"
+              @click="openSupplierEdit(scope.row)"
+            >编辑</el-button>
+            <el-button
+              size="small"
+              type="danger"
+              @click="supplierDelete(scope.row)"
+            >删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!--      分页-->
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="searchSupplierList.pageInfo.page"
+          :page-size="searchSupplierList.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="isOpenSupplierEdit"
+        title="修改供应商信息"
+        direction="rtl"
+        size="30%"
+      >
+        <div>
+          <el-form
+            v-model="supplierEditData"
+            label-position="left"
+            label-width="auto"
+            style="max-width: 400px"
+          >
+            <el-form-item label="供应商名称">
+              <el-input v-model="supplierEditData.name" />
+            </el-form-item>
+            <el-form-item label="负责人">
+              <el-input v-model="supplierEditData.contactName" />
+            </el-form-item>
+            <el-form-item label="城市">
+              <el-input v-model="supplierEditData.city" />
+            </el-form-item>
+            <el-form-item label="地址">
+              <el-input v-model="supplierEditData.address" />
+            </el-form-item>
+            <el-form-item label="邮箱">
+              <el-input v-model="supplierEditData.email" />
+            </el-form-item>
+            <el-form-item label="电话">
+              <el-input v-model="supplierEditData.phone" />
+            </el-form-item>
+            <el-form-item label="备注">
+              <el-input v-model="supplierEditData.remarks" />
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                type="primary"
+                @click="supplierSubmit"
+              >提交</el-button>
+              <el-button @click="isOpenSupplierEdit = false">关闭</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+      </el-drawer>
+      <el-drawer
+        v-model="isOpenSupplierAdd"
+        title="新增供应商信息"
+        direction="rtl"
+        size="30%"
+      >
+        <div>
+          <el-form
+            v-model="supplierAddData"
+            label-position="left"
+            label-width="auto"
+            style="max-width: 400px"
+          >
+            <el-form-item label="供应商名称">
+              <el-input v-model="supplierAddData.name" />
+            </el-form-item>
+            <el-form-item label="负责人">
+              <el-input v-model="supplierAddData.contactName" />
+            </el-form-item>
+            <el-form-item label="城市">
+              <el-input v-model="supplierAddData.city" />
+            </el-form-item>
+            <el-form-item label="地址">
+              <el-input v-model="supplierAddData.address" />
+            </el-form-item>
+            <el-form-item label="邮箱">
+              <el-input v-model="supplierAddData.email" />
+            </el-form-item>
+            <el-form-item label="电话">
+              <el-input v-model="supplierAddData.phone" />
+            </el-form-item>
+            <el-form-item label="备注">
+              <el-input v-model="supplierAddData.remarks" />
+            </el-form-item>
+            <el-form-item>
+              <el-button
+                type="primary"
+                @click="supplierAddSubmit"
+              >提交</el-button>
+              <el-button @click="isOpenSupplierAdd = false">关闭</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+      </el-drawer>
+    </el-main>
+  </el-container>
+</template>
+
+<script setup>
+import { onMounted, ref } from 'vue'
+import { createSupplier, deleteSupplier, querySupplierList, updateSupplier } from '@/api/storehouse'
+import { ElMessage, ElMessageBox } from 'element-plus'
+
+const supplierList = ref()
+const searchSupplierList = ref({
+  pageInfo: {
+    page: 1,
+    pageSize: 10,
+  },
+  name: '',
+})
+const total = ref(0)
+
+const getData = async() => {
+  await querySupplierList(searchSupplierList.value).then(res => {
+    supplierList.value = res.data.list
+    total.value = res.data.total
+    console.log(res)
+  })
+}
+
+// 分页
+const handleSizeChange = (val) => {
+  searchSupplierList.value.pageSize = val
+  getData()
+}
+
+const handleCurrentChange = (val) => {
+  searchSupplierList.value.page = val
+  getData()
+}
+// 修改
+const supplierEditData = ref()
+const isOpenSupplierEdit = ref(false)
+const openSupplierEdit = (val) => {
+  console.log('修改', val)
+  isOpenSupplierEdit.value = true
+  supplierEditData.value = val
+}
+
+const supplierSubmit = async() => {
+  await updateSupplier(supplierEditData.value).then(res => {
+    if (res.code === 0) {
+      ElMessage.success('修改成功')
+      getData()
+    } else {
+      ElMessage.error('修改失败')
+    }
+    isOpenSupplierEdit.value = false
+  })
+}
+
+const supplierDelete = (val) => {
+  ElMessageBox.confirm(
+    '将永久删除该信息。是否继续?',
+    '删除',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(async() => {
+      await deleteSupplier(val).then(res => {
+        if (res.code === 0) {
+          ElMessage.success('删除成功')
+          getData()
+        } else {
+          ElMessage.error('删除失败')
+        }
+      })
+    })
+    .catch(() => {
+      ElMessage({
+        type: 'info',
+        message: '删除已取消',
+      })
+    })
+}
+
+// 新增
+const supplierAddData = ref({
+  name: '',
+  contactName: '',
+  city: '',
+  address: '',
+  email: '',
+  phone: '',
+  remarks: ''
+})
+const isOpenSupplierAdd = ref(false)
+const openSupplierAdd = () => {
+  isOpenSupplierAdd.value = true
+}
+
+const supplierAddSubmit = async() => {
+  if (supplierAddData.value.name === '') {
+    ElMessage.error('供应商名称不能为空')
+    return
+  }
+  await createSupplier(supplierAddData.value).then(res => {
+    if (res.code === 0) {
+      ElMessage.success('添加成功')
+      getData()
+    } else {
+      ElMessage.error('添加失败')
+    }
+    isOpenSupplierAdd.value = false
+  })
+}
+
+onMounted(() => {
+  getData()
+})
+</script>

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

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