WorkAudit.php 11.2 KB
<?php
declare(strict_types=1);

namespace app\controller\admin;

use app\BaseController;
use think\facade\Db;

class WorkAudit extends BaseController
{
    protected function maskOpenid(string $s): string
    {
        if ($s === '') {
            return '—';
        }
        $len = strlen($s);
        if ($len <= 8) {
            return substr($s, 0, 2) . '****';
        }

        return substr($s, 0, 4) . '****' . substr($s, -4);
    }

    /** 待审核列表 */
    public function pendingList()
    {
        $rows = Db::name('work')->alias('w')
            ->leftJoin('mp_user u', 'u.id = w.user_id')
            ->where('w.status', 'pending')
            ->field('w.*,u.nickname as author_name,u.openid as author_openid')
            ->order('w.id', 'desc')
            ->select()
            ->toArray();

        $list = [];
        foreach ($rows as $w) {
            $cats = Db::name('work_category')->where('work_id', $w['id'])->column('category');
            $list[] = [
                'id'           => (int) $w['id'],
                'userId'       => (int) $w['user_id'],
                'imageUrl'     => $w['cover_image'],
                'title'        => $w['title'],
                'author'       => $w['author_name'] ?: '用户',
                'authorOpenid' => $this->maskOpenid((string) ($w['author_openid'] ?? '')),
                'uploadDate'   => date('Y-m-d', strtotime((string) $w['create_time'])),
                'category'     => $cats[0] ?? '',
            ];
        }

        return json(['code' => 0, 'msg' => 'ok', 'data' => ['list' => $list]]);
    }

    /** 已拒绝列表(含拒绝原因摘要) */
    public function rejectedList()
    {
        $rows = Db::name('work')->alias('w')
            ->leftJoin('mp_user u', 'u.id = w.user_id')
            ->where('w.status', 'rejected')
            ->field('w.*,u.nickname as author_name,u.openid as author_openid')
            ->order('w.update_time', 'desc')
            ->order('w.id', 'desc')
            ->select()
            ->toArray();

        $list = [];
        foreach ($rows as $w) {
            $cats = Db::name('work_category')->where('work_id', $w['id'])->column('category');
            $reason = trim((string) ($w['reject_reason'] ?? ''));
            $list[] = [
                'id'           => (int) $w['id'],
                'userId'       => (int) $w['user_id'],
                'imageUrl'     => $w['cover_image'],
                'title'        => $w['title'],
                'author'       => $w['author_name'] ?: '用户',
                'authorOpenid' => $this->maskOpenid((string) ($w['author_openid'] ?? '')),
                'uploadDate'   => date('Y-m-d', strtotime((string) $w['create_time'])),
                'rejectDate'   => date('Y-m-d', strtotime((string) ($w['update_time'] ?? 'now'))),
                'rejectReason' => $reason,
                'category'     => $cats[0] ?? '',
            ];
        }

        return json(['code' => 0, 'msg' => 'ok', 'data' => ['list' => $list]]);
    }

    /** 已通过列表(含排序);keyword 搜标题、作者昵称、作品 ID、日期(YYYY-MM-DD / YYYY-MM) */
    public function approvedList()
    {
        $keyword = trim((string) $this->request->get('keyword', ''));

        $q = Db::name('work')->alias('w')
            ->leftJoin('mp_user u', 'u.id = w.user_id')
            ->where('w.status', 'approved')
            ->field('w.*,u.nickname as author_name,u.openid as author_openid');

        if ($keyword !== '') {
            $like    = '%' . addcslashes($keyword, '%_\\') . '%';
            $clauses = ['w.title LIKE ?', 'u.nickname LIKE ?'];
            $bind    = [$like, $like];
            if (ctype_digit($keyword)) {
                $clauses[] = 'w.id = ?';
                $bind[]    = (int) $keyword;
            }
            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $keyword)) {
                $clauses[] = 'DATE(w.create_time) = ?';
                $bind[]    = $keyword;
                $clauses[] = '(w.publish_date IS NOT NULL AND DATE(w.publish_date) = ?)';
                $bind[]    = $keyword;
            } elseif (preg_match('/^\d{4}-\d{2}$/', $keyword)) {
                $pfx       = $keyword . '%';
                $clauses[] = 'w.create_time LIKE ?';
                $bind[]    = $pfx;
                $clauses[] = 'w.publish_date LIKE ?';
                $bind[]    = $pfx;
            }
            $q->whereRaw('(' . implode(' OR ', $clauses) . ')', $bind);
        }

        $rows = $q->order('w.sort_order', 'asc')
            ->order('w.id', 'asc')
            ->select()
            ->toArray();

        $list = [];
        foreach ($rows as $w) {
            $cats = Db::name('work_category')->where('work_id', $w['id'])->column('category');
            $createTs = strtotime((string) ($w['create_time'] ?? ''));
            $pub      = $w['publish_date'] ? (string) $w['publish_date'] : '';
            $list[] = [
                'id'             => (int) $w['id'],
                'userId'         => (int) $w['user_id'],
                'imageUrl'       => $w['cover_image'],
                'title'          => $w['title'],
                'author'         => $w['author_name'] ?: '用户',
                'authorOpenid'   => $this->maskOpenid((string) ($w['author_openid'] ?? '')),
                'uploadDate'     => $createTs ? date('Y-m-d', $createTs) : '',
                'createTime'     => (string) ($w['create_time'] ?? ''),
                'publishDate'    => $pub,
                'approvedDate'   => $pub !== '' ? $pub : date('Y-m-d', strtotime((string) ($w['update_time'] ?? 'now'))),
                'updateTime'     => (string) ($w['update_time'] ?? ''),
                'category'       => $cats[0] ?? '',
                'order'          => (int) $w['sort_order'],
            ];
        }

        return json(['code' => 0, 'msg' => 'ok', 'data' => ['list' => $list]]);
    }

    /** 作品完整信息(审核用,含多图、类别、作者) */
    public function detail(int $id)
    {
        if ($id <= 0) {
            return json(['code' => 400, 'msg' => '参数错误', 'data' => []]);
        }

        $w = Db::name('work')->alias('w')
            ->leftJoin('mp_user u', 'u.id = w.user_id')
            ->where('w.id', $id)
            ->field('w.*,u.nickname as author_name,u.openid as author_openid,u.phone as author_phone')
            ->find();

        if (!$w) {
            return json(['code' => 404, 'msg' => '作品不存在', 'data' => []]);
        }

        $imgRows = Db::name('work_image')
            ->where('work_id', $id)
            ->order('sort', 'asc')
            ->order('id', 'asc')
            ->field('url,sort')
            ->select()
            ->toArray();

        $images = [];
        foreach ($imgRows as $r) {
            $images[] = [
                'url'  => (string) $r['url'],
                'sort' => (int) $r['sort'],
            ];
        }
        $cover = (string) ($w['cover_image'] ?? '');
        if ($images === [] && $cover !== '') {
            $images[] = ['url' => $cover, 'sort' => 0];
        }

        $cats = Db::name('work_category')->where('work_id', $id)->column('category');

        return json([
            'code' => 0,
            'msg'  => 'ok',
            'data' => [
                'work' => [
                    'id'              => (int) $w['id'],
                    'userId'          => (int) $w['user_id'],
                    'title'           => (string) $w['title'],
                    'description'     => (string) $w['description'],
                    'shootDate'       => $w['shoot_date'] ? (string) $w['shoot_date'] : '',
                    'status'          => (string) $w['status'],
                    'coverImage'      => $cover,
                    'likesCount'      => (int) $w['likes_count'],
                    'createTime'      => (string) ($w['create_time'] ?? ''),
                    'categories'      => $cats,
                    'images'          => $images,
                    'author'          => $w['author_name'] ? (string) $w['author_name'] : '用户',
                    'authorOpenid'    => $this->maskOpenid((string) ($w['author_openid'] ?? '')),
                    'authorPhone'     => trim((string) ($w['author_phone'] ?? '')),
                    'rejectReason'    => trim((string) ($w['reject_reason'] ?? '')),
                ],
            ],
        ]);
    }

    public function approve(int $id)
    {
        $w = Db::name('work')->where('id', $id)->where('status', 'pending')->find();
        if (!$w) {
            return json(['code' => 404, 'msg' => '记录不存在', 'data' => []]);
        }
        $maxSort = (int) Db::name('work')->where('status', 'approved')->max('sort_order');
        Db::name('work')->where('id', $id)->update([
            'status'        => 'approved',
            'publish_date'  => date('Y-m-d'),
            'sort_order'    => $maxSort + 1,
            'update_time'   => date('Y-m-d H:i:s'),
        ]);

        return json(['code' => 0, 'msg' => '已通过', 'data' => []]);
    }

    public function reject(int $id)
    {
        $w = Db::name('work')->where('id', $id)->where('status', 'pending')->find();
        if (!$w) {
            return json(['code' => 404, 'msg' => '记录不存在', 'data' => []]);
        }
        $reason = trim((string) $this->request->post('reason', ''));
        if ($reason === '' || mb_strlen($reason) > 500) {
            return json(['code' => 400, 'msg' => '请填写拒绝原因(1~500 字)', 'data' => []]);
        }
        Db::name('work')->where('id', $id)->update([
            'status'         => 'rejected',
            'reject_reason'  => $reason,
            'update_time'    => date('Y-m-d H:i:s'),
        ]);

        return json(['code' => 0, 'msg' => '已拒绝', 'data' => []]);
    }

    /** 物理删除作品及关联数据(待审核 / 已通过 / 已拒绝均可) */
    public function delete(int $id)
    {
        if ($id <= 0) {
            return json(['code' => 400, 'msg' => '参数错误', 'data' => []]);
        }

        $w = Db::name('work')->where('id', $id)->find();
        if (!$w) {
            return json(['code' => 404, 'msg' => '记录不存在', 'data' => []]);
        }

        Db::transaction(function () use ($id): void {
            Db::name('work_like')->where('work_id', $id)->delete();
            Db::name('work_category')->where('work_id', $id)->delete();
            Db::name('work_image')->where('work_id', $id)->delete();
            Db::name('work')->where('id', $id)->delete();
        });

        return json(['code' => 0, 'msg' => '已删除', 'data' => []]);
    }

    /** body: { "ids": [3,1,2] } 按数组顺序写 sort_order */
    public function sortApproved()
    {
        $ids = $this->request->post('ids', []);
        if (!is_array($ids) || $ids === []) {
            return json(['code' => 400, 'msg' => 'ids 必填', 'data' => []]);
        }
        $i = 1;
        foreach ($ids as $id) {
            $id = (int) $id;
            if ($id <= 0) {
                continue;
            }
            Db::name('work')->where('id', $id)->where('status', 'approved')->update([
                'sort_order'  => $i++,
                'update_time' => date('Y-m-d H:i:s'),
            ]);
        }

        return json(['code' => 0, 'msg' => '已更新排序', 'data' => []]);
    }
}