Sfoglia il codice sorgente

质量监控分析数据下钻功能

刘洋 1 anno fa
parent
commit
6a872ead91

+ 142 - 0
src/views/report/quality-analysis/degree-drill-dialog.vue

@@ -0,0 +1,142 @@
+<template>
+  <my-dialog
+    :visible="visible"
+    :header="title"
+    :width="1200"
+    :closeOnOverlayClick="false"
+    @close="emit('update:visible', false)"
+  >
+    <div class="drill-search-box">
+      <div class="field">
+        <div class="label">服务单元:</div>
+        <div class="value">{{ data?.serviceName }}</div>
+      </div>
+      <div class="field" v-if="data?.supplierName">
+        <div class="label">供应商:</div>
+        <div class="value">{{ data?.supplierName }}</div>
+      </div>
+      <div class="field" v-if="data?.regionName">
+        <div class="label">大区:</div>
+        <div class="value">{{ data?.regionName }}</div>
+      </div>
+      <div class="field" v-if="data?.Influence_degree">
+        <div class="label">影响度:</div>
+        <div class="value">{{ data?.Influence_degree }}</div>
+      </div>
+      <div class="field" v-if="data?.reasonName">
+        <div class="label">问题原因类型:</div>
+        <div class="value">{{ data?.reasonName }}</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"
+    >
+      <template #custom-type="{ col, row }">
+        {{ customerTypeFilter(row[col.colKey]) }}
+      </template>
+      <template #flow-status="{ col, row }">
+        {{ flowStatusFilter(row[col.colKey]) }}
+      </template>
+      <template #issues-type="{ col, row }">
+        {{ issuesTypeFilter(row[col.colKey]) }}
+      </template>
+      <template #issues-reason="{ col, row }">
+        {{ issuesReasonTypeFilter(row[col.colKey]) }}
+      </template>
+      <template #submit-time="{ col, row }">
+        {{ timestampFilter(row[col.colKey]) }}
+      </template>
+      <template #update-time="{ col, row }">
+        {{ timestampFilter(row[col.colKey]) }}
+      </template>
+    </t-table>
+  </my-dialog>
+</template>
+<script setup name="DegreeDrillDialog">
+import { ref, computed, reactive, watch } from 'vue';
+import { CUSTOMER_TYPE } from '@/config/constants';
+import { dateFormat } from '@/utils/tool';
+import useFetchTable from '@/hooks/useFetchTable';
+import { degreeDrill } from '@/api/report';
+import {
+  timestampFilter,
+  customerTypeFilter,
+  issuesReasonTypeFilter,
+  issuesTypeFilter,
+  flowStatusFilter,
+} from '@/utils/filter';
+const tableColumns = [
+  { colKey: 'problemNo', title: '质量问题编号', width: 200, fixed: 'left' },
+  { colKey: 'crmNo', title: '项目单号', width: 200 },
+  { colKey: 'customType', title: '客户类型', cell: 'custom-type', width: 120 },
+  { colKey: 'custom', title: '客户名称', width: 140 },
+  { colKey: 'sopTypeStr', title: '实施产品' },
+  { colKey: 'summary', title: '问题简要' },
+  { colKey: 'userNames', title: '责任人', width: 140 },
+  { colKey: 'type', title: '问题类型', cell: 'issues-type', width: 120 },
+  { colKey: 'reason', title: '问题归因', cell: 'issues-reason', width: 160 },
+  { colKey: 'influenceDegree', title: '影响度', width: 100 },
+  { colKey: 'submitter', title: '提交人', width: 140 },
+  {
+    colKey: 'submissionTime',
+    title: '提交时间',
+    cell: 'submit-time',
+    width: 180,
+  },
+  {
+    colKey: 'updateDateTime',
+    title: '更新时间',
+    cell: 'update-time',
+    width: 180,
+  },
+  { colKey: 'status', title: '流程状态', cell: 'flow-status', width: 120 },
+  { colKey: 'taskName', title: '当前节点', minWidth: 160 },
+  { colKey: 'pendApproveUsers', title: '当前负责人', width: 140 },
+];
+const props = defineProps({
+  visible: Boolean,
+  data: Object,
+  title: String,
+});
+const emit = defineEmits(['close']);
+
+watch(
+  () => props.visible,
+  (val) => {
+    val && search();
+  }
+);
+const transParams = computed(() => {
+  let data = props.data || {};
+  let params = {};
+  for (let key in data) {
+    if (!key.endsWith('Name')) {
+      params[key] = data[key];
+    }
+  }
+  return params;
+});
+
+const { loading, pagination, tableData, search, onChange } = useFetchTable(
+  degreeDrill,
+  {
+    params: transParams,
+  },
+  false
+);
+</script>

+ 143 - 15
src/views/report/quality-analysis/index.vue

@@ -145,7 +145,13 @@
       v-model:visible="showInventoryDrillData"
       :data="inventoryDrillData"
       :footer="false"
-    ></InventoryDrillDialog> </div
+    ></InventoryDrillDialog>
+    <DegreeDrillDialog
+      v-model:visible="showDegreeDrillData"
+      :data="degreeDrillData"
+      :title="degreeDrillTitle"
+      :footer="false"
+    ></DegreeDrillDialog> </div
 ></template>
 
 <script setup name="QualityAnalysis">
@@ -166,11 +172,13 @@ import {
 import { FullscreenIcon } from 'tdesign-icons-vue-next';
 import { ISSUES_REASON_TYPE } from '@/config/constants';
 import InventoryDrillDialog from './inventory-drill-dialog.vue';
+import DegreeDrillDialog from './degree-drill-dialog.vue';
 import { cloneDeep } from 'lodash';
 const chart11 = ref();
 const chart12 = ref();
 const chart21 = ref();
 const chart22 = ref();
+const degreeDrillTitle = ref('');
 const inventoryDrillData = ref({
   serviceUnitId: '',
   degree: '',
@@ -185,12 +193,81 @@ const chart0Click = (params) => {
   )?.name;
   showInventoryDrillData.value = true;
 };
+const degreeDrillData = ref({
+  Influence_degree: '',
+  region_id: '',
+  regionName: '',
+  reason: '',
+  supplierId: '',
+  supplierName: '',
+  serviceUnitId: '',
+  serviceName: '',
+});
 
 const showDegreeDrillData = ref(false);
-const chart11Click = (params) => {};
-const chart12Click = (params) => {};
-const chart21Click = (params) => {};
-const chart22Click = (params) => {};
+
+const getReasonValue = (name) => {
+  for (let key in ISSUES_REASON_TYPE) {
+    if (ISSUES_REASON_TYPE[key] == name) {
+      return key;
+    }
+  }
+  return '';
+};
+const chart11Click = (params) => {
+  let map = getSupplierIdsMap(result11.value);
+  degreeDrillTitle.value = '影响度供应商分布';
+  degreeDrillData.value = {
+    serviceUnitId: serviceId.value,
+    serviceName: serviceOptions.value.find((item) => item.id == serviceId.value)
+      ?.name,
+    Influence_degree: params.name,
+    supplierId: map[params.seriesName],
+    supplierName: params.seriesName,
+  };
+  showDegreeDrillData.value = true;
+};
+const chart12Click = (params) => {
+  let map = getSupplierIdsMap(result12.value);
+  degreeDrillTitle.value = '执行协调类归因供应商分布';
+  degreeDrillData.value = {
+    serviceUnitId: serviceId.value,
+    serviceName: serviceOptions.value.find((item) => item.id == serviceId.value)
+      ?.name,
+    supplierId: map[params.seriesName],
+    supplierName: params.seriesName,
+    reason: getReasonValue(params.name),
+    reasonName: params.name,
+  };
+  showDegreeDrillData.value = true;
+};
+const chart21Click = (params) => {
+  let map = getRegionIdsMap(result21.value);
+  degreeDrillTitle.value = '影响度大区分布';
+  degreeDrillData.value = {
+    serviceUnitId: serviceId.value,
+    serviceName: serviceOptions.value.find((item) => item.id == serviceId.value)
+      ?.name,
+    region_id: map[params.name],
+    Influence_degree: params.seriesName,
+    regionName: params.name,
+  };
+  showDegreeDrillData.value = true;
+};
+const chart22Click = (params) => {
+  let map = getRegionIdsMap(result22.value);
+  degreeDrillTitle.value = '执行协调类归因大区分布';
+  degreeDrillData.value = {
+    serviceUnitId: serviceId.value,
+    serviceName: serviceOptions.value.find((item) => item.id == serviceId.value)
+      ?.name,
+    region_id: map[params.name],
+    reason: getReasonValue(params.seriesName),
+    regionName: params.name,
+    reasonName: params.seriesName,
+  };
+  showDegreeDrillData.value = true;
+};
 const curTimeRange = ref([]);
 const timeParams = computed(() => {
   return {
@@ -241,7 +318,7 @@ watch(group, () => {
   overallRadarRun({ serviceUnitId: serviceId.value, group: group.value });
 });
 
-const buildBarData = (result = {}) => {
+const buildBarData1 = (result = {}) => {
   let xData = Object.keys(result);
   let names = Object.values(result)
     ? Object.keys(Object.values(result)[0] || {})
@@ -260,6 +337,25 @@ const buildBarData = (result = {}) => {
   }
   return { xData, seriesData: sData };
 };
+const buildBarData2 = (result = {}) => {
+  let xData = Object.keys(result);
+  let names = Object.values(result)
+    ? Object.keys(Object.values(result)[0] || {}).filter((key) => key !== 'id')
+    : [];
+  let sData = [];
+  for (let i = 0; i < names.length; i++) {
+    let data = [];
+    for (let j = 0; j < xData.length; j++) {
+      data.push(result[xData[j]][names[i]] || 0);
+    }
+    sData.push({
+      name: names[i],
+      data: data,
+      barWidth: '16px',
+    });
+  }
+  return { xData, seriesData: sData };
+};
 // 总体盘点饼图
 const overallPieOptions = computed(() => {
   const result = Object.entries(overallPieData.value || {});
@@ -350,13 +446,23 @@ const barExtendOption = {
   },
 };
 const options11 = computed(() => {
+  // let res = {
+  //   A: { 小熊U: { value: 1, id: 1 } },
+  //   B: { 小熊U: { value: 1, id: 1 } },
+  // };
   return createStackingBarOption(
-    buildBarData(result11.value || {}),
+    // buildBarData1(res),
+    buildBarData1(result11.value || {}),
     barExtendOption
   );
 });
 const options12 = computed(() => {
-  let res = result12.value || {};
+  let res =
+    // {
+    //   EXEC: { 小熊U: { value: 1, id: 1 } },
+    //   MANAGER: { 小熊U: { value: 1, id: 1 } },
+    // } ||
+    result12.value || {};
   let obj = Object.keys(res).reduce((o, k) => {
     if (ISSUES_REASON_TYPE[k]) {
       o[ISSUES_REASON_TYPE[k]] = res[k];
@@ -366,19 +472,41 @@ const options12 = computed(() => {
     return o;
   }, {});
 
-  return createStackingBarOption(buildBarData(obj), barExtendOption);
+  return createStackingBarOption(buildBarData1(obj), barExtendOption);
 });
-// const supplierIdsMap = computed(() => {
-//   let res = cloneDeep(result12.value || {});
-// });
+const getSupplierIdsMap = (result) => {
+  let map = {};
+  let res = cloneDeep(result || {});
+  let objs = Object.values(res);
+  for (let i = 0; i < objs.length; i++) {
+    let obj = objs[i];
+    for (let k in obj) {
+      map[k] = obj.id;
+    }
+  }
+  return map;
+};
+const getRegionIdsMap = (result) => {
+  let map = {};
+  let res = cloneDeep(result || {});
+  for (let k in res) {
+    map[k] = res[k].id;
+  }
+  return map;
+};
 const options21 = computed(() => {
+  // let res = { 'm1108教务处 大区': { A: 1, B: 1, id: 1 } };
+
   return createStackingBarOption(
-    buildBarData(result21.value || {}),
+    // buildBarData2(res),
+    buildBarData2(result21.value || {}),
     barExtendOption
   );
 });
 const options22 = computed(() => {
-  let res = result22.value || {};
+  let res =
+    // { 'm1108教务处 大区': { EXEC: 1, MANAGER: 1, id: 1 } } ||
+    result22.value || {};
   for (let key in res) {
     let oldObj = res[key];
     let objNew = Object.keys(oldObj).reduce((o, k) => {
@@ -391,7 +519,7 @@ const options22 = computed(() => {
     }, {});
     res[key] = objNew;
   }
-  return createStackingBarOption(buildBarData(res), barExtendOption);
+  return createStackingBarOption(buildBarData2(res), barExtendOption);
 });
 </script>
 

+ 46 - 10
src/views/report/quality-analysis/inventory-drill-dialog.vue

@@ -37,7 +37,19 @@
       <template #custom-type="{ col, row }">
         {{ customerTypeFilter(row[col.colKey]) }}
       </template>
-      <template #begin-time="{ col, row }">
+      <template #flow-status="{ col, row }">
+        {{ flowStatusFilter(row[col.colKey]) }}
+      </template>
+      <template #issues-type="{ col, row }">
+        {{ issuesTypeFilter(row[col.colKey]) }}
+      </template>
+      <template #issues-reason="{ col, row }">
+        {{ issuesReasonTypeFilter(row[col.colKey]) }}
+      </template>
+      <template #submit-time="{ col, row }">
+        {{ timestampFilter(row[col.colKey]) }}
+      </template>
+      <template #update-time="{ col, row }">
         {{ timestampFilter(row[col.colKey]) }}
       </template>
     </t-table>
@@ -49,16 +61,40 @@ import { CUSTOMER_TYPE } from '@/config/constants';
 import { dateFormat } from '@/utils/tool';
 import useFetchTable from '@/hooks/useFetchTable';
 import { inventoryDrill } from '@/api/report';
-import { customerTypeFilter, timestampFilter } from '@/utils/filter';
+import {
+  timestampFilter,
+  customerTypeFilter,
+  issuesReasonTypeFilter,
+  issuesTypeFilter,
+  flowStatusFilter,
+} from '@/utils/filter';
 const tableColumns = [
-  { colKey: 'service', title: '服务单元' },
-  { colKey: 'crmNo', title: '项目单号' },
-  { colKey: 'beginTime', title: '派单时间', cell: 'begin-time' },
-  { colKey: 'crmUserName', title: '客户经理' },
-  { colKey: 'customType', title: '客户类型', cell: 'custom-type' },
-  { colKey: 'custom', title: '客户名称' },
-  { colKey: 'name', title: '项目名称' },
-  { colKey: 'product', title: '实施产品' },
+  { colKey: 'problemNo', title: '质量问题编号', width: 200, fixed: 'left' },
+  { colKey: 'crmNo', title: '项目单号', width: 200 },
+  { colKey: 'customType', title: '客户类型', cell: 'custom-type', width: 120 },
+  { colKey: 'custom', title: '客户名称', width: 140 },
+  { colKey: 'sopTypeStr', title: '实施产品' },
+  { colKey: 'summary', title: '问题简要' },
+  { colKey: 'userNames', title: '责任人', width: 140 },
+  { colKey: 'type', title: '问题类型', cell: 'issues-type', width: 120 },
+  { colKey: 'reason', title: '问题归因', cell: 'issues-reason', width: 160 },
+  { colKey: 'influenceDegree', title: '影响度', width: 100 },
+  { colKey: 'submitter', title: '提交人', width: 140 },
+  {
+    colKey: 'submissionTime',
+    title: '提交时间',
+    cell: 'submit-time',
+    width: 180,
+  },
+  {
+    colKey: 'updateDateTime',
+    title: '更新时间',
+    cell: 'update-time',
+    width: 180,
+  },
+  { colKey: 'status', title: '流程状态', cell: 'flow-status', width: 120 },
+  { colKey: 'taskName', title: '当前节点', minWidth: 160 },
+  { colKey: 'pendApproveUsers', title: '当前负责人', width: 140 },
 ];
 const props = defineProps({
   visible: Boolean,