guonan
2025-07-03 ca74058a77d7c9000a485502a2b53fbef5807ef5
src/views/left/CitySim.vue
@@ -447,15 +447,16 @@
/**
 * 数据处理主函数
 * @param {Array} data - 解析后的原始数据数组,每个元素是一个对象
 */
const processData = (data) => {
  // 检查空数据
  // 检查是否为空数据
  if (data.length === 0) {
    ElMessage.warning("文件内容为空!");
    return;
  }
  // 匹配字段名
  // 匹配列名(例如“时间”、“小时雨强”)
  const columns = matchColumns(data[0]);
  // 校验必要字段是否存在
@@ -475,22 +476,18 @@
    return;
  }
  // 时间列校验是否升序
  // 校验时间列是否升序排列
  if (!isTimeColumnSorted(data, columns.time)) {
    ElMessage.error("时间列必须按升序排列!");
    forms.fileList = [];
    return;
  }
  // 提取单位
  forms.intensityUnit = extractUnitFromHeader(columns.intensity);
  // 提取单位(如 mm/h),若没有则设为空字符串
  forms.intensityUnit = extractUnitFromHeader(columns.intensity) || "";
  if (!forms.intensityUnit) {
    forms.intensityUnit = "";
  }
  // 转换 key 名并转换数值类型
  forms.rainFallList = data.map((row) => ({
  // 将原始数据转换为统一结构的对象数组
  const rawRainFallList = data.map((row) => ({
    time: row[columns.time],
    intensity: parseFloat(row[columns.intensity]),
    total: columns.totalRainfall
@@ -498,21 +495,44 @@
      : undefined,
  }));
  console.log(forms.rainFallList, "解析后的降雨数据");
  // 更新 forms.rainFallList,可用于图表显示等用途
  forms.rainFallList = rawRainFallList;
  // 计算统计信息
  const firstTime = parseDateTime(data[0][columns.time]);
  const lastTime = parseDateTime(data[data.length - 1][columns.time]);
  // 判断是否为整小时数据(即相邻时间间隔是否为整小时)
  const isHourlyData = checkIfHourlyData(rawRainFallList);
  let hourlyRainfallList = [];
  if (!isHourlyData) {
    // 如果不是整小时数据,按小时进行聚合处理
    hourlyRainfallList = aggregateToHourlyRainfall(rawRainFallList);
    console.log(hourlyRainfallList, "修正后的小时雨强");
  } else {
    // 如果是整小时数据,直接使用原始雨强值
    hourlyRainfallList = rawRainFallList.map((item) => ({
      time: item.time,
      intensity: item.intensity,
    }));
  }
  // 计算起始时间和结束时间(毫秒数)
  const firstTime = parseDateTime(hourlyRainfallList[0]?.time);
  const lastTime = parseDateTime(
    hourlyRainfallList[hourlyRainfallList.length - 1]?.time
  );
  // 计算持续时间(单位:小时)
  const durationSeconds = Math.floor((lastTime - firstTime) / 1000);
  forms.duration = (durationSeconds / 3600).toFixed(2); // 小时
  forms.duration = (durationSeconds / 3600).toFixed(2); // 单位:小时
  // 找出最大小时雨强
  const maxIntensity = Math.max(
    ...data
      .map((row) => parseFloat(row[columns.intensity]))
      .filter((v) => !isNaN(v))
    ...hourlyRainfallList.map((item) => item.intensity).filter((v) => !isNaN(v))
  ).toFixed(2);
  forms.intensity = maxIntensity;
  // 若有总降雨量列,取出最后一个值作为总降雨量
  if (columns.totalRainfall) {
    const lastTotal = parseFloat(data[data.length - 1][columns.totalRainfall]);
    forms.rainfall = isNaN(lastTotal) ? 0 : lastTotal.toFixed(2);
@@ -521,56 +541,80 @@
  }
};
// // 处理数据
// const processData = (data) => {
//   // 1. 检查数据是否为空
//   if (data.length === 0) {
//     ElMessage.warning("文件内容为空!");
//     return;
//   }
/**
 * 检查数据是否为整小时记录
 * @param {Array} rainList - 原始降雨数据列表,每个元素包含 time 和 intensity
 * @returns {boolean} - 是否为整小时数据
 */
function checkIfHourlyData(rainList) {
  if (rainList.length < 2) return true; // 只有一个点,默认视为整小时数据
//   // 2. 获取表头(第一列是时间列)
//   const tableColumns = Object.keys(data[0]);
//   const timeColumn = tableColumns[0]; // 假设第一列是时间
  for (let i = 1; i < rainList.length; i++) {
    // 解析两个相邻时间点
    const time1 = parseDateTime(rainList[i - 1].time);
    const time2 = parseDateTime(rainList[i].time);
//   // 3. 校验时间列是否按升序排列
//   if (!isTimeColumnSorted(data, timeColumn)) {
//     ElMessage.error("时间列必须按升序排列!");
//     forms.fileList = [];
//     return; // 终止处理
//   }
    // 计算时间差(分钟)
    const diffMinutes = Math.abs(time2 - time1) / (1000 * 60);
//   const intensityColumn = tableColumns[1]; // 雨强列(如 "小时雨强(mm/h)")
//   // console.log(intensityColumn, "intensityColumnintensityColumnintensityColumn");
//   // 3. 提取第二列的单位(如 "(mm/h)" → "mm/h")
//   const intensityUnit = extractUnitFromHeader(intensityColumn);
//   forms.intensityUnit = intensityUnit; // 存储单位(可选)
//   console.log(forms.intensityUnit,'aaaaaaaaaaaaaaaaaaaaa')
    // 如果时间差不是整小时(不能被60整除),则不是整小时数据
    if (diffMinutes % 60 !== 0) {
      return false;
    }
  }
//   // 4. 如果校验通过,继续处理数据
//   forms.rainFallList = transformKeys(data);
//   console.log(forms.rainFallList, "data");
  return true;
}
//   // 5. 计算降雨时长、雨强、累计雨量(原逻辑)
//   const firstTime = parseDateTime(data[0][timeColumn]);
//   const lastTime = parseDateTime(data[data.length - 1][timeColumn]);
//   const timeDuration = Math.floor((lastTime - firstTime) / 1000);
//   // 降雨时长
//   forms.duration = (timeDuration / 3600).toFixed(2);
//   // 降雨强度
//   const maxValue = Math.max(
//     ...data.map((row) => {
//       const value = parseFloat(row[tableColumns[1]]);
//       return isNaN(value) ? -Infinity : value;
//     })
//   ).toFixed(2);
//   forms.intensity = maxValue;
/**
 * 将任意时间粒度的雨强数据,按小时聚合为“小时雨强”
 * @param {Array} rainList - 原始数据列表,每个元素包含 time 和 intensity
 * @returns {Array} - 按小时分组的聚合结果
 */
function aggregateToHourlyRainfall(rainList) {
  const grouped = {}; // 用于临时存储每个小时的数据
//   const lastValue = data[data.length - 1][tableColumns[2]];
//   forms.rainfall = lastValue;
  for (const item of rainList) {
    // 解析时间字符串为时间戳
    const timestamp = parseDateTime(item.time);
// };
    // 如果解析失败,跳过当前项
    if (isNaN(timestamp)) {
      console.warn("无效的时间格式,已跳过", item.time);
      continue;
    }
    // 将时间戳转为 Date 对象以便操作日期
    const dt = new Date(timestamp);
    // 构造年月日+小时键(如:"2024-08-25 14")
    const year = String(dt.getFullYear()).padStart(4, "0");
    const month = String(dt.getMonth() + 1).padStart(2, "0"); // 注意月份从0开始
    const date = String(dt.getDate()).padStart(2, "0");
    const hour = String(dt.getHours()).padStart(2, "0");
    const hourKey = `${year}-${month}-${date} ${hour}`;
    // 初始化该小时的聚合对象
    if (!grouped[hourKey]) {
      grouped[hourKey] = {
        time: `${hourKey}:00:00`, // 标准化为整点时间
        intensity: 0,
      };
    }
    // 累加该小时内所有雨强值
    grouped[hourKey].intensity += item.intensity;
  }
  // 将聚合结果转为数组并保留两位小数
  const result = Object.values(grouped).map((item) => ({
    time: item.time,
    intensity: Number(item.intensity.toFixed(2)),
  }));
  return result;
}
/**
 * 解析日期时间字符串或Excel数字日期,返回时间戳(毫秒数)
 * @param {string|number} dateString - 日期字符串或Excel数字日期