diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index 56d039f2f..93d44b0dd 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -30,6 +30,7 @@ use App\Models\ProjectTaskFile; use App\Models\ProjectTaskUser; use App\Models\WebSocketDialog; use App\Exceptions\ApiException; +use App\Models\ProjectPermission; use App\Module\BillMultipleExport; use Illuminate\Support\Facades\DB; use App\Models\ProjectTaskFlowChange; @@ -876,10 +877,10 @@ class ProjectController extends AbstractController public function column__one() { User::auth(); - // + // $column_id = intval(Request::input('column_id')); $deleted = Request::input('deleted', 'no'); - // + // $builder = ProjectColumn::whereId($column_id); if ($deleted == 'all') { $builder->withTrashed(); @@ -890,10 +891,10 @@ class ProjectController extends AbstractController if (empty($column)) { return Base::retError('列表不存在'); } - // + // return Base::retSuccess('success', $column); } - + /** * @api {get} api/project/task/lists 19. 任务列表 @@ -1004,6 +1005,10 @@ class ProjectController extends AbstractController $builder->whereNull('project_tasks.archived_at'); } // + if (ProjectPermission::getPermission($project_id, ProjectPermission::PANEL_SHOW_TASK_COMPLETE) == 0) { + $builder->whereNull('project_tasks.complete_at'); + } + // if ($deleted == 'all') { $builder->withTrashed(); } elseif ($deleted == 'yes') { @@ -1507,7 +1512,7 @@ class ProjectController extends AbstractController $archived = Request::input('archived', 'no'); // $isArchived = str_replace(['all', 'yes', 'no'], [null, false, true], $archived); - $task = ProjectTask::userTask($task_id, $isArchived, true, false, ['taskUser', 'taskTag']); + $task = ProjectTask::userTask($task_id, $isArchived, true, '', ['taskUser', 'taskTag']); // 项目可见性 $project_userid = ProjectUser::whereProjectId($task->project_id)->whereOwner(1)->value('userid'); // 项目负责人 if ($task->visibility != 1 && $user->userid != $project_userid) { @@ -1603,7 +1608,7 @@ class ProjectController extends AbstractController return Base::retError('文件不存在或已被删除'); } // - $task = ProjectTask::userTask($file->task_id, true, true, true); + $task = ProjectTask::userTask($file->task_id, true, true, ProjectPermission::TASK_REMOVE); // $task->pushMsg('filedelete', $file); $file->delete(); @@ -1732,6 +1737,7 @@ class ProjectController extends AbstractController $column_id = $data['column_id']; // 项目 $project = Project::userProject($project_id); + ProjectTask::userTaskPermission(ProjectPermission::TASK_ADD, $project); // 列表 $column = null; $newColumn = null; @@ -1808,7 +1814,7 @@ class ProjectController extends AbstractController $task_id = intval(Request::input('task_id')); $name = Request::input('name'); // - $task = ProjectTask::userTask($task_id, true, true, true); + $task = ProjectTask::userTask($task_id, true, true, ProjectPermission::TASK_ADD); if ($task->complete_at) { return Base::retError('主任务已完成无法添加子任务'); } @@ -1867,7 +1873,7 @@ class ProjectController extends AbstractController $param = Request::input(); $task_id = intval($param['task_id']); // - $task = ProjectTask::userTask($task_id, true, true, 2); + $task = ProjectTask::userTask($task_id, true, true, ProjectPermission::TASK_UPDATE); $taskUser = ProjectTaskUser::select(['userid', 'owner'])->whereTaskId($task_id)->get(); $owners = $taskUser->where('owner', 1)->pluck('userid')->toArray(); // 负责人 $assists = $taskUser->where('owner', 0)->pluck('userid')->toArray(); // 协助人 @@ -2003,7 +2009,7 @@ class ProjectController extends AbstractController $task_id = intval(Request::input('task_id')); $type = Request::input('type', 'add'); // - $task = ProjectTask::userTask($task_id, $type == 'add', true, true); + $task = ProjectTask::userTask($task_id, $type == 'add', true, ProjectPermission::TASK_ARCHIVED); // if ($task->parent_id > 0) { return Base::retError('子任务不支持此功能'); @@ -2045,7 +2051,7 @@ class ProjectController extends AbstractController $task_id = intval(Request::input('task_id')); $type = Request::input('type', 'delete'); // - $task = ProjectTask::userTask($task_id, null, $type !== 'recovery', true); + $task = ProjectTask::userTask($task_id, null, $type !== 'recovery', ProjectPermission::TASK_REMOVE); if ($type == 'recovery') { $task->restoreTask(); return Base::retSuccess('操作成功', ['id' => $task->id]); @@ -2080,7 +2086,7 @@ class ProjectController extends AbstractController return Base::retError('记录不存在'); } // - $task = ProjectTask::userTask($projectLog->task_id, true, true, true); + $task = ProjectTask::userTask($projectLog->task_id, true, true, ProjectPermission::TASK_UPDATE); // $record = $projectLog->record; if ($record['flow'] && is_array($record['flow'])) { @@ -2219,21 +2225,21 @@ class ProjectController extends AbstractController $task_id = intval(Request::input('task_id')); $project_id = intval(Request::input('project_id')); $column_id = intval(Request::input('column_id')); - // - $task = ProjectTask::userTask($task_id, true, true, 2); - // + // + $task = ProjectTask::userTask($task_id, true, true, ProjectPermission::TASK_MOVE); + // if( $task->project_id == $project_id && $task->column_id == $column_id){ return Base::retSuccess('移动成功', ['id' => $task_id]); } - // + // $project = Project::userProject($project_id); $column = ProjectColumn::whereProjectId($project->id)->whereId($column_id)->first(); if (empty($column)) { return Base::retError('列表不存在'); } - // + // $task->moveTask($project_id,$column_id); - // + // return Base::retSuccess('移动成功', ['id' => $task_id]); } @@ -2411,4 +2417,64 @@ class ProjectController extends AbstractController 'top_at' => $projectUser->top_at?->toDateTimeString(), ]); } + + /** + * @api {get} api/project/permission 43. 获取项目权限设置 + * + * @apiDescription 需要token身份 + * @apiVersion 1.0.0 + * @apiGroup project + * @apiName permission + * + * @apiParam {Number} project_id 项目ID + * + * @apiSuccess {Number} ret 返回状态码(1正确、0错误) + * @apiSuccess {String} msg 返回信息(错误描述) + * @apiSuccess {Object} data 返回数据 + */ + public function permission() + { + $user = User::auth(); + $projectId = intval(Request::input('project_id'), 0); + $projectUser = ProjectUser::whereUserid($user->userid)->whereProjectId($projectId)->first(); + if (!$projectUser) { + return Base::retError("项目不存在"); + } + $projectPermission = ProjectPermission::initPermissions($projectId); + return Base::retSuccess("success", $projectPermission); + } + + /** + * @api {get} api/project/permission/update 44. 项目权限设置 + * + * @apiDescription 需要token身份 + * @apiVersion 1.0.0 + * @apiGroup project + * @apiName permission__update + * + * @apiParam {Number} project_id 项目ID + * @apiParam {Array} task_add 添加任务权限 + * @apiParam {Array} task_update 修改任务权限 + * @apiParam {Array} task_remove 删除任务权限 + * @apiParam {Array} task_update_complete 标记完成权限 + * @apiParam {Array} task_archived 归档任务权限 + * @apiParam {Array} task_move 移动任务权限 + * @apiParam {Number} panel_show_task_complete 是否显示已完成任务 1显示 0不显示 + * + * @apiSuccess {Number} ret 返回状态码(1正确、0错误) + * @apiSuccess {String} msg 返回信息(错误描述) + * @apiSuccess {Object} data 返回数据 + */ + public function permission__update() + { + $user = User::auth(); + $projectId = intval(Request::input('project_id'), 0); + $projectUser = ProjectUser::whereUserid($user->userid)->whereProjectId($projectId)->first(); + if (!$projectUser) { + return Base::retError("项目不存在"); + } + $permissions = Request::only([ProjectPermission::TASK_ADD, ProjectPermission::TASK_UPDATE, ProjectPermission::TASK_REMOVE, ProjectPermission::TASK_UPDATE_COMPLETE, ProjectPermission::TASK_ARCHIVED, ProjectPermission::TASK_MOVE, ProjectPermission::PANEL_SHOW_TASK_COMPLETE]); + $projectPermission = ProjectPermission::updatePermissions($projectId, Base::newArrayRecursive('intval', $permissions)); + return Base::retSuccess("success", $projectPermission); + } } diff --git a/app/Models/Project.php b/app/Models/Project.php index 7eb5c1b9a..36956af85 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -24,6 +24,7 @@ use Request; * @property int|null $dialog_id 聊天会话ID * @property string|null $archived_at 归档时间 * @property int|null $archived_userid 归档会员 + * @property int|null $is_fixed 是否固定 * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $deleted_at @@ -47,6 +48,7 @@ use Request; * @method static \Illuminate\Database\Eloquent\Builder|Project whereDesc($value) * @method static \Illuminate\Database\Eloquent\Builder|Project whereDialogId($value) * @method static \Illuminate\Database\Eloquent\Builder|Project whereId($value) + * @method static \Illuminate\Database\Eloquent\Builder|Project whereIsFixed($value) * @method static \Illuminate\Database\Eloquent\Builder|Project whereName($value) * @method static \Illuminate\Database\Eloquent\Builder|Project wherePersonal($value) * @method static \Illuminate\Database\Eloquent\Builder|Project whereUpdatedAt($value) @@ -170,6 +172,8 @@ class Project extends AbstractModel $array['task_my_complete'] = $builder->whereNotNull('project_tasks.complete_at')->count(); $array['task_my_percent'] = $array['task_my_num'] ? intval($array['task_my_complete'] / $array['task_my_num'] * 100) : 0; // + $array['panel_show_task_complete'] = ProjectPermission::getPermission($this->id, ProjectPermission::PANEL_SHOW_TASK_COMPLETE); + // return $array; } diff --git a/app/Models/ProjectPermission.php b/app/Models/ProjectPermission.php new file mode 100644 index 000000000..2619fd5e4 --- /dev/null +++ b/app/Models/ProjectPermission.php @@ -0,0 +1,116 @@ +permissions; + if ($key){ + if (!isset($currentPermissions[$key])) { + throw new ApiException('项目权限设置不存在'); + } + return $currentPermissions[$key]; + } + return $projectPermission; + } + + /** + * 初始化项目权限 + * + * @param int $projectId + * @return ProjectPermission + */ + public static function initPermissions($projectId) + { + $permissions = [ + self::TASK_ADD => [1,3], + self::TASK_UPDATE => [1,2], + self::TASK_REMOVE => [1,2], + self::TASK_UPDATE_COMPLETE => [1,2], + self::TASK_ARCHIVED => [1,2], + self::TASK_MOVE => [1,2], + self::PANEL_SHOW_TASK_COMPLETE => 1, + ]; + return self::firstOrCreate( + ['project_id' => $projectId], + ['permissions' => Base::array2json($permissions)] + ); + } + + /** + * 更新项目权限 + * + * @param int $projectId + * @param array $permissions + * @return ProjectPermission + */ + public static function updatePermissions($projectId, $newPermissions) + { + $projectPermission = self::initPermissions($projectId); + $currentPermissions = $projectPermission->permissions; + $mergedPermissions = empty($newPermissions) ? $currentPermissions : array_merge($currentPermissions, $newPermissions); + + $projectPermission->permissions = Base::array2json($mergedPermissions); + $projectPermission->save(); + + return $projectPermission; + } +} diff --git a/app/Models/ProjectTask.php b/app/Models/ProjectTask.php index 5c565bd5f..c4201e641 100644 --- a/app/Models/ProjectTask.php +++ b/app/Models/ProjectTask.php @@ -32,7 +32,8 @@ use Request; * @property int|null $archived_follow 跟随项目归档(项目取消归档时任务也取消归档) * @property string|null $complete_at 完成时间 * @property int|null $userid 创建人 - * @property int|null $is_all_visible 是否所有人可见 + * @property int|null $visibility 任务可见性:1-项目人员 2-任务人员 3-指定成员 + * @property int|null $is_default 是否默认任务 * @property int|null $p_level 优先级 * @property string|null $p_name 优先级名称 * @property string|null $p_color 优先级颜色 @@ -81,7 +82,7 @@ use Request; * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereFlowItemId($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereFlowItemName($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereId($value) - * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereIsAllVisible($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereIsDefault($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereLoop($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereLoopAt($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereName($value) @@ -94,6 +95,7 @@ use Request; * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereStartAt($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereUpdatedAt($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereUserid($value) + * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereVisibility($value) * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask withTrashed() * @method static \Illuminate\Database\Eloquent\Builder|ProjectTask withoutTrashed() * @mixin \Eloquent @@ -1667,8 +1669,8 @@ class ProjectTask extends AbstractModel /** * 移动任务 - * @param int $project_id - * @param int $column_id + * @param int $project_id + * @param int $column_id * @return bool */ public function moveTask(int $projectId, int $columnId) @@ -1694,11 +1696,11 @@ class ProjectTask extends AbstractModel $taskUser->project_id = $projectId; $taskUser->save(); } - // + // $this->project_id = $projectId; $this->column_id = $columnId; $this->save(); - // + // $this->addLog("移动{任务}"); }); $this->pushMsg('update'); @@ -1728,14 +1730,11 @@ class ProjectTask extends AbstractModel * @param int $task_id * @param bool $archived true:仅限未归档, false:仅限已归档, null:不限制 * @param bool $trashed true:仅限未删除, false:仅限已删除, null:不限制 - * @param int|bool $permission - * - 0|false 限制:项目成员、任务成员、任务群聊成员(任务成员 = 任务创建人+任务协助人+任务负责人) - * - 1|true 限制:项目负责人、任务成员 - * - 2 已有负责人才限制true (子任务时如果是主任务负责人也可以) + * @param string $action 动作名称 * @param array $with * @return self */ - public static function userTask($task_id, $archived = true, $trashed = true, $permission = false, $with = []) + public static function userTask($task_id, $archived = true, $trashed = true, $action = '', $with = []) { $builder = self::with($with)->allData()->where("project_tasks.id", intval($task_id)); if ($trashed === false) { @@ -1758,7 +1757,7 @@ class ProjectTask extends AbstractModel try { $project = Project::userProject($task->project_id); } catch (\Throwable $e) { - if ($task->owner !== null || (!$permission && $task->permission(4))) { + if ($task->owner !== null || (empty($action) && $task->permission(4))) { $project = Project::find($task->project_id); if (empty($project)) { throw new ApiException('项目不存在或已被删除', [ 'task_id' => $task_id ], -4002); @@ -1767,14 +1766,52 @@ class ProjectTask extends AbstractModel throw new ApiException($e->getMessage(), [ 'task_id' => $task_id ], -4002); } } - // - if ($permission >= 2) { - $permission = $task->hasOwner() ? 1 : 0; - } - if ($permission && !$project->owner && !$task->permission(3)) { - throw new ApiException('仅限项目负责人、任务负责人、协助人员或任务创建者操作'); + if ($action) { + self::userTaskPermission($action, $project, $task); } // return $task; } + + /** + * 检查用户是否有执行特定动作的权限 + * @param string $action 动作名称 + * @param Project $project 项目实例 + * @param Task $task 任务实例 + * @return bool + */ + public static function userTaskPermission($action, $project, $task = null) + { + $permissions = ProjectPermission::getPermission($project->id, $action); + foreach ($permissions as $permission) { + switch ($permission) { + case 1: + // 项目负责人 + if (!$project->owner) { + throw new ApiException('仅限项目负责人操作', [ 'project_id' => $project->id ]); + } + break; + case 2: + // 任务负责人 + if (!$task->isOwner()) { + throw new ApiException('仅限任务负责人操作', [ 'project_id' => $project->id ]); + } + break; + case 3: + // 项目成员 + $instance = new self(); + if (!($instance->useridInTheProject(User::userid()) === 1)) { + throw new ApiException('仅限项目成员操作', [ 'project_id' => $project->id ]); + } + break; + case 4: + // 任务成员(任务成员 = 任务创建人+任务协助人+任务负责人) + if ($task->isCreater()) { + throw new ApiException('仅限任务成员操作', [ 'project_id' => $project->id ]); + } + break; + } + } + return true; + } } diff --git a/app/Module/Base.php b/app/Module/Base.php index ce6690bb6..3781ae88d 100755 --- a/app/Module/Base.php +++ b/app/Module/Base.php @@ -687,6 +687,22 @@ class Base return $string; } + /** + * 递归处理数组 + * + * @param string $callback 如:'intval'、'trim'、'addslashes'、'stripslashes'、'htmlspecialchars' + * @param array $array + * @return array + */ + public static function newArrayRecursive($callback, $array) + { + $func = function ($item) use (&$func, &$callback) { + return is_array($item) ? array_map($func, $item) : call_user_func($callback, $item); + }; + + return array_map($func, $array); + } + /** * 重MD5加密 * @param $text diff --git a/resources/assets/js/pages/manage/components/ProjectPanel.vue b/resources/assets/js/pages/manage/components/ProjectPanel.vue index 883906802..21ff6bd8f 100644 --- a/resources/assets/js/pages/manage/components/ProjectPanel.vue +++ b/resources/assets/js/pages/manage/components/ProjectPanel.vue @@ -304,7 +304,7 @@ -
+
@@ -347,9 +347,8 @@ - + diff --git a/resources/assets/js/pages/manage/components/ProjectPermission.vue b/resources/assets/js/pages/manage/components/ProjectPermission.vue index fc4beb71d..f00cc581b 100644 --- a/resources/assets/js/pages/manage/components/ProjectPermission.vue +++ b/resources/assets/js/pages/manage/components/ProjectPermission.vue @@ -4,61 +4,69 @@ {{$L('权限设置')}}
- +
-
{{$L('任务权限')}}:
- - + {{ $L('项目负责人') }} + {{ $L('项目成员') }} - - - - + + {{ $L('项目负责人') }} + {{ $L('任务负责人') }} + {{ $L('项目成员') }} - - - - + + {{ $L('项目负责人') }} + {{ $L('任务负责人') }} + {{ $L('项目成员') }} - - - - + + {{ $L('项目负责人') }} + {{ $L('任务负责人') }} + {{ $L('项目成员') }} - - - - + + {{ $L('项目负责人') }} + {{ $L('任务负责人') }} + {{ $L('项目成员') }} + + + + + {{ $L('项目负责人') }} + {{ $L('任务负责人') }} + {{ $L('项目成员') }}
{{$L('面板显示')}}:
- - - + + {{ $L('默认显示') }} + {{ $L('默认不显示') }}
{{ $L('项目面板默认显示已完成的任务') }}
- +
-
@@ -76,11 +84,12 @@ export default { return { formData: { task_add: [1,3], - task_edit: [1], - task_mark_complete: [1], - task_archiving: [1], - task_delete: [1], - panel_display: 0 + task_update: [1,2], + task_update_complete: [1,2], + task_archived: [1,2], + task_remove: [1,2], + task_move: [1,2], + panel_show_task_complete: 1 } } }, @@ -105,17 +114,12 @@ export default { getData() { this.loadIng++; this.$store.dispatch("call", { - url: 'project/flow/list', + url: 'project/permission', data: { project_id: this.projectId, }, }).then(({data}) => { - // this.list = data.map(item => { - // item.project_flow_bak = JSON.stringify(item.project_flow_item) - // return item; - // }); - // this.openIndex = this.list.length === 1 ? ("index_" + this.list[0].id) : "" - // this.$nextTick(this.syncScroller); + this.formData = data.permissions; }).catch(({msg}) => { $A.modalError(msg); }).finally(_ => { @@ -123,6 +127,28 @@ export default { }); }, + updateData() { + this.loadIng++; + this.$store.dispatch("call", { + url: 'project/permission/update', + method: 'post', + data: { + project_id: this.projectId, + ...this.formData + }, + }).then(({data}) => { + this.formData = data.permissions; + this.$Message.success(this.$L('修改成功')); + }).catch(({msg}) => { + $A.modalError(msg); + }).finally(_ => { + this.loadIng--; + }); + }, + + onClose() { + this.$emit('close') + }, } }