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

如何优雅实现FormIO表格元素的列数据求和?

计算FormIO表格指定列数值总和的优化方案

我需要计算FormIO表格中某列的数值总和,当前使用的脚本虽能实现功能,但代码冗余度很高:

if(data['personesAtesesNoBinari17'] >= 0 || 
  data['personesAtesesNoBinari1631'] >= 0 || 
  data['personesAtesesNoBinari3066'] >= 0 || 
  data['personesAtesesNoBinari67'] >= 0){
  
if(data['personesAtesesNoBinari17'] === undefined){
    data['personesAtesesNoBinari17'] = 0;
  }
  if(data['personesAtesesNoBinari1631'] === undefined){
    data['personesAtesesNoBinari1631'] = 0;
  }
  if(data['personesAtesesNoBinari3066'] === undefined){
    data['personesAtesesNoBinari3066'] = 0;
  }
  if(data['personesAtesesNoBinari67'] === undefined){
    data['personesAtesesNoBinari67'] = 0;
  }
  data['personesAtesesNoBinariTotal2'] = 
    data['personesAtesesNoBinari17'] +
    data['personesAtesesNoBinari1631'] + 
    data['personesAtesesNoBinari3066'] + 
    data['personesAtesesNoBinari67'];

}else{
  data['personesAtesesNoBinariTotal2'] = 0;
}

除输出项data['personesAtesesVoluntariatTotal1']外,每个data['']都是含数字的单元格。

我曾尝试以下更简洁的循环脚本,该脚本在Visual Studio Code中可正常运行,但在FormIO环境下无法生效:

let result = 0;

for (let i = 1; i < (data['tableName'].rows.length-1); i++)
{
        result += parseInt(data['tableName'].rows[i].cells[1]);
}
data['outputName'] = result;

以下是该表格的JSON配置:

{  
  "label": "Table",  
  "cellAlignment": "left",  
  "customClass": "standardTable tableSpacing",  
  "bordered": true,  
  "hover": true,  
  "key": "table22",  
  "type": "table",  
  "numRows": 6,  
  "numCols": 4,  
  "input": false,  
  "tableView": false,  
  "rows": [  
    [  
      {  
        "components": []  
      },  
      {  
        "components": [  
          {  
            "label": "HTML",  
            "attrs": [  
              {  
                "attr": "",  
                "value": ""  
              }  
            ],  
            "content": "<div style=\"text-align:center ; background-color : #900000 ; height: 100%;\"><h3 style=\"color:white;font-weight: bold;\">No binari</h3></div>",  
            "refreshOnChange": false,  
            "key": "html154",  
            "type": "htmlelement",  
            "input": false,  
            "tableView": false  
          }  
        ]  
      }  
    ],  
    [  
      {  
        "components": [  
          {  
            "label": "HTML",  
            "attrs": [  
              {  
                "attr": "",  
                "value": ""  
              }  
            ],  
            "content": "<div>Persones de menys de 16 anys</div>",  
            "refreshOnChange": false,  
            "key": "html155",  
            "type": "htmlelement",  
            "input": false,  
            "tableView": false  
          }  
        ]  
      },  
      {  
        "components": [  
          {  
            "label": "Number",  
            "hideLabel": true,  
            "mask": false,  
            "tableView": false,  
            "delimiter": false,  
            "requireDecimal": false,  
            "inputFormat": "plain",  
            "truncateMultipleSpaces": false,  
            "key": "personesAtesesNoBinari17",  
            "type": "number",  
            "input": true  
          }  
        ]  
      }  
    ],  
    [  
      {  
        "components": [  
          {  
            "label": "HTML",  
            "attrs": [  
              {  
                "attr": "",  
                "value": ""  
              }  
            ],  
            "content": "<div>Persones entre 16 a 29 anys</div>",  
            "refreshOnChange": false,  
            "key": "html156",  
            "type": "htmlelement",  
            "input": false,  
            "tableView": false  
          }  
        ]  
      },  
      {  
        "components": [  
          {  
            "label": "Number",  
            "hideLabel": true,  
            "mask": false,  
            "tableView": false,  
            "delimiter": false,  
            "requireDecimal": false,  
            "inputFormat": "plain",  
            "truncateMultipleSpaces": false,  
            "key": "personesAtesesNoBinari1631",  
            "type": "number",  
            "input": true  
          }  
        ]  
      }  
    ],  
    [  
      {  
        "components": [  
          {  
            "label": "HTML",  
            "attrs": [  
              {  
                "attr": "",  
                "value": ""  
              }  
            ],  
            "content": "<div>Persones entre 30 i 64 anys</div>",  
            "refreshOnChange": false,  
            "key": "html157",  
            "type": "htmlelement",  
            "input": false,  
            "tableView": false  
          }  
        ]  
      },  
      {  
        "components": [  
          {  
            "label": "Number",  
            "hideLabel": true,  
            "mask": false,  
            "tableView": false,  
            "delimiter": false,  
            "requireDecimal": false,  
            "inputFormat": "plain",  
            "truncateMultipleSpaces": false,  
            "key": "personesAtesesNoBinari3066",  
            "type": "number",  
            "input": true  
          }  
        ]  
      }  
    ],  
    [  
      {  
        "components": [  
          {  
            "label": "HTML",  
            "attrs": [  
              {  
                "attr": "",  
                "value": ""  
              }  
            ],  
            "content": "<div>Persones de 65 anys o més</div>",  
            "refreshOnChange": false,  
            "key": "html158",  
            "type": "htmlelement",  
            "input": false,  
            "tableView": false  
          }  
        ]  
      },  
      {  
        "components": [  
          {  
            "label": "Number",  
            "hideLabel": true,  
            "mask": false,  
            "tableView": false,  
            "delimiter": false,  
            "requireDecimal": false,  
            "inputFormat": "plain",  
            "truncateMultipleSpaces": false,  
            "key": "personesAtesesNoBinari67",  
            "type": "number",  
            "input": true  
          }  
        ]  
      }  
    ],  
    [  
      {  
        "components": [  
          {  
            "label": "HTML",  
            "attrs": [  
              {  
                "attr": "",  
                "value": ""  
              }  
            ],  
            "content": "<div>Total</div>",  
            "refreshOnChange": false,  
            "key": "html159",  
            "type": "htmlelement",  
            "input": false,  
            "tableView": false  
          }  
        ]  
      },  
      {  
        "components": [  
          {  
            "label": "Number",  
            "hideLabel": true,  
            "mask": false,  
            "disabled": true,  
            "tableView": false,  
            "defaultValue": 0,  
            "delimiter": false,  
            "requireDecimal": false,  
            "inputFormat": "plain",  
            "truncateMultipleSpaces": false,  
            "key": "personesAtesesNoBinariTotal2",  
            "logic": [  
              {  
                "name": "SumatoriPersonesAtesesNoBinariTotal",  
                "trigger": {  
                  "type": "javascript",  
                  "javascript": "if(data['personesAtesesNoBinari17'] >= 0 || data['personesAtesesNoBinari1631'] >= 0 || data['personesAtesesNoBinari3066'] >= 0 || data['personesAtesesNoBinari67'] >= 0){
  if(data['personesAtesesNoBinari17'] === undefined){
    data['personesAtesesNoBinari17'] = 0;
  }
  if(data['personesAtesesNoBinari1631'] === undefined){
    data['personesAtesesNoBinari1631'] = 0;
  }
  if(data['personesAtesesNoBinari3066'] === undefined){
    data['personesAtesesNoBinari3066'] = 0;
  }
  if(data['personesAtesesNoBinari67'] === undefined){
    data['personesAtesesNoBinari67'] = 0;
  }
  data['personesAtesesNoBinariTotal2'] = data['personesAtesesNoBinari17'] + data['personesAtesesNoBinari1631'] + data['personesAtesesNoBinari3066'] + data['personesAtesesNoBinari67'];
}else{
  data['personesAtesesNoBinariTotal2'] = 0;
}"  
                },  
                "actions": [  
                  {  
                    "name": "SumatoriPersonesAtesesNoBinariTotal",  
                    "type": "value",  
                    "value": "value = data['personesAtesesNoBinariTotal2'];"  
                  }  
                ]  
              }  
            ],  
            "type": "number",  
            "personesAtesesNoBinariTotal2": 0,  
            "personesAtesesNoBinariTotal": 0,  
            "input": true  
          }  
        ]  
      }  
    ]  
  ]
}

优化方案

方案一:简化现有字段求和逻辑

将需要求和的字段放入数组,使用reduce方法遍历计算总和,自动处理undefined或非数值的情况,代码简洁且功能完整:

// 定义要求和的字段列表
const targetFields = [
  'personesAtesesNoBinari17',
  'personesAtesesNoBinari1631',
  'personesAtesesNoBinari3066',
  'personesAtesesNoBinari67'
];

// 计算总和,自动将无效值转为0
data['personesAtesesNoBinariTotal2'] = targetFields.reduce((sum, fieldKey) => {
  const val = data[fieldKey];
  return sum + (typeof val === 'number' && !isNaN(val) ? val : 0);
}, 0);

方案二:解决循环脚本失效问题

原循环脚本失效的核心原因:FormIO中表格内的用户输入值不会存储在表格组件的rows属性里,而是直接以每个单元格组件的key作为属性挂载在data对象下。所以无法通过data['tableName'].rows[i].cells[1]获取值。

如果想要动态遍历目标列的字段(比如字段可能后续新增),可以先提取表格配置中目标列的所有数字组件key,再求和:

// 获取表格组件的配置(假设在FormIO逻辑中可通过组件实例获取,或提前定义列的组件key)
const tableConfig = data._schema.components.find(comp => comp.key === 'table22');
// 提取第二列(索引1)的所有数字组件key
const columnFields = tableConfig.rows
  .slice(1, -1) // 跳过表头和总计行
  .map(row => row[1].components[0].key);

// 计算总和
data['personesAtesesNoBinariTotal2'] = columnFields.reduce((sum, fieldKey) => {
  const val = data[fieldKey];
  return sum + (typeof val === 'number' && !isNaN(val) ? val : 0);
}, 0);

注意:如果在FormIO的逻辑脚本中无法直接获取_schema,建议直接使用方案一的字段数组方式,更稳定可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 11:36:59