Преглед на файлове

Merge remote-tracking branch 'origin/master'

lipenghui преди 4 месеца
родител
ревизия
61694867e7

+ 62 - 0
src/api/pms/iotcargolocation/index.ts

@@ -0,0 +1,62 @@
+import request from '@/config/axios'
+
+// PMS 货位 VO
+export interface IotCargoLocationVO {
+  id: number // 主键
+  deptId: number // 部门id
+  factoryId: number // 工厂id(SAP) 专业公司
+  factoryCode: string // 工厂编码
+  costCenterId: number // 成本中心id (system_sap_org表id)
+  costCenterCode: string // 成本中心 code
+  storageLocationId: number // 库存地点id (system_sap_org表id)
+  storageLocationCode: string // 库存地点编码
+  storageLocationName: string // 库存地点名称
+  storageAreaId: number // 库区id
+  storageAreaName: string // 库区名称
+  shelvesId: number // 货架id
+  shelvesName: string // 货架名称
+  code: string // 货位编码
+  name: string // 货位名称
+  type: number // 货位类型
+  row: number // 排号(货架的水平分区)
+  layer: number // 层号(货架的垂直分区)
+  columnNumber: number // 列号(货架的纵深分区)
+  capacity: number // 货位容量(单位:可自定义,如件数、体积m³、重量kg)
+  currentUsage: number // 当前已使用容量
+  sort: number // 显示顺序
+  status: number // 状态 0启用  1停用
+  remark: string // 备注
+}
+
+// PMS 货位 API
+export const IotCargoLocationApi = {
+  // 查询PMS 货位分页
+  getIotCargoLocationPage: async (params: any) => {
+    return await request.get({ url: `/pms/iot-cargo-location/page`, params })
+  },
+
+  // 查询PMS 货位详情
+  getIotCargoLocation: async (id: number) => {
+    return await request.get({ url: `/pms/iot-cargo-location/get?id=` + id })
+  },
+
+  // 新增PMS 货位
+  createIotCargoLocation: async (data: IotCargoLocationVO) => {
+    return await request.post({ url: `/pms/iot-cargo-location/create`, data })
+  },
+
+  // 修改PMS 货位
+  updateIotCargoLocation: async (data: IotCargoLocationVO) => {
+    return await request.put({ url: `/pms/iot-cargo-location/update`, data })
+  },
+
+  // 删除PMS 货位
+  deleteIotCargoLocation: async (id: number) => {
+    return await request.delete({ url: `/pms/iot-cargo-location/delete?id=` + id })
+  },
+
+  // 导出PMS 货位 Excel
+  exportIotCargoLocation: async (params) => {
+    return await request.download({ url: `/pms/iot-cargo-location/export-excel`, params })
+  },
+}

+ 63 - 59
src/api/pms/iotsapstock/index.ts

@@ -1,59 +1,63 @@
-import request from '@/config/axios'
-
-// PMS SAP 库存(通用库存/项目部库存) VO
-export interface IotSapStockVO {
-  id: number // 主键
-  deptId: number // 组织部门id
-  factory: string // 工厂(SAP) 专业公司
-  projectDepartment: string // 库存地点 - SAP 部门 项目部级 通用库 项目部库
-  materialCode: string // 物料编码
-  materialName: string // 物料名称
-  materialGroupName: string // 物料组
-  materialGroupId: number // 物料组id
-  quantity: number // 数量
-  unitPrice: number // 单价
-  unit: string // 单位
-  safetyStock: number // 安全库存
-  shelvesId: number // 货架id
-  cargoLocationId: number // 库位id
-  type: number // 类型(通用库 项目部库)
-  syncStatus: number // 同步状态 0未同步 1同步成功 2同步失败
-  syncTime: Date // 最后一次同步时间
-  syncError: string // 同步失败时的错误信息
-  sort: number // 排序
-  status: number // 状态 0启用  1停用
-  remark: string // 备注
-}
-
-// PMS SAP 库存(通用库存/项目部库存) API
-export const IotSapStockApi = {
-  // 查询PMS SAP 库存(通用库存/项目部库存)分页
-  getIotSapStockPage: async (params: any) => {
-    return await request.get({ url: `/pms/iot-sap-stock/page`, params })
-  },
-
-  // 查询PMS SAP 库存(通用库存/项目部库存)详情
-  getIotSapStock: async (id: number) => {
-    return await request.get({ url: `/pms/iot-sap-stock/get?id=` + id })
-  },
-
-  // 新增PMS SAP 库存(通用库存/项目部库存)
-  createIotSapStock: async (data: IotSapStockVO) => {
-    return await request.post({ url: `/pms/iot-sap-stock/create`, data })
-  },
-
-  // 修改PMS SAP 库存(通用库存/项目部库存)
-  updateIotSapStock: async (data: IotSapStockVO) => {
-    return await request.put({ url: `/pms/iot-sap-stock/update`, data })
-  },
-
-  // 删除PMS SAP 库存(通用库存/项目部库存)
-  deleteIotSapStock: async (id: number) => {
-    return await request.delete({ url: `/pms/iot-sap-stock/delete?id=` + id })
-  },
-
-  // 导出PMS SAP 库存(通用库存/项目部库存) Excel
-  exportIotSapStock: async (params) => {
-    return await request.download({ url: `/pms/iot-sap-stock/export-excel`, params })
-  },
-}
+import request from '@/config/axios'
+
+// PMS SAP 库存(通用库存/项目部库存) VO
+export interface IotSapStockVO {
+  id: number // 主键
+  deptId: number // 组织部门id
+  factoryId: number // 工厂(SAP) 专业公司id
+  factory: string // 工厂(SAP) 专业公司名称
+  storageLocationId: number // 库存地点id
+  projectDepartment: string // 库存地点 - SAP 部门 项目部级 通用库 项目部库
+  materialCode: string // 物料编码
+  materialName: string // 物料名称
+  materialGroupName: string // 物料组
+  materialGroupId: number // 物料组id
+  quantity: number // 数量
+  unitPrice: number // 单价
+  unit: string // 单位
+  safetyStock: number // 安全库存
+  storageAreaId: number // 库区id
+  storageAreaName: string // 库区名称
+  shelvesId: number // 货架id
+  cargoLocationId: number // 库位id
+  type: number // 类型(通用库 项目部库)
+  syncStatus: number // 同步状态 0未同步 1同步成功 2同步失败
+  syncTime: Date // 最后一次同步时间
+  syncError: string // 同步失败时的错误信息
+  sort: number // 排序
+  status: number // 状态 0启用  1停用
+  remark: string // 备注
+}
+
+// PMS SAP 库存(通用库存/项目部库存) API
+export const IotSapStockApi = {
+  // 查询PMS SAP 库存(通用库存/项目部库存)分页
+  getIotSapStockPage: async (params: any) => {
+    return await request.get({ url: `/pms/iot-sap-stock/page`, params })
+  },
+
+  // 查询PMS SAP 库存(通用库存/项目部库存)详情
+  getIotSapStock: async (id: number) => {
+    return await request.get({ url: `/pms/iot-sap-stock/get?id=` + id })
+  },
+
+  // 新增PMS SAP 库存(通用库存/项目部库存)
+  createIotSapStock: async (data: IotSapStockVO) => {
+    return await request.post({ url: `/pms/iot-sap-stock/create`, data })
+  },
+
+  // 修改PMS SAP 库存(通用库存/项目部库存)
+  updateIotSapStock: async (data: IotSapStockVO) => {
+    return await request.put({ url: `/pms/iot-sap-stock/update`, data })
+  },
+
+  // 删除PMS SAP 库存(通用库存/项目部库存)
+  deleteIotSapStock: async (id: number) => {
+    return await request.delete({ url: `/pms/iot-sap-stock/delete?id=` + id })
+  },
+
+  // 导出PMS SAP 库存(通用库存/项目部库存) Excel
+  exportIotSapStock: async (params) => {
+    return await request.download({ url: `/pms/iot-sap-stock/export-excel`, params })
+  },
+}

+ 60 - 0
src/api/pms/iotshelves/index.ts

@@ -0,0 +1,60 @@
+import request from '@/config/axios'
+
+// PMS 货架 VO
+export interface IotShelvesVO {
+  id: number // 主键
+  deptId: number // 部门id
+  factoryId: number // 工厂id(SAP) 专业公司id system_sap_org表id
+  factoryCode: string // 工厂code
+  factoryName: string // 工厂name
+  costCenterId: number // 成本中心id (system_sap_org表id)
+  costCenterCode: string // 成本中心 code
+  storageLocationId: number // 库存地点id (system_sap_org表id)
+  storageLocationCode: string // 库存地点编码
+  storageLocationName: string // 库存地点名称
+  storageAreaId: number // 仓库区域id(A区 B区)
+  storageAreaName: string // 仓库库区名称
+  code: string // 货架编码
+  name: string // 货架名称
+  type: number // 货架类型
+  sort: number // 显示顺序
+  status: number // 状态 0启用  1停用
+  remark: string // 备注
+}
+
+// PMS 货架 API
+export const IotShelvesApi = {
+  // 查询PMS 货架分页
+  getIotShelvesPage: async (params: any) => {
+    return await request.get({ url: `/pms/iot-shelves/page`, params })
+  },
+
+  getSimpleShelvesList: async (): Promise<IotShelvesVO[]> => {
+    return await request.get({ url: '/pms/iot-shelves/simple-list' })
+  },
+
+  // 查询PMS 货架详情
+  getIotShelves: async (id: number) => {
+    return await request.get({ url: `/pms/iot-shelves/get?id=` + id })
+  },
+
+  // 新增PMS 货架
+  createIotShelves: async (data: IotShelvesVO) => {
+    return await request.post({ url: `/pms/iot-shelves/create`, data })
+  },
+
+  // 修改PMS 货架
+  updateIotShelves: async (data: IotShelvesVO) => {
+    return await request.put({ url: `/pms/iot-shelves/update`, data })
+  },
+
+  // 删除PMS 货架
+  deleteIotShelves: async (id: number) => {
+    return await request.delete({ url: `/pms/iot-shelves/delete?id=` + id })
+  },
+
+  // 导出PMS 货架 Excel
+  exportIotShelves: async (params) => {
+    return await request.download({ url: `/pms/iot-shelves/export-excel`, params })
+  },
+}

+ 58 - 0
src/api/pms/iotstoragearea/index.ts

@@ -0,0 +1,58 @@
+import request from '@/config/axios'
+
+// PMS 库区 VO
+export interface IotStorageAreaVO {
+  id: number // 主键
+  deptId: number // 部门id
+  factoryId: number // 工厂id(SAP) 专业公司id system_sap_org表id
+  factoryCode: string // 工厂code
+  factoryName: string // 工厂name
+  costCenterId: number // 成本中心id (system_sap_org表id)
+  costCenterCode: string // 成本中心 code
+  storageLocationId: number // 库存地点id (system_sap_org表id)
+  storageLocationCode: string // 库存地点编码
+  storageLocationName: string // 库存地点名称
+  code: string // 库区编码
+  name: string // 库区名称
+  type: number // 库区类型
+  sort: number // 显示顺序
+  status: number // 状态 0启用  1停用
+  remark: string // 备注
+}
+
+// PMS 库区 API
+export const IotStorageAreaApi = {
+  // 查询PMS 库区分页
+  getIotStorageAreaPage: async (params: any) => {
+    return await request.get({ url: `/pms/iot-storage-area/page`, params })
+  },
+
+  getSimpleStorageAreaList: async (): Promise<IotStorageAreaVO[]> => {
+    return await request.get({ url: '/pms/iot-storage-area/simple-list' })
+  },
+
+  // 查询PMS 库区详情
+  getIotStorageArea: async (id: number) => {
+    return await request.get({ url: `/pms/iot-storage-area/get?id=` + id })
+  },
+
+  // 新增PMS 库区
+  createIotStorageArea: async (data: IotStorageAreaVO) => {
+    return await request.post({ url: `/pms/iot-storage-area/create`, data })
+  },
+
+  // 修改PMS 库区
+  updateIotStorageArea: async (data: IotStorageAreaVO) => {
+    return await request.put({ url: `/pms/iot-storage-area/update`, data })
+  },
+
+  // 删除PMS 库区
+  deleteIotStorageArea: async (id: number) => {
+    return await request.delete({ url: `/pms/iot-storage-area/delete?id=` + id })
+  },
+
+  // 导出PMS 库区 Excel
+  exportIotStorageArea: async (params) => {
+    return await request.download({ url: `/pms/iot-storage-area/export-excel`, params })
+  },
+}

+ 0 - 1
src/api/system/tree/index.ts

@@ -1,5 +1,4 @@
 import request from '@/config/axios'
-import {IotProductClassifyVO} from "@/api/pms/productclassify";
 import {DeptVO} from "@/api/system/dept";
 
 // pms树 VO

+ 180 - 0
src/views/pms/iotcargolocation/IotCargoLocationForm.vue

@@ -0,0 +1,180 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="库存地点" prop="storageLocationId">
+        <el-select v-model="formData.storageLocationId" clearable placeholder="请选择">
+          <el-option
+            v-for="item in storageLocationList"
+            :key="item.id"
+            :label="item.storageLocationName"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="库区" prop="storageAreaId">
+        <el-select v-model="formData.storageAreaId" clearable placeholder="请选择">
+          <el-option
+            v-for="item in storageAreaList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="货架" prop="shelvesId">
+        <el-select v-model="formData.shelvesId" clearable placeholder="请选择">
+          <el-option
+            v-for="item in shelvesList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="货位编码" prop="code">
+        <el-input v-model="formData.code" placeholder="请输入货位编码" />
+      </el-form-item>
+      <el-form-item label="货位名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入货位名称" />
+      </el-form-item>
+      <el-form-item label="显示顺序" prop="sort">
+        <el-input-number v-model="formData.sort" :min="0" controls-position="right" />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { IotCargoLocationApi, IotCargoLocationVO } from '@/api/pms/iotcargolocation'
+import * as SapOrgApi from "@/api/system/saporg";
+import * as IotStorageAreaApi from "@/api/pms/iotstoragearea";
+import * as IotShelvesApi from "@/api/pms/iotshelves";
+
+/** PMS 货位 表单 */
+defineOptions({ name: 'IotCargoLocationForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const storageLocationList = ref([] as SapOrgApi.SapOrgVO[]) // 库存地点列表
+const storageAreaList = ref([] as IotStorageAreaApi.IotStorageAreaVO[]) // 库存地点区域列表
+const shelvesList = ref([] as IotShelvesApi.IotShelvesVO[]) // 货架列表
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  deptId: undefined,
+  factoryId: undefined,
+  factoryCode: undefined,
+  costCenterId: undefined,
+  costCenterCode: undefined,
+  storageLocationId: undefined,
+  storageLocationCode: undefined,
+  shelvesId: undefined,
+  storageAreaId: undefined,
+  code: undefined,
+  name: undefined,
+  type: undefined,
+  row: undefined,
+  layer: undefined,
+  column: undefined,
+  capacity: undefined,
+  currentUsage: undefined,
+  sort: undefined,
+  status: undefined,
+  remark: undefined,
+})
+const formRules = reactive({
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await IotCargoLocationApi.getIotCargoLocation(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+  // 加载库存地点(SAP)列表
+  storageLocationList.value = await SapOrgApi.SapOrgApi.getSimpleSapOrgList(3)
+  // 加载库区列表
+  storageAreaList.value = await IotStorageAreaApi.IotStorageAreaApi.getSimpleStorageAreaList()
+  // 加载货架列表
+  shelvesList.value = await IotShelvesApi.IotShelvesApi.getSimpleShelvesList()
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as IotCargoLocationVO
+    if (formType.value === 'create') {
+      await IotCargoLocationApi.createIotCargoLocation(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotCargoLocationApi.updateIotCargoLocation(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    deptId: undefined,
+    factoryId: undefined,
+    factoryCode: undefined,
+    costCenterId: undefined,
+    costCenterCode: undefined,
+    storageLocationId: undefined,
+    storageLocationCode: undefined,
+    shelvesId: undefined,
+    code: undefined,
+    name: undefined,
+    type: undefined,
+    row: undefined,
+    layer: undefined,
+    column: undefined,
+    capacity: undefined,
+    currentUsage: undefined,
+    sort: undefined,
+    status: undefined,
+    remark: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 241 - 0
src/views/pms/iotcargolocation/index.vue

@@ -0,0 +1,241 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="库存地点" prop="storageLocationId">
+        <el-select v-model="queryParams.storageLocationId" clearable placeholder="请选择" class="!w-240px">
+          <el-option
+            v-for="item in storageLocationList"
+            :key="item.id"
+            :label="item.storageLocationName"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="库区" prop="storageAreaId">
+        <el-select v-model="queryParams.storageAreaId" clearable placeholder="请选择" class="!w-240px">
+          <el-option
+            v-for="item in storageAreaList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="货架" prop="shelvesId">
+        <el-select v-model="queryParams.shelvesId" clearable placeholder="请选择" class="!w-240px">
+          <el-option
+            v-for="item in shelvesList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="货位名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入货位名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['pms:iot-cargo-location:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['pms:iot-cargo-location:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="库存地点" align="center" prop="storageLocationName" />
+      <el-table-column label="仓库区域" align="center" prop="storageAreaName" />
+      <el-table-column label="货架" align="center" prop="shelvesName" />
+      <el-table-column label="货位编码" align="center" prop="code" />
+      <el-table-column label="货位名称" align="center" prop="name" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['pms:iot-cargo-location:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['pms:iot-cargo-location:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <IotCargoLocationForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotCargoLocationApi, IotCargoLocationVO } from '@/api/pms/iotcargolocation'
+import IotCargoLocationForm from './IotCargoLocationForm.vue'
+import * as SapOrgApi from "@/api/system/saporg";
+import * as IotStorageAreaApi from "@/api/pms/iotstoragearea";
+import * as IotShelvesApi from "@/api/pms/iotshelves";
+
+/** PMS 货位 列表 */
+defineOptions({ name: 'IotCargoLocation' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const storageLocationList = ref([] as SapOrgApi.SapOrgVO[]) // 库存地点列表
+const storageAreaList = ref([] as IotStorageAreaApi.IotStorageAreaVO[]) // 库存地点区域列表
+const shelvesList = ref([] as IotShelvesApi.IotShelvesVO[]) // 货架列表
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotCargoLocationVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: undefined,
+  factoryId: undefined,
+  factoryCode: undefined,
+  costCenterId: undefined,
+  costCenterCode: undefined,
+  storageLocationId: undefined,
+  storageLocationCode: undefined,
+  storageAreaId: undefined,
+  shelvesId: undefined,
+  code: undefined,
+  name: undefined,
+  type: undefined,
+  row: undefined,
+  layer: undefined,
+  columnNumber: undefined,
+  capacity: undefined,
+  currentUsage: undefined,
+  sort: undefined,
+  status: undefined,
+  remark: undefined,
+  createTime: [],
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotCargoLocationApi.getIotCargoLocationPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+  // 加载库存地点(SAP)列表
+  storageLocationList.value = await SapOrgApi.SapOrgApi.getSimpleSapOrgList(3)
+  // 加载库存地点区域(SAP)列表
+  storageAreaList.value = await IotStorageAreaApi.IotStorageAreaApi.getSimpleStorageAreaList()
+  // 加载库存地点货架(SAP)列表
+  shelvesList.value = await IotShelvesApi.IotShelvesApi.getSimpleShelvesList()
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await IotCargoLocationApi.deleteIotCargoLocation(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotCargoLocationApi.exportIotCargoLocation(queryParams)
+    download.excel(data, 'PMS 货位.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 12 - 54
src/views/pms/iotsapstock/IotSapStockForm.vue

@@ -7,73 +7,26 @@
       label-width="100px"
       v-loading="formLoading"
     >
-      <el-form-item label="组织部门id" prop="deptId">
-        <el-input v-model="formData.deptId" placeholder="请输入组织部门id" />
-      </el-form-item>
-      <el-form-item label="工厂(SAP) 专业公司" prop="factory">
-        <el-input v-model="formData.factory" placeholder="请输入工厂(SAP) 专业公司" />
-      </el-form-item>
-      <el-form-item label="库存地点 - SAP 部门 项目部级 通用库 项目部库" prop="projectDepartment">
-        <el-input v-model="formData.projectDepartment" placeholder="请输入库存地点 - SAP 部门 项目部级 通用库 项目部库" />
-      </el-form-item>
       <el-form-item label="物料编码" prop="materialCode">
-        <el-input v-model="formData.materialCode" placeholder="请输入物料编码" />
+        <el-input v-model="formData.materialCode" placeholder="请输入物料编码" disabled/>
       </el-form-item>
       <el-form-item label="物料名称" prop="materialName">
-        <el-input v-model="formData.materialName" placeholder="请输入物料名称" />
-      </el-form-item>
-      <el-form-item label="物料组" prop="materialGroupName">
-        <el-input v-model="formData.materialGroupName" placeholder="请输入物料组" />
-      </el-form-item>
-      <el-form-item label="物料组id" prop="materialGroupId">
-        <el-input v-model="formData.materialGroupId" placeholder="请输入物料组id" />
+        <el-input v-model="formData.materialName" placeholder="请输入物料名称" disabled/>
       </el-form-item>
       <el-form-item label="数量" prop="quantity">
-        <el-input v-model="formData.quantity" placeholder="请输入数量" />
+        <el-input v-model="formData.quantity" placeholder="请输入数量" disabled/>
       </el-form-item>
       <el-form-item label="单价" prop="unitPrice">
-        <el-input v-model="formData.unitPrice" placeholder="请输入单价" />
+        <el-input v-model="formData.unitPrice" placeholder="请输入单价" disabled/>
       </el-form-item>
       <el-form-item label="单位" prop="unit">
-        <el-input v-model="formData.unit" placeholder="请输入单位" />
+        <el-input v-model="formData.unit" placeholder="请输入单位" disabled/>
       </el-form-item>
       <el-form-item label="安全库存" prop="safetyStock">
         <el-input v-model="formData.safetyStock" placeholder="请输入安全库存" />
       </el-form-item>
-      <el-form-item label="货架id" prop="shelvesId">
-        <el-input v-model="formData.shelvesId" placeholder="请输入货架id" />
-      </el-form-item>
-      <el-form-item label="库位id" prop="cargoLocationId">
-        <el-input v-model="formData.cargoLocationId" placeholder="请输入库位id" />
-      </el-form-item>
-      <el-form-item label="类型(通用库 项目部库)" prop="type">
-        <el-select v-model="formData.type" placeholder="请选择类型(通用库 项目部库)">
-          <el-option label="请选择字典生成" value="" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="同步状态 0未同步 1同步成功 2同步失败" prop="syncStatus">
-        <el-radio-group v-model="formData.syncStatus">
-          <el-radio value="1">请选择字典生成</el-radio>
-        </el-radio-group>
-      </el-form-item>
-      <el-form-item label="最后一次同步时间" prop="syncTime">
-        <el-date-picker
-          v-model="formData.syncTime"
-          type="date"
-          value-format="x"
-          placeholder="选择最后一次同步时间"
-        />
-      </el-form-item>
-      <el-form-item label="同步失败时的错误信息" prop="syncError">
-        <el-input v-model="formData.syncError" placeholder="请输入同步失败时的错误信息" />
-      </el-form-item>
       <el-form-item label="排序" prop="sort">
-        <el-input v-model="formData.sort" placeholder="请输入排序" />
-      </el-form-item>
-      <el-form-item label="状态 0启用  1停用" prop="status">
-        <el-radio-group v-model="formData.status">
-          <el-radio value="1">请选择字典生成</el-radio>
-        </el-radio-group>
+        <el-input-number v-model="formData.sort" :min="0" controls-position="right" />
       </el-form-item>
       <el-form-item label="备注" prop="remark">
         <el-input v-model="formData.remark" placeholder="请输入备注" />
@@ -122,6 +75,11 @@ const formData = ref({
   remark: undefined,
 })
 const formRules = reactive({
+  safetyStock: [{
+    pattern: /^(?!-)\d+(\.\d+)?$/,
+    message: '安全库存必须为非负小数',
+    trigger: 'blur'
+  }]
 })
 const formRef = ref() // 表单 Ref
 
@@ -194,4 +152,4 @@ const resetForm = () => {
   }
   formRef.value?.resetFields()
 }
-</script>
+</script>

+ 32 - 188
src/views/pms/iotsapstock/index.vue

@@ -8,32 +8,25 @@
       :inline="true"
       label-width="68px"
     >
-      <el-form-item label="组织部门id" prop="deptId">
-        <el-input
-          v-model="queryParams.deptId"
-          placeholder="请输入组织部门id"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="工厂(SAP) 专业公司" prop="factory">
-        <el-input
-          v-model="queryParams.factory"
-          placeholder="请输入工厂(SAP) 专业公司"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
+      <el-form-item label="工厂" prop="factoryId">
+        <el-select v-model="queryParams.factoryId" clearable placeholder="请选择" class="!w-240px">
+          <el-option
+            v-for="item in factoryList"
+            :key="item.id"
+            :label="item.factoryName"
+            :value="item.id!"
+          />
+        </el-select>
       </el-form-item>
-      <el-form-item label="库存地点 - SAP 部门 项目部级 通用库 项目部库" prop="projectDepartment">
-        <el-input
-          v-model="queryParams.projectDepartment"
-          placeholder="请输入库存地点 - SAP 部门 项目部级 通用库 项目部库"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
+      <el-form-item label="库存地点" prop="storageLocationId">
+        <el-select v-model="queryParams.storageLocationId" clearable placeholder="请选择" class="!w-240px">
+          <el-option
+            v-for="item in storageLocationList"
+            :key="item.id"
+            :label="item.storageLocationName"
+            :value="item.id!"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item label="物料编码" prop="materialCode">
         <el-input
@@ -53,146 +46,6 @@
           class="!w-240px"
         />
       </el-form-item>
-      <el-form-item label="物料组" prop="materialGroupName">
-        <el-input
-          v-model="queryParams.materialGroupName"
-          placeholder="请输入物料组"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="物料组id" prop="materialGroupId">
-        <el-input
-          v-model="queryParams.materialGroupId"
-          placeholder="请输入物料组id"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="数量" prop="quantity">
-        <el-input
-          v-model="queryParams.quantity"
-          placeholder="请输入数量"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="单价" prop="unitPrice">
-        <el-input
-          v-model="queryParams.unitPrice"
-          placeholder="请输入单价"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="单位" prop="unit">
-        <el-input
-          v-model="queryParams.unit"
-          placeholder="请输入单位"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="安全库存" prop="safetyStock">
-        <el-input
-          v-model="queryParams.safetyStock"
-          placeholder="请输入安全库存"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="货架id" prop="shelvesId">
-        <el-input
-          v-model="queryParams.shelvesId"
-          placeholder="请输入货架id"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="库位id" prop="cargoLocationId">
-        <el-input
-          v-model="queryParams.cargoLocationId"
-          placeholder="请输入库位id"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="类型(通用库 项目部库)" prop="type">
-        <el-select
-          v-model="queryParams.type"
-          placeholder="请选择类型(通用库 项目部库)"
-          clearable
-          class="!w-240px"
-        >
-          <el-option label="请选择字典生成" value="" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="同步状态 0未同步 1同步成功 2同步失败" prop="syncStatus">
-        <el-select
-          v-model="queryParams.syncStatus"
-          placeholder="请选择同步状态 0未同步 1同步成功 2同步失败"
-          clearable
-          class="!w-240px"
-        >
-          <el-option label="请选择字典生成" value="" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="最后一次同步时间" prop="syncTime">
-        <el-date-picker
-          v-model="queryParams.syncTime"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="daterange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-          class="!w-220px"
-        />
-      </el-form-item>
-      <el-form-item label="同步失败时的错误信息" prop="syncError">
-        <el-input
-          v-model="queryParams.syncError"
-          placeholder="请输入同步失败时的错误信息"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="排序" prop="sort">
-        <el-input
-          v-model="queryParams.sort"
-          placeholder="请输入排序"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="状态 0启用  1停用" prop="status">
-        <el-select
-          v-model="queryParams.status"
-          placeholder="请选择状态 0启用  1停用"
-          clearable
-          class="!w-240px"
-        >
-          <el-option label="请选择字典生成" value="" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="备注" prop="remark">
-        <el-input
-          v-model="queryParams.remark"
-          placeholder="请输入备注"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
       <el-form-item label="创建时间" prop="createTime">
         <el-date-picker
           v-model="queryParams.createTime"
@@ -231,33 +84,14 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      <el-table-column label="主键" align="center" prop="id" />
-      <el-table-column label="组织部门id" align="center" prop="deptId" />
-      <el-table-column label="工厂(SAP) 专业公司" align="center" prop="factory" />
-      <el-table-column label="库存地点 - SAP 部门 项目部级 通用库 项目部库" align="center" prop="projectDepartment" />
+      <el-table-column label="工厂" align="center" prop="factory" />
+      <el-table-column label="库存地点" align="center" prop="projectDepartment" />
       <el-table-column label="物料编码" align="center" prop="materialCode" />
       <el-table-column label="物料名称" align="center" prop="materialName" />
-      <el-table-column label="物料组" align="center" prop="materialGroupName" />
-      <el-table-column label="物料组id" align="center" prop="materialGroupId" />
       <el-table-column label="数量" align="center" prop="quantity" />
       <el-table-column label="单价" align="center" prop="unitPrice" />
       <el-table-column label="单位" align="center" prop="unit" />
       <el-table-column label="安全库存" align="center" prop="safetyStock" />
-      <el-table-column label="货架id" align="center" prop="shelvesId" />
-      <el-table-column label="库位id" align="center" prop="cargoLocationId" />
-      <el-table-column label="类型(通用库 项目部库)" align="center" prop="type" />
-      <el-table-column label="同步状态 0未同步 1同步成功 2同步失败" align="center" prop="syncStatus" />
-      <el-table-column
-        label="最后一次同步时间"
-        align="center"
-        prop="syncTime"
-        :formatter="dateFormatter"
-        width="180px"
-      />
-      <el-table-column label="同步失败时的错误信息" align="center" prop="syncError" />
-      <el-table-column label="排序" align="center" prop="sort" />
-      <el-table-column label="状态 0启用  1停用" align="center" prop="status" />
-      <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column
         label="创建时间"
         align="center"
@@ -273,7 +107,7 @@
             @click="openForm('update', scope.row.id)"
             v-hasPermi="['pms:iot-sap-stock:update']"
           >
-            编辑
+            安全库存
           </el-button>
           <el-button
             link
@@ -304,6 +138,7 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { IotSapStockApi, IotSapStockVO } from '@/api/pms/iotsapstock'
 import IotSapStockForm from './IotSapStockForm.vue'
+import * as SapOrgApi from "@/api/system/saporg";
 
 /** PMS SAP 库存(通用库存/项目部库存) 列表 */
 defineOptions({ name: 'IotSapStock' })
@@ -311,6 +146,9 @@ defineOptions({ name: 'IotSapStock' })
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 
+const factoryList = ref([] as SapOrgApi.SapOrgVO[])   // 工厂列表
+const storageLocationList = ref([] as SapOrgApi.SapOrgVO[]) // 库存地点列表
+
 const loading = ref(true) // 列表的加载中
 const list = ref<IotSapStockVO[]>([]) // 列表的数据
 const total = ref(0) // 列表的总页数
@@ -318,7 +156,9 @@ const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
   deptId: undefined,
+  factoryId: undefined,
   factory: undefined,
+  storageLocationId: undefined,
   projectDepartment: undefined,
   materialCode: undefined,
   materialName: undefined,
@@ -352,6 +192,10 @@ const getList = async () => {
   } finally {
     loading.value = false
   }
+  // 加载工厂(SAP)列表
+  factoryList.value = await SapOrgApi.SapOrgApi.getSimpleSapOrgList(1)
+  // 加载库存地点(SAP)列表
+  storageLocationList.value = await SapOrgApi.SapOrgApi.getSimpleSapOrgList(3)
 }
 
 /** 搜索按钮操作 */
@@ -404,4 +248,4 @@ const handleExport = async () => {
 onMounted(() => {
   getList()
 })
-</script>
+</script>

+ 157 - 0
src/views/pms/iotshelves/IotShelvesForm.vue

@@ -0,0 +1,157 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="库存地点" prop="storageLocationId">
+        <el-select v-model="formData.storageLocationId" clearable placeholder="请选择">
+          <el-option
+            v-for="item in storageLocationList"
+            :key="item.id"
+            :label="item.storageLocationName"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="仓库区域" prop="storageAreaId">
+        <el-select v-model="formData.storageAreaId" clearable placeholder="请选择">
+          <el-option
+            v-for="item in storageAreaList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="货架编码" prop="code">
+        <el-input v-model="formData.code" placeholder="请输入货架编码" />
+      </el-form-item>
+      <el-form-item label="货架名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入货架名称" />
+      </el-form-item>
+      <el-form-item label="显示顺序" prop="sort">
+        <el-input-number v-model="formData.sort" :min="0" controls-position="right" />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { IotShelvesApi, IotShelvesVO } from '@/api/pms/iotshelves'
+import * as SapOrgApi from "@/api/system/saporg";
+import * as IotStorageAreaApi from "@/api/pms/iotstoragearea";
+
+/** PMS 货架 表单 */
+defineOptions({ name: 'IotShelvesForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const storageLocationList = ref([] as SapOrgApi.SapOrgVO[]) // 库存地点列表
+const storageAreaList = ref([] as IotStorageAreaApi.IotStorageAreaVO[]) // 库存地点区域列表
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  deptId: undefined,
+  factoryId: undefined,
+  factoryCode: undefined,
+  factoryName: undefined,
+  costCenterId: undefined,
+  costCenterCode: undefined,
+  storageLocationId: undefined,
+  storageLocationCode: undefined,
+  storageAreaId: undefined,
+  code: undefined,
+  name: undefined,
+  type: undefined,
+  sort: undefined,
+  status: undefined,
+  remark: undefined,
+})
+const formRules = reactive({
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await IotShelvesApi.getIotShelves(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+  // 加载库存地点(SAP)列表
+  storageLocationList.value = await SapOrgApi.SapOrgApi.getSimpleSapOrgList(3)
+  // 加载库存地点(SAP)列表
+  storageAreaList.value = await IotStorageAreaApi.IotStorageAreaApi.getSimpleStorageAreaList()
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as IotShelvesVO
+    if (formType.value === 'create') {
+      await IotShelvesApi.createIotShelves(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotShelvesApi.updateIotShelves(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    deptId: undefined,
+    factoryId: undefined,
+    factoryCode: undefined,
+    factoryName: undefined,
+    costCenterId: undefined,
+    costCenterCode: undefined,
+    storageLocationId: undefined,
+    storageLocationCode: undefined,
+    storageAreaId: undefined,
+    code: undefined,
+    name: undefined,
+    type: undefined,
+    sort: undefined,
+    status: undefined,
+    remark: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 221 - 0
src/views/pms/iotshelves/index.vue

@@ -0,0 +1,221 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="库存地点" prop="storageLocationId">
+        <el-select v-model="queryParams.storageLocationId" clearable placeholder="请选择" class="!w-240px">
+          <el-option
+            v-for="item in storageLocationList"
+            :key="item.id"
+            :label="item.storageLocationName"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="仓库区域" prop="storageAreaId">
+        <el-select v-model="queryParams.storageAreaId" clearable placeholder="请选择" class="!w-240px">
+          <el-option
+            v-for="item in storageAreaList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="货架名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入货架名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['pms:iot-shelves:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['pms:iot-shelves:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="库存地点" align="center" prop="storageLocationName" />
+      <el-table-column label="仓库区域" align="center" prop="storageAreaName" />
+      <el-table-column label="货架编码" align="center" prop="code" />
+      <el-table-column label="货架名称" align="center" prop="name" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['pms:iot-shelves:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['pms:iot-shelves:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <IotShelvesForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotShelvesApi, IotShelvesVO } from '@/api/pms/iotshelves'
+import IotShelvesForm from './IotShelvesForm.vue'
+import * as SapOrgApi from "@/api/system/saporg";
+import * as IotStorageAreaApi from "@/api/pms/iotstoragearea";
+
+/** PMS 货架 列表 */
+defineOptions({ name: 'IotShelves' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const storageLocationList = ref([] as SapOrgApi.SapOrgVO[]) // 库存地点列表
+const storageAreaList = ref([] as IotStorageAreaApi.IotStorageAreaVO[]) // 库存地点区域列表
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotShelvesVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: undefined,
+  factoryId: undefined,
+  factoryCode: undefined,
+  factoryName: undefined,
+  costCenterId: undefined,
+  costCenterCode: undefined,
+  storageLocationId: undefined,
+  storageLocationCode: undefined,
+  storageAreaId: undefined,
+  code: undefined,
+  name: undefined,
+  type: undefined,
+  sort: undefined,
+  status: undefined,
+  remark: undefined,
+  createTime: [],
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotShelvesApi.getIotShelvesPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+  // 加载库存地点(SAP)列表
+  storageLocationList.value = await SapOrgApi.SapOrgApi.getSimpleSapOrgList(3)
+  // 加载库存地点区域(SAP)列表
+  storageAreaList.value = await IotStorageAreaApi.IotStorageAreaApi.getSimpleStorageAreaList()
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await IotShelvesApi.deleteIotShelves(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotShelvesApi.exportIotShelves(queryParams)
+    download.excel(data, 'PMS 货架.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>

+ 145 - 0
src/views/pms/iotstoragearea/IotStorageAreaForm.vue

@@ -0,0 +1,145 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="库存地点" prop="storageLocationId">
+        <el-select v-model="formData.storageLocationId" clearable placeholder="请选择">
+          <el-option
+            v-for="item in storageLocationList"
+            :key="item.id"
+            :label="item.storageLocationName"
+            :value="item.id!"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="库区编码" prop="code">
+        <el-input v-model="formData.code" placeholder="请输入库区编码" />
+      </el-form-item>
+      <el-form-item label="库区名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入库区名称" />
+      </el-form-item>
+      <el-form-item label="显示排序" prop="sort">
+        <el-input-number v-model="formData.sort" :min="0" controls-position="right" />
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import {IotStorageAreaApi, IotStorageAreaVO} from '@/api/pms/iotstoragearea'
+import * as SapOrgApi from "@/api/system/saporg";
+import {FormRules} from 'element-plus'
+
+/** PMS 库区 表单 */
+defineOptions({ name: 'IotStorageAreaForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+
+const storageLocationList = ref([] as SapOrgApi.SapOrgVO[]) // 库存地点列表
+
+const formData = ref({
+  id: undefined,
+  deptId: undefined,
+  factoryId: undefined,
+  factoryCode: undefined,
+  factoryName: undefined,
+  costCenterId: undefined,
+  costCenterCode: undefined,
+  storageLocationId: undefined,
+  storageLocationCode: undefined,
+  code: undefined,
+  name: undefined,
+  type: undefined,
+  sort: undefined,
+  status: undefined,
+  remark: undefined,
+})
+const formRules = reactive<FormRules>({
+  storageLocationId: [{ required: true, message: '库存地点不能为空', trigger: 'blur' }],
+  name: [{ required: true, message: '库区名称不能为空', trigger: 'blur' }],
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await IotStorageAreaApi.getIotStorageArea(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+  // 加载库存地点(SAP)列表
+  storageLocationList.value = await SapOrgApi.SapOrgApi.getSimpleSapOrgList(3)
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as IotStorageAreaVO
+    if (formType.value === 'create') {
+      await IotStorageAreaApi.createIotStorageArea(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await IotStorageAreaApi.updateIotStorageArea(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    deptId: undefined,
+    factoryId: undefined,
+    factoryCode: undefined,
+    factoryName: undefined,
+    costCenterId: undefined,
+    costCenterCode: undefined,
+    storageLocationId: undefined,
+    storageLocationCode: undefined,
+    code: undefined,
+    name: undefined,
+    type: undefined,
+    sort: undefined,
+    status: undefined,
+    remark: undefined,
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 191 - 0
src/views/pms/iotstoragearea/index.vue

@@ -0,0 +1,191 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="库区名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入库区名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['pms:iot-storage-area:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['pms:iot-storage-area:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="库存地点" align="center" prop="storageLocationName" />
+      <el-table-column label="库区编码" align="center" prop="code" />
+      <el-table-column label="库区名称" align="center" prop="name" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+      <el-table-column label="操作" align="center" min-width="120px">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['pms:iot-storage-area:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['pms:iot-storage-area:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <IotStorageAreaForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { IotStorageAreaApi, IotStorageAreaVO } from '@/api/pms/iotstoragearea'
+import IotStorageAreaForm from './IotStorageAreaForm.vue'
+
+/** PMS 库区 列表 */
+defineOptions({ name: 'IotStorageArea' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<IotStorageAreaVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: undefined,
+  factoryId: undefined,
+  factoryCode: undefined,
+  factoryName: undefined,
+  costCenterId: undefined,
+  costCenterCode: undefined,
+  storageLocationId: undefined,
+  storageLocationCode: undefined,
+  storageLocationName: undefined,
+  code: undefined,
+  name: undefined,
+  type: undefined,
+  sort: undefined,
+  status: undefined,
+  remark: undefined,
+  createTime: [],
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotStorageAreaApi.getIotStorageAreaPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await IotStorageAreaApi.deleteIotStorageArea(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await IotStorageAreaApi.exportIotStorageArea(queryParams)
+    download.excel(data, 'PMS 库区.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>