PHP项目怎样实现用户反馈处理?

wen PHP项目 50

本文目录导读:

PHP项目怎样实现用户反馈处理?

  1. 数据库设计
  2. 前端反馈提交页面
  3. 后端处理代码
  4. 后台管理界面
  5. 电子邮件通知
  6. 状态更新API
  7. 配置文件
  8. 安全建议

我来介绍PHP项目实现用户反馈处理的完整方案,涵盖前端收集、后端处理和后台管理。

数据库设计

反馈表单表

CREATE TABLE `feedback` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL COMMENT '用户ID(未登录可为null)',
  `type` tinyint(4) NOT NULL COMMENT '反馈类型:1-功能建议 2-BUG报告 3-产品问题 4-其他', varchar(200) NOT NULL COMMENT '反馈标题',
  `content` text NOT NULL COMMENT '反馈内容',
  `contact` varchar(100) DEFAULT NULL COMMENT '联系方式',
  `screenshot` varchar(500) DEFAULT NULL COMMENT '截图路径',
  `status` tinyint(4) DEFAULT '0' COMMENT '状态:0-待处理 1-处理中 2-已解决 3-已关闭',
  `priority` tinyint(4) DEFAULT '2' COMMENT '优先级:1-紧急 2-普通 3-低',
  `admin_reply` text COMMENT '管理员回复',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

反馈处理日志表

CREATE TABLE `feedback_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `feedback_id` int(11) NOT NULL,
  `action` varchar(50) NOT NULL COMMENT '操作类型',
  `operator` int(11) NOT NULL COMMENT '操作人',
  `remark` text COMMENT '备注',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_feedback_id` (`feedback_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

前端反馈提交页面

feedback_form.php

<!DOCTYPE html>
<html>
<head>用户反馈</title>
</head>
<body>
    <div class="container">
        <h2>用户反馈</h2>
        <form id="feedbackForm" method="post" enctype="multipart/form-data" action="submit_feedback.php">
            <div class="form-group">
                <label>反馈类型</label>
                <select name="type" required>
                    <option value="1">功能建议</option>
                    <option value="2">BUG报告</option>
                    <option value="3">产品问题</option>
                    <option value="4">其他</option>
                </select>
            </div>
            <div class="form-group">
                <label>标题</label>
                <input type="text" name="title" required maxlength="200">
            </div>
            <div class="form-group">
                <label>详细描述</label>
                <textarea name="content" rows="5" required></textarea>
            </div>
            <div class="form-group">
                <label>联系方式(选填)</label>
                <input type="text" name="contact" placeholder="邮箱或手机号">
            </div>
            <div class="form-group">
                <label>截图(选填)</label>
                <input type="file" name="screenshot" accept="image/*">
            </div>
            <button type="submit">提交反馈</button>
        </form>
    </div>
    <script>
        document.getElementById('feedbackForm').onsubmit = async function(e) {
            e.preventDefault();
            const formData = new FormData(this);
            try {
                const response = await fetch('submit_feedback.php', {
                    method: 'POST',
                    body: formData
                });
                const result = await response.json();
                if (result.success) {
                    alert('感谢您的反馈!');
                    this.reset();
                } else {
                    alert(result.message || '提交失败,请重试');
                }
            } catch (error) {
                alert('网络错误,请重试');
            }
        };
    </script>
</body>
</html>

后端处理代码

submit_feedback.php

<?php
session_start();
require_once 'config.php';
require_once 'functions.php';
header('Content-Type: application/json');
try {
    // 验证必要字段
    if (empty($_POST['title']) || empty($_POST['content'])) {
        throw new Exception('标题和内容不能为空');
    }
    // 上传截图
    $screenshotPath = null;
    if (isset($_FILES['screenshot']) && $_FILES['screenshot']['error'] == 0) {
        $allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
        if (!in_array($_FILES['screenshot']['type'], $allowedTypes)) {
            throw new Exception('只支持JPG、PNG、GIF格式的图片');
        }
        $uploadDir = 'uploads/feedback/';
        if (!file_exists($uploadDir)) {
            mkdir($uploadDir, 0777, true);
        }
        $fileName = uniqid() . '_' . basename($_FILES['screenshot']['name']);
        $filePath = $uploadDir . $fileName;
        if (!move_uploaded_file($_FILES['screenshot']['tmp_name'], $filePath)) {
            throw new Exception('截图上传失败');
        }
        $screenshotPath = $filePath;
    }
    // 插入数据库
    $pdo = getDBConnection();
    $stmt = $pdo->prepare("INSERT INTO feedback 
        (user_id, type, title, content, contact, screenshot, status, created_at) 
        VALUES (?, ?, ?, ?, ?, ?, 0, NOW())");
    $stmt->execute([
        $_SESSION['user_id'] ?? null,
        $_POST['type'],
        $_POST['title'],
        $_POST['content'],
        $_POST['contact'] ?? null,
        $screenshotPath
    ]);
    // 发送通知(可选)
    sendNotification($feedbackId);
    echo json_encode(['success' => true, 'message' => '反馈提交成功']);
} catch (Exception $e) {
    echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}

后台管理界面

admin_feedback.php

<?php
session_start();
require_once 'config.php';
require_once 'functions.php';
// 验证管理员权限
if (!isAdmin()) {
    header('Location: login.php');
    exit;
}
$pdo = getDBConnection();
// 获取反馈列表
$stmt = $pdo->query("SELECT f.*, u.username 
    FROM feedback f 
    LEFT JOIN users u ON f.user_id = u.id 
    ORDER BY f.created_at DESC");
$feedbacks = $stmt->fetchAll();
// 处理回复提交
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['reply'])) {
    $feedbackId = $_POST['feedback_id'];
    $replyContent = $_POST['reply_content'];
    $stmt = $pdo->prepare("UPDATE feedback SET 
        admin_reply = ?, 
        status = 2, 
        updated_at = NOW() 
        WHERE id = ?");
    $stmt->execute([$replyContent, $feedbackId]);
    // 记录日志
    $logStmt = $pdo->prepare("INSERT INTO feedback_log 
        (feedback_id, action, operator, remark) 
        VALUES (?, 'reply', ?, ?)");
    $logStmt->execute([$feedbackId, $_SESSION['admin_id'], '管理员回复']);
    header('Location: admin_feedback.php?msg=回复成功');
    exit;
}
?>
<!DOCTYPE html>
<html>
<head>反馈管理</title>
    <style>
        .feedback-card { border: 1px solid #ddd; padding: 15px; margin: 10px 0; }
        .status-badge { padding: 3px 8px; border-radius: 3px; }
        .status-pending { background: #ffc107; }
        .status-processing { background: #17a2b8; color: white; }
        .status-resolved { background: #28a745; color: white; }
        .status-closed { background: #6c757d; color: white; }
    </style>
</head>
<body>
    <h2>用户反馈管理</h2>
    <div class="filter-bar">
        <select id="statusFilter" onchange="filterFeedbacks()">
            <option value="">全部状态</option>
            <option value="0">待处理</option>
            <option value="1">处理中</option>
            <option value="2">已解决</option>
            <option value="3">已关闭</option>
        </select>
    </div>
    <?php foreach ($feedbacks as $feedback): ?>
    <div class="feedback-card" data-status="<?= $feedback['status'] ?>">
        <div class="feedback-header">
            <span class="status-badge status-<?= 
                ['pending', 'processing', 'resolved', 'closed'][$feedback['status']] 
            ?>">
                <?= ['待处理', '处理中', '已解决', '已关闭'][$feedback['status']] ?>
            </span>
            <span>用户:<?= htmlspecialchars($feedback['username'] ?: '匿名') ?></span>
            <span>时间:<?= $feedback['created_at'] ?></span>
        </div>
        <h3><?= htmlspecialchars($feedback['title']) ?></h3>
        <p><?= nl2br(htmlspecialchars($feedback['content'])) ?></p>
        <?php if ($feedback['screenshot']): ?>
        <div class="screenshot">
            <img src="<?= $feedback['screenshot'] ?>" alt="截图" style="max-width: 300px;">
        </div>
        <?php endif; ?>
        <?php if ($feedback['admin_reply']): ?>
        <div class="reply-box">
            <h4>管理员回复:</h4>
            <p><?= nl2br(htmlspecialchars($feedback['admin_reply'])) ?></p>
        </div>
        <?php endif; ?>
        <div class="actions">
            <form method="post" class="reply-form">
                <input type="hidden" name="feedback_id" value="<?= $feedback['id'] ?>">
                <textarea name="reply_content" placeholder="输入回复内容" required></textarea>
                <button type="submit" name="reply">回复并解决</button>
            </form>
            <button onclick="changeStatus(<?= $feedback['id'] ?>, 1)">标记处理中</button>
            <button onclick="changeStatus(<?= $feedback['id'] ?>, 3)">关闭</button>
        </div>
    </div>
    <?php endforeach; ?>
    <script>
    function changeStatus(id, status) {
        if (!confirm('确认修改状态?')) return;
        fetch('update_feedback_status.php', {
            method: 'POST',
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({id: id, status: status})
        }).then(response => response.json()).then(data => {
            if (data.success) location.reload();
        });
    }
    function filterFeedbacks() {
        const status = document.getElementById('statusFilter').value;
        document.querySelectorAll('.feedback-card').forEach(card => {
            if (!status || card.dataset.status === status) {
                card.style.display = 'block';
            } else {
                card.style.display = 'none';
            }
        });
    }
    </script>
</body>
</html>

电子邮件通知

send_notification.php

<?php
function sendFeedbackNotification($feedbackId, $type) {
    $adminEmail = 'admin@example.com';
    $subject = '新的用户反馈通知';
    $message = "收到新的用户反馈 #{$feedbackId}\n";
    $message .= "类型:" . getFeedbackType($type) . "\n";
    $message .= "请在后台查看详情。";
    mail($adminEmail, $subject, $message);
}
function sendReplyNotification($userEmail, $feedbackTitle) {
    $subject = '您的反馈已收到回复';
    $message = "您关于「{$feedbackTitle}」的反馈已收到回复,请查看。";
    mail($userEmail, $subject, $message);
}

状态更新API

update_feedback_status.php

<?php
session_start();
header('Content-Type: application/json');
require_once 'config.php';
require_once 'functions.php';
// 验证管理员权限
if (!isAdmin()) {
    echo json_encode(['success' => false, 'message' => '无权限']);
    exit;
}
$input = json_decode(file_get_contents('php://input'), true);
try {
    $pdo = getDBConnection();
    $stmt = $pdo->prepare("UPDATE feedback SET 
        status = ?,
        updated_at = NOW() 
        WHERE id = ?");
    $stmt->execute([$input['status'], $input['id']]);
    // 记录日志
    $logStmt = $pdo->prepare("INSERT INTO feedback_log 
        (feedback_id, action, operator, remark) 
        VALUES (?, 'status_change', ?, ?)");
    $statusNames = ['待处理', '处理中', '已解决', '已关闭'];
    $logStmt->execute([
        $input['id'],
        $_SESSION['admin_id'],
        "状态变更为:{$statusNames[$input['status']]}"
    ]);
    echo json_encode(['success' => true]);
} catch (Exception $e) {
    echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}

配置文件

config.php

<?php
// 数据库配置
define('DB_HOST', 'localhost');
define('DB_NAME', 'feedback_system');
define('DB_USER', 'root');
define('DB_PASS', '');
// 邮件配置
define('SMTP_HOST', 'smtp.example.com');
define('SMTP_PORT', 587);
define('SMTP_USER', 'noreply@example.com');
define('SMTP_PASS', 'password');
// 文件上传配置
define('MAX_FILE_SIZE', 5 * 1024 * 1024); // 5MB
define('ALLOWED_EXTENSIONS', ['jpg', 'jpeg', 'png', 'gif']);
function getDBConnection() {
    try {
        $pdo = new PDO(
            "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
            DB_USER,
            DB_PASS,
            [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
            ]
        );
        return $pdo;
    } catch (PDOException $e) {
        die("数据库连接失败: " . $e->getMessage());
    }
}

安全建议

  1. CSRF防护:添加CSRF token验证
  2. XSS防护:输出时使用 htmlspecialchars()
  3. 文件上传安全:验证文件类型和大小
  4. SQL注入防护:使用预处理语句
  5. 访问控制:后台管理需要权限验证
  6. 数据验证:前后端都要验证输入数据

这个方案提供了完整的用户反馈处理流程,包括提交、存储、回复和状态管理,可以根据实际需求进行扩展,比如添加邮件通知、微信通知、数据分析等功能。

抱歉,评论功能暂时关闭!