feeRule($data, $user, false); if(!$status) return [$status, $msg]; $update = $msg['data'][0]; try { // 2. 开启事务 DB::beginTransaction(); // 3. 更新当前节点本身 $model = new Fee(); $model->where('id', $data['id'])->update($update); // 4. 判断如果是顶级节点(parent_id == 0),则更新下面所有的子集 if (isset($update['parent_id']) && $update['parent_id'] == 0) { // 获取当前顶级节点最新的两个字段值 $isOther = $update['is_other'] ?? Fee::IS_OTHER_ZERO; $isDirect = $update['is_direct'] ?? Fee::IS_DIRECT_ZERO; // 调用递归方法,向下同步所有后代节点 $this->syncChildrenAttributes($data['id'], $isOther, $isDirect); } DB::commit(); return [true, '']; } catch (\Exception $exception) { DB::rollBack(); return [false, $exception->getMessage()]; } } /** * 辅助方法:递归更新所有子集的 is_other 和 is_direct 属性 * * @param int $parentId 当前父级ID * @param int $isOther * @param int $isDirect */ public function syncChildrenAttributes($parentId, $isOther, $isDirect) { // 1. 找出当前节点下的所有直接子节点 $children = Fee::where('parent_id', $parentId) ->where('del_time', 0) ->get(); // 如果没有子节点了,直接退出递归 if ($children->isEmpty()) { return; } // 2. 批量更新这些直接子节点的这两个字段 Fee::where('parent_id', $parentId) ->where('del_time', 0) ->update([ 'is_other' => $isOther, 'is_direct' => $isDirect, ]); // 3. 递归向下:让每个子节点再去更新它们自己的子节点(孙子辈) foreach ($children as $child) { $this->syncChildrenAttributes($child->id, $isOther, $isDirect); } } public function feeAdd($data,$user){ list($status,$msg) = $this->feeRule($data,$user); if(!$status) return [$status,$msg]; try { DB::beginTransaction(); foreach ($msg['data'] as $value){ $model = new Fee(); $model->parent_id = $value['parent_id']; $model->title = $value['title']; $model->code = $value['code']; $model->is_other = $value['is_other'] ?? Fee::IS_OTHER_ZERO; $model->is_direct = $value['is_direct'] ?? Fee::IS_DIRECT_ZERO; $model->sort = $value['sort'] ?? 0; $model->top_depart_id = $value['top_depart_id']; $model->save(); } DB::commit(); }catch (\Exception $exception){ DB::rollBack(); return [false,$exception->getMessage()]; } return [true,'']; } public function feeDel($data, $user){ list($status,$msg) = $this->checkFeeDel($data); if(! $status) return [false, $msg]; Fee::whereIn('id',$data['id'])->update([ 'del_time'=>time() ]); return [true,'']; } public function checkFeeDel($data){ if($this->isEmpty($data,'id')) return [false,'ID不能为空']; $bool = Fee::whereIn('parent_id', $data['id'])->where('del_time',0)->exists(); if($bool) return [false,'该费用存在子类型']; return [true, '']; } public function feeCommon($data,$user, $field = []){ if(empty($field)) $field = Fee::$field; $model = Fee::TopClear($user,$data); $model = $model->where('del_time',0) ->select($field) ->orderby('sort', 'asc') ->orderby('id', 'asc'); if(isset($data['parent_id'])) $model->where('parent_id', $data['parent_id']); if(isset($data['is_direct'])) $model->where('is_direct', $data['is_direct']); if(isset($data['is_other'])) $model->where('is_other', $data['is_other']); if(! empty($data['title'])) $model->where('title', 'LIKE', '%'.$data['title'].'%'); if(! empty($data['code'])) $model->where('code', 'LIKE', '%'.$data['code'].'%'); return $model; } public function feeList($data, $user){ $model = $this->feeCommon($data, $user); $list = $model->get()->toArray(); $list = $this->fillFeeList($list, $user); $list_tree = $list; if(! empty($list_tree)) { $minParentId = min(array_column($list_tree, 'parent_id')); $list_tree = $this->makeTree($minParentId,$list_tree); $list_tree = $this->set_sort_circle($list_tree); } return [true,['data' => $list,'tree' => $list_tree]]; } public function fillFeeList($list, $user, $is_export = false){ if(empty($list)) return $list; if($is_export){ $map = Fee::where('del_time',0) ->whereIn('id', array_column($list['data'], 'parent_id')) ->select('code','id', 'title') ->get() ->toArray(); $map = array_column($map, null, 'id'); foreach ($list['data'] as $key => $value){ $tmp = $map[$value['parent_id']] ?? ""; $list['data'][$key]['parent_code'] = $tmp['code'] ?? ""; $list['data'][$key]['parent_title'] = $tmp['title'] ?? ""; $list['data'][$key]['is_other_title'] = Fee::IS_OTHER[$value['is_other']] ?? ""; $list['data'][$key]['is_direct_title'] = Fee::IS_DIRECT[$value['is_direct']] ?? ""; } } return $list; } public function feeRule($data,$user, $is_check = true){ if(empty($data['data'])) return [false,'数据不能为空!']; $code = array_column($data['data'],'code'); $title = array_column($data['data'],'title'); $code = array_map(function($val) { return $val !== null ? $val : 0; }, $code); $title = array_map(function($val) { return $val !== null ? $val : 0; }, $title); $code_count = array_count_values($code); $title_count = array_count_values($title); foreach ($code as $value){ if(empty($value)) return [false,'编码不能为空!']; if($code_count[$value] > 1) return [false,'编码不能重复']; } foreach ($title as $value){ if(empty($value)) return [false,'名称不能为空!']; if($title_count[$value] > 1) return [false,'名称不能重复']; } foreach ($data['data'] as $key => $value){ $top_depart_id = $user['top_depart_id']; if(empty($value['parent_id'])) $data['data'][$key]['parent_id'] = 0; // 1. 基础互斥校验 $isOther = $value['is_other'] ?? Fee::IS_OTHER_ZERO; $isDirect = $value['is_direct'] ?? Fee::IS_DIRECT_ZERO; if ($isOther && $isDirect) return [false, '是否其他费用和是否直接投入费用不能同时开启']; $data['data'][$key]['top_depart_id'] = $top_depart_id; $data['data'][$key]['upd_time'] = time(); if($is_check){ $data['data'][$key]['crt_time'] = time(); $bool = Fee::whereRaw("binary code = '{$value['code']}'") ->where('top_depart_id', $top_depart_id) ->where('del_time',0) ->exists(); }else{ if($this->isEmpty($data,'id')) return [false,'id不能为空!']; $bool = Fee::whereRaw("binary code = '{$value['code']}'") ->where('top_depart_id', $top_depart_id) ->where('id','<>',$data['id']) ->where('del_time',0) ->exists(); } if($bool) return [false,'编码已存在']; } return [true, $data]; } }