From 4619d7c1944afbc85eb680167ca188fccc822259 Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期四, 09 四月 2026 17:55:06 +0800
Subject: [PATCH] 根据产品大类联合查询库存信息

---
 src/views/inventoryManagement/stockManagement/New.vue           |   37 +++-
 src/views/basicData/product/ProductSelectDialog.vue             |    2 
 src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue |   60 +++++--
 src/views/inventoryManagement/stockManagement/index.vue         |   57 ++++--
 src/views/inventoryManagement/stockManagement/Record.vue        |  222 +++++++++++++++++++++++++++
 src/views/inventoryManagement/stockManagement/Subtract.vue      |   42 ++++-
 src/api/inventoryManagement/stockInventory.js                   |    9 +
 7 files changed, 371 insertions(+), 58 deletions(-)

diff --git a/src/api/inventoryManagement/stockInventory.js b/src/api/inventoryManagement/stockInventory.js
index aed71e2..10a211d 100644
--- a/src/api/inventoryManagement/stockInventory.js
+++ b/src/api/inventoryManagement/stockInventory.js
@@ -8,6 +8,15 @@
     });
 };
 
+// 鍒嗛〉鏌ヨ鑱斿悎搴撳瓨璁板綍鍒楄〃锛堝寘鍚晢鍝佷俊鎭級
+export const getStockInventoryListPageCombined = (params) => {
+    return request({
+        url: "/stockInventory/pageListCombinedStockInventory",
+        method: "get",
+        params,
+    });
+};
+
 // 鍒涘缓搴撳瓨璁板綍
 export const createStockInventory = (params) => {
     return request({
diff --git a/src/views/basicData/product/ProductSelectDialog.vue b/src/views/basicData/product/ProductSelectDialog.vue
index ded23cc..c10d29e 100644
--- a/src/views/basicData/product/ProductSelectDialog.vue
+++ b/src/views/basicData/product/ProductSelectDialog.vue
@@ -55,6 +55,7 @@
 const props = defineProps<{
   modelValue: boolean;
   single?: boolean; // 鏄惁鍙兘閫夋嫨涓�涓紝榛樿false锛堝彲閫夋嫨澶氫釜锛�
+  topProductParentId?: number; // 涓�绾т骇鍝乮d
 }>();
 
 const emit = defineEmits(['update:modelValue', 'confirm']);
@@ -159,6 +160,7 @@
       model: query.model.trim(),
       current: page.pageNum,
       size: page.pageSize,
+      topProductParentId: props.topProductParentId,
     });
     tableData.value = res.records;
     total.value = res.total;
diff --git a/src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue b/src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue
index 463cb83..a7a9400 100644
--- a/src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue
+++ b/src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue
@@ -8,10 +8,27 @@
     >
       <el-form label-width="140px" :model="formState" ref="formRef">
         <el-form-item
+            label="搴撳瓨绫诲瀷"
+            prop="type"
+            :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨搴撳瓨绫诲瀷',
+                trigger: 'change',
+              }
+            ]"
+        >
+          <el-select v-model="formState.type" placeholder="璇烽�夋嫨搴撳瓨绫诲瀷" @change="handleChangeType">
+            <el-option label="鍚堟牸搴撳瓨" value="qualified" :disabled="(operationType === 'frozen' && props.record.qualifiedUnLockedQuantity <= 0) || (operationType === 'thaw' && props.record.qualifiedLockedQuantity <= 0)" />
+            <el-option label="涓嶅悎鏍煎簱瀛�" value="unqualified" :disabled="(operationType === 'frozen' && props.record.unQualifiedUnLockedQuantity <= 0) || (operationType === 'thaw' && props.record.unQualifiedLockedQuantity <= 0)" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item
             :label="operationType === 'frozen' ? '鍐荤粨鏁伴噺锛�' : '瑙e喕鏁伴噺锛�'"
             prop="lockedQuantity"
         >
-          <el-input-number v-model="formState.lockedQuantity" :step="1" :min="1" precision="0" style="width: 100%" :max="maxCount" />
+          <el-input-number v-model="formState.lockedQuantity" :step="1" :min="maxCount > 0 ? 1 : 0" precision="0" style="width: 100%" :max="maxCount" :disabled="maxCount < 1" />
         </el-form-item>
       </el-form>
 
@@ -26,7 +43,7 @@
 </template>
 
 <script setup>
-import {ref, computed, getCurrentInstance} from "vue";
+import {ref, computed, getCurrentInstance, onMounted} from "vue";
 import {frozenStockInventory, thawStockInventory} from "@/api/inventoryManagement/stockInventory.js";
 import {frozenStockUninventory, thawStockUninventory} from "@/api/inventoryManagement/stockUninventory.js";
 
@@ -42,12 +59,6 @@
     default: 'frozen',
   },
 
-  type: {
-    type: String,
-    required: true,
-    default: 'qualified',
-  },
-
   record: {
     type: Object,
     default: () => {},
@@ -58,7 +69,8 @@
 
 // 鍝嶅簲寮忔暟鎹紙鏇夸唬閫夐」寮忕殑 data锛�
 const formState = ref({
-  lockedQuantity: 0,
+  type: undefined,
+  lockedQuantity: undefined,
 });
 
 const isShow = computed({
@@ -76,7 +88,8 @@
 const closeModal = () => {
   // 閲嶇疆琛ㄥ崟鏁版嵁
   formState.value = {
-    lockedQuantity: undefined
+    lockedQuantity: undefined,
+    type: undefined,
   };
   isShow.value = false;
 };
@@ -84,17 +97,32 @@
 const maxCount = computed(() => {
   // 鍐荤粨搴撳瓨鏈�澶ф暟閲忎负鏈В鍐绘暟閲�
   if (props.operationType === 'frozen') {
-    return props.record.unLockedQuantity
+    // 鍐荤粨鍚堟牸搴撳瓨鏈�澶ф暟閲忎负鏈В鍐诲悎鏍兼暟閲�
+    if (formState.value.type === 'qualified') {
+      return Math.max(0, props.record.qualifiedUnLockedQuantity || 0)
+    }
+    // 鍐荤粨涓嶅悎鏍煎簱瀛樻渶澶ф暟閲忎负鏈В鍐讳笉鍚堟牸鏁伴噺
+    return Math.max(0, props.record.unQualifiedUnLockedQuantity || 0)
   }
   // 瑙e喕搴撳瓨鏈�澶ф暟閲忎负宸插喕缁撴暟閲�
-  return props.record.lockedQuantity
+  if (formState.value.type === 'qualified') {
+    // 瑙e喕鍚堟牸搴撳瓨鏈�澶ф暟閲忎负宸插喕缁撳悎鏍兼暟閲�
+    return Math.max(0, props.record.qualifiedLockedQuantity || 0)
+  }
+  // 瑙e喕涓嶅悎鏍煎簱瀛樻渶澶ф暟閲忎负宸插喕缁撲笉鍚堟牸鏁伴噺
+  return Math.max(0, props.record.unQualifiedLockedQuantity || 0)
 })
+
+const handleChangeType = (type) => {
+  formState.value.lockedQuantity = maxCount.value;
+}
 
 const handleSubmit = () => {
   proxy.$refs["formRef"].validate(valid => {
     if (valid) {
-      const data = Object.assign({id: props.record.id}, formState.value);
-      if (props.type === 'qualified') {
+      const data = Object.assign({}, formState.value);
+      if (formState.value.type === 'qualified') {
+        data.id = props.record.qualifiedId;
         // 鍐荤粨
         if (props.operationType === 'frozen') {
           frozenStockInventory(data).then(res => {
@@ -122,6 +150,7 @@
           })
         }
       } else {
+        data.id = props.record.unQualifiedId;
         if (props.operationType === 'frozen') {
           frozenStockUninventory(data).then(res => {
             if (res.code === 200) {
@@ -153,7 +182,6 @@
 };
 
 onMounted(() => {
-  formState.value.lockedQuantity = maxCount.value;
 })
 
 defineExpose({
@@ -161,4 +189,4 @@
   handleSubmit,
   isShow,
 });
-</script>
+</script>
\ No newline at end of file
diff --git a/src/views/inventoryManagement/stockManagement/New.vue b/src/views/inventoryManagement/stockManagement/New.vue
index 1f86fd6..df92c21 100644
--- a/src/views/inventoryManagement/stockManagement/New.vue
+++ b/src/views/inventoryManagement/stockManagement/New.vue
@@ -38,6 +38,23 @@
         </el-form-item>
 
         <el-form-item
+            label="搴撳瓨绫诲瀷"
+            prop="type"
+            :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨搴撳瓨绫诲瀷',
+                trigger: 'change',
+              }
+            ]"
+        >
+          <el-select v-model="formState.type" placeholder="璇烽�夋嫨搴撳瓨绫诲瀷">
+            <el-option label="鍚堟牸搴撳瓨" value="qualified" />
+            <el-option label="涓嶅悎鏍煎簱瀛�" value="unqualified" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item
             label="搴撳瓨鏁伴噺"
             prop="qualitity"
         >
@@ -45,7 +62,7 @@
         </el-form-item>
 
         <el-form-item
-            v-if="type === 'qualified'"
+            v-if="formState.type === 'qualified'"
             label="搴撳瓨棰勮鏁伴噺"
             prop="warnNum"
         >
@@ -61,8 +78,9 @@
       <ProductSelectDialog
           v-model="showProductSelectDialog"
           @confirm="handleProductSelect"
+          :top-product-parent-id="props.topProductParentId"
           single
-      />
+        />
       <template #footer>
         <div class="dialog-footer">
           <el-button type="primary" @click="handleSubmit">纭</el-button>
@@ -84,12 +102,11 @@
     type: Boolean,
     required: true,
   },
-
-  type: {
-    type: String,
-    required: true,
-    default: 'qualified',
-  },
+  topProductParentId: {
+    type: Number,
+    default: undefined,
+    required: false,
+  }
 });
 
 const emit = defineEmits(['update:visible', 'completed']);
@@ -101,6 +118,7 @@
   productName: "",
   productModelName: "",
   unit: "",
+  type: undefined,
   qualitity: 0,
   warnNum: 0,
   remark: '',
@@ -158,7 +176,7 @@
         proxy.$modal.msgError("璇烽�夋嫨瑙勬牸");
         return;
       }
-      if (props.type === 'qualified') {
+      if (formState.value.type === 'qualified') {
         createStockInventory(formState.value).then(res => {
           // 鍏抽棴妯℃�佹
           isShow.value = false;
@@ -167,6 +185,7 @@
           proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
         })
       } else {
+        formState.value.warnNum = 0;
         createStockUnInventory(formState.value).then(res => {
           // 鍏抽棴妯℃�佹
           isShow.value = false;
diff --git a/src/views/inventoryManagement/stockManagement/Record.vue b/src/views/inventoryManagement/stockManagement/Record.vue
new file mode 100644
index 0000000..4f9537f
--- /dev/null
+++ b/src/views/inventoryManagement/stockManagement/Record.vue
@@ -0,0 +1,222 @@
+<template>
+  <div class="app-container">
+    <div class="search_form">
+      <div>
+        <span class="search_title ml10">浜у搧澶х被锛�</span>
+        <el-input v-model="searchForm.productName"
+                  style="width: 240px"
+                  placeholder="璇疯緭鍏�"
+                  clearable/>
+        <el-button type="primary" @click="handleQuery" style="margin-left: 10px">鎼滅储</el-button>
+      </div>
+      <div>
+         <el-button type="primary" @click="isShowNewModal = true">鏂板搴撳瓨</el-button>
+        <el-button type="info" plain icon="Upload" @click="isShowImportModal = true">
+          瀵煎叆搴撳瓨
+        </el-button>
+        <el-button @click="handleOut">瀵煎嚭</el-button>
+      </div>
+    </div>
+    <div class="table_list">
+      <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
+        :expand-row-keys="expandedRowKeys" :row-key="(row, index) => index" style="width: 100%"
+        :row-class-name="tableRowClassName" height="calc(100vh - 18.5em)">
+        <el-table-column align="center" type="selection" width="55" />
+        <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+        <el-table-column label="浜у搧澶х被" prop="productName" show-overflow-tooltip />
+        <el-table-column label="瑙勬牸鍨嬪彿" prop="model" show-overflow-tooltip />
+        <el-table-column label="鍗曚綅" prop="unit" show-overflow-tooltip />
+        <el-table-column label="鍚堟牸搴撳瓨鏁伴噺" prop="qualifiedQuantity" show-overflow-tooltip />
+        <el-table-column label="涓嶅悎鏍煎簱瀛樻暟閲�" prop="unQualifiedQuantity" show-overflow-tooltip />
+        <el-table-column label="鍚堟牸鍐荤粨鏁伴噺" prop="qualifiedLockedQuantity" show-overflow-tooltip />
+        <el-table-column label="涓嶅悎鏍煎喕缁撴暟閲�" prop="unQualifiedLockedQuantity" show-overflow-tooltip />
+        <el-table-column label="搴撳瓨棰勮鏁伴噺" prop="warnNum"  show-overflow-tooltip />
+        <el-table-column label="澶囨敞" prop="remark"  show-overflow-tooltip />
+        <el-table-column label="鏈�杩戞洿鏂版椂闂�" prop="updateTime" show-overflow-tooltip />
+        <el-table-column fixed="right" label="鎿嶄綔" min-width="90" align="center">
+          <template #default="scope">
+            <el-button link type="primary" @click="showSubtractModal(scope.row)" :disabled="scope.row.unQualifiedUnLockedQuantity === 0 && scope.row.qualifiedUnLockedQuantity === 0">棰嗙敤</el-button>
+            <el-button link type="primary" v-if="scope.row.unQualifiedUnLockedQuantity > 0 || scope.row.qualifiedUnLockedQuantity > 0" @click="showFrozenModal(scope.row)">鍐荤粨</el-button>
+            <el-button link type="primary" v-if="scope.row.qualifiedLockedQuantity > 0 || scope.row.unQualifiedLockedQuantity > 0" @click="showThawModal(scope.row)">瑙e喕</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper"
+        :page="page.current" :limit="page.size" @pagination="paginationChange" />
+    </div>
+    <new-stock-inventory v-if="isShowNewModal"
+                 v-model:visible="isShowNewModal"
+                 :top-product-parent-id="props.productId"
+                 @completed="handleQuery" />
+
+    <subtract-stock-inventory v-if="isShowSubtractModal"
+                 v-model:visible="isShowSubtractModal"
+                 :record="record"
+                 :type="record.stockType"
+                 @completed="handleQuery" />
+    <!-- 瀵煎叆搴撳瓨-->
+    <import-stock-inventory v-if="isShowImportModal"
+                 v-model:visible="isShowImportModal"
+                 type="qualified"
+                 @uploadSuccess="handleQuery" />
+    <!-- 鍐荤粨/瑙e喕搴撳瓨-->
+    <frozen-and-thaw-stock-inventory v-if="isShowFrozenAndThawModal"
+                 v-model:visible="isShowFrozenAndThawModal"
+                 :record="record"
+                 :operation-type="operationType"
+                 :type="record.stockType"
+                 @completed="handleQuery" />
+  </div>
+</template>
+
+<script setup>
+import pagination from '@/components/PIMTable/Pagination.vue'
+import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue'
+import {ElMessage, ElMessageBox} from "element-plus";
+import {
+  getStockInventoryListPageCombined
+} from "@/api/inventoryManagement/stockInventory.js";
+const props = defineProps({
+  productId: {
+    type: Number,
+    required: true,
+    default: 0
+  }
+});
+
+const NewStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/New.vue"));
+const SubtractStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Subtract.vue"));
+const ImportStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Import.vue"));
+const FrozenAndThawStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/FrozenAndThaw.vue"));
+const { proxy } = getCurrentInstance()
+const tableData = ref([])
+const selectedRows = ref([])
+const record = ref({})
+const tableLoading = ref(false)
+const page = reactive({
+  current: 1,
+  size: 100,
+})
+const total = ref(0)
+// 鏄惁鏄剧ず鏂板寮规
+const isShowNewModal = ref(false)
+// 鏄惁鏄剧ず棰嗙敤寮规
+const isShowSubtractModal = ref(false)
+// 鏄惁鏄剧ず鍐荤粨/瑙e喕寮规
+const isShowFrozenAndThawModal = ref(false)
+// 鎿嶄綔绫诲瀷
+const operationType = ref('frozen')
+// 鏄惁鏄剧ず瀵煎叆寮规
+const isShowImportModal = ref(false)
+const data = reactive({
+  searchForm: {
+    productName: '',
+    topParentProductId: props.productId,
+  }
+})
+const { searchForm } = toRefs(data)
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  page.current = 1
+  getList()
+}
+const paginationChange = (obj) => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList()
+}
+const getList = () => {
+  tableLoading.value = true
+  getStockInventoryListPageCombined({ ...searchForm.value, ...page }).then(res => {
+    tableLoading.value = false
+    tableData.value = res.data.records
+    total.value = res.data.total
+    // 鏁版嵁鍔犺浇瀹屾垚鍚庢鏌ュ簱瀛�
+    // checkStockAndCreatePurchase();
+  }).catch(() => {
+    tableLoading.value = false
+  })
+}
+
+const handleFileSuccess = (response) => {
+  const { code, msg } = response;
+  if (code == 200) {
+    ElMessage({ message: "瀵煎叆鎴愬姛", type: "success" });
+    upload.open = false;
+    emits("uploadSuccess");
+  } else {
+    ElMessage({ message: msg, type: "error" });
+  }
+};
+
+// 鐐瑰嚮棰嗙敤
+const showSubtractModal = (row) => {
+  record.value = row
+  isShowSubtractModal.value = true
+}
+
+// 鐐瑰嚮鍐荤粨
+const showFrozenModal = (row) => {
+  record.value = row
+  isShowFrozenAndThawModal.value = true
+  operationType.value = 'frozen'
+}
+
+// 鐐瑰嚮瑙e喕
+const showThawModal = (row) => {
+  record.value = row
+  isShowFrozenAndThawModal.value = true
+  operationType.value = 'thaw'
+}
+
+// 琛ㄦ牸閫夋嫨鏁版嵁
+const handleSelectionChange = (selection) => {
+  // 杩囨护鎺夊瓙鏁版嵁
+  selectedRows.value = selection.filter(item => item.id);
+  console.log('selection', selectedRows.value)
+}
+const expandedRowKeys = ref([])
+
+// 琛ㄦ牸琛岀被鍚�
+const tableRowClassName = ({ row }) => {
+  const stock = Number(row?.qualifiedUnLockedQuantity ?? 0);
+  const warn = Number(row?.warnNum ?? 0);
+  if (!Number.isFinite(stock) || !Number.isFinite(warn)) {
+    return '';
+  }
+  return stock < warn ? 'row-low-stock' : '';
+};
+
+// 瀵煎嚭
+const handleOut = () => {
+  ElMessageBox.confirm(
+    '鏄惁纭瀵煎嚭锛�',
+    '瀵煎嚭', {
+    confirmButtonText: '纭',
+    cancelButtonText: '鍙栨秷',
+    type: 'warning',
+  }
+  ).then(() => {
+    proxy.download("/stockInventory/exportStockInventory", {topParentProductId: props.productId}, '搴撳瓨淇℃伅.xlsx')
+  }).catch(() => {
+    proxy.$modal.msg("宸插彇娑�")
+  })
+}
+
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style scoped lang="scss">
+:deep(.row-low-stock td) {
+  background-color: #fde2e2;
+  color: #c45656;
+}
+
+:deep(.row-low-stock:hover > td) {
+  background-color: #fcd4d4;
+}
+</style>
diff --git a/src/views/inventoryManagement/stockManagement/Subtract.vue b/src/views/inventoryManagement/stockManagement/Subtract.vue
index a277a00..b0e83c6 100644
--- a/src/views/inventoryManagement/stockManagement/Subtract.vue
+++ b/src/views/inventoryManagement/stockManagement/Subtract.vue
@@ -38,6 +38,23 @@
         </el-form-item>
 
         <el-form-item
+            label="搴撳瓨绫诲瀷"
+            prop="type"
+            :rules="[
+                {
+                required: true,
+                message: '璇烽�夋嫨搴撳瓨绫诲瀷',
+                trigger: 'change',
+              }
+            ]"
+        >
+          <el-select v-model="formState.type" placeholder="璇烽�夋嫨搴撳瓨绫诲瀷" @change="handleTypeChange">
+            <el-option label="鍚堟牸搴撳瓨" value="qualified" :disabled="props.record.qualifiedUnLockedQuantity <= 0" />
+            <el-option label="涓嶅悎鏍煎簱瀛�" value="unqualified" :disabled="props.record.unQualifiedUnLockedQuantity <= 0" />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item
             label="鏁伴噺"
             prop="qualitity"
         >
@@ -79,12 +96,7 @@
   record: {
     type: Object,
     default: () => {},
-  },
-  type: {
-    type: String,
-    required: true,
-    default: 'qualified',
-  },
+  }
 });
 
 const emit = defineEmits(['update:visible', 'completed']);
@@ -94,8 +106,19 @@
 })
 
 const maxQuality = computed(() => {
-  return props.record.unLockedQuantity ? props.record.unLockedQuantity :  0;
+  let max = 0;
+  if (formState.value.type === 'qualified') {
+    max = props.record.qualifiedUnLockedQuantity ? props.record.qualifiedUnLockedQuantity :  0;
+  } else {
+    max = props.record.unQualifiedUnLockedQuantity ? props.record.unQualifiedUnLockedQuantity :  0;
+  }
+  // 纭繚 max 鑷冲皯涓� 1锛岄伩鍏� min > max 鐨勯敊璇�
+  return Math.max(max, 1);
 })
+
+const handleTypeChange = () => {
+  formState.value.qualitity = undefined;
+}
 
 const initFormData = () => {
   if (props.record) {
@@ -145,7 +168,6 @@
 const handleProductSelect = async (products) => {
   if (products && products.length > 0) {
     const product = products[0];
-    console.log(product)
     formState.value.productId = product.productId;
     formState.value.productName = product.productName;
     formState.value.productModelName = product.model;
@@ -169,7 +191,7 @@
         proxy.$modal.msgError("璇烽�夋嫨瑙勬牸");
         return;
       }
-      if (props.type === 'qualified') {
+      if (formState.value.type === 'qualified') {
         subtractStockInventory(formState.value).then(res => {
           // 鍏抽棴妯℃�佹
           isShow.value = false;
@@ -196,4 +218,4 @@
   handleSubmit,
   isShow,
 });
-</script>
+</script>
\ No newline at end of file
diff --git a/src/views/inventoryManagement/stockManagement/index.vue b/src/views/inventoryManagement/stockManagement/index.vue
index 347de38..b3aa7ee 100644
--- a/src/views/inventoryManagement/stockManagement/index.vue
+++ b/src/views/inventoryManagement/stockManagement/index.vue
@@ -1,33 +1,44 @@
 <template>
   <div class="app-container">
-    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
-      <el-tab-pane v-for="tab in tabs"
-                   :label="tab.label"
-                   :name="tab.name"
-                   :key="tab.name">
-        <component :is="tab.name === 'qualified' ? QualifiedRecord : UnqualifiedRecord" />
-      </el-tab-pane>
-    </el-tabs>
+    <div v-loading="loading" element-loading-text="鍔犺浇涓�..." style="min-height: 80vh;">
+      <el-tabs v-model="activeTab" @tab-change="handleTabChange" v-if="!loading">
+        <el-tab-pane v-for="tab in products"
+                     :label="tab.productName"
+                     :name="tab.id"
+                     :key="tab.id">
+          <Record :product-id="tab.id" v-if="tab.id === activeTab" />
+        </el-tab-pane>
+      </el-tabs>
+    </div>
   </div>
 </template>
 
 <script setup>
-import QualifiedRecord from "@/views/inventoryManagement/stockManagement/Qualified.vue";
-import UnqualifiedRecord from "@/views/inventoryManagement/stockManagement/Unqualified.vue";
-
-const activeTab = ref('qualified')
-const tabs = ref([
-  {
-    label: '鍚堟牸搴撳瓨',
-    name: 'qualified'
-  },
-  {
-    label: '涓嶅悎鏍煎簱瀛�',
-    name: 'unqualified'
-  }
-])
+import { ref, onMounted } from 'vue';
+import { productTreeList } from "@/api/basicData/product.js";
+import Record from "@/views/inventoryManagement/stockManagement/Record.vue";
+const products = ref([])
+const activeTab = ref(null)
+const loading = ref(false)
 
 const handleTabChange = (tabName) => {
   activeTab.value = tabName;
 }
-</script>
+
+const fetchProducts = async () => {
+  loading.value = true;
+  try {
+    const res = await productTreeList();
+    products.value = res.filter((item) => item.parentId === null).map(({ id, productName }) => ({ id, productName }));
+    if (products.value.length > 0) {
+      activeTab.value = products.value[0].id;
+    }
+  } finally {
+    loading.value = false;
+  }
+}
+
+onMounted(() => {
+  fetchProducts();
+})
+</script>
\ No newline at end of file

--
Gitblit v1.9.3