449 行
16 KiB
PHP
449 行
16 KiB
PHP
<?php
|
|
namespace Retail\Controller;
|
|
use Think\Controller;
|
|
|
|
/**
|
|
* 骑手申诉处理管理控制器
|
|
*/
|
|
class RiderAppealController extends Controller {
|
|
|
|
/**
|
|
* 申诉管理首页
|
|
*/
|
|
public function index() {
|
|
$this->display();
|
|
}
|
|
|
|
/**
|
|
* 获取申诉列表
|
|
*/
|
|
public function getAppealList() {
|
|
$page = I('page', 1, 'intval');
|
|
$pageSize = I('pageSize', 20, 'intval');
|
|
$keyword = I('keyword', '', 'trim');
|
|
$status = I('status', '', 'trim');
|
|
$type = I('type', '', 'trim');
|
|
$start_time = I('start_time', '', 'trim');
|
|
$end_time = I('end_time', '', 'trim');
|
|
|
|
$where = array();
|
|
|
|
// 关键词搜索(骑手姓名、手机号、订单号)
|
|
if (!empty($keyword)) {
|
|
$where['_string'] = "(u.nickname LIKE '%{$keyword}%' OR u.phone LIKE '%{$keyword}%' OR a.order_no LIKE '%{$keyword}%')";
|
|
}
|
|
|
|
// 状态筛选
|
|
if ($status !== '') {
|
|
$where['a.status'] = $status;
|
|
}
|
|
|
|
// 申诉类型筛选
|
|
if ($type !== '') {
|
|
$where['a.appeal_type'] = $type;
|
|
}
|
|
|
|
// 时间范围筛选
|
|
if (!empty($start_time)) {
|
|
$where['a.create_time'] = array('egt', strtotime($start_time . ' 00:00:00'));
|
|
}
|
|
if (!empty($end_time)) {
|
|
$where['a.create_time'] = array('elt', strtotime($end_time . ' 23:59:59'));
|
|
}
|
|
|
|
$model = M('rider_appeal');
|
|
$total = $model->alias('a')
|
|
->join('ls_users u ON a.rider_id = u.id')
|
|
->where($where)
|
|
->count();
|
|
|
|
$list = $model->alias('a')
|
|
->field('a.*, u.nickname, u.phone, u.avatar')
|
|
->join('ls_users u ON a.rider_id = u.id')
|
|
->where($where)
|
|
->order('a.create_time desc')
|
|
->page($page, $pageSize)
|
|
->select();
|
|
|
|
// 格式化数据
|
|
foreach ($list as &$item) {
|
|
$item['status_text'] = $this->getStatusText($item['status']);
|
|
$item['appeal_type_text'] = $this->getAppealTypeText($item['appeal_type']);
|
|
$item['create_time_format'] = date('Y-m-d H:i:s', $item['create_time']);
|
|
$item['handle_time_format'] = $item['handle_time'] ? date('Y-m-d H:i:s', $item['handle_time']) : '';
|
|
|
|
// 获取订单信息
|
|
if (!empty($item['order_no'])) {
|
|
$order = M('order')->where(array('order_no' => $item['order_no']))->find();
|
|
$item['order_info'] = $order;
|
|
}
|
|
}
|
|
|
|
$this->ajaxReturn(array(
|
|
'code' => 0,
|
|
'msg' => 'success',
|
|
'data' => array(
|
|
'list' => $list,
|
|
'total' => $total
|
|
)
|
|
));
|
|
}
|
|
|
|
/**
|
|
* 获取申诉详情
|
|
*/
|
|
public function getAppealDetail() {
|
|
$id = I('id', 0, 'intval');
|
|
if (empty($id)) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '参数错误'));
|
|
}
|
|
|
|
$detail = M('rider_appeal')->alias('a')
|
|
->field('a.*, u.nickname, u.phone, u.avatar')
|
|
->join('ls_users u ON a.rider_id = u.id')
|
|
->where(array('a.id' => $id))
|
|
->find();
|
|
|
|
if (empty($detail)) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '申诉不存在'));
|
|
}
|
|
|
|
// 格式化数据
|
|
$detail['status_text'] = $this->getStatusText($detail['status']);
|
|
$detail['appeal_type_text'] = $this->getAppealTypeText($detail['appeal_type']);
|
|
$detail['create_time_format'] = date('Y-m-d H:i:s', $detail['create_time']);
|
|
$detail['handle_time_format'] = $detail['handle_time'] ? date('Y-m-d H:i:s', $detail['handle_time']) : '';
|
|
|
|
// 获取订单详情
|
|
if (!empty($detail['order_no'])) {
|
|
$order = M('order')->where(array('order_no' => $detail['order_no']))->find();
|
|
$detail['order_info'] = $order;
|
|
}
|
|
|
|
// 获取申诉图片
|
|
if (!empty($detail['images'])) {
|
|
$detail['image_list'] = explode(',', $detail['images']);
|
|
} else {
|
|
$detail['image_list'] = array();
|
|
}
|
|
|
|
// 获取处理记录
|
|
$handle_logs = M('rider_appeal_log')
|
|
->where(array('appeal_id' => $id))
|
|
->order('create_time desc')
|
|
->select();
|
|
$detail['handle_logs'] = $handle_logs;
|
|
|
|
$this->ajaxReturn(array(
|
|
'code' => 0,
|
|
'msg' => 'success',
|
|
'data' => $detail
|
|
));
|
|
}
|
|
|
|
/**
|
|
* 处理申诉
|
|
*/
|
|
public function handleAppeal() {
|
|
$id = I('id', 0, 'intval');
|
|
$status = I('status', 0, 'intval'); // 1:通过 2:驳回
|
|
$handle_remark = I('handle_remark', '', 'trim');
|
|
$compensation_amount = I('compensation_amount', 0, 'floatval');
|
|
|
|
if (empty($id)) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '参数错误'));
|
|
}
|
|
|
|
if (!in_array($status, array(1, 2))) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '处理状态错误'));
|
|
}
|
|
|
|
if (empty($handle_remark)) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '处理说明不能为空'));
|
|
}
|
|
|
|
// 获取申诉信息
|
|
$appeal = M('rider_appeal')->where(array('id' => $id))->find();
|
|
if (empty($appeal)) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '申诉不存在'));
|
|
}
|
|
|
|
if ($appeal['status'] != 0) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '该申诉已处理'));
|
|
}
|
|
|
|
// 开启事务
|
|
M()->startTrans();
|
|
|
|
try {
|
|
// 更新申诉状态
|
|
$update_data = array(
|
|
'status' => $status,
|
|
'handle_remark' => $handle_remark,
|
|
'handle_time' => time(),
|
|
'handler_id' => session('admin_id')
|
|
);
|
|
|
|
if ($status == 1 && $compensation_amount > 0) {
|
|
$update_data['compensation_amount'] = $compensation_amount;
|
|
}
|
|
|
|
$result = M('rider_appeal')->where(array('id' => $id))->save($update_data);
|
|
if (!$result) {
|
|
throw new \Exception('更新申诉状态失败');
|
|
}
|
|
|
|
// 记录处理日志
|
|
$log_data = array(
|
|
'appeal_id' => $id,
|
|
'handler_id' => session('admin_id'),
|
|
'action' => $status == 1 ? 'approve' : 'reject',
|
|
'remark' => $handle_remark,
|
|
'create_time' => time()
|
|
);
|
|
M('rider_appeal_log')->add($log_data);
|
|
|
|
// 如果申诉通过且有补偿金额,增加骑手余额
|
|
if ($status == 1 && $compensation_amount > 0) {
|
|
$rider_id = $appeal['rider_id'];
|
|
|
|
// 更新骑手余额
|
|
$balance_result = M('users')->where(array('id' => $rider_id))
|
|
->setInc('balance', $compensation_amount);
|
|
if (!$balance_result) {
|
|
throw new \Exception('更新骑手余额失败');
|
|
}
|
|
|
|
// 记录余额变动
|
|
$balance_log = array(
|
|
'user_id' => $rider_id,
|
|
'type' => 'appeal_compensation',
|
|
'amount' => $compensation_amount,
|
|
'balance_before' => M('users')->where(array('id' => $rider_id))->getField('balance') - $compensation_amount,
|
|
'balance_after' => M('users')->where(array('id' => $rider_id))->getField('balance'),
|
|
'remark' => '申诉补偿:' . $appeal['appeal_reason'],
|
|
'create_time' => time()
|
|
);
|
|
M('balance_log')->add($balance_log);
|
|
}
|
|
|
|
M()->commit();
|
|
$this->ajaxReturn(array('code' => 0, 'msg' => '处理成功'));
|
|
|
|
} catch (\Exception $e) {
|
|
M()->rollback();
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => $e->getMessage()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 批量处理申诉
|
|
*/
|
|
public function batchHandle() {
|
|
$ids = I('ids', '', 'trim');
|
|
$status = I('status', 0, 'intval');
|
|
$handle_remark = I('handle_remark', '', 'trim');
|
|
|
|
if (empty($ids)) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '请选择要处理的申诉'));
|
|
}
|
|
|
|
if (!in_array($status, array(1, 2))) {
|
|
$this->ajaxReturn(array('code' => 1, 'msg' => '处理状态错误'));
|
|
}
|
|
|
|
if (empty($handle_remark)) {
|
|
$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;
|
|
|
|
// 检查申诉状态
|
|
$appeal = M('rider_appeal')->where(array('id' => $id))->find();
|
|
if (empty($appeal) || $appeal['status'] != 0) {
|
|
continue;
|
|
}
|
|
|
|
// 更新申诉状态
|
|
$update_data = array(
|
|
'status' => $status,
|
|
'handle_remark' => $handle_remark,
|
|
'handle_time' => time(),
|
|
'handler_id' => session('admin_id')
|
|
);
|
|
|
|
$result = M('rider_appeal')->where(array('id' => $id))->save($update_data);
|
|
if ($result) {
|
|
// 记录处理日志
|
|
$log_data = array(
|
|
'appeal_id' => $id,
|
|
'handler_id' => session('admin_id'),
|
|
'action' => $status == 1 ? 'approve' : 'reject',
|
|
'remark' => $handle_remark,
|
|
'create_time' => time()
|
|
);
|
|
M('rider_appeal_log')->add($log_data);
|
|
$success_count++;
|
|
}
|
|
}
|
|
|
|
$this->ajaxReturn(array(
|
|
'code' => 0,
|
|
'msg' => "批量处理完成,成功处理{$success_count}条申诉"
|
|
));
|
|
}
|
|
|
|
/**
|
|
* 导出申诉数据
|
|
*/
|
|
public function exportAppeal() {
|
|
$keyword = I('keyword', '', 'trim');
|
|
$status = I('status', '', 'trim');
|
|
$type = I('type', '', 'trim');
|
|
$start_time = I('start_time', '', 'trim');
|
|
$end_time = I('end_time', '', 'trim');
|
|
|
|
$where = array();
|
|
|
|
if (!empty($keyword)) {
|
|
$where['_string'] = "(u.nickname LIKE '%{$keyword}%' OR u.phone LIKE '%{$keyword}%' OR a.order_no LIKE '%{$keyword}%')";
|
|
}
|
|
if ($status !== '') {
|
|
$where['a.status'] = $status;
|
|
}
|
|
if ($type !== '') {
|
|
$where['a.appeal_type'] = $type;
|
|
}
|
|
if (!empty($start_time)) {
|
|
$where['a.create_time'] = array('egt', strtotime($start_time . ' 00:00:00'));
|
|
}
|
|
if (!empty($end_time)) {
|
|
$where['a.create_time'] = array('elt', strtotime($end_time . ' 23:59:59'));
|
|
}
|
|
|
|
$list = M('rider_appeal')->alias('a')
|
|
->field('a.*, u.nickname, u.phone')
|
|
->join('ls_users u ON a.rider_id = u.id')
|
|
->where($where)
|
|
->order('a.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', '处理说明');
|
|
$objActSheet->setCellValue('J1', '补偿金额');
|
|
$objActSheet->setCellValue('K1', '申诉时间');
|
|
$objActSheet->setCellValue('L1', '处理时间');
|
|
|
|
// 填充数据
|
|
$row = 2;
|
|
foreach ($list as $item) {
|
|
$objActSheet->setCellValue('A' . $row, $item['id']);
|
|
$objActSheet->setCellValue('B' . $row, $item['nickname']);
|
|
$objActSheet->setCellValue('C' . $row, $item['phone']);
|
|
$objActSheet->setCellValue('D' . $row, $this->getAppealTypeText($item['appeal_type']));
|
|
$objActSheet->setCellValue('E' . $row, $item['order_no']);
|
|
$objActSheet->setCellValue('F' . $row, $item['appeal_reason']);
|
|
$objActSheet->setCellValue('G' . $row, $item['appeal_content']);
|
|
$objActSheet->setCellValue('H' . $row, $this->getStatusText($item['status']));
|
|
$objActSheet->setCellValue('I' . $row, $item['handle_remark']);
|
|
$objActSheet->setCellValue('J' . $row, $item['compensation_amount']);
|
|
$objActSheet->setCellValue('K' . $row, date('Y-m-d H:i:s', $item['create_time']));
|
|
$objActSheet->setCellValue('L' . $row, $item['handle_time'] ? date('Y-m-d H:i:s', $item['handle_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 getAppealStats() {
|
|
$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_appeal');
|
|
|
|
$stats = array(
|
|
'total_count' => $model->where($where)->count(),
|
|
'pending_count' => $model->where(array_merge($where, array('status' => 0)))->count(),
|
|
'approved_count' => $model->where(array_merge($where, array('status' => 1)))->count(),
|
|
'rejected_count' => $model->where(array_merge($where, array('status' => 2)))->count(),
|
|
'order_appeal_count' => $model->where(array_merge($where, array('appeal_type' => 'order')))->count(),
|
|
'rating_appeal_count' => $model->where(array_merge($where, array('appeal_type' => 'rating')))->count(),
|
|
'penalty_appeal_count' => $model->where(array_merge($where, array('appeal_type' => 'penalty')))->count()
|
|
);
|
|
|
|
// 计算总补偿金额
|
|
$total_compensation = $model->where(array_merge($where, array('status' => 1)))
|
|
->sum('compensation_amount');
|
|
$stats['total_compensation'] = number_format($total_compensation ?: 0, 2);
|
|
|
|
$this->ajaxReturn(array(
|
|
'code' => 0,
|
|
'msg' => 'success',
|
|
'data' => $stats
|
|
));
|
|
}
|
|
|
|
/**
|
|
* 获取状态文本
|
|
*/
|
|
private function getStatusText($status) {
|
|
$statusMap = array(
|
|
0 => '待处理',
|
|
1 => '已通过',
|
|
2 => '已驳回'
|
|
);
|
|
return isset($statusMap[$status]) ? $statusMap[$status] : '未知';
|
|
}
|
|
|
|
/**
|
|
* 获取申诉类型文本
|
|
*/
|
|
private function getAppealTypeText($type) {
|
|
$typeMap = array(
|
|
'order' => '订单异常申诉',
|
|
'rating' => '差评申诉',
|
|
'penalty' => '违规处罚申诉',
|
|
'payment' => '收入异常申诉',
|
|
'other' => '其他申诉'
|
|
);
|
|
return isset($typeMap[$type]) ? $typeMap[$type] : '其他';
|
|
}
|
|
}
|
|
?>
|