Initial commit: Flutter 无书应用项目
This commit is contained in:
379
ht/api/admin.php
Normal file
379
ht/api/admin.php
Normal file
@@ -0,0 +1,379 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 管理员API
|
||||
* 提供管理后台所需的API接口
|
||||
*/
|
||||
|
||||
// 引入必要文件
|
||||
require_once '../inc/pubs.php';
|
||||
require_once '../inc/sqls.php';
|
||||
|
||||
// 获取操作类型
|
||||
$action = isset($_REQUEST['act']) ? $_REQUEST['act'] : '';
|
||||
|
||||
// 实例化数据库操作类
|
||||
$db = new DB();
|
||||
|
||||
// 根据操作类型执行相应操作
|
||||
switch ($action) {
|
||||
// 添加用户
|
||||
case 'addUser':
|
||||
// 验证管理员权限
|
||||
$admin = checkAuth('addUser', true);
|
||||
if (!$admin) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$username = isset($_POST['username']) ? safeFilter($_POST['username']) : '';
|
||||
$password = isset($_POST['password']) ? $_POST['password'] : '';
|
||||
$role = isset($_POST['role']) ? intval($_POST['role']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($username) || empty($password)) {
|
||||
ajaxReturn(1, '用户名和密码不能为空');
|
||||
}
|
||||
|
||||
// 验证手机号格式
|
||||
if (!preg_match('/^1[3456789]\d{9}$/', $username)) {
|
||||
ajaxReturn(1, '请输入正确的手机号码');
|
||||
}
|
||||
|
||||
// 验证密码长度
|
||||
if (strlen($password) < 6) {
|
||||
ajaxReturn(1, '密码长度不能少于6位');
|
||||
}
|
||||
|
||||
// 检查用户名是否已存在
|
||||
$existUser = $db->getOne('users', "username = '$username'");
|
||||
if ($existUser) {
|
||||
ajaxReturn(1, '该手机号已被注册');
|
||||
}
|
||||
|
||||
// 密码加密
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
// 添加用户
|
||||
$userId = $db->insert('users', [
|
||||
'username' => $username,
|
||||
'password' => $hashedPassword,
|
||||
'irole' => $role,
|
||||
'status' => 1,
|
||||
'regtime' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
if (!$userId) {
|
||||
ajaxReturn(1, '添加失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
writeLog($admin['id'], 'add_user', "添加用户:$username");
|
||||
|
||||
ajaxReturn(0, '添加成功', ['id' => $userId]);
|
||||
break;
|
||||
|
||||
// 更新用户信息
|
||||
case 'updateUser':
|
||||
// 验证管理员权限
|
||||
$admin = checkAuth('updateUser', true);
|
||||
if (!$admin) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
$role = isset($_POST['role']) ? intval($_POST['role']) : null;
|
||||
$status = isset($_POST['status']) ? intval($_POST['status']) : null;
|
||||
|
||||
// 参数验证
|
||||
if (empty($id)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
$targetUser = $db->getOne('users', "id = $id");
|
||||
if (!$targetUser) {
|
||||
ajaxReturn(1, '用户不存在');
|
||||
}
|
||||
|
||||
// 不能禁用自己的账号
|
||||
if ($id == $admin['id'] && $status === 0) {
|
||||
ajaxReturn(1, '不能禁用当前登录的账号');
|
||||
}
|
||||
|
||||
// 准备更新数据
|
||||
$updateData = [];
|
||||
|
||||
if ($role !== null) {
|
||||
$updateData['irole'] = $role;
|
||||
}
|
||||
|
||||
if ($status !== null) {
|
||||
$updateData['status'] = $status;
|
||||
}
|
||||
|
||||
if (empty($updateData)) {
|
||||
ajaxReturn(1, '没有要更新的数据');
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
$result = $db->update('users', $updateData, "id = $id");
|
||||
if (!$result) {
|
||||
ajaxReturn(1, '更新失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
$logContent = "更新用户信息:" . $targetUser['username'];
|
||||
writeLog($admin['id'], 'update_user', $logContent);
|
||||
|
||||
ajaxReturn(0, '更新成功');
|
||||
break;
|
||||
|
||||
// 重置用户密码
|
||||
case 'resetPassword':
|
||||
// 验证管理员权限
|
||||
$admin = checkAuth('resetPassword', true);
|
||||
if (!$admin) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
$password = isset($_POST['password']) ? $_POST['password'] : '';
|
||||
|
||||
// 参数验证
|
||||
if (empty($id) || empty($password)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 验证密码长度
|
||||
if (strlen($password) < 6) {
|
||||
ajaxReturn(1, '密码长度不能少于6位');
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
$targetUser = $db->getOne('users', "id = $id");
|
||||
if (!$targetUser) {
|
||||
ajaxReturn(1, '用户不存在');
|
||||
}
|
||||
|
||||
// 密码加密
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
// 更新密码
|
||||
$result = $db->update('users', [
|
||||
'password' => $hashedPassword
|
||||
], "id = $id");
|
||||
|
||||
if (!$result) {
|
||||
ajaxReturn(1, '重置失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
$logContent = "重置用户密码:" . $targetUser['username'];
|
||||
writeLog($admin['id'], 'reset_password', $logContent);
|
||||
|
||||
ajaxReturn(0, '密码重置成功');
|
||||
break;
|
||||
|
||||
// 获取投票统计数据
|
||||
case 'getVoteStats':
|
||||
// 验证管理员权限
|
||||
$admin = checkAuth('getVoteStats', true);
|
||||
if (!$admin) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$topicId = isset($_REQUEST['topic_id']) ? intval($_REQUEST['topic_id']) : 0;
|
||||
|
||||
// 如果指定了特定投票
|
||||
if ($topicId) {
|
||||
// 获取投票信息
|
||||
$vote = $db->getOne('vote', "id = $topicId");
|
||||
if (!$vote) {
|
||||
ajaxReturn(1, '投票不存在');
|
||||
}
|
||||
|
||||
// 获取选项列表
|
||||
$options = $db->getAll('xuan', "topic_id = $topicId", '*', 'sort ASC, id ASC');
|
||||
|
||||
// 获取每个选项的投票数
|
||||
$voteCounts = [];
|
||||
$sql = "SELECT option_id, COUNT(*) as vote_count FROM " . $db->table('recs') . " WHERE topic_id = $topicId GROUP BY option_id";
|
||||
$result = $db->query($sql);
|
||||
|
||||
if ($result) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$voteCounts[$row['option_id']] = $row['vote_count'];
|
||||
}
|
||||
}
|
||||
|
||||
// 统计总票数
|
||||
$totalVotes = array_sum($voteCounts);
|
||||
|
||||
// 格式化选项数据
|
||||
$formattedOptions = [];
|
||||
foreach ($options as $option) {
|
||||
$count = isset($voteCounts[$option['id']]) ? $voteCounts[$option['id']] : 0;
|
||||
$percentage = $totalVotes > 0 ? round(($count / $totalVotes) * 100, 1) : 0;
|
||||
|
||||
$formattedOptions[] = [
|
||||
'id' => $option['id'],
|
||||
'name' => $option['name'],
|
||||
'count' => $count,
|
||||
'percentage' => $percentage
|
||||
];
|
||||
}
|
||||
|
||||
// 获取参与用户
|
||||
$participants = [];
|
||||
$sql = "SELECT DISTINCT u.username, r.vote_time, r.ip
|
||||
FROM " . $db->table('recs') . " r
|
||||
LEFT JOIN " . $db->table('users') . " u ON r.user_id = u.id
|
||||
WHERE r.topic_id = $topicId
|
||||
ORDER BY r.vote_time DESC";
|
||||
$result = $db->query($sql);
|
||||
|
||||
if ($result) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$participants[] = [
|
||||
'username' => $row['username'],
|
||||
'vote_time' => $row['vote_time'],
|
||||
'ip' => $row['ip']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
ajaxReturn(0, '获取成功', [
|
||||
'vote' => $vote,
|
||||
'options' => $formattedOptions,
|
||||
'totalVotes' => $totalVotes,
|
||||
'participants' => $participants
|
||||
]);
|
||||
} else {
|
||||
// 获取所有投票的统计信息
|
||||
$voteStats = [];
|
||||
|
||||
// 获取所有投票
|
||||
$votes = $db->getAll('vote', '', '*', 'addtime DESC');
|
||||
|
||||
foreach ($votes as $vote) {
|
||||
// 获取该投票的总票数
|
||||
$totalVotes = $db->count('recs', "topic_id = {$vote['id']}");
|
||||
|
||||
// 获取参与人数
|
||||
$sql = "SELECT COUNT(DISTINCT user_id) as user_count FROM " . $db->table('recs') . " WHERE topic_id = {$vote['id']}";
|
||||
$result = $db->query($sql);
|
||||
$userCount = 0;
|
||||
|
||||
if ($result && $row = $result->fetch_assoc()) {
|
||||
$userCount = $row['user_count'];
|
||||
}
|
||||
|
||||
$voteStats[] = [
|
||||
'id' => $vote['id'],
|
||||
'title' => $vote['title'],
|
||||
'start_time' => $vote['statime'],
|
||||
'end_time' => $vote['endtime'],
|
||||
'total_votes' => $totalVotes,
|
||||
'user_count' => $userCount,
|
||||
'view_count' => $vote['iview']
|
||||
];
|
||||
}
|
||||
|
||||
ajaxReturn(0, '获取成功', [
|
||||
'voteStats' => $voteStats
|
||||
]);
|
||||
}
|
||||
break;
|
||||
|
||||
// 获取系统日志
|
||||
case 'getLogs':
|
||||
// 验证管理员权限
|
||||
$admin = checkAuth('getLogs', true);
|
||||
if (!$admin) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取分页参数
|
||||
$page = isset($_REQUEST['page']) ? intval($_REQUEST['page']) : 1;
|
||||
$pageSize = isset($_REQUEST['page_size']) ? intval($_REQUEST['page_size']) : 20;
|
||||
|
||||
// 获取筛选参数
|
||||
$userId = isset($_REQUEST['user_id']) ? intval($_REQUEST['user_id']) : 0;
|
||||
$action = isset($_REQUEST['action']) ? safeFilter($_REQUEST['action']) : '';
|
||||
$startDate = isset($_REQUEST['start_date']) ? $_REQUEST['start_date'] : '';
|
||||
$endDate = isset($_REQUEST['end_date']) ? $_REQUEST['end_date'] : '';
|
||||
|
||||
// 构建查询条件
|
||||
$whereConditions = [];
|
||||
|
||||
if ($userId) {
|
||||
$whereConditions[] = "user_id = $userId";
|
||||
}
|
||||
|
||||
if ($action) {
|
||||
$whereConditions[] = "action = '$action'";
|
||||
}
|
||||
|
||||
if ($startDate) {
|
||||
$whereConditions[] = "logtime >= '$startDate 00:00:00'";
|
||||
}
|
||||
|
||||
if ($endDate) {
|
||||
$whereConditions[] = "logtime <= '$endDate 23:59:59'";
|
||||
}
|
||||
|
||||
$whereStr = !empty($whereConditions) ? implode(' AND ', $whereConditions) : '';
|
||||
|
||||
// 获取总记录数
|
||||
$total = $db->count('logs', $whereStr);
|
||||
|
||||
// 计算分页信息
|
||||
$pagination = getPagination($total, $page, $pageSize);
|
||||
|
||||
// 获取日志列表
|
||||
$orderBy = "logtime DESC";
|
||||
$limit = "{$pagination['offset']}, {$pagination['pageSize']}";
|
||||
|
||||
$sql = "SELECT l.*, u.username
|
||||
FROM " . $db->table('logs') . " l
|
||||
LEFT JOIN " . $db->table('users') . " u ON l.user_id = u.id
|
||||
" . ($whereStr ? "WHERE $whereStr" : "") . "
|
||||
ORDER BY $orderBy
|
||||
LIMIT $limit";
|
||||
|
||||
$result = $db->query($sql);
|
||||
$logs = [];
|
||||
|
||||
if ($result) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$logs[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有操作类型,用于筛选
|
||||
$sql = "SELECT DISTINCT action FROM " . $db->table('logs');
|
||||
$result = $db->query($sql);
|
||||
$actionTypes = [];
|
||||
|
||||
if ($result) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$actionTypes[] = $row['action'];
|
||||
}
|
||||
}
|
||||
|
||||
ajaxReturn(0, '获取成功', [
|
||||
'logs' => $logs,
|
||||
'pagination' => $pagination,
|
||||
'actionTypes' => $actionTypes
|
||||
]);
|
||||
break;
|
||||
|
||||
// 未知操作
|
||||
default:
|
||||
ajaxReturn(1, '未知操作');
|
||||
break;
|
||||
}
|
||||
425
ht/api/topic.php
Normal file
425
ht/api/topic.php
Normal file
@@ -0,0 +1,425 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 投票主题相关API
|
||||
*/
|
||||
|
||||
// 引入必要文件
|
||||
require_once '../inc/pubs.php';
|
||||
require_once '../inc/sqls.php';
|
||||
|
||||
// 获取操作类型
|
||||
$action = isset($_REQUEST['act']) ? $_REQUEST['act'] : '';
|
||||
|
||||
// 实例化数据库操作类
|
||||
$db = new DB();
|
||||
|
||||
// 根据操作类型执行相应操作
|
||||
switch ($action) {
|
||||
// 获取投票主题列表
|
||||
case 'getList':
|
||||
// 验证管理员权限
|
||||
$user = checkAuth('getList', true);
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取分页参数
|
||||
$page = isset($_REQUEST['page']) ? intval($_REQUEST['page']) : 1;
|
||||
$pageSize = isset($_REQUEST['page_size']) ? intval($_REQUEST['page_size']) : 10;
|
||||
|
||||
// 获取筛选参数
|
||||
$status = isset($_REQUEST['status']) ? $_REQUEST['status'] : '';
|
||||
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : '';
|
||||
$keyword = isset($_REQUEST['keyword']) ? safeFilter($_REQUEST['keyword']) : '';
|
||||
|
||||
// 构建查询条件
|
||||
$whereConditions = [];
|
||||
if ($status !== '') {
|
||||
$whereConditions[] = "status = " . intval($status);
|
||||
}
|
||||
if ($type !== '') {
|
||||
$whereConditions[] = "itype = " . intval($type);
|
||||
}
|
||||
if (!empty($keyword)) {
|
||||
$whereConditions[] = "(title LIKE '%$keyword%' OR idesc LIKE '%$keyword%')";
|
||||
}
|
||||
|
||||
$whereStr = !empty($whereConditions) ? implode(' AND ', $whereConditions) : '';
|
||||
|
||||
// 获取总记录数
|
||||
$total = $db->count('vote', $whereStr);
|
||||
|
||||
// 计算分页信息
|
||||
$pagination = getPagination($total, $page, $pageSize);
|
||||
|
||||
// 获取投票列表
|
||||
$orderBy = "addtime DESC";
|
||||
$limit = "{$pagination['offset']}, {$pagination['pageSize']}";
|
||||
$voteList = $db->getAll('vote', $whereStr, '*', $orderBy, $limit);
|
||||
|
||||
// 格式化日期
|
||||
foreach ($voteList as &$vote) {
|
||||
$vote['statime_formatted'] = date('Y-m-d H:i', strtotime($vote['statime']));
|
||||
$vote['endtime_formatted'] = date('Y-m-d H:i', strtotime($vote['endtime']));
|
||||
$vote['addtime_formatted'] = date('Y-m-d H:i', strtotime($vote['addtime']));
|
||||
}
|
||||
|
||||
ajaxReturn(0, '获取成功', [
|
||||
'list' => $voteList,
|
||||
'pagination' => $pagination
|
||||
]);
|
||||
break;
|
||||
|
||||
// 获取投票主题详情
|
||||
case 'getDetail':
|
||||
// 获取参数
|
||||
$id = isset($_REQUEST['id']) ? intval($_REQUEST['id']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($id)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 获取投票详情
|
||||
$vote = $db->getOne('vote', "id = $id");
|
||||
if (!$vote) {
|
||||
ajaxReturn(1, '投票不存在');
|
||||
}
|
||||
|
||||
// 获取选项列表
|
||||
$options = $db->getAll('xuan', "topic_id = $id", '*', 'sort ASC, id ASC');
|
||||
|
||||
ajaxReturn(0, '获取成功', [
|
||||
'vote' => $vote,
|
||||
'options' => $options
|
||||
]);
|
||||
break;
|
||||
|
||||
// 添加投票主题
|
||||
case 'add':
|
||||
// 验证管理员权限
|
||||
$user = checkAuth('add', true);
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$title = isset($_POST['title']) ? safeFilter($_POST['title']) : '';
|
||||
$desc = isset($_POST['desc']) ? safeFilter($_POST['desc']) : '';
|
||||
$statime = isset($_POST['statime']) ? $_POST['statime'] : '';
|
||||
$endtime = isset($_POST['endtime']) ? $_POST['endtime'] : '';
|
||||
$type = isset($_POST['type']) ? intval($_POST['type']) : 0;
|
||||
$maxtime = isset($_POST['maxtime']) ? intval($_POST['maxtime']) : 1;
|
||||
$status = isset($_POST['status']) ? intval($_POST['status']) : 1;
|
||||
|
||||
// 参数验证
|
||||
if (empty($title)) {
|
||||
ajaxReturn(1, '请输入投票标题');
|
||||
}
|
||||
|
||||
if (empty($statime) || empty($endtime)) {
|
||||
ajaxReturn(1, '请选择开始和结束时间');
|
||||
}
|
||||
|
||||
if (strtotime($statime) >= strtotime($endtime)) {
|
||||
ajaxReturn(1, '结束时间必须晚于开始时间');
|
||||
}
|
||||
|
||||
if ($type == 1 && $maxtime < 2) {
|
||||
ajaxReturn(1, '多选投票最少可选2项');
|
||||
}
|
||||
|
||||
// 添加投票主题
|
||||
$topicId = $db->insert('vote', [
|
||||
'title' => $title,
|
||||
'idesc' => $desc,
|
||||
'statime' => $statime,
|
||||
'endtime' => $endtime,
|
||||
'itype' => $type,
|
||||
'maxtime' => $maxtime,
|
||||
'status' => $status,
|
||||
'addtime' => date('Y-m-d H:i:s'),
|
||||
'adduser' => $user['id'],
|
||||
'iview' => 0
|
||||
]);
|
||||
|
||||
if (!$topicId) {
|
||||
ajaxReturn(1, '添加失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'add_topic', "添加投票:$title");
|
||||
|
||||
ajaxReturn(0, '添加成功', ['id' => $topicId]);
|
||||
break;
|
||||
|
||||
// 更新投票主题
|
||||
case 'update':
|
||||
// 验证管理员权限
|
||||
$user = checkAuth('update', true);
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
$title = isset($_POST['title']) ? safeFilter($_POST['title']) : '';
|
||||
$desc = isset($_POST['desc']) ? safeFilter($_POST['desc']) : '';
|
||||
$statime = isset($_POST['statime']) ? $_POST['statime'] : '';
|
||||
$endtime = isset($_POST['endtime']) ? $_POST['endtime'] : '';
|
||||
$type = isset($_POST['type']) ? intval($_POST['type']) : 0;
|
||||
$maxtime = isset($_POST['maxtime']) ? intval($_POST['maxtime']) : 1;
|
||||
$status = isset($_POST['status']) ? intval($_POST['status']) : 1;
|
||||
|
||||
// 参数验证
|
||||
if (empty($id)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
if (empty($title)) {
|
||||
ajaxReturn(1, '请输入投票标题');
|
||||
}
|
||||
|
||||
if (empty($statime) || empty($endtime)) {
|
||||
ajaxReturn(1, '请选择开始和结束时间');
|
||||
}
|
||||
|
||||
if (strtotime($statime) >= strtotime($endtime)) {
|
||||
ajaxReturn(1, '结束时间必须晚于开始时间');
|
||||
}
|
||||
|
||||
if ($type == 1 && $maxtime < 2) {
|
||||
ajaxReturn(1, '多选投票最少可选2项');
|
||||
}
|
||||
|
||||
// 检查投票是否存在
|
||||
$vote = $db->getOne('vote', "id = $id");
|
||||
if (!$vote) {
|
||||
ajaxReturn(1, '投票不存在');
|
||||
}
|
||||
|
||||
// 更新投票主题
|
||||
$result = $db->update('vote', [
|
||||
'title' => $title,
|
||||
'idesc' => $desc,
|
||||
'statime' => $statime,
|
||||
'endtime' => $endtime,
|
||||
'itype' => $type,
|
||||
'maxtime' => $maxtime,
|
||||
'status' => $status
|
||||
], "id = $id");
|
||||
|
||||
if (!$result) {
|
||||
ajaxReturn(1, '更新失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'update_topic', "更新投票:$title");
|
||||
|
||||
ajaxReturn(0, '更新成功');
|
||||
break;
|
||||
|
||||
// 删除投票主题
|
||||
case 'delete':
|
||||
// 验证管理员权限
|
||||
$user = checkAuth('delete', true);
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($id)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 检查投票是否存在
|
||||
$vote = $db->getOne('vote', "id = $id");
|
||||
if (!$vote) {
|
||||
ajaxReturn(1, '投票不存在');
|
||||
}
|
||||
|
||||
// 开始事务
|
||||
$db->startTransaction();
|
||||
|
||||
try {
|
||||
// 删除相关记录
|
||||
$db->delete('recs', "topic_id = $id");
|
||||
$db->delete('xuan', "topic_id = $id");
|
||||
$db->delete('vote', "id = $id");
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'delete_topic', "删除投票:{$vote['title']}");
|
||||
|
||||
// 提交事务
|
||||
$db->commit();
|
||||
|
||||
ajaxReturn(0, '删除成功');
|
||||
} catch (Exception $e) {
|
||||
// 回滚事务
|
||||
$db->rollback();
|
||||
ajaxReturn(1, '删除失败:' . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
|
||||
// 获取投票选项
|
||||
case 'getOptions':
|
||||
// 获取参数
|
||||
$topicId = isset($_REQUEST['topic_id']) ? intval($_REQUEST['topic_id']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($topicId)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 获取选项列表
|
||||
$options = $db->getAll('xuan', "topic_id = $topicId", '*', 'sort ASC, id ASC');
|
||||
|
||||
ajaxReturn(0, '获取成功', $options);
|
||||
break;
|
||||
|
||||
// 添加投票选项
|
||||
case 'addOption':
|
||||
// 验证管理员权限
|
||||
$user = checkAuth('addOption', true);
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$topicId = isset($_POST['topic_id']) ? intval($_POST['topic_id']) : 0;
|
||||
$name = isset($_POST['name']) ? safeFilter($_POST['name']) : '';
|
||||
$imgs = isset($_POST['imgs']) ? safeFilter($_POST['imgs']) : '';
|
||||
$desc = isset($_POST['desc']) ? safeFilter($_POST['desc']) : '';
|
||||
$sort = isset($_POST['sort']) ? intval($_POST['sort']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($topicId) || empty($name)) {
|
||||
ajaxReturn(1, '请填写必要参数');
|
||||
}
|
||||
|
||||
// 检查投票是否存在
|
||||
$vote = $db->getOne('vote', "id = $topicId");
|
||||
if (!$vote) {
|
||||
ajaxReturn(1, '投票不存在');
|
||||
}
|
||||
|
||||
// 添加选项
|
||||
$optionId = $db->insert('xuan', [
|
||||
'topic_id' => $topicId,
|
||||
'name' => $name,
|
||||
'imgs' => $imgs,
|
||||
'idesc' => $desc,
|
||||
'sort' => $sort,
|
||||
'addtime' => date('Y-m-d H:i:s'),
|
||||
'adduser' => $user['id']
|
||||
]);
|
||||
|
||||
if (!$optionId) {
|
||||
ajaxReturn(1, '添加失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'add_option', "添加投票选项:$name");
|
||||
|
||||
ajaxReturn(0, '添加成功', ['id' => $optionId]);
|
||||
break;
|
||||
|
||||
// 更新投票选项
|
||||
case 'updateOption':
|
||||
// 验证管理员权限
|
||||
$user = checkAuth('updateOption', true);
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
$name = isset($_POST['name']) ? safeFilter($_POST['name']) : '';
|
||||
$imgs = isset($_POST['imgs']) ? safeFilter($_POST['imgs']) : '';
|
||||
$desc = isset($_POST['desc']) ? safeFilter($_POST['desc']) : '';
|
||||
$sort = isset($_POST['sort']) ? intval($_POST['sort']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($id) || empty($name)) {
|
||||
ajaxReturn(1, '请填写必要参数');
|
||||
}
|
||||
|
||||
// 检查选项是否存在
|
||||
$option = $db->getOne('xuan', "id = $id");
|
||||
if (!$option) {
|
||||
ajaxReturn(1, '选项不存在');
|
||||
}
|
||||
|
||||
// 更新选项
|
||||
$result = $db->update('xuan', [
|
||||
'name' => $name,
|
||||
'imgs' => $imgs,
|
||||
'idesc' => $desc,
|
||||
'sort' => $sort
|
||||
], "id = $id");
|
||||
|
||||
if (!$result) {
|
||||
ajaxReturn(1, '更新失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'update_option', "更新投票选项:$name");
|
||||
|
||||
ajaxReturn(0, '更新成功');
|
||||
break;
|
||||
|
||||
// 删除投票选项
|
||||
case 'deleteOption':
|
||||
// 验证管理员权限
|
||||
$user = checkAuth('deleteOption', true);
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$id = isset($_POST['id']) ? intval($_POST['id']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($id)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 检查选项是否存在
|
||||
$option = $db->getOne('xuan', "id = $id");
|
||||
if (!$option) {
|
||||
ajaxReturn(1, '选项不存在');
|
||||
}
|
||||
|
||||
// 开始事务
|
||||
$db->startTransaction();
|
||||
|
||||
try {
|
||||
// 删除投票记录
|
||||
$db->delete('recs', "option_id = $id");
|
||||
|
||||
// 删除选项
|
||||
$db->delete('xuan', "id = $id");
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'delete_option', "删除投票选项:{$option['name']}");
|
||||
|
||||
// 提交事务
|
||||
$db->commit();
|
||||
|
||||
ajaxReturn(0, '删除成功');
|
||||
} catch (Exception $e) {
|
||||
// 回滚事务
|
||||
$db->rollback();
|
||||
ajaxReturn(1, '删除失败:' . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
|
||||
// 未知操作
|
||||
default:
|
||||
ajaxReturn(1, '未知操作');
|
||||
break;
|
||||
}
|
||||
203
ht/api/upload.php
Normal file
203
ht/api/upload.php
Normal file
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 图片上传处理API
|
||||
* 处理图片上传,支持自动调整大于1280宽度的图片为1024宽度
|
||||
*/
|
||||
|
||||
// 引入必要文件
|
||||
require_once '../inc/pubs.php';
|
||||
require_once '../inc/sqls.php';
|
||||
|
||||
// 验证用户登录状态
|
||||
if (!checkLogin()) {
|
||||
exit(json_encode([
|
||||
'code' => 1001,
|
||||
'msg' => '请先登录'
|
||||
]));
|
||||
}
|
||||
|
||||
// 检查请求方法
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
exit(json_encode([
|
||||
'code' => 1002,
|
||||
'msg' => '请求方法错误'
|
||||
]));
|
||||
}
|
||||
|
||||
// 检查是否有文件上传
|
||||
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
|
||||
exit(json_encode([
|
||||
'code' => 1003,
|
||||
'msg' => '上传失败: ' . uploadErrorMessage($_FILES['image']['error'])
|
||||
]));
|
||||
}
|
||||
|
||||
// 验证文件类型
|
||||
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
$fileType = $_FILES['image']['type'];
|
||||
|
||||
if (!in_array($fileType, $allowedTypes)) {
|
||||
exit(json_encode([
|
||||
'code' => 1004,
|
||||
'msg' => '只允许上传JPG、PNG、GIF和WEBP格式的图片'
|
||||
]));
|
||||
}
|
||||
|
||||
// 验证文件大小(最大10MB)
|
||||
$maxFileSize = 10 * 1024 * 1024; // 10MB
|
||||
if ($_FILES['image']['size'] > $maxFileSize) {
|
||||
exit(json_encode([
|
||||
'code' => 1005,
|
||||
'msg' => '文件大小超过限制,最大允许10MB'
|
||||
]));
|
||||
}
|
||||
|
||||
// 准备上传路径
|
||||
$uploadDir = '../uploads/';
|
||||
if (!file_exists($uploadDir)) {
|
||||
mkdir($uploadDir, 0777, true);
|
||||
}
|
||||
|
||||
// 生成唯一文件名
|
||||
$extension = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
|
||||
$fileName = uniqid('img_') . '_' . date('Ymd') . '.' . $extension;
|
||||
$uploadPath = $uploadDir . $fileName;
|
||||
$relativeUrl = 'uploads/' . $fileName;
|
||||
|
||||
// 处理图片上传
|
||||
$uploaded = false;
|
||||
|
||||
// 获取图片信息
|
||||
$imageInfo = getimagesize($_FILES['image']['tmp_name']);
|
||||
if (!$imageInfo) {
|
||||
exit(json_encode([
|
||||
'code' => 1006,
|
||||
'msg' => '无效的图片文件'
|
||||
]));
|
||||
}
|
||||
|
||||
$width = $imageInfo[0];
|
||||
$height = $imageInfo[1];
|
||||
|
||||
// 如果图片宽度大于1280,则调整为1024宽度(尽管前端已经处理,这里作为后端保障)
|
||||
if ($width > 1280) {
|
||||
// 计算新高度,保持比例
|
||||
$newWidth = 1024;
|
||||
$newHeight = intval($height * ($newWidth / $width));
|
||||
|
||||
// 根据图片类型创建图像
|
||||
switch ($imageInfo[2]) {
|
||||
case IMAGETYPE_JPEG:
|
||||
$source = imagecreatefromjpeg($_FILES['image']['tmp_name']);
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
$source = imagecreatefrompng($_FILES['image']['tmp_name']);
|
||||
break;
|
||||
case IMAGETYPE_GIF:
|
||||
$source = imagecreatefromgif($_FILES['image']['tmp_name']);
|
||||
break;
|
||||
case IMAGETYPE_WEBP:
|
||||
$source = imagecreatefromwebp($_FILES['image']['tmp_name']);
|
||||
break;
|
||||
default:
|
||||
exit(json_encode([
|
||||
'code' => 1007,
|
||||
'msg' => '不支持的图片格式'
|
||||
]));
|
||||
}
|
||||
|
||||
// 创建新图像
|
||||
$thumb = imagecreatetruecolor($newWidth, $newHeight);
|
||||
|
||||
// 保持PNG和WebP的透明度
|
||||
if ($imageInfo[2] == IMAGETYPE_PNG || $imageInfo[2] == IMAGETYPE_WEBP) {
|
||||
imagealphablending($thumb, false);
|
||||
imagesavealpha($thumb, true);
|
||||
$transparent = imagecolorallocatealpha($thumb, 255, 255, 255, 127);
|
||||
imagefilledrectangle($thumb, 0, 0, $newWidth, $newHeight, $transparent);
|
||||
}
|
||||
|
||||
// 调整图像大小
|
||||
imagecopyresampled($thumb, $source, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
||||
|
||||
// 保存图像
|
||||
switch ($imageInfo[2]) {
|
||||
case IMAGETYPE_JPEG:
|
||||
$uploaded = imagejpeg($thumb, $uploadPath, 90);
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
$uploaded = imagepng($thumb, $uploadPath, 9);
|
||||
break;
|
||||
case IMAGETYPE_GIF:
|
||||
$uploaded = imagegif($thumb, $uploadPath);
|
||||
break;
|
||||
case IMAGETYPE_WEBP:
|
||||
$uploaded = imagewebp($thumb, $uploadPath, 90);
|
||||
break;
|
||||
}
|
||||
|
||||
// 释放内存
|
||||
imagedestroy($source);
|
||||
imagedestroy($thumb);
|
||||
} else {
|
||||
// 直接移动上传的文件
|
||||
$uploaded = move_uploaded_file($_FILES['image']['tmp_name'], $uploadPath);
|
||||
}
|
||||
|
||||
// 检查上传是否成功
|
||||
if (!$uploaded) {
|
||||
exit(json_encode([
|
||||
'code' => 1008,
|
||||
'msg' => '文件保存失败'
|
||||
]));
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
$user = $_SESSION['user'];
|
||||
$ip = "".$_SERVER['REMOTE_ADDR'];
|
||||
$db = new DB();
|
||||
$db->insert('logs', [
|
||||
'user_id' => $user['id'],
|
||||
'action' => '上传图片',
|
||||
'idesc' => '上传了图片: ' . $fileName,
|
||||
'ip' => $ip,
|
||||
'logtime' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
// 返回成功信息和图片URL
|
||||
exit(json_encode([
|
||||
'code' => 0,
|
||||
'msg' => '上传成功',
|
||||
'data' => [
|
||||
'url' => $relativeUrl,
|
||||
'width' => $width,
|
||||
'height' => $height
|
||||
]
|
||||
]));
|
||||
|
||||
/**
|
||||
* 获取上传错误消息
|
||||
* @param int $errorCode 上传错误代码
|
||||
* @return string 错误消息
|
||||
*/
|
||||
function uploadErrorMessage($errorCode) {
|
||||
switch ($errorCode) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
return '上传的文件超过了php.ini中upload_max_filesize指令限制的大小';
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
return '上传的文件超过了HTML表单中MAX_FILE_SIZE指令指定的大小';
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
return '文件只有部分被上传';
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
return '没有文件被上传';
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
return '找不到临时文件夹';
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
return '文件写入失败';
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
return '文件上传被PHP扩展程序中断';
|
||||
default:
|
||||
return '未知上传错误';
|
||||
}
|
||||
}
|
||||
238
ht/api/user.php
Normal file
238
ht/api/user.php
Normal file
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 用户相关API
|
||||
*/
|
||||
|
||||
// 引入必要文件
|
||||
require_once '../inc/pubs.php';
|
||||
require_once '../inc/sqls.php';
|
||||
|
||||
// 获取操作类型
|
||||
$action = isset($_REQUEST['act']) ? $_REQUEST['act'] : '';
|
||||
|
||||
// 实例化数据库操作类
|
||||
$db = new DB();
|
||||
|
||||
// 根据操作类型执行相应操作
|
||||
switch ($action) {
|
||||
// 用户登录
|
||||
case 'login':
|
||||
// 获取参数
|
||||
$username = isset($_POST['username']) ? safeFilter($_POST['username']) : '';
|
||||
$password = isset($_POST['password']) ? $_POST['password'] : '';
|
||||
|
||||
// 参数验证
|
||||
if (empty($username) || empty($password)) {
|
||||
ajaxReturn(1, '账号和密码不能为空');
|
||||
}
|
||||
|
||||
// 查询用户
|
||||
$user = $db->getOne('users', "username = '$username'");
|
||||
|
||||
// 验证用户和密码
|
||||
if (!$user || !password_verify($password, $user['password'])) {
|
||||
ajaxReturn(1, '用户名或密码错误');
|
||||
}
|
||||
|
||||
// 验证用户状态
|
||||
if ($user['status'] != 1) {
|
||||
ajaxReturn(1, '账号已被禁用,请联系管理员');
|
||||
}
|
||||
|
||||
// 更新最后登录时间
|
||||
$db->update('users', [
|
||||
'logtime' => date('Y-m-d H:i:s')
|
||||
], "id = {$user['id']}");
|
||||
|
||||
// 记录登录日志
|
||||
writeLog($user['id'], 'login', '用户登录');
|
||||
|
||||
// 存储session
|
||||
session_start();
|
||||
$_SESSION['user'] = $user;
|
||||
|
||||
ajaxReturn(0, '登录成功', $user);
|
||||
break;
|
||||
|
||||
// 用户注册
|
||||
case 'register':
|
||||
// 获取参数
|
||||
$username = isset($_POST['username']) ? safeFilter($_POST['username']) : '';
|
||||
$password = isset($_POST['password']) ? $_POST['password'] : '';
|
||||
$userIdentifier = isset($_POST['user_identifier']) ? safeFilter($_POST['user_identifier']) : '';
|
||||
|
||||
// 参数验证
|
||||
if (empty($username) || empty($password)) {
|
||||
ajaxReturn(1, '账号和密码不能为空');
|
||||
}
|
||||
|
||||
// 验证账号格式(手机号/邮箱/微信号)
|
||||
$phoneRegex = '/^1[3456789]\d{9}$/';
|
||||
$emailRegex = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
|
||||
$wechatRegex = '/^[a-zA-Z0-9_-]{6,20}$/';
|
||||
|
||||
if (!preg_match($phoneRegex, $username) && !preg_match($emailRegex, $username) && !preg_match($wechatRegex, $username)) {
|
||||
ajaxReturn(1, '请输入正确的手机号、邮箱或微信号');
|
||||
}
|
||||
|
||||
// 验证密码长度
|
||||
if (strlen($password) < 6) {
|
||||
ajaxReturn(1, '密码长度不能少于6位');
|
||||
}
|
||||
|
||||
// 检查用户名是否已存在
|
||||
$existUser = $db->getOne('users', "username = '$username'");
|
||||
if ($existUser) {
|
||||
ajaxReturn(1, '该账号已被注册');
|
||||
}
|
||||
|
||||
// 密码加密
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
// 添加用户
|
||||
$userId = $db->insert('users', [
|
||||
'username' => $username,
|
||||
'password' => $hashedPassword,
|
||||
'irole' => 0, // 普通用户
|
||||
'status' => 1, // 正常状态
|
||||
'regtime' => date('Y-m-d H:i:s'),
|
||||
'user_identifier' => $userIdentifier
|
||||
]);
|
||||
|
||||
if (!$userId) {
|
||||
ajaxReturn(1, '注册失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录注册日志
|
||||
writeLog($userId, 'register', '用户注册');
|
||||
|
||||
ajaxReturn(0, '注册成功');
|
||||
break;
|
||||
|
||||
// 用户登出
|
||||
case 'logout':
|
||||
session_start();
|
||||
|
||||
// 记录登出日志
|
||||
if (isset($_SESSION['user']) && !empty($_SESSION['user']['id'])) {
|
||||
writeLog($_SESSION['user']['id'], 'logout', '用户登出');
|
||||
}
|
||||
|
||||
// 清除session
|
||||
unset($_SESSION['user']);
|
||||
session_destroy();
|
||||
|
||||
// 跳转到首页
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
break;
|
||||
|
||||
// 获取用户信息
|
||||
case 'getUserInfo':
|
||||
// 验证权限
|
||||
$user = checkAuth('getUserInfo');
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 移除敏感信息
|
||||
unset($user['password']);
|
||||
|
||||
ajaxReturn(0, '获取成功', $user);
|
||||
break;
|
||||
|
||||
// 更新用户信息
|
||||
case 'updateUserInfo':
|
||||
// 验证权限
|
||||
$user = checkAuth('updateUserInfo');
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$newPassword = isset($_POST['new_password']) ? $_POST['new_password'] : '';
|
||||
$confirmPassword = isset($_POST['confirm_password']) ? $_POST['confirm_password'] : '';
|
||||
|
||||
// 如果要更新密码
|
||||
if (!empty($newPassword)) {
|
||||
// 验证密码长度
|
||||
if (strlen($newPassword) < 6) {
|
||||
ajaxReturn(1, '密码长度不能少于6位');
|
||||
}
|
||||
|
||||
// 验证两次密码是否一致
|
||||
if ($newPassword !== $confirmPassword) {
|
||||
ajaxReturn(1, '两次输入的密码不一致');
|
||||
}
|
||||
|
||||
// 更新密码
|
||||
$hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);
|
||||
|
||||
// 更新用户信息
|
||||
$result = $db->update('users', [
|
||||
'password' => $hashedPassword
|
||||
], "id = {$user['id']}");
|
||||
|
||||
if (!$result) {
|
||||
ajaxReturn(1, '更新失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'update_password', '修改密码');
|
||||
|
||||
// 更新 session 中的用户信息
|
||||
$updatedUser = $db->getOne('users', "id = {$user['id']}");
|
||||
$_SESSION['user'] = $updatedUser;
|
||||
|
||||
ajaxReturn(0, '密码更新成功');
|
||||
} else {
|
||||
ajaxReturn(1, '请输入新密码');
|
||||
}
|
||||
break;
|
||||
|
||||
// 更新用户标识
|
||||
case 'updateUserIdentifier':
|
||||
// 验证权限
|
||||
$user = checkAuth('updateUserIdentifier');
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$userIdentifier = isset($_POST['user_identifier']) ? safeFilter($_POST['user_identifier']) : '';
|
||||
|
||||
// 验证用户标识长度
|
||||
if (strlen($userIdentifier) > 100) {
|
||||
ajaxReturn(1, '用户标识长度不能超过100个字符');
|
||||
}
|
||||
|
||||
// 更新用户标识
|
||||
$result = $db->update('users', [
|
||||
'user_identifier' => $userIdentifier
|
||||
], "id = {$user['id']}");
|
||||
|
||||
if (!$result) {
|
||||
ajaxReturn(1, '更新失败,请稍后重试');
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'update_identifier', '更新用户标识');
|
||||
|
||||
// 获取更新后的用户信息
|
||||
$updatedUser = $db->getOne('users', "id = {$user['id']}");
|
||||
|
||||
// 移除敏感信息
|
||||
unset($updatedUser['password']);
|
||||
|
||||
// 更新 session 中的用户信息
|
||||
$_SESSION['user'] = $updatedUser;
|
||||
|
||||
ajaxReturn(0, '更新成功', $updatedUser);
|
||||
break;
|
||||
|
||||
// 未知操作
|
||||
default:
|
||||
ajaxReturn(1, '未知操作');
|
||||
break;
|
||||
}
|
||||
219
ht/api/vote.php
Normal file
219
ht/api/vote.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 投票操作API
|
||||
*/
|
||||
|
||||
// 引入必要文件
|
||||
require_once '../inc/pubs.php';
|
||||
require_once '../inc/sqls.php';
|
||||
|
||||
// 获取操作类型
|
||||
$action = isset($_REQUEST['act']) ? $_REQUEST['act'] : '';
|
||||
|
||||
// 实例化数据库操作类
|
||||
$db = new DB();
|
||||
|
||||
// 根据操作类型执行相应操作
|
||||
switch ($action) {
|
||||
// 提交投票
|
||||
case 'submit':
|
||||
// 验证权限
|
||||
$user = checkAuth('submit');
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$topicId = isset($_POST['topic_id']) ? intval($_POST['topic_id']) : 0;
|
||||
$optionsStr = isset($_POST['options']) ? $_POST['options'] : '';
|
||||
|
||||
// 参数验证
|
||||
if (empty($topicId) || empty($optionsStr)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 转换选项为数组
|
||||
$options = explode(',', $optionsStr);
|
||||
if (empty($options)) {
|
||||
ajaxReturn(1, '请至少选择一个选项');
|
||||
}
|
||||
|
||||
// 获取投票信息
|
||||
$vote = $db->getOne('vote', "id = $topicId");
|
||||
if (!$vote) {
|
||||
ajaxReturn(1, '投票不存在');
|
||||
}
|
||||
|
||||
// 验证投票状态
|
||||
$now = date('Y-m-d H:i:s');
|
||||
if ($vote['status'] != 1) {
|
||||
ajaxReturn(1, '该投票已被禁用');
|
||||
}
|
||||
|
||||
if ($vote['statime'] > $now) {
|
||||
ajaxReturn(1, '该投票尚未开始');
|
||||
}
|
||||
|
||||
if ($vote['endtime'] < $now) {
|
||||
ajaxReturn(1, '该投票已经结束');
|
||||
}
|
||||
|
||||
// 检查用户是否已投票
|
||||
$hasVoted = $db->count('recs', "topic_id = $topicId AND user_id = {$user['id']}");
|
||||
if ($hasVoted > 0) {
|
||||
ajaxReturn(1, '您已经参与过该投票');
|
||||
}
|
||||
|
||||
// 验证选项数量
|
||||
if ($vote['itype'] == 1 && count($options) > $vote['maxtime']) {
|
||||
ajaxReturn(1, "最多只能选择 {$vote['maxtime']} 项");
|
||||
}
|
||||
|
||||
// 验证选项是否存在
|
||||
foreach ($options as $optionId) {
|
||||
$option = $db->getOne('xuan', "id = $optionId AND topic_id = $topicId");
|
||||
if (!$option) {
|
||||
ajaxReturn(1, '选项不存在');
|
||||
}
|
||||
}
|
||||
|
||||
// 开始事务
|
||||
$db->startTransaction();
|
||||
|
||||
try {
|
||||
// 添加投票记录
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
$time = date('Y-m-d H:i:s');
|
||||
|
||||
foreach ($options as $optionId) {
|
||||
$result = $db->insert('recs', [
|
||||
'topic_id' => $topicId,
|
||||
'user_id' => $user['id'],
|
||||
'option_id' => $optionId,
|
||||
'vote_time' => $time,
|
||||
'ip' => $ip
|
||||
]);
|
||||
|
||||
if (!$result) {
|
||||
throw new Exception('提交投票失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 记录日志
|
||||
writeLog($user['id'], 'vote', "参与投票:{$vote['title']}");
|
||||
|
||||
// 提交事务
|
||||
$db->commit();
|
||||
|
||||
ajaxReturn(0, '投票成功');
|
||||
} catch (Exception $e) {
|
||||
// 回滚事务
|
||||
$db->rollback();
|
||||
ajaxReturn(1, $e->getMessage());
|
||||
}
|
||||
break;
|
||||
|
||||
// 检查是否已投票
|
||||
case 'checkVoted':
|
||||
// 验证权限
|
||||
$user = checkAuth('checkVoted');
|
||||
if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取参数
|
||||
$topicId = isset($_REQUEST['topic_id']) ? intval($_REQUEST['topic_id']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($topicId)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 检查用户是否已投票
|
||||
$hasVoted = $db->count('recs', "topic_id = $topicId AND user_id = {$user['id']}");
|
||||
|
||||
ajaxReturn(0, '查询成功', ['hasVoted' => $hasVoted > 0]);
|
||||
break;
|
||||
|
||||
// 获取投票结果
|
||||
case 'getResult':
|
||||
// 获取参数
|
||||
$topicId = isset($_REQUEST['topic_id']) ? intval($_REQUEST['topic_id']) : 0;
|
||||
|
||||
// 参数验证
|
||||
if (empty($topicId)) {
|
||||
ajaxReturn(1, '参数错误');
|
||||
}
|
||||
|
||||
// 获取投票信息
|
||||
$vote = $db->getOne('vote', "id = $topicId");
|
||||
if (!$vote) {
|
||||
ajaxReturn(1, '投票不存在');
|
||||
}
|
||||
|
||||
// 获取选项列表
|
||||
$options = $db->getAll('xuan', "topic_id = $topicId", '*', 'sort ASC, id ASC');
|
||||
if (empty($options)) {
|
||||
ajaxReturn(1, '暂无投票选项');
|
||||
}
|
||||
|
||||
// 获取投票结果
|
||||
$sql = "SELECT option_id, COUNT(*) as vote_count FROM " . $db->table('recs') . " WHERE topic_id = $topicId GROUP BY option_id";
|
||||
$result = $db->query($sql);
|
||||
|
||||
$voteResults = [];
|
||||
$totalVotes = 0;
|
||||
|
||||
if ($result) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$voteResults[$row['option_id']] = $row['vote_count'];
|
||||
$totalVotes += $row['vote_count'];
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化结果
|
||||
$formattedResults = [];
|
||||
foreach ($options as $option) {
|
||||
$voteCount = isset($voteResults[$option['id']]) ? $voteResults[$option['id']] : 0;
|
||||
$percentage = $totalVotes > 0 ? round(($voteCount / $totalVotes) * 100, 1) : 0;
|
||||
|
||||
$formattedResults[] = [
|
||||
'id' => $option['id'],
|
||||
'name' => $option['name'],
|
||||
'count' => $voteCount,
|
||||
'percentage' => $percentage
|
||||
];
|
||||
}
|
||||
|
||||
// 用户是否已投票
|
||||
$hasVoted = false;
|
||||
$userVotes = [];
|
||||
|
||||
if (isset($_SESSION['user']) && !empty($_SESSION['user']['id'])) {
|
||||
$userId = $_SESSION['user']['id'];
|
||||
$userVoteRecords = $db->getAll('recs', "topic_id = $topicId AND user_id = $userId");
|
||||
|
||||
if (!empty($userVoteRecords)) {
|
||||
$hasVoted = true;
|
||||
foreach ($userVoteRecords as $record) {
|
||||
$userVotes[] = $record['option_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ajaxReturn(0, '获取成功', [
|
||||
'vote' => $vote,
|
||||
'options' => $options,
|
||||
'results' => $formattedResults,
|
||||
'totalVotes' => $totalVotes,
|
||||
'hasVoted' => $hasVoted,
|
||||
'userVotes' => $userVotes
|
||||
]);
|
||||
break;
|
||||
|
||||
// 未知操作
|
||||
default:
|
||||
ajaxReturn(1, '未知操作');
|
||||
break;
|
||||
}
|
||||
Reference in New Issue
Block a user