HTML 表单中同名 name="ids[]" 的复选框提交时,PHP 自动接收为数组 $_POST['ids'] = [1, 5, 8]。后端用主键 IN 条件一次性删除。
<table class="table table-striped">
<thead>
<tr>
<th style="width: 40px">
<input type="checkbox" class="check-all">
</th>
<th>ID</th>
<th>标题</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<volist name="list" id="vo">
<tr>
<td><input type="checkbox" name="ids[]" value="{$vo.id}" class="check-item"></td>
<td>{$vo.id}</td>
<td>{$vo.title}</td>
<td>
<a href="{:url('edit', ['id' => $vo.id])}">编辑</a>
<a href="javascript:;" class="btn-delete" data-id="{$vo.id}">删除</a>
</td>
</tr>
</volist>
</tbody>
</table>
<div class="batch-actions">
<button type="button" id="btn-batch-delete" class="btn btn-danger">
<i class="fa fa-trash"></i> 批量删除选中
</button>
</div>
<script>
// 全选/反选
$('.check-all').change(function() {
$('.check-item').prop('checked', this.checked);
});
// 批量删除 AJAX
$('#btn-batch-delete').click(function() {
const ids = $('.check-item:checked').map(function() { return this.value; }).get();
if (!ids.length) {
layer.msg('请至少选择一项', {icon: 2});
return;
}
layer.confirm('确定删除选中的 ' + ids.length + ' 条记录?', {icon: 3}, function(index) {
$.post('{:url("batchDelete")}', {ids: ids.join(",")}, function(res) {
if (res.code === 1) {
layer.msg(res.msg, {icon: 1}, function() { location.reload(); });
} else {
layer.msg(res.msg, {icon: 2});
}
}, 'json');
layer.close(index);
});
});
</script>
<?php
namespace app\admin\controller;
use think\facade\Db;
use think\facade\Request;
class Article extends BaseController
{
// 批量删除
public function batchDelete()
{
$ids = Request::param('ids');
if (empty($ids)) {
return json(['code' => 0, 'msg' => '参数为空']);
}
// 安全过滤:仅允许数字
$idArr = array_filter(explode(',', $ids), 'ctype_digit');
if (empty($idArr)) {
return json(['code' => 0, 'msg' => '无效ID']);
}
// 获取主键名 (兼容无主键表)
$pk = Db::name('article')->getPk();
if (!$pk) {
return json(['code' => 0, 'msg' => '表无主键']);
}
try {
$count = Db::name('article')
->where($pk, 'in', $idArr)
->delete();
return json([
'code' => 1,
'msg' => "成功删除 {$count} 条记录",
'data' => ['deleted' => $count]
]);
} catch (\Exception $e) {
\think\facade\Log::error('批量删除失败', ['ids' => $ids, 'error' => $e->getMessage()]);
return json(['code' => 0, 'msg' => '删除失败:' . $e->getMessage()]);
}
}
// 单条删除 (复用)
public function delete($id)
{
return $this->batchDelete(); // 复用逻辑,前端传 ids=id
}
}
public function batchDelete()
{
$ids = input('param.ids');
$idArr = array_filter(explode(',', $ids), 'ctype_digit');
// ...
$count = db('article')->where('id', 'in', $idArr)->delete();
// ...
}
若分类表采用嵌套集合模型 (lft/rgt),批量删除需级联子节点:
public function batchDeleteCategory()
{
$ids = array_filter(explode(',', input('ids')), 'ctype_digit');
$categories = db('category')->where('id', 'in', $ids)->select();
Db::transaction(function () use ($categories) {
foreach ($categories as $cat) {
// 删除子树
db('category')
->where('lft', '>=', $cat['lft'])
->where('rgt', '<=', $cat['rgt'])
->delete();
}
});
return json(['code' => 1, 'msg' => '删除成功']);
}
ThinkPHP 批量删除核心是 name="ids[]" + whereIn。生产环境必须叠加:权限控制、软删除、事务、日志审计、CSRF 防护。前端用 Layer/SweetAlert 交互确认,后端统一 JSON 响应,体验与安全兼得。