553 行
19 KiB
PHP
553 行
19 KiB
PHP
<?php
|
||
namespace Retail\Controller;
|
||
use Think\Controller;
|
||
|
||
/**
|
||
* 骑手系统消息管理控制器
|
||
*/
|
||
class RiderMessageController extends Controller {
|
||
|
||
/**
|
||
* 消息管理首页
|
||
*/
|
||
public function index() {
|
||
$this->display();
|
||
}
|
||
|
||
/**
|
||
* 获取消息列表
|
||
*/
|
||
public function getMessageList() {
|
||
$page = I('page', 1, 'intval');
|
||
$pageSize = I('pageSize', 20, 'intval');
|
||
$keyword = I('keyword', '', 'trim');
|
||
$type = I('type', '', 'trim');
|
||
$status = I('status', '', 'trim');
|
||
$start_time = I('start_time', '', 'trim');
|
||
$end_time = I('end_time', '', 'trim');
|
||
|
||
$where = array();
|
||
|
||
// 关键词搜索
|
||
if (!empty($keyword)) {
|
||
$where['title|content'] = array('like', '%' . $keyword . '%');
|
||
}
|
||
|
||
// 消息类型筛选
|
||
if ($type !== '') {
|
||
$where['message_type'] = $type;
|
||
}
|
||
|
||
// 状态筛选
|
||
if ($status !== '') {
|
||
$where['status'] = $status;
|
||
}
|
||
|
||
// 时间范围筛选
|
||
if (!empty($start_time)) {
|
||
$where['create_time'] = array('egt', strtotime($start_time . ' 00:00:00'));
|
||
}
|
||
if (!empty($end_time)) {
|
||
$where['create_time'] = array('elt', strtotime($end_time . ' 23:59:59'));
|
||
}
|
||
|
||
$model = M('rider_message');
|
||
$total = $model->where($where)->count();
|
||
|
||
$list = $model->where($where)
|
||
->order('create_time desc')
|
||
->page($page, $pageSize)
|
||
->select();
|
||
|
||
// 格式化数据
|
||
foreach ($list as &$item) {
|
||
$item['message_type_text'] = $this->getMessageTypeText($item['message_type']);
|
||
$item['status_text'] = $this->getStatusText($item['status']);
|
||
$item['create_time_format'] = date('Y-m-d H:i:s', $item['create_time']);
|
||
$item['send_time_format'] = $item['send_time'] ? date('Y-m-d H:i:s', $item['send_time']) : '';
|
||
|
||
// 统计接收人数和已读人数
|
||
if ($item['target_type'] == 'all') {
|
||
$item['target_count'] = M('users')->where(array('user_type' => 'rider', 'status' => 1))->count();
|
||
} elseif ($item['target_type'] == 'specific') {
|
||
$item['target_count'] = M('rider_message_receiver')->where(array('message_id' => $item['id']))->count();
|
||
} else {
|
||
$item['target_count'] = 0;
|
||
}
|
||
|
||
$item['read_count'] = M('rider_message_read')->where(array('message_id' => $item['id']))->count();
|
||
}
|
||
|
||
$this->ajaxReturn(array(
|
||
'code' => 0,
|
||
'msg' => 'success',
|
||
'data' => array(
|
||
'list' => $list,
|
||
'total' => $total
|
||
)
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 获取消息详情
|
||
*/
|
||
public function getMessageDetail() {
|
||
$id = I('id', 0, 'intval');
|
||
if (empty($id)) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '参数错误'));
|
||
}
|
||
|
||
$detail = M('rider_message')->where(array('id' => $id))->find();
|
||
if (empty($detail)) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '消息不存在'));
|
||
}
|
||
|
||
// 格式化数据
|
||
$detail['message_type_text'] = $this->getMessageTypeText($detail['message_type']);
|
||
$detail['status_text'] = $this->getStatusText($detail['status']);
|
||
$detail['create_time_format'] = date('Y-m-d H:i:s', $detail['create_time']);
|
||
$detail['send_time_format'] = $detail['send_time'] ? date('Y-m-d H:i:s', $detail['send_time']) : '';
|
||
|
||
// 获取接收人列表
|
||
if ($detail['target_type'] == 'specific') {
|
||
$receivers = M('rider_message_receiver')->alias('r')
|
||
->field('r.*, u.nickname, u.phone')
|
||
->join('ls_users u ON r.rider_id = u.id')
|
||
->where(array('r.message_id' => $id))
|
||
->select();
|
||
$detail['receivers'] = $receivers;
|
||
}
|
||
|
||
// 获取已读统计
|
||
$read_stats = M('rider_message_read')->alias('r')
|
||
->field('r.*, u.nickname, u.phone')
|
||
->join('ls_users u ON r.rider_id = u.id')
|
||
->where(array('r.message_id' => $id))
|
||
->order('r.read_time desc')
|
||
->select();
|
||
|
||
foreach ($read_stats as &$read) {
|
||
$read['read_time_format'] = date('Y-m-d H:i:s', $read['read_time']);
|
||
}
|
||
|
||
$detail['read_stats'] = $read_stats;
|
||
|
||
$this->ajaxReturn(array(
|
||
'code' => 0,
|
||
'msg' => 'success',
|
||
'data' => $detail
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 添加/编辑消息
|
||
*/
|
||
public function saveMessage() {
|
||
$id = I('id', 0, 'intval');
|
||
$data = array(
|
||
'title' => I('title', '', 'trim'),
|
||
'content' => I('content', '', 'trim'),
|
||
'message_type' => I('message_type', '', 'trim'),
|
||
'target_type' => I('target_type', '', 'trim'),
|
||
'send_immediately' => I('send_immediately', 0, 'intval'),
|
||
'scheduled_time' => I('scheduled_time', '', 'trim'),
|
||
'image_url' => I('image_url', '', 'trim'),
|
||
'link_url' => I('link_url', '', 'trim'),
|
||
'status' => I('status', 0, 'intval')
|
||
);
|
||
|
||
$target_riders = I('target_riders', '', 'trim');
|
||
|
||
// 数据验证
|
||
if (empty($data['title'])) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '消息标题不能为空'));
|
||
}
|
||
if (empty($data['content'])) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '消息内容不能为空'));
|
||
}
|
||
if (empty($data['message_type'])) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '请选择消息类型'));
|
||
}
|
||
if (empty($data['target_type'])) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '请选择发送对象'));
|
||
}
|
||
|
||
if ($data['target_type'] == 'specific' && empty($target_riders)) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '请选择接收骑手'));
|
||
}
|
||
|
||
if (!$data['send_immediately'] && empty($data['scheduled_time'])) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '请设置发送时间'));
|
||
}
|
||
|
||
// 处理发送时间
|
||
if ($data['send_immediately']) {
|
||
$data['send_time'] = time();
|
||
$data['status'] = 1; // 已发送
|
||
} else {
|
||
$data['send_time'] = strtotime($data['scheduled_time']);
|
||
$data['status'] = 0; // 待发送
|
||
}
|
||
|
||
unset($data['send_immediately'], $data['scheduled_time']);
|
||
|
||
$model = M('rider_message');
|
||
|
||
// 开启事务
|
||
M()->startTrans();
|
||
|
||
try {
|
||
if ($id > 0) {
|
||
// 编辑
|
||
$data['update_time'] = time();
|
||
$result = $model->where(array('id' => $id))->save($data);
|
||
$message_id = $id;
|
||
} else {
|
||
// 添加
|
||
$data['create_time'] = time();
|
||
$data['update_time'] = time();
|
||
$message_id = $model->add($data);
|
||
$result = $message_id;
|
||
}
|
||
|
||
if (!$result) {
|
||
throw new \Exception('保存消息失败');
|
||
}
|
||
|
||
// 处理接收人
|
||
if ($data['target_type'] == 'specific') {
|
||
// 先删除原有接收人
|
||
M('rider_message_receiver')->where(array('message_id' => $message_id))->delete();
|
||
|
||
// 添加新的接收人
|
||
$rider_ids = explode(',', $target_riders);
|
||
foreach ($rider_ids as $rider_id) {
|
||
$rider_id = intval($rider_id);
|
||
if ($rider_id <= 0) continue;
|
||
|
||
M('rider_message_receiver')->add(array(
|
||
'message_id' => $message_id,
|
||
'rider_id' => $rider_id,
|
||
'create_time' => time()
|
||
));
|
||
}
|
||
}
|
||
|
||
// 如果是立即发送,执行发送逻辑
|
||
if ($data['status'] == 1) {
|
||
$this->sendMessage($message_id);
|
||
}
|
||
|
||
M()->commit();
|
||
$this->ajaxReturn(array('code' => 0, 'msg' => '操作成功'));
|
||
|
||
} catch (\Exception $e) {
|
||
M()->rollback();
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => $e->getMessage()));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送消息
|
||
*/
|
||
public function sendMessage($message_id = 0) {
|
||
if ($message_id == 0) {
|
||
$message_id = I('id', 0, 'intval');
|
||
}
|
||
|
||
if (empty($message_id)) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '参数错误'));
|
||
}
|
||
|
||
$message = M('rider_message')->where(array('id' => $message_id))->find();
|
||
if (empty($message)) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '消息不存在'));
|
||
}
|
||
|
||
if ($message['status'] == 1) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '消息已发送'));
|
||
}
|
||
|
||
// 获取目标骑手
|
||
$target_riders = array();
|
||
if ($message['target_type'] == 'all') {
|
||
$target_riders = M('users')->where(array('user_type' => 'rider', 'status' => 1))->getField('id', true);
|
||
} elseif ($message['target_type'] == 'specific') {
|
||
$target_riders = M('rider_message_receiver')->where(array('message_id' => $message_id))->getField('rider_id', true);
|
||
}
|
||
|
||
if (empty($target_riders)) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '没有找到目标骑手'));
|
||
}
|
||
|
||
// 这里可以集成推送服务,如极光推送、友盟推送等
|
||
// 示例:调用推送接口
|
||
$push_result = $this->pushToRiders($target_riders, $message);
|
||
|
||
// 更新消息状态
|
||
M('rider_message')->where(array('id' => $message_id))->save(array(
|
||
'status' => 1,
|
||
'send_time' => time(),
|
||
'update_time' => time()
|
||
));
|
||
|
||
if ($message_id == I('id', 0, 'intval')) {
|
||
$this->ajaxReturn(array('code' => 0, 'msg' => '发送成功'));
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 删除消息
|
||
*/
|
||
public function deleteMessage() {
|
||
$id = I('id', 0, 'intval');
|
||
if (empty($id)) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '参数错误'));
|
||
}
|
||
|
||
// 开启事务
|
||
M()->startTrans();
|
||
|
||
try {
|
||
// 删除消息
|
||
$result = M('rider_message')->where(array('id' => $id))->delete();
|
||
if (!$result) {
|
||
throw new \Exception('删除消息失败');
|
||
}
|
||
|
||
// 删除相关数据
|
||
M('rider_message_receiver')->where(array('message_id' => $id))->delete();
|
||
M('rider_message_read')->where(array('message_id' => $id))->delete();
|
||
|
||
M()->commit();
|
||
$this->ajaxReturn(array('code' => 0, 'msg' => '删除成功'));
|
||
|
||
} catch (\Exception $e) {
|
||
M()->rollback();
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => $e->getMessage()));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量发送消息
|
||
*/
|
||
public function batchSend() {
|
||
$ids = I('ids', '', 'trim');
|
||
if (empty($ids)) {
|
||
$this->ajaxReturn(array('code' => 1, 'msg' => '请选择要发送的消息'));
|
||
}
|
||
|
||
$id_array = explode(',', $ids);
|
||
$success_count = 0;
|
||
|
||
foreach ($id_array as $id) {
|
||
$id = intval($id);
|
||
if ($id <= 0) continue;
|
||
|
||
$message = M('rider_message')->where(array('id' => $id))->find();
|
||
if (empty($message) || $message['status'] == 1) {
|
||
continue;
|
||
}
|
||
|
||
try {
|
||
$this->sendMessage($id);
|
||
$success_count++;
|
||
} catch (\Exception $e) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
$this->ajaxReturn(array(
|
||
'code' => 0,
|
||
'msg' => "批量发送完成,成功发送{$success_count}条消息"
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 导出消息数据
|
||
*/
|
||
public function exportMessage() {
|
||
$keyword = I('keyword', '', 'trim');
|
||
$type = I('type', '', 'trim');
|
||
$status = I('status', '', 'trim');
|
||
$start_time = I('start_time', '', 'trim');
|
||
$end_time = I('end_time', '', 'trim');
|
||
|
||
$where = array();
|
||
|
||
if (!empty($keyword)) {
|
||
$where['title|content'] = array('like', '%' . $keyword . '%');
|
||
}
|
||
if ($type !== '') {
|
||
$where['message_type'] = $type;
|
||
}
|
||
if ($status !== '') {
|
||
$where['status'] = $status;
|
||
}
|
||
if (!empty($start_time)) {
|
||
$where['create_time'] = array('egt', strtotime($start_time . ' 00:00:00'));
|
||
}
|
||
if (!empty($end_time)) {
|
||
$where['create_time'] = array('elt', strtotime($end_time . ' 23:59:59'));
|
||
}
|
||
|
||
$list = M('rider_message')->where($where)->order('create_time desc')->select();
|
||
|
||
// 导出Excel
|
||
vendor('PHPExcel.PHPExcel');
|
||
$objPHPExcel = new \PHPExcel();
|
||
$objPHPExcel->setActiveSheetIndex(0);
|
||
$objActSheet = $objPHPExcel->getActiveSheet();
|
||
|
||
// 设置表头
|
||
$objActSheet->setCellValue('A1', '消息ID');
|
||
$objActSheet->setCellValue('B1', '消息标题');
|
||
$objActSheet->setCellValue('C1', '消息类型');
|
||
$objActSheet->setCellValue('D1', '发送对象');
|
||
$objActSheet->setCellValue('E1', '接收人数');
|
||
$objActSheet->setCellValue('F1', '已读人数');
|
||
$objActSheet->setCellValue('G1', '状态');
|
||
$objActSheet->setCellValue('H1', '创建时间');
|
||
$objActSheet->setCellValue('I1', '发送时间');
|
||
|
||
// 填充数据
|
||
$row = 2;
|
||
foreach ($list as $item) {
|
||
// 统计接收人数和已读人数
|
||
if ($item['target_type'] == 'all') {
|
||
$target_count = M('users')->where(array('user_type' => 'rider', 'status' => 1))->count();
|
||
} elseif ($item['target_type'] == 'specific') {
|
||
$target_count = M('rider_message_receiver')->where(array('message_id' => $item['id']))->count();
|
||
} else {
|
||
$target_count = 0;
|
||
}
|
||
|
||
$read_count = M('rider_message_read')->where(array('message_id' => $item['id']))->count();
|
||
|
||
$objActSheet->setCellValue('A' . $row, $item['id']);
|
||
$objActSheet->setCellValue('B' . $row, $item['title']);
|
||
$objActSheet->setCellValue('C' . $row, $this->getMessageTypeText($item['message_type']));
|
||
$objActSheet->setCellValue('D' . $row, $item['target_type'] == 'all' ? '全部骑手' : '指定骑手');
|
||
$objActSheet->setCellValue('E' . $row, $target_count);
|
||
$objActSheet->setCellValue('F' . $row, $read_count);
|
||
$objActSheet->setCellValue('G' . $row, $this->getStatusText($item['status']));
|
||
$objActSheet->setCellValue('H' . $row, date('Y-m-d H:i:s', $item['create_time']));
|
||
$objActSheet->setCellValue('I' . $row, $item['send_time'] ? date('Y-m-d H:i:s', $item['send_time']) : '');
|
||
$row++;
|
||
}
|
||
|
||
$filename = '系统消息_' . date('YmdHis') . '.xlsx';
|
||
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||
header('Content-Disposition: attachment;filename="' . $filename . '"');
|
||
header('Cache-Control: max-age=0');
|
||
|
||
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
|
||
$objWriter->save('php://output');
|
||
exit;
|
||
}
|
||
|
||
/**
|
||
* 获取消息统计
|
||
*/
|
||
public function getMessageStats() {
|
||
$start_time = I('start_time', '', 'trim');
|
||
$end_time = I('end_time', '', 'trim');
|
||
|
||
$where = array();
|
||
if (!empty($start_time)) {
|
||
$where['create_time'] = array('egt', strtotime($start_time . ' 00:00:00'));
|
||
}
|
||
if (!empty($end_time)) {
|
||
$where['create_time'] = array('elt', strtotime($end_time . ' 23:59:59'));
|
||
}
|
||
|
||
$model = M('rider_message');
|
||
|
||
$stats = array(
|
||
'total_count' => $model->where($where)->count(),
|
||
'sent_count' => $model->where(array_merge($where, array('status' => 1)))->count(),
|
||
'pending_count' => $model->where(array_merge($where, array('status' => 0)))->count(),
|
||
'announcement_count' => $model->where(array_merge($where, array('message_type' => 'announcement')))->count(),
|
||
'policy_count' => $model->where(array_merge($where, array('message_type' => 'policy')))->count(),
|
||
'activity_count' => $model->where(array_merge($where, array('message_type' => 'activity')))->count(),
|
||
'system_count' => $model->where(array_merge($where, array('message_type' => 'system')))->count()
|
||
);
|
||
|
||
// 计算总阅读率
|
||
$total_sent = $stats['sent_count'];
|
||
if ($total_sent > 0) {
|
||
$total_reads = M('rider_message_read')->alias('r')
|
||
->join('ls_rider_message m ON r.message_id = m.id')
|
||
->where(array_merge($where, array('m.status' => 1)))
|
||
->count();
|
||
$stats['read_rate'] = number_format(($total_reads / $total_sent) * 100, 2);
|
||
} else {
|
||
$stats['read_rate'] = '0.00';
|
||
}
|
||
|
||
$this->ajaxReturn(array(
|
||
'code' => 0,
|
||
'msg' => 'success',
|
||
'data' => $stats
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 推送消息到骑手
|
||
*/
|
||
private function pushToRiders($rider_ids, $message) {
|
||
// 这里集成具体的推送服务
|
||
// 例如:极光推送、友盟推送、Firebase等
|
||
|
||
// 示例代码(需要根据实际推送服务调整)
|
||
/*
|
||
$push_data = array(
|
||
'title' => $message['title'],
|
||
'content' => $message['content'],
|
||
'extras' => array(
|
||
'message_id' => $message['id'],
|
||
'message_type' => $message['message_type'],
|
||
'link_url' => $message['link_url']
|
||
)
|
||
);
|
||
|
||
// 调用推送接口
|
||
$push_service = new PushService();
|
||
$result = $push_service->pushToUsers($rider_ids, $push_data);
|
||
|
||
return $result;
|
||
*/
|
||
|
||
// 临时返回成功
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 获取消息类型文本
|
||
*/
|
||
private function getMessageTypeText($type) {
|
||
$typeMap = array(
|
||
'announcement' => '平台公告',
|
||
'policy' => '政策变更',
|
||
'activity' => '活动提醒',
|
||
'system' => '系统通知',
|
||
'order' => '订单通知',
|
||
'reward' => '奖励通知'
|
||
);
|
||
return isset($typeMap[$type]) ? $typeMap[$type] : '其他';
|
||
}
|
||
|
||
/**
|
||
* 获取状态文本
|
||
*/
|
||
private function getStatusText($status) {
|
||
$statusMap = array(
|
||
0 => '待发送',
|
||
1 => '已发送'
|
||
);
|
||
return isset($statusMap[$status]) ? $statusMap[$status] : '未知';
|
||
}
|
||
}
|
||
?>
|