spring
21 小时以前 a5378ba9d7f0aac37092c43eecdf54782d714bc5
fix: 财务大屏接口联调90%
已修改7个文件
已删除1个文件
862 ■■■■■ 文件已修改
src/api/viewIndex.js 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/financialAnalysis/components/CarouselCards.vue 306 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/financialAnalysis/components/ProductTypeSwitch.vue 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/financialAnalysis/components/center-bottom.vue 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/financialAnalysis/components/center-center.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/financialAnalysis/components/center-top.vue 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/financialAnalysis/components/left-bottom.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/financialAnalysis/components/left-top.vue 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/viewIndex.js
@@ -1,157 +1,189 @@
// é¦–页接口
import request from '@/utils/request'
import request from "@/utils/request";
// é”€å”®-采购-库存数据
export const getBusiness = () => {
    return request({
        url: '/home/business',
        method: 'get'
    })
}
  return request({
    url: "/home/business",
    method: "get",
  });
};
// å®¢æˆ·åˆåŒé‡‘额分析
export const analysisCustomerContractAmounts = () => {
    return request({
        url: '/home/analysisCustomerContractAmounts',
        method: 'get'
    })
}
  return request({
    url: "/home/analysisCustomerContractAmounts",
    method: "get",
  });
};
// è´¨æ£€åˆ†æž
export const qualityStatistics = () => {
    return request({
        url: '/home/qualityStatistics',
        method: 'get'
    })
}
  return request({
    url: "/home/qualityStatistics",
    method: "get",
  });
};
// åº”收应付统计
export const statisticsReceivablePayable = (query) => {
    return request({
        url: '/home/statisticsReceivablePayable',
        method: 'get',
        params: query
    })
}
  return request({
    url: "/home/statisticsReceivablePayable",
    method: "get",
    params: query,
  });
};
// å¾…办事项
export const homeTodos = () => {
    return request({
        url: '/home/todos',
        method: 'get'
    })
}
  return request({
    url: "/home/todos",
    method: "get",
  });
};
// çº¿å½¢å›¾
export const getAmountHalfYear = () => {
    return request({
        url: '/sales/ledger/getAmountHalfYear',
        method: 'get'
    })
}
  return request({
    url: "/sales/ledger/getAmountHalfYear",
    method: "get",
  });
};
// å„生产订单的完成进度统计
// /home/progressStatistics
export const getProgressStatistics = ()=>{
    return request({
        url: '/home/progressStatistics',
        method: 'get'
    })
}
export const getProgressStatistics = () => {
  return request({
    url: "/home/progressStatistics",
    method: "get",
  });
};
//在制品周转情况
//home/workInProcessTurnover
export const getWorkInProcessTurnover = () => {
    return request({
        url: '/home/workInProcessTurnover',
        method: 'get'
    })
}
  return request({
    url: "/home/workInProcessTurnover",
    method: "get",
  });
};
// å®¢æˆ·è¥æ”¶è´¡çŒ®æ•°å€¼åˆ†æž
export const customerRevenueAnalysis = (params) => {
    return request({
        url: '/home/customerRevenueAnalysis',
        method: 'get',
        params
    })
}
  return request({
    url: "/home/customerRevenueAnalysis",
    method: "get",
    params,
  });
};
// å‘˜å·¥-客户-供应商总数
export const summaryStatistics = () => {
    return request({
        url: '/home/summaryStatistics',
        method: 'get'
    })
}
  return request({
    url: "/home/summaryStatistics",
    method: "get",
  });
};
// å„部门人员分布
export const deptStaffDistribution = () => {
    return request({
        url: '/home/deptStaffDistribution',
        method: 'get'
    })
}
  return request({
    url: "/home/deptStaffDistribution",
    method: "get",
  });
};
// ä¾›åº”商采购排名
export const supplierPurchaseRanking = (query) => {
    return request({
        url: '/home/supplierPurchaseRanking',
        method: 'get',
        params: query
    })
}
  return request({
    url: "/home/supplierPurchaseRanking",
    method: "get",
    params: query,
  });
};
// å®¢æˆ·é‡‘额贡献排名
export const customerContributionRanking = (query) => {
    return request({
        url: '/home/customerContributionRanking',
        method: 'get',
        params: query
    })
}
  return request({
    url: "/home/customerContributionRanking",
    method: "get",
    params: query,
  });
};
// å„产品大类分布
export const productCategoryDistribution = () => {
    return request({
        url: '/home/productCategoryDistribution',
        method: 'get'
    })
}
  return request({
    url: "/home/productCategoryDistribution",
    method: "get",
  });
};
// äº§å“é”€å”®é‡‘额分析
export const productSalesAnalysis = () => {
    return request({
        url: '/home/productSalesAnalysis',
        method: 'get'
    })
}
  return request({
    url: "/home/productSalesAnalysis",
    method: "get",
  });
};
// åŽŸææ–™é‡‡è´­é‡‘é¢å æ¯”
export const rawMaterialPurchaseAmountRatio = () => {
    return request({
        url: '/home/rawMaterialPurchaseAmountRatio',
        method: 'get'
    })
}
  return request({
    url: "/home/rawMaterialPurchaseAmountRatio",
    method: "get",
  });
};
// é”€å”®/采购/储存产品数
export const salesPurchaseStorageProductCount = () => {
    return request({
        url: '/home/salesPurchaseStorageProductCount',
        method: 'get'
    })
}
  return request({
    url: "/home/salesPurchaseStorageProductCount",
    method: "get",
  });
};
// äº§å“å‡ºå…¥åº“分析(可传 productType: 1 åŽŸææ–™ 2 åŠæˆå“ 3 æˆå“ï¼‰
export const productInOutAnalysis = (params) => {
    return request({
        url: '/home/productInOutAnalysis',
        method: 'get',
        params
    })
}
  return request({
    url: "/home/productInOutAnalysis",
    method: "get",
    params,
  });
};
// äº§å“å‘¨è½¬å¤©æ•°
export const productTurnoverDays = () => {
    return request({
        url: '/home/productTurnoverDays',
        method: 'get'
    })
}
  return request({
    url: "/home/productTurnoverDays",
    method: "get",
  });
};
// æ”¶æ”¯å¯¹æ¯”分析
export const incomeExpenseAnalysis = () => {
  return request({
    url: "/home/incomeExpenseAnalysis",
    method: "get",
  });
};
// åˆ©æ¶¦è¶‹åŠ¿åˆ†æž
export const profitTrendAnalysis = () => {
  return request({
    url: "/home/profitTrendAnalysis",
    method: "get",
  });
};
// æœˆåº¦æ”¶å…¥
export const getMonthlyIncome = () => {
  return request({
    url: "/home/monthlyIncome",
    method: "get",
  });
};
// æœˆåº¦æ”¯å‡º
export const getMonthlyExpenditure = () => {
  return request({
    url: "/home/monthlyExpenditure",
    method: "get",
  });
};
src/views/reportAnalysis/financialAnalysis/components/CarouselCards.vue
ÎļþÒÑɾ³ý
src/views/reportAnalysis/financialAnalysis/components/ProductTypeSwitch.vue
@@ -4,9 +4,13 @@
    class="product-type-switch"
    @change="handleChange"
  >
    <el-radio-button :label="1">原材料</el-radio-button>
    <el-radio-button :label="3">半成品</el-radio-button>
    <el-radio-button :label="2">成品</el-radio-button>
    <el-radio-button
      v-for="opt in options"
      :key="opt.label"
      :label="opt.label"
    >
      {{ opt.text }}
    </el-radio-button>
  </el-radio-group>
</template>
@@ -15,8 +19,17 @@
const props = defineProps({
  modelValue: {
    type: Number,
    default: 1, // é»˜è®¤é€‰ä¸­"原材料"
    type: [Number, String],
    default: 1, // é»˜è®¤é€‰ä¸­ç¬¬ä¸€ä¸ª
  },
  // å¯é…ç½®é€‰é¡¹ï¼Œé»˜è®¤æ˜¯åŽŸç»„ä»¶çš„ã€ŒåŽŸææ–™ / åŠæˆå“ / æˆå“ã€
  options: {
    type: Array,
    default: () => [
      { label: 1, text: '原材料' },
      { label: 3, text: '半成品' },
      { label: 2, text: '成品' },
    ],
  },
})
src/views/reportAnalysis/financialAnalysis/components/center-bottom.vue
@@ -22,6 +22,7 @@
import { ref, onMounted } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from './PanelHeader.vue'
import { profitTrendAnalysis } from '@/api/viewIndex.js'
const chartStyle = { width: '100%', height: '150%' }
const grid = { left: '3%', right: '4%', bottom: '3%', top: '4%', containLabel: true }
@@ -70,10 +71,22 @@
const yAxis1 = [{ type: 'value', axisLabel: { color: '#B8C8E0' } }]
const fetchData = () => {
  profitTrendAnalysis()
    .then((res) => {
      if (res.code === 200 && Array.isArray(res.data)) {
        const list = res.data
        xAxis1.value[0].data = list.map((d) => d.name)
        barSeries1.value[0].data = list.map((d) => parseFloat(d.value) || 0)
      }
    })
    .catch((err) => {
      console.error('获取利润趋势分析失败:', err)
    })
}
onMounted(() => {
  // å…ˆç”¨æœ¬åœ°å‡æ•°æ®ï¼ˆåŽç»­å¦‚有接口可替换)
  xAxis1.value[0].data = ['1月', '2月', '3月', '4月', '5月', '6月']
  barSeries1.value[0].data = [12000, 18000, 9000, 16000, 14000, 20000]
  fetchData()
})
</script>
src/views/reportAnalysis/financialAnalysis/components/center-center.vue
@@ -30,6 +30,7 @@
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
import Echarts from '@/components/Echarts/echarts.vue'
import { incomeExpenseAnalysis } from '@/api/viewIndex.js'
const chartStyle = { width: '100%', height: '100%' }
const grid = {
@@ -128,16 +129,23 @@
  },
}
// å…ˆç”¨æœ¬åœ°å‡æ•°æ®ï¼ˆåŽç»­å¦‚有接口可直接替换这里)
const setMockData = () => {
  const dates = ['1/22', '1/23', '1/24', '1/25', '1/26', '1/27', '1/28']
  xAxis1.value[0].data = dates
  lineSeries.value[0].data = [1200, 1800, 900, 1600, 1400, 2000, 1700] // æ”¶å…¥
  lineSeries.value[1].data = [800, 1100, 700, 1200, 1000, 1500, 1300] // æ”¯å‡º
const fetchData = () => {
  incomeExpenseAnalysis()
    .then((res) => {
      if (res.code === 200 && Array.isArray(res.data)) {
        const list = res.data
        xAxis1.value[0].data = list.map((d) => d.date)
        lineSeries.value[0].data = list.map((d) => Number(d.income) || 0)
        lineSeries.value[1].data = list.map((d) => Number(d.expense) || 0)
      }
    })
    .catch((err) => {
      console.error('获取收支对比分析失败:', err)
    })
}
onMounted(() => {
  setMockData()
  fetchData()
})
</script>
src/views/reportAnalysis/financialAnalysis/components/center-top.vue
@@ -10,7 +10,10 @@
        <div class="card-body">
          <div class="card-left">
            <div class="card-title">月度收入</div>
            <div class="card-amount">{{ income.amount }}</div>
            <div class="card-amount">
              <span>{{ formatAmountWanNumber(income.amount) }}</span>
              <span v-if="isWanAmount(income.amount)" class="card-amount-unit">万</span>
            </div>
          </div>
          <div class="card-right">
            <div class="metric-row">
@@ -22,7 +25,15 @@
            </div>
            <div class="metric-row">
              <span class="metric-label">逾期数</span>
              <span class="metric-value metric-up">{{ income.overdueCount }}</span>
              <span class="metric-value metric-up">
                {{ formatAmountWanNumber(income.overdueCount) }}
                <span
                  v-if="isWanAmount(income.overdueCount)"
                  class="metric-unit"
                >
                  ä¸‡
                </span>
              </span>
            </div>
            <div class="metric-row">
              <span class="metric-label">逾期率</span>
@@ -43,16 +54,30 @@
        <div class="card-body">
          <div class="card-left">
            <div class="card-title">月度支出</div>
            <div class="card-amount">{{ expense.amount }}</div>
            <div class="card-amount">
              <span>{{ formatAmountWanNumber(expense.amount) }}</span>
              <span v-if="isWanAmount(expense.amount)" class="card-amount-unit">万</span>
            </div>
          </div>
          <div class="card-right">
            <div class="metric-row">
              <span class="metric-label">付款率</span>
              <span class="metric-value metric-down">{{ expense.netProfit }}</span>
              <span class="metric-value" :class="metricClass(expense.netProfit)">
                {{ formatPercent(expense.netProfit.value) }}
                <span class="arrow">{{ metricArrow(expense.netProfit) }}</span>
              </span>
            </div>
            <div class="metric-row">
              <span class="metric-label">毛利润</span>
              <span class="metric-value metric-down">{{ expense.grossProfit }}</span>
              <span class="metric-value metric-down">
                {{ formatAmountWanNumber(expense.grossProfit) }}
                <span
                  v-if="isWanAmount(expense.grossProfit)"
                  class="metric-unit"
                >
                  ä¸‡
                </span>
              </span>
            </div>
            <div class="metric-row">
              <span class="metric-label">利润率</span>
@@ -70,33 +95,93 @@
</template>
<script setup>
import { ref } from 'vue'
import { onMounted, ref } from 'vue'
import { getMonthlyIncome, getMonthlyExpenditure } from '@/api/viewIndex'
// æš‚时使用本地示例数据,后续可接真实接口覆盖
const income = ref({
  amount: 102,
  repayRate: { value: 52, trend: 1 }, // æ­£å‘ â†‘
  overdueCount: 10092,
  overdueRate: { value: 12, trend: 1 },
  amount: 0,
  repayRate: { value: 0, trend: 0 },
  overdueCount: 0,
  overdueRate: { value: 0, trend: 0 },
})
const expense = ref({
  amount: 102,
  netProfit: 291013,
  grossProfit: 10092,
  profitRate: { value: 12, trend: -1 }, // è´Ÿå‘ â†“
  amount: 0,
  netProfit: { value: 0, trend: 0 },
  grossProfit: 0,
  profitRate: { value: 0, trend: 0 },
})
const fetchMonthlyIncome = async () => {
  const res = await getMonthlyIncome()
  const data = res?.data || {}
  income.value.amount = data.monthlyIncome ?? 0
  const collectionRate = Number(data.collectionRate ?? 0)
  const overdueRate = Number(data.overdueRate ?? 0)
  income.value.repayRate = {
    value: collectionRate,
    trend: collectionRate >= 0 ? 1 : -1,
  }
  income.value.overdueCount = data.overdueNum ?? 0
  income.value.overdueRate = {
    value: overdueRate,
    trend: overdueRate >= 0 ? 1 : -1,
  }
}
const fetchMonthlyExpenditure = async () => {
  const res = await getMonthlyExpenditure()
  const data = res?.data || {}
  expense.value.amount = data.monthlyExpenditure ?? 0
  const paymentRate = Number(data.paymentRate ?? 0)
  expense.value.netProfit = {
    value: paymentRate,
    trend: paymentRate >= 0 ? 1 : -1,
  }
  expense.value.grossProfit = data.grossProfit ?? 0
  const profitMarginRate = Number(data.profitMarginRate ?? 0)
  expense.value.profitRate = {
    value: profitMarginRate,
    trend: profitMarginRate >= 0 ? 1 : -1,
  }
}
const isWanAmount = (val) => {
  const num = Number(val) || 0
  return Math.abs(num) >= 10000
}
const formatAmountWanNumber = (val) => {
  const num = Number(val) || 0
  if (Math.abs(num) >= 10000) {
    return (num / 10000).toFixed(2)
  }
  return num.toFixed(2)
}
const formatPercent = (val) => {
  const num = Number(val) || 0
  return `${num.toFixed(2)}%`
  // ç™¾åˆ†æ¯”展示始终用绝对值,小数保留两位
  return `${Math.abs(num).toFixed(2)}%`
}
const metricClass = (metric) =>
  Number(metric.trend) >= 0 ? 'metric-up' : 'metric-down'
const metricClass = (metric) => {
  if (metric?.trend === undefined || metric?.trend === null) return 'metric-up'
  return Number(metric.trend) >= 0 ? 'metric-up' : 'metric-down'
}
const metricArrow = (metric) =>
  Number(metric.trend) >= 0 ? '↑' : '↓'
const metricArrow = (metric) => {
  if (metric?.trend === undefined || metric?.trend === null) return ''
  return Number(metric.trend) >= 0 ? '↑' : '↓'
}
onMounted(() => {
  fetchMonthlyIncome()
  fetchMonthlyExpenditure()
})
</script>
<style scoped>
@@ -110,7 +195,7 @@
  flex: 1;
  display: flex;
  align-items: center;
  padding: 18px 24px;
  padding: 18px 10px;
  background-image: url('@/assets/BI/border@2x.png');
  background-size: 100% 100%;
  background-position: center;
@@ -156,10 +241,18 @@
  font-size: 36px;
  line-height: 1.1;
  margin-top: 8px;
  display: inline-flex;
  align-items: baseline;
  white-space: nowrap;
  background: linear-gradient(360deg, #008bfd 0%, #ffffff 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.card-amount-unit {
  font-size: 20px;
  margin-left: 4px;
}
.card-right {
@@ -193,6 +286,11 @@
  align-items: center;
}
.metric-unit {
  font-size: 12px;
  margin-left: 2px;
}
.metric-value .arrow {
  font-size: 13px;
  margin-left: 4px;
src/views/reportAnalysis/financialAnalysis/components/left-bottom.vue
@@ -1,7 +1,14 @@
<template>
  <div>
    <PanelHeader title="支出构成分析" />
    <PanelHeader title="构成分析" />
    <div class="main-panel panel-item-customers">
      <div class="filters-row">
        <ProductTypeSwitch
          v-model="amountType"
          :options="amountTypeOptions"
          @change="handleTypeChange"
        />
      </div>
      <!-- <CarouselCards :items="cardItems" :visible-count="3" /> -->
      <div class="pie-chart-wrapper">
        <div class="pie-background"></div>
@@ -25,7 +32,7 @@
import { ref, onMounted, computed } from 'vue'
import Echarts from '@/components/Echarts/echarts.vue'
import PanelHeader from './PanelHeader.vue'
import CarouselCards from './CarouselCards.vue'
import ProductTypeSwitch from './ProductTypeSwitch.vue'
import { rawMaterialPurchaseAmountRatio } from '@/api/viewIndex.js'
/**
@@ -41,6 +48,14 @@
  }
  return resObj
}
// å½“前类型:1=支出 2=收入
const amountType = ref(1)
const amountTypeOptions = [
  { label: 1, text: '支出' },
  { label: 2, text: '收入' },
]
// æ•°æ®åˆ—表(来自接口)
const dataList = ref([])
@@ -69,7 +84,7 @@
    top: 'center',
    left: '52%',
    itemGap: 30,
    show: false,
    show: true,
    data: data,
    formatter: function (name) {
      const item = landObjData.value[name]
@@ -112,12 +127,13 @@
}
// åŒå±‚环形饼图
// åŒå±‚环形饼图
const landSeries = ref([
  {
    name: '产品采购金额分析',
    name: '构成分析',
    type: 'pie',
    radius: ['50%', '75%'],
    center: ['50%', '60%'],
    radius: ['40%', '60%'],
    center: ['25%', '50%'],
    itemStyle: {
      borderColor: '#0a1c3a',
      borderWidth: 2,
@@ -126,16 +142,7 @@
      },
    },
    label: {
      show: true,
      position: 'outside',
      color: '#fff',
      fontSize: 12,
      lineHeight: 18,
      // rich: {
      //   ...dotRich,
      //   parent: { fontSize: 14, fontWeight: 600, color: '#fff', lineHeight: 20, overflow: 'break' },
      //   child: { fontSize: 12, color: '#fff', lineHeight: 18 },
      // },
      show: false
    },
    minAngle: 15,
    data: dataList.value,
@@ -148,8 +155,8 @@
  {
    // å†…圈
    type: 'pie',
    radius: ['50%', '60%'],
    center: ['50%', '60%'],
    radius: ['40%', '45%'],
    center: ['25%', '50%'],
    silent: true,
    label: {
      show: false,
@@ -175,6 +182,8 @@
}
const fetchData = () => {
  // ç›®å‰æŽ¥å£åªæœ‰æ”¯å‡ºæž„成占比,先忽略类型参数
  // é¢„留扩展:后续可根据 amountType åˆ‡ä¸åŒæŽ¥å£
  rawMaterialPurchaseAmountRatio()
    .then((res) => {
      if (res.code === 200 && Array.isArray(res.data)) {
@@ -199,6 +208,10 @@
    })
}
const handleTypeChange = () => {
  fetchData()
}
onMounted(() => {
  fetchData()
})
@@ -209,6 +222,14 @@
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.filters-row {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
}
.panel-item-customers {
@@ -228,11 +249,11 @@
.pie-background {
  position: absolute;
  left: 50%;
  top: 60%;
  left: 25%;
  top: 50%;
  transform: translate(-51.5%, -50%);
  width: 380px;
  height: 380px;
  width: 310px;
  height: 310px;
  background-image: url('@/assets/BI/玫瑰图边框.png');
  background-size: contain;
  background-position: center;
src/views/reportAnalysis/financialAnalysis/components/left-top.vue
@@ -20,7 +20,7 @@
<script setup>
import { ref, onMounted } from 'vue'
import { productSalesAnalysis } from '@/api/viewIndex.js'
import { getAmountHalfYear } from '@/api/viewIndex.js'
import PanelHeader from './PanelHeader.vue'
import Echarts from '@/components/Echarts/echarts.vue'
@@ -30,13 +30,16 @@
}
const grid = { left: '3%', right: '4%', bottom: '3%', top: '10%', containLabel: true }
const barLegend = { show: true, textStyle: { color: '#B8C8E0' }, data: ['金额'] }
const barLegend = {
  show: true,
  textStyle: { color: '#B8C8E0' },
  data: ['开票金额', '回款金额'],
}
const barSeries1 = ref([
  {
    name: '金额',
    name: '开票金额',
    type: 'bar',
    barGap: 0,
    barWidth: 30,
    barWidth: 20,
    emphasis: { focus: 'series' },
    itemStyle: {
      color: {
@@ -46,8 +49,29 @@
        x2: 0,
        y2: 1,
        colorStops: [
          { offset: 1, color: '#00A4ED' },
          { offset: 0, color: '#4EE4FF' },
          { offset: 1, color: 'rgba(0, 164, 237, 0)' },
          { offset: 0, color: 'rgba(78, 228, 255, 1)' },
        ],
      },
    },
    data: [],
  },
  {
    name: '回款金额',
    type: 'bar',
    barGap: '40%',
    barWidth: 20,
    emphasis: { focus: 'series' },
    itemStyle: {
      color: {
        type: 'linear',
        x: 0,
        y: 0,
        x2: 0,
        y2: 1,
        colorStops: [
          { offset: 1, color: 'rgba(83, 126, 245, 0.19)' },
          { offset: 0, color: 'rgba(144, 97, 248, 1)' },
        ],
      },
    },
@@ -71,16 +95,21 @@
const yAxis1 = [{ type: 'value', axisLabel: { color: '#B8C8E0' } }]
const fetchData = () => {
  productSalesAnalysis()
  getAmountHalfYear()
    .then((res) => {
      if (res.code === 200 && Array.isArray(res.data)) {
        const items = res.data
      xAxis1.value[0].data = items.map((item) => item.name)
      barSeries1.value[0].data = items.map((item) => parseFloat(item.value) || 0)
        xAxis1.value[0].data = items.map((item) => item.month)
        barSeries1.value[0].data = items.map(
          (item) => parseFloat(item.invoiceAmount) || 0
        )
        barSeries1.value[1].data = items.map(
          (item) => parseFloat(item.receiptAmount) || 0
        )
      }
    })
    .catch((err) => {
      console.error('获取产品销售金额分析失败:', err)
      console.error('获取近半年回款与开票数据失败:', err)
    })
}