index.vue 6.18 KB
<template>
  <NTimeline class="go-chart-configurations-timeline">
    <NTimelineItem v-show="isCharts && dimensionsAndSource" type="info" :title="TimelineTitleEnum.MAPPING">
      <n-table striped>
        <thead>
          <tr>
            <th v-for="item in tableTitle" :key="item">{{ item }}</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(item, index) in dimensionsAndSource" :key="index">
            <td>{{ item.field }}</td>
            <td>{{ item.mapping }}</td>
            <td>
              <NSpace v-if="item.result === 0">
                <NBadge dot type="success"></NBadge>
                <NText>无</NText>
              </NSpace>
              <NSpace v-else>
                <NBadge dot :type="item.result === 1 ? 'success' : 'error'"></NBadge>
                <NText>匹配{{ item.result === 1 ? '成功' : '失败' }}</NText>
              </NSpace>
            </td>
          </tr>
        </tbody>
      </n-table>
    </NTimelineItem>
    <NTimelineItem v-show="filterShow" color="#97846c" :title="TimelineTitleEnum.FILTER">
      <NSpace :size="18" vertical>
        <NText depth="3">过滤器默认处理接口返回值的「data」字段</NText>
        <ChartDataMonacoEditor></ChartDataMonacoEditor>
      </NSpace>
    </NTimelineItem>
    <NTimelineItem type="success" :title="TimelineTitleEnum.CONTENT">
      <NSpace vertical>
        <NSpace class="source-btn-box">
          <NUpload v-model:file-list="uploadFileListRef" :show-file-list="false" :customRequest="customRequest"
            @before-upload="beforeUpload">
            <NSpace>
              <NButton v-if="!ajax" class="sourceBtn-item" :disabled="noData">
                <template #icon>
                  <NIcon>
                    <document-add-icon />
                  </NIcon>
                </template>
                导入(json / txt)
              </NButton>
            </NSpace>
          </NUpload>
          <div>
            <NButton class="sourceBtn-item" :disabled="noData" @click="download">
              <template #icon>
                <NIcon>
                  <document-download-icon />
                </NIcon>
              </template>
              下载
            </NButton>
            <n-tooltip trigger="hover">
              <template #trigger>
                <NIcon class="go-ml-1" size="21" :depth="3">
                  <help-outline-icon></help-outline-icon>
                </NIcon>
              </template>
              <NText depth="3">点击【下载】查看完整数据</NText>
            </n-tooltip>
          </div>
        </NSpace>
        <NCard size="small">
          <NScrollbar style="max-height: 400px;">
            <NCode :code="toString(source)" language="json"></NCode>
          </NScrollbar>
        </NCard>
      </NSpace>
    </NTimelineItem>
  </NTimeline>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { ChartFrameEnum } from '@/packages/index.d'
import { RequestDataTypeEnum } from '@/enums/httpEnum'
import { icon } from '@/plugins'
import isObject from 'lodash/isObject'
import { toString, isArray } from '@/utils'
import { useTargetData } from '../../../../hooks/useTargetData.hook'
import { DataResultEnum, TimelineTitleEnum } from '../../../index.d'
import { useFile } from '../../../hooks/useFile.hooks'
import { ChartDataMonacoEditor } from '../ChartDataMonacoEditor'
import { NBadge, NButton, NCard, NCode, NIcon, NScrollbar, NSpace, NText, NTimeline, NTimelineItem, NUpload } from 'naive-ui'

const { targetData } = useTargetData()
const props = defineProps({
  show: {
    type: Boolean,
    required: false
  },
  ajax: {
    type: Boolean,
    required: true
  }
})

// 表格标题
const tableTitle = ['字段', '映射', '状态']

const { HelpOutlineIcon } = icon.ionicons5
const { DocumentAddIcon, DocumentDownloadIcon } = icon.carbon

const source = ref()
const dimensions = ref()
const dimensionsAndSource = ref()
const noData = ref(false)

const { uploadFileListRef, customRequest, beforeUpload, download } = useFile(targetData)

// 是否展示过滤器
const filterShow = computed(() => {
  return targetData.value.request.requestDataType !== RequestDataTypeEnum.STATIC
})

// 是支持 dataset 的图表类型
const isCharts = computed(() => {
  return targetData.value.chartConfig.chartFrame === ChartFrameEnum.ECHARTS
})

// 处理映射列表状态结果
const matchingHandle = (mapping: string) => {
  let res = DataResultEnum.SUCCESS
  for (let i = 0; i < source.value.length; i++) {
    if (source.value[i][mapping] === undefined) {
      res = DataResultEnum.FAILURE
      return res
    }
  }
  return DataResultEnum.SUCCESS
}

// 处理映射列表
const dimensionsAndSourceHandle = () => {
  try {
    // 去除首项数据轴标识
    return dimensions.value.map((dimensionsItem: string, index: number) => {
      return index === 0
        ? {
          // 字段
          field: '通用标识',
          // 映射
          mapping: dimensionsItem,
          // 结果
          result: DataResultEnum.NULL
        }
        : {
          field: `数据项-${index}`,
          mapping: dimensionsItem,
          result: matchingHandle(dimensionsItem)
        }
    })
  } catch (error) {
    return []
  }
}

watch(
  () => targetData.value?.option?.dataset,
  (
    newData?: {
      source: any
      dimensions: any
    } | null
  ) => {
    
    if (newData && targetData?.value?.chartConfig?.chartFrame === ChartFrameEnum.ECHARTS) {
      // 只有 DataSet 数据才有对应的格式
      source.value = newData
      if (isCharts.value) {
        dimensions.value = newData.dimensions
        dimensionsAndSource.value = dimensionsAndSourceHandle()
      }
    } else if (newData !== undefined && newData !== null) {
      dimensionsAndSource.value = null
      source.value = newData
    } else {
      noData.value = true
      source.value = '此组件无数据源'
    }
    if (isArray(newData)) {
      dimensionsAndSource.value = null
    }
  },
  {
    immediate: true
  }
)
</script>

<style lang="scss" scoped>
@include go('chart-configurations-timeline') {
  @include deep() {
    pre {
      white-space: pre-wrap;
      word-wrap: break-word;
    }
  }

  .source-btn-box {
    margin-top: 10px !important;
  }
}
</style>