Browse Source

🎈 perf: 优化邮件模板内容

Pchen0 1 month ago
parent
commit
7b4ae16d12
2 changed files with 90 additions and 22 deletions
  1. 84 15
      plugin/Email/emailLayout.js
  2. 6 7
      plugin/Email/emailTemplate.js

+ 84 - 15
plugin/Email/emailLayout.js

@@ -2,8 +2,18 @@
 
 const BRAND = 'RunForge'
 
-/** 所有经 renderEmail 输出的邮件页脚均附带此说明 */
-const AUTO_REPLY_NOTICE = '本邮件由系统自动发送,请勿直接回复'
+/** 页脚固定说明(分段展示,避免单行过长) */
+const FOOTER_DISCLAIMER = {
+    label: '本邮件由系统自动发送,请勿直接回复本邮件。',
+    helpPrefix: '如需帮助,请访问 RunForge 网站提交工单,或发送邮件至',
+    helpEmail: 'service@xxoo365.top'
+}
+
+/** 合并后的纯文本说明(供外部引用) */
+const AUTO_REPLY_NOTICE = [
+    FOOTER_DISCLAIMER.label,
+    `${FOOTER_DISCLAIMER.helpPrefix} ${FOOTER_DISCLAIMER.helpEmail}`
+].join(' ')
 
 /**
  * Escape text for safe insertion into HTML email bodies.
@@ -36,6 +46,24 @@ const ACCENTS = {
     danger: '#b91c1c'
 }
 
+/**
+ * 页脚:可选补充说明 + 固定分段提示(左对齐,避免长句居中拥挤)
+ * @param {string} footerExtra
+ */
+function buildFooterHtml(footerExtra) {
+    const ctx = footerExtra
+        ? `<div class="footer-context">${escapeHtml(footerExtra)}</div>`
+        : ''
+
+    const mail = escapeHtml(FOOTER_DISCLAIMER.helpEmail)
+
+    return `${ctx}
+        <span class="footer-meta-label">${escapeHtml(FOOTER_DISCLAIMER.label)}</span>
+        <ul class="footer-meta">
+          <li>${escapeHtml(FOOTER_DISCLAIMER.helpPrefix)} <a href="mailto:${mail}">${mail}</a></li>
+        </ul>`
+}
+
 /**
  * Wrap transactional email body in shared layout (single stylesheet + structure).
  * @param {object} opts
@@ -59,11 +87,7 @@ function renderEmail(opts) {
     const accent = ACCENTS[variant] || ACCENTS.default
     const year = new Date().getFullYear()
 
-    const footerNote = footerExtra
-        ? `<p class="fineprint">${escapeHtml(footerExtra)}</p>`
-        : ''
-
-    const autoReplyLine = `<p class="fineprint">${escapeHtml(AUTO_REPLY_NOTICE)}</p>`
+    const footerHtml = buildFooterHtml(footerExtra)
 
     return `<!DOCTYPE html>
 <html lang="zh-CN">
@@ -126,14 +150,58 @@ function renderEmail(opts) {
     font-family:Consolas,'Courier New',monospace;
   }
   .footer {
-    padding:16px 28px 22px;
-    border-top:1px solid #f1f5f9;
-    text-align:center;
+    padding:0;
+    border-top:1px solid #e2e8f0;
+    background:#f8fafc;
+  }
+  .footer-inner {
+    max-width:504px;
+    margin:0 auto;
+    padding:18px 28px 20px;
+    text-align:left;
+  }
+  .footer-context {
+    margin:0 0 14px;
+    padding:10px 12px;
+    font-size:13px;
+    line-height:1.55;
+    color:#475569;
+    background:#ffffff;
+    border:1px solid #e2e8f0;
+    border-radius:6px;
+  }
+  .footer-meta {
+    margin:0;
+    padding:0;
+    list-style:none;
     font-size:12px;
-    line-height:1.5;
+    line-height:1.65;
+    color:#64748b;
+  }
+  .footer-meta li { margin:0; padding:0; }
+  .footer-meta li + li { margin-top:8px; }
+  .footer-meta-label {
+    display:block;
+    font-size:11px;
+    font-weight:600;
+    letter-spacing:0.04em;
+    color:#94a3b8;
+    margin-bottom:8px;
+  }
+  .footer-meta a {
+    color:#1e40af;
+    text-decoration:none;
+    word-break:break-all;
+  }
+  .footer-copyright {
+    margin:14px 0 0;
+    padding-top:14px;
+    border-top:1px solid #e2e8f0;
+    text-align:center;
+    font-size:11px;
+    line-height:1.4;
     color:#94a3b8;
   }
-  .fineprint { margin:0 0 8px; font-size:12px; color:#64748b; }
   .tag {
     display:inline-block;
     margin-left:10px;
@@ -157,9 +225,10 @@ function renderEmail(opts) {
       ${bodyHtml}
     </div>
     <div class="footer">
-      ${footerNote}
-      ${autoReplyLine}
-      <p style="margin:0;">© ${year} ${escapeHtml(BRAND)}</p>
+      <div class="footer-inner">
+        ${footerHtml}
+        <p class="footer-copyright">© ${year} ${escapeHtml(BRAND)}</p>
+      </div>
     </div>
   </div>
 </div>

+ 6 - 7
plugin/Email/emailTemplate.js

@@ -96,7 +96,7 @@ class emailTemplate {
                 kv('更新时间', this.stramptoTime(new Date().getTime()))
             ].join('')),
             notice(autoNote, 'neutral'),
-            notice('请在当前更新乐跑账号信息的设备上使用「智慧体育」小程序;请勿在其他设备登录该小程序,以免登录状态失效并需重新绑定。', 'neutral'),
+            notice('请在当前登录乐跑账号的设备上使用「智慧体育」小程序;请勿在其他设备登录该小程序,以免登录状态失效并需重新绑定。', 'neutral'),
             pEsc('如需帮助,请联系 RunForge 客服。', { last: true })
         ].join('')
 
@@ -115,9 +115,9 @@ class emailTemplate {
     async lepaoOver(email, data) {
         const bodyHtml = [
             pEsc(`尊敬的 ${data.name}:`),
-            pEsc('您在本学期设定的乐跑目标已全部完成,系统已为您关闭自动乐跑功能。'),
-            pEsc('感谢本学期以来的配合。若仍需跑步,可在 RunForge 中按需重新开启相关功能。'),
-            notice('如有疑问,请通过 RunForge 工单或客服渠道联系我们。', 'neutral'),
+            pEsc('您设定的乐跑目标已全部完成,系统已为您关闭自动乐跑功能。'),
+            pEsc('感谢的配合。若仍需跑步,可在 RunForge 中按需重新开启相关功能。'),
+            notice('如有疑问,请通过 RunForge 工单反馈。', 'neutral'),
             pEsc('祝您学习生活愉快。', { last: true })
         ].join('')
 
@@ -157,7 +157,7 @@ class emailTemplate {
 
         const bodyHtml = [
             pEsc(`尊敬的 ${data.name}:`),
-            pEsc('系统已代您完成一次乐跑,摘要如下:'),
+            pEsc('系统已成功代您完成一次乐跑,摘要如下:'),
             panel([
                 kv('学号', data.account),
                 kv('跑区', passTit),
@@ -166,8 +166,7 @@ class emailTemplate {
                 kv('距离', `${distanceKm || '—'} km`),
                 goalLines
             ].join('')),
-            notice('若已开启自动乐跑,请勿在其他设备登录「智慧体育」小程序,以免登录状态失效。', 'neutral'),
-            pEsc('如需协助,请联系 RunForge 客服。', { last: true })
+            notice('若已开启自动乐跑,请勿在除更新乐跑账号信息以外的其他设备登录「智慧体育」小程序,以免登录状态失效。', 'neutral')
         ].join('')
 
         await sendEmail(