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

基于ExtJS的Rally Excel导入:更新含多选选项的已有特性方案咨询

实现Excel导入Rally并更新特性属性的后续步骤

既然你已经搞定了Excel文件上传的部分,接下来核心就是解析Excel数据、匹配Rally中已有特性、处理多选字段、批量更新Rally数据这几个关键环节,我一步步给你拆解:

1. 解析上传的Excel文件

在ExtJS里,你可以用SheetJS/xlsx(直接引入前端即可,不用依赖后端中转)来解析Excel内容:

  • 先获取上传的文件对象,通过FileReader读取成ArrayBuffer再解析:
// 假设你已从filefield组件拿到上传的file对象
const reader = new FileReader();
reader.onload = function(e) {
  const data = new Uint8Array(e.target.result);
  const workbook = XLSX.read(data, { type: 'array' });
  // 取第一个工作表的数据
  const worksheet = workbook.Sheets[workbook.SheetNames[0]];
  // 转成JSON格式,方便后续处理
  const excelData = XLSX.utils.sheet_to_json(worksheet);
  // 进入下一步数据处理
  processExcelData(excelData);
};
reader.readAsArrayBuffer(file);
  • 注意要让Excel表头和你要更新的Rally字段对应,比如表头设为FeatureID(对应Rally的FormattedID)、MultiSelectField(对应你的多选字段),这样解析后每条数据的属性能直接匹配。

2. 匹配Rally中的已有特性

你需要通过Excel里的唯一标识(比如Feature的FormattedID,如F123)去Rally查询对应的Feature记录:

  • 用Rally的SDK Rally.data.wsapi.Store来批量查询:
function processExcelData(excelData) {
  const rallyStore = Ext.create('Rally.data.wsapi.Store', {
    model: 'Feature',
    // 按需获取需要更新的字段,ObjectID是更新必备的
    fetch: ['FormattedID', 'YourMultiSelectField', 'ObjectID'],
    filters: [
      {
        property: 'FormattedID',
        operator: 'in',
        value: excelData.map(item => item.FeatureID) // 把Excel里的所有FeatureID拼成查询条件
      }
    ]
  });

  rallyStore.load({
    callback: function(records, operation, success) {
      if (success) {
        // 把查询到的Rally记录按FormattedID做映射,方便后续快速匹配
        const featureMap = {};
        records.forEach(record => {
          featureMap[record.get('FormattedID')] = record;
        });
        // 开始处理每条Excel数据的更新
        updateFeatures(excelData, featureMap);
      } else {
        Ext.Msg.alert('错误', '查询Rally特性失败:' + operation.error.message);
      }
    }
  });
}

3. 处理多选字段的特殊逻辑

Rally中的多选字段(比如自定义多选下拉)存储的是对象数组(每个对象包含_ref和Name属性),而Excel里的多选值一般是逗号分隔的字符串(比如"选项A,选项B"),所以需要做格式转换:

  • 先获取该多选字段的所有可选值元数据,拿到每个选项的_ref:
// 获取指定多选字段的选项映射(名称对应_ref)
function getMultiSelectOptions(fieldName, callback) {
  const fieldStore = Ext.create('Rally.data.wsapi.FieldStore', {
    model: 'Feature',
    fetch: ['AllowedValues']
  });

  fieldStore.load({
    callback: function(fields) {
      const targetField = fields.find(field => field.get('Name') === fieldName);
      if (targetField) {
        const allowedValues = targetField.get('AllowedValues');
        const optionMap = {};
        allowedValues.forEach(opt => {
          optionMap[opt.Name] = opt._ref;
        });
        callback(optionMap);
      } else {
        Ext.Msg.alert('错误', '找不到指定的多选字段:' + fieldName);
      }
    }
  });
}
  • 然后在更新时,把Excel里的逗号分隔字符串转成Rally需要的格式:
function updateFeatures(excelData, featureMap) {
  // 先获取多选字段的选项映射
  getMultiSelectOptions('YourMultiSelectField', function(optionMap) {
    const updatePromises = [];
    excelData.forEach(item => {
      const feature = featureMap[item.FeatureID];
      if (!feature) {
        console.warn(`未找到特性:${item.FeatureID},跳过更新`);
        return;
      }
      // 处理多选值:拆分字符串并转成Rally要求的对象数组
      const multiSelectValues = item.MultiSelectField.split(',')
        .map(name => {
          const trimmedName = name.trim();
          return { _ref: optionMap[trimmedName] };
        })
        .filter(opt => opt._ref); // 过滤掉不存在的无效选项

      // 准备要更新的数据
      const updateData = {
        YourMultiSelectField: multiSelectValues
        // 其他需要更新的字段可以在这里添加
      };

      // 创建更新的Promise,方便批量处理结果
      const updatePromise = new Promise((resolve, reject) => {
        feature.set(updateData);
        feature.save({
          callback: function(record, operation) {
            if (operation.success) {
              resolve(`特性${item.FeatureID}更新成功`);
            } else {
              reject(`特性${item.FeatureID}更新失败:${operation.error.message}`);
            }
          }
        });
      });
      updatePromises.push(updatePromise);
    });

    // 等待所有更新完成,汇总结果提示用户
    Promise.allSettled(updatePromises).then(results => {
      const successCount = results.filter(r => r.status === 'fulfilled').length;
      const failCount = results.filter(r => r.status === 'rejected').length;
      const failMessages = results.filter(r => r.status === 'rejected').map(r => r.reason).join('\n');
      let message = `更新完成:成功${successCount}条,失败${failCount}条`;
      if (failCount > 0) {
        message += '\n失败详情:\n' + failMessages;
      }
      Ext.Msg.alert('更新结果', message);
    });
  });
}

4. 关键注意事项

  • 字段API名称:Rally中的自定义字段API名通常以c_开头(比如c_YourMultiSelectField),你可以在Rally的「设置→自定义字段」里查看准确的API名称,别用显示名去调用接口
  • 权限限制:确保当前登录用户有Feature的编辑权限,否则更新会直接失败
  • 批量限流:如果要更新大量数据,建议添加分批延迟处理,避免触发Rally的API请求频率限制
  • 测试验证:先拿2-3条数据做测试,确认多选字段转换正确、更新后Rally中的特性属性符合预期再批量执行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:49:48