diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php index 07131a364..f994bc407 100755 --- a/app/Http/Controllers/Api/ProjectController.php +++ b/app/Http/Controllers/Api/ProjectController.php @@ -1987,6 +1987,44 @@ class ProjectController extends AbstractController ]); } + /** + * @api {post} api/project/task/related/delete 删除任务关联 + * + * @apiDescription 需要token身份(限:项目、任务负责人) + * @apiVersion 1.0.0 + * @apiGroup project + * @apiName task__related__delete + * + * @apiParam {Number} task_id 任务ID + * @apiParam {Number} related_task_id 关联任务ID + * + * @apiSuccess {Number} ret 返回状态码(1正确、0错误) + * @apiSuccess {String} msg 返回信息(错误描述) + * @apiSuccess {Object} data 返回数据 + */ + public function task__related__delete() + { + User::auth(); + // + $task_id = intval(Request::input('task_id')); + $related_task_id = intval(Request::input('related_task_id')); + if ($task_id <= 0 || $related_task_id <= 0) { + return Base::retError('参数错误'); + } + // + $task = ProjectTask::userTask($task_id); + // + $project = Project::userProject($task->project_id); + ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_UPDATE, $task); + // + $success = ProjectTaskRelation::deleteRelation($task_id, $related_task_id); + if (!$success) { + return Base::retError('关联不存在'); + } + // + return Base::retSuccess('操作成功'); + } + /** * @api {get} api/project/task/content 获取任务详细描述 * diff --git a/app/Models/ProjectTaskRelation.php b/app/Models/ProjectTaskRelation.php index 4ce8de48a..74f301b33 100644 --- a/app/Models/ProjectTaskRelation.php +++ b/app/Models/ProjectTaskRelation.php @@ -143,6 +143,41 @@ class ProjectTaskRelation extends AbstractModel return true; } + /** + * 删除双向任务关联 + * + * @param int $taskId 任务ID + * @param int $relatedTaskId 关联任务ID + * @return bool 是否删除成功 + */ + public static function deleteRelation(int $taskId, int $relatedTaskId): bool + { + // 删除正向关联 + $deleted1 = static::whereTaskId($taskId) + ->whereRelatedTaskId($relatedTaskId) + ->delete(); + + // 删除反向关联 + $deleted2 = static::whereTaskId($relatedTaskId) + ->whereRelatedTaskId($taskId) + ->delete(); + + if ($deleted1 || $deleted2) { + // 推送关联更新 + $sourceTask = ProjectTask::with('project')->find($taskId); + $targetTask = ProjectTask::with('project')->find($relatedTaskId); + if ($sourceTask?->project) { + $sourceTask->pushMsg('relation', null, null, false); + } + if ($targetTask?->project) { + $targetTask->pushMsg('relation', null, null, false); + } + return true; + } + + return false; + } + public static function recordMentionsFromMessage(WebSocketDialogMsg $msg): void { if ($msg->type !== 'text') { diff --git a/resources/assets/js/pages/manage/components/TaskDetail.vue b/resources/assets/js/pages/manage/components/TaskDetail.vue index 51110bab1..aa2684da7 100755 --- a/resources/assets/js/pages/manage/components/TaskDetail.vue +++ b/resources/assets/js/pages/manage/components/TaskDetail.vue @@ -376,6 +376,10 @@ class="related-status archived"> {{$L('已归档')}} + @@ -1597,6 +1601,26 @@ export default { this.$store.dispatch('openTask', item.related_task_id); }, + removeRelatedTask(item) { + if (!item || !item.related_task_id) { + return; + } + $A.modalConfirm({ + title: '温馨提示', + content: '确定要解除与任务 #' + item.related_task_id + ' 的关联吗?', + onOk: () => { + this.$store.dispatch('deleteTaskRelated', { + taskId: this.taskId, + relatedTaskId: item.related_task_id, + }).then(() => { + this.loadRelatedTasks(); + }).catch(({msg}) => { + $A.modalError(msg); + }); + }, + }); + }, + onTaskRelationUpdate(taskId) { if (!taskId || taskId !== this.taskId) { return; diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index 5f6e79f6a..390429ef4 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -2635,6 +2635,19 @@ export default { }); }, + deleteTaskRelated({commit, dispatch}, {taskId, relatedTaskId}) { + return new Promise((resolve, reject) => { + dispatch("call", { + url: 'project/task/related/delete', + data: {task_id: taskId, related_task_id: relatedTaskId}, + }).then(({msg}) => { + commit('task/related/clear', taskId); + commit('task/related/clear', relatedTaskId); + resolve(msg); + }).catch(reject); + }); + }, + /** * 添加子任务 * @param dispatch diff --git a/resources/assets/sass/pages/components/task-detail.scss b/resources/assets/sass/pages/components/task-detail.scss index 22ab338d8..65f7bd663 100644 --- a/resources/assets/sass/pages/components/task-detail.scss +++ b/resources/assets/sass/pages/components/task-detail.scss @@ -674,6 +674,24 @@ } } + .related-remove { + flex-shrink: 0; + font-size: 14px; + color: #c5c8ce; + cursor: pointer; + opacity: 0; + transition: opacity 0.2s ease, color 0.2s ease; + margin-left: 4px; + + &:hover { + color: #ed4014; + } + } + + &:hover .related-remove { + opacity: 1; + } + .ivu-tag { margin-left: 8px; }