gongchunyi
10 小时以前 efaf84576990daddeff16875624bd1c46dafecfc
Merge branch 'dev_New' of http://114.132.189.42:9002/r/product-inventory-management into dev_New
已添加1个文件
已修改9个文件
802 ■■■■ 文件已修改
src/api/inventoryManagement/stockInventory.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockUninventory.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/viewIndex.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/New.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/Qualified.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/Subtract.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/Unqualified.vue 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockReport/index.vue 364 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockInventory.js
@@ -41,3 +41,22 @@
        params,
    });
};
// å†»ç»“库存记录
export const frozenStockInventory = (params) => {
    return request({
        url: "/stockInventory/frozenStock",
        method: "post",
        data: params,
    });
};
// è§£å†»åº“存记录
export const thawStockInventory = (params) => {
    return request({
        url: "/stockInventory/thawStock",
        method: "post",
        data: params,
    });
};
src/api/inventoryManagement/stockUninventory.js
@@ -25,3 +25,21 @@
        data: params,
    });
};
// å†»ç»“库存记录
export const frozenStockUninventory = (params) => {
    return request({
        url: "/stockUninventory/frozenStock",
        method: "post",
        data: params,
    });
};
// è§£å†»åº“存记录
export const thawStockUninventory = (params) => {
    return request({
        url: "/stockUninventory/thawStock",
        method: "post",
        data: params,
    });
};
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'
    })
}
src/views/inventoryManagement/stockManagement/FrozenAndThaw.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,164 @@
<template>
  <div>
    <el-dialog
        v-model="isShow"
        :title="operationType === 'frozen' ? '冻结库存' : '解冻库存'"
        width="800"
        @close="closeModal"
    >
      <el-form label-width="140px" :model="formState" ref="formRef">
        <el-form-item
            :label="operationType === 'frozen' ? '冻结数量:' : '解冻数量:'"
            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
  }
  // è§£å†»åº“存最大数量为已冻结数量
  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>
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: '',
});
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)">解冻</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" />
    <!-- å†»ç»“/解冻库存-->
    <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)
// æ˜¯å¦æ˜¾ç¤ºå†»ç»“/解冻弹框
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'
}
// ç‚¹å‡»è§£å†»
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 '';
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 = () => {
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)">解冻</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" />
    <!-- å†»ç»“/解冻库存-->
    <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)
// æ˜¯å¦æ˜¾ç¤ºå†»ç»“/解冻弹框
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'
}
// ç‚¹å‡»è§£å†»
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' : '';
};
// å¯¼å‡º
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],
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'
// æ•°æ®åˆ—表(来自接口)
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>