浏览代码

二期小收尾一下

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

+ 21 - 2
src/api/report.js

@@ -1,5 +1,6 @@
 import { request } from '@/utils/request.js';
 
+// -----------------------------------派单分析-----------------------------------------
 //客户类型分布
 export const customTypeAnalysis = (params) =>
   request({
@@ -59,8 +60,15 @@ export const dispatchStatisticsAnalysis = (params) =>
     url: '/api/admin/tb/crm/analyse/project',
     params,
   });
+//项目派单完成率下钻
+export const dispatchStatisticsDrill = (params) =>
+  request({
+    url: '/api/admin/tb/crm/analyse/project/detail',
+    params,
+  });
 
-//服务单元分析-按时间查询服务单元列表
+// -----------------------------------服务单元分析-----------------------------------------
+//按时间查询服务单元列表
 export const serviceServiceList = (params) =>
   request({
     url: '/api/service/analyse/list',
@@ -80,6 +88,12 @@ export const supplierOverviewAnalysis = (params) =>
     url: '/api/service/analyse/supplier',
     params,
   });
+//人力供应商项目数量分布及占比 数据下钻
+export const supplierOverviewDrill = (params) =>
+  request({
+    url: '/api/service/analyse/supplier/detail',
+    params,
+  });
 //人力供应商项目角色人员分布
 export const supplierRoleAnalysis = (params) =>
   request({
@@ -173,7 +187,12 @@ export const projectProcessAnalysis = (params) =>
     url: '/api/sop/schedule/projectProgress',
     params,
   });
-
+//点击阶段分布的下钻接口
+export const sopDetailDrill = (params) =>
+  request({
+    url: '/api/sop/schedule/detail',
+    params,
+  });
 // -----------------------------------设备保障监控-----------------------------------------
 export const deviceStatusAnalysis = (params) =>
   request({

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

@@ -1,11 +1,6 @@
 <template>
   <div class="table-loop" ref="tableLoop">
     <div class="thead">
-      <!-- <div class="td col1">排名</div>
-      <div class="td col2">城市</div>
-      <div class="td col3">总数</div>
-      <div class="td col4">百分比</div>
-      <div class="td col5">增减</div> -->
       <div class="td index">排名</div>
       <div
         class="td"
@@ -35,15 +30,6 @@
         <div class="td index"
           ><div class="cell">{{ index + 1 }}</div></div
         >
-        <!-- <div class="td col2">{{ item.name }}</div>
-        <div class="td col3"> {{ item.count }} </div>
-        <div class="td col4">
-          <div class="process-box">
-            <div class="process" :style="{ width: item.rate }"></div>
-          </div>
-        </div>
-        <div class="td col5"></div> -->
-
         <div
           class="td"
           v-for="(v, i) in columns"
@@ -94,7 +80,6 @@ const rowClick = (item) => {
 <style lang="less" scoped>
 .table-loop {
   height: 100%;
-  padding-top: 10px;
   overflow: auto;
   .thead {
     height: 36px;

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

@@ -7,13 +7,31 @@
     @click="handleClick"
     @zr:click="handleZrClick"
   />
+  <t-dialog
+    :visible="visible"
+    header=""
+    :width="1200"
+    attach="body"
+    :closeOnOverlayClick="false"
+    :footer="false"
+    @close="visible = false"
+  >
+    <div style="height: calc(100vh - 150px)">
+      <v-charts
+        v-if="renderChart"
+        :option="options"
+        :autoresize="autoresize"
+        :style="{ width, height }"
+      />
+    </div>
+  </t-dialog>
 </template>
 
 <script setup>
 import { ref, computed, nextTick } from 'vue';
 import VCharts from 'vue-echarts';
 import { useAppStore } from '@/store';
-
+const visible = ref(false);
 const emits = defineEmits(['chartClick']);
 
 const props = defineProps({
@@ -60,6 +78,13 @@ const handleZrClick = (params) => {
 nextTick(() => {
   renderChart.value = true;
 });
+
+const maximize = () => {
+  visible.value = true;
+};
+defineExpose({
+  maximize,
+});
 </script>
 
 <style scoped lang="less"></style>

+ 13 - 12
src/utils/chart.js

@@ -81,7 +81,8 @@ export const createStackingBarOption = ({ xData, seriesData }, extend = {}) => {
         bottom: '1%',
         containLabel: true,
         show: true,
-        borderColor: appStore.isFullscreen ? '#0A3367' : '#e5e5e5',
+        // borderColor: appStore.isFullscreen ? '#0A3367' : '#e5e5e5',
+        borderColor: 'transparent',
       },
       xAxis: {
         type: 'value',
@@ -484,22 +485,22 @@ export const createPercentBarOption = (
   const oData = cloneDeep(originData);
   let newData = [];
   if (originData.length) {
-    newData = originData.map((subArr, index) => {
+    newData = originData.map(() => {
       return [];
     });
-    for (let i = 0; i < originData[0].length; i++) {
-      let total = 0;
-      for (let j = 0; j < originData.length; j++) {
-        total += originData[j][i];
-      }
-      for (let x = 0; x < originData.length; x++) {
-        if (i != originData[0].length - 1) {
-          newData[x].push(Math.round((originData[x][i] / total) * 100));
+    for (let i = 0; i < originData.length; i++) {
+      let row = originData[i];
+      let rowTotal = row.reduce((num, item) => {
+        return num + item;
+      }, 0);
+      for (let j = 0; j < row.length; j++) {
+        if (j != row.length - 1) {
+          newData[i].push(Math.round((row[j] / rowTotal) * 100));
         } else {
-          let prevTotal = newData[x].reduce((num, v) => {
+          let prevTotal = newData[i].reduce((num, v) => {
             return v + num;
           }, 0);
-          newData[x].push(100 - prevTotal);
+          newData[i].push(100 - prevTotal);
         }
       }
     }

+ 87 - 0
src/views/report/dispatch-analysis/dispatch-statistics-drill-dialog.vue

@@ -0,0 +1,87 @@
+<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?.serviceName }}</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="DispatchStatisticsDrillDialog">
+import { ref, computed, reactive, watch } from 'vue';
+import { CUSTOMER_TYPE } from '@/config/constants';
+import { dateFormat } from '@/utils/tool';
+import useFetchTable from '@/hooks/useFetchTable';
+import { dispatchStatisticsDrill } 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 {
+    serviceId: props.data?.serviceId,
+    startTime: props.timeParams.startTime,
+    endTime: props.timeParams.endTime,
+  };
+});
+
+const { loading, pagination, tableData, search, onChange } = useFetchTable(
+  dispatchStatisticsDrill,
+  {
+    params: transParams,
+  },
+  false
+);
+</script>

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

@@ -18,11 +18,18 @@
               ></div>
             </div>
             <div class="card chart2-box">
-              <div class="title">研究生月度派单分配及对比</div>
+              <div class="title"
+                ><span>研究生月度派单分配及对比</span>
+                <FullscreenIcon
+                  class="cursor-pointer"
+                  @click="chart2?.maximize"
+                  color="#595959"
+              /></div>
               <div class="chart-wrap"
                 ><my-chart
                   :options="options2"
                   @chartClick="chart2Click"
+                  ref="chart2"
                 ></my-chart
               ></div>
             </div>
@@ -60,9 +67,15 @@
         <div class="row2 flex">
           <div class="col1">
             <div class="card chart6-box">
-              <div class="title">教务处月度派单分布及对比备份</div>
+              <div class="title"
+                ><span>教务处月度派单分布及对比备份</span
+                ><FullscreenIcon
+                  class="cursor-pointer"
+                  @click="chart3?.maximize"
+                  color="#595959"
+              /></div>
               <div class="chart-wrap">
-                <my-chart :options="options3"></my-chart>
+                <my-chart :options="options3" ref="chart3"></my-chart>
               </div>
             </div>
           </div>
@@ -74,6 +87,7 @@
                   class="service-item"
                   v-for="item in result6"
                   :key="item.id"
+                  @click="serviceClick(item)"
                 >
                   <div class="head flex justify-between items-center">
                     <div>{{ item.name }}</div>
@@ -131,6 +145,12 @@
       :footer="false"
       :timeParams="timeParams"
     ></SupplierDispatchDrillDialog>
+    <DispatchStatisticsDrill
+      v-model:visible="showDispatchStatisticsDrill"
+      :data="dispatchStatisticsDrillData"
+      :footer="false"
+      :timeParams="timeParams"
+    ></DispatchStatisticsDrill>
   </div>
 </template>
 
@@ -144,6 +164,9 @@ 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 DispatchStatisticsDrill from './dispatch-statistics-drill-dialog.vue';
+import { FullscreenIcon } from 'tdesign-icons-vue-next';
+
 import {
   createBarOption,
   createRingPieOption,
@@ -156,7 +179,8 @@ import {
   supplierDispatchAnalysis,
   dispatchStatisticsAnalysis,
 } from '@/api/report';
-
+const chart2 = ref();
+const chart3 = ref();
 const showCustomTypeDrill = ref(false);
 const customTypeDrillData = ref({ type: '' });
 
@@ -169,6 +193,9 @@ const regionDispatchDrillData = ref({ type: '', regionId: '', name: '' });
 const showSupplierDispatchDrill = ref(false);
 const supplierDispatchDrillData = ref({ supplierId: '', name: '' });
 
+const showDispatchStatisticsDrill = ref(false);
+const dispatchStatisticsDrillData = ref({ serviceId: '', serviceName: '' });
+
 const curTimeRange = ref([]);
 const timeParams = computed(() => {
   return {
@@ -260,12 +287,12 @@ const tableColumns = [
   {
     prop: 'name',
     label: '城市',
-    style: { width: 'calc((100% - 84px) / 2)' },
+    style: { width: 'calc((100% - 90px) / 2)' },
   },
   {
     prop: 'count',
     label: '总数',
-    style: { width: 'calc((100% - 84px) / 4)' },
+    style: { width: 'calc((100% - 90px) / 4)' },
   },
   {
     prop: 'rate',
@@ -338,6 +365,12 @@ const tableRowClick6 = (item) => {
   showRegionDispatchDrill.value = true;
 };
 
+const serviceClick = (item) => {
+  dispatchStatisticsDrillData.value.serviceId = item.id;
+  dispatchStatisticsDrillData.value.serviceName = item.name;
+  showDispatchStatisticsDrill.value = true;
+};
+
 const options2 = computed(() => {
   return createBarOption(comResult2.value);
 });
@@ -437,6 +470,7 @@ const options4 = computed(() =>
       }
       .chart-wrap {
         height: calc(100% - 36px);
+        padding: 2px;
         &.service-box {
           display: flex;
           flex-wrap: wrap;
@@ -450,6 +484,10 @@ const options4 = computed(() =>
           padding: 6px 8px;
           background-color: #f7f7f7;
           border-radius: 2px;
+          cursor: pointer;
+          &:hover {
+            box-shadow: 0 0 0 2px #4080ff;
+          }
 
           .head {
             font-size: 12px;

+ 65 - 2
src/views/report/project-analysis/index.vue

@@ -18,9 +18,18 @@
           <div class="card">
             <div class="title">
               <span class="label">大区项目阶段分布及对比</span>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart1?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
-              <my-chart :options="options1"></my-chart>
+              <my-chart
+                :options="options1"
+                @chartClick="chart1Click"
+                ref="chart1"
+              ></my-chart>
             </div>
           </div>
           <div class="card">
@@ -34,9 +43,18 @@
           <div class="card">
             <div class="title">
               <span class="label">供应商项目阶段分布及对比</span>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart3?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
-              <my-chart :options="options3"></my-chart>
+              <my-chart
+                :options="options3"
+                @chartClick="chart3Click"
+                ref="chart3"
+              ></my-chart>
             </div>
           </div>
         </div>
@@ -52,6 +70,11 @@
         </div>
       </div>
     </div>
+    <SopDetailDrillDialog
+      v-model:visible="showSopDetailDrill"
+      :data="sopDetailDrillData"
+      :footer="false"
+    ></SopDetailDrillDialog>
   </div>
 </template>
 
@@ -68,6 +91,19 @@ import {
   projectStageAnalysis,
   projectProcessAnalysis,
 } from '@/api/report';
+import SopDetailDrillDialog from './sop-detail-drill-dialog.vue';
+import { FullscreenIcon } from 'tdesign-icons-vue-next';
+const chart1 = ref();
+const chart3 = ref();
+const showSopDetailDrill = ref(false);
+const sopDetailDrillData = ref({
+  serviceId: '',
+  serviceName: '',
+  regionId: '',
+  supplierId: '',
+  regionName: '',
+  supplierName: '',
+});
 const curTimeRange = ref([]);
 const timeParams = computed(() => {
   return {
@@ -137,6 +173,7 @@ watch(serviceId, (serviceId) => {
 const options1 = computed(() => {
   let res = result1.value || {};
   let xData = Object.keys(res);
+
   let originData = Object.values(res).map((item) => {
     return sortKeys.map((v) => item[v] || 0);
   });
@@ -146,6 +183,32 @@ const options1 = computed(() => {
     legendData: legendData,
   });
 });
+const chart1Click = (params) => {
+  let obj = result1.value?.[params.name];
+  sopDetailDrillData.value = {
+    serviceId: serviceId.value,
+    serviceName: serviceOptions.value.find((item) => item.id == serviceId.value)
+      ?.name,
+    regionId: obj.region_id,
+    supplierId: '',
+    regionName: params.name,
+    supplierName: '',
+  };
+  showSopDetailDrill.value = true;
+};
+const chart3Click = (params) => {
+  let obj = result3.value?.[params.name];
+  sopDetailDrillData.value = {
+    serviceId: serviceId.value,
+    serviceName: serviceOptions.value.find((item) => item.id == serviceId.value)
+      ?.name,
+    regionId: '',
+    supplierId: obj.region_id,
+    regionName: '',
+    supplierName: params.name,
+  };
+  showSopDetailDrill.value = true;
+};
 const options2 = computed(() => {
   let obj = result2.value?.POPULATION || {};
   let data = sortKeys.map((prop, index) => {

+ 88 - 0
src/views/report/project-analysis/sop-detail-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?.serviceName }}</div>
+      </div>
+      <div class="field">
+        <div class="label">{{
+          props.data?.regionId ? '大区:' : '供应商:'
+        }}</div>
+        <div class="value">{{
+          props.data?.regionName || props.data?.supplierName
+        }}</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="SopDetailDrillDialog">
+import { ref, computed, reactive, watch } from 'vue';
+import { CUSTOMER_TYPE } from '@/config/constants';
+import { dateFormat } from '@/utils/tool';
+import useFetchTable from '@/hooks/useFetchTable';
+import { sopDetailDrill } from '@/api/report';
+const tableColumns = [
+  { colKey: 'serviceName', title: '服务单元' },
+  { colKey: 'crmNo', title: '项目单号' },
+  { colKey: 'beginTime', title: '派单时间' },
+  { colKey: 'customManagerName', title: '客户经理' },
+  { colKey: 'customManagerTypeStr', title: '客户类型' },
+  { colKey: 'customName', title: '客户名称' },
+  { colKey: 'crmName', title: '项目名称' },
+  { colKey: 'productName', title: '实施产品' },
+];
+const props = defineProps({
+  visible: Boolean,
+  data: Object,
+});
+const emit = defineEmits(['close']);
+
+watch(
+  () => props.visible,
+  () => {
+    search();
+  }
+);
+const transParams = computed(() => {
+  return {
+    serviceId: props.data?.serviceId,
+    supplierId: props.data?.supplierId,
+    regionId: props.data?.regionId,
+    supplierId: props.data?.supplierId,
+  };
+});
+
+const { loading, pagination, tableData, search, onChange } = useFetchTable(
+  sopDetailDrill,
+  {
+    params: transParams,
+  },
+  false
+);
+</script>

+ 54 - 13
src/views/report/quality-analysis/index.vue

@@ -54,45 +54,81 @@
           <div class="card">
             <div class="title">
               <span class="label">影响度供应商分布及对比</span>
-              <t-button variant="outline">
+              <!-- <t-button variant="outline">
                 <template #icon><FullscreenIcon /></template>
-              </t-button>
+              </t-button> -->
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart11?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
-              <my-chart v-if="result11" :options="options11"></my-chart>
+              <my-chart
+                v-if="result11"
+                :options="options11"
+                ref="chart11"
+              ></my-chart>
             </div>
           </div>
           <div class="card">
             <div class="title">
               <span class="label">执行协调类归因供应商分布及对比</span>
-              <t-button variant="outline">
+              <!-- <t-button variant="outline">
                 <template #icon><FullscreenIcon /></template>
-              </t-button>
+              </t-button> -->
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart12?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
-              <my-chart v-if="result12" :options="options12"></my-chart>
+              <my-chart
+                v-if="result12"
+                :options="options12"
+                ref="chart12"
+              ></my-chart>
             </div>
           </div>
           <div class="card">
             <div class="title">
               <span class="label">影响度大区分布及对比TOP5</span>
-              <t-button variant="outline">
+              <!-- <t-button variant="outline">
                 <template #icon><FullscreenIcon /></template>
-              </t-button>
+              </t-button> -->
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart21?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
-              <my-chart v-if="result21" :options="options21"></my-chart>
+              <my-chart
+                v-if="result21"
+                :options="options21"
+                ref="chart21"
+              ></my-chart>
             </div>
           </div>
           <div class="card">
             <div class="title">
               <span class="label">执行协调类归因大区分布及对比TOP5</span>
-              <t-button variant="outline">
+              <!-- <t-button variant="outline">
                 <template #icon><FullscreenIcon /></template>
-              </t-button>
+              </t-button> -->
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart22?.maximize"
+                color="#595959"
+              />
             </div>
             <div class="chart-wrap">
-              <my-chart v-if="result22" :options="options22"></my-chart>
+              <my-chart
+                v-if="result22"
+                :options="options22"
+                ref="chart22"
+              ></my-chart>
             </div>
           </div>
         </div>
@@ -116,6 +152,10 @@ import {
   qualityAnalysisInfluence,
 } from '@/api/report';
 import { FullscreenIcon } from 'tdesign-icons-vue-next';
+const chart11 = ref();
+const chart12 = ref();
+const chart21 = ref();
+const chart22 = ref();
 const curTimeRange = ref([]);
 const timeParams = computed(() => {
   return {
@@ -252,9 +292,10 @@ const overallRadarOptions = computed(() => {
 const barExtendOption = {
   grid: {
     top: 50,
+    left: 15,
   },
   yAxis: {
-    name: '单位:件',
+    name: '件',
     nameTextStyle: {
       color: '#595959',
     },

+ 41 - 5
src/views/report/service-analysis/index.vue

@@ -46,7 +46,10 @@
               <span class="label">人力供应商项目数量分布及占比</span>
             </div>
             <div style="height: calc(100% - 36px)">
-              <my-chart :options="options2"></my-chart>
+              <my-chart
+                :options="options2"
+                @chartClick="chart2Click"
+              ></my-chart>
             </div>
           </div>
         </div>
@@ -177,14 +180,24 @@
           <div class="card">
             <div class="title">
               <span class="label">大区在服务人数分布及对比</span>
+              <FullscreenIcon
+                class="cursor-pointer"
+                @click="chart8?.maximize"
+                color="#595959"
+              />
             </div>
             <div style="height: calc(100% - 36px)">
-              <my-chart :options="options8"></my-chart>
+              <my-chart :options="options8" ref="chart8"></my-chart>
             </div>
           </div>
         </div>
       </div>
     </div>
+    <SupplierDetailDrillDialog
+      v-model:visible="showSupplierDetailDrill"
+      :data="supplierDetailDrillData"
+      :footer="false"
+    ></SupplierDetailDrillDialog>
   </div>
 </template>
 
@@ -209,6 +222,29 @@ import {
   personNumAnalysis,
   serviceServiceList,
 } from '@/api/report';
+import SupplierDetailDrillDialog from './supplier-detail-drill-dialog.vue';
+import { FullscreenIcon } from 'tdesign-icons-vue-next';
+const chart8 = ref();
+
+const showSupplierDetailDrill = ref(false);
+const supplierDetailDrillData = ref({
+  serviceUnitId: '',
+  serviceName: '',
+  supplierId: '',
+  supplierName: '',
+});
+
+const chart2Click = (params) => {
+  supplierDetailDrillData.value.supplierId = params.data.id;
+  supplierDetailDrillData.value.supplierName = params.data.name;
+  supplierDetailDrillData.value.serviceUnitId = serviceId.value;
+  supplierDetailDrillData.value.serviceName = serviceOptions.value.find(
+    (item) => item.id == serviceId.value
+  )?.name;
+  setTimeout(() => {
+    showSupplierDetailDrill.value = true;
+  }, 10);
+};
 const ssgcsNum = ref('');
 const qyxtrNum = ref('');
 const curTimeRange = ref([]);
@@ -357,7 +393,7 @@ const options2 = computed(() => {
         return item;
       }),
       title: '派单数',
-      center: ['50%', '25%'],
+      center: ['50%', '30%'],
       seriesName: '数量',
       radius: [40, 60],
     },
@@ -461,7 +497,7 @@ const options8 = computed(() => {
     new Set((result8.value || []).map((item) => item.region_name))
   );
   let names = Array.from(
-    new Set((result8.value || []).map((item) => item.name))
+    new Set((result8.value || []).map((item) => item.name || 'null'))
   );
   let sData = [];
   for (let i = 0; i < names.length; i++) {
@@ -473,7 +509,7 @@ const options8 = computed(() => {
       data.push(find?.count || 0);
     }
     sData.push({
-      name: names[i],
+      name: names[i] || 'null',
       data: data,
     });
   }

+ 82 - 0
src/views/report/service-analysis/supplier-detail-drill-dialog.vue

@@ -0,0 +1,82 @@
+<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?.serviceName }}</div>
+      </div>
+      <div class="field">
+        <div class="label">供应商:</div>
+        <div class="value">{{ props.data?.supplierName }}</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="SupplierDetailDrillDialog">
+import { ref, computed, reactive, watch } from 'vue';
+import { CUSTOMER_TYPE } from '@/config/constants';
+import { dateFormat } from '@/utils/tool';
+import useFetchTable from '@/hooks/useFetchTable';
+import { supplierOverviewDrill } 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,
+});
+const emit = defineEmits(['close', 'update:visible']);
+
+watch(
+  () => props.visible,
+  () => {
+    search();
+  }
+);
+const transParams = computed(() => {
+  return {
+    serviceUnitId: props.data?.serviceUnitId,
+    supplierId: props.data?.supplierId,
+  };
+});
+
+const { loading, pagination, tableData, search, onChange } = useFetchTable(
+  supplierOverviewDrill,
+  {
+    params: transParams,
+  },
+  false
+);
+</script>