anonResultReportView.vue 9.54 KB
<route lang="yaml">
    name: anonResultReportView
    </route>

<script lang="ts" setup name="anonResultReportView">
import {
  getAnonAnalyzePageData,
  getAnonAnalyzeResult,
  getAnonTaskDetail,
  htmlToWord,
  sendAnonReport,
} from '@/api/modules/dataAnonymization';
import { changeNum, download } from '@/utils/common';
import { ElMessage } from 'element-plus';
import anonResultAnalysis from './components/anonResultAnalysis.vue';
import { commonPageConfig, USERROLE } from '@/utils/enum';
import { calcColumnWidth } from '@/utils';
import html2canvas from 'html2canvas';

const route = useRoute();
const router = useRouter();
const fullPath = route.fullPath;
const taskGuid = ref(route.query.guid);
const { proxy } = getCurrentInstance() as any;
const resultDataLoading = ref(false);

/** 是否是数据提供方 */
const isDataProvider = computed(() => {
  return localStorage.getItem('userRole') == USERROLE.PROVIDER;
})

const downPromise: any = ref()

/** 提交保存和编辑后的执行guid */
const taskExecGuid = ref(route.query.execGuid);

/** 记录原始的值信息,防止上一步之后未修改数据时不调用接口 */
const oldAnonTaskValueInfo: any = ref({});
/** 执行结果信息 */
const analysisResultInfo: any = ref({});

const containerRef = ref();

const containerWidth = ref(containerRef.value?.offsetWidth || 0)

/** ------------------------- 匿名化分析结果页面数据展示 ---------------- */
const pageInfo: any = ref({
  ...commonPageConfig,
})

const pageChange = (info) => {
  pageInfo.value.curr = Number(info.curr);
  pageInfo.value.limit = Number(info.limit);
  getAnalysisResultPageData();
}

/** 每列字段对应的列宽计算结果。 */
const originResultTableFieldColumn = ref({});

/** 结果分析中的字段表格数据 */
const resultData: any = ref([]);
/** 全部未分页的数据,下载word时使用。 */
const fullResultData: any = ref([]);

/** 结果分析中的字段信息 */
const analysisResultTableFields: any = ref([]);

const analysisResultLoading = ref(false);

/** otherWidth表示使用标题宽度时添加标题排序图标等宽度 */
const calcTableColumnWidth = (data: any[], prop, title, otherWidth = 0) => {
  let d: any[] = [];
  data.forEach((dt) => d.push(dt[prop]));
  //样式使用默认值。
  return calcColumnWidth(
    d,
    title,
    {
      fontSize: 14,
      fontFamily: "SimSun",
    },
    {
      fontSize: 14,
      fontFamily: "SimSun",
    },
    otherWidth
  );
};

watch(
  resultData,
  (val: any[], oldVal) => {
    if (!analysisResultTableFields.value?.length) {
      originResultTableFieldColumn.value = {};
      return;
    }
    originResultTableFieldColumn.value = {};
    analysisResultTableFields.value.forEach((field, index) => {
      originResultTableFieldColumn.value[field.enName] = calcTableColumnWidth(
        val?.slice(0, 20) || [],
        field.enName,
        field.chName,
        24
      );
    });
  },
  {
    deep: true,
  }
);

const getAnalysisResultPageData = (isFull = false) => {
  analysisResultLoading.value = true;
  getAnonAnalyzePageData({
    pageIndex: pageInfo.value.curr,
    pageSize: isFull ? -1 : pageInfo.value.limit,
    taskExecGuid: taskExecGuid.value,
  }).then((res: any) => {
    analysisResultLoading.value = false;
    if (res?.code == proxy.$passCode) {
      if (isFull) {
        fullResultData.value = [];
        res.data?.records?.forEach(d => {
          let obj = {};
          analysisResultTableFields.value.forEach(t => {
            obj[t.enName] = d.fieldValue?.[t.enName];
          });
          obj['equivalenceClassNum'] = changeNum(d.equivalenceClassNum || 0, 0);
          obj['reIdentifyRisk'] = changeNum(d.reIdentifyRisk || 0, 2);
          obj['isGtThreshold'] = d.isGtThreshold;
          fullResultData.value.push(obj);
        });
        resultData.value = fullResultData.value.slice(0, pageInfo.value.limit);
        pageInfo.value.rows = fullResultData.value.length;
      } else {
        resultData.value = [];
        res.data?.records?.forEach(d => {
          let obj = {};
          analysisResultTableFields.value.forEach(t => {
            obj[t.enName] = d.fieldValue?.[t.enName];
          });
          obj['equivalenceClassNum'] = changeNum(d.equivalenceClassNum || 0, 0);
          obj['reIdentifyRisk'] = changeNum(d.reIdentifyRisk || 0, 2);
          obj['isGtThreshold'] = d.isGtThreshold;
          resultData.value.push(obj);
        });
        pageInfo.value.rows = res.data?.totalRows ?? 0;
      }
    } else {
      proxy.$ElMessage.error(res.msg);
    }
  })
}

const isWordStyle = ref(false);

/** 下载评估报告 */
const transfer = () => {
  isWordStyle.value = true;
}

const domClone: any = ref(null);

const resultReportRef = ref();

const convertHtml2Img = (dom, domClone) => {
  const element = <HTMLElement>dom.querySelector('.kpi-content')
  if (!element) {
    return Promise.resolve();
  }
  return html2canvas(element, {
    allowTaint: true,
    useCORS: true,
    scale: 2,
  }).then((canvas: any) => {
    document.documentElement.scrollTop = 0;
    document.body.scrollTop = 0;
    element.parentNode && ((<HTMLElement>element.parentNode).scrollTop = 0);
    let url = canvas.toDataURL('image/jpeg');
    let img = document.createElement('img');
    if (url) {
      // img.src = url.split(',')[1];
      img.src = url;
      img.width = 620;
      img.height = 265;
      img.crossOrigin = 'Anonymous';
    }
    const copyElement = <HTMLElement>domClone.querySelector('.kpi-content')
    copyElement.parentNode?.replaceChild(img, copyElement);
  })
}

const loadingText = ref('');

const getHTML = (reportResultContent) => {
  let html = reportResultContent;
  html = html.replace(/"/g, "'");
  return html;
};

const downloadWord = () => {
  if (downPromise.value) {
    return;
  }
  let dom = domClone.value || (domClone.value = document.createElement('div'));
  let report = resultReportRef.value?.report;
  dom.innerHTML = report?.innerHTML;
  resultDataLoading.value = true;
  loadingText.value = `评测报告正在${route.query.dataOwner == '1' ? '发送' : '下载' }中,请勿关闭浏览器...`;
  downPromise.value = convertHtml2Img(report, dom).then(() => {
    if (route.query.dataOwner == '1') {
      sendAnonReport({ taskGuid: taskGuid.value, html: encodeURIComponent(`<div>${getHTML(dom.innerHTML)}</div>`) }).then((res: any) => {
        downPromise.value = null
        loadingText.value = '';
        resultDataLoading.value = false;
        if (res?.code == proxy.$passCode) {
          proxy.$ElMessage.success('评测报告发送成功');
        } else {
          res?.msg && ElMessage.error(res?.msg);
        }
      })
    } else {
      htmlToWord({ html: encodeURIComponent(`<div>${getHTML(dom.innerHTML)}</div>`) }).then((res: any) => {
        downPromise.value = null
        loadingText.value = '';
        resultDataLoading.value = false;
        if (res && !res.msg) {
          download(res, (route.query.taskName || oldAnonTaskValueInfo.value.taskName) + '_匿名化评估报告.docx', 'word')
        } else {
          res?.msg && ElMessage.error(res?.msg);
        }
      })
    }
  }).catch(() => {
    downPromise.value = null;
  });
}

onMounted(() => {
  nextTick(() => {
    containerWidth.value = containerRef.value?.offsetWidth || 0;
  })
  window.onresize = () => {
    containerWidth.value = containerRef.value?.offsetWidth || 0;
  }
})

onBeforeMount(() => {
  resultDataLoading.value = true;
  getAnonAnalyzeResult(taskExecGuid.value).then((res: any) => {
    resultDataLoading.value = false;
    if (res?.code == proxy.$passCode) {
      analysisResultInfo.value = res.data || {};
      analysisResultTableFields.value = res.data?.column || [];
      pageInfo.value.curr = 1;
      getAnalysisResultPageData(true);
    } else {
      res?.msg && proxy.$ElMessage.error(res.msg);
    }
  });
  getAnonTaskDetail(taskGuid.value).then((res: any) => {
    if (res?.code == proxy.$passCode) {
      oldAnonTaskValueInfo.value = res.data || {};
    } else {
      res?.msg && proxy.$ElMessage.error(res.msg);
    }
  });
})

</script>

<template>
  <div class="table_tool_wrap" v-loading="resultDataLoading" ref="containerRef" :element-loading-text="loadingText">
    <!-- 连接器不需要显示下载报告按钮 -->
    <template v-if="!isDataProvider">
      <el-button v-show="!isWordStyle" style="margin-bottom: 8px;" type="primary" @click="transfer"
        v-preReClick>预览Word评估报告</el-button>
      <div v-show="isWordStyle" style="margin-bottom: 8px;">
        <el-button @click="isWordStyle = false">返回</el-button>
        <el-button type="primary" @click="downloadWord">{{ route.query.dataOwner == '1' ? '确认并发送评测报告' : '下载评测报告'
        }}</el-button>
      </div>
    </template>
    <anonResultAnalysis ref="resultReportRef" :show-title="true" :analysis-result-info="analysisResultInfo"
      :isWordStyle="isWordStyle" :style="isWordStyle ? {
        height: !isDataProvider ? 'calc(100% - 36px)' : '100%',
        'overflow-y': 'auto',
        'margin-right': '-16px',
        'padding-right': '16px',
        width: 'auto'
      } : null" :analysis-result-loading="analysisResultLoading"
      :analysis-result-table-fields="analysisResultTableFields" :old-anon-task-value-info="oldAnonTaskValueInfo"
      :container-width="containerWidth" :origin-result-table-field-column="originResultTableFieldColumn"
      :page-info="pageInfo" :result-data="resultData" :fullResultData="fullResultData" @page-change="pageChange">
    </anonResultAnalysis>
  </div>
</template>

<style lang="scss" scoped>
.table_tool_wrap {
  width: 100%;
  height: 100%;
  padding: 8px 16px 16px;
  overflow-y: auto;
}
</style>