基于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
相关产品推荐
相关产品推荐

