NOW() AND o.expires_at >= ? AND o.expires_at <= ? AND o.expire_notify_sent = 0 AND o.status IN (\'paid\', \'shipped\', \'completed\')'; $stmt = db()->prepare($sql); $stmt->execute([$lo, $hi]); $rows = $stmt->fetchAll(); $sent = 0; $skipped = 0; $errors = []; $preview = []; foreach ($rows as $row) { $to = !empty($row['contact_email']) ? $row['contact_email'] : $row['u_email']; if (empty($to)) { $skipped++; $errors[] = '订单 #' . $row['id'] . ' 无收件邮箱,已跳过'; continue; } $daysLeft = (int) ceil((strtotime($row['expires_at']) - time()) / 86400); $name = $row['nickname'] ?: $row['username']; $subject = '[' . SITE_NAME . '] 您的服务即将到期(剩余 ' . $daysLeft . ' 天),请及时续期'; $body = buildExpireMail($name, $row['order_no'], $row['expires_at'], $daysLeft); if ($dryRun) { $preview[] = '预览 #' . $row['id'] . ' → ' . $to . ' | 剩余 ' . $daysLeft . ' 天'; $sent++; continue; } $res = fnwSendMail($to, $subject, $body); if (!empty($res['ok'])) { db()->prepare('UPDATE ' . tn('orders') . ' SET expire_notify_sent = 1 WHERE id = ?')->execute([$row['id']]); $sent++; } else { $errors[] = '订单 #' . $row['id'] . ' 发送失败:' . ($res['error'] ?? '未知错误'); } } $out = []; $out[] = '[' . date('Y-m-d H:i:s') . '] 到期前提醒任务' . ($dryRun ? '(预览模式)' : ''); $out[] = '扫描窗口:' . $lo . ' ~ ' . $hi . '(距到期约 ' . ($notifyDays - 1) . '~' . ($notifyDays + 1) . ' 天)'; $out[] = '命中订单:' . count($rows) . ' 笔;已发送:' . $sent . ';跳过:' . $skipped; if ($dryRun && $preview) { $out[] = '--- 预览列表 ---'; $out = array_merge($out, $preview); } if ($errors) { $out[] = '--- 注意事项 ---'; $out = array_merge($out, $errors); } $out[] = ''; $text = implode("\n", $out); if ($isCli) { fwrite(STDOUT, $text); } else { echo $text; } /** * 生成到期提醒邮件正文(HTML)。 */ function buildExpireMail($name, $orderNo, $expiresAt, $daysLeft) { $exp = date('Y-m-d H:i', strtotime($expiresAt)); $site = SITE_NAME; return '
你好 ' . h($name) . ',你在 ' . h($site) . ' 的订单 ' . h($orderNo) . ' 所对应的服务即将到期。
' . '到期时间:' . h($exp) . '
' . '剩余天数:约 ' . (int) $daysLeft . ' 天
' . '为避免服务中断,请在到期前通过「我的订单 → 对应订单 → 申请续期」提交工单,或联系客服办理续期。
' . '若已办理续期请忽略此邮件。本邮件由系统自动发送,请勿直接回复。
' . '