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

PHP/MySQL多对多关联下按状态分组展示活动人员的问题

活动人员分组展示与定向邮件发送方案

表结构确认

先明确三张核心表的结构(基于你的描述):

-- 活动表
CREATE TABLE animations (
    id INT PRIMARY KEY AUTO_INCREMENT,
    nom VARCHAR(255) NOT NULL,
    date DATE NOT NULL
    -- 可添加其他字段:lieu, description等
);

-- 工作人员表
CREATE TABLE animateurs (
    id INT PRIMARY KEY AUTO_INCREMENT,
    nom VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL
    -- 可添加其他字段:telephone, poste等
);

-- 多对多关联表(记录人员参与活动的状态)
CREATE TABLE crosstable (
    animation_id INT NOT NULL,
    animateur_id INT NOT NULL,
    statut ENUM('可用', '必要时可用', '不可用') NOT NULL,
    PRIMARY KEY (animation_id, animateur_id),
    FOREIGN KEY (animation_id) REFERENCES animations(id),
    FOREIGN KEY (animateur_id) REFERENCES animateurs(id)
);

一、实现“可用人员”列下的分组展示

1. 优化SQL查询,聚合不同状态的人员

通过GROUP_CONCAT和条件判断,一次性按活动聚合出“直接可用”和“必要时可用”的人员列表,避免多次查询:

SELECT 
    a.id,
    a.nom AS animation_nom,
    a.date,
    -- 聚合直接可用的人员
    GROUP_CONCAT(CASE WHEN c.statut = '可用' THEN an.nom END SEPARATOR ', ') AS disponible,
    -- 聚合必要时可用的人员
    GROUP_CONCAT(CASE WHEN c.statut = '必要时可用' THEN an.nom END SEPARATOR ', ') AS disponible_si_besoin
FROM animations a
LEFT JOIN crosstable c ON a.id = c.animation_id
LEFT JOIN animateurs an ON c.animateur_id = an.id
GROUP BY a.id, a.nom, a.date;

2. 前端表格展示调整

在“可用人员”列内拆分两个子分组,用粗体区分标题:

<?php
// 数据库连接(替换为你的配置)
$pdo = new PDO('mysql:host=localhost;dbname=你的数据库名', '用户名', '密码');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// 执行查询
$sql = "SELECT a.id, a.nom AS animation_nom, a.date, GROUP_CONCAT(CASE WHEN c.statut = '可用' THEN an.nom END SEPARATOR ', ') AS disponible, GROUP_CONCAT(CASE WHEN c.statut = '必要时可用' THEN an.nom END SEPARATOR ', ') AS disponible_si_besoin FROM animations a LEFT JOIN crosstable c ON a.id = c.animation_id LEFT JOIN animateurs an ON c.animateur_id = an.id GROUP BY a.id, a.nom, a.date";
$stmt = $pdo->query($sql);
$animations = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

<table border="1" cellpadding="8" cellspacing="0">
    <thead>
        <tr>
            <th>活动名称</th>
            <th>活动日期</th>
            <th>可用人员</th>
        </tr>
    </thead>
    <tbody>
        <?php foreach ($animations as $anim): ?>
        <tr>
            <td><?= htmlspecialchars($anim['animation_nom']) ?></td>
            <td><?= htmlspecialchars($anim['date']) ?></td>
            <td>
                <strong>直接可用:</strong><br>
                <?= !empty($anim['disponible']) ? htmlspecialchars($anim['disponible']) : '无' ?><br><br>
                <strong>必要时可用:</strong><br>
                <?= !empty($anim['disponible_si_besoin']) ? htmlspecialchars($anim['disponible_si_besoin']) : '无' ?>
            </td>
        </tr>
        <?php endforeach; ?>
    </tbody>
</table>

二、实现向特定状态人员发送邮件

1. 精准查询目标人员

根据活动ID和状态筛选出需要接收邮件的人员,用预处理语句避免SQL注入:

SELECT an.email, an.nom
FROM animateurs an
JOIN crosstable c ON an.id = c.animateur_id
WHERE c.animation_id = :animation_id AND c.statut = :statut;

2. 邮件发送实现

方案1:原生mail()函数(适合新手入门)

<?php
// 获取目标活动ID(示例从URL参数获取,需做合法性校验)
$animation_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$target_statut = '必要时可用'; // 可根据需求修改状态

// 数据库连接
$pdo = new PDO('mysql:host=localhost;dbname=你的数据库名', '用户名', '密码');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// 查询目标人员
$sql = "SELECT an.email, an.nom FROM animateurs an JOIN crosstable c ON an.id = c.animateur_id WHERE c.animation_id = :id AND c.statut = :statut";
$stmt = $pdo->prepare($sql);
$stmt->execute([
    'id' => $animation_id,
    'statut' => $target_statut
]);
$destinataires = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 邮件配置
$sujet = "活动支援通知";
$headers = "From: 活动管理员 <admin@votre-site.com>\r\n";
$headers .= "Content-Type: text/plain; charset=utf-8\r\n";

// 批量发送
foreach ($destinataires as $dest) {
    $message = "您好 {$dest['nom']}:\n\n现有ID为{$animation_id}的活动需要您的支援,请及时查看。";
    mail($dest['email'], $sujet, $message, $headers);
    // 可选:记录发送日志到数据库
}

echo "邮件已成功发送给符合条件的人员!";
?>

方案2:PHPMailer(推荐正式环境使用,稳定性更高)

先通过Composer安装:composer require phpmailer/phpmailer,然后替换发送逻辑:

<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

// 初始化PHPMailer
$mail = new PHPMailer(true);

try {
    // SMTP配置(替换为你的邮箱服务商信息)
    $mail->isSMTP();
    $mail->Host = 'smtp.example.com';
    $mail->SMTPAuth = true;
    $mail->Username = 'votre@email.com';
    $mail->Password = 'votre-mot-de-passe';
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
    $mail->Port = 465;

    // 发件人设置
    $mail->setFrom('admin@votre-site.com', '活动管理员');
    
    // 批量添加收件人并发送
    foreach ($destinataires as $dest) {
        $mail->addAddress($dest['email'], $dest['nom']);
        $mail->Subject = "活动支援通知";
        $mail->Body = "您好 {$dest['nom']}:\n\n现有ID为{$animation_id}的活动需要您的支援,请及时查看。";
        $mail->send();
        $mail->clearAddresses(); // 清空收件人,准备下一个
    }

    echo "邮件已全部发送完成!";
} catch (Exception $e) {
    echo "邮件发送失败:{$mail->ErrorInfo}";
}
?>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 03:10:56