You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于后端due对象的进度条进度计算实现方案咨询

进度条组件的进度百分比计算逻辑完善

需求背景

已完成进度条组件开发,需基于后端返回的due对象实现进度百分比计算逻辑,用于单元摘要生成的实时进度跟踪。

后端返回的due对象结构

due: {
  coref: 1,
  extract: 4,
  keyconcepts: 1,
  question-text-cmas: 1,
  question-text-fibq: 1,
  question-text-mcq: 1,
  rank: 1,
  summary-1: 1,
  text: 1,
  topic: 1
}

字段规则说明

  • 属性处理完成后会被后端从due对象中移除
  • 属性值为1表示待处理,大于1表示处理中

现有初始实现代码

const propertiesRef = useRef({
    extract: { curr: 0, max: 15 },
    keyconcepts: { curr: 0, max: 20 },
    question: {
        cmas: { curr: 0, max: 10 },
        fibq: { crr: 0, max: 10 }, // 拼写错误:crr -> curr
        mcq: { curr: 0, max: 10 },
    },
    rank: { curr: 0, max: 5 },
    summary: { curr: 0, max: 15 },
    text: { curr: 0, max: 10 },
    topic: { curr: 0, max: 5 },
    allOver: 0,
}); // 存储进度数据

const getProcess = async () => {
    let conditionLoop = true;
    do {
        setTimeout(async () => {
            await axios
                .get(`Route`, { withCredentials: true }) // 获取due对象
                .then((res) => {
                    conditionLoop = res.data.due;
                    if (res?.data?.due) {
                        for (let key in propertiesRef.current) {
                            if (res.data.due.hasOwn(key)) {
                                console.log(key, res.data.due[key]);
                            }
                            if (res.data.due.hasOwn("question-text-cmas")) {
                                console.log(res.data.due);
                            }
                            if (res.data.due.hasOwn("question-text-fibq")) {
                                console.log(res.data.due);
                            }
                            if (res.data.due.hasOwn("question-text-mcq")) {
                                console.log(res.data.due);
                            }
                        }
                    } else {
                        propertiesRef.current.allOver = 1;
                        conditionloop=false; // 拼写错误:conditionloop -> conditionLoop
                    }
                    console.log(propertiesRef.current);
                });
        }, 2000);
    } while (conditionLoop);
};

完善后的实现逻辑与代码

核心改进方向

  1. 修复原代码拼写错误,避免逻辑异常
  2. 建立due字段与本地进度项的映射关系,统一处理普通字段和嵌套字段
  3. 实现基于due状态的进度更新逻辑(待处理/处理中/已完成)
  4. 计算总进度百分比,适配进度条组件
  5. 优化轮询逻辑,避免定时器堆积,增加错误处理

完整代码

const propertiesRef = useRef({
    extract: { curr: 0, max: 15 },
    keyconcepts: { curr: 0, max: 20 },
    question: {
        cmas: { curr: 0, max: 10 },
        fibq: { curr: 0, max: 10 }, // 修正拼写错误
        mcq: { curr: 0, max: 10 },
    },
    rank: { curr: 0, max: 5 },
    summary: { curr: 0, max: 15 },
    text: { curr: 0, max: 10 },
    topic: { curr: 0, max: 5 },
    allOver: 0,
});

// 预计算所有进度项的总max值
const totalMax = useMemo(() => {
  const { question, ...rest } = propertiesRef.current;
  const questionMax = Object.values(question).reduce((sum, item) => sum + item.max, 0);
  const restMax = Object.values(rest)
    .filter(item => typeof item === 'object')
    .reduce((sum, item) => sum + item.max, 0);
  return questionMax + restMax;
}, []);

// 建立due字段与本地进度项的映射
const fieldMapping = {
  extract: 'extract',
  keyconcepts: 'keyconcepts',
  'question-text-cmas': ['question', 'cmas'],
  'question-text-fibq': ['question', 'fibq'],
  'question-text-mcq': ['question', 'mcq'],
  rank: 'rank',
  'summary-1': 'summary',
  text: 'text',
  topic: 'topic',
  coref: null, // coref无对应进度项,忽略
};

const getProcess = async () => {
    let conditionLoop = true;
    let timerId;

    // 进度更新逻辑
    const updateProgress = (due) => {
      Object.keys(fieldMapping).forEach(field => {
        const target = fieldMapping[field];
        if (!target) return;

        // 获取对应进度项
        let progressItem;
        if (Array.isArray(target)) {
          progressItem = propertiesRef.current[target[0]][target[1]];
        } else {
          progressItem = propertiesRef.current[target];
        }

        if (due.hasOwnProperty(field)) {
          const status = due[field];
          if (status === 1) {
            // 待处理:进度重置为0
            progressItem.curr = 0;
          } else {
            // 处理中:按步长递增进度,直到达到max
            if (progressItem.curr < progressItem.max) {
              progressItem.curr += 1; // 可根据实际情况调整步长
            }
          }
        } else {
          // 已完成:进度直接设为max
          progressItem.curr = progressItem.max;
        }
      });

      // 计算总进度百分比
      const { question, ...rest } = propertiesRef.current;
      const questionCurr = Object.values(question).reduce((sum, item) => sum + item.curr, 0);
      const restCurr = Object.values(rest)
        .filter(item => typeof item === 'object')
        .reduce((sum, item) => sum + item.curr, 0);
      const totalCurr = questionCurr + restCurr;
      const progressPercent = Math.round((totalCurr / totalMax) * 100);

      // 检查是否全部完成
      if (progressPercent === 100) {
        propertiesRef.current.allOver = 1;
        conditionLoop = false;
        clearTimeout(timerId);
      }
    };

    // 轮询逻辑
    while (conditionLoop) {
      try {
        const res = await axios.get(`Route`, { withCredentials: true });
        const due = res.data.due;

        if (due) {
          updateProgress(due);
        } else {
          // 后端无返回due,直接标记全部完成
          propertiesRef.current.allOver = 1;
          conditionLoop = false;
        }

        // 等待2秒后发起下一次请求
        await new Promise(resolve => timerId = setTimeout(resolve, 2000));
      } catch (error) {
        console.error('获取进度失败:', error);
        // 出错后停止轮询
        conditionLoop = false;
        clearTimeout(timerId);
      }
    }
};

关键优化点

  1. 修正原代码中的拼写错误,避免逻辑异常
  2. 使用while循环结合Promise实现正确轮询,避免定时器堆积
  3. 通过字段映射统一处理嵌套字段(如question-text-cmas对应question.cmas)
  4. 基于due字段的状态(1/大于1/不存在)分别更新进度
  5. 自动计算总进度百分比,直接适配进度条组件
  6. 添加错误处理,避免请求失败后无限循环

内容的提问来源于stack exchange,提问作者Yovel Hadad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:20:33