Newer
Older
KaiFengPC / src / views / sponeScreen / projectHM / ZhongheFenXi_component / typicalLandSiteShuJuQuShi.vue
@zhangdeliang zhangdeliang 5 days ago 12 KB update
<template>
  <div class="shuJuQuShi flex" v-loading="echartLoading" element-loading-text="加载中..." element-loading-background="rgba(0, 0, 0,0.4)">
    <div class="echarts" ref="echarts" v-show="!isShow"></div>
    <empty v-if="isShow" emptyText="暂未查到数据" :width="100" :height="100" style="margin-top: 50px"></empty>
  </div>
  <!-- 分析建议弹窗 -->
  <el-dialog v-model="dialogShow" title="AI生成分析建议" width="600px" append-to-body draggable>
    <el-form>
      <el-form-item label="请输入问题" prop="question">
        <el-input type="textarea" v-model="question" style="width: 100%"></el-input>
      </el-form-item>
    </el-form>
    <el-button type="primary" @click="aiDataSuggest">开始生成</el-button>
    <div class="aiContent" v-loading="loadingAI" element-loading-text="AI正在分析中...">
      <div class="suggestContDialog" v-html="suggestContent"></div>
      <img src="@/assets/newImgs/HMScreen/resultAI.gif" alt="" class="aiImg" />
    </div>
  </el-dialog>
</template>
<script setup>
import { graphicReport, aiToGetSuggest } from '@/api/sponeScreen/syntherticData.js';
import html2Canvas from 'html2canvas';
import { sysUpload } from '@/api/login.js';

const { proxy } = getCurrentInstance();
const propsColor = proxy.fixDict['propsColorYs']; // 根据因子的单位来匹配
const props = defineProps({
  searchDate: Array,
  typicalLandInfo: Object,
  domSelect: Object,
});
const question = ref('从排水专业分析这段数据');
const dialogShow = ref(false);
const suggestContent = ref('');
const loadingAI = ref(false);
const echartLoading = ref(true);
const isShow = ref(false);
const myChart = shallowRef(null);
const yAxisData = ref([]);
// 获取列表数据
function getPipelineEcharts() {
  echartLoading.value = true;
  let params = {
    startTime: proxy.moment(props.searchDate[0]).format('YYYY-MM-DD') + ' 08:00:00',
    endTime: proxy.moment(props.searchDate[1]).format('YYYY-MM-DD') + ' 08:00:00',
    stCode: props.typicalLandInfo.stCode,
  };
  graphicReport(params).then(res => {
    let { data } = res;
    echartLoading.value = false;
    //initEcharts(data.propertyMonitorXList, data.propertyMonitorList)
    let targerts = ['小时水量', 'SS', '水位', '流速'];
    let newPropertyMonitorList =
      data['propertyMonitorList'] && data['propertyMonitorList'].filter(item => targerts.includes(item.monitorPropertyName));
    data['propertyMonitorList'] = newPropertyMonitorList;
    getRainData(data);
  });
}
//根据关联的雨量站获取雨量站数据
const getRainData = async val => {
  let params = {
    startTime: proxy.moment(props.searchDate[0]).format('YYYY-MM-DD') + ' 08:00:00',
    endTime: proxy.moment(props.searchDate[1]).format('YYYY-MM-DD') + ' 08:00:00',
    stCode: props.typicalLandInfo.referRainStCode,
  };
  let { data } = await graphicReport(params);
  echartLoading.value = false;
  let rainData = {};
  if (data.propertyMonitorList.length) {
    data.propertyMonitorList.forEach(item => {
      if (item.monitorPropertyName.includes('5分钟时段降水量')) {
        rainData = item;
      }
    });
  }
  isShow.value = data.propertyMonitorXList.length ? false : true;
  if (val['propertyMonitorList'] && val['propertyMonitorList'].length) {
    val.propertyMonitorList.unshift(rainData);
  } else {
    val['propertyMonitorList'] = [rainData];
  }

  initEcharts(data.propertyMonitorXList, val.propertyMonitorList);
};
const initEcharts = (timeList, propertyMonitorList) => {
  if (!!myChart.value) {
    myChart.value.dispose();
  }
  myChart.value = proxy.echarts.init(proxy.$refs.echarts);
  const xAxisData = propertyMonitorList.map((item, index) => {
    return {
      type: index == 0 ? 'category' : '',
      //x轴类目名称列表
      data: timeList,
      //x 轴所在的 grid 的索引,默认0表示位于第一个 grid
      gridIndex: index,
      axisLabel: {
        color: '#2395FF',
        fontSize: 14,
        fontFamily: 'Source Han Sans CN',
        // show: index == propertyMonitorList.length - 1 ? true : false,
      },
      axisLine: {
        show: true,
        onZero: false,
        lineStyle: {
          color: '#2395FF',
          width: 1,
          type: 'solid',
        },
        show: true,
      },
    };
  });
  yAxisData.value = propertyMonitorList.map((item, index) => {
    const current = propsColor.find(it => it.label === item.propertyUnit);
    var maxNum = Math.max(...item.ylist);
    return {
      type: 'value',
      //展示网格线
      splitLine: {
        show: true,
      },
      inverse: item.monitorPropertyName.includes('5分钟时段降水量') ? true : false,
      //y 轴所在的 grid 的索引,默认0表示位于第一个 grid
      gridIndex: index,
      name: `${item.monitorPropertyName}(${current.value})`,
      nameLocation: item.monitorPropertyName.includes('5分钟时段降水量') ? 'start' : 'end',
      nameGap: 10, //纵坐标名字与轴线之间的距离
      nameTextStyle: {
        fontFamily: 'Source Han Sans CN',
        fontSize: '14px',
        color: current.color,
        align: 'left', // 设置文字左对齐
      },
      splitLine: {
        show: true,
        lineStyle: {
          type: 'dashed',
          color: '#ffffff1c',
        },
      },
      axisLine: {
        show: true,
        lineStyle: {
          color: '#2395FF',
        },
      },
      max: function (value) {
        if (current.value == 'mm') {
          return (Number(maxNum) * 1.1).toFixed(0);
        }
      },
      axisLabel: {
        // formatter: '{value} ',
        color: '#47AFFE',
        fontSize: 14,
        fontFamily: 'Source Han Sans CN',
        align: 'right', // 文字右对齐
        formatter: function (value, index) {
          if (value >= 10000 && value < 10000000) {
            value = value / 10000 + '万';
          } else if (value >= 10000000) {
            value = value / 10000000 + '千万';
          }
          if (index % 2 === 0) {
            return value;
          } else {
            return '';
          }
        },
      },
    };
  });
  const seriesData = propertyMonitorList.map((item, index) => {
    const current = propsColor.find(it => it.label === item.propertyUnit);
    if (current.value == 'mm') {
      return {
        type: 'bar',
        name: `${item.monitorPropertyName}(${current.value})`,
        data: item.ylist, //y轴类目数据
        barWidth: '2px',
        itemStyle: {
          color: current.color,
        },
        xAxisIndex: index, //使用x轴的索引
        yAxisIndex: index, //使用y轴的索引
      };
    } else {
      return {
        type: 'line',
        name: `${item.monitorPropertyName}(${current.value})`,
        data: item.ylist, //y轴类目数据
        lineStyle: {
          color: current.color, // 设置线的颜色为红色
          width: 2,
        },
        xAxisIndex: index, //使用x轴的索引
        yAxisIndex: index, //使用y轴的索引
      };
    }
  });
  const legendData = propertyMonitorList.map((item, index) => {
    const current = propsColor.find(it => it.label === item.propertyUnit);
    let topVal = 10 + 130 * index;
    return {
      data: [`${item.monitorPropertyName}(${current.value})`],
      show: false,
      color: current.color,
      top: topVal,
    };
  });
  const gridData = propertyMonitorList.map((item, index) => {
    let topVal = 45 + 135 * index;
    let bottomVal = 730 - 133 * (index + 1);
    return {
      top: topVal,
      bottom: bottomVal,

      left: 50,
      right: 0,
    };
  });
  const dataZoomXAxisIndex = propertyMonitorList.map((item, index) => {
    return index;
  });
  const option = {
    color: ['#23d0df4a'],
    axisPointer: {
      link: [
        {
          xAxisIndex: 'all',
        },
      ],
    },
    legend: legendData,
    grid: gridData,
    tooltip: {
      trigger: 'axis',
      show: true,
      backgroundColor: 'rgba(18,56,104,0.9)', // 设置背景色为半透明的白色
      borderColor: '#48ABFF', // 边框颜色
      borderWidth: 1, // 边框宽度
      borderRadius: 4, // 设置边框圆角
      textStyle: {
        // 设置字体颜色
        color: '#F0F8FF',
        fontFamily: 'Source Han Sans CN',
        fontWeight: 500,
        fontSize: '15px',
        color: '#F0F8FF',
      },
      formatter: function (params, b, c) {
        let dataArr = [];
        let newDataArr = [];
        let formatterStr = '';
        params.map(function (item, index) {
          dataArr[item.seriesIndex] = item;
        });
        dataArr.map(function (item, index) {
          newDataArr.push({ seriesName: item.seriesName, name: item.name, value: item.value });
        });
        formatterStr += params[0].axisValue + '<br />';
        newDataArr.map(function (item, index) {
          formatterStr += item.seriesName + ':' + item.value + '<br />';
        });
        return formatterStr;
      },
    },
    dataZoom: {
      // 设置滚动条的隐藏与显示
      show: true,
      // 设置滚动条类型
      type: 'inside',
      // 设置背景颜色
      backgroundColor: '#F1F1F1',
      // 设置选中范围的填充颜色
      fillerColor: '#C1C1C1',
      // 设置边框颜色
      borderColor: '#F1F1F1',
      // 是否显示detail,即拖拽时候显示详细数值信息
      showDetail: false,
      // 数据窗口范围的起始数值
      start: 0,
      // 数据窗口范围的结束数值(一页显示多少条数据)
      end: 100,
      // empty:当前数据窗口外的数据,被设置为空。
      // 即不会影响其他轴的数据范围
      filterMode: 'empty',
      // 设置滚动条宽度,相对于盒子宽度
      width: '50%',
      // 设置滚动条高度
      height: 8,
      // 设置滚动条显示位置
      left: 'center',
      // 是否锁定选择区域(或叫做数据窗口)的大小
      zoomLoxk: true,
      // 控制手柄的尺寸
      handleSize: 0,
      // dataZoom-slider组件离容器下侧的距离
      bottom: 0,
      xAxisIndex: dataZoomXAxisIndex,
    },
    xAxis: xAxisData,
    yAxis: yAxisData.value,
    series: seriesData,
  };

  myChart.value.setOption(option);
};

// 显示输入问题的弹窗
function showDialogAI() {
  dialogShow.value = true;
}

// 生成建议
function aiDataSuggest() {
  loadingAI.value = true;
  html2Canvas(props.domSelect, {
    dpi: 300, // 解决生产图片模糊
    useCORS: true,
    allowTaint: false,
    logging: false,
    scale: 1,
  }).then(res => {
    downloadBase64(res.toDataURL(), 'aiDataSuggest');
  });
}

const downloadBase64 = (dataUrl, fileName) => {
  const parts = dataUrl.split(';base64,');
  const contentType = parts[0].split(':')[1];
  let strArr = contentType.split('/');
  const raw = window.atob(parts[1]);
  const rawLength = raw.length;
  const uInt8Array = new Uint8Array(rawLength);
  for (let i = 0; i < rawLength; ++i) {
    uInt8Array[i] = raw.charCodeAt(i);
  }
  const blob = new Blob([uInt8Array], { type: contentType });
  const newFilename = fileName + '.' + strArr[1];
  const file = new File([blob], newFilename, { type: contentType });
  let formData = new FormData();
  formData.append('file', file);
  sysUpload(formData).then(res => {
    if (res.code == 200) {
      let datas = res.data;
      // 文件状态改为上传成功
      console.log('----上传成功', datas.url);
      let params = {
        content: question.value,
        pictureUrl: datas.url,
      };
      aiToGetSuggest(params).then(res => {
        loadingAI.value = false;
        if (!!res.data) {
          let datas = JSON.parse(res.data);
          suggestContent.value = datas.output.choices[0].message.content[0].text;
          suggestContent.value = suggestContent.value.replace(/\n/g, '<br />');
        } else {
          suggestContent.value = '暂无分析建议';
        }
      });
    } else {
      proxy.$modal.msgError('上传失败');
      loadingAI.value = false;
    }
  });
};

onMounted(() => {});
defineExpose({
  getPipelineEcharts,
  showDialogAI,
});
</script>
<style lang="scss">
.aiContent {
  position: relative;
  height: 600px;
  margin-top: 10px;
  margin-bottom: 10px;
  .suggestContDialog {
    width: 100%;
    height: 100%;
    overflow: auto;
    color: #c6c6c6;
    padding: 20px;
    background: url('@/assets/newImgs/HMScreen/contentBgAI.png') no-repeat;
    background-size: 100% 100%;
  }
  .aiImg {
    position: absolute;
    right: -20px;
    bottom: 0px;
    z-index: 99;
    width: 100px;
    height: 100px;
  }
}

.shuJuQuShi {
  width: 100%;
  height: 730px;

  .echarts {
    width: 100%;
    height: 100%;
  }
}
</style>