From efaf84576990daddeff16875624bd1c46dafecfc Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期二, 27 一月 2026 17:32:26 +0800
Subject: [PATCH] Merge branch 'dev_New' of http://114.132.189.42:9002/r/product-inventory-management into dev_New

---
 src/views/inventoryManagement/stockManagement/New.vue                |   13 
 src/api/inventoryManagement/stockUninventory.js                      |   18 +
 src/api/viewIndex.js                                                 |    9 
 src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue      |  164 +++++++++++
 src/views/inventoryManagement/stockManagement/Qualified.vue          |   34 ++
 src/views/inventoryManagement/stockManagement/Subtract.vue           |    2 
 src/views/inventoryManagement/stockManagement/Unqualified.vue        |   45 ++
 src/views/inventoryManagement/stockReport/index.vue                  |  364 +++++++++++++-------------
 src/api/inventoryManagement/stockInventory.js                        |   19 +
 src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue |  134 ++++++++
 10 files changed, 594 insertions(+), 208 deletions(-)

diff --git a/src/api/inventoryManagement/stockInventory.js b/src/api/inventoryManagement/stockInventory.js
index 15e1b3a..aed71e2 100644
--- a/src/api/inventoryManagement/stockInventory.js
+++ b/src/api/inventoryManagement/stockInventory.js
@@ -41,3 +41,22 @@
         params,
     });
 };
+
+// 鍐荤粨搴撳瓨璁板綍
+export const frozenStockInventory = (params) => {
+    return request({
+        url: "/stockInventory/frozenStock",
+        method: "post",
+        data: params,
+    });
+};
+
+// 瑙e喕搴撳瓨璁板綍
+export const thawStockInventory = (params) => {
+    return request({
+        url: "/stockInventory/thawStock",
+        method: "post",
+        data: params,
+    });
+};
+
diff --git a/src/api/inventoryManagement/stockUninventory.js b/src/api/inventoryManagement/stockUninventory.js
index bdde283..73907c7 100644
--- a/src/api/inventoryManagement/stockUninventory.js
+++ b/src/api/inventoryManagement/stockUninventory.js
@@ -25,3 +25,21 @@
         data: params,
     });
 };
+
+// 鍐荤粨搴撳瓨璁板綍
+export const frozenStockUninventory = (params) => {
+    return request({
+        url: "/stockUninventory/frozenStock",
+        method: "post",
+        data: params,
+    });
+};
+
+// 瑙e喕搴撳瓨璁板綍
+export const thawStockUninventory = (params) => {
+    return request({
+        url: "/stockUninventory/thawStock",
+        method: "post",
+        data: params,
+    });
+};
diff --git a/src/api/viewIndex.js b/src/api/viewIndex.js
index 2acf915..85e81bd 100644
--- a/src/api/viewIndex.js
+++ b/src/api/viewIndex.js
@@ -113,4 +113,13 @@
         url: '/home/productCategoryDistribution',
         method: 'get'
     })
+}
+
+// 浜у搧澶х被鍒嗗竷
+// /home/productCategoryDistribution
+export const productCategoryDistribution = () => {
+    return request({
+        url: '/home/productCategoryDistribution',
+        method: 'get'
+    })
 }
\ No newline at end of file
diff --git a/src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue b/src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue
new file mode 100644
index 0000000..463cb83
--- /dev/null
+++ b/src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue
@@ -0,0 +1,164 @@
+<template>
+  <div>
+    <el-dialog
+        v-model="isShow"
+        :title="operationType === 'frozen' ? '鍐荤粨搴撳瓨' : '瑙e喕搴撳瓨'"
+        width="800"
+        @close="closeModal"
+    >
+      <el-form label-width="140px" :model="formState" ref="formRef">
+        <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-form-item>
+      </el-form>
+
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="handleSubmit">纭</el-button>
+          <el-button @click="closeModal">鍙栨秷</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import {ref, computed, getCurrentInstance} from "vue";
+import {frozenStockInventory, thawStockInventory} from "@/api/inventoryManagement/stockInventory.js";
+import {frozenStockUninventory, thawStockUninventory} from "@/api/inventoryManagement/stockUninventory.js";
+
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    required: true,
+  },
+
+  operationType: {
+    type: String,
+    required: true,
+    default: 'frozen',
+  },
+
+  type: {
+    type: String,
+    required: true,
+    default: 'qualified',
+  },
+
+  record: {
+    type: Object,
+    default: () => {},
+  }
+});
+
+const emit = defineEmits(['update:visible', 'completed']);
+
+// 鍝嶅簲寮忔暟鎹紙鏇夸唬閫夐」寮忕殑 data锛�
+const formState = ref({
+  lockedQuantity: 0,
+});
+
+const isShow = computed({
+  get() {
+    return props.visible;
+  },
+  set(val) {
+    emit('update:visible', val);
+  },
+});
+
+
+let { proxy } = getCurrentInstance()
+
+const closeModal = () => {
+  // 閲嶇疆琛ㄥ崟鏁版嵁
+  formState.value = {
+    lockedQuantity: undefined
+  };
+  isShow.value = false;
+};
+
+const maxCount = computed(() => {
+  // 鍐荤粨搴撳瓨鏈�澶ф暟閲忎负鏈В鍐绘暟閲�
+  if (props.operationType === 'frozen') {
+    return props.record.unLockedQuantity
+  }
+  // 瑙e喕搴撳瓨鏈�澶ф暟閲忎负宸插喕缁撴暟閲�
+  return props.record.lockedQuantity
+})
+
+const handleSubmit = () => {
+  proxy.$refs["formRef"].validate(valid => {
+    if (valid) {
+      const data = Object.assign({id: props.record.id}, formState.value);
+      if (props.type === 'qualified') {
+        // 鍐荤粨
+        if (props.operationType === 'frozen') {
+          frozenStockInventory(data).then(res => {
+            if (res.code === 200) {
+              // 鍏抽棴妯℃�佹
+              isShow.value = false;
+              // 鍛婄煡鐖剁粍浠跺凡瀹屾垚
+              emit('completed');
+              proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+            } else {
+              proxy.$modal.msgError(res.msg);
+            }
+          })
+        } else {
+          thawStockInventory(data).then(res => {
+            if (res.code === 200) {
+              // 鍏抽棴妯℃�佹
+              isShow.value = false;
+              // 鍛婄煡鐖剁粍浠跺凡瀹屾垚
+              emit('completed');
+              proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+            } else {
+              proxy.$modal.msgError(res.msg);
+            }
+          })
+        }
+      } else {
+        if (props.operationType === 'frozen') {
+          frozenStockUninventory(data).then(res => {
+            if (res.code === 200) {
+              // 鍏抽棴妯℃�佹
+              isShow.value = false;
+              // 鍛婄煡鐖剁粍浠跺凡瀹屾垚
+              emit('completed');
+              proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+            } else {
+              proxy.$modal.msgError(res.msg);
+            }
+          })
+        } else {
+          thawStockUninventory(data).then(res => {
+            if (res.code === 200) {
+              // 鍏抽棴妯℃�佹
+              isShow.value = false;
+              // 鍛婄煡鐖剁粍浠跺凡瀹屾垚
+              emit('completed');
+              proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
+            } else {
+              proxy.$modal.msgError(res.msg);
+            }
+          })
+        }
+      }
+    }
+  })
+};
+
+onMounted(() => {
+  formState.value.lockedQuantity = maxCount.value;
+})
+
+defineExpose({
+  closeModal,
+  handleSubmit,
+  isShow,
+});
+</script>
diff --git a/src/views/inventoryManagement/stockManagement/New.vue b/src/views/inventoryManagement/stockManagement/New.vue
index 751c639..1f86fd6 100644
--- a/src/views/inventoryManagement/stockManagement/New.vue
+++ b/src/views/inventoryManagement/stockManagement/New.vue
@@ -38,10 +38,18 @@
         </el-form-item>
 
         <el-form-item
-            label="鏁伴噺"
+            label="搴撳瓨鏁伴噺"
             prop="qualitity"
         >
-          <el-input-number v-model="formState.qualitity" :step="1" :min="0" style="width: 100%" />
+          <el-input-number v-model="formState.qualitity" :step="1" :min="1" style="width: 100%" />
+        </el-form-item>
+
+        <el-form-item
+            v-if="type === 'qualified'"
+            label="搴撳瓨棰勮鏁伴噺"
+            prop="warnNum"
+        >
+          <el-input-number v-model="formState.warnNum" :step="1" :min="0" :max="formState.qualitity" style="width: 100%" />
         </el-form-item>
 
         <el-form-item label="澶囨敞" prop="remark">
@@ -94,6 +102,7 @@
   productModelName: "",
   unit: "",
   qualitity: 0,
+  warnNum: 0,
   remark: '',
 });
 
diff --git a/src/views/inventoryManagement/stockManagement/Qualified.vue b/src/views/inventoryManagement/stockManagement/Qualified.vue
index 2ee39db..8b15db1 100644
--- a/src/views/inventoryManagement/stockManagement/Qualified.vue
+++ b/src/views/inventoryManagement/stockManagement/Qualified.vue
@@ -27,12 +27,15 @@
         <el-table-column label="瑙勬牸鍨嬪彿" prop="model" show-overflow-tooltip />
         <el-table-column label="鍗曚綅" prop="unit" show-overflow-tooltip />
         <el-table-column label="搴撳瓨鏁伴噺" prop="qualitity" show-overflow-tooltip />
+        <el-table-column label="鍐荤粨鏁伴噺" prop="lockedQuantity" 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="60" align="center">
           <template #default="scope">
-            <el-button link type="primary" size="small" @click="showSubtractModal(scope.row)" :disabled="scope.row.qualitity === 0">棰嗙敤</el-button>
+            <el-button link type="primary" size="small" @click="showSubtractModal(scope.row)" :disabled="scope.row.unLockedQuantity === 0">棰嗙敤</el-button>
+            <el-button link type="primary" size="small" v-if="scope.row.unLockedQuantity > 0" @click="showFrozenModal(scope.row)">鍐荤粨</el-button>
+            <el-button link type="primary" size="small" v-if="scope.row.lockedQuantity > 0" @click="showThawModal(scope.row)">瑙e喕</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -47,12 +50,20 @@
     <subtract-stock-inventory v-if="isShowSubtractModal"
                  v-model:visible="isShowSubtractModal"
                  :record="record"
+                 type="qualified"
                  @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="qualified"
+                 @completed="handleQuery" />
   </div>
 </template>
 
@@ -64,6 +75,7 @@
 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([])
@@ -78,6 +90,10 @@
 const isShowNewModal = ref(false)
 // 鏄惁鏄剧ず棰嗙敤寮规
 const isShowSubtractModal = ref(false)
+// 鏄惁鏄剧ず鍐荤粨/瑙e喕寮规
+const isShowFrozenAndThawModal = ref(false)
+// 鎿嶄綔绫诲瀷
+const operationType = ref('frozen')
 // 鏄惁鏄剧ず瀵煎叆寮规
 const isShowImportModal = ref(false)
 const data = reactive({
@@ -128,6 +144,20 @@
   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) => {
   // 杩囨护鎺夊瓙鏁版嵁
@@ -138,7 +168,7 @@
 
 // 琛ㄦ牸琛岀被鍚�
 const tableRowClassName = ({ row }) => {
-  const stock = Number(row?.inboundNum0 ?? 0);
+  const stock = Number(row?.unLockedQuantity ?? 0);
   const warn = Number(row?.warnNum ?? 0);
   if (!Number.isFinite(stock) || !Number.isFinite(warn)) {
     return '';
diff --git a/src/views/inventoryManagement/stockManagement/Subtract.vue b/src/views/inventoryManagement/stockManagement/Subtract.vue
index 082153c..a277a00 100644
--- a/src/views/inventoryManagement/stockManagement/Subtract.vue
+++ b/src/views/inventoryManagement/stockManagement/Subtract.vue
@@ -94,7 +94,7 @@
 })
 
 const maxQuality = computed(() => {
-  return props.record.qualitity ? props.record.qualitity :  0;
+  return props.record.unLockedQuantity ? props.record.unLockedQuantity :  0;
 })
 
 const initFormData = () => {
diff --git a/src/views/inventoryManagement/stockManagement/Unqualified.vue b/src/views/inventoryManagement/stockManagement/Unqualified.vue
index 67d5f58..9b5652d 100644
--- a/src/views/inventoryManagement/stockManagement/Unqualified.vue
+++ b/src/views/inventoryManagement/stockManagement/Unqualified.vue
@@ -24,12 +24,14 @@
         <el-table-column label="瑙勬牸鍨嬪彿" prop="model" show-overflow-tooltip />
         <el-table-column label="鍗曚綅" prop="unit" show-overflow-tooltip />
         <el-table-column label="搴撳瓨鏁伴噺" prop="qualitity" show-overflow-tooltip />
-        <el-table-column label="搴撳瓨棰勮鏁伴噺" prop="warnNum"  show-overflow-tooltip />
+        <el-table-column label="鍐荤粨鏁伴噺" prop="lockedQuantity" 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="60" align="center">
           <template #default="scope">
-            <el-button link type="primary" size="small" @click="showSubtractModal(scope.row)" :disabled="scope.row.qualitity === 0">棰嗙敤</el-button>
+            <el-button link type="primary" size="small" @click="showSubtractModal(scope.row)" :disabled="scope.row.unLockedQuantity === 0">棰嗙敤</el-button>
+            <el-button link type="primary" size="small" v-if="scope.row.unLockedQuantity > 0" @click="showFrozenModal(scope.row)">鍐荤粨</el-button>
+            <el-button link type="primary" size="small" v-if="scope.row.lockedQuantity > 0" @click="showThawModal(scope.row)">瑙e喕</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -44,7 +46,15 @@
     <subtract-stock-inventory v-if="isShowSubtractModal"
                  v-model:visible="isShowSubtractModal"
                  :record="record"
+                 type="unqualified"
                  @completed="handleQuery" />
+    <!-- 鍐荤粨/瑙e喕搴撳瓨-->
+    <frozen-and-thaw-stock-inventory v-if="isShowFrozenAndThawModal"
+                                     v-model:visible="isShowFrozenAndThawModal"
+                                     :record="record"
+                                     :operation-type="operationType"
+                                     type="unqualified"
+                                     @completed="handleQuery" />
   </div>
 </template>
 
@@ -55,6 +65,7 @@
 import { getStockUninventoryListPage } from "@/api/inventoryManagement/stockUninventory.js";
 const NewStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/New.vue"));
 const SubtractStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Subtract.vue"));
+const FrozenAndThawStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/FrozenAndThaw.vue"));
 
 const { proxy } = getCurrentInstance()
 const tableData = ref([])
@@ -70,6 +81,10 @@
 const isShowNewModal = ref(false)
 // 鏄惁鏄剧ず棰嗙敤寮规
 const isShowSubtractModal = ref(false)
+// 鏄惁鏄剧ず鍐荤粨/瑙e喕寮规
+const isShowFrozenAndThawModal = ref(false)
+// 鎿嶄綔绫诲瀷
+const operationType = ref('frozen')
 const data = reactive({
   searchForm: {
     productName: '',
@@ -107,6 +122,20 @@
   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) => {
   // 杩囨护鎺夊瓙鏁版嵁
@@ -117,12 +146,12 @@
 
 // 琛ㄦ牸琛岀被鍚�
 const tableRowClassName = ({ row }) => {
-  const stock = Number(row?.inboundNum0 ?? 0);
-  const warn = Number(row?.warnNum ?? 0);
-  if (!Number.isFinite(stock) || !Number.isFinite(warn)) {
-    return '';
-  }
-  return stock < warn ? 'row-low-stock' : '';
+  // const stock = Number(row?.unLockedQuantity ?? 0);
+  // const warn = Number(row?.warnNum ?? 0);
+  // if (!Number.isFinite(stock) || !Number.isFinite(warn)) {
+  //   return '';
+  // }
+  // return stock < warn ? 'row-low-stock' : '';
 };
 
 // 瀵煎嚭
diff --git a/src/views/inventoryManagement/stockReport/index.vue b/src/views/inventoryManagement/stockReport/index.vue
index 1879ea6..a0a1f67 100644
--- a/src/views/inventoryManagement/stockReport/index.vue
+++ b/src/views/inventoryManagement/stockReport/index.vue
@@ -14,17 +14,17 @@
           <el-option label="鏈堟姤" value="monthly" />
           <el-option label="杩涘嚭瀛樻姤琛�" value="inout" />
         </el-select>
-
+        
         <span class="search_title ml10">鏃堕棿鑼冨洿锛�</span>
-        <el-date-picker
-          v-if="searchForm.reportType === 'daily'"
-          v-model="searchForm.singleDate"
-          type="date"
-          placeholder="璇烽�夋嫨鏃ユ湡"
-          format="YYYY-MM-DD"
-          value-format="YYYY-MM-DD"
-          style="width: 200px;"
-        />
+         <el-date-picker
+           v-if="searchForm.reportType === 'daily'"
+           v-model="searchForm.singleDate"
+           type="date"
+           placeholder="璇烽�夋嫨鏃ユ湡"
+           format="YYYY-MM-DD"
+           value-format="YYYY-MM-DD"
+           style="width: 200px;"
+         />
         <el-date-picker
           v-else-if="searchForm.reportType === 'monthly'"
           v-model="searchForm.monthRange"
@@ -47,7 +47,7 @@
           value-format="YYYY-MM-DD"
           style="width: 240px;"
         />
-
+        
         <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
           鏌ヨ
         </el-button>
@@ -55,91 +55,91 @@
       </div>
 
       <div class="search_right">
-        <!--        <el-button type="success" @click="handleExport" icon="Download">-->
-        <!--          瀵煎嚭鎶ヨ〃-->
-        <!--        </el-button>-->
+<!--        <el-button type="success" @click="handleExport" icon="Download">-->
+<!--          瀵煎嚭鎶ヨ〃-->
+<!--        </el-button>-->
       </div>
     </div>
 
-    <!--    &lt;!&ndash; 缁熻鍗$墖 &ndash;&gt;-->
-    <!--    <div class="stats_cards" v-if="reportData.summary">-->
-    <!--      <el-row :gutter="20">-->
-    <!--        <el-col :span="6">-->
-    <!--          <el-card class="stats_card">-->
-    <!--            <div class="stats_content">-->
-    <!--              <div class="stats_icon in">-->
-    <!--                <el-icon><TrendCharts /></el-icon>-->
-    <!--              </div>-->
-    <!--              <div class="stats_info">-->
-    <!--                <div class="stats_value">{{ reportData.summary.totalIn || 0 }}</div>-->
-    <!--                <div class="stats_label">鎬诲叆搴撻噺</div>-->
-    <!--              </div>-->
-    <!--            </div>-->
-    <!--          </el-card>-->
-    <!--        </el-col>-->
-    <!--        <el-col :span="6">-->
-    <!--          <el-card class="stats_card">-->
-    <!--            <div class="stats_content">-->
-    <!--              <div class="stats_icon out">-->
-    <!--                <el-icon><TrendCharts /></el-icon>-->
-    <!--              </div>-->
-    <!--              <div class="stats_info">-->
-    <!--                <div class="stats_value">{{ reportData.summary.totalOut || 0 }}</div>-->
-    <!--                <div class="stats_label">鎬诲嚭搴撻噺</div>-->
-    <!--              </div>-->
-    <!--            </div>-->
-    <!--          </el-card>-->
-    <!--        </el-col>-->
-    <!--        <el-col :span="6">-->
-    <!--          <el-card class="stats_card">-->
-    <!--            <div class="stats_content">-->
-    <!--              <div class="stats_icon stock">-->
-    <!--                <el-icon><Box /></el-icon>-->
-    <!--              </div>-->
-    <!--              <div class="stats_info">-->
-    <!--                <div class="stats_value">{{ reportData.summary.currentStock || 0 }}</div>-->
-    <!--                <div class="stats_label">褰撳墠搴撳瓨</div>-->
-    <!--              </div>-->
-    <!--            </div>-->
-    <!--          </el-card>-->
-    <!--        </el-col>-->
-    <!--        <el-col :span="6">-->
-    <!--          <el-card class="stats_card">-->
-    <!--            <div class="stats_content">-->
-    <!--              <div class="stats_icon turnover">-->
-    <!--                <el-icon><Refresh /></el-icon>-->
-    <!--              </div>-->
-    <!--              <div class="stats_info">-->
-    <!--                <div class="stats_value">{{ reportData.summary.turnoverRate || 0 }}%</div>-->
-    <!--                <div class="stats_label">鍛ㄨ浆鐜�</div>-->
-    <!--              </div>-->
-    <!--            </div>-->
-    <!--          </el-card>-->
-    <!--        </el-col>-->
-    <!--      </el-row>-->
-    <!--    </div>-->
+<!--    &lt;!&ndash; 缁熻鍗$墖 &ndash;&gt;-->
+<!--    <div class="stats_cards" v-if="reportData.summary">-->
+<!--      <el-row :gutter="20">-->
+<!--        <el-col :span="6">-->
+<!--          <el-card class="stats_card">-->
+<!--            <div class="stats_content">-->
+<!--              <div class="stats_icon in">-->
+<!--                <el-icon><TrendCharts /></el-icon>-->
+<!--              </div>-->
+<!--              <div class="stats_info">-->
+<!--                <div class="stats_value">{{ reportData.summary.totalIn || 0 }}</div>-->
+<!--                <div class="stats_label">鎬诲叆搴撻噺</div>-->
+<!--              </div>-->
+<!--            </div>-->
+<!--          </el-card>-->
+<!--        </el-col>-->
+<!--        <el-col :span="6">-->
+<!--          <el-card class="stats_card">-->
+<!--            <div class="stats_content">-->
+<!--              <div class="stats_icon out">-->
+<!--                <el-icon><TrendCharts /></el-icon>-->
+<!--              </div>-->
+<!--              <div class="stats_info">-->
+<!--                <div class="stats_value">{{ reportData.summary.totalOut || 0 }}</div>-->
+<!--                <div class="stats_label">鎬诲嚭搴撻噺</div>-->
+<!--              </div>-->
+<!--            </div>-->
+<!--          </el-card>-->
+<!--        </el-col>-->
+<!--        <el-col :span="6">-->
+<!--          <el-card class="stats_card">-->
+<!--            <div class="stats_content">-->
+<!--              <div class="stats_icon stock">-->
+<!--                <el-icon><Box /></el-icon>-->
+<!--              </div>-->
+<!--              <div class="stats_info">-->
+<!--                <div class="stats_value">{{ reportData.summary.currentStock || 0 }}</div>-->
+<!--                <div class="stats_label">褰撳墠搴撳瓨</div>-->
+<!--              </div>-->
+<!--            </div>-->
+<!--          </el-card>-->
+<!--        </el-col>-->
+<!--        <el-col :span="6">-->
+<!--          <el-card class="stats_card">-->
+<!--            <div class="stats_content">-->
+<!--              <div class="stats_icon turnover">-->
+<!--                <el-icon><Refresh /></el-icon>-->
+<!--              </div>-->
+<!--              <div class="stats_info">-->
+<!--                <div class="stats_value">{{ reportData.summary.turnoverRate || 0 }}%</div>-->
+<!--                <div class="stats_label">鍛ㄨ浆鐜�</div>-->
+<!--              </div>-->
+<!--            </div>-->
+<!--          </el-card>-->
+<!--        </el-col>-->
+<!--      </el-row>-->
+<!--    </div>-->
 
-    <!--    &lt;!&ndash; 鍥捐〃鍖哄煙 &ndash;&gt;-->
-    <!--    <div class="chart_section" v-if="reportData.chartData">-->
-    <!--      <el-row :gutter="20">-->
-    <!--        <el-col :span="12">-->
-    <!--          <el-card>-->
-    <!--            <template #header>-->
-    <!--              <span>搴撳瓨瓒嬪娍鍥�</span>-->
-    <!--            </template>-->
-    <!--            <div ref="trendChart" style="height: 300px;"></div>-->
-    <!--          </el-card>-->
-    <!--        </el-col>-->
-    <!--        <el-col :span="12">-->
-    <!--          <el-card>-->
-    <!--            <template #header>-->
-    <!--              <span>杩涘嚭搴撳姣�</span>-->
-    <!--            </template>-->
-    <!--            <div ref="comparisonChart" style="height: 300px;"></div>-->
-    <!--          </el-card>-->
-    <!--        </el-col>-->
-    <!--      </el-row>-->
-    <!--    </div>-->
+<!--    &lt;!&ndash; 鍥捐〃鍖哄煙 &ndash;&gt;-->
+<!--    <div class="chart_section" v-if="reportData.chartData">-->
+<!--      <el-row :gutter="20">-->
+<!--        <el-col :span="12">-->
+<!--          <el-card>-->
+<!--            <template #header>-->
+<!--              <span>搴撳瓨瓒嬪娍鍥�</span>-->
+<!--            </template>-->
+<!--            <div ref="trendChart" style="height: 300px;"></div>-->
+<!--          </el-card>-->
+<!--        </el-col>-->
+<!--        <el-col :span="12">-->
+<!--          <el-card>-->
+<!--            <template #header>-->
+<!--              <span>杩涘嚭搴撳姣�</span>-->
+<!--            </template>-->
+<!--            <div ref="comparisonChart" style="height: 300px;"></div>-->
+<!--          </el-card>-->
+<!--        </el-col>-->
+<!--      </el-row>-->
+<!--    </div>-->
 
     <!-- 璇︾粏鏁版嵁琛ㄦ牸 -->
     <div class="table_section">
@@ -147,88 +147,88 @@
         <template #header>
           <span>{{ getTableTitle() }}</span>
         </template>
-        <el-table
-            v-loading="tableLoading"
-            :data="reportData.tableData"
-            border
-            height="400"
-            style="width: 100%"
-            :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
-        >
+         <el-table
+           v-loading="tableLoading"
+           :data="reportData.tableData"
+           border
+           height="400"
+           style="width: 100%"
+           :header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
+         >
           <el-table-column
-              align="center"
-              label="搴忓彿"
-              type="index"
-              width="60"
+            align="center"
+            label="搴忓彿"
+            type="index"
+            width="60"
           />
-          <el-table-column
-              label="鍏ュ簱鏃堕棿"
-              prop="createTime"
-              width="200"
-              show-overflow-tooltip
-              v-if="searchForm.reportType !== 'inout'"
-          />
-          <el-table-column
-              label="鍏ュ簱鎵规"
-              prop="inboundBatches"
-              width="240"
-              show-overflow-tooltip
-              v-if="searchForm.reportType !== 'inout'"
-          />
-          <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="totalStockIn"
-              align="center"
-              v-if="searchForm.reportType === 'inout'"
-          />
-          <el-table-column
-              label="鍏ュ簱鏁伴噺"
-              prop="stockInNum"
-              align="center"
-              v-else
-          />
-          <el-table-column
-              label="鍑哄簱鏁伴噺"
-              prop="totalStockOut"
-              width="100"
-              align="center"
-              v-if="searchForm.reportType === 'inout'"
-          />
-          <el-table-column
-              label="鐜板湪搴撳瓨"
-              prop="currentStock"
-              align="center"
-          />
-          <el-table-column label="鏉ユ簮"
-                           prop="recordType"
-                           v-if="searchForm.reportType !== 'inout'"
-                           show-overflow-tooltip>
-            <template #default="scope">
-              {{ getRecordType(scope.row.recordType) }}
-            </template>
-          </el-table-column>
-          <el-table-column
-              label="鍏ュ簱浜�"
-              prop="createBy"
-              width="80"
-              v-if="searchForm.reportType !== 'inout'"
-              show-overflow-tooltip
-          />
+           <el-table-column
+             label="鍏ュ簱鏃堕棿"
+             prop="createTime"
+             width="200"
+             show-overflow-tooltip
+             v-if="searchForm.reportType !== 'inout'"
+           />
+           <el-table-column
+             label="鍏ュ簱鎵规"
+             prop="inboundBatches"
+             width="240"
+             show-overflow-tooltip
+             v-if="searchForm.reportType !== 'inout'"
+           />
+           <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="totalStockIn"
+             align="center"
+             v-if="searchForm.reportType === 'inout'"
+           />
+           <el-table-column
+               label="鍏ュ簱鏁伴噺"
+               prop="stockInNum"
+               align="center"
+               v-else
+           />
+           <el-table-column
+             label="鍑哄簱鏁伴噺"
+             prop="totalStockOut"
+             width="100"
+             align="center"
+             v-if="searchForm.reportType === 'inout'"
+           />
+           <el-table-column
+             label="鐜板湪搴撳瓨"
+             prop="currentStock"
+             align="center"
+           />
+           <el-table-column label="鏉ユ簮"
+                            prop="recordType"
+                            v-if="searchForm.reportType !== 'inout'"
+                            show-overflow-tooltip>
+             <template #default="scope">
+               {{ getRecordType(scope.row.recordType) }}
+             </template>
+           </el-table-column>
+           <el-table-column
+             label="鍏ュ簱浜�"
+             prop="createBy"
+             width="80"
+             v-if="searchForm.reportType !== 'inout'"
+             show-overflow-tooltip
+           />
         </el-table>
       </el-card>
     </div>
@@ -307,7 +307,7 @@
   if (!validateSearchForm()) {
     return
   }
-
+  
   tableLoading.value = true
   try {
     const params = getQueryParams()
@@ -325,7 +325,7 @@
       // nextTick(() => {
       //   initCharts()
       // })
-
+      
     }
   } catch (error) {
     ElMessage.error('鏌ヨ澶辫触锛�' + error.message)
@@ -395,7 +395,7 @@
     startDate: "",
     endDate: ""
   }
-
+  
   if (searchForm.reportType === 'daily') {
     params.reportDate = searchForm.singleDate
   } else if (searchForm.reportType === 'monthly') {
@@ -405,7 +405,7 @@
     params.startDate = searchForm.dateRange[0]
     params.endDate = searchForm.dateRange[1]
   }
-
+  
   return params
 }
 
@@ -427,7 +427,7 @@
   if (!validateSearchForm()) {
     return
   }
-
+  
   try {
     const params = getQueryParams()
     // const response = await exportStockReport(params)
@@ -442,7 +442,7 @@
     // link.click()
     // document.body.removeChild(link)
     // window.URL.revokeObjectURL(url)
-
+    
     // ElMessage.success('瀵煎嚭鎴愬姛')
   } catch (error) {
     ElMessage.error('瀵煎嚭澶辫触锛�' + error.message)
@@ -452,7 +452,7 @@
 // 鍒濆鍖栧浘琛�
 const initCharts = () => {
   if (!reportData.value.chartData) return
-
+  
   initTrendChart()
   initComparisonChart()
 }
@@ -460,7 +460,7 @@
 // 鍒濆鍖栬秼鍔垮浘
 const initTrendChart = () => {
   if (!trendChart.value) return
-
+  
   const chart = echarts.init(trendChart.value)
   const option = {
     title: {
@@ -497,7 +497,7 @@
 // 鍒濆鍖栧姣斿浘
 const initComparisonChart = () => {
   if (!comparisonChart.value) return
-
+  
   const chart = echarts.init(comparisonChart.value)
   const option = {
     title: {
@@ -544,7 +544,7 @@
 onMounted(() => {
   const today = new Date()
   searchForm.singleDate = today.toISOString().split('T')[0]
-
+  
   const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000)
   searchForm.dateRange = [
     yesterday.toISOString().split('T')[0],
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
index 7bd7307..998bfef 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
@@ -2,19 +2,18 @@
   <div>
     <PanelHeader title="浜у搧澶х被" />
     <div class="panel-item-customers">
+      <div style="height: 70%">
       <div style="height: 100%"> 
         <Echarts
           ref="chart"
           :chartStyle="chartStyle"
-          :grid="grid"
-          :legend="workInProcessBarLegend"
-          :series="workInProcessBarSeries"
-          :tooltip="tooltip"
-          :xAxis="workInProcessXAxis"
-          :yAxis="workInProcessYAxis"
+          :legend="landLegend"
+          :series="landSeries"
+          :tooltip="landTooltip"
+          :color="landColors"
           :options="{ backgroundColor: 'transparent', textStyle: { color: '#B8C8E0' } }"
           style="height: 100%"
-          class="work-in-process-chart"
+          class="land-chart"
         />
       </div>
     </div>
@@ -27,6 +26,15 @@
 import PanelHeader from '../PanelHeader.vue'
 import { productCategoryDistribution } from '@/api/viewIndex.js'
 
+// 鏁版嵁鍒楄〃锛堟潵鑷帴鍙o級
+const dataList = ref([])
+import { productCategoryDistribution } from '@/api/viewIndex.js'
+
+// 棰滆壊鍒楄〃
+const landColors = ['#26FFCB', '#24CBFF', '#35FBF4', '#2651FF', '#D1E4F5', '#5782F7', '#2F67EF', '#82BAFF']
+
+// 鍥句緥閰嶇疆锛堝彸渚х珫鎺掞級
+const landLegend = {
 // 鍦ㄥ埗鍝佸伐搴忔煴鐘跺浘閰嶇疆
 const workInProcessXAxis = ref([
   {
@@ -51,12 +59,75 @@
 
 const workInProcessBarLegend = {
   show: false,
-  textStyle: { color: '#B8C8E0' },
+  icon: 'circle',
   data: [],
+  right: '8%',
+  top: '40%',
+  orient: 'vertical',
+  itemGap: 14,
+  itemWidth: 6,
+  itemHeight: 6,
+  textStyle: {
+    fontSize: 12,
+    rich: {
+      unit: {
+        color: '#fff',
+        fontSize: 12,
+        padding: [0, 10, 0, 0],
+      },
+      text: {
+        width: 60,
+        color: '#fff',
+        fontSize: 12,
+      },
+    },
+  },
+  formatter: function (name) {
+    const list = dataList.value || []
+    const item = list.find((d) => d.name === name)
+    if (!item) return name
+    const val = Number(item.value || 0)
+    const totalValue = list.reduce((sum, it) => sum + Number(it.value || 0), 0)
+    const percent = totalValue ? ((val / totalValue) * 100).toFixed(2) : '0.00'
+    return `{text|${name}}${val}{unit| 鍏》}${percent}{unit|%}`
+  },
 }
 
-const workInProcessBarSeries = ref([
+// 鎻愮ず妗�
+const landTooltip = {
+  triggerOn: 'click',
+  alwaysShowContent: true,
+  position: function (pt) {
+    return [pt[0], 130]
+  },
+}
+
+// 鍙屽眰鐜舰楗煎浘
+const landSeries = ref([
   {
+    name: '澶栧湀',
+    type: 'pie',
+    radius: ['35%', '55%'],
+    center: ['50%', '50%'],
+    label: {
+      show: true,
+      color: '#fff',
+      fontSize: 12,
+      lineHeight: 18,
+      formatter: function (params) {
+        const children = params?.data?.children || []
+        if (!children.length) return ''
+        // label 灞曠ず children 鐨� name + value
+        return children.map((c) => `${c.name} ${c.value}`).join('\n')
+      },
+    },
+    labelLine: {
+      show: true,
+      length: 40,
+      length2: 40,
+      lineStyle: {
+        color: '#B8C8E0',
+      },
     name: '浜у搧鏁伴噺',
     type: 'bar',
     barWidth: 25,
@@ -65,6 +136,19 @@
       focus: 'series',
     },
     itemStyle: {
+      color: function (params) {
+        return landColors[params.dataIndex % landColors.length]
+      },
+    },
+    // 鍒濆缁戝畾涓哄搷搴斿紡鏁版嵁婧愶紝鍚庣画閫氳繃鎺ュ彛濉厖
+    data: dataList.value,
+  },
+  {
+    // 鍐呭湀
+    type: 'pie',
+    radius: ['35%', '40%'],
+    center: ['50%', '50%'],
+    silent: true,
       color: {
         type: 'linear',
         x: 0,
@@ -79,19 +163,42 @@
       borderRadius: [4, 4, 0, 0]
     },
     label: {
-      show: true,
-      position: 'top',
-      color: '#B8C8E0',
+      show: false,
     },
-    data: [],
+    labelLine: {
+      show: false,
+    },
+    itemStyle: {
+      color: 'rgba(0, 127, 255, 0.25)',
+    },
+    data: [1],
   },
 ])
 
 const chartStyle = {
   width: '100%',
+  height: '150%',
   height: '100%',
 }
 
+const loadData = async () => {
+  try {
+    const res = await productCategoryDistribution()
+    const items = res?.data?.items || []
+    dataList.value = items.map((it) => ({
+      name: it.name,
+      value: Number(it.value || 0),
+      rate: it.rate,
+      children: Array.isArray(it.children) ? it.children : [],
+    }))
+    landLegend.data = dataList.value.map((d) => d.name)
+    landSeries.value[0].data = dataList.value
+  } catch (e) {
+    console.error('鑾峰彇浜у搧澶х被鍒嗗竷澶辫触:', e)
+    dataList.value = []
+    landLegend.data = []
+    landSeries.value[0].data = []
+  }
 const grid = {
   left: '3%',
   right: '4%',
@@ -128,6 +235,7 @@
 }
 
 onMounted(() => {
+  loadData()
   getProductCategoryDistribution()
 })
 </script>

--
Gitblit v1.9.3