Эх сурвалжийг харах

服务单元分析补充开发

刘洋 1 жил өмнө
parent
commit
ea15e5bd73

+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
   "name": "sop-web",
   "description": "",
-  "version": "1.0.0",
+  "version": "1.0.1",
   "private": true,
   "author": "星辰大海",
   "license": "MIT",

+ 26 - 0
src/api/report.js

@@ -7,6 +7,32 @@ export const customTypeAnalysis = (params) =>
     params,
   });
 
+//客户类型分布的下钻接口
+export const customTypeDrill = (params) =>
+  request({
+    url: '/api/admin/tb/crm/analyse/custom/type/detail',
+    params,
+  });
+
+//月度派单分布下钻接口
+export const monthDispatchDrill = (params) =>
+  request({
+    url: '/api/admin/tb/crm/analyse/monthly/detail',
+    params,
+  });
+//大区在执行派单排名下钻接口
+export const regionDispatchDrill = (params) =>
+  request({
+    url: '/api/admin/tb/crm/analyse/region/detail',
+    params,
+  });
+//供应商派单分布下钻接口
+export const supplierDispatchDrill = (params) =>
+  request({
+    url: '/api/admin/tb/crm/analyse/supplier/detail',
+    params,
+  });
+
 //月度派单分布及对比接口
 export const monthDispatchAnalysis = (params) =>
   request({

+ 11 - 0
src/components/common/table-loop/index.vue

@@ -30,6 +30,7 @@
         class="slide"
         v-for="(item, index) in data || []"
         :key="index"
+        @click="rowClick(item)"
       >
         <div class="td index"
           ><div class="cell">{{ index + 1 }}</div></div
@@ -67,6 +68,7 @@ import { Navigation, Mousewheel, Autoplay } from 'swiper';
 import { Swiper, SwiperSlide } from 'vue-awesome-swiper';
 import 'swiper/css';
 import 'swiper/css/autoplay';
+const emits = defineEmits(['rowClick']);
 const props = defineProps({ data: Object, columns: Array });
 const modules = ref([Navigation, Mousewheel, Autoplay]);
 const swiperKey = ref(Date.now() + '');
@@ -82,6 +84,11 @@ onMounted(() => {
     swiperKey.value = Date.now() + '';
   });
 });
+
+const rowClick = (item) => {
+  console.log('item:', item);
+  emits('rowClick', item);
+};
 </script>
 
 <style lang="less" scoped>
@@ -100,6 +107,10 @@ onMounted(() => {
     }
   }
   .slide {
+    cursor: pointer;
+    &:hover {
+      background-color: #f7f7f7;
+    }
     .td {
       color: #262626;
       .cell {

+ 17 - 1
src/components/global/chart/index.vue

@@ -4,6 +4,8 @@
     :option="options"
     :autoresize="autoresize"
     :style="{ width, height }"
+    @click="handleClick"
+    @zr:click="handleZrClick"
   />
 </template>
 
@@ -12,6 +14,8 @@ import { ref, computed, nextTick } from 'vue';
 import VCharts from 'vue-echarts';
 import { useAppStore } from '@/store';
 
+const emits = defineEmits(['chartClick']);
+
 const props = defineProps({
   options: {
     type: Object,
@@ -40,7 +44,19 @@ const mode = computed(() => {
 });
 
 const renderChart = ref(false);
-
+const handleClick = (params) => {
+  console.log('params:', params);
+  emits('chartClick', params);
+};
+const handleZrClick = (params) => {
+  if (
+    params.topTarget &&
+    params.topTarget.parent.anid &&
+    params.target === undefined
+  ) {
+    console.log('点击x或y轴');
+  }
+};
 nextTick(() => {
   renderChart.value = true;
 });

+ 9 - 1
src/components/global/search-form/components/search-form-item.vue

@@ -91,7 +91,7 @@
       v-bind="attrs"
     />
   </template>
-  <!-- 日期范围选择 -->
+  <!-- 日期范围选择,精确到时分 -->
   <template v-if="item.type == 'daterange'">
     <t-date-range-picker
       v-model="params[item.prop]"
@@ -102,6 +102,14 @@
       v-bind="attrs"
     />
   </template>
+  <!-- 日期范围选择 -->
+  <template v-if="item.type == 'dateDayrange'">
+    <t-date-range-picker
+      v-model="params[item.prop]"
+      value-type="time-stamp"
+      v-bind="attrs"
+    />
+  </template>
 </template>
 
 <script setup name="SearchFormItem">

+ 19 - 0
src/style/global.less

@@ -721,3 +721,22 @@ body {
     }
   }
 }
+
+.drill-search-box {
+  display: flex;
+  margin-bottom: 10px;
+  .field {
+    font-size: 14px;
+    display: flex;
+    height: 40px;
+    align-items: center;
+    .label {
+      color: #595959;
+    }
+    .value {
+      color: #262626;
+      padding-left: 10px;
+      padding-right: 50px;
+    }
+  }
+}

+ 4 - 2
src/utils/chart.js

@@ -285,7 +285,7 @@ export const createRingPieOption = (
         formatter: (name) => {
           let target = data.find((item) => item.name == name);
           let float = ((target.value * 100) / total).toFixed(1);
-          return `${name} ${Number(float) + '%'}`;
+          return target.value ? `${name} ${Number(float) + '%'}` : `${name}`;
           //   return `{a|${name}}{b|${Number(float) * 100 + '%'}}`;
         },
       },
@@ -361,7 +361,9 @@ export const createCakePieOption = (
           let item = data.find((item) => item.name == name);
           let percent =
             total == 0 ? 0 : ((item?.value / total) * 100).toFixed(2);
-          return `${name} ${item?.value} (${percent + '%'})`;
+          return item?.value
+            ? `${name} ${item?.value} (${percent + '%'})`
+            : `${name}`;
         },
       },
       series: [

+ 67 - 17
src/views/report/dispatch-analysis/custom-type-drill-dialog.vue

@@ -2,36 +2,86 @@
   <my-dialog
     :visible="visible"
     :header="`客户类型`"
-    :width="1000"
+    :width="1200"
     :closeOnOverlayClick="false"
     @close="emit('update:visible', false)"
   >
-    <SearchForm :fields="fields" :params="params"> </SearchForm>
+    <div class="drill-search-box">
+      <div class="field">
+        <div class="label">客户类型:</div>
+        <div class="value">{{ CUSTOMER_TYPE[props.data?.type] }}</div>
+      </div>
+      <div class="field">
+        <div class="label">时间:</div>
+        <div class="value"
+          >{{ dateFormat(props.timeParams?.startTime, 'yyyy-MM-dd') }} -
+          {{ dateFormat(props.timeParams?.endTime, 'yyyy-MM-dd') }}</div
+        >
+      </div>
+    </div>
+    <t-table
+      ref="tableRef"
+      size="small"
+      row-key="key"
+      :columns="tableColumns"
+      :data="tableData"
+      bordered
+      :pagination="{
+        defaultCurrent: 1,
+        defaultPageSize: 10,
+        onChange,
+        showJumper: true,
+        showPageSize: false,
+        total: pagination.total,
+        current: pagination.pageNumber,
+      }"
+      v-loading="loading"
+    >
+    </t-table>
   </my-dialog>
 </template>
 <script setup name="CustomTypeDrillDialog">
 import { ref, computed, reactive, watch } from 'vue';
 import { CUSTOMER_TYPE } from '@/config/constants';
-import { dictToOptionList } from '@/utils/tool';
+import { dateFormat } from '@/utils/tool';
+import useFetchTable from '@/hooks/useFetchTable';
+import { customTypeDrill } from '@/api/report';
+const tableColumns = [
+  { colKey: 'service', title: '服务单元' },
+  { colKey: 'crmNo', title: '项目单号' },
+  { colKey: 'beginTime', title: '派单时间' },
+  { colKey: 'crmUserName', title: '客户经理' },
+  { colKey: 'customType', title: '客户类型' },
+  { colKey: 'custom', title: '客户名称' },
+  { colKey: 'name', title: '项目名称' },
+  { colKey: 'product', title: '实施产品' },
+];
 const props = defineProps({
   visible: Boolean,
   data: Object,
+  timeParams: Array,
 });
 const emit = defineEmits(['close']);
-const fields = ref([
+
+watch(
+  () => props.visible,
+  () => {
+    search();
+  }
+);
+const transParams = computed(() => {
+  return {
+    type: props.data?.type,
+    startTime: props.timeParams.startTime,
+    endTime: props.timeParams.endTime,
+  };
+});
+
+const { loading, pagination, tableData, search, onChange } = useFetchTable(
+  customTypeDrill,
   {
-    prop: 'type',
-    label: '客户类型',
-    type: 'select',
-    labelWidth: 70,
-    colSpan: 6,
-    options: dictToOptionList(CUSTOMER_TYPE),
+    params: transParams,
   },
-]);
-const params = reactive({
-  type: '',
-});
-watch(props.visible, () => {
-  params.type = '';
-});
+  false
+);
 </script>

+ 79 - 6
src/views/report/dispatch-analysis/index.vue

@@ -11,13 +11,19 @@
             <div class="card chart1-box" v-loading="loading1">
               <div class="title">客户类型</div>
               <div class="chart-wrap"
-                ><my-chart :options="options1"></my-chart
+                ><my-chart
+                  :options="options1"
+                  @chartClick="chart1Click"
+                ></my-chart
               ></div>
             </div>
             <div class="card chart2-box">
               <div class="title">研究生月度派单分配及对比</div>
               <div class="chart-wrap"
-                ><my-chart :options="options2"></my-chart
+                ><my-chart
+                  :options="options2"
+                  @chartClick="chart2Click"
+                ></my-chart
               ></div>
             </div>
           </div>
@@ -33,7 +39,10 @@
             <div class="card chart4-box">
               <div class="title">供应商派单分布</div>
               <div class="chart-wrap"
-                ><my-chart :options="options4"></my-chart
+                ><my-chart
+                  :options="options4"
+                  @chartClick="chart4Click"
+                ></my-chart
               ></div>
             </div>
             <div class="card chart5-box">
@@ -42,6 +51,7 @@
                 <table-loop
                   :data="tableDataHandle(result5)"
                   :columns="tableColumns"
+                  @rowClick="tableRowClick5"
                 ></table-loop>
               </div>
             </div>
@@ -90,6 +100,7 @@
                 <table-loop
                   :data="tableDataHandle(result8)"
                   :columns="tableColumns"
+                  @rowClick="tableRowClick6"
                 ></table-loop>
               </div>
             </div>
@@ -99,8 +110,27 @@
     </div>
     <CustomTypeDrillDialog
       v-model:visible="showCustomTypeDrill"
+      :data="customTypeDrillData"
       :footer="false"
+      :timeParams="timeParams"
     ></CustomTypeDrillDialog>
+    <MonthDispatchDrillDialog
+      v-model:visible="showMonthDispatchDrill"
+      :data="monthDispatchDrillData"
+      :footer="false"
+    ></MonthDispatchDrillDialog>
+    <RegionDispatchDrillDialog
+      v-model:visible="showRegionDispatchDrill"
+      :data="regionDispatchDrillData"
+      :footer="false"
+      :timeParams="timeParams"
+    ></RegionDispatchDrillDialog>
+    <SupplierDispatchDrillDialog
+      v-model:visible="showSupplierDispatchDrill"
+      :data="supplierDispatchDrillData"
+      :footer="false"
+      :timeParams="timeParams"
+    ></SupplierDispatchDrillDialog>
   </div>
 </template>
 
@@ -111,6 +141,9 @@ import TableLoop from '@/components/common/table-loop/index.vue';
 import { CUSTOMER_TYPE } from '@/config/constants';
 import { useRequest } from 'vue-request';
 import CustomTypeDrillDialog from './custom-type-drill-dialog.vue';
+import MonthDispatchDrillDialog from './month-dispatch-drill-dialog.vue';
+import RegionDispatchDrillDialog from './region-dispatch-drill-dialog.vue';
+import SupplierDispatchDrillDialog from './supplier-dispatch-drill-dialog.vue';
 import {
   createBarOption,
   createRingPieOption,
@@ -124,7 +157,17 @@ import {
   dispatchStatisticsAnalysis,
 } from '@/api/report';
 
-const showCustomTypeDrill = ref(true);
+const showCustomTypeDrill = ref(false);
+const customTypeDrillData = ref({ type: '' });
+
+const showMonthDispatchDrill = ref(false);
+const monthDispatchDrillData = ref({ type: '', month: '' });
+
+const showRegionDispatchDrill = ref(false);
+const regionDispatchDrillData = ref({ type: '', regionId: '', name: '' });
+
+const showSupplierDispatchDrill = ref(false);
+const supplierDispatchDrillData = ref({ supplierId: '', name: '' });
 
 const curTimeRange = ref([]);
 const timeParams = computed(() => {
@@ -204,7 +247,7 @@ const barDataHandle = (result) => {
       return find ? find : { ...item, count: 0 };
     });
     return {
-      xData: year.map((item) => `${String(item.year).slice(2)}-${item.month}`),
+      xData: year.map((item) => `${item.year}-${item.month}`),
       seriesData: [
         { name: '当期', data: year.map((item) => item.count) },
         { name: '同期', data: lastYear2.map((item) => item.count) },
@@ -229,7 +272,7 @@ const tableColumns = [
     label: '百分比',
     style: { width: '50px' },
   },
-  { prop: 'compare', label: '增减' },
+  { prop: 'compare', label: '增减', style: { width: '40px' } },
 ];
 const tableDataHandle = (data) => {
   if (!data) {
@@ -264,6 +307,36 @@ const options1 = computed(() => {
     seriesName: '客户类型',
   });
 });
+const chart1Click = (params) => {
+  customTypeDrillData.value.type =
+    params.data.name === '研究生' ? 'CLOUD_MARK' : 'OFFICE';
+  showCustomTypeDrill.value = true;
+};
+const chart2Click = (params) => {
+  monthDispatchDrillData.value.type = 'CLOUD_MARK';
+  monthDispatchDrillData.value.year = params.name.split('-')[0];
+  monthDispatchDrillData.value.month = params.name.split('-')[1];
+  showMonthDispatchDrill.value = true;
+};
+const chart4Click = (params) => {
+  regionDispatchDrillData.value.name = params.name;
+  regionDispatchDrillData.value.supplierId = params.data.id;
+  showSupplierDispatchDrill.value = true;
+};
+
+const tableRowClick5 = (item) => {
+  regionDispatchDrillData.value.type = 'CLOUD_MARK';
+  regionDispatchDrillData.value.regionId = item.id;
+  regionDispatchDrillData.value.name = item.name;
+  showRegionDispatchDrill.value = true;
+};
+
+const tableRowClick6 = (item) => {
+  regionDispatchDrillData.value.type = 'OFFICE';
+  regionDispatchDrillData.value.regionId = item.id;
+  regionDispatchDrillData.value.name = item.name;
+  showRegionDispatchDrill.value = true;
+};
 
 const options2 = computed(() => {
   return createBarOption(comResult2.value);

+ 83 - 0
src/views/report/dispatch-analysis/month-dispatch-drill-dialog.vue

@@ -0,0 +1,83 @@
+<template>
+  <my-dialog
+    :visible="visible"
+    :header="`月度派单分配及对比`"
+    :width="1200"
+    :closeOnOverlayClick="false"
+    @close="emit('update:visible', false)"
+  >
+    <div class="drill-search-box">
+      <div class="field">
+        <div class="label">客户类型:</div>
+        <div class="value">{{ CUSTOMER_TYPE[props.data?.type] }}</div>
+      </div>
+      <div class="field">
+        <div class="label">年月</div>
+        <div class="value">{{ props.data.year + '-' + props.data.month }}</div>
+      </div>
+    </div>
+    <t-table
+      ref="tableRef"
+      size="small"
+      row-key="key"
+      :columns="tableColumns"
+      :data="tableData"
+      bordered
+      :pagination="{
+        defaultCurrent: 1,
+        defaultPageSize: 10,
+        onChange,
+        showJumper: true,
+        showPageSize: false,
+        total: pagination.total,
+        current: pagination.pageNumber,
+      }"
+      v-loading="loading"
+    >
+    </t-table>
+  </my-dialog>
+</template>
+<script setup name="MonthDispatchDrillDialog">
+import { ref, computed, reactive, watch } from 'vue';
+import { CUSTOMER_TYPE } from '@/config/constants';
+import useFetchTable from '@/hooks/useFetchTable';
+import { monthDispatchDrill } from '@/api/report';
+import { dateFormat } from '@/utils/tool';
+const tableColumns = [
+  { colKey: 'service', title: '服务单元' },
+  { colKey: 'crmNo', title: '项目单号' },
+  { colKey: 'beginTime', title: '派单时间' },
+  { colKey: 'crmUserName', title: '客户经理' },
+  { colKey: 'customType', title: '客户类型' },
+  { colKey: 'custom', title: '客户名称' },
+  { colKey: 'name', title: '项目名称' },
+  { colKey: 'product', title: '实施产品' },
+];
+const props = defineProps({
+  visible: Boolean,
+  data: Object,
+});
+const emit = defineEmits(['close']);
+
+watch(
+  () => props.visible,
+  () => {
+    search();
+  }
+);
+const transParams = computed(() => {
+  return {
+    type: props.data?.type,
+    month: props.data?.month,
+    year: props.data?.year,
+  };
+});
+
+const { loading, pagination, tableData, search, onChange } = useFetchTable(
+  monthDispatchDrill,
+  {
+    params: transParams,
+  },
+  false
+);
+</script>

+ 93 - 0
src/views/report/dispatch-analysis/region-dispatch-drill-dialog.vue

@@ -0,0 +1,93 @@
+<template>
+  <my-dialog
+    :visible="visible"
+    :header="`大区在执行派单`"
+    :width="1200"
+    :closeOnOverlayClick="false"
+    @close="emit('update:visible', false)"
+  >
+    <div class="drill-search-box">
+      <div class="field">
+        <div class="label">客户类型:</div>
+        <div class="value">{{ CUSTOMER_TYPE[props.data?.type] }}</div>
+      </div>
+
+      <div class="field">
+        <div class="label">大区:</div>
+        <div class="value">{{ props.data?.name }}</div>
+      </div>
+      <div class="field">
+        <div class="label">时间:</div>
+        <div class="value"
+          >{{ dateFormat(props.timeParams?.startTime, 'yyyy-MM-dd') }} -
+          {{ dateFormat(props.timeParams?.endTime, 'yyyy-MM-dd') }}</div
+        >
+      </div>
+    </div>
+    <t-table
+      ref="tableRef"
+      size="small"
+      row-key="key"
+      :columns="tableColumns"
+      :data="tableData"
+      bordered
+      :pagination="{
+        defaultCurrent: 1,
+        defaultPageSize: 10,
+        onChange,
+        showJumper: true,
+        showPageSize: false,
+        total: pagination.total,
+        current: pagination.pageNumber,
+      }"
+      v-loading="loading"
+    >
+    </t-table>
+  </my-dialog>
+</template>
+<script setup name="RegionDispatchDrillDialog">
+import { ref, computed, reactive, watch } from 'vue';
+import { CUSTOMER_TYPE } from '@/config/constants';
+import { dateFormat } from '@/utils/tool';
+import useFetchTable from '@/hooks/useFetchTable';
+import { regionDispatchDrill } from '@/api/report';
+const tableColumns = [
+  { colKey: 'service', title: '服务单元' },
+  { colKey: 'crmNo', title: '项目单号' },
+  { colKey: 'beginTime', title: '派单时间' },
+  { colKey: 'crmUserName', title: '客户经理' },
+  { colKey: 'customType', title: '客户类型' },
+  { colKey: 'custom', title: '客户名称' },
+  { colKey: 'name', title: '项目名称' },
+  { colKey: 'product', title: '实施产品' },
+];
+const props = defineProps({
+  visible: Boolean,
+  data: Object,
+  timeParams: Array,
+});
+const emit = defineEmits(['close']);
+
+watch(
+  () => props.visible,
+  () => {
+    search();
+  }
+);
+const transParams = computed(() => {
+  return {
+    type: props.data?.type,
+    regionId: props.data?.regionId,
+    startTime: props.timeParams.startTime,
+    endTime: props.timeParams.endTime,
+  };
+});
+
+const { loading, pagination, tableData, search, onChange } = useFetchTable(
+  regionDispatchDrill,
+  {
+    params: transParams,
+  },
+  false
+);
+</script>

+ 88 - 0
src/views/report/dispatch-analysis/supplier-dispatch-drill-dialog.vue

@@ -0,0 +1,88 @@
+<template>
+  <my-dialog
+    :visible="visible"
+    :header="`供应商派单分布`"
+    :width="1200"
+    :closeOnOverlayClick="false"
+    @close="emit('update:visible', false)"
+  >
+    <div class="drill-search-box">
+      <div class="field">
+        <div class="label">供应商:</div>
+        <div class="value">{{ props.data?.name }}</div>
+      </div>
+      <div class="field">
+        <div class="label">时间:</div>
+        <div class="value"
+          >{{ dateFormat(props.timeParams?.startTime, 'yyyy-MM-dd') }} -
+          {{ dateFormat(props.timeParams?.endTime, 'yyyy-MM-dd') }}</div
+        >
+      </div>
+    </div>
+    <t-table
+      ref="tableRef"
+      size="small"
+      row-key="key"
+      :columns="tableColumns"
+      :data="tableData"
+      bordered
+      :pagination="{
+        defaultCurrent: 1,
+        defaultPageSize: 10,
+        onChange,
+        showJumper: true,
+        showPageSize: false,
+        total: pagination.total,
+        current: pagination.pageNumber,
+      }"
+      v-loading="loading"
+    >
+    </t-table>
+  </my-dialog>
+</template>
+<script setup name="SupplierDrillDialog">
+import { ref, computed, reactive, watch } from 'vue';
+import { CUSTOMER_TYPE } from '@/config/constants';
+import { dateFormat } from '@/utils/tool';
+import useFetchTable from '@/hooks/useFetchTable';
+import { supplierDispatchDrill } from '@/api/report';
+const tableColumns = [
+  { colKey: 'service', title: '服务单元' },
+  { colKey: 'crmNo', title: '项目单号' },
+  { colKey: 'beginTime', title: '派单时间' },
+  { colKey: 'crmUserName', title: '客户经理' },
+  { colKey: 'customType', title: '客户类型' },
+  { colKey: 'custom', title: '客户名称' },
+  { colKey: 'name', title: '项目名称' },
+  { colKey: 'product', title: '实施产品' },
+];
+const props = defineProps({
+  visible: Boolean,
+  data: Object,
+  timeParams: Array,
+});
+const emit = defineEmits(['close']);
+
+watch(
+  () => props.visible,
+  () => {
+    search();
+  }
+);
+const transParams = computed(() => {
+  return {
+    type: props.data?.type,
+    supplierId: props.data?.supplierId,
+    startTime: props.timeParams.startTime,
+    endTime: props.timeParams.endTime,
+  };
+});
+
+const { loading, pagination, tableData, search, onChange } = useFetchTable(
+  supplierDispatchDrill,
+  {
+    params: transParams,
+  },
+  false
+);
+</script>

+ 156 - 81
src/views/report/service-analysis/index.vue

@@ -59,6 +59,7 @@
                 :options="supplierOptions"
                 size="small"
                 style="width: 150px"
+                placeholder="请选择人力供应商"
               >
               </t-select>
             </div>
@@ -70,14 +71,18 @@
                 <div class="num-show flex items-center justify-around">
                   <div class="desc">
                     <div class="label">实施工程师(人)</div>
-                    <div class="value">172</div>
+                    <div class="value">{{ ssgcsNum }}</div>
                   </div>
                   <div class="desc">
                     <div class="label">区域协调人(人)</div>
-                    <div class="value">39</div>
+                    <div class="value">{{ qyxtrNum }}</div>
                   </div>
                 </div>
-                <div class="desc-text">覆盖4个大区:北京、天津、武汉、广州</div>
+                <div class="desc-text"
+                  >覆盖{{ regionOptions?.length }}个大区:{{
+                    regionOptions.map((item) => item.label).join('、')
+                  }}</div
+                >
               </div>
             </div>
           </div>
@@ -87,6 +92,14 @@
           >
             <div class="title">
               <span class="label">项目角色待调配额盘点</span>
+              <t-select
+                v-model="regionId"
+                :options="regionOptions"
+                size="small"
+                style="width: 150px"
+                placeholder="请选择大区"
+              >
+              </t-select>
             </div>
             <div class="box4">
               <div class="charts-box">
@@ -110,8 +123,12 @@
                 </div>
               </div>
               <div class="desc-text">
-                <p>大区内同业务类型待划拨派单数量:3个</p>
-                <p>当前大区覆盖城市:2个</p>
+                <p
+                  >大区内同业务类型待划拨派单数量:{{
+                    result4?.projectWait
+                  }}个</p
+                >
+                <p>当前大区覆盖城市:{{ result4?.regionCities }}个</p>
               </div>
             </div>
           </div>
@@ -121,9 +138,14 @@
             </div>
             <div class="bar-box flex items-center">
               <div class="process-box">
-                <div class="process" :style="{ width: '20%' }"></div>
+                <div
+                  class="process"
+                  :style="{ width: (result5 || 0) * 100 + '%' }"
+                ></div>
               </div>
-              <span class="process-text m-l-10px">20%</span>
+              <span class="process-text m-l-10px">{{
+                (result5 || 0) * 100 + '%'
+              }}</span>
             </div>
           </div>
           <div class="card m-t-15px" style="height: 80px">
@@ -132,9 +154,14 @@
             </div>
             <div class="bar-box flex items-center">
               <div class="process-box">
-                <div class="process" :style="{ width: '90%' }"></div>
+                <div
+                  class="process"
+                  :style="{ width: (result6 || 0) * 100 + '%' }"
+                ></div>
               </div>
-              <span class="process-text m-l-10px">90%</span>
+              <span class="process-text m-l-10px">{{
+                (result5 || 0) * 100 + '%'
+              }}</span>
             </div>
           </div>
         </div>
@@ -182,6 +209,8 @@ import {
   personNumAnalysis,
   serviceServiceList,
 } from '@/api/report';
+const ssgcsNum = ref('');
+const qyxtrNum = ref('');
 const curTimeRange = ref([]);
 const serviceOptions = ref([]);
 const timeParams = computed(() => {
@@ -206,7 +235,7 @@ const {
 const {
   data: result3,
   loading: loading3,
-  run: run3,
+  runAsync: run3,
 } = useRequest(supplierRoleAnalysis); //人力供应商项目角色人员分布
 
 const { data: regionList, runAsync: runGetRegionList } =
@@ -215,7 +244,7 @@ const { data: regionList, runAsync: runGetRegionList } =
 const {
   data: result4,
   loading: loading4,
-  runAsync: run4,
+  run: run4,
 } = useRequest(projectRoleAnalysis); //项目角色待调配配额盘点
 
 const {
@@ -253,6 +282,9 @@ watch(serviceId, (serviceUnitId) => {
   run1({ serviceUnitId });
   run2({ serviceUnitId }).then((res) => {
     if (!supplierId.value) {
+      if (res.supplierDistribution?.length) {
+        supplierId.value = res.supplierDistribution[0].id;
+      }
       //赋值,默认选择第一个供应商
       //todo ...
     }
@@ -265,17 +297,47 @@ watch(serviceId, (serviceUnitId) => {
 
 const supplierId = ref('');
 const supplierOptions = computed(() => {
+  return (result2.value?.supplierDistribution || []).map((item) => {
+    item.label = item.name;
+    item.value = item.id;
+    return item;
+  });
   //与result2相关,转换数据即可
   return [];
 });
 const regionId = ref('');
 const regionOptions = computed(() => {
-  //与result4相关,转换数据即可
-  return [];
+  return (regionList.value || []).map((item) => {
+    item.label = item.region_name;
+    item.value = item.region_id;
+    return item;
+  });
 });
-watch('supplierId', (supplierId) => {
-  run3({ serviceUnitId: serviceId.value, supplierId });
-  runGetRegionList({ serviceUnitId: serviceId.value, supplierId });
+watch(supplierId, (supplierId) => {
+  run3({ serviceUnitId: serviceId.value, supplierId }).then((res) => {
+    let obj1 = res.find(
+      (item) => item.NAME === '实施工程师' || item.name === '实施工程师'
+    );
+    let obj2 = res.find(
+      (item) => item.NAME === '区域协调人' || item.name === '区域协调人'
+    );
+    obj1 && (ssgcsNum.value = obj1.count);
+    obj2 && (qyxtrNum.value = obj2.count);
+  });
+  runGetRegionList({ serviceUnitId: serviceId.value, supplierId }).then(
+    (res) => {
+      if (res && res.length) {
+        regionId.value = res[0].region_id;
+      }
+    }
+  );
+});
+watch(regionId, (regionId) => {
+  run4({
+    serviceUnitId: serviceId.value,
+    supplierId: supplierId.value,
+    regionId,
+  });
 });
 
 const options1 = computed(() => {
@@ -285,77 +347,89 @@ const options1 = computed(() => {
     radius: '80%',
   });
 });
-const options2 = createRingPieOption(
-  {
-    data: [
-      { name: '阳光雨露', value: 26 },
-      { name: '软通智服', value: 12 },
-      { name: 'AAAA', value: 13 },
-      { name: 'BBBB', value: 12 },
-      { name: 'CCCC', value: 12 },
-      { name: 'DDDD', value: 15 },
-      { name: 'EEEE', value: 42 },
-      { name: 'FFFF', value: 102 },
-      { name: 'GGGG', value: 12 },
-      { name: 'HHHH', value: 72 },
-    ],
-    title: '派单数',
-    center: ['50%', '25%'],
-    seriesName: '数量',
-    radius: [40, 60],
-  },
-  {
-    legend: {
-      // type: 'scroll',
-      orient: 'horizontal',
-      top: null,
-      right: null,
-      bottom: '0%',
-      left: 'center',
+
+const options2 = computed(() => {
+  const supplierDistribution = result2?.supplierDistribution || [];
+  return createRingPieOption(
+    {
+      data: supplierDistribution.map((item) => {
+        item.value = item.count;
+        return item;
+      }),
+      title: '派单数',
+      center: ['50%', '25%'],
+      seriesName: '数量',
+      radius: [40, 60],
     },
-  }
-);
+    {
+      legend: {
+        // type: 'scroll',
+        orient: 'horizontal',
+        top: null,
+        right: null,
+        bottom: '0%',
+        left: 'center',
+      },
+    }
+  );
+});
 
-const options3 = createCakePieOption(
-  {
-    data: [
-      { name: '实施工程师', value: 172 },
-      { name: '区域协调人', value: 39 },
-    ],
-    radius: [0, 50],
-    center: ['50%', '50%'],
-    seriesName: '角色分布',
-  },
-  {
-    legend: {
-      show: false,
+const options3 = computed(() => {
+  let data = (result3.value || []).map((item) => {
+    item.value = item.count;
+    item.name = item.NAME || item.name;
+    return item;
+  });
+  return createCakePieOption(
+    {
+      data: data,
+      radius: [0, 50],
+      center: ['50%', '50%'],
+      seriesName: '角色分布',
     },
-    // legend: {
-    //   orient: 'horizontal',
-    //   top: '',
-    //   right: '',
-    //   bottom: '1%',
-    //   left: 'center',
-    // },
-  }
-);
+    {
+      legend: {
+        show: false,
+      },
+    }
+  );
+});
 
-const options41 = createWaterBallOption({
-  data: 65 / 100,
-  title: '剩130配额',
-  radius: '80%',
+const options41 = computed(() => {
+  let projectRoleQuota = result4.value?.projectRoleQuota || {};
+  return createWaterBallOption({
+    data: projectRoleQuota.effectDistributed / projectRoleQuota.effectQuota,
+    title: `剩${
+      projectRoleQuota.effectQuota - projectRoleQuota.effectDistributed
+    }配额`,
+    radius: '80%',
+  });
 });
-const options42 = createWaterBallOption({
-  data: 35 / 100,
-  title: '剩34配额',
-  radius: '80%',
-  color: '35, 195, 67',
+const options42 = computed(() => {
+  let projectRoleQuota = result4.value?.projectRoleQuota || {};
+  return createWaterBallOption({
+    data:
+      projectRoleQuota.coordinatorDistributed /
+      projectRoleQuota.coordinatorQuota,
+    title: `剩${
+      projectRoleQuota.coordinatorQuota -
+      projectRoleQuota.coordinatorDistributed
+    }配额`,
+    radius: '80%',
+    color: '35, 195, 67',
+  });
 });
-const options43 = createWaterBallOption({
-  data: 55 / 100,
-  title: '剩14配额',
-  radius: '80%',
-  color: '255, 154, 46',
+const options43 = computed(() => {
+  let projectRoleQuota = result4.value?.projectRoleQuota || {};
+  return createWaterBallOption({
+    data:
+      projectRoleQuota.assistantDistributed / projectRoleQuota.assistantQuota,
+    title: `剩${
+      projectRoleQuota.assistantQuota - projectRoleQuota.assistantDistributed
+    }配额`,
+    radius: '80%',
+    color: '255, 154, 46',
+  });
 });
 const options7 = computed(() => {
   return createCakePieOption(
@@ -403,6 +477,7 @@ const options8 = computed(() => {
       data: data,
     });
   }
+  console.log(xData, sData);
   return createStackingBarOption(
     {
       xData: xData,