本文目录导读:

我来介绍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());
}
}
安全建议
- CSRF防护:添加CSRF token验证
- XSS防护:输出时使用
htmlspecialchars() - 文件上传安全:验证文件类型和大小
- SQL注入防护:使用预处理语句
- 访问控制:后台管理需要权限验证
- 数据验证:前后端都要验证输入数据
这个方案提供了完整的用户反馈处理流程,包括提交、存储、回复和状态管理,可以根据实际需求进行扩展,比如添加邮件通知、微信通知、数据分析等功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播