Browse Source

pms 保养工单 填报 功能优化

zhangcl 3 months ago
parent
commit
f188058a47

+ 63 - 58
src/api/pms/iotmainworkorder/index.ts

@@ -1,58 +1,63 @@
-import request from '@/config/axios'
-
-// 保养工单 VO
-export interface IotMainWorkOrderVO {
-  id: number // 主键id
-  planId: number // 保养计划id
-  planSerialNumber: string // 保养计划编号
-  deptId: number // 组织id
-  orderNumber: string // 工单号
-  name: string // 工单名称 (吐哈-C14-保养计划)
-  type: number // 工单类型(1计划生成  2临时新建)
-  responsiblePerson: string // 负责人id 多个以逗号分隔
-  responsiblePersonName: string // 负责人id 多个以逗号分隔
-  cost: number // 保养费用
-  result: number // 保养结果(1待执行 2已执行)
-  otherCost: number // 其他费用
-  laborCost: number // 人工费用
-  outsourcingFlag: number // 是否委外 0否  1是
-  actualStartTime: Date // 实际保养开始时间
-  actualEndTime: Date // 实际保养结束时间
-  remark: string // 备注
-  status: number // 状态 0启用  1停用
-  processInstanceId: string // 流程实例id
-  auditStatus: number // 审批状态 未提交、审批中、审批通过、审批不通过、已取消
-}
-
-// 保养工单 API
-export const IotMainWorkOrderApi = {
-  // 查询保养工单分页
-  getIotMainWorkOrderPage: async (params: any) => {
-    return await request.get({ url: `/pms/iot-main-work-order/page`, params })
-  },
-
-  // 查询保养工单详情
-  getIotMainWorkOrder: async (id: number) => {
-    return await request.get({ url: `/pms/iot-main-work-order/get?id=` + id })
-  },
-
-  // 新增保养工单
-  createIotMainWorkOrder: async (data: IotMainWorkOrderVO) => {
-    return await request.post({ url: `/pms/iot-main-work-order/create`, data })
-  },
-
-  // 修改保养工单
-  updateIotMainWorkOrder: async (data: IotMainWorkOrderVO) => {
-    return await request.put({ url: `/pms/iot-main-work-order/update`, data })
-  },
-
-  // 删除保养工单
-  deleteIotMainWorkOrder: async (id: number) => {
-    return await request.delete({ url: `/pms/iot-main-work-order/delete?id=` + id })
-  },
-
-  // 导出保养工单 Excel
-  exportIotMainWorkOrder: async (params) => {
-    return await request.download({ url: `/pms/iot-main-work-order/export-excel`, params })
-  },
-}
+import request from '@/config/axios'
+
+// 保养工单 VO
+export interface IotMainWorkOrderVO {
+  id: number // 主键id
+  planId: number // 保养计划id
+  planSerialNumber: string // 保养计划编号
+  deptId: number // 组织id
+  orderNumber: string // 工单号
+  name: string // 工单名称 (吐哈-C14-保养计划)
+  type: number // 工单类型(1计划生成  2临时新建)
+  responsiblePerson: string // 负责人id 多个以逗号分隔
+  responsiblePersonName: string // 负责人id 多个以逗号分隔
+  cost: number // 保养费用
+  result: number // 保养结果(1待执行 2已执行)
+  otherCost: number // 其他费用
+  laborCost: number // 人工费用
+  outsourcingFlag: number // 是否委外 0否  1是
+  actualStartTime: Date // 实际保养开始时间
+  actualEndTime: Date // 实际保养结束时间
+  remark: string // 备注
+  status: number // 状态 0启用  1停用
+  processInstanceId: string // 流程实例id
+  auditStatus: number // 审批状态 未提交、审批中、审批通过、审批不通过、已取消
+}
+
+// 保养工单 API
+export const IotMainWorkOrderApi = {
+  // 查询保养工单分页
+  getIotMainWorkOrderPage: async (params: any) => {
+    return await request.get({ url: `/pms/iot-main-work-order/page`, params })
+  },
+
+  // 查询保养工单详情
+  getIotMainWorkOrder: async (id: number) => {
+    return await request.get({ url: `/pms/iot-main-work-order/get?id=` + id })
+  },
+
+  // 新增保养工单
+  createIotMainWorkOrder: async (data: IotMainWorkOrderVO) => {
+    return await request.post({ url: `/pms/iot-main-work-order/create`, data })
+  },
+
+  // 修改保养工单
+  updateIotMainWorkOrder: async (data: IotMainWorkOrderVO) => {
+    return await request.put({ url: `/pms/iot-main-work-order/update`, data })
+  },
+
+  // 填写保养工单
+  fillWorkOrder: async (data: any) => {
+    return await request.put({ url: `/pms/iot-main-work-order/fillWorkOrder`, data })
+  },
+
+  // 删除保养工单
+  deleteIotMainWorkOrder: async (id: number) => {
+    return await request.delete({ url: `/pms/iot-main-work-order/delete?id=` + id })
+  },
+
+  // 导出保养工单 Excel
+  exportIotMainWorkOrder: async (params) => {
+    return await request.download({ url: `/pms/iot-main-work-order/export-excel`, params })
+  },
+}

+ 67 - 63
src/api/pms/iotmainworkorderbommaterial/index.ts

@@ -1,63 +1,67 @@
-import request from '@/config/axios'
-
-// PMS 保养工单明细设备BOM挂载物料关联 VO
-export interface IotMainWorkOrderBomMaterialVO {
-  id: number // 主键
-  mainPlanId: number // 保养计划id
-  workOrderId: number // 保养工单id
-  mainWorkOrderDetailId: number // 保养工单明细id
-  deviceCategoryId: number // 物料所属设备分类
-  bomNodeId: number // 保养工单明细设备BOM节点id
-  name: string // 设备分类公共BOM节点名称
-  code: string // 设备分类公共BOM节点编码
-  materialId: number // 物料id
-  materialCode: string // 物料编码
-  materialName: string // 物料名称
-  quantity: number // 消耗数量
-  unitPrice: number // 单价(元)
-  totalPrice: number // 总金额(元)
-  kilometerCycle: number // 公里数周期(千米)
-  kiloCycleLead: number // 公里数周期-提前量(千米)
-  timePeriod: number // 时间周期(小时)
-  timePeriodLead: number // 时间周期-提前量(小时)
-  naturalDatePeriod: number // 自然日周期(天)
-  naturalDatePeroidLead: number // 自然日周期-提前量(天)
-  materialSource: string // 物料来源 (SAP库存 本地库存...)
-  inventoryAddress: string // 库存地点
-  sort: number // 排序
-  status: number // 状态 0启用  1停用
-  remark: string // 备注
-}
-
-// PMS 保养工单明细设备BOM挂载物料关联 API
-export const IotMainWorkOrderBomMaterialApi = {
-  // 查询PMS 保养工单明细设备BOM挂载物料关联分页
-  getIotMainWorkOrderBomMaterialPage: async (params: any) => {
-    return await request.get({ url: `/pms/iot-main-work-order-bom-material/page`, params })
-  },
-
-  // 查询PMS 保养工单明细设备BOM挂载物料关联详情
-  getIotMainWorkOrderBomMaterial: async (id: number) => {
-    return await request.get({ url: `/pms/iot-main-work-order-bom-material/get?id=` + id })
-  },
-
-  // 新增PMS 保养工单明细设备BOM挂载物料关联
-  createIotMainWorkOrderBomMaterial: async (data: IotMainWorkOrderBomMaterialVO) => {
-    return await request.post({ url: `/pms/iot-main-work-order-bom-material/create`, data })
-  },
-
-  // 修改PMS 保养工单明细设备BOM挂载物料关联
-  updateIotMainWorkOrderBomMaterial: async (data: IotMainWorkOrderBomMaterialVO) => {
-    return await request.put({ url: `/pms/iot-main-work-order-bom-material/update`, data })
-  },
-
-  // 删除PMS 保养工单明细设备BOM挂载物料关联
-  deleteIotMainWorkOrderBomMaterial: async (id: number) => {
-    return await request.delete({ url: `/pms/iot-main-work-order-bom-material/delete?id=` + id })
-  },
-
-  // 导出PMS 保养工单明细设备BOM挂载物料关联 Excel
-  exportIotMainWorkOrderBomMaterial: async (params) => {
-    return await request.download({ url: `/pms/iot-main-work-order-bom-material/export-excel`, params })
-  },
-}
+import request from '@/config/axios'
+
+// PMS 保养工单明细设备BOM挂载物料关联 VO
+export interface IotMainWorkOrderBomMaterialVO {
+  id: number // 主键
+  mainPlanId: number // 保养计划id
+  workOrderId: number // 保养工单id
+  mainWorkOrderDetailId: number // 保养工单明细id
+  deviceCategoryId: number // 物料所属设备分类
+  bomNodeId: number // 保养工单明细设备BOM节点id
+  name: string // 设备分类公共BOM节点名称
+  code: string // 设备分类公共BOM节点编码
+  materialId: number // 物料id
+  materialCode: string // 物料编码
+  materialName: string // 物料名称
+  quantity: number // 消耗数量
+  unitPrice: number // 单价(元)
+  totalPrice: number // 总金额(元)
+  kilometerCycle: number // 公里数周期(千米)
+  kiloCycleLead: number // 公里数周期-提前量(千米)
+  timePeriod: number // 时间周期(小时)
+  timePeriodLead: number // 时间周期-提前量(小时)
+  naturalDatePeriod: number // 自然日周期(天)
+  naturalDatePeroidLead: number // 自然日周期-提前量(天)
+  materialSource: string // 物料来源 (SAP库存 本地库存...)
+  inventoryAddress: string // 库存地点
+  sort: number // 排序
+  status: number // 状态 0启用  1停用
+  remark: string // 备注
+}
+
+// PMS 保养工单明细设备BOM挂载物料关联 API
+export const IotMainWorkOrderBomMaterialApi = {
+  // 查询PMS 保养工单明细设备BOM挂载物料关联分页
+  getIotMainWorkOrderBomMaterialPage: async (params: any) => {
+    return await request.get({ url: `/pms/iot-main-work-order-bom-material/page`, params })
+  },
+
+  // 查询PMS 保养工单明细设备BOM挂载物料关联详情
+  getIotMainWorkOrderBomMaterial: async (id: number) => {
+    return await request.get({ url: `/pms/iot-main-work-order-bom-material/get?id=` + id })
+  },
+
+  // 新增PMS 保养工单明细设备BOM挂载物料关联
+  createIotMainWorkOrderBomMaterial: async (data: IotMainWorkOrderBomMaterialVO) => {
+    return await request.post({ url: `/pms/iot-main-work-order-bom-material/create`, data })
+  },
+
+  // 修改PMS 保养工单明细设备BOM挂载物料关联
+  updateIotMainWorkOrderBomMaterial: async (data: IotMainWorkOrderBomMaterialVO) => {
+    return await request.put({ url: `/pms/iot-main-work-order-bom-material/update`, data })
+  },
+
+  // 删除PMS 保养工单明细设备BOM挂载物料关联
+  deleteIotMainWorkOrderBomMaterial: async (id: number) => {
+    return await request.delete({ url: `/pms/iot-main-work-order-bom-material/delete?id=` + id })
+  },
+
+  // 导出PMS 保养工单明细设备BOM挂载物料关联 Excel
+  exportIotMainWorkOrderBomMaterial: async (params) => {
+    return await request.download({ url: `/pms/iot-main-work-order-bom-material/export-excel`, params })
+  },
+
+  workOrderMaterials: async (params) => {
+    return await request.get({ url: `/pms/iot-main-work-order-bom-material/workOrderMaterials`, params })
+  },
+}

+ 121 - 19
src/views/pms/iotmainworkorder/IotMainWorkOrder.vue

@@ -63,6 +63,7 @@
     <!-- 列表 -->
     <!-- 列表 -->
     <ContentWrap>
     <ContentWrap>
       <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
       <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+        <el-table-column label="bom节点" align="center" prop="bomNodeId" v-if="false"/>
         <el-table-column label="设备编码" align="center" prop="deviceCode" />
         <el-table-column label="设备编码" align="center" prop="deviceCode" />
         <el-table-column label="设备名称" align="center" prop="deviceName" />
         <el-table-column label="设备名称" align="center" prop="deviceName" />
         <el-table-column label="累计运行时间(H)" align="center" prop="totalRunTime" :formatter="erpPriceTableColumnFormatter"/>
         <el-table-column label="累计运行时间(H)" align="center" prop="totalRunTime" :formatter="erpPriceTableColumnFormatter"/>
@@ -74,6 +75,7 @@
               v-model="scope.row.mileageRule"
               v-model="scope.row.mileageRule"
               :active-value="0"
               :active-value="0"
               :inactive-value="1"
               :inactive-value="1"
+              :disabled="true"
             />
             />
           </template>
           </template>
         </el-table-column>
         </el-table-column>
@@ -83,6 +85,7 @@
               v-model="scope.row.runningTimeRule"
               v-model="scope.row.runningTimeRule"
               :active-value="0"
               :active-value="0"
               :inactive-value="1"
               :inactive-value="1"
+              :disabled="true"
             />
             />
           </template>
           </template>
         </el-table-column>
         </el-table-column>
@@ -92,6 +95,7 @@
               v-model="scope.row.naturalDateRule"
               v-model="scope.row.naturalDateRule"
               :active-value="0"
               :active-value="0"
               :inactive-value="1"
               :inactive-value="1"
+              :disabled="true"
             />
             />
           </template>
           </template>
         </el-table-column>
         </el-table-column>
@@ -108,11 +112,43 @@
                   配置
                   配置
                 </el-button>
                 </el-button>
               </div>
               </div>
+              <div style="margin-left: 12px">
+                <el-button
+                  link
+                  type="primary"
+                  @click="openMaterialForm(scope.row)"
+                >
+                  选择物料
+                </el-button>
+              </div>
+              <div style="margin-left: 12px">
+                <el-button
+                  link
+                  type="primary"
+                  @click="handleView(scope.row.bomNodeId)"
+                >
+                  物料详情
+                </el-button>
+              </div>
             </div>
             </div>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
       </el-table>
       </el-table>
     </ContentWrap>
     </ContentWrap>
+
+    <!-- 选择的物料列表 -->
+    <ContentWrap>
+      <el-table v-loading="false" :data="materialList" :stripe="true" :show-overflow-tooltip="true" v-if="false">
+        <el-table-column label="bom节点" align="center" prop="bomNodeId" />
+        <el-table-column label="物料编码" align="center" prop="materialCode" />
+        <el-table-column label="物料名称" align="center" prop="materialName" />
+        <el-table-column label="单位" align="center" prop="unit" />
+        <el-table-column label="单价(CNY/元)" align="center" prop="unitPrice" :formatter="erpPriceTableColumnFormatter"/>
+        <el-table-column label="消耗数量" align="center" prop="quantity" />
+        <el-table-column label="总库存数量" align="center" prop="totalInventoryQuantity" />
+      </el-table>
+    </ContentWrap>
+
   </ContentWrap>
   </ContentWrap>
   <ContentWrap>
   <ContentWrap>
     <el-form>
     <el-form>
@@ -140,6 +176,7 @@
           :precision="2"
           :precision="2"
           :min="0"
           :min="0"
           controls-position="right"
           controls-position="right"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
       <!-- 推迟公里数 -->
       <!-- 推迟公里数 -->
@@ -166,6 +203,7 @@
           :precision="1"
           :precision="1"
           :min="0"
           :min="0"
           controls-position="right"
           controls-position="right"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
       <!-- 推迟时长 -->
       <!-- 推迟时长 -->
@@ -193,6 +231,7 @@
           placeholder="选择日期"
           placeholder="选择日期"
           format="YYYY-MM-DD"
           format="YYYY-MM-DD"
           value-format="YYYY-MM-DD"
           value-format="YYYY-MM-DD"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
       <!-- 推迟自然日期 -->
       <!-- 推迟自然日期 -->
@@ -219,6 +258,7 @@
           :precision="2"
           :precision="2"
           :min="0"
           :min="0"
           controls-position="right"
           controls-position="right"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
       <el-form-item
       <el-form-item
@@ -231,6 +271,7 @@
           :precision="2"
           :precision="2"
           :min="0"
           :min="0"
           controls-position="right"
           controls-position="right"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
       <el-form-item
       <el-form-item
@@ -243,6 +284,7 @@
           :precision="1"
           :precision="1"
           :min="0"
           :min="0"
           controls-position="right"
           controls-position="right"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
       <el-form-item
       <el-form-item
@@ -255,6 +297,7 @@
           :precision="1"
           :precision="1"
           :min="0"
           :min="0"
           controls-position="right"
           controls-position="right"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
       <el-form-item
       <el-form-item
@@ -266,6 +309,7 @@
           v-model="configDialog.form.nextNaturalDate"
           v-model="configDialog.form.nextNaturalDate"
           :min="0"
           :min="0"
           controls-position="right"
           controls-position="right"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
       <el-form-item
       <el-form-item
@@ -277,6 +321,7 @@
           v-model="configDialog.form.naturalDatePeriodLead"
           v-model="configDialog.form.naturalDatePeriodLead"
           :min="0"
           :min="0"
           controls-position="right"
           controls-position="right"
+          :disabled="true"
         />
         />
       </el-form-item>
       </el-form-item>
     </el-form>
     </el-form>
@@ -285,7 +330,15 @@
       <el-button type="primary" @click="saveConfig">保存</el-button>
       <el-button type="primary" @click="saveConfig">保存</el-button>
     </template>
     </template>
   </el-dialog>
   </el-dialog>
-
+  <!-- 表单弹窗:添加/修改 -->
+  <WorkOrderMaterial ref="materialFormRef" @choose="selectChoose" />
+  <!-- 抽屉组件 展示已经选择的物料 并编辑物料消耗 -->
+  <MaterialListDrawer
+    :model-value="drawerVisible"
+    @update:model-value="val => drawerVisible = val"
+    :node-id="currentBomNodeId"
+    :materials="materialList.filter(item => item.bomNodeId === currentBomNodeId)"
+  />
 </template>
 </template>
 <script setup lang="ts">
 <script setup lang="ts">
 import { IotMaintainApi, IotMaintainVO } from '@/api/pms/maintain'
 import { IotMaintainApi, IotMaintainVO } from '@/api/pms/maintain'
@@ -293,8 +346,10 @@ import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
 import * as UserApi from '@/api/system/user'
 import * as UserApi from '@/api/system/user'
 import { useUserStore } from '@/store/modules/user'
 import { useUserStore } from '@/store/modules/user'
 import { ref } from 'vue'
 import { ref } from 'vue'
+import type { ComponentPublicInstance } from 'vue'
 import { IotMaintenanceBomApi, IotMaintenanceBomVO } from '@/api/pms/iotmaintenancebom'
 import { IotMaintenanceBomApi, IotMaintenanceBomVO } from '@/api/pms/iotmaintenancebom'
 import { IotMainWorkOrderBomApi, IotMainWorkOrderBomVO } from '@/api/pms/iotmainworkorderbom'
 import { IotMainWorkOrderBomApi, IotMainWorkOrderBomVO } from '@/api/pms/iotmainworkorderbom'
+import { IotMainWorkOrderBomMaterialApi, IotMainWorkOrderBomMaterialVO } from '@/api/pms/iotmainworkorderbommaterial'
 import { IotMaintenancePlanApi, IotMaintenancePlanVO } from '@/api/pms/maintenance'
 import { IotMaintenancePlanApi, IotMaintenancePlanVO } from '@/api/pms/maintenance'
 import { IotMainWorkOrderApi, IotMainWorkOrderVO } from '@/api/pms/iotmainworkorder'
 import { IotMainWorkOrderApi, IotMainWorkOrderVO } from '@/api/pms/iotmainworkorder'
 import { useTagsViewStore } from '@/store/modules/tagsView'
 import { useTagsViewStore } from '@/store/modules/tagsView'
@@ -303,6 +358,8 @@ import MainPlanDeviceList from "@/views/pms/maintenance/MainPlanDeviceList.vue";
 import * as DeptApi from "@/api/system/dept";
 import * as DeptApi from "@/api/system/dept";
 import {erpPriceTableColumnFormatter} from "@/utils";
 import {erpPriceTableColumnFormatter} from "@/utils";
 import dayjs from 'dayjs'
 import dayjs from 'dayjs'
+import MaterialListDrawer from "@/views/pms/iotmainworkorder/SelectedMaterialDrawer.vue";
+import WorkOrderMaterial from "@/views/pms/iotmainworkorder/WorkOrderMaterial.vue";
 
 
 /** 保养计划 表单 */
 /** 保养计划 表单 */
 defineOptions({ name: 'IotMainWorkOrderBom' })
 defineOptions({ name: 'IotMainWorkOrderBom' })
@@ -314,12 +371,16 @@ const { currentRoute, push } = useRouter()
 const deptUsers = ref<UserApi.UserVO[]>([]) // 用户列表
 const deptUsers = ref<UserApi.UserVO[]>([]) // 用户列表
 const dept = ref() // 当前登录人所属部门对象
 const dept = ref() // 当前登录人所属部门对象
 const configFormRef = ref() // 配置弹出框对象
 const configFormRef = ref() // 配置弹出框对象
+const bomNodeId = ref() // 最新的bomNodeId
 const dialogTitle = ref('') // 弹窗的标题
 const dialogTitle = ref('') // 弹窗的标题
 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
 const formType = ref('') // 表单的类型:create - 新增;update - 修改
 const formType = ref('') // 表单的类型:create - 新增;update - 修改
 const deviceLabel = ref('') // 表单的类型:create - 新增;update - 修改
 const deviceLabel = ref('') // 表单的类型:create - 新增;update - 修改
-// const list = ref<IotMaintenanceBomVO[]>([]) // 设备bom关联列表的数据
+const drawerVisible = ref<boolean>(false)
+const currentBomNodeId = ref() // 当前选中的bom节点
+const showDrawer = ref()
 const list = ref<IotMainWorkOrderBomVO[]>([]) // 保养工单bom关联列表的数据
 const list = ref<IotMainWorkOrderBomVO[]>([]) // 保养工单bom关联列表的数据
+const materialList = ref<IotMainWorkOrderBomMaterialVO[]>([]) // 保养工单bom关联物料列表
 const deviceIds = ref<number[]>([]) // 已经选择的设备id数组
 const deviceIds = ref<number[]>([]) // 已经选择的设备id数组
 const { params, name } = useRoute() // 查询参数
 const { params, name } = useRoute() // 查询参数
 const id = params.id
 const id = params.id
@@ -338,6 +399,12 @@ const formRules = reactive({
 })
 })
 const formRef = ref() // 表单 Ref
 const formRef = ref() // 表单 Ref
 
 
+interface MaterialFormExpose {
+  open: (deptId: number, bomNodeId: number) => void
+}
+
+const materialFormRef = ref<MaterialFormExpose>();
+
 // 新增配置相关状态
 // 新增配置相关状态
 const configDialog = reactive({
 const configDialog = reactive({
   visible: false,
   visible: false,
@@ -393,6 +460,45 @@ const openConfigDialog = (row: IotMainWorkOrderBomVO) => {
   configDialog.visible = true
   configDialog.visible = true
 }
 }
 
 
+// const materialFormRef = ref()
+const openMaterialForm = (row: any) => {
+  bomNodeId.value = row.bomNodeId;
+  console.log('这是一个对象:', row.bomNodeId)
+  materialFormRef.value.open(formData.value.deptId, bomNodeId.value)
+}
+
+const selectChoose = (selectedMaterial) => {
+  selectedMaterial.bomNodeId = bomNodeId.value
+  // 关联 bomNodeId
+  const processedMaterials = selectedMaterial.map(material => ({
+    ...material,
+    bomNodeId: bomNodeId.value // 统一关联当前行的 bomNodeId
+  }));
+
+  // 避免重复添加
+  processedMaterials.forEach(newMaterial => {
+    // 检查是否已存在相同 bomNodeId + materialCode 的条目
+    const isExist = materialList.value.some(item =>
+      item.bomNodeId === bomNodeId.value &&
+      item.materialCode === newMaterial.materialCode
+    );
+
+    if (!isExist) {
+      materialList.value.push(newMaterial);
+    }
+  });
+  console.log('选择完成的数据:', JSON.stringify(selectedMaterial))
+  console.log('添加到本地列表的数据:', materialList.value)
+}
+
+/** 查看已经选择的物料 并编辑 */
+const handleView = (nodeId) => {
+  currentBomNodeId.value = nodeId
+  drawerVisible.value = true
+  // showDrawer.value.openDrawer()
+  console.log('当前bom节点:', currentBomNodeId.value)
+}
+
 // 保存配置
 // 保存配置
 const saveConfig = () => {
 const saveConfig = () => {
   (configFormRef.value as any).validate((valid: boolean) => {
   (configFormRef.value as any).validate((valid: boolean) => {
@@ -464,16 +570,22 @@ const submitForm = async () => {
   // 校验表单
   // 校验表单
   await formRef.value.validate()
   await formRef.value.validate()
   // 校验表格数据
   // 校验表格数据
-  const isValid = validateTableData()
-  if (!isValid) return
+  // const isValid = validateTableData()
+  // if (!isValid) return
   // 提交请求
   // 提交请求
   formLoading.value = true
   formLoading.value = true
   try {
   try {
     const data = {
     const data = {
-      mainPlan: formData.value,
-      mainPlanBom: list.value
+      mainWorkOrder: formData.value,
+      mainWorkOrderBom: list.value,
+      mainWorkOrderMaterials: materialList.value
     }
     }
-    if (formType.value === 'create') {
+    debugger
+    await IotMainWorkOrderApi.fillWorkOrder(data)
+    message.success(t('common.createSuccess'))
+    close()
+
+    /* if (formType.value === 'create') {
       await IotMaintenancePlanApi.createIotMaintenancePlan(data)
       await IotMaintenancePlanApi.createIotMaintenancePlan(data)
       message.success(t('common.createSuccess'))
       message.success(t('common.createSuccess'))
       close()
       close()
@@ -481,7 +593,7 @@ const submitForm = async () => {
       await IotMaintainApi.updateIotMaintain(data)
       await IotMaintainApi.updateIotMaintain(data)
       message.success(t('common.updateSuccess'))
       message.success(t('common.updateSuccess'))
       close()
       close()
-    }
+    } */
     // 发送操作成功的事件
     // 发送操作成功的事件
     emit('success')
     emit('success')
   } finally {
   } finally {
@@ -619,7 +731,7 @@ const resetForm = () => {
   formRef.value?.resetFields()
   formRef.value?.resetFields()
 }
 }
 onMounted(async () => {
 onMounted(async () => {
-  console.log('id-'+id)
+  materialList.value = []
   const deptId = useUserStore().getUser.deptId
   const deptId = useUserStore().getUser.deptId
   // 查询当前登录人所属部门名称
   // 查询当前登录人所属部门名称
   dept.value = await DeptApi.getDept(deptId)
   dept.value = await DeptApi.getDept(deptId)
@@ -629,15 +741,11 @@ onMounted(async () => {
   // if (id){
   // if (id){
   try{
   try{
     formType.value = 'update'
     formType.value = 'update'
-    // const iotMaintain = await IotMaintainApi.getIotMaintain(id);
-    // deviceLabel.value = iotMaintain.deviceName
-    // formData.value = iotMaintain
     // 查询保养工单 主表数据
     // 查询保养工单 主表数据
     const workOrder = await IotMainWorkOrderApi.getIotMainWorkOrder(id);
     const workOrder = await IotMainWorkOrderApi.getIotMainWorkOrder(id);
     formData.value = workOrder
     formData.value = workOrder
     // 查询保养工单 明细数据
     // 查询保养工单 明细数据
     const data = await IotMainWorkOrderBomApi.getWorkOrderBOMs(queryParams);
     const data = await IotMainWorkOrderBomApi.getWorkOrderBOMs(queryParams);
-    console.log('这是个数组:', data)
     list.value = []
     list.value = []
     if (Array.isArray(data)) {
     if (Array.isArray(data)) {
       list.value = data.map(item => ({
       list.value = data.map(item => ({
@@ -650,12 +758,6 @@ onMounted(async () => {
     console.error('数据加载失败:', error)
     console.error('数据加载失败:', error)
     message.error('数据加载失败,请重试')
     message.error('数据加载失败,请重试')
   }
   }
-  /* } else {
-    formType.value = 'create';
-    const { wsCache } = useCache()
-    const userInfo = wsCache.get(CACHE_KEY.USER)
-    formData.value.responsiblePerson = userInfo.user.id;
-  } */
 })
 })
 
 
 </script>
 </script>

+ 133 - 0
src/views/pms/iotmainworkorder/SelectedMaterialDrawer.vue

@@ -0,0 +1,133 @@
+<template>
+  <el-drawer
+    title="物料详情"
+    :append-to-body="true"
+    :model-value="modelValue"
+    @update:model-value="$emit('update:modelValue', $event)"
+    :show-close="false"
+    direction="rtl"
+    :size="computedSize"
+    :before-close="handleClose"
+  >
+    <template v-if="nodeId">
+      <div v-loading="loading" style="height: 100%">
+        <el-table :data="filteredMaterials" style="width: 100%">
+          <el-table-column prop="bomNodeId" label="bom节点" width="180" v-if="false"/>
+          <el-table-column prop="materialName" label="物料名称" width="180" />
+          <el-table-column prop="materialCode" label="物料编码" width="180" />
+          <el-table-column prop="unit" label="单位" width="180" />
+          <el-table-column prop="quantity" label="消耗数量" width="180" />
+          <el-table-column prop="materialSource" label="库存类型" width="180" />
+          <el-table-column label="操作" align="right">
+            <template #default="scope">
+              <el-button
+                size="small"
+                type="danger"
+                @click="emit('delete', scope.row)"
+              >删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <!-- 分页
+        <Pagination
+          :total="total"
+          v-model:page="queryParams.pageNo"
+          v-model:limit="queryParams.pageSize"
+          @pagination="loadMaterials(props.nodeId)"
+        />
+        -->
+      </div>
+    </template>
+
+  </el-drawer>
+</template>
+<script setup lang="ts">
+
+import { ref, watch, defineOptions, defineEmits } from 'vue'
+import { ElMessage } from 'element-plus'
+import * as PmsMaterialApi from '@/api/pms/material'
+import {dateFormatter} from "@/utils/formatTime";
+const drawerVisible = ref<boolean>(false)
+const emit = defineEmits(['update:modelValue', 'add', 'delete'])
+
+defineOptions({
+  name: 'SelectedMaterialDrawer'
+})
+
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  createTime: [],
+  bomId: '',
+  name: '',
+  code: ''
+})
+
+const windowWidth = ref(window.innerWidth)
+// 动态计算百分比
+const computedSize = computed(() => {
+  return windowWidth.value > 1200 ? '60%' : '80%'
+})
+
+const loading = ref(false)
+const total = ref(0) // 列表的总页数
+// const materials = ref([])
+
+const props = defineProps({
+  modelValue: Boolean,
+  nodeId: Number,
+  materials: Array // 接收父组件传递的完整物料列表
+})
+
+// 监听bom树节点ID变化
+watch(() => props.nodeId, (newVal) => {
+  console.log('传递过来的nodeId', newVal)
+  if (newVal) {
+    // await loadMaterials(newVal)
+  }
+})
+
+// 计算属性过滤当前节点物料
+const filteredMaterials = computed(() => {
+  return props.materials?.filter(item =>
+    item.bomNodeId === props.nodeId
+  ) || []
+})
+
+// 加载指定bom节点下的物料数据
+const loadMaterials = async (nodeId) => {
+  queryParams.bomId = nodeId
+  try {
+    loading.value = true
+    // API调用
+    const data = await PmsMaterialApi.listByBomId(queryParams)
+    materials.value = data.list
+    total.value = data.total
+  } catch (error) {
+    ElMessage.error('数据加载失败')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 打开抽屉
+const openDrawer = () => {
+  drawerVisible.value = true
+}
+
+// 关闭抽屉
+const closeDrawer = () => {
+  drawerVisible.value = false
+}
+
+// 关闭抽屉
+const handleClose = () => {
+  emit('update:modelValue', false)
+  // materials.value = []
+}
+
+defineExpose({ openDrawer, closeDrawer }) // 暴露方法给父组件
+
+</script>
+
+<style lang="scss" scoped></style>

+ 232 - 0
src/views/pms/iotmainworkorder/WorkOrderMaterial.vue

@@ -0,0 +1,232 @@
+<template>
+  <Dialog v-model="dialogVisible" title="选择物料" style="width: 1100px; max-height: 800px">
+    <ContentWrap>
+      <el-form
+        class="-mb-15px"
+        :model="queryParams"
+        ref="queryFormRef"
+        :inline="true"
+        label-width="68px"
+      >
+        <el-form-item label="物料编码" prop="code">
+          <el-input
+            v-model="queryParams.code"
+            placeholder="请输入物料编码"
+            clearable
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="物料名称" prop="name">
+          <el-input
+            v-model="queryParams.name"
+            placeholder="请输入物料名称"
+            clearable
+            @keyup.enter="handleQuery"
+          />
+        </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 @click="handleConfirm" class="custom-green-button"><Icon icon="ep:check" class="mr-5px" /> 确认选择</el-button>
+        </el-form-item>
+      </el-form>
+    </ContentWrap>
+    <ContentWrap>
+      <el-table
+        v-loading="loading"
+        :data="list"
+        :stripe="true"
+        ref="tableRef"
+        :show-overflow-tooltip="true"
+        @row-click="handleRowClick"
+      >
+        <el-table-column width="60" label="选择">
+          <template #default="{ row }">
+            <el-checkbox
+              :model-value="selectedRows.some(item => item.materialCode === row.materialCode)"
+              @click.stop="toggleRow(row)"
+              class="no-label-radio"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="物料编码"
+          align="center"
+          prop="materialCode"
+          :show-overflow-tooltip="true"
+          class="!w-100px"
+        />
+        <el-table-column
+          label="物料名称"
+          align="center"
+          prop="materialName"
+          :show-overflow-tooltip="true"
+        />
+        <el-table-column label="单位" align="center" prop="unit"  />
+        <el-table-column label="总库存数量" align="center" prop="totalInventoryQuantity"/>
+        <el-table-column label="消耗数量" align="center" prop="quantity" >
+          <template #default="scope">
+            <el-input v-model="scope.row.quantity"
+                      @click.stop=""
+                      @focus="scope.$el.querySelector('input').focus()"/>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- 分页 -->
+      <Pagination
+        :total="total"
+        v-model:page="queryParams.pageNo"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </ContentWrap>
+  </Dialog>
+</template>
+
+<script setup lang="ts">
+import * as MaintainMaterialApi from '@/api/pms/maintain/material'
+import * as WorkOrderBomMaterialApi from '@/api/pms/iotmainworkorderbommaterial'
+import { IotMaintainMaterialVO } from '@/api/pms/maintain/material'
+import { propTypes } from '@/utils/propTypes'
+import { defineExpose } from 'vue';
+import {IotDeviceVO} from "@/api/pms/device";
+
+// const emit = defineEmits(['choose']) // 定义 success 事件,用于操作成功后的回调
+// 调整 emit 类型
+const emit = defineEmits<{
+  (e: 'choose', value: WorkOrderBomMaterialApi.IotMainWorkOrderBomMaterialVO[]): void
+  (e: 'close'): void
+}>()
+const dialogVisible = ref(false) // 弹窗的是否展示
+const loading = ref(true) // 列表的加载中
+const queryFormRef = ref() // 搜索的表单
+const list = ref<WorkOrderBomMaterialApi.IotMainWorkOrderBomMaterialVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const tableRef = ref();
+const selectedRows = ref<WorkOrderBomMaterialApi.IotMainWorkOrderBomMaterialVO[]>([]); // 多选数据(存储所有选中行的数组)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  deptId: 0,
+  bomNodeId: 0,
+  name: '',
+  code: ''
+})
+
+const selectedRow = ref(null)
+
+// 处理单选逻辑
+const selectRow = (row) => {
+  selectedRow.value = selectedRow.value?.id === row.id ? null : row
+  emit('choose', row)
+  dialogVisible.value = false
+}
+
+// 点击整行选中
+const handleRowClick = (row) => {
+  toggleRow(row)
+}
+const open = async (deptId: number, bomNodeId: number) => {
+  console.log('传递过来的数据:', deptId)
+  dialogVisible.value = true
+  queryParams.deptId = deptId;
+  queryParams.bomNodeId = bomNodeId;
+  await getList()
+}
+
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+const getList = async () => {
+  loading.value = true
+  try {
+    // queryParams.deptId = props.deptId
+    const data =
+      await WorkOrderBomMaterialApi.IotMainWorkOrderBomMaterialApi.workOrderMaterials(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+// 确认选择
+const handleConfirm = () => {
+  if (selectedRows.value.length === 0) {
+    ElMessage.warning('请至少选择一个物料')
+    return
+  }
+  emit('choose', selectedRows.value.map(row => ({
+    ...row,
+    // 确保返回必要字段
+    id: row.id,
+    materialCode: row.materialCode,
+    materialName: row.materialName,
+    unitPrice: row.unitPrice,
+    unit: row.unit,
+    quantity: row.quantity,
+  })))
+  dialogVisible.value = false;
+  handleClose()
+};
+
+// 关闭时清空选择
+const handleClose = () => {
+  tableRef.value?.clearSelection();
+  selectedRows.value = []
+  emit('close')
+};
+
+// 多选 切换行选中状态
+const toggleRow = (row) => {
+  const index = selectedRows.value.findIndex(item => item.materialCode === row.materialCode);
+  if (index > -1) {
+    selectedRows.value.splice(index, 1); // 取消选中
+  } else {
+    selectedRows.value.push(row); // 选中
+  }
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+const choose = (row: IotMaintainMaterialVO) => {
+  emit('choose', row)
+  dialogVisible.value = false
+}
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+</script>
+<style lang="scss" scoped>
+.no-label-radio .el-radio__label {
+  display: none;
+}
+.no-label-radio .el-radio__inner {
+  margin-right: 0;
+}
+
+
+/* 自定义淡绿色按钮 */
+:deep(.custom-green-button) {
+  background-color: #e1f3d8;
+  border-color: #e1f3d8;
+  color: #67c23a;
+}
+
+/* 悬停效果 */
+:deep(.custom-green-button:hover) {
+  background-color: #d1e8c0;
+  border-color: #d1e8c0;
+  color: #5daf34;
+}
+
+/* 点击效果 */
+:deep(.custom-green-button:active) {
+  background-color: #c2dca8;
+  border-color: #c2dca8;
+}
+</style>

+ 1 - 1
src/views/pms/iotmainworkorder/index.vue

@@ -107,7 +107,7 @@
             @click="openForm('update', scope.row.id)"
             @click="openForm('update', scope.row.id)"
             v-hasPermi="['pms:iot-main-work-order:update']"
             v-hasPermi="['pms:iot-main-work-order:update']"
           >
           >
-            编辑
+            填报
           </el-button>
           </el-button>
           <el-button
           <el-button
             link
             link