文章分类更新状态和删除
状态的更新和删除,放在一起介绍了,因为简单,哈哈。
更改状态和删除的路由已经写好了, 在/routes/web.php文件中,
$router->post('/category/del/{id:[1-9]+}', 'CategoryController@del'); // 删除文章分类
$router->post('/category/status/{id:[1-9]+}', 'CategoryController@status'); // 更改状态status
这两个路由,要求传分类的id,并且是数字,不能为空。
写到这里,我发下之前做迁移的时候,少了一个开启和停用的状态字段,那我们现在加一个,打开/database/migrations/目录,修改category迁移,增加一个
$table->unsignedInteger('is_open')->default(1)->comment('是否开启,0:关闭,1:开启');
然后到命令行工具上,执行
php artisan migrate:rollback
这个命令是回滚操作。上个命令是新建category表,这次是删除表。这个命令使用的时候要小心。因为现在是开发阶段,并且是我一个人开发,所以回滚没问题,但是之前的数据没有了,但是我做这个操作之前,已经备份数据库了。如果后边有很多版本了,就不能这样操作了,后边我会专门介绍如何新增字段、修改字段、添加索引等。
然后再执行命令
php artisan migrate
这个是迁移,category表又新增好了。我会把数据导入进去的。Category模型中,也要添加一个is_open的字段。
打开/app/Models/category.php文件,这里加一个新的方法,用于处理开启和关闭。
public static function isOpen(Category $category)
{
$category->is_open = !$category->is_open;
return $category->update();
}
为什么is_open的值要等于自己的非呢?假如一个分类信息的is_open值是1,在前端的页面展示应该是开启,当你点击开启按钮,必然是为了关闭这条信息,当你点击关闭按钮,必然是为了开启这条信息,所以使用取非的操作。is_open的数据类型可以使用bit类型,只有0和1两种状态,在这里使用bit类型更合适。
再看看控制器,打开/app/Http/Controllers/Admin/CategoryController.php文件,增加一个方法
public function status(int $id, Request $request)
{
$category = Category::where('id', $id)->first();
if (empty($category->id)) {
$this->response->setMsg(400, '信息不存在');
return $this->response->responseJSON();
}
Category::isOpen($category);
$this->response->setData(['status' => (int)$category->is_open]);
return $this->response->responseJSON();
}
第一步检查信息是否存在,第二步更新is_open的值,第三步,把更新后的值返回给前端。当接口返回的status是1时,前端的开关按钮应该展示开启,当接口返回的status是0时,前端的开关按钮应该展示关闭。
我在category.blade.php文件中,增加一段js代码,用于更改开启和停用的状态,注意:任何ajax的请求,都因应该处理error回调信息,这段代码中我没有处理,之前的也没有处理,但是我知道是需要处理的,这里只是为了演示,简单起见不做处理。
// 切换开启和停用状态
$('.layui-form-switch').on('click', function () {
var that = $(this);
var id = $(this).prev().attr('id');
$.post('/admin/category/status/' + id, function (data) {
console.log(data);
if (data.data.status === 1) {
that.addClass('layui-form-onswitch');
that.html('<em>启用</em>')
} else {
that.removeClass('layui-form-onswitch');
that.html('<em>停用</em>')
}
})
});
效果如下
第二部分,删除操作。
这个页面有两个删除,一个是批量删除,一个单个删除,我们把批量删除和单个删除复用一个删除接口,那么,原来我们写的路由要做个修改了,改成这样
打开Category的模型,增加一个方法
public static function del(array $ids)
{
return Category::whereIn('id', $ids)->update(['is_del' => 1]);
}
很简单,就是批量的把is_del的值改为1,这样就标识该条信息被删除了。删除有两种,一种是物理性删除,一种是软删除。很好理解,物理性删除就彻底删除了,表中不再保存该信息了,软删除就是信息还在,但是用状态来表示被删除。laravel/lumen提供了一种软删除操作,它会给表加一个deleted_at字段,如果删除了,deleted_at的值就是删除的日期,用这种方式删除比较好,既可以记录到删除的时间,又能标识该信息被删除。这里我就不做演示,有兴趣的话,可以看软删除。
打开Category的控制器,增加一个方法
public function del(Request $request)
{
Category::del($request->input('ids'));
return $this->response->responseJSON();
}
非常简单,不做太多介绍。但是这里使用的是批量删除,并没有检查数组中的每一个id是否在数组表中是否存在,在某些业务情况下,是需要检查每一条信息的,那么应该做以下操作:
- 检查入参是不是数组
- 根据数组中id查询出表中的数据
- 查询出的信息条数和入参数组中的id元素数应该相等,并且一一对应,否则是有问题的
- 若以上没有问题,再批量删除或者一个一个删除
最后,把模型、控制器、视图的代码发出来。前端代码,相比之前我做了少许修改。
模型代码
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function child()
{
return $this->hasMany(Category::class, 'parent_id', 'id')
->select(['id', 'type', 'parent_id', 'name', 'dir_name', 'pic', 'is_open', 'is_nav', 'sort', 'is_del']);
}
public function parent()
{
return $this->belongsTo(Category::class, 'parent_id', 'id');
}
public static function add(array $data)
{
$category = new Category();
!empty($data['type']) && $category->type = (int)$data['type'];
!empty($data['parent_id']) && $category->parent_id = (int)$data['parent_id'];
!empty($data['name']) && $category->name = $data['name'];
!empty($data['dir_name']) && $category->dir_name = $data['dir_name'];
!empty($data['pic']) && $category->pic = $data['pic'];
!empty($data['is_open']) && $category->is_open = $data['is_open'];
!empty($data['is_nav']) && $category->is_nav = (int)$data['is_nav'];
!empty($data['sort']) && $category->sort = (int)$data['sort'];
return $category->save();
}
public static function edit(Category $category, array $data)
{
!empty($data['type']) && $category->type = (int)$data['type'];
!empty($data['parent_id']) && $category->parent_id = (int)$data['parent_id'];
!empty($data['name']) && $category->name = $data['name'];
!empty($data['dir_name']) && $category->dir_name = $data['dir_name'];
!empty($data['pic']) && $category->pic = $data['pic'];
!empty($data['is_open']) && $category->is_open = $data['is_open'];
!empty($data['is_nav']) && $category->is_nav = (int)$data['is_nav'];
!empty($data['sort']) && $category->sort = (int)$data['sort'];
!empty($data['is_del']) && $category->is_del = (int)$data['is_del'];
return $category->update();
}
public static function lists()
{
return Category::with('child.child')
->select(['id', 'type', 'parent_id', 'name', 'dir_name', 'pic', 'is_nav', 'sort', 'is_del', 'is_open'])
->where('parent_id', 0)
->where('is_del', 0)
->get();
}
public static function del(array $ids)
{
return Category::whereIn('id', $ids)->update(['is_del' => 1]);
}
public static function isOpen(Category $category)
{
$category->is_open = !$category->is_open;
return $category->update();
}
}
控制器代码
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Category\AddCategory;
use App\Models\Category;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
* @throws \Illuminate\Validation\ValidationException
*/
public function add(Request $request)
{
// 判断不是不post方式提交数据
if ($request->post()) {
// 对新增数据做验证
$this->validate($request, AddCategory::rules(), AddCategory::msg(), AddCategory::attr());
// 添加分类
Category::add($request->input());
return $this->response->responseJSON();
}
return view('admin.category.addCategory');
}
/**
* @param int $id
* @param Request $request
* @return \Illuminate\Http\JsonResponse|\Illuminate\View\View
*/
public function addChild(int $id, Request $request)
{
// 同时获取父级的信息
$category = Category::with('parent')->where('id', $id)->first();
// if(empty($category->id)){
// //跳转到错误页面
// }
// 判断不是不post方式提交数据
if ($request->post()) {
// 添加分类
Category::add($request->input());
return $this->response->responseJSON();
}
$data['category'] = $category;
return view('admin.category.addChildCategory', $data);
}
/**
* @param int $id
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function edit(int $id, Request $request)
{
$category = Category::where('id', $id)->first();
// if(empty($category->id)){
// //跳转到错误页面
// }
if ($request->post()) {
// 添加分类
Category::edit($category, $request->input());
return $this->response->responseJSON();
}
$data['category'] = $category;
return view('admin.category.editCategory', $data);
}
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function lists(Request $request)
{
$data['list'] = Category::lists();
return view('admin.category.category', $data);
}
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function del(Request $request)
{
Category::del($request->input('ids'));
return $this->response->responseJSON();
}
/**
* @param int $id
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function status(int $id, Request $request)
{
$category = Category::where('id', $id)->first();
if (empty($category->id)) {
$this->response->setMsg(400, '删除的信息不存在');
return $this->response->responseJSON();
}
Category::isOpen($category);
$this->response->setData(['status' => (int)$category->is_open]);
return $this->response->responseJSON();
}
}
视图代码
<!DOCTYPE html>
<html class="x-admin-sm">
<head>
<meta charset="UTF-8">
<title>欢迎页面-X-admin2.2</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport"
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi"/>
<link rel="stylesheet" href="/css/font.css">
<link rel="stylesheet" href="/css/xadmin.css">
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="/lib/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="/js/xadmin.js"></script>
<!-- 让IE8/9支持媒体查询,从而兼容栅格 -->
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
.input_with {
width: 500px;
}
</style>
</head>
<body>
<div class="x-nav">
<span class="layui-breadcrumb">
<a href="/admin/index">首页</a>
<a>
<cite>文章分类</cite></a>
</span>
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right"
onclick="location.reload()" title="刷新">
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i>
</a>
</div>
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-header">
<button class="layui-btn layui-btn-danger" onclick="delAll()">
<i class="layui-icon"></i>批量删除
</button>
<button class="layui-btn" onclick="xadmin.open('增加分类','/admin/category/add',500,500)" lay-submit=""
lay-filter="sreach"><i class="layui-icon"></i>增加分类
</button>
</div>
<div class="layui-card-body ">
<table class="layui-table layui-form">
<thead>
<tr>
<th width="20">
<input type="checkbox" id="checkbox-all" name="" lay-skin="primary">
</th>
<th width="70">ID</th>
<th>分类名</th>
<th width="50">排序</th>
<th width="80">状态</th>
<th width="250">操作</th>
</thead>
<tbody class="x-cate">
@foreach($list as $value)
<tr cate-id='{{ $value['id'] }}' fid='{{ $value['parent_id'] }}'>
<td>
<input type="checkbox" name="{{ $value['id'] }}" lay-skin="primary">
</td>
<td>{{ $value['id'] }}</td>
<td>
@if(count($value['child']) > 0)
<i class="layui-icon x-show" status='true'></i>@else @endif
{{ $value['name'] }}
</td>
<td><input type="text" class="layui-input x-sort" name="order" value="1"></td>
<td>
<input type="checkbox" name="switch" lay-text="开启|停用"
@if($value['is_open'] == 1) checked @endif
lay-skin="switch" id="{{ $value['id'] }}">
</td>
<td class="td-manage">
<button class="layui-btn layui-btn layui-btn-xs"
onclick="xadmin.open('编辑','/admin/category/edit/{{ $value['id'] }}',500,500)"><i
class="layui-icon"></i>编辑
</button>
<button class="layui-btn layui-btn-warm layui-btn-xs"
onclick="xadmin.open('添加子栏目','/admin/category/addChild/{{ $value['id'] }}',500,500)">
<i class="layui-icon"></i>添加子栏目
</button>
<button class="layui-btn-danger layui-btn layui-btn-xs"
onclick="delOne('{{ $value['id'] }}',this)" href="javascript:;"><i
class="layui-icon"></i>删除
</button>
</td>
</tr>
@foreach($value['child'] as $child)
<tr cate-id='{{ $child['id'] }}' fid='{{ $child['parent_id'] }}'>
<td>
<input type="checkbox" name="{{ $child['id'] }}" lay-skin="primary">
</td>
<td>{{ $child['id'] }}</td>
<td>
@if(count($child['child']) > 0)<i class="layui-icon x-show" status='true'></i>@else
├ @endif
{{ $child['name'] }}
</td>
<td><input type="text" class="layui-input x-sort" name="order" value="1"></td>
<td>
<input type="checkbox" name="switch" lay-text="开启|停用"
@if($child['is_open'] == 1) checked @endif
lay-skin="switch" id="{{ $child['id'] }}">
</td>
<td class="td-manage">
<button class="layui-btn layui-btn layui-btn-xs"
onclick="xadmin.open('编辑','/admin/category/edit/{{ $child['id'] }}',500,500)"><i
class="layui-icon"></i>编辑
</button>
<button class="layui-btn layui-btn-warm layui-btn-xs"
onclick="xadmin.open('添加子栏目','/admin/category/addChild/{{ $child['id'] }}',500,500)">
<i class="layui-icon"></i>添加子栏目
</button>
<button class="layui-btn-danger layui-btn layui-btn-xs"
onclick="delOne('{{ $child['id'] }}',this)" href="javascript:;"><i
class="layui-icon"></i>删除
</button>
</td>
</tr>
@foreach($child['child'] as $cd)
<tr cate-id='{{ $cd['id'] }}' fid='{{ $cd['parent_id'] }}'>
<td>
<input type="checkbox" name="{{ $cd['id'] }}" lay-skin="primary">
</td>
<td>{{ $cd['id'] }}</td>
<td>
├{{ $cd['name'] }}
</td>
<td><input type="text" class="layui-input x-sort" name="order" value="1"></td>
<td>
<input type="checkbox" name="switch" lay-text="开启|停用"
@if($cd['is_open'] == 1) checked @endif
lay-skin="switch" id="{{ $cd['id'] }}">
</td>
<td class="td-manage">
<button class="layui-btn layui-btn layui-btn-xs"
onclick="xadmin.open('编辑','/admin/category/edit/{{ $cd['id'] }}',500,500)">
<i class="layui-icon"></i>编辑
</button>
<button class="layui-btn layui-btn-warm layui-btn-xs"
onclick="xadmin.open('添加子栏目','/admin/category/addChild/{{ $cd['id'] }}',500,500)">
<i class="layui-icon"></i>添加子栏目
</button>
<button class="layui-btn-danger layui-btn layui-btn-xs"
onclick="delOne('{{ $cd['id'] }}',this)" href="javascript:;"><i
class="layui-icon"></i>删除
</button>
</td>
</tr>
@endforeach
@endforeach
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script>
layui.use(['form'], function () {
form = layui.form;
});
/*删除一个*/
function delOne(id,obj) {
var ids = [id];
del(ids);
}
function delAll() {
var ids = [];
$('tbody .layui-form-checkbox').each(function (i, elm) {
if ($(this).hasClass('layui-form-checked')) {
var id = $(this).prev().attr('name');
ids.push(id);
}
});
console.log(ids);
del(ids);
}
function del(ids, obj) {
layer.confirm('确认要删除吗?', function (index) {
$.post('/admin/category/del', {ids: ids}, function (data) {
console.log(data);
if (data.code === 200) {
if(obj) $(obj).parents("tr").remove();
layer.msg('已删除!', {icon: 1, time: 1000});
} else {
layer.msg('已删除失败!', {icon: 1, time: 1000});
}
})
});
}
// 分类展开收起的分类的逻辑
//
$(function () {
$("tbody.x-cate tr[fid!='0']").hide();
// 栏目多级显示效果
$('.x-show').click(function () {
if ($(this).attr('status') == 'true') {
$(this).html('');
$(this).attr('status', 'false');
cateId = $(this).parents('tr').attr('cate-id');
$("tbody tr[fid=" + cateId + "]").show();
} else {
cateIds = [];
$(this).html('');
$(this).attr('status', 'true');
cateId = $(this).parents('tr').attr('cate-id');
getCateId(cateId);
for (var i in cateIds) {
$("tbody tr[cate-id=" + cateIds[i] + "]").hide().find('.x-show').html('').attr('status', 'true');
}
}
});
$('thead .layui-form-checkbox').on('click', function () {
if ($(this).hasClass('layui-form-checked')) {
$('tbody .layui-form-checkbox').addClass('layui-form-checked');
} else {
$('tbody .layui-form-checkbox').removeClass('layui-form-checked');
}
});
// 切换开启和停用状态
$('.layui-form-switch').on('click', function () {
var that = $(this);
var id = $(this).prev().attr('id');
$.post('/admin/category/status/' + id, function (data) {
console.log(data);
if (data.data.status === 1) {
that.addClass('layui-form-onswitch');
that.html('<em>启用</em>')
} else {
that.removeClass('layui-form-onswitch');
that.html('<em>停用</em>')
}
})
});
});
var cateIds = [];
function getCateId(cateId) {
$("tbody tr[fid=" + cateId + "]").each(function (index, el) {
id = $(el).attr('cate-id');
cateIds.push(id);
getCateId(id);
});
}
</script>
</body>
</html>