From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/crm/statistics/performance/components/ReceivablePricePerformance.vue |  236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 236 insertions(+), 0 deletions(-)

diff --git a/src/views/crm/statistics/performance/components/ReceivablePricePerformance.vue b/src/views/crm/statistics/performance/components/ReceivablePricePerformance.vue
new file mode 100644
index 0000000..169f074
--- /dev/null
+++ b/src/views/crm/statistics/performance/components/ReceivablePricePerformance.vue
@@ -0,0 +1,236 @@
+<!-- 鍛樺伐涓氱哗缁熻 -->
+<template>
+  <!-- Echarts鍥� -->
+  <el-card shadow="never">
+    <el-skeleton :loading="loading" animated>
+      <Echart :height="500" :options="echartsOption" />
+    </el-skeleton>
+  </el-card>
+
+  <!-- 缁熻鍒楄〃 -->
+  <el-card shadow="never" class="mt-16px">
+    <el-table v-loading="loading" :data="tableData">
+      <el-table-column
+        v-for="item in columnsData"
+        :key="item.prop"
+        :label="item.label"
+        :prop="item.prop"
+        align="center"
+      >
+        <template #default="scope">
+          {{ scope.row[item.prop] }}
+        </template>
+      </el-table-column>
+    </el-table>
+  </el-card>
+</template>
+<script setup lang="ts">
+import { EChartsOption } from 'echarts'
+import {
+  StatisticsPerformanceApi,
+  StatisticsPerformanceRespVO
+} from '@/api/crm/statistics/performance'
+
+defineOptions({ name: 'ContractPricePerformance' })
+const props = defineProps<{ queryParams: any }>() // 鎼滅储鍙傛暟
+
+const loading = ref(false) // 鍔犺浇涓�
+const list = ref<StatisticsPerformanceRespVO[]>([]) // 鍒楄〃鐨勬暟鎹�
+
+/** 鏌辩姸鍥鹃厤缃細绾靛悜 */
+const echartsOption = reactive<EChartsOption>({
+  grid: {
+    left: 20,
+    right: 20,
+    bottom: 20,
+    containLabel: true
+  },
+  legend: {},
+  series: [
+    {
+      name: '褰撴湀鍥炴閲戦锛堝厓锛�',
+      type: 'line',
+      data: []
+    },
+    {
+      name: '涓婃湀鍥炴閲戦锛堝厓锛�',
+      type: 'line',
+      data: []
+    },
+    {
+      name: '鍘诲勾鍚屾湀鍥炴閲戦锛堝厓锛�',
+      type: 'line',
+      data: []
+    },
+    {
+      name: '鐜瘮澧為暱鐜囷紙%锛�',
+      type: 'line',
+      yAxisIndex: 1,
+      data: []
+    },
+    {
+      name: '鍚屾瘮澧為暱鐜囷紙%锛�',
+      type: 'line',
+      yAxisIndex: 1,
+      data: []
+    }
+  ],
+  toolbox: {
+    feature: {
+      dataZoom: {
+        xAxisIndex: false // 鏁版嵁鍖哄煙缂╂斁锛歒 杞翠笉缂╂斁
+      },
+      brush: {
+        type: ['lineX', 'clear'] // 鍖哄煙缂╂斁鎸夐挳銆佽繕鍘熸寜閽�
+      },
+      saveAsImage: { show: true, name: '瀹㈡埛鎬婚噺鍒嗘瀽' } // 淇濆瓨涓哄浘鐗�
+    }
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  yAxis: [
+    {
+      type: 'value',
+      name: '閲戦锛堝厓锛�',
+      axisTick: {
+        show: false
+      },
+      axisLabel: {
+        color: '#BDBDBD',
+        formatter: '{value}'
+      },
+      /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */
+      axisLine: {
+        lineStyle: {
+          color: '#BDBDBD'
+        }
+      },
+      splitLine: {
+        show: true,
+        lineStyle: {
+          color: '#e6e6e6'
+        }
+      }
+    },
+    {
+      type: 'value',
+      name: '',
+      axisTick: {
+        alignWithLabel: true,
+        lineStyle: {
+          width: 0
+        }
+      },
+      axisLabel: {
+        color: '#BDBDBD',
+        formatter: '{value}%'
+      },
+      /** 鍧愭爣杞磋酱绾跨浉鍏宠缃� */
+      axisLine: {
+        lineStyle: {
+          color: '#BDBDBD'
+        }
+      },
+      splitLine: {
+        show: true,
+        lineStyle: {
+          color: '#e6e6e6'
+        }
+      }
+    }
+  ],
+  xAxis: {
+    type: 'category',
+    name: '鏃ユ湡',
+    data: []
+  }
+}) as EChartsOption
+
+/** 鑾峰彇缁熻鏁版嵁 */
+const loadData = async () => {
+  // 1. 鍔犺浇缁熻鏁版嵁
+  loading.value = true
+  const performanceList = await StatisticsPerformanceApi.getReceivablePricePerformance(
+    props.queryParams
+  )
+
+  // 2.1 鏇存柊 Echarts 鏁版嵁
+  if (echartsOption.xAxis && echartsOption.xAxis['data']) {
+    echartsOption.xAxis['data'] = performanceList.map((s: StatisticsPerformanceRespVO) => s.time)
+  }
+  if (echartsOption.series && echartsOption.series[0] && echartsOption.series[0]['data']) {
+    echartsOption.series[0]['data'] = performanceList.map(
+      (s: StatisticsPerformanceRespVO) => s.currentMonthCount
+    )
+  }
+  if (echartsOption.series && echartsOption.series[1] && echartsOption.series[1]['data']) {
+    echartsOption.series[1]['data'] = performanceList.map(
+      (s: StatisticsPerformanceRespVO) => s.lastMonthCount
+    )
+    echartsOption.series[3]['data'] = performanceList.map((s: StatisticsPerformanceRespVO) =>
+      s.lastMonthCount !== 0
+        ? (((s.currentMonthCount - s.lastMonthCount) / s.lastMonthCount) * 100).toFixed(2)
+        : 'NULL'
+    )
+  }
+  if (echartsOption.series && echartsOption.series[2] && echartsOption.series[1]['data']) {
+    echartsOption.series[2]['data'] = performanceList.map(
+      (s: StatisticsPerformanceRespVO) => s.lastYearCount
+    )
+    echartsOption.series[4]['data'] = performanceList.map((s: StatisticsPerformanceRespVO) =>
+      s.lastYearCount !== 0
+        ? (((s.currentMonthCount - s.lastYearCount) / s.lastYearCount) * 100).toFixed(2)
+        : 'NULL'
+    )
+  }
+
+  // 2.2 鏇存柊鍒楄〃鏁版嵁
+  list.value = performanceList
+  convertListData()
+  loading.value = false
+}
+
+// 鍒濆鍖栨暟鎹�
+const columnsData = reactive([])
+const tableData = reactive([
+  { title: '褰撴湀鍥炴閲戦缁熻锛堝厓锛�' },
+  { title: '涓婃湀鍥炴閲戦缁熻锛堝厓锛�' },
+  { title: '鍘诲勾褰撴湀鍥炴閲戦缁熻锛堝厓锛�' },
+  { title: '鐜瘮澧為暱鐜囷紙%锛�' },
+  { title: '鍚屾瘮澧為暱鐜囷紙%锛�' }
+])
+
+// 瀹氫箟 init 鏂规硶
+const convertListData = () => {
+  const columnObj = { label: '鏃ユ湡', prop: 'title' }
+  columnsData.splice(0, columnsData.length) //娓呯┖鏁扮粍
+  columnsData.push(columnObj)
+
+  list.value.forEach((item, index) => {
+    const columnObj = { label: item.time, prop: 'prop' + index }
+    columnsData.push(columnObj)
+    tableData[0]['prop' + index] = item.currentMonthCount
+    tableData[1]['prop' + index] = item.lastMonthCount
+    tableData[2]['prop' + index] = item.lastYearCount
+    tableData[3]['prop' + index] =
+      item.lastMonthCount !== 0
+        ? (((item.currentMonthCount - item.lastMonthCount) / item.lastMonthCount) * 100).toFixed(2)
+        : 'NULL'
+    tableData[4]['prop' + index] =
+      item.lastYearCount !== 0
+        ? (((item.currentMonthCount - item.lastYearCount) / item.lastYearCount) * 100).toFixed(2)
+        : 'NULL'
+  })
+}
+
+defineExpose({ loadData })
+
+/** 鍒濆鍖� */
+onMounted(async () => {
+  await loadData()
+})
+</script>

--
Gitblit v1.8.0