JavaScript基于JSON生成表格并邮件发送为空问题解决
邮件中表格为空问题的解决方案:正确填充JSON数据到格式化表格
问题背景
我用JavaScript编写了循环添加表格的函数,期望将JSON数据填充到格式化表格后发送至邮箱,但发送的邮件中表格始终为空。需求是自动将所有数据插入表格,最终效果需符合指定样式(忽略exp和status列)。
问题根源
- 前端JS逻辑缺陷:无效的条件判断(
data[j].org != data[j].org永远为假)导致数据遍历异常,且表格标签未正确闭合,邮件客户端无法解析无效HTML结构。 - 依赖客户端JS执行:邮件客户端普遍禁用JavaScript,前端动态生成表格的逻辑完全无法生效。
- HTML与样式问题:重复使用ID、冲突的CSS类、不完整的标签结构,导致样式失效或渲染混乱。
解决方案
核心思路:后端预生成完整HTML表格
避免依赖邮件客户端的JS执行,直接在后端完成数据分组、表格HTML生成,再注入到模板中发送。
修正后的代码
后端处理函数
async function listItems(){ try { console.log('========data scan======='); const data = await docClient.scan( params ).promise(); // 按org字段分组数据,避免重复生成表头 const groupedData = data.Items.reduce((acc, item) => { if (!acc[item.org]) { acc[item.org] = []; } acc[item.org].push(item); return acc; }, {}); // 生成完整的表格HTML内容 let tableHtml = ''; Object.keys(groupedData).forEach(org => { // 生成组织专属表头 tableHtml += ` <thead> <tr><th class="tc-head" colspan="3">${org}</th></tr> <tr> <td class="tc-row">ID</td> <td class="tc-row">EndPoint</td> <td class="tc-row">Status</td> </tr> </thead> <tbody>`; // 生成该组织下的数据行 groupedData[org].forEach(item => { const statusClass = item.online ? 'green' : 'red'; tableHtml += ` <tr> <td class="tc-col">${item.id}</td> <td class="tc-col">${item.endpoint}</td> <td class="tc-col ${statusClass}">${item.online ? '在线' : '离线'}</td> </tr>`; }); tableHtml += `</tbody>`; }); // 读取HTML模板并替换表格占位符 let scanning = fs.readFileSync(`./table.html`, "utf8"); scanning = scanning.replace('{{tableContent}}', tableHtml); const filter = data.Items.filter( item => !item.online && item.exp <= Math.floor( (new Date()).getTime() / 1000.0 ) ); console.log('filter', filter); if (filter.length >= 1) { const to = 'myemail@gmail.com'; const subject = 'EV Scanning Data!!!'; // 直接发送预生成好的完整HTML邮件 const send = await sendEmail(to, subject, scanning); console.log('send', send, 'data', data); // 改用Promise批量更新数据,确保异步操作完成 await Promise.all(filter.map(item => { const putItemParams = { TableName: tableListStation, Item: { id: item.id, org: item.org, online: item.online, endpoint: item.endpoint, exp: Math.floor( (new Date(Date.now() + 172800000)).getTime() / 1000.0 ), updatedAt: momentGetDateJKT() } }; console.log('item params', putItemParams); return docClient.put(putItemParams).promise(); })); } return data; } catch (err) { return err; } }
HTML模板(table.html)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Charger Station Status</title> <style type="text/css"> .tc { border-collapse: collapse; border-color: #9abad9; border-spacing: 0; width: 100%; margin-bottom: 20px; } .tc td { background-color: #ebf5ff; border-color: #9abad9; border-style: solid; border-width: 1px; color: #444; font-family: Arial, sans-serif; font-size: 14px; padding: 10px 5px; word-break: normal; } .tc th { background-color: #409cff; border-color: #9abad9; border-style: solid; border-width: 1px; color: #fff; font-family: Arial, sans-serif; font-size: 14px; padding: 10px 5px; } .tc .tc-row { background-color: #efefef; text-align: center; font-weight: bold; } .tc .tc-head { background-color: #9aff99; font-weight: bold; text-align: center; } .tc .tc-col{ text-align: left; } .red{ background-color: #ffcccc; color: #cc0000; } .green{ background-color: #ccffcc; color: #006600; } @media screen and (max-width: 767px) { .tc-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; } } </style> </head> <body> <header>EV Charger Station Status</header> <div class="tc-wrap"> <table class="tc"> {{tableContent}} </table> </div> </body> </html>
关键修改说明
- 数据分组优化:用
reduce按org分组,避免重复生成表头,简化逻辑。 - 后端生成HTML:完全绕过客户端JS,直接生成可被邮件客户端解析的完整表格。
- 样式修复:删除重复的
.green类,用状态类代替重复ID,调整颜色适配邮件显示。 - 异步操作优化:将
docClient.put改为Promise批量执行,确保数据更新完成后再继续流程。
内容的提问来源于stack exchange,提问作者Jansen Su
相关产品推荐
相关产品推荐

