218 lines
6.9 KiB
PHP
218 lines
6.9 KiB
PHP
<?php
|
||
// +----------------------------------------------------------------------
|
||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||
// +----------------------------------------------------------------------
|
||
// | Author: ywxapp<admin@ywxapp.cn>
|
||
// +----------------------------------------------------------------------
|
||
declare (strict_types = 1);
|
||
|
||
namespace addon\blog\controller\backend;
|
||
|
||
use addon\blog\model\BlogCategory as CategoryModel;
|
||
use think\facade\Request;
|
||
use think\facade\View;
|
||
use think\Validate;
|
||
use ywxapp\controller\BackendBase;
|
||
|
||
/**
|
||
* Category 类
|
||
*
|
||
* @author ywxapp <admin@ywxapp.cn>
|
||
*/
|
||
class Category extends BackendBase
|
||
{
|
||
|
||
protected $noNeedVerify = ['*'];
|
||
|
||
|
||
protected function initialize()
|
||
{}
|
||
|
||
/**
|
||
* 分类列表(后台管理全部分类:全局共享 + 各会员自建)
|
||
* 以 layui treeTable 所需的扁平结构返回(带 pid / is_parent),由前端 treeTable 自动成树。
|
||
*/
|
||
public function index()
|
||
{
|
||
$categories = CategoryModel::withCount('articles')
|
||
->order('uid', 'asc')
|
||
->order('sort', 'asc')
|
||
->select()
|
||
->toArray();
|
||
|
||
// 收集归属会员昵称
|
||
$uids = [];
|
||
foreach ($categories as $c) {
|
||
if (!empty($c['uid'])) {
|
||
$uids[] = $c['uid'];
|
||
}
|
||
}
|
||
$owners = [];
|
||
if ($uids) {
|
||
$owners = \think\facade\Db::name('member')
|
||
->whereIn('uid', array_unique($uids))
|
||
->column('nickname', 'uid');
|
||
}
|
||
|
||
// 计算哪些分类拥有子分类(用于 treeTable 的 is_parent 标记)
|
||
$parentIds = array_unique(array_filter(array_column($categories, 'pid')));
|
||
|
||
$treeData = [];
|
||
foreach ($categories as $c) {
|
||
$treeData[] = [
|
||
'id' => $c['id'],
|
||
'pid' => $c['pid'],
|
||
'title' => $c['name'], // treeTable 节点显示名称
|
||
'name' => $c['name'],
|
||
'description' => $c['description'] ?? '',
|
||
'sort' => $c['sort'],
|
||
'status' => $c['status'],
|
||
'is_parent' => in_array($c['id'], $parentIds, true) ? 1 : 0,
|
||
'owner' => empty($c['uid']) ? '全局共享' : ($owners[$c['uid']] ?? ('#' . $c['uid'])),
|
||
'articles_count' => $c['articles_count'] ?? 0,
|
||
];
|
||
}
|
||
|
||
return View::fetch('category/index', [
|
||
'treeData' => json_encode($treeData, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG),
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 添加分类页面
|
||
*/
|
||
public function add()
|
||
{
|
||
$categories = CategoryModel::order('sort', 'asc')->select();
|
||
return View::fetch('category/add', ['categories' => $categories]);
|
||
}
|
||
|
||
/**
|
||
* 保存分类
|
||
*/
|
||
public function save()
|
||
{
|
||
$data = Request::post();
|
||
$data['uid'] = 0; // 后台管理的分类为全局共享分类
|
||
$data['pid'] = (int) Request::post('pid', 0);
|
||
$data['create_at'] = time();
|
||
$data['update_at'] = time();
|
||
|
||
$validate = new Validate([
|
||
'name|分类名称' => 'require|unique:BlogCategory,name,0,id,uid,0',
|
||
'pid|上级分类' => 'number',
|
||
'sort|排序' => 'number|between:0,999',
|
||
]);
|
||
|
||
if (! $validate->check($data)) {
|
||
return json(['code' => 0, 'msg' => $validate->getError()]);
|
||
}
|
||
|
||
CategoryModel::create($data);
|
||
return json(['code' => 1, 'msg' => '分类添加成功', 'url' => '/blog/backend/category']);
|
||
}
|
||
|
||
/**
|
||
* 编辑分类页面
|
||
*/
|
||
public function edit($id = null)
|
||
{
|
||
$category = CategoryModel::find($id);
|
||
$categories = CategoryModel::order('sort', 'asc')->select();
|
||
return View::fetch('category/edit', ['category' => $category, 'categories' => $categories]);
|
||
}
|
||
|
||
/**
|
||
* 更新分类
|
||
*/
|
||
public function update($id)
|
||
{
|
||
$category = CategoryModel::find($id);
|
||
if (! $category) {
|
||
return json(['code' => 0, 'msg' => '分类不存在']);
|
||
}
|
||
|
||
if ((int) Request::post('pid', 0) === (int) $id) {
|
||
return json(['code' => 0, 'msg' => '上级分类不能选择自己']);
|
||
}
|
||
|
||
$data = Request::post();
|
||
$data['pid'] = (int) Request::post('pid', 0);
|
||
$data['update_at'] = time();
|
||
|
||
$validate = new Validate([
|
||
'name|分类名称' => 'require|unique:BlogCategory,name,' . $id . ',id,uid,' . $category->uid,
|
||
'pid|上级分类' => 'number',
|
||
'sort|排序' => 'number|between:0,999',
|
||
]);
|
||
|
||
if (! $validate->check($data)) {
|
||
return json(['code' => 0, 'msg' => $validate->getError()]);
|
||
}
|
||
|
||
$category->save($data);
|
||
return json(['code' => 1, 'msg' => '分类更新成功', 'url' => '/blog/backend/category']);
|
||
}
|
||
|
||
/**
|
||
* 删除分类
|
||
*/
|
||
public function delete($id)
|
||
{
|
||
$category = CategoryModel::find($id);
|
||
if ($category) {
|
||
if ($category->children()->count() > 0) {
|
||
return json(['code' => 0, 'msg' => '该分类下有子分类,请先删除子分类']);
|
||
}
|
||
if ($category->articles()->count() > 0) {
|
||
return json(['code' => 0, 'msg' => '该分类下有文章,无法删除']);
|
||
}
|
||
$category->delete();
|
||
return json(['code' => 1, 'msg' => '分类已删除']);
|
||
}
|
||
return json(['code' => 0, 'msg' => '分类不存在']);
|
||
}
|
||
|
||
/**
|
||
* 批量删除分类(前端 treeTable 勾选后调用)
|
||
*/
|
||
public function batchDelete()
|
||
{
|
||
$ids = Request::post('ids', '');
|
||
$idArr = array_filter(array_map('intval', explode(',', (string) $ids)));
|
||
if (empty($idArr)) {
|
||
return json(['code' => 0, 'msg' => '请选择要删除的分类']);
|
||
}
|
||
|
||
$deleted = 0;
|
||
$skipped = 0;
|
||
foreach ($idArr as $id) {
|
||
$category = CategoryModel::find($id);
|
||
if (! $category) {
|
||
continue;
|
||
}
|
||
if ($category->children()->count() > 0) {
|
||
$skipped++;
|
||
continue;
|
||
}
|
||
if ($category->articles()->count() > 0) {
|
||
$skipped++;
|
||
continue;
|
||
}
|
||
$category->delete();
|
||
$deleted++;
|
||
}
|
||
|
||
if ($deleted === 0) {
|
||
return json(['code' => 0, 'msg' => '选中的分类均包含子分类或文章,无法删除']);
|
||
}
|
||
$msg = '成功删除 ' . $deleted . ' 个分类';
|
||
if ($skipped > 0) {
|
||
$msg .= ',' . $skipped . ' 个因含子分类/文章已跳过';
|
||
}
|
||
return json(['code' => 1, 'msg' => $msg]);
|
||
}
|
||
}
|