yaowanxin
5 天以前 0152b0200faff12f0ece317cdb32dcbcf486757d
添加库存核算统计页面,调整固定资产页面图表
已添加1个文件
已修改2个文件
508 ■■■■ 文件已修改
src/api/inventoryManagement/stockIn.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/accounting/index.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/inventoryAccounting/index.vue 390 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockIn.js
@@ -64,5 +64,11 @@
}
//
//查询库存图表数据
export function getStockInChartData() {
    return request({
        url: '/stockin/listReport',
        method: 'get'
    })
}
src/views/financialManagement/accounting/index.vue
@@ -2,43 +2,13 @@
  <div style="padding: 20px;">
    <!-- é¡µé¢æ ‡é¢˜å’Œç­›é€‰æ¡ä»¶ -->
    <div class="w-full md:w-auto flex items-center gap-3" style="margin-bottom: 20px;">
      <el-date-picker
        v-model="dateRange"
        type="daterange"
        format="YYYY-MM-DD"
        value-format="YYYY-MM-DD"
        range-separator="至"
        start-placeholder="开始日期"
        end-placeholder="结束日期"
        clearable
        @change="handleDateChange"
        class="w-full md:w-auto"
        style="margin-right: 30px;"
      />
      <!-- è®¾å¤‡ç±»åž‹ç­›é€‰ -->
      <el-select
        v-model="equipmentType"
        placeholder="设备类型"
        clearable
        @change="handleFilterChange"
        style="margin-right: 20px; width: 150px;"
      >
        <el-option
          v-for="item in equipmentTypeOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
      <el-button
        type="primary"
        icon="Refresh"
        @click="resetFilters"
        size="default"
      >
        é‡ç½®
        æŸ¥è¯¢
      </el-button>
    </div>
@@ -117,9 +87,9 @@
          :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
        >
          <el-table-column prop="id" label="资产编号" width="120" />
          <el-table-column prop="deviceName" label="设备名称" width="150" />
          <el-table-column prop="deviceModel" label="型号规格" width="150" />
          <el-table-column prop="supplierName" label="供应商" width="120" />
          <el-table-column prop="deviceName" label="设备名称" width="250" />
          <el-table-column prop="deviceModel" label="型号规格" min-width="150" />
          <el-table-column prop="supplierName" label="供应商" min-width="120" />
          <el-table-column prop="unit" label="单位" width="120" />
          <el-table-column prop="number" label="数量" width="120" />
          <el-table-column prop="originalValue" label="原值(元)" width="120">
@@ -358,33 +328,42 @@
    if (equipmentListRes.code === 200) {
      equipmentList.value = equipmentListRes.data.records;
      pagination.value.total = equipmentListRes.data.total;
    }
    // // èŽ·å–è®¾å¤‡ç±»åž‹åˆ†å¸ƒæ•°æ®
    // const typeDistributionRes = await getEquipmentTypes({
    //   startDate: dateRange.value ? dateRange.value[0] : null,
    //   endDate: dateRange.value ? dateRange.value[1] : null,
    //   equipmentType: equipmentType.value
    // });
    // if (typeDistributionRes.code === 200) {
    //   typeDistributionData.value = typeDistributionRes.data.map(item => ({
    //     name: item.typeName,
    //     value: item.count,
    //     count: item.count,
    //     amount: `Â¥${formatCurrency(item.totalValue)}`
    //   }));
    //
    //   // æž„建折线图数据
    //   typeDistributionLineSeries.value = [
    //     {
    //       name: '设备数量',
    //       type: 'line',
    //       data: typeDistributionRes.data.map(item => item.count)
    //     }
    //   ];
    //   // æ›´æ–°x轴数据
    //   xAxis.value[0].data = typeDistributionRes.data.map(item => item.typeName);
    // }
      // æ ¹æ® equipmentList æŒ‰ deviceName è¿›è¡Œåˆ†ç±»ç»Ÿè®¡
      const deviceNameMap = {};
      equipmentList.value.forEach(item => {
        const deviceName = item.deviceName;
        if (!deviceNameMap[deviceName]) {
          deviceNameMap[deviceName] = {
            name: deviceName,
            count: 0,
            totalValue: 0
          };
        }
        deviceNameMap[deviceName].count += item.number || 1; // å‡è®¾ number ä¸ºè®¾å¤‡æ•°é‡
        deviceNameMap[deviceName].totalValue += item.taxIncludingPriceTotal || 0; // ç´¯åŠ å«ç¨Žæ€»ä»·
      });
      // è½¬æ¢ä¸º typeDistributionData æ ¼å¼
      typeDistributionData.value = Object.values(deviceNameMap).map(item => ({
        name: item.name,
        value: item.count,
        count: item.count,
        amount: `Â¥${formatCurrency(item.totalValue)}`
      }));
      // æ›´æ–°x轴数据
      xAxis.value[0].data = typeDistributionData.value.map(item => item.name);
      // æž„建折线图数据
      typeDistributionLineSeries.value = [
        {
          name: '设备数量',
          type: 'line',
          data: typeDistributionData.value.map(item => item.count)
        }
      ];
    }
  } catch (error) {
    console.error('获取固定资产数据失败:', error);
  }
@@ -416,17 +395,6 @@
    default:
      return 'info';
  }
};
// å¤„理日期范围变化
const handleDateChange = (newRange) => {
  dateRange.value = newRange;
  fetchData();
};
// å¤„理筛选条件变化
const handleFilterChange = () => {
  fetchData();
};
// é‡ç½®ç­›é€‰æ¡ä»¶
src/views/financialManagement/inventoryAccounting/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,390 @@
<template>
  <div class="inventory-statistics">
    <!-- ç­›é€‰è¡¨å• -->
    <div class="filter-form">
      <el-form :model="filterForm" inline>
<!--        <el-form-item label="时间范围">-->
<!--          <el-date-picker-->
<!--            v-model="filterForm.dateRange"-->
<!--            type="daterange"-->
<!--            range-separator="至"-->
<!--            start-placeholder="开始日期"-->
<!--            end-placeholder="结束日期"-->
<!--          />-->
<!--        </el-form-item>-->
<!--        <el-form-item label="供应商名称">-->
<!--          <el-input v-model="filterForm.supplierName" style="width: 240px" placeholder="请输入" clearable prefix-icon="Search" />-->
<!--        </el-form-item>-->
<!--        <el-form-item label="产品名称">-->
<!--          <el-input v-model="filterForm.productCategory" style="width: 240px" placeholder="请输入" clearable prefix-icon="Search" />-->
<!--        </el-form-item>-->
        <el-form-item>
          <el-button type="primary" @click="handleSearch">查询</el-button>
<!--          <el-button @click="handleReset">重置</el-button>-->
<!--          <el-button type="success" @click="handleExport">导出</el-button>-->
        </el-form-item>
      </el-form>
    </div>
    <!-- ç»Ÿè®¡æ±‡æ€»å¡ç‰‡ -->
    <div class="summary-cards">
      <el-row :gutter="20">
        <el-col :span="6">
          <el-card class="summary-card">
            <div class="summary-item">
              <p class="summary-title">总库存数量</p>
              <p class="summary-value">{{ summaryData.totalInventoryCount }}</p>
            </div>
          </el-card>
        </el-col>
        <el-col :span="6">
          <el-card class="summary-card">
            <div class="summary-item">
              <p class="summary-title">总库存金额</p>
              <p class="summary-value">Â¥{{ summaryData.totalInventoryValue }}</p>
            </div>
          </el-card>
        </el-col>
        <el-col :span="6">
          <el-card class="summary-card">
            <div class="summary-item">
              <p class="summary-title">库存变动数量</p>
              <p class="summary-value">{{ summaryData.inventoryChangeCount }}</p>
            </div>
          </el-card>
        </el-col>
        <el-col :span="6">
          <el-card class="summary-card">
            <div class="summary-item">
              <p class="summary-title">库存变动金额</p>
              <p class="summary-value">Â¥{{ summaryData.inventoryChangeValue }}</p>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>
    <!-- å›¾è¡¨åŒºåŸŸ -->
    <div class="chart-section">
      <el-row :gutter="20">
        <el-col :span="12">
          <el-card class="chart-card">
            <template #header>
              <div class="card-header">
                <span>库存分类占比</span>
              </div>
            </template>
            <div id="category-pie-chart" style="height: 400px;"></div>
          </el-card>
        </el-col>
        <el-col :span="12">
          <el-card class="chart-card">
            <template #header>
              <div class="card-header">
                <span>库存金额趋势</span>
              </div>
            </template>
            <div id="amount-trend-chart" style="height: 400px;"></div>
          </el-card>
        </el-col>
      </el-row>
    </div>
    <!-- æ•°æ®è¡¨æ ¼ -->
    <div class="table_list">
      <el-table
        :data="tableData"
        v-loading="loading"
        border
        style="width: 100%"
        :header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column label="供应商名称" prop="supplierName" width="240" show-overflow-tooltip />
        <el-table-column label="产品" prop="productCategory" min-width="100" show-overflow-tooltip />
        <el-table-column label="规格型号" prop="specificationModel" min-width="200" show-overflow-tooltip />
        <el-table-column label="单位" prop="unit" width="70" show-overflow-tooltip />
        <el-table-column label="入库数量" prop="inboundNum" width="90" show-overflow-tooltip />
        <el-table-column label="库存数量" prop="inboundNum0" width="90" show-overflow-tooltip />
        <el-table-column label="含税单价" prop="taxInclusiveUnitPrice" width="100" show-overflow-tooltip />
        <el-table-column label="含税总价" prop="taxInclusiveTotalPrice" width="100" show-overflow-tooltip />
        <el-table-column label="税率(%)" prop="taxRate" width="80" show-overflow-tooltip />
        <el-table-column label="不含税总价" prop="taxExclusiveTotalPrice" width="100" show-overflow-tooltip />
        <el-table-column label="入库人" prop="createBy" width="100" show-overflow-tooltip />
      </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>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick } from 'vue'
import * as echarts from 'echarts'
import {getStockInChartData, getStockInPage} from "@/api/inventoryManagement/stockIn.js";
// çŠ¶æ€å˜é‡
const loading = ref(false)
const total = ref(0)
const tableData = ref([])
const summaryData = ref({})
const page = reactive({
  current: 1,
  size: 100,
})
// å›¾è¡¨å®žä¾‹
const categoryPieChart = ref(null)
const amountTrendChart = ref(null)
// ç­›é€‰è¡¨å•
const filterForm = reactive({
  dateRange: [],
  supplierName: '',
  productCategory: ''
})
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  loadData()
}
// åˆå§‹åŒ–数据
onMounted(() => {
  loadSummaryData()
  loadData()
})
// åŠ è½½ç»Ÿè®¡æ±‡æ€»æ•°æ®
const loadSummaryData = () => {
  getStockInChartData().then(res => {
    summaryData.value = res.data
  })
}
// åŠ è½½åº“å­˜æ•°æ®
const loadData = () => {
  loading.value = true
  getStockInPage({ ...filterForm, ...page }).then(res => {
    loading.value = false
    tableData.value = res.data.records
    total.value = res.data.total
    console.log('res', res.data.records)
    // æ•°æ®åŠ è½½å®ŒæˆåŽæ¸²æŸ“å›¾è¡¨
    nextTick(() => {
      renderCategoryPieChart()
      renderAmountTrendChart()
    })
  }).catch(() => {
    loading.value = false
  })
}
// æ¸²æŸ“分类占比饼图
const renderCategoryPieChart = () => {
  if (!categoryPieChart.value) {
    categoryPieChart.value = echarts.init(document.getElementById('category-pie-chart'))
  }
  // æ ¹æ® tableData æŒ‰ productCategory åˆ†ç±»å¹¶è®¡ç®— inboundNum0 æ•°é‡æ€»å’Œ
  const categoryMap = tableData.value.reduce((acc, cur) => {
    acc[cur.productCategory] = (acc[cur.productCategory] || 0) + cur.inboundNum0
    return acc
  }, {})
  // å°†åˆ†ç±»ç»“果转换为 ECharts é¥¼å›¾æ‰€éœ€çš„æ•°æ®æ ¼å¼
  const categoryData = Object.entries(categoryMap).map(([name, value]) => ({
    name: name,
    value: value
  }))
  const option = {
    title: {
      text: '库存分类占比',
      left: 'center'
    },
    tooltip: {
      trigger: 'item',
      formatter: '{a} <br/>{b}: {c} ({d}%)'
    },
    legend: {
      orient: 'vertical',
      left: 'left'
    },
    series: [
      {
        name: '库存分类',
        type: 'pie',
        radius: ['40%', '70%'],
        avoidLabelOverlap: false,
        itemStyle: {
          borderRadius: 10,
          borderColor: '#fff',
          borderWidth: 2
        },
        label: {
          show: true,
          formatter: '{b}: {d}%'
        },
        emphasis: {
          label: {
            show: true,
            fontSize: '16',
            fontWeight: 'bold'
          }
        },
        data: categoryData
      }
    ]
  }
  categoryPieChart.value.setOption(option)
}
// æ¸²æŸ“金额趋势折线图
const renderAmountTrendChart = () => {
  if (!amountTrendChart.value) {
    amountTrendChart.value = echarts.init(document.getElementById('amount-trend-chart'))
  }
  // æŒ‰æœˆä»½åˆ†ç»„并计算taxInclusiveTotalPrice总和
  const monthlyAmounts = tableData.value.reduce((acc, cur) => {
    const date = new Date(cur.createTime);
    const month = date.getMonth() + 1;
    // ç¡®ä¿month在1-12范围内
    if (month >= 1 && month <= 12) {
      acc[month] = (acc[month] || 0) + cur.taxInclusiveTotalPrice;
    }
    return acc;
  }, {});
  // ç”Ÿæˆ12个月的数据,缺失月份用0代替
  const amounts = [];
  for (let i = 1; i <= 12; i++) {
    amounts.push(monthlyAmounts[i] || 0);
  }
  const dates = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
  const option = {
    title: {
      text: '库存金额趋势',
      left: 'center'
    },
    tooltip: {
      trigger: 'axis',
      formatter: '{b}: Â¥{c}'
    },
    xAxis: {
      type: 'category',
      data: dates
    },
    yAxis: {
      type: 'value',
      axisLabel: {
        formatter: 'Â¥{value}'
      }
    },
    series: [
      {
        name: '库存金额',
        type: 'line',
        data: amounts,
        smooth: true,
        areaStyle: {}
      }
    ]
  }
  amountTrendChart.value.setOption(option)
}
// æŸ¥è¯¢æ“ä½œ
const handleSearch = () => {
  loadData()
}
// é‡ç½®æ“ä½œ
const handleReset = () => {
  filterForm.dateRange = []
  filterForm.supplierName = ''
  filterForm.productCategory = ''
  loadData()
}
// å¯¼å‡ºæ“ä½œ
const handleExport = () => {
  console.log('导出数据')
}
// çª—口大小改变时,重新调整图表大小
window.addEventListener('resize', () => {
  if (categoryPieChart.value) categoryPieChart.value.resize()
  if (amountTrendChart.value) amountTrendChart.value.resize()
})
</script>
<style scoped>
.inventory-statistics {
  padding: 20px;
}
.filter-form {
  margin-bottom: 20px;
}
.summary-cards {
  margin-bottom: 20px;
}
.summary-card {
  text-align: center;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.summary-item {
  width: 100%;
}
.summary-title {
  font-size: 14px;
  color: #606266;
  margin-bottom: 5px;
}
.summary-value {
  font-size: 24px;
  font-weight: bold;
  color: #303133;
}
.summary-value.warning {
  color: #e6a23c;
}
.summary-value.danger {
  color: #f56c6c;
}
.chart-section {
  margin-bottom: 20px;
}
.chart-card {
  height: 460px;
}
.card-header {
  font-weight: bold;
}
.table_list {
  margin-top: 20px;
}
.pagination {
  text-align: right;
  margin-top: 20px;
}
</style>