riku
2025-09-11 307b17ef15c73a071912a262834f2a5f68e1fa87
src/views/historymode/component/MissionReport.vue
@@ -72,6 +72,7 @@
import chartMapAmap from '@/utils/chart/chart-map-amap';
import { Legend } from '@/model/Legend';
import { getHexColor, getColorBetweenTwoColors } from '@/utils/color';
import { getGridDataDetailFactorValue } from '@/model/GridDataDetail';
// 借用卫星遥测模块中的100米网格
const props = defineProps({
@@ -106,7 +107,8 @@
      cityName: formObj.value.location.cName,
      districtCode: formObj.value.location.dCode,
      districtName: formObj.value.location.dName
    }
    },
    factorTypes: radioOptions(TYPE0).map((e) => e.name)
  };
});
@@ -121,6 +123,7 @@
  srySceneCount: 5,
  sryProbByFactor:
    '颗粒物(PM)相关X处,占比 %,主要涉及工地扬尘污染问题、道路扬尘污染问题等;VOC相关X处,占比 %,主要涉及加油站油气泄露、餐饮油烟污染等',
  sryFocusRegion: '聚焦区域',
  missionInfoList: [
    {
      missionCode: '',
@@ -129,7 +132,8 @@
      _airQulity: 'AQI:30(优)',
      mainFactor: '',
      _abnormalFactors: '',
      sceneCount: 0
      sceneCount: 0,
      _kilometres: '1000'
    }
  ],
  missionDetailList: [
@@ -147,6 +151,7 @@
          avgValue: 38
        }
      ],
      _airQulity: 'AQI:30(优)',
      aqi: 30,
      pollutionDegree: '优'
    }
@@ -174,6 +179,31 @@
        }
      ]
    }
  ],
  gridFusionByAQIList: [
    {
      pollutionDegree: '优',
      _areaDes: '走航区域大小',
      _gridDes: '100米正方形网格',
      _missionDes: '20250729、20250730两次',
      highRiskGridList: [
        {
          index: 1,
          factor: 'PM2.5',
          // 标准色网格图
          gridImgUrl1: '',
          // 对比色网格图
          gridImgUrl2: '',
          factorValue: 20,
          // 四至范围,顺序为最小经度,最大经度,最小纬度,最大纬度
          bounds: [121.4945, 121.4955, 31.2304, 31.2314],
          _boundsDes: '四至范围',
          // 涉及街镇
          town: '',
          _scenesDes: '涉及的污染场景'
        }
      ]
    }
  ]
};
@@ -183,7 +213,9 @@
    generateMissionList(params.value).then(() => {
      generateMissionDetail(params.value).then(() => {
        generateClueByRiskArea(params.value).then(() => {
          generateDocx();
          generateGridFusion(params.value).then(() => {
            generateDocx();
          });
        });
      });
    });
@@ -217,6 +249,7 @@
        return `${item.first}相关${item.second}处,占比 ${Math.round(item.third * 1000) / 10}%,主要涉及${getPollutingProblemTypes(item.first)}等`;
      })
      .join(';');
    templateParam.sryFocusRegion = res.data.focusRegion.join('、');
  });
}
@@ -228,18 +261,6 @@
      item._abnormalFactors = item.abnormalFactors
        .map((factor) => factor)
        .join('、');
      return item;
    });
  });
}
function generateMissionDetail(param) {
  return dataAnalysisApi.fetchMissionDetail(param).then((res) => {
    templateParam.missionDetailList = res.data.map((item, index) => {
      const t = formatDateTimeRange(item.startTime, item.endTime).split(' ');
      item._index = index + 1;
      item._startTime = t[0];
      item._time = t[1];
      item._kilometres = Math.round(item.kilometres / 1000);
      const keySceneMap = new Map();
@@ -256,16 +277,35 @@
            `${info.count}个${type}(${info.scenes.map((s) => s.name).join('、')})`
        )
        .join('、');
      item._dataStat = item.dataStatistics
        .map(
          (e) =>
            `${e.factor.des}(范围${e.minValue}–${e.maxValue}μg/m³,均值${e.avgValue}μg/m³)`
        )
        .join('、');
      item._focusScene =
        item.scenes.length > 0
          ? item.scenes.map((s) => s.name).join('、')
          : '道路交通密集区和部分施工周边';
      return item;
    });
  });
}
function generateMissionDetail(param) {
  return dataAnalysisApi.fetchMissionDetail(param).then((res) => {
    templateParam.missionDetailList = res.data.map((item, index) => {
      const t = formatDateTimeRange(item.startTime, item.endTime).split(' ');
      item._index = index + 1;
      item._startTime = t[0];
      item._time = t[1];
      item._kilometres = Math.round(item.kilometres / 1000);
      item._airQulity = `AQI:${item.aqi}(${item.pollutionDegree})`;
      const factorNames = radioOptions(TYPE0).map((e) => e.name);
      item._dataStatistics = item.dataStatistics.filter((e) => {
        return factorNames.indexOf(e.factor) != -1;
      });
      radioOptions(TYPE0).forEach((f) => {
        const _factor = item.dataStatistics.find((e) => e.factor == f.name);
        item[`avgValue_${f.name}`] = _factor?.avgValue ?? '-';
        item[`maxValue_${f.name}`] = _factor?.maxValue ?? '-';
        item[`minValue_${f.name}`] = _factor?.minValue ?? '-';
      });
      return item;
@@ -278,7 +318,7 @@
    templateParam.clueByAreaList = res.data.map((item, index) => {
      return {
        _index: index + 1,
        _area: item.sceneInfo.name + '周边',
        _area: `${item.sceneInfo.type}${item.sceneInfo.name}周边`,
        clueByFactorList: item.clueByFactorList.map((cbf) => {
          return {
            factor: cbf.factor,
@@ -348,63 +388,240 @@
  return images;
}
function handleMixClick() {
  const tags = [1, 2];
  const fetchGridData = () => {
    gridApi.mixUnderwayGridData(props.groupId, tags).then((res) => {
      const gridData = res.data.map((v) => {
        const data = v.pm25;
        const grid = gridCellList.value.find((g) => {
          return g.cellIndex == v.cellId;
function generateGridFusion(param) {
  return dataAnalysisApi.fetchGridFusion(param).then((res) => {
    const promiseList = [];
    templateParam.gridFusionByAQIList = [];
    res.data.forEach((item) => {
      const scenes = [];
      item.missionList.forEach((m) => {
        m.keyScene.map((s) => {
          if (scenes.indexOf(s.name) == -1) {
            scenes.push(s.name);
          }
        });
        const { color, nextColor, range, nextRange } =
          Legend.getStandardColorAndNext('PM25', data);
        const ratio = (data - range) / (nextRange - range);
        const _color = getColorBetweenTwoColors(
          color.map((v) => v * 255),
          nextColor.map((v) => v * 255),
          ratio
        );
        // // 根据遥测数据计算网格颜色
        //         const { color, nextColor, range, nextRange } =
        //           Legend.getCustomColorAndNext(data, min, max);
        //         const ratio = (data - range) / (nextRange - range);
        //         const _color = getColorBetweenTwoColors(
        //           color.map((v) => v * 255),
        //           nextColor.map((v) => v * 255),
        //           ratio
        //         );
        return {
          centerLng: grid.longitude,
          centerLat: grid.latitude,
          value: _color,
          coordinates: [
            [grid.point1Lon, grid.point1Lat],
            [grid.point2Lon, grid.point2Lat],
            [grid.point3Lon, grid.point3Lat],
            [grid.point4Lon, grid.point4Lat]
          ]
        };
      });
      // chartMapAmap.generateGridMap(gridData).then((url) => {
      //   gridBase64Url.value = url;
      // });
      gridBase64Url.value = chartMap.generateGridMap(gridData);
      const gfbAQI = {
        pollutionDegree: item.pollutionDegree,
        _areaDes: `走航区域经过${scenes.join('、')}`,
        _gridDes: `${item.gridLen}米正方形网格`,
        _missionDes: `${item.missionList.map((m) => m.missionCode).join('、')}共${item.missionList.length}次`
      };
      const _highRiskGridList = [];
      item.highRiskGridList.forEach((g, i) => {
        // const g = item.highRiskGridList[0];
        // const i = 0;
        const p = generateGridFusionImg(g.factorType, item.gridFusionList).then(
          (url) => {
            const { url1, url2 } = url;
            _highRiskGridList.push({
              index: i + 1,
              factor: g.factorType,
              // 标准色网格图
              gridImgUrl1: url1,
              // 对比色网格图
              gridImgUrl2: url2,
              factorValue: g.factorValue,
              // 四至范围,顺序为最小经度,最大经度,最小纬度,最大纬度
              _boundsDes: `经度${g.bounds[0]}至${g.bounds[1]},纬度${g.bounds[2]}至${g.bounds[3]}`,
              // 涉及街镇
              town: g.town,
              _scenesDes:
                g.highRiskScenes.length > 0
                  ? `涉及的污染场景包括${g.highRiskScenes.map((s) => s.name).join('、')}`
                  : '网格内可能存在隐藏风险源'
            });
          }
        );
        promiseList.push(p);
      });
      gfbAQI.highRiskGridList = _highRiskGridList;
      templateParam.gridFusionByAQIList.push(gfbAQI);
    });
  };
    return Promise.all(promiseList).then(() => {
      return templateParam.gridFusionByAQIList;
    });
    // templateParam.gridFusionByAQIList = res.data.map((item) => {
    //   const scenes = [];
    //   item.missionList.forEach((m) => {
    //     m.keyScene.map((s) => {
    //       if (scenes.indexOf(s.name) == -1) {
    //         scenes.push(s.name);
    //       }
    //     });
    //   });
    //   return {
    //     pollutionDegree: item.pollutionDegree,
    //     _areaDes: `走航区域经过${scenes.join('、')}`,
    //     _gridDes: `${item.gridLen}米正方形网格`,
    //     _missionDes: `${item.missionList.map((m) => m.missioncode).join('、')}${item.missionList.length}次`,
    //     highRiskGridList: item.highRiskGridList.map(async (g, i) => {
    //       const { url1, url2 } = await generateGridFusionImg(
    //         g.factorType,
    //         item.gridFusionList
    //       );
    //       return {
    //         index: i + 1,
    //         factor: g.factorType,
    //         // 标准色网格图
    //         gridImgUrl1: url1,
    //         // 对比色网格图
    //         gridImgUrl2: url2,
    //         factorValue: g.factorValue,
    //         // 四至范围,顺序为最小经度,最大经度,最小纬度,最大纬度
    //         _boundsDes: `经度${g.bounds[0]}至${g.bounds[1]},纬度${g.bounds[2]}至${g.bounds[3]}`,
    //         // 涉及街镇
    //         town: g.town,
    //         _scenesDes: g.highRiskScenes.map((s) => s.name).join('、')
    //       };
    //     })
    //   };
    // });
  });
}
  if (gridCellList.value.length == 0) {
    gridApi
      .fetchGridCell(props.groupId)
      .then((res) => {
        gridCellList.value = res.data;
      })
      .then(() => fetchGridData());
  } else {
    fetchGridData();
async function generateGridFusionImg(factorName, dataList) {
  let min = 1000000;
  let max = 0;
  dataList.forEach((v) => {
    min = Math.min(min, getGridDataDetailFactorValue(v.data, factorName));
    max = Math.max(max, getGridDataDetailFactorValue(v.data, factorName));
  });
  const gridDataStand = [];
  const gridDataCustom = [];
  dataList.forEach((v) => {
    const data = getGridDataDetailFactorValue(v.data, factorName);
    const grid = v.cell;
    // 标准色
    const {
      color: color1,
      nextColor: nextColor1,
      range: range1,
      nextRange: nextRange1
    } = Legend.getStandardColorAndNext(factorName, data);
    const ratio1 = (data - range1) / (nextRange1 - range1);
    const _color1 = getColorBetweenTwoColors(
      color1.map((v) => v * 255),
      nextColor1.map((v) => v * 255),
      ratio1
    );
    // 对比色
    const { color, nextColor, range, nextRange } = Legend.getCustomColorAndNext(
      data,
      min,
      max
    );
    const ratio = (data - range) / (nextRange - range);
    const _color = getColorBetweenTwoColors(
      color.map((v) => v * 255),
      nextColor.map((v) => v * 255),
      ratio
    );
    gridDataStand.push({
      centerLng: grid.longitude,
      centerLat: grid.latitude,
      value: _color1,
      coordinates: [
        [grid.point1Lon, grid.point1Lat],
        [grid.point2Lon, grid.point2Lat],
        [grid.point3Lon, grid.point3Lat],
        [grid.point4Lon, grid.point4Lat]
      ]
    });
    gridDataCustom.push({
      centerLng: grid.longitude,
      centerLat: grid.latitude,
      value: _color,
      coordinates: [
        [grid.point1Lon, grid.point1Lat],
        [grid.point2Lon, grid.point2Lat],
        [grid.point3Lon, grid.point3Lat],
        [grid.point4Lon, grid.point4Lat]
      ]
    });
  });
  const url1 = await chartMap.generateGridMap(gridDataStand);
  const url2 = await chartMap.generateGridMap(gridDataCustom);
  if (gridBase64Url.value == null) {
    gridBase64Url.value = url1;
  }
  return {
    url1,
    url2
  };
}
function handleMixClick({ tags = [10, 11], factorName = 'PM25' }) {
  generateGridFusion(params.value).then(() => {});
  // const fetchGridData = () => {
  //   gridApi.mixUnderwayGridData(props.groupId, tags).then((res) => {
  //     var min = 1000000;
  //     var max = 0;
  //     res.data.forEach((v) => {
  //       min = Math.min(min, getGridDataDetailFactorValue(v, factorName));
  //       max = Math.max(max, getGridDataDetailFactorValue(v, factorName));
  //     });
  //     const gridData = res.data.map((v) => {
  //       const data = getGridDataDetailFactorValue(v, factorName);
  //       const grid = gridCellList.value.find((g) => {
  //         return g.cellIndex == v.cellId;
  //       });
  //       // const { color, nextColor, range, nextRange } =
  //       //   Legend.getStandardColorAndNext('PM25', data);
  //       // const ratio = (data - range) / (nextRange - range);
  //       // const _color = getColorBetweenTwoColors(
  //       //   color.map((v) => v * 255),
  //       //   nextColor.map((v) => v * 255),
  //       //   ratio
  //       // );
  //       // 根据遥测数据计算网格颜色
  //       const { color, nextColor, range, nextRange } =
  //         Legend.getCustomColorAndNext(data, min, max);
  //       const ratio = (data - range) / (nextRange - range);
  //       const _color = getColorBetweenTwoColors(
  //         color.map((v) => v * 255),
  //         nextColor.map((v) => v * 255),
  //         ratio
  //       );
  //       return {
  //         centerLng: grid.longitude,
  //         centerLat: grid.latitude,
  //         value: _color,
  //         coordinates: [
  //           [grid.point1Lon, grid.point1Lat],
  //           [grid.point2Lon, grid.point2Lat],
  //           [grid.point3Lon, grid.point3Lat],
  //           [grid.point4Lon, grid.point4Lat]
  //         ]
  //       };
  //     });
  //     // chartMapAmap.generateGridMap(gridData).then((url) => {
  //     //   gridBase64Url.value = url;
  //     // });
  //     chartMap.generateGridMap(gridData).then((url) => {
  //       gridBase64Url.value = url;
  //     });
  //   });
  // };
  // if (gridCellList.value.length == 0) {
  //   gridApi
  //     .fetchGridCell(props.groupId)
  //     .then((res) => {
  //       gridCellList.value = res.data;
  //     })
  //     .then(() => fetchGridData());
  // } else {
  //   fetchGridData();
  // }
}
function generateDocx() {