From ab8ff90598b99b1b88b925c03e82e20ff0426fcf Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 01 六月 2026 17:09:52 +0800
Subject: [PATCH] 新疆马铃薯 1.库存管理绑定设备,添加查看数采功能

---
 src/views/inventoryManagement/stockManagement/New.vue                            |   40 ---
 src/views/inventoryManagement/stockManagement/IotDataDialog.vue                  |  330 ++++++++++++++++++++++++++++++
 src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue |   16 
 src/views/inventoryManagement/stockManagement/Record.vue                         |   39 +++
 src/views/inventoryManagement/stockManagement/Subtract.vue                       |   22 +
 src/api/inventoryManagement/stockInventory.js                                    |   17 +
 src/views/inventoryManagement/stockManagement/BindDeviceDialog.vue               |  145 +++++++++++++
 7 files changed, 558 insertions(+), 51 deletions(-)

diff --git a/src/api/inventoryManagement/stockInventory.js b/src/api/inventoryManagement/stockInventory.js
index 539eedc..0671391 100644
--- a/src/api/inventoryManagement/stockInventory.js
+++ b/src/api/inventoryManagement/stockInventory.js
@@ -103,3 +103,20 @@
     });
 };
 
+// 鑾峰彇鐗╄仈璁惧瀹炴椂鏁伴噰鏁版嵁
+export const getIotRealtimeData = (id) => {
+    return request({
+        url: `/stockInventory/iotRealtime/${id}`,
+        method: "get",
+    });
+};
+
+// 缁戝畾鐗╄仈璁惧鍒板簱瀛�
+export const bindIotDevice = (id, warehouse) => {
+    return request({
+        url: `/stockInventory/bindIotDevice/${id}`,
+        method: "put",
+        data: { warehouse },
+    });
+};
+
diff --git a/src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue b/src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue
index b2fb88d..873e62a 100644
--- a/src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue
+++ b/src/views/collaborativeApproval/notificationManagement/meetApplication/index.vue
@@ -126,9 +126,9 @@
           >
             <el-option
                 v-for="person in employees"
-                :key="person.id"
-                :label="`${person.staffName}${person.postName ? ` (${person.postName})` : ''}`"
-                :value="person.id"
+                :key="person.userId"
+                :label="`${person.nickName || person.userName}${person.dept?.deptName ? ` (${person.dept.deptName})` : ''}`"
+                :value="person.userId"
             />
           </el-select>
         </el-form-item>
@@ -156,7 +156,7 @@
 import {ElMessage} from 'element-plus'
 import {Plus, Document, Promotion, Bell} from '@element-plus/icons-vue'
 import {getRoomEnum, saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js'
-import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js";
+import {userListNoPageByTenantId} from "@/api/system/user.js";
 
 // 褰撳墠鐢宠绫诲瀷
 const currentType = ref('department') // approval: 瀹℃壒娴佺▼, department: 閮ㄩ棬绾�, notification: 閫氱煡鍙戝竷
@@ -415,12 +415,8 @@
   getRoomEnum().then(res => {
     meetingRooms.value = res.data
   })
-  staffOnJobListPage({
-    current: -1,
-    size: -1,
-    staffState: 1
-  }).then(res => {
-    employees.value = res.data.records.sort((a, b) => (a.postName || '').localeCompare(b.postName || ''))
+  userListNoPageByTenantId().then(res => {
+    employees.value = res.data || []
   })
 })
 </script>
diff --git a/src/views/inventoryManagement/stockManagement/BindDeviceDialog.vue b/src/views/inventoryManagement/stockManagement/BindDeviceDialog.vue
new file mode 100644
index 0000000..31a72c4
--- /dev/null
+++ b/src/views/inventoryManagement/stockManagement/BindDeviceDialog.vue
@@ -0,0 +1,145 @@
+<template>
+  <div>
+    <el-dialog v-model="isShow"
+               title="缁戝畾鐗╄仈璁惧"
+               width="600"
+               @close="closeModal">
+      <el-form label-width="100px"
+               :model="formState"
+               ref="formRef">
+        <el-form-item label="浜у搧鍚嶇О">
+          <el-input v-model="props.record.productName" disabled />
+        </el-form-item>
+        <el-form-item label="瑙勬牸鍨嬪彿">
+          <el-input v-model="props.record.model" disabled />
+        </el-form-item>
+        <el-form-item label="鎵瑰彿">
+          <el-input v-model="props.record.batchNo" disabled />
+        </el-form-item>
+        <el-form-item label="鐗╄仈璁惧"
+                      prop="deviceIds"
+                      :rules="[
+                        {
+                          required: false,
+                          message: '璇烽�夋嫨鐗╄仈璁惧',
+                          trigger: 'change',
+                        }
+                      ]">
+          <el-select v-model="formState.deviceIds"
+                     multiple
+                     filterable
+                     placeholder="璇烽�夋嫨鐗╄仈璁惧"
+                     style="width: 100%">
+            <el-option v-for="item in deviceOptions"
+                       :key="item.id"
+                       :label="`${item.deviceName} (${item.deviceModel})`"
+                       :value="item.id">
+              <span style="float: left">{{ item.deviceName }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">{{ item.deviceModel }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="handleSubmit" :loading="submitLoading">纭</el-button>
+          <el-button @click="closeModal">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { ref, computed, onMounted, getCurrentInstance } from "vue";
+  import { getLedgerPage } from "@/api/equipmentManagement/ledger.js";
+  import { bindIotDevice } from "@/api/inventoryManagement/stockInventory.js";
+
+  const props = defineProps({
+    visible: {
+      type: Boolean,
+      required: true,
+    },
+    record: {
+      type: Object,
+      default: () => ({}),
+    },
+  });
+
+  const emit = defineEmits(["update:visible", "completed"]);
+
+  const { proxy } = getCurrentInstance();
+
+  const isShow = computed({
+    get() {
+      return props.visible;
+    },
+    set(val) {
+      emit("update:visible", val);
+    },
+  });
+
+  const formRef = ref(null);
+  const submitLoading = ref(false);
+  const deviceOptions = ref([]);
+
+  const formState = ref({
+    deviceIds: [],
+  });
+
+  // 鑾峰彇鐗╄仈璁惧鍒楄〃
+  const getDeviceOptions = async () => {
+    try {
+      const res = await getLedgerPage({
+        isIotDevice: 1,
+        page: 1,
+        size: 999,
+      });
+      if (res.data && res.data.records) {
+        deviceOptions.value = res.data.records;
+      }
+    } catch (error) {
+      console.error("鑾峰彇鐗╄仈璁惧鍒楄〃澶辫触:", error);
+      proxy.$modal.msgError("鑾峰彇鐗╄仈璁惧鍒楄〃澶辫触");
+    }
+  };
+
+  // 鍒濆鍖栧凡缁戝畾璁惧
+  const initSelectedDevices = () => {
+    if (props.record.warehouse) {
+      // warehouse 瀛楁瀛樺偍鐨勬槸閫楀彿鍒嗛殧鐨勮澶嘔D
+      const deviceIds = props.record.warehouse.split(",").map(id => Number(id.trim())).filter(id => !isNaN(id));
+      formState.value.deviceIds = deviceIds;
+    }
+  };
+
+  const closeModal = () => {
+    formState.value.deviceIds = [];
+    isShow.value = false;
+  };
+
+  const handleSubmit = () => {
+    formRef.value.validate(valid => {
+      if (valid) {
+        submitLoading.value = true;
+        // 灏嗚澶嘔D鏁扮粍杞崲涓洪�楀彿鍒嗛殧鐨勫瓧绗︿覆
+        const warehouse = formState.value.deviceIds.join(",");
+        bindIotDevice(props.record.id, warehouse)
+          .then(res => {
+            submitLoading.value = false;
+            proxy.$modal.msgSuccess("缁戝畾鎴愬姛");
+            closeModal();
+            emit("completed");
+          })
+          .catch(() => {
+            submitLoading.value = false;
+          });
+      }
+    });
+  };
+
+  onMounted(() => {
+    getDeviceOptions();
+    initSelectedDevices();
+  });
+</script>
diff --git a/src/views/inventoryManagement/stockManagement/IotDataDialog.vue b/src/views/inventoryManagement/stockManagement/IotDataDialog.vue
new file mode 100644
index 0000000..2f12009
--- /dev/null
+++ b/src/views/inventoryManagement/stockManagement/IotDataDialog.vue
@@ -0,0 +1,330 @@
+<template>
+  <div>
+    <el-dialog v-model="isShow"
+               title="鐗╄仈璁惧瀹炴椂鏁伴噰"
+               width="800"
+               @close="closeModal">
+      <div v-if="loading" v-loading="loading" element-loading-text="鍔犺浇涓�..." style="min-height: 200px;"></div>
+      <div v-else-if="!hasDevices" class="empty-state">
+        <el-empty description="鏆傛棤缁戝畾鐨勭墿鑱旇澶�">
+          <el-button type="primary" @click="closeModal">鍘荤粦瀹�</el-button>
+        </el-empty>
+      </div>
+      <div v-else>
+        <div class="device-header">
+          <div class="refresh-switch">
+            <el-switch v-model="autoRefresh" active-text="鑷姩鍒锋柊(30s)" />
+          </div>
+          <el-button type="primary" size="small" @click="fetchData" :loading="loading">
+            <el-icon><Refresh /></el-icon>鍒锋柊
+          </el-button>
+        </div>
+        <div class="devices-container">
+          <el-card v-for="device in deviceData.devices" :key="device.deviceId" class="device-card">
+            <template #header>
+              <div class="device-header-info">
+                <div class="device-title">
+                  <span class="device-name">{{ device.deviceName }}</span>
+                  <el-tag size="small" type="info">{{ device.deviceModel }}</el-tag>
+                </div>
+                <div class="device-status">
+                  <span class="status-dot" :class="getStatusClass(device.status)"></span>
+                  <span :class="getStatusTextClass(device.status)">{{ device.status || '鏈煡' }}</span>
+                </div>
+              </div>
+            </template>
+            <div v-if="device.status === '鍦ㄧ嚎'" class="device-data">
+              <el-row :gutter="10">
+                <el-col :span="8" v-if="device.temperature">
+                  <div class="data-item">
+                    <el-icon class="data-icon"><Sunny /></el-icon>
+                    <div class="data-info">
+                      <div class="data-label">娓╁害</div>
+                      <div class="data-value">{{ device.temperature }}</div>
+                    </div>
+                  </div>
+                </el-col>
+                <el-col :span="8" v-if="device.humidity">
+                  <div class="data-item">
+                    <el-icon class="data-icon"><Drizzling /></el-icon>
+                    <div class="data-info">
+                      <div class="data-label">婀垮害</div>
+                      <div class="data-value">{{ device.humidity }}</div>
+                    </div>
+                  </div>
+                </el-col>
+                <el-col :span="8" v-if="device.co2">
+                  <div class="data-item">
+                    <el-icon class="data-icon"><WindPower /></el-icon>
+                    <div class="data-info">
+                      <div class="data-label">CO2</div>
+                      <div class="data-value">{{ device.co2 }}</div>
+                    </div>
+                  </div>
+                </el-col>
+                <el-col :span="8" v-if="device.light">
+                  <div class="data-item">
+                    <el-icon class="data-icon"><Sunrise /></el-icon>
+                    <div class="data-info">
+                      <div class="data-label">鍏夌収</div>
+                      <div class="data-value">{{ device.light }}</div>
+                    </div>
+                  </div>
+                </el-col>
+                <el-col :span="8" v-if="device.battery">
+                  <div class="data-item">
+                    <el-icon class="data-icon"><Lightning /></el-icon>
+                    <div class="data-info">
+                      <div class="data-label">鐢甸噺</div>
+                      <div class="data-value">{{ device.battery }}</div>
+                    </div>
+                  </div>
+                </el-col>
+              </el-row>
+            </div>
+            <div v-else class="device-offline">
+              <el-alert :title="device.statusMessage || '璁惧绂荤嚎'" type="warning" :closable="false" show-icon />
+            </div>
+          </el-card>
+        </div>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="closeModal">鍏抽棴</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+  import { ref, computed, onMounted, onUnmounted, watch } from "vue";
+  import { getIotRealtimeData } from "@/api/inventoryManagement/stockInventory.js";
+  import { Refresh, Sunny, Drizzling, WindPower, Sunrise, Lightning } from "@element-plus/icons-vue";
+
+  const props = defineProps({
+    visible: {
+      type: Boolean,
+      required: true,
+    },
+    record: {
+      type: Object,
+      default: () => ({}),
+    },
+  });
+
+  const emit = defineEmits(["update:visible"]);
+
+  const isShow = computed({
+    get() {
+      return props.visible;
+    },
+    set(val) {
+      emit("update:visible", val);
+    },
+  });
+
+  const loading = ref(false);
+  const deviceData = ref({
+    inventoryId: null,
+    iotDeviceIds: "",
+    devices: [],
+  });
+  const autoRefresh = ref(false);
+  let refreshTimer = null;
+
+  const hasDevices = computed(() => {
+    return deviceData.value.devices && deviceData.value.devices.length > 0;
+  });
+
+  const getStatusClass = (status) => {
+    switch (status) {
+      case "鍦ㄧ嚎":
+        return "status-online";
+      case "offline":
+        return "status-offline";
+      case "error":
+        return "status-error";
+      default:
+        return "status-offline";
+    }
+  };
+
+  const getStatusTextClass = (status) => {
+    switch (status) {
+      case "鍦ㄧ嚎":
+        return "text-online";
+      case "offline":
+        return "text-offline";
+      case "error":
+        return "text-error";
+      default:
+        return "text-offline";
+    }
+  };
+
+  const fetchData = async () => {
+    if (!props.record.id) return;
+    loading.value = true;
+    try {
+      const res = await getIotRealtimeData(props.record.id);
+      if (res.code === 200 && res.data) {
+        deviceData.value = res.data;
+      }
+    } catch (error) {
+      console.error("鑾峰彇鐗╄仈璁惧鏁版嵁澶辫触:", error);
+    } finally {
+      loading.value = false;
+    }
+  };
+
+  const closeModal = () => {
+    autoRefresh.value = false;
+    isShow.value = false;
+  };
+
+  // 鑷姩鍒锋柊
+  watch(autoRefresh, (val) => {
+    if (val) {
+      refreshTimer = setInterval(() => {
+        fetchData();
+      }, 30000);
+    } else {
+      if (refreshTimer) {
+        clearInterval(refreshTimer);
+        refreshTimer = null;
+      }
+    }
+  });
+
+  onMounted(() => {
+    fetchData();
+  });
+
+  onUnmounted(() => {
+    if (refreshTimer) {
+      clearInterval(refreshTimer);
+    }
+  });
+</script>
+
+<style scoped>
+  .empty-state {
+    padding: 40px 0;
+  }
+
+  .device-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20px;
+  }
+
+  .refresh-switch {
+    display: flex;
+    align-items: center;
+  }
+
+  .devices-container {
+    display: flex;
+    flex-direction: column;
+    gap: 15px;
+  }
+
+  .device-card {
+    margin-bottom: 10px;
+  }
+
+  .device-header-info {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  .device-title {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+  }
+
+  .device-name {
+    font-weight: bold;
+    font-size: 16px;
+  }
+
+  .device-status {
+    display: flex;
+    align-items: center;
+    gap: 5px;
+  }
+
+  .status-dot {
+    width: 8px;
+    height: 8px;
+    border-radius: 50%;
+    display: inline-block;
+  }
+
+  .status-online {
+    background-color: #67c23a;
+  }
+
+  .status-offline {
+    background-color: #909399;
+  }
+
+  .status-error {
+    background-color: #f56c6c;
+  }
+
+  .text-online {
+    color: #67c23a;
+  }
+
+  .text-offline {
+    color: #909399;
+  }
+
+  .text-error {
+    color: #f56c6c;
+  }
+
+  .device-data {
+    padding: 10px 0;
+  }
+
+  .data-item {
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    background-color: #f5f7fa;
+    border-radius: 4px;
+    margin-bottom: 10px;
+  }
+
+  .data-icon {
+    font-size: 24px;
+    color: #409eff;
+    margin-right: 10px;
+  }
+
+  .data-info {
+    flex: 1;
+  }
+
+  .data-label {
+    font-size: 12px;
+    color: #909399;
+    margin-bottom: 2px;
+  }
+
+  .data-value {
+    font-size: 16px;
+    font-weight: bold;
+    color: #303133;
+  }
+
+  .device-offline {
+    padding: 20px 0;
+  }
+</style>
diff --git a/src/views/inventoryManagement/stockManagement/New.vue b/src/views/inventoryManagement/stockManagement/New.vue
index 06d72bb..d49fc5a 100644
--- a/src/views/inventoryManagement/stockManagement/New.vue
+++ b/src/views/inventoryManagement/stockManagement/New.vue
@@ -49,23 +49,6 @@
                        value="unqualified" />
           </el-select>
         </el-form-item>
-        <el-form-item label="浠撳簱"
-                      prop="warehouse"
-                      :rules="[
-                {
-                required: true,
-                message: '璇烽�夋嫨浠撳簱',
-                trigger: 'change',
-              }
-            ]">
-          <el-select v-model="formState.warehouse"
-                     placeholder="璇烽�夋嫨浠撳簱">
-            <el-option v-for="item in warehouseOptions"
-                       :key="item.value"
-                       :label="item.label"
-                       :value="item.value" />
-          </el-select>
-        </el-form-item>
         <el-form-item label="搴撳瓨鏁伴噺"
                       prop="qualitity">
           <el-input-number v-model="formState.qualitity"
@@ -119,11 +102,10 @@
 </template>
 
 <script setup>
-  import { ref, computed, watch, getCurrentInstance, onMounted } from "vue";
+  import { ref, computed, watch, getCurrentInstance } from "vue";
   import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
   import { addStockInRecordOnly } from "@/api/inventoryManagement/stockInventory.js";
   import { createStockUnInventory } from "@/api/inventoryManagement/stockUninventory.js";
-  import { getDicts } from "@/api/system/dict/data";
 
   const props = defineProps({
     visible: {
@@ -146,7 +128,6 @@
     productName: "",
     productModelName: "",
     unit: "",
-    warehouse: undefined,
     type: undefined,
     qualitity: 0,
     batchNo: null,
@@ -154,9 +135,6 @@
     createTime: "",
     remark: "",
   });
-
-  // 浠撳簱閫夐」
-  const warehouseOptions = ref([]);
 
   const isShow = computed({
     get() {
@@ -168,21 +146,6 @@
   });
 
   const showProductSelectDialog = ref(false);
-
-  // 鑾峰彇浠撳簱瀛楀吀鏁版嵁
-  const getWarehouseOptions = async () => {
-    const res = await getDicts("warehouse");
-    if (res.code === 200) {
-      warehouseOptions.value = res.data.map(item => ({
-        label: item.dictLabel,
-        value: item.dictValue,
-      }));
-    }
-  };
-
-  onMounted(() => {
-    getWarehouseOptions();
-  });
 
   // 鎵瑰彿涓虹┖鏃惰浆涓� null
   watch(
@@ -204,7 +167,6 @@
       productName: "",
       productModelName: "",
       unit: "",
-      warehouse: undefined,
       type: undefined,
       qualitity: 0,
       batchNo: null,
diff --git a/src/views/inventoryManagement/stockManagement/Record.vue b/src/views/inventoryManagement/stockManagement/Record.vue
index 13217f9..1ce95be 100644
--- a/src/views/inventoryManagement/stockManagement/Record.vue
+++ b/src/views/inventoryManagement/stockManagement/Record.vue
@@ -113,12 +113,18 @@
                          show-overflow-tooltip />
         <el-table-column fixed="right"
                          label="鎿嶄綔"
-                         min-width="80"
+                         min-width="190"
                          align="center">
           <template #default="scope">
             <el-button link
                        type="primary"
                        @click="showDetailModal(scope.row)">璇︽儏</el-button>
+            <el-button link
+                       type="success"
+                       @click="showBindDeviceModal(scope.row)">缁戝畾璁惧</el-button>
+            <el-button link
+                       type="info"
+                       @click="showIotDataModal(scope.row)">鏌ョ湅鏁伴噰</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -156,6 +162,15 @@
                                      :operation-type="operationType"
                                      :type="record.stockType"
                                      @completed="handleQuery" />
+    <!-- 缁戝畾鐗╄仈璁惧 -->
+    <bind-device-dialog v-if="isShowBindDeviceModal"
+                        v-model:visible="isShowBindDeviceModal"
+                        :record="record"
+                        @completed="handleQuery" />
+    <!-- 鏌ョ湅鐗╄仈璁惧鏁伴噰 -->
+    <iot-data-dialog v-if="isShowIotDataModal"
+                     v-model:visible="isShowIotDataModal"
+                     :record="record" />
   </div>
 </template>
 
@@ -187,6 +202,12 @@
   const BatchNoQtyDetail = defineAsyncComponent(() =>
     import("@/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue")
   );
+  const BindDeviceDialog = defineAsyncComponent(() =>
+    import("@/views/inventoryManagement/stockManagement/BindDeviceDialog.vue")
+  );
+  const IotDataDialog = defineAsyncComponent(() =>
+    import("@/views/inventoryManagement/stockManagement/IotDataDialog.vue")
+  );
   const { proxy } = getCurrentInstance();
   const tableData = ref([]);
   const selectedRows = ref([]);
@@ -209,6 +230,10 @@
   const operationType = ref("frozen");
   // 鏄惁鏄剧ず瀵煎叆寮规
   const isShowImportModal = ref(false);
+  // 鏄惁鏄剧ず缁戝畾璁惧寮规
+  const isShowBindDeviceModal = ref(false);
+  // 鏄惁鏄剧ず鐗╄仈鏁伴噰寮规
+  const isShowIotDataModal = ref(false);
   const data = reactive({
     searchForm: {
       productName: "",
@@ -308,6 +333,18 @@
     operationType.value = "thaw";
   };
 
+  // 鐐瑰嚮缁戝畾璁惧
+  const showBindDeviceModal = row => {
+    record.value = row;
+    isShowBindDeviceModal.value = true;
+  };
+
+  // 鐐瑰嚮鏌ョ湅鏁伴噰
+  const showIotDataModal = row => {
+    record.value = row;
+    isShowIotDataModal.value = true;
+  };
+
   // 琛ㄦ牸閫夋嫨鏁版嵁
   const handleSelectionChange = selection => {
     // 杩囨护鎺夊瓙鏁版嵁
diff --git a/src/views/inventoryManagement/stockManagement/Subtract.vue b/src/views/inventoryManagement/stockManagement/Subtract.vue
index 2cdfcb6..34b1ac1 100644
--- a/src/views/inventoryManagement/stockManagement/Subtract.vue
+++ b/src/views/inventoryManagement/stockManagement/Subtract.vue
@@ -61,6 +61,16 @@
           <el-input-number v-model="formState.qualitity" :step="1" :min="1" :max="maxQuality" style="width: 100%" />
         </el-form-item>
 
+        <el-form-item label="鍑哄簱鎵规" prop="outboundBatches">
+          <el-input 
+            v-model="formState.outboundBatches" 
+            placeholder="鐣欑┖鑷姩鐢熸垚"
+            maxlength="100"
+            show-word-limit
+          />
+          <div class="form-tip">涓嶅~鍒欒嚜鍔ㄧ敓鎴愶紝鏍煎紡锛欳K骞存湀鏃�-搴忓彿</div>
+        </el-form-item>
+
         <el-form-item label="澶囨敞" prop="remark">
           <el-input v-model="formState.remark" type="textarea" />
         </el-form-item>
@@ -134,6 +144,7 @@
   model: "",
   unit: "",
   qualitity: 0,
+  outboundBatches: "",
   remark: '',
 });
 
@@ -157,6 +168,7 @@
     productModelId: undefined,
     productName: "",
     productModelName: "",
+    outboundBatches: "",
     description: '',
   };
   isShow.value = false;
@@ -216,4 +228,12 @@
   handleSubmit,
   isShow,
 });
-</script>
\ No newline at end of file
+</script>
+
+<style scoped>
+.form-tip {
+  font-size: 12px;
+  color: #909399;
+  margin-top: 4px;
+}
+</style>
\ No newline at end of file

--
Gitblit v1.9.3