appendattrs['task_num'])) { $builder = ProjectTask::whereProjectId($this->id)->whereParentId(0)->whereNull('archived_at'); $this->appendattrs['task_num'] = $builder->count(); $this->appendattrs['task_complete'] = $builder->whereNotNull('complete_at')->count(); $this->appendattrs['task_percent'] = $this->appendattrs['task_num'] ? intval($this->appendattrs['task_complete'] / $this->appendattrs['task_num'] * 100) : 0; // $builder = ProjectTask::whereProjectId($this->id)->whereParentId(0)->authData(User::userid(), true)->whereNull('archived_at'); $this->appendattrs['task_my_num'] = $builder->count(); $this->appendattrs['task_my_complete'] = $builder->whereNotNull('complete_at')->count(); $this->appendattrs['task_my_percent'] = $this->appendattrs['task_my_num'] ? intval($this->appendattrs['task_my_complete'] / $this->appendattrs['task_my_num'] * 100) : 0; } } /** * 任务数量 * @return int */ public function getTaskNumAttribute() { $this->generateTaskData(); return $this->appendattrs['task_num']; } /** * 任务完成数量 * @return int */ public function getTaskCompleteAttribute() { $this->generateTaskData(); return $this->appendattrs['task_complete']; } /** * 任务完成率 * @return int */ public function getTaskPercentAttribute() { $this->generateTaskData(); return $this->appendattrs['task_percent']; } /** * 任务数量(我的) * @return int */ public function getTaskMyNumAttribute() { $this->generateTaskData(); return $this->appendattrs['task_my_num']; } /** * 任务完成数量(我的) * @return int */ public function getTaskMyCompleteAttribute() { $this->generateTaskData(); return $this->appendattrs['task_my_complete']; } /** * 任务完成率(我的) * @return int */ public function getTaskMyPercentAttribute() { $this->generateTaskData(); return $this->appendattrs['task_my_percent']; } /** * 负责人会员ID * @return int */ public function getOwnerUseridAttribute() { if (!isset($this->appendattrs['owner_userid'])) { $ownerUser = $this->projectUser->where('owner', 1)->first(); $this->appendattrs['owner_userid'] = $ownerUser ? $ownerUser->userid : 0; } return $this->appendattrs['owner_userid']; } /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function projectColumn(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(ProjectColumn::class, 'project_id', 'id')->orderBy('sort')->orderBy('id'); } /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function projectLog(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(ProjectLog::class, 'project_id', 'id')->orderByDesc('id'); } /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function projectUser(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(ProjectUser::class, 'project_id', 'id')->orderBy('id'); } /** * 查询自己的项目 * @param self $query * @param null $userid * @return self */ public function scopeAuthData($query, $userid = null) { $userid = $userid ?: User::userid(); $query->join('project_users', 'projects.id', '=', 'project_users.project_id') ->where('project_users.userid', $userid); return $query; } /** * 加入项目 * @param int $userid 加入的会员ID * @return bool */ public function joinProject($userid) { if (empty($userid)) { return false; } if (!User::whereUserid($userid)->exists()) { return false; } ProjectUser::updateInsert([ 'project_id' => $this->id, 'userid' => $userid, ]); return true; } /** * 同步项目成员至聊天室 */ public function syncDialogUser() { if (empty($this->dialog_id)) { return; } AbstractModel::transaction(function() { $userids = $this->relationUserids(); foreach ($userids as $userid) { WebSocketDialogUser::updateInsert([ 'dialog_id' => $this->dialog_id, 'userid' => $userid, ]); } WebSocketDialogUser::whereDialogId($this->dialog_id)->whereNotIn('userid', $userids)->delete(); }); } /** * 获取相关所有人员(项目负责人、项目成员) * @return array */ public function relationUserids() { return $this->projectUser->pluck('userid')->toArray(); } /** * 会员id是否在项目里 * @param int $userid * @return int 0:不存在、1存在、2存在且是管理员 */ public function useridInTheProject($userid) { $user = ProjectUser::whereProjectId($this->id)->whereUserid(intval($userid))->first(); if (empty($user)) { return 0; } return $user->owner ? 2 : 1; } /** * 归档项目、取消归档 * @param Carbon|null $archived_at 归档时间 * @return bool */ public function archivedProject($archived_at) { AbstractModel::transaction(function () use ($archived_at) { if ($archived_at === null) { // 取消归档 $this->archived_at = null; $this->addLog("项目取消归档"); $this->pushMsg('add', $this); ProjectTask::whereProjectId($this->id)->whereArchivedFollow(1)->update([ 'archived_at' => null, 'archived_follow' => 0 ]); } else { // 归档项目 $this->archived_at = $archived_at; $this->archived_userid = User::userid(); $this->addLog("项目归档"); $this->pushMsg('archived'); ProjectTask::whereProjectId($this->id)->whereArchivedAt(null)->update([ 'archived_at' => $archived_at, 'archived_follow' => 1 ]); } $this->save(); }); return true; } /** * 删除项目 * @return bool */ public function deleteProject() { AbstractModel::transaction(function () { $dialog = WebSocketDialog::find($this->dialog_id); $dialog?->deleteDialog(); $columns = ProjectColumn::whereProjectId($this->id)->get(); foreach ($columns as $column) { $column->deleteColumn(false); } $this->delete(); $this->addLog("删除项目"); }); $this->pushMsg('delete'); return true; } /** * 添加项目日志 * @param string $detail * @param int $userid * @return ProjectLog */ public function addLog($detail, $userid = 0) { $log = ProjectLog::createInstance([ 'project_id' => $this->id, 'column_id' => 0, 'task_id' => 0, 'userid' => $userid ?: User::userid(), 'detail' => $detail, ]); $log->save(); return $log; } /** * 推送消息 * @param string $action * @param array $data 发送内容,默认为[id=>项目ID] * @param array $userid 指定会员,默认为项目所有成员 */ public function pushMsg($action, $data = null, $userid = null) { if ($data === null) { $data = ['id' => $this->id]; } if ($userid === null) { $userid = $this->relationUserids(); } $params = [ 'ignoreFd' => Request::header('fd'), 'userid' => $userid, 'msg' => [ 'type' => 'project', 'action' => $action, 'data' => $data, ] ]; $task = new PushTask($params, false); Task::deliver($task); } /** * 根据用户获取项目信息(用于判断会员是否存在项目内) * @param int $project_id * @param bool $ignoreArchived 排除已归档 * @return self */ public static function userProject($project_id, $ignoreArchived = true) { $project = self::select(self::projectSelect)->authData()->where('projects.id', intval($project_id))->first(); if (empty($project)) { throw new ApiException('项目不存在或不在成员列表内', [ 'project_id' => $project_id ], -4001); } if ($ignoreArchived && $project->archived_at != null) { throw new ApiException('项目已归档', [ 'project_id' => $project_id ], -4001); } return $project; } }