model = new \app\admin\model\FcPost; } /** * 查看待审核信息列表 * * 默认展示待审核(audit_status=0)的数据,支持通用搜索 * * @return string|\think\response\Json * @throws \think\Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function index() { $this->request->filter(['strip_tags', 'trim']); if (false === $this->request->isAjax()) { return $this->view->fetch(); } if ($this->request->request('keyField')) { return $this->selectpage(); } [$where, $sort, $order, $offset, $limit] = $this->buildparams(); // 如果通用搜索未指定审核状态,默认只展示待审核信息(audit_status = 0) $filter = (array)json_decode($this->request->get('filter', ''), true); $hasAuditFilter = isset($filter['audit_status']) && $filter['audit_status'] !== ''; $query = $this->model->where($where); if (!$hasAuditFilter) { $query->where('audit_status', 0); } $list = $query ->order('id', 'desc') ->paginate($limit); $result = ['total' => $list->total(), 'rows' => $list->items()]; return json($result); } /** * 审核处理接口(支持单条与批量) * * @return void * @throws \think\Exception */ public function audit() { $ids = $this->request->post('ids'); $auditStatus = (int)$this->request->post('auditStatus'); $reason = trim((string)$this->request->post('reason', '')); if (!in_array($auditStatus, [1, 2], true)) { $this->error('审核状态仅支持通过(1)或驳回(2)'); } $ids = $this->normalizeIds($ids); if (!$ids) { $this->error('请选择要审核的信息'); } if ($auditStatus === 2 && $reason === '') { $this->error('请填写驳回原因'); } if (mb_strlen($reason, 'utf-8') > 200) { $reason = mb_substr($reason, 0, 200, 'utf-8'); } $posts = Db::name('fc_post')->where('id', 'in', $ids)->whereNull('deletetime')->select(); if (!$posts) { $this->error('信息不存在或已删除'); } $changed = 0; $skipped = 0; Db::startTrans(); try { foreach ($posts as $post) { $from = (int)$post['audit_status']; if ($from === $auditStatus) { $skipped++; continue; } Db::name('fc_post')->where('id', $post['id'])->update([ 'audit_status' => $auditStatus, 'audit_reason' => $reason, 'updatetime' => time(), ]); // 分类信息量维护 if (!empty($post['category_id'])) { if ($auditStatus === 1 && $from !== 1) { Db::name('fc_category')->where('id', $post['category_id'])->setInc('post_count'); } elseif ($auditStatus === 2 && $from === 1) { Db::name('fc_category') ->where('id', $post['category_id']) ->where('post_count', '>', 0) ->setDec('post_count'); } } // 站内信通知发布用户 Db::name('fc_message')->insert([ 'user_id' => $post['user_id'], 'type' => 'system', 'title' => $auditStatus === 1 ? '信息审核通过' : '信息审核未通过', 'content' => $auditStatus === 1 ? sprintf('您发布的信息「%s」已通过审核并上架展示。', $post['title']) : sprintf('您发布的信息「%s」未通过审核,原因:%s', $post['title'], $reason), 'isread' => 0, 'createtime' => time(), ]); $changed++; } Db::commit(); } catch (\Exception $e) { Db::rollback(); $this->error('审核处理失败:' . $e->getMessage()); } $actionText = $auditStatus === 1 ? '审核通过' : '审核驳回'; AdminLog::setTitle(sprintf('%s,涉及 %d 条信息(成功 %d 条,跳过 %d 条)', $actionText, count($ids), $changed, $skipped)); $msg = $changed > 0 ? sprintf('%s成功(已处理 %d 条)', $actionText, $changed) : '所选信息已处于该状态,未重复处理'; $this->success($msg); } /** * 快捷通过接口 * * @return void */ public function pass() { $this->request->post(['auditStatus' => 1, 'reason' => '']); $this->audit(); } /** * 快捷驳回接口 * * @return void */ public function reject() { $this->request->post(['auditStatus' => 2]); $this->audit(); } /** * 查看信息详情或进入专属审核工作台 * * @param int|null $ids 信息ID * @return string|\think\response\Json */ public function detail($ids = null) { $id = $this->request->param('ids', 0) ?: $this->request->param('id/d', 0); if (!$id) { $this->error('缺少参数ID'); } $row = $this->model->where('id', $id)->find(); if (!$row) { $this->error('信息不存在或已删除'); } // 补齐分类名称 if ($row->category_id) { $category = Db::name('fc_category')->where('id', $row->category_id)->find(); $row->category_name = $category ? $category['name'] : '未分类'; } else { $row->category_name = '未分类'; } // 解析多图相册 $mediaList = []; $rawMedia = $row->getData('media'); if (!empty($rawMedia)) { $decoded = is_string($rawMedia) ? json_decode($rawMedia, true) : $rawMedia; if (is_array($decoded)) { $mediaList = array_values(array_filter($decoded)); } else { $mediaList = array_values(array_filter(explode(',', (string)$rawMedia))); } } if (empty($mediaList) && !empty($row->cover)) { $mediaList[] = $row->cover; } // 获取发布用户画像 $userInfo = [ 'id' => $row->user_id, 'nickname' => $row->user_name ?: '未知用户', 'mobile' => '', 'avatar' => '/assets/img/avatar.png', 'post_count' => 0 ]; $user = Db::name('user')->where('id', $row->user_id)->field('id,nickname,mobile,avatar')->find(); if ($user) { $userInfo['nickname'] = $user['nickname'] ?: $userInfo['nickname']; $userInfo['mobile'] = $user['mobile'] ?: ''; $userInfo['avatar'] = $user['avatar'] ?: $userInfo['avatar']; $userInfo['post_count'] = Db::name('fc_post')->where('user_id', $user['id'])->count(); } $mode = $this->request->param('mode', 'audit'); $this->view->assign('mode', $mode); $this->view->assign('row', $row); $this->view->assign('userInfo', $userInfo); $this->view->assign('mediaList', $mediaList); $this->view->assign('queue', $this->auditQueue($row->getData())); if ($mode === 'audit') { return $this->view->fetch('fc/post/audit'); } return $this->view->fetch('fc/post/detail'); } /** * 审核队列位置(供审核工作台显示「第 x / y 条」和上/下一条) * GET fc/postaudit/queue?id=123 * * @return void */ public function queue() { $id = (int)$this->request->param('id', 0); $row = Db::name('fc_post')->where('id', $id)->whereNull('deletetime')->find(); if (!$row) { $this->error('信息不存在或已删除'); } $this->success('', null, $this->auditQueue($row)); } /** * 计算待审核队列的上下文(第几条、总数、上一条、下一条) * * @param array $current 当前信息数组 * @return array */ protected function auditQueue(array $current) { $id = (int)$current['id']; $pendingIds = Db::name('fc_post') ->whereNull('deletetime') ->where('audit_status', 0) ->order('id', 'desc') ->column('id'); $total = count($pendingIds); $pos = array_search($id, $pendingIds, true); if ($pos === false) { return ['index' => 0, 'total' => $total, 'prev' => 0, 'next' => 0]; } $prevId = $pos > 0 ? $pendingIds[$pos - 1] : 0; $nextId = $pos + 1 < $total ? $pendingIds[$pos + 1] : 0; return [ 'index' => $pos + 1, 'total' => $total, 'prev' => $prevId, 'next' => $nextId, ]; } /** * 解析请求中的 ID 数组 * * @param mixed $ids 前端提交的ID * @return array */ protected function normalizeIds($ids) { if (is_array($ids)) { $arr = $ids; } elseif (is_string($ids)) { $arr = explode(',', $ids); } else { $arr = [$ids]; } $arr = array_map('intval', $arr); $arr = array_filter($arr, function ($v) { return $v > 0; }); return array_values(array_unique($arr)); } }