浏览代码

报表coding...

刘洋 1 年之前
父节点
当前提交
43402ac7dc

+ 20 - 2
src/api/report.js

@@ -4,7 +4,6 @@ import { request } from '@/utils/request.js';
 export const customTypeAnalysis = (params) =>
 export const customTypeAnalysis = (params) =>
   request({
   request({
     url: '/api/admin/tb/crm/analyse/custom/type',
     url: '/api/admin/tb/crm/analyse/custom/type',
-    method: 'post',
     params,
     params,
   });
   });
 
 
@@ -12,6 +11,25 @@ export const customTypeAnalysis = (params) =>
 export const monthDispatchAnalysis = (params) =>
 export const monthDispatchAnalysis = (params) =>
   request({
   request({
     url: '/api/admin/tb/crm/analyse/monthly',
     url: '/api/admin/tb/crm/analyse/monthly',
-    method: 'post',
+    params,
+  });
+//大区在执行派单排名接口
+export const dispatchRankingAnalysis = (params) =>
+  request({
+    url: '/api/admin/tb/crm/analyse/region',
+    params,
+  });
+
+//供应商派单分布接口
+export const supplierDispatchAnalysis = (params) =>
+  request({
+    url: '/api/admin/tb/crm/analyse/supplier',
+    params,
+  });
+
+//项目派单完成率接口
+export const dispatchStatisticsAnalysis = (params) =>
+  request({
+    url: '/api/admin/tb/crm/analyse/project',
     params,
     params,
   });
   });

+ 106 - 148
src/components/common/china-point-chart/index.vue

@@ -7,37 +7,43 @@ import chinaMap from '@/assets/json/china.json';
 import * as echarts from 'echarts';
 import * as echarts from 'echarts';
 import MyChart from '../../global/chart';
 import MyChart from '../../global/chart';
 import geoCoordMap from './geoCoordMap';
 import geoCoordMap from './geoCoordMap';
+import { colorList } from '@/utils/chart';
 onMounted(() => {
 onMounted(() => {
   echarts.registerMap('china', { geoJSON: chinaMap });
   echarts.registerMap('china', { geoJSON: chinaMap });
 });
 });
-let data2 = [
-  { name: '哈尔滨', value: 131426 },
-  { name: '沈阳', value: 30716 },
-  { name: '西安', value: 25380 },
-  { name: '太原', value: 25152 },
-  { name: '呼和浩特', value: 19896 },
-  { name: '天津', value: 14843 },
-  { name: '石家庄', value: 13697 },
-  { name: '郑州', value: 8494 },
-  { name: '贵阳', value: 8442 },
-];
-let data1 = [
-  { name: '银川', value: 8398 },
-  { name: '西宁', value: 8390 },
-  { name: '济南', value: 67715 },
-  { name: '长春', value: 7100 },
-  { name: '北京', value: 36506 },
-  { name: '重庆', value: 4672 },
-  { name: '兰州', value: 4302 },
-  { name: '乌鲁木齐', value: 4294 },
-  { name: '上海', value: 3091 },
-  { name: '昆明', value: 2428 },
-  { name: '武汉', value: 71800 },
-];
+// let data2 = [
+//   { name: '哈尔滨', value: 131426 },
+//   { name: '沈阳', value: 30716 },
+//   { name: '西安', value: 25380 },
+//   { name: '太原', value: 25152 },
+//   { name: '呼和浩特', value: 19896 },
+//   { name: '天津', value: 14843 },
+//   { name: '石家庄', value: 13697 },
+//   { name: '郑州', value: 8494 },
+//   { name: '贵阳', value: 8442 },
+// ];
+// let data1 = [
+//   { name: '银川', value: 8398 },
+//   { name: '西宁', value: 8390 },
+//   { name: '济南', value: 67715 },
+//   { name: '长春', value: 7100 },
+//   { name: '北京', value: 36506 },
+//   { name: '重庆', value: 4672 },
+//   { name: '兰州', value: 4302 },
+//   { name: '乌鲁木齐', value: 4294 },
+//   { name: '上海', value: 3091 },
+//   { name: '昆明', value: 2428 },
+//   { name: '武汉', value: 71800 },
+// ];
+const props = defineProps({ data: Object });
 const convertData = (data) => {
 const convertData = (data) => {
+  console.log('data:::', data);
   var res = [];
   var res = [];
   for (var i = 0; i < data.length; i++) {
   for (var i = 0; i < data.length; i++) {
-    var geoCoord = geoCoordMap[data[i].name];
+    var geoCoord =
+      geoCoordMap[
+        data[i].name.endsWith('省') ? data[i].name.slice(0, -1) : data[i].name
+      ];
     if (geoCoord) {
     if (geoCoord) {
       res.push({
       res.push({
         name: data[i].name,
         name: data[i].name,
@@ -47,6 +53,80 @@ const convertData = (data) => {
   }
   }
   return res;
   return res;
 };
 };
+const dataHandle = (data) => {
+  if (!data) {
+    return [];
+  } else {
+    let arr = [];
+    // console.log('data', data);
+    // console.log('data[0].data:', data[0].data);
+    // console.log('convertData[data[0].data]', convertData[data[0].data]);
+    for (let i = 0; i < data.length; i++) {
+      let item = data[i];
+      arr.push(
+        {
+          name: item.name,
+          type: 'scatter',
+          coordinateSystem: 'geo',
+          data: convertData(item.data),
+          symbolSize: function (val) {
+            return val[2] / 3000;
+          },
+          label: {
+            normal: {
+              formatter: '{b}',
+              position: 'right',
+              show: false,
+            },
+            emphasis: {
+              show: true,
+            },
+          },
+          itemStyle: {
+            normal: {
+              color: colorList[i],
+            },
+          },
+        },
+        {
+          name: item.name,
+          type: 'effectScatter',
+          coordinateSystem: 'geo',
+          data: convertData(
+            item.data.sort(function (a, b) {
+              return b.value - a.value;
+            })
+          ),
+          symbolSize: function (val) {
+            return val[2] / 3000;
+          },
+          showEffectOn: 'render',
+          rippleEffect: {
+            brushType: 'stroke',
+          },
+          hoverAnimation: true,
+          label: {
+            normal: {
+              formatter: '{b}',
+              position: 'right',
+              fontSize: 12,
+              show: true,
+            },
+          },
+          itemStyle: {
+            normal: {
+              color: colorList[i],
+              shadowBlur: 10,
+              shadowColor: '#333',
+            },
+          },
+          zlevel: 1,
+        }
+      );
+    }
+    return arr;
+  }
+};
 const options = computed(() => {
 const options = computed(() => {
   return {
   return {
     backgroundColor: 'rgba(0,0,0,.05)',
     backgroundColor: 'rgba(0,0,0,.05)',
@@ -126,129 +206,7 @@ const options = computed(() => {
         },
         },
       },
       },
     },
     },
-    series: [
-      {
-        name: '教务处',
-        type: 'scatter',
-        coordinateSystem: 'geo',
-        data: convertData(data1),
-        symbolSize: function (val) {
-          return val[2] / 3000;
-        },
-        label: {
-          normal: {
-            formatter: '{b}',
-            position: 'right',
-            show: false,
-          },
-          emphasis: {
-            show: true,
-          },
-        },
-        itemStyle: {
-          normal: {
-            color: '#23C343',
-          },
-        },
-      },
-      {
-        name: '教务处',
-        type: 'effectScatter',
-        coordinateSystem: 'geo',
-        data: convertData(
-          data1
-            .sort(function (a, b) {
-              return b.value - a.value;
-            })
-            .slice(0, 21)
-        ),
-        symbolSize: function (val) {
-          return val[2] / 3000;
-        },
-        showEffectOn: 'render',
-        rippleEffect: {
-          brushType: 'stroke',
-        },
-        hoverAnimation: true,
-        label: {
-          normal: {
-            formatter: '{b}',
-            position: 'right',
-            fontSize: 12,
-            show: true,
-          },
-        },
-        itemStyle: {
-          normal: {
-            color: '#23C343',
-            shadowBlur: 10,
-            shadowColor: '#333',
-          },
-        },
-        zlevel: 1,
-      },
-
-      {
-        name: '研究生',
-        type: 'scatter',
-        coordinateSystem: 'geo',
-        data: convertData(data2),
-        symbolSize: function (val) {
-          return val[2] / 3000;
-        },
-        label: {
-          normal: {
-            formatter: '{b}',
-            position: 'right',
-            show: false,
-          },
-          emphasis: {
-            show: true,
-          },
-        },
-        itemStyle: {
-          normal: {
-            color: '#F4E925',
-          },
-        },
-      },
-      {
-        name: '研究生',
-        type: 'effectScatter',
-        coordinateSystem: 'geo',
-        data: convertData(
-          data2
-            .sort(function (a, b) {
-              return b.value - a.value;
-            })
-            .slice(0, 21)
-        ),
-        symbolSize: function (val) {
-          return val[2] / 3000;
-        },
-        showEffectOn: 'render',
-        rippleEffect: {
-          brushType: 'stroke',
-        },
-        hoverAnimation: true,
-        label: {
-          normal: {
-            formatter: '{b}',
-            position: 'right',
-            fontSize: 12,
-            show: true,
-          },
-        },
-        itemStyle: {
-          normal: {
-            color: '#F4E925',
-            shadowBlur: 10,
-            shadowColor: '#333',
-          },
-        },
-        zlevel: 1,
-      },
-    ],
+    series: dataHandle(props.data),
   };
   };
 });
 });
 </script>
 </script>

+ 19 - 56
src/components/common/table-loop/index.vue

@@ -17,60 +17,20 @@
       :mousewheel="true"
       :mousewheel="true"
       :autoplay="{ delay: 1500 }"
       :autoplay="{ delay: 1500 }"
     >
     >
-      <swiper-slide class="slide">
-        <div class="td col1">1</div>
-        <div class="td col2">呼和浩特</div>
-        <div class="td col3"> 22 </div>
+      <swiper-slide
+        class="slide"
+        v-for="(item, index) in data || []"
+        :key="index"
+      >
+        <div class="td col1">{{ index + 1 }}</div>
+        <div class="td col2">{{ item.name }}</div>
+        <div class="td col3"> {{ item.count }} </div>
         <div class="td col4">
         <div class="td col4">
           <div class="process-box">
           <div class="process-box">
-            <div class="process" :style="{ width: '70%' }"></div>
+            <div class="process" :style="{ width: item.rate }"></div>
           </div>
           </div>
         </div>
         </div>
-        <div class="td col5">+19</div>
-      </swiper-slide>
-      <swiper-slide class="slide">
-        <div class="td col1">2</div>
-        <div class="td col2">呼和浩特</div>
-        <div class="td col3">19</div>
-        <div class="td col4">
-          <div class="process-box">
-            <div class="process" :style="{ width: '70%' }"></div>
-          </div>
-        </div>
-        <div class="td col5">+19</div>
-      </swiper-slide>
-      <swiper-slide class="slide">
-        <div class="td col1">3</div>
-        <div class="td col2">呼和浩特</div>
-        <div class="td col3">19</div>
-        <div class="td col4">
-          <div class="process-box">
-            <div class="process" :style="{ width: '70%' }"></div>
-          </div>
-        </div>
-        <div class="td col5">+19</div>
-      </swiper-slide>
-      <swiper-slide class="slide">
-        <div class="td col1">4</div>
-        <div class="td col2">呼和浩特</div>
-        <div class="td col3">19</div>
-        <div class="td col4">
-          <div class="process-box">
-            <div class="process" :style="{ width: '70%' }"></div>
-          </div>
-        </div>
-        <div class="td col5">+19</div>
-      </swiper-slide>
-      <swiper-slide class="slide">
-        <div class="td col1">5</div>
-        <div class="td col2">呼和浩特</div>
-        <div class="td col3">19</div>
-        <div class="td col4">
-          <div class="process-box">
-            <div class="process" :style="{ width: '70%' }"></div>
-          </div>
-        </div>
-        <div class="td col5">+19</div>
+        <div class="td col5"></div>
       </swiper-slide>
       </swiper-slide>
     </swiper>
     </swiper>
   </div>
   </div>
@@ -82,6 +42,7 @@ import { Navigation, Mousewheel, Autoplay } from 'swiper';
 import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
 import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
 import 'swiper/css';
 import 'swiper/css';
 import 'swiper/css/autoplay';
 import 'swiper/css/autoplay';
+const props = defineProps({ data: Object });
 const modules = ref([Navigation, Mousewheel, Autoplay]);
 const modules = ref([Navigation, Mousewheel, Autoplay]);
 const swiperKey = ref(Date.now() + '');
 const swiperKey = ref(Date.now() + '');
 const tableLoop = ref();
 const tableLoop = ref();
@@ -112,18 +73,20 @@ onMounted(() => {
       line-height: 36px;
       line-height: 36px;
     }
     }
   }
   }
+  .slide {
+    .col1,
+    .col2,
+    .col3 {
+      color: #262626;
+    }
+  }
   .col1 {
   .col1 {
     width: 34px;
     width: 34px;
-
-    color: #262626;
   }
   }
   .col2 {
   .col2 {
     width: calc((100% - 84px) / 2);
     width: calc((100% - 84px) / 2);
-    color: #262626;
-  }
-  .col3 {
-    color: #262626;
   }
   }
+
   .col3,
   .col3,
   .col5 {
   .col5 {
     width: calc((100% - 84px) / 4);
     width: calc((100% - 84px) / 4);

+ 1 - 1
src/utils/chart.js

@@ -27,7 +27,7 @@ const mergeParams = (options, obj) => {
   });
   });
   return options;
   return options;
 };
 };
-const colorList = [
+export const colorList = [
   '#4080FF',
   '#4080FF',
   '#23C343',
   '#23C343',
   '#37a2da',
   '#37a2da',

+ 114 - 27
src/views/report/dispatch-analysis/index.vue

@@ -24,7 +24,9 @@
           <div class="col2 flex-1">
           <div class="col2 flex-1">
             <div class="statistics"></div>
             <div class="statistics"></div>
             <div class="china-box">
             <div class="china-box">
-              <ChinaPointChart></ChinaPointChart>
+              <ChinaPointChart
+                :data="chinaDataHandle(result5, result8)"
+              ></ChinaPointChart>
             </div>
             </div>
           </div>
           </div>
           <div class="col3">
           <div class="col3">
@@ -37,7 +39,7 @@
             <div class="card chart5-box">
             <div class="card chart5-box">
               <div class="title">研究生城市在执行派单排名</div>
               <div class="title">研究生城市在执行派单排名</div>
               <div class="chart-wrap">
               <div class="chart-wrap">
-                <table-loop></table-loop>
+                <table-loop :data="tableDataHandle(result5)"></table-loop>
               </div>
               </div>
             </div>
             </div>
           </div>
           </div>
@@ -140,7 +142,7 @@
             <div class="card chart8-box">
             <div class="card chart8-box">
               <div class="title">教务处城市在执行派单排名</div>
               <div class="title">教务处城市在执行派单排名</div>
               <div class="chart-wrap">
               <div class="chart-wrap">
-                <table-loop></table-loop>
+                <table-loop :data="tableDataHandle(result8)"></table-loop>
               </div>
               </div>
             </div>
             </div>
           </div>
           </div>
@@ -161,8 +163,20 @@ import {
   createRingPieOption,
   createRingPieOption,
   createCakePieOption,
   createCakePieOption,
 } from '@/utils/chart';
 } from '@/utils/chart';
-import { customTypeAnalysis, monthDispatchAnalysis } from '@/api/report';
+import {
+  customTypeAnalysis,
+  monthDispatchAnalysis,
+  dispatchRankingAnalysis,
+  supplierDispatchAnalysis,
+  dispatchStatisticsAnalysis,
+} from '@/api/report';
 const curTimeRange = ref([]);
 const curTimeRange = ref([]);
+const timeParams = computed(() => {
+  return {
+    startTime: new Date(curTimeRange.value[0]).getTime(),
+    endTime: new Date(curTimeRange.value[1]).getTime(),
+  };
+});
 const {
 const {
   data: result1,
   data: result1,
   loading: loading1,
   loading: loading1,
@@ -173,15 +187,96 @@ const {
   loading: loading2,
   loading: loading2,
   run: run2,
   run: run2,
 } = useRequest(monthDispatchAnalysis);
 } = useRequest(monthDispatchAnalysis);
+const comResult2 = computed(() => {
+  return barDataHandle(result2.value);
+});
+const comResult3 = computed(() => {
+  return barDataHandle(result3.value);
+});
 const {
 const {
   data: result3,
   data: result3,
   loading: loading3,
   loading: loading3,
   run: run3,
   run: run3,
 } = useRequest(monthDispatchAnalysis);
 } = useRequest(monthDispatchAnalysis);
+const {
+  data: result4,
+  loading: loading4,
+  run: run4,
+} = useRequest(supplierDispatchAnalysis);
+const {
+  data: result5,
+  loading: loading5,
+  run: run5,
+} = useRequest(dispatchRankingAnalysis);
+const {
+  data: result6,
+  loading: loading6,
+  run: run6,
+} = useRequest(dispatchStatisticsAnalysis);
+const {
+  data: result8,
+  loading: loading8,
+  run: run8,
+} = useRequest(dispatchRankingAnalysis);
+
+const chinaDataHandle = (result5, result8) => {
+  if (!result5 || !result8) {
+    return null;
+  } else {
+    let arr5 = result5?.day.map((item) => {
+      item.value = item.count;
+      return item;
+    });
+    let arr8 = result8?.day.map((item) => {
+      item.value = item.count;
+      return item;
+    });
+    return [
+      { name: '教务处', data: arr8 },
+      { name: '研究生', data: arr5 },
+    ];
+  }
+};
+
+const barDataHandle = (result) => {
+  if (!result) {
+    return { xData: [], seriesData: [] };
+  } else {
+    const { lastYear, year } = result;
+    let lastYear2 = year.map((item) => {
+      let find = lastYear.find((v) => v.month == item.month);
+      return find ? find : { ...item, count: 0 };
+    });
+    return {
+      xData: year.map((item) => `${String(item.year).slice(2)}-${item.month}`),
+      seriesData: [
+        { name: '当期', data: year.map((item) => item.count) },
+        { name: '同期', data: lastYear2.map((item) => item.count) },
+      ],
+    };
+  }
+};
+const tableDataHandle = (data) => {
+  if (!data) {
+    return [];
+  } else {
+    let totalCount = data.day.reduce((num, item) => {
+      return num + item.count;
+    }, 0);
+    return data.day.map((item) => {
+      item.rate = ((item.count * 100) / totalCount).toFixed(2) + '%';
+      return item;
+    });
+  }
+};
 onMounted(() => {
 onMounted(() => {
-  run1({ year: '2023' });
-  run2({ year: '2023', type: 'CLOUD_MARK' });
-  run2({ year: '2023', type: 'OFFICE' });
+  run1({ ...timeParams.value });
+  run2({ ...timeParams.value, type: 'CLOUD_MARK' });
+  run3({ ...timeParams.value, type: 'OFFICE' });
+  run4({ ...timeParams.value });
+  run5({ ...timeParams.value, type: 'CLOUD_MARK' });
+  run6({ ...timeParams.value });
+  run8({ ...timeParams.value, type: 'OFFICE' });
 });
 });
 const options1 = computed(() => {
 const options1 = computed(() => {
   return createRingPieOption({
   return createRingPieOption({
@@ -195,29 +290,21 @@ const options1 = computed(() => {
   });
   });
 });
 });
 
 
-const options2 = createBarOption({
-  xData: ['23-01', '23-02', '23-03', '23-04', '23-05'],
-  seriesData: [
-    { name: '当期', data: [322.1, 421.4, 100.9, 662, 200.03] },
-    { name: '同期', data: [990.84, 400, 343.5, 200.3, 552] },
-  ],
+const options2 = computed(() => {
+  return createBarOption(comResult2.value);
 });
 });
-const options3 = createBarOption({
-  xData: ['23-01', '23-02', '23-03', '23-04', '23-05'],
-  seriesData: [
-    { name: '当期', data: [322.1, 421.4, 100.9, 662, 200.03] },
-    { name: '同期', data: [990.84, 400, 343.5, 200.3, 552] },
-  ],
+const options3 = computed(() => {
+  return createBarOption(comResult3.value);
 });
 });
 
 
-const options4 = createCakePieOption({
-  data: [
-    { value: 20, name: '国宝' },
-    { value: 30, name: '治安' },
-    { value: 30, name: 'rose7' },
-    { value: 40, name: 'rose8' },
-  ],
-});
+const options4 = computed(() =>
+  createCakePieOption({
+    data: (result4.value || []).map((item) => {
+      item.value = item.count;
+      return item;
+    }),
+  })
+);
 </script>
 </script>
 
 
 <style lang="less" scoped>
 <style lang="less" scoped>