get('page_size') ?? 10; $projectAsset = Project::filter($request->all())->allowed()->with('assets')->paginate($pageSize); return ProjectResource::collection($projectAsset); } public function treeIndex(string $id){ $project = Project::allowed($id)->findOrFail($id); //获取项目所关联的需求所在需求分组的id $requirementsGroupIds=$project->requirementsGroup ->pluck('id')->unique()->toArray(); // 加载项目中的所有Asset及其关联的RequirementGroup $assetsWithRequirementGroups = $project->assets()->with('requirementGroups')->get(); $filteredAssets = $assetsWithRequirementGroups->map(function ($asset) use ($requirementsGroupIds) { if (empty($requirementsGroupIds)) { // 如果$requirementsGroupIds为空,则清空requirementGroups集合 $asset->setRelation('requirementGroups', collect()); } else { // 否则,过滤requirementGroups集合 $asset->setRelation('requirementGroups', $asset->requirementGroups->filter(function ($group) use ($requirementsGroupIds) { return in_array($group->id, $requirementsGroupIds); })); } return $asset; }); return AssetRequirementGroupTreeResource::collection($filteredAssets); } /** * Store a newly created resource in storage. */ public function store(FileAssociationService $service, CreateOrUpdateRequest $request) { $project = new Project(); $project->mergeFillable([ 'company_id', 'created_by' ]); $service->check( $request->get("file_ids", []), FileObjectType::PROJECT, $request->get("file_uuid"), ); DB::transaction(function () use ($request, $project, $service) { $project->fill([ ...$request->all(), 'company_id' => Auth::user()->company_id, 'created_by' => Auth::id(), 'description' => $request->description? (new \App\Services\File\ImageUrlService)->interceptImageUrl($request->description) : null, 'whitelist' => $request->whitelist ? sprintf(",%s,", implode(',', $request->whitelist)) : null, ]); $project->save(); ActionRepository::createByProject($project, ObjectAction::CREATED); $service->association($project->id); if ($request->has("assets")) { foreach ($request->get("assets", []) as $assetId) { ProjectAsset::create([ 'project_id' => $project->id, 'asset_id' => $assetId, ]); } } if ($request->has("plans")) { foreach ($request->get("plans", []) as $planId) { ProjectPlan::create([ 'project_id' => $project->id, 'plan_id' => $planId, ]); } } TeamMember::create([ 'project_id' => $project->id, 'user_id' => Auth::id(), 'role' => '', 'limited' => 1, 'join_at' => Carbon::now()->toDateString(), 'created_by' => Auth::id(), ]); }); return $this->created(); } /** * Display the specified resource. */ public function show(string $id) { $project = Project::allowed($id)->findOrFail($id); return new ProjectDetailResource($project); } /** * Update the specified resource in storage. */ public function update(CreateOrUpdateRequest $request, string $id) { $project = Project::allowed($id)->findOrFail($id); $project->fill([ ...$request->all(), 'description' => $request->description? (new \App\Services\File\ImageUrlService)->interceptImageUrl($request->description) : null, 'whitelist' => $request->whitelist ? sprintf(",%s,", implode(',', $request->whitelist)) : null, ]); $changes = ModelChangeDetector::detector(ActionObjectType::PROJECT, $project); $project->save(); ActionRepository::createByProject($project, ObjectAction::EDITED, objectChanges: $changes); if ($request->has("assets")) { ProjectAsset::where('project_id', $project->id)->delete(); foreach ($request->get("assets", []) as $assetId) { ProjectAsset::create([ 'project_id' => $project->id, 'asset_id' => $assetId, ]); } } if ($request->has("plans")) { ProjectPlan::where('project_id', $project->id)->delete(); foreach ($request->get("plans", []) as $planId) { ProjectPlan::create([ 'project_id' => $project->id, 'plan_id' => $planId, ]); } } return $this->noContent(); } /** * Remove the specified resource from storage. */ public function destroy(string $id) { $project = Project::allowed($id)->findOrFail($id); $project->delete(); ActionRepository::createByProject($project, ObjectAction::DELETED); return $this->noContent(); } public function closed(Request $request, string $id) { $project = Project::allowed($id)->findOrFail($id); $project->status = ProjectStatus::CLOSED->value; $changes = ModelChangeDetector::detector(ActionObjectType::PROJECT, $project); $project->save(); ActionRepository::createByProject( $project, ObjectAction::CLOSED, $request->comment?(new \App\Services\File\ImageUrlService)->interceptImageUrl($request->comment) : null, objectChanges: $changes ); return $this->noContent(); } public function start(Request $request, string $id) { $project = Project::allowed($id)->findOrFail($id); $project->status = ProjectStatus::DOING->value; $changes = ModelChangeDetector::detector(ActionObjectType::PROJECT, $project); $project->save(); ActionRepository::createByProject( $project, ObjectAction::STARTED, $request->comment?(new \App\Services\File\ImageUrlService)->interceptImageUrl($request->comment) : null, objectChanges: $changes ); return $this->noContent(); } public function pause(Request $request, string $id) { $project = Project::allowed($id)->findOrFail($id); $project->status = ProjectStatus::PAUSE->value; $changes = ModelChangeDetector::detector(ActionObjectType::PROJECT, $project); $project->save(); ActionRepository::createByProject( $project, ObjectAction::PAUSED, $request->comment?(new \App\Services\File\ImageUrlService)->interceptImageUrl($request->comment) : null, objectChanges: $changes ); return $this->noContent(); } /** * 延期 * * @param PostponeRequest $request * @param string $id * @return \Illuminate\Http\Response */ public function postpone(PostponeRequest $request, string $id) { $project = Project::allowed($id)->findOrFail($id); $project->fill($request->only([ 'begin', 'end' ])); $changes = ModelChangeDetector::detector(ActionObjectType::PROJECT, $project); $project->save(); ActionRepository::createByProject( $project, ObjectAction::DELAY, $request->comment?(new \App\Services\File\ImageUrlService)->interceptImageUrl($request->comment) : null, objectChanges: $changes ); return $this->noContent(); } public function linkRequirement(LinkRequirementRequest $request, string $id) { $requirementIds = $request->get("requirement_id",[]); $project = Project::allowed($id)->findOrFail($id); if(! $requirementIds){ return $this->forbidden("Please select the correct requirement"); } // $requirement = Requirement::findOrFail($request->requirement_id); // $exists = ProjectAsset::query() // ->where('project_id', $project->id) // ->where('asset_id', $requirement->asset_id) // ->count(); // if (! $exists) { // return $this->forbidden("Please select the correct requirement"); // } DB::transaction(function () use ($requirementIds,$project) { foreach ($requirementIds as $requirementId) { $requirement=Requirement::query()->where('id',$requirementId)->first(); ProjectRequirement::query()->firstOrCreate([ 'project_id' => $project->id, 'requirement_id' => $requirement->id, 'asset_id' => $requirement->asset_id, 'requirement_group_id'=> $requirement->requirement_group_id, ]); } }); return $this->noContent(); } public function unlinkRequirement(UnlinkRequirementRequest $request, string $id) { $requirementIds = $request->get("requirement_id",[]); $project = Project::allowed($id)->findOrFail($id); if (! $requirementIds) { return $this->forbidden("Please select the correct requirement"); } if($project->requirements->isEmpty()){ return $this->forbidden("Project has no associated requirements"); } DB::transaction(function () use ($requirementIds,$project) { foreach ($requirementIds as $requirement) { ProjectRequirement::query()->where([ 'project_id' => $project->id, 'requirement_id' => $requirement, ])->delete(); } }); return $this->noContent(); } public function linkRequirementByPlan(LinkRequirementByPlanRequest $request, string $id) { $project = Project::allowed($id)->findOrFail($id); $plan = Plan::findOrFail($request->plan_id); foreach ($plan->requirements as $requirement) { ProjectRequirement::query()->firstOrCreate([ 'project_id' => $project->id, 'requirement_id' => $requirement->id, ]); } return $this->noContent(); } public function plan(string $id) { $project = Project::allowed($id)->findOrFail($id); return SimplePlanResource::collection($project->plans); } public function requirement(Request $request,string $id) { $project = Project::allowed($id)->findOrFail($id); // 初始化 requirements 的查询构建器 $requirementsQuery = $project->requirements(); if ($request->has('asset')) { $asset_id = $request->input('asset'); $requirementsQuery->where('requirements.asset_id', $asset_id); } if ($request->has('requirementGroup')) { $requirementGroup = $request->input('requirementGroup'); $requirementsQuery->where('requirements.requirement_group_id', $requirementGroup); } if ($request->has('status')) { $status = $request->input('status'); $requirementsQuery->where('requirements.status', $status); } $requirements = $requirementsQuery ->with(['createdBy']) // 预加载 createdBy 关联 ->simplePaginate(); return ProjectRequirementResource::collection($requirements); } public function notLinkAssetRequirement(string $id) { $project = Project::allowed($id)->findOrFail($id); $requirements = $project->assets ? Requirement::query()->whereIn('asset_id', $project->assets?->pluck('id')->toArray())->whereNotIn('id', $project->requirements?->pluck('id')->toArray())->simplePaginate() : []; return AssetRequirementResource::collection($requirements); } public function updateLinkAssets(UpdateLinkAssetsRequest $request, string $projectId) { $project = Project::allowed($projectId)->find($projectId); if (is_null($project)){ return $this->badRequest('project does not exist'); } $assetsIds = $request->assets; DB::transaction(function () use ($projectId,$assetsIds) { ProjectAsset::where('project_id', $projectId)->delete(); foreach ($assetsIds as $assetId) { ProjectAsset::create([ 'project_id' => $projectId, 'asset_id' => $assetId, ]); } }); return $this->noContent(); } public function dynamic(Request $request, string $id) { $project = Project::allowed($id)->findOrFail($id); return $this->success([ 'data' => ActionRepository::dynamic($project, $request->all()) ]); } public function kanban(Request $request, ProjectKanbanService $service, string $id) { $project = Project::allowed($id)->findOrFail($id); return $this->success([ 'data' => $service->kanban($project, $request->get("group", "requirement_asc")) ]); } public function groupView(Request $request, string $id) { $project = Project::allowed($id)->findOrFail($id); $group = in_array( $request->get("group"), ['requirement_id','status','assign','finished_by','closed_by','task_type'] ) ? $request->get("group") : "requirement_id"; return $this->success([ 'data' => (new ProjectTaskGroupViewService())->groupView($project, $group, $request->all()) ]); } public function gantt(Request $request, string $id) { $project = Project::allowed($id)->findOrFail($id); $group = in_array( $request->get("group"), ['requirement_id','assign','task_type'] ) ? $request->get("group") : "task_type"; return $this->success([ 'data' => (new ProjectGanttService())->gantt($project, $group) ]); } public function printKanban(string $id) { $project = Project::allowed($id)->findOrFail($id); return $this->success([ 'data' => [ 'requirements' => ProjectKanbanRequirementResource::collection($project->requirements), 'tasks' => ProjectKanbanTaskResource::collection($project->tasks), 'task_status' => TaskStatus::cases(), ] ]); } public function latestDynamic(string $id) { $project = Project::allowed($id)->findOrFail($id); return $this->success([ 'data' => ActionRepository::latestDynamic($project) ]); } public function requirementsLinkGroup(string $id){ $requirementsLinksGroup = Project::allowed($id)->findOrFail($id)->requirementsGroup->unique('id'); return RequirementGroupParentResource::collection($requirementsLinksGroup); } public function tree() { $projects = Project::allowed()->get(['id', 'name'])->each(function ($project) { // 设置固定的type值 $project->type = 'project'; $project->uniId=$project->type.'_'.$project->id; }); return $this->success([ 'data' => $projects ]); } }