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 @@