model = new \app\admin\model\course\Group; $this->groupBindModel = new \app\admin\model\course\GroupBind(); } /** * 查看 */ public function index() { $this->request->filter(['strip_tags', 'trim']); list($where, $sort, $order, $offset, $limit) = $this->buildparams(); $list = $this->model ->where($where) ->where(['uniacid' => UNIACID]) ->order($sort, $order) ->paginate($limit); $rows = $list->toArray(); if (!empty($rows['data'])) { foreach ($rows['data'] as &$item) { $item['course_count'] = $this->groupBindModel->groupGetCourseBindCount($item['id']); } } $result = array("total" => $rows['total'], "rows" => $rows['data'], 'attr' => [ 'status' => $this->model->getStatusList() ]); return $this->success("获取成功", $result); } /** * 获取分组树(4级) */ public function tree() { $list = $this->model ->where(['uniacid' => UNIACID, 'parent_id' => 0]) ->order('sort', 'asc') ->order('id', 'asc') ->select(); $result = []; foreach ($list as $item) { $result[] = $this->getGroupTree($item); } return $this->success("获取成功", $result); } /** * 递归获取分组树(4级) */ protected function getGroupTree($group) { $data = $group->toArray(); $children = $this->model ->where(['uniacid' => UNIACID, 'parent_id' => $group['id']]) ->order('sort', 'asc') ->order('id', 'asc') ->select(); if (!empty($children)) { $data['children'] = []; foreach ($children as $child) { $data['children'][] = $this->getGroupTree($child); } } return $data; } /** * 添加 */ public function add() { $params = $this->request->param('row/a'); if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); $params['uniacid'] = UNIACID; $params['createtime'] = time(); if (!isset($params['sort'])) { $params['sort'] = $this->model->defineSort(); } $result = $this->model->allowField(true)->save($params); if ($result !== false) { $this->success("添加成功"); } else { $this->error(__('No rows were inserted')); } } /** * 编辑 */ public function edit($ids = null) { $params = $this->request->param('row/a'); if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); $row = $this->model->where('id', $ids)->where('uniacid', UNIACID)->find(); if (!$row) { $this->error(__('No Results were found')); } $result = $row->allowField(true)->save($params); if ($result !== false) { $this->success("更新成功"); } else { $this->error(__('No rows were updated')); } } /** * 删除 */ public function del($ids = "") { if ($ids) { // 检查是否有子分组 $hasChildren = $this->model->where('parent_id', 'in', $ids)->where('uniacid', UNIACID)->find(); if ($hasChildren) { $this->error('该分组下存在子分组,请先删除子分组'); } $count = $this->model->where('id', 'in', $ids)->where('uniacid', UNIACID)->delete(); if ($count) { // 删除关联的课程绑定 foreach (explode(',', $ids) as $id) { $this->groupBindModel->groupDelCourseBind($id); } $this->success("删除成功"); } else { $this->error(__('No rows were deleted')); } } $this->error(__('Parameter %s can not be empty', 'ids')); } /** * 获取状态列表 */ public function getStatusList() { $this->success("获取成功", $this->model->getStatusList()); } /** * 根据ID获取分组信息 */ public function info($ids = null) { $row = $this->model ->where('id', $ids) ->where('uniacid', UNIACID) ->find(); if (!$row) { $this->error(__('No Results were found')); } $data = $row->toArray(); // 获取父级信息 if ($data['parent_id'] > 0) { $parent = $this->model ->where('id', $data['parent_id']) ->where('uniacid', UNIACID) ->find(); $data['parent_name'] = $parent ? $parent['name'] : ''; } else { $data['parent_name'] = ''; } $this->success("获取成功", $data); } /** * 批量保存分组(前端完成所有操作后一次性提交) * * @param array original_ids 原始数据中的所有分组ID列表 * @param array groups 完整的树形分组结构数据 */ public function save() { $originalIds = $this->request->param('original_ids/a', []); $groups = $this->request->param('groups/a', []); if (empty($groups)) { $this->error('分组数据不能为空'); } // 提取当前提交的所有ID $currentIds = $this->extractAllIds($groups); // 找出需要删除的ID(在original_ids中存在,但不在currentIds中) $toDelete = array_diff($originalIds, $currentIds); // 分组处理数据,按层级分组(4级:0, 1, 2, 3) $toAdd = [0 => [], 1 => [], 2 => [], 3 => []]; $toUpdate = [0 => [], 1 => [], 2 => [], 3 => []]; $this->categorizeDataByLevel($groups, $toAdd, $toUpdate); // 开始事务 Db::startTrans(); $result = null; $error = null; try { $addedCount = 0; $updatedCount = 0; $deletedCount = 0; // 1. 先删除(从叶子节点开始,避免外键约束问题) if (!empty($toDelete)) { $deleteList = $this->model ->where('id', 'in', $toDelete) ->where('uniacid', UNIACID) ->order('id', 'desc') ->select(); foreach ($deleteList as $item) { $deletedCount += $this->deleteGroupRecursive($item['id']); } } // 2. 更新现有数据(按层级顺序) $idMapping = []; for ($level = 0; $level <= 3; $level++) { usort($toUpdate[$level], function ($a, $b) { return $a['sort'] - $b['sort']; }); foreach ($toUpdate[$level] as $item) { $id = $item['id']; unset($item['id']); unset($item['children']); unset($item['level']); $this->model->where('id', $id)->where('uniacid', UNIACID)->update($item); $updatedCount++; } } // 3. 新增数据 - 按原始树形结构顺序保存 $this->saveAddedGroups($groups, $idMapping, $addedCount); Db::commit(); $result = [ 'added' => $addedCount, 'updated' => $updatedCount, 'deleted' => $deletedCount, 'id_mapping' => $idMapping ]; } catch (\Exception $e) { Db::rollback(); $error = $e->getMessage(); } if ($error) { $this->error('保存失败:' . $error); } else { $this->success('保存成功', $result); } } /** * 递归删除分组及其子分组 */ protected function deleteGroupRecursive($groupId) { $count = 0; // 先删除子分组 $children = $this->model ->where('parent_id', $groupId) ->where('uniacid', UNIACID) ->column('id'); foreach ($children as $childId) { $count += $this->deleteGroupRecursive($childId); } // 删除关联的课程绑定 $this->groupBindModel->groupDelCourseBind($groupId); // 再删除当前分组 $count += $this->model->where('id', $groupId)->where('uniacid', UNIACID)->delete(); return $count; } /** * 从树形结构中提取所有ID */ protected function extractAllIds($groups) { $ids = []; foreach ($groups as $item) { $ids[] = abs($item['id']); if (!empty($item['children'])) { $ids = array_merge($ids, $this->extractAllIds($item['children'])); } } return array_unique($ids); } /** * 将数据按层级分类为新增和更新(4级) */ protected function categorizeDataByLevel($groups, &$toAdd, &$toUpdate, $parentId = 0, $level = 0) { foreach ($groups as $item) { $currentParentId = $item['id']; $item['parent_id'] = $parentId; $item['level'] = $level; if ($item['id'] < 0) { $toAdd[$level][] = $item; } else { $toUpdate[$level][] = $item; } if (!empty($item['children'])) { $this->categorizeDataByLevel($item['children'], $toAdd, $toUpdate, $currentParentId, $level + 1); } } } /** * 递归保存新增分组(按原始树形结构顺序) */ protected function saveAddedGroups($groups, &$idMapping, &$addedCount, $parentId = 0) { usort($groups, function ($a, $b) { return $a['sort'] - $b['sort']; }); foreach ($groups as $item) { $isNew = $item['id'] < 0; if ($isNew) { $tempId = $item['id']; $data = [ 'name' => $item['name'], 'parent_id' => $parentId, 'status' => isset($item['status']) ? intval($item['status']) : 1, 'sort' => isset($item['sort']) ? $item['sort'] : 0, 'uniacid' => UNIACID, 'createtime' => time(), ]; $newId = $this->model->insertGetId($data); $idMapping[$tempId] = $newId; $addedCount++; if (!empty($item['children'])) { $this->saveAddedGroups($item['children'], $idMapping, $addedCount, $newId); } } else { if (!empty($item['children'])) { $this->saveAddedGroups($item['children'], $idMapping, $addedCount, $item['id']); } } } } /** * 设置排序 */ public function setSort($id, $type = 'up') { $self = $this->model->where('id', $id)->where('uniacid', UNIACID)->find(); if (!$self) { $this->error(__('No Results were found')); } $direction = $type == 'up' ? '<' : '>'; $sort = $type == 'up' ? 'desc' : 'asc'; $brother = $this->model ->where('sort', $direction, $self['sort']) ->where('uniacid', UNIACID) ->order('sort', $sort) ->find(); if (!$brother) { $this->error(__('无继续调节空间')); } $this->model->where([ 'id' => $self['id'] ])->update([ 'sort' => $brother['sort'] ]); $this->model->where([ 'id' => $brother['id'] ])->update([ 'sort' => $self['sort'] ]); return $this->success("操作成功"); } }