From b0742021b671ef8203077ea3eb1176164f372efc Mon Sep 17 00:00:00 2001 From: ganzizi Date: Fri, 24 Nov 2023 18:25:28 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E4=BB=BB=E5=8A=A1=E5=88=9B=E5=BB=BA=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20-=2090%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Api/ProjectController.php | 100 ++++++++++++--- app/Models/Project.php | 4 + app/Models/ProjectPermission.php | 116 ++++++++++++++++++ app/Models/ProjectTask.php | 73 ++++++++--- app/Module/Base.php | 16 +++ .../pages/manage/components/ProjectPanel.vue | 5 +- .../manage/components/ProjectPermission.vue | 100 +++++++++------ 7 files changed, 339 insertions(+), 75 deletions(-) create mode 100644 app/Models/ProjectPermission.php 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') + }, } } From 3508d7a472d1ed0b31cad3261a4d6655febe7290 Mon Sep 17 00:00:00 2001 From: weifashi <605403358@qq.com> Date: Tue, 28 Nov 2023 15:40:03 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E9=A1=B9=E7=9B=AE=E6=9D=83=E9=99=90?= =?UTF-8?q?=20-=20100%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Api/ProjectController.php | 72 ++++++++--- app/Models/Project.php | 2 - app/Models/ProjectPermission.php | 116 +++++++++++++++--- app/Models/ProjectTask.php | 56 +-------- .../pages/manage/components/ProjectPanel.vue | 2 +- .../manage/components/ProjectPermission.vue | 93 ++++++++------ .../pages/components/project-permission.scss | 27 +++- 7 files changed, 244 insertions(+), 124 deletions(-) diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index 93d44b0dd..bdd150b0b 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -576,6 +576,8 @@ class ProjectController extends AbstractController $project = Project::userProject($project_id); // if ($only_column) { + // + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_LIST_SORT); // 排序列表 $index = 0; foreach ($sort as $item) { @@ -761,6 +763,8 @@ class ProjectController extends AbstractController // 项目 $project = Project::userProject($project_id); // + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_LIST_ADD); + // if (empty($name)) { return Base::retError('列表名称不能为空'); } @@ -810,7 +814,9 @@ class ProjectController extends AbstractController return Base::retError('列表不存在'); } // 项目 - Project::userProject($column->project_id); + $project = Project::userProject($column->project_id); + // + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_LIST_UPDATE); // if (Arr::exists($data, 'name') && $column->name != $data['name']) { $column->addLog("修改列表名称:{$column->name} => {$data['name']}"); @@ -850,7 +856,9 @@ class ProjectController extends AbstractController return Base::retError('列表不存在'); } // 项目 - Project::userProject($column->project_id, true, true); + $project = Project::userProject($column->project_id); + // + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_LIST_REMOVE); // $column->deleteColumn(); return Base::retSuccess('删除成功', ['id' => $column->id]); @@ -1005,10 +1013,6 @@ 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') { @@ -1512,7 +1516,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, '', ['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) { @@ -1608,7 +1612,9 @@ class ProjectController extends AbstractController return Base::retError('文件不存在或已被删除'); } // - $task = ProjectTask::userTask($file->task_id, true, true, ProjectPermission::TASK_REMOVE); + $task = ProjectTask::userTask($file->task_id); + // + ProjectPermission::userTaskPermission(Project::userProject($task->project_id), ProjectPermission::TASK_UPDATE, $task); // $task->pushMsg('filedelete', $file); $file->delete(); @@ -1737,7 +1743,8 @@ class ProjectController extends AbstractController $column_id = $data['column_id']; // 项目 $project = Project::userProject($project_id); - ProjectTask::userTaskPermission(ProjectPermission::TASK_ADD, $project); + // + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_ADD); // 列表 $column = null; $newColumn = null; @@ -1814,11 +1821,13 @@ class ProjectController extends AbstractController $task_id = intval(Request::input('task_id')); $name = Request::input('name'); // - $task = ProjectTask::userTask($task_id, true, true, ProjectPermission::TASK_ADD); + $task = ProjectTask::userTask($task_id); if ($task->complete_at) { return Base::retError('主任务已完成无法添加子任务'); } // + ProjectPermission::userTaskPermission(Project::userProject($task->project_id), ProjectPermission::TASK_ADD); + // $task = ProjectTask::addTask([ 'name' => $name, 'parent_id' => $task->id, @@ -1873,11 +1882,18 @@ class ProjectController extends AbstractController $param = Request::input(); $task_id = intval($param['task_id']); // - $task = ProjectTask::userTask($task_id, true, true, ProjectPermission::TASK_UPDATE); + $task = ProjectTask::userTask($task_id); + // + $project = Project::userProject($task->project_id); + if (Arr::exists($param, 'flow_item_id')) { + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_STATUS, $task); + }else{ + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_UPDATE, $task); + } + // $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(); // 协助人 - // 更新任务 $updateMarking = []; $task->updateTask($param, $updateMarking); @@ -2009,12 +2025,15 @@ class ProjectController extends AbstractController $task_id = intval(Request::input('task_id')); $type = Request::input('type', 'add'); // - $task = ProjectTask::userTask($task_id, $type == 'add', true, ProjectPermission::TASK_ARCHIVED); + $task = ProjectTask::userTask($task_id, $type == 'add'); // if ($task->parent_id > 0) { return Base::retError('子任务不支持此功能'); } // + $project = Project::userProject($task->project_id); + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_ARCHIVED, $task); + // if ($type == 'recovery') { $task->archivedTask(null); } elseif ($type == 'add') { @@ -2051,7 +2070,11 @@ class ProjectController extends AbstractController $task_id = intval(Request::input('task_id')); $type = Request::input('type', 'delete'); // - $task = ProjectTask::userTask($task_id, null, $type !== 'recovery', ProjectPermission::TASK_REMOVE); + $task = ProjectTask::userTask($task_id, null, $type !== 'recovery'); + // + $project = Project::userProject($task->project_id); + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_REMOVE, $task); + // if ($type == 'recovery') { $task->restoreTask(); return Base::retSuccess('操作成功', ['id' => $task->id]); @@ -2086,7 +2109,7 @@ class ProjectController extends AbstractController return Base::retError('记录不存在'); } // - $task = ProjectTask::userTask($projectLog->task_id, true, true, ProjectPermission::TASK_UPDATE); + $task = ProjectTask::userTask($projectLog->task_id); // $record = $projectLog->record; if ($record['flow'] && is_array($record['flow'])) { @@ -2226,7 +2249,10 @@ class ProjectController extends AbstractController $project_id = intval(Request::input('project_id')); $column_id = intval(Request::input('column_id')); // - $task = ProjectTask::userTask($task_id, true, true, ProjectPermission::TASK_MOVE); + $task = ProjectTask::userTask($task_id); + // + $project = Project::userProject($task->project_id); + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_MOVE, $task); // if( $task->project_id == $project_id && $task->column_id == $column_id){ return Base::retSuccess('移动成功', ['id' => $task_id]); @@ -2459,7 +2485,6 @@ class ProjectController extends AbstractController * @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 返回信息(错误描述) @@ -2473,7 +2498,18 @@ class ProjectController extends AbstractController 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]); + $permissions = Request::only([ + ProjectPermission::TASK_LIST_ADD, + ProjectPermission::TASK_LIST_UPDATE, + ProjectPermission::TASK_LIST_REMOVE, + ProjectPermission::TASK_LIST_SORT, + ProjectPermission::TASK_ADD, + ProjectPermission::TASK_UPDATE, + ProjectPermission::TASK_REMOVE, + ProjectPermission::TASK_STATUS, + ProjectPermission::TASK_ARCHIVED, + ProjectPermission::TASK_MOVE, + ]); $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 36956af85..3a6c9fc66 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -172,8 +172,6 @@ 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 index 2619fd5e4..fff4e117f 100644 --- a/app/Models/ProjectPermission.php +++ b/app/Models/ProjectPermission.php @@ -27,13 +27,32 @@ use App\Module\Base; class ProjectPermission extends AbstractModel { - const TASK_ADD = 'task_add'; // 任务添加 - const TASK_UPDATE = 'task_update'; // 任务更新 - const TASK_REMOVE = 'task_remove'; // 任务删除 - const TASK_UPDATE_COMPLETE = 'task_update_complete'; // 任务完成 - const TASK_ARCHIVED = 'task_archived'; // 任务归档 - const TASK_MOVE = 'task_move'; // 任务移动 - const PANEL_SHOW_TASK_COMPLETE = 'panel_show_task_complete'; // 显示已完成任务 + const TASK_LIST_ADD = 'task_list_add'; // 添加列 + const TASK_LIST_UPDATE = 'task_list_update'; // 修改列 + const TASK_LIST_REMOVE = 'task_list_remove'; // 删除列 + const TASK_LIST_SORT = 'task_list_sort'; // 列表排序 + const TASK_ADD = 'task_add'; // 任务添加 + const TASK_UPDATE = 'task_update'; // 任务更新 + const TASK_STATUS = 'task_status'; // 任务状态 + const TASK_REMOVE = 'task_remove'; // 任务删除 + const TASK_ARCHIVED = 'task_archived'; // 任务归档 + const TASK_MOVE = 'task_move'; // 任务移动 + + // 权限列表 + const PERMISSIONS = [ + 'project_leader' => 1, // 项目负责人 + 'project_member' => 2, // 项目成员 + 'task_leader' => 3, // 任务负责人 + 'task_assist' => 4, // 任务协助人 + ]; + + // 权限描述 + const PERMISSIONS_DESC = [ + 1 => "项目负责人", + 2 => "项目成员", + 3 => "任务负责人", + 4 => "任务协助人", + ]; /** * The attributes that are mass assignable. @@ -63,7 +82,7 @@ class ProjectPermission extends AbstractModel { $projectPermission = self::initPermissions($projectId); $currentPermissions = $projectPermission->permissions; - if ($key){ + if ($key) { if (!isset($currentPermissions[$key])) { throw new ApiException('项目权限设置不存在'); } @@ -81,13 +100,16 @@ class ProjectPermission extends AbstractModel 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, + self::TASK_LIST_ADD => $projectTaskList = [self::PERMISSIONS['project_leader'], self::PERMISSIONS['project_member']], + self::TASK_LIST_UPDATE => $projectTaskList, + self::TASK_LIST_REMOVE => [self::PERMISSIONS['project_leader']], + self::TASK_LIST_SORT => $projectTaskList, + self::TASK_ADD => $projectTaskList, + self::TASK_UPDATE => $taskUpdate = [self::PERMISSIONS['project_leader'], self::PERMISSIONS['task_leader'], self::PERMISSIONS['task_assist']], + self::TASK_STATUS => [self::PERMISSIONS['project_leader'], self::PERMISSIONS['task_leader']], + self::TASK_REMOVE => $taskUpdate, + self::TASK_ARCHIVED => $taskUpdate, + self::TASK_MOVE => $taskUpdate ]; return self::firstOrCreate( ['project_id' => $projectId], @@ -113,4 +135,68 @@ class ProjectPermission extends AbstractModel return $projectPermission; } + + /** + * 检查用户是否有执行特定动作的权限 + * @param string $action 动作名称 + * @param Project $project 项目实例 + * @param ProjectTask $task 任务实例 + * @return bool + */ + public static function userTaskPermission(Project $project, $action, ProjectTask $task = null) + { + $userid = User::userid(); + $permissions = self::getPermission($project->id, $action); + switch ($action) { + // 任务添加,任务更新, 任务状态, 任务删除, 任务完成, 任务归档, 任务移动 + case self::TASK_LIST_ADD: + case self::TASK_LIST_UPDATE: + case self::TASK_LIST_REMOVE: + case self::TASK_LIST_SORT: + case self::TASK_ADD: + case self::TASK_UPDATE: + case self::TASK_STATUS: + case self::TASK_REMOVE: + case self::TASK_ARCHIVED: + case self::TASK_MOVE: + $verify = false; + // 项目负责人 + if (in_array(self::PERMISSIONS['project_leader'], $permissions)) { + if ($project->owner) { + $verify = true; + } + } + // 项目成员 + if (!$verify && in_array(self::PERMISSIONS['project_member'], $permissions)) { + $user = ProjectUser::whereProjectId($project->id)->whereUserid(intval($userid))->first(); + if (!empty($user)) { + $verify = true; + } + } + // 任务负责人 + if (!$verify && $task && in_array(self::PERMISSIONS['task_leader'], $permissions)) { + if ($task->isOwner()) { + $verify = true; + } + } + // 任务协助人 + if (!$verify && $task && in_array(self::PERMISSIONS['task_assist'], $permissions)) { + if ($task->isAssister()) { + $verify = true; + } + } + // + if (!$verify) { + $desc = []; + rsort($permissions); + foreach ($permissions as $permission) { + $desc[] = self::PERMISSIONS_DESC[$permission]; + } + $desc = array_reverse($desc); + throw new ApiException(sprintf("仅限%s操作", implode('、', $desc))); + } + break; + } + return true; + } } diff --git a/app/Models/ProjectTask.php b/app/Models/ProjectTask.php index c4201e641..813f73c06 100644 --- a/app/Models/ProjectTask.php +++ b/app/Models/ProjectTask.php @@ -551,15 +551,12 @@ class ProjectTask extends AbstractModel */ public function updateTask($data, &$updateMarking = []) { + // AbstractModel::transaction(function () use ($data, &$updateMarking) { // 主任务 $mainTask = $this->parent_id > 0 ? self::find($this->parent_id) : null; // 工作流 if (Arr::exists($data, 'flow_item_id')) { - $isProjectOwner = $this->useridInTheProject(User::userid()) === 2; - if (!$isProjectOwner && !$this->isOwner()) { - throw new ApiException('仅限项目或任务负责人修改任务状态'); - } if ($this->flow_item_id == $data['flow_item_id']) { throw new ApiException('任务状态未发生改变'); } @@ -580,6 +577,7 @@ class ProjectTask extends AbstractModel throw new ApiException("当前状态[{$currentFlowItem->name}]不可流转到[{$newFlowItem->name}]"); } if ($currentFlowItem->userlimit) { + $isProjectOwner = $this->useridInTheProject(User::userid()) === 2; if (!$isProjectOwner && !in_array(User::userid(), $currentFlowItem->userids)) { throw new ApiException("当前状态[{$currentFlowItem->name}]仅限状态负责人或项目负责人修改"); } @@ -1730,11 +1728,10 @@ class ProjectTask extends AbstractModel * @param int $task_id * @param bool $archived true:仅限未归档, false:仅限已归档, null:不限制 * @param bool $trashed true:仅限未删除, false:仅限已删除, null:不限制 - * @param string $action 动作名称 * @param array $with * @return self */ - public static function userTask($task_id, $archived = true, $trashed = true, $action = '', $with = []) + public static function userTask($task_id, $archived = true, $trashed = true, $with = []) { $builder = self::with($with)->allData()->where("project_tasks.id", intval($task_id)); if ($trashed === false) { @@ -1757,7 +1754,7 @@ class ProjectTask extends AbstractModel try { $project = Project::userProject($task->project_id); } catch (\Throwable $e) { - if ($task->owner !== null || (empty($action) && $task->permission(4))) { + if ($task->owner !== null || $task->permission(4)) { $project = Project::find($task->project_id); if (empty($project)) { throw new ApiException('项目不存在或已被删除', [ 'task_id' => $task_id ], -4002); @@ -1766,52 +1763,7 @@ class ProjectTask extends AbstractModel throw new ApiException($e->getMessage(), [ 'task_id' => $task_id ], -4002); } } - 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/resources/assets/js/pages/manage/components/ProjectPanel.vue b/resources/assets/js/pages/manage/components/ProjectPanel.vue index 21ff6bd8f..b204efe1f 100644 --- a/resources/assets/js/pages/manage/components/ProjectPanel.vue +++ b/resources/assets/js/pages/manage/components/ProjectPanel.vue @@ -304,7 +304,7 @@ -
+
diff --git a/resources/assets/js/pages/manage/components/ProjectPermission.vue b/resources/assets/js/pages/manage/components/ProjectPermission.vue index f00cc581b..bc6c49c5a 100644 --- a/resources/assets/js/pages/manage/components/ProjectPermission.vue +++ b/resources/assets/js/pages/manage/components/ProjectPermission.vue @@ -8,64 +8,86 @@
-
+ + +
{{$L('任务列权限')}}:
+ + + {{ $L('项目负责人') }} + {{ $L('项目成员') }} + + + + + {{ $L('项目负责人') }} + {{ $L('项目成员') }} + + + + + {{ $L('项目负责人') }} + {{ $L('项目成员') }} + + + + + {{ $L('项目负责人') }} + {{ $L('项目成员') }} + +
{{$L('任务权限')}}:
{{ $L('项目负责人') }} - {{ $L('项目成员') }} + {{ $L('项目成员') }} {{ $L('项目负责人') }} - {{ $L('任务负责人') }} - {{ $L('项目成员') }} + {{ $L('任务负责人') }} + {{ $L('任务协助人') }} + {{ $L('项目成员') }} - - + + {{ $L('项目负责人') }} - {{ $L('任务负责人') }} - {{ $L('项目成员') }} + {{ $L('任务负责人') }} + {{ $L('任务协助人') }} + {{ $L('项目成员') }} {{ $L('项目负责人') }} - {{ $L('任务负责人') }} - {{ $L('项目成员') }} + {{ $L('任务负责人') }} + {{ $L('任务协助人') }} + {{ $L('项目成员') }} {{ $L('项目负责人') }} - {{ $L('任务负责人') }} - {{ $L('项目成员') }} + {{ $L('任务负责人') }} + {{ $L('任务协助人') }} + {{ $L('项目成员') }} - + {{ $L('项目负责人') }} - {{ $L('任务负责人') }} - {{ $L('项目成员') }} + {{ $L('任务负责人') }} + {{ $L('任务协助人') }} + {{ $L('项目成员') }} - -
{{$L('面板显示')}}:
- - - {{ $L('默认显示') }} - {{ $L('默认不显示') }} - -
{{ $L('项目面板默认显示已完成的任务') }}
-
- +
+ @@ -82,14 +104,15 @@ export default { }, data() { return { + loadIng: 0, formData: { - task_add: [1,3], - 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 + project_task_list: [], + task_add: [], + task_update: [], + task_status: [], + task_archived: [], + task_remove: [], + task_move: [] } } }, diff --git a/resources/assets/sass/pages/components/project-permission.scss b/resources/assets/sass/pages/components/project-permission.scss index 5c1c4fbf4..486ebc4a9 100644 --- a/resources/assets/sass/pages/components/project-permission.scss +++ b/resources/assets/sass/pages/components/project-permission.scss @@ -11,7 +11,6 @@ font-size: 20px; font-weight: 500; line-height: 1; - // style="font-weight: bold;line-height: 40px;" padding: 20px 20px 24px; display: flex; align-items: center; @@ -33,6 +32,7 @@ overflow: auto; margin-bottom: 20px; height: 100%; + position: relative; .project-permission-title{ font-weight: 500; @@ -49,4 +49,29 @@ } } + .project-permission-footer{ + flex-shrink: 0; + position: static; + padding: 16px 26px; + border-top: 1px solid #F4F4F5; + display: flex; + align-items: center; + gap: 16px; + button { + min-width: 120px; + height: 38px; + line-height: 36px; + } + } +} + + +body.window-portrait { + .project-permission { + .project-permission-footer{ + button { + width: 50%; + } + } + } }