feat(子任务可见性):优化子任务可见性

This commit is contained in:
Meng 2023-06-28 20:45:52 +08:00
parent ee3c3a0497
commit 5d57666cd4
4 changed files with 183 additions and 101 deletions

View File

@ -896,17 +896,7 @@ class ProjectController extends AbstractController
public function task__lists() public function task__lists()
{ {
$user = User::auth(); $user = User::auth();
$userid = $user->userid;
// 任务可见性
$project_ids = Project::whereUserid($user->userid)->pluck('id')->toArray(); // 负责人项目ids
$main_task_ids = ProjectTask::whereIn('project_id', $project_ids)->pluck('id')->toArray(); // 负责人项目任务ids
$other_task_ids = ProjectTaskUser::whereUserid($user->userid)->whereColumn('task_id', '=', 'task_pid')->whereNotIn('project_id', $project_ids)->pluck('task_id')->toArray(); // 非负责人项目任务ids
$all_visible_task_ids = ProjectTask::whereIsAllVisible(1)->pluck('id')->toArray(); // 所有人可见项目ids
$one_task_ids = array_merge($main_task_ids, $other_task_ids);
$visibility_task_ids = array_merge($one_task_ids, $all_visible_task_ids);
$builder = ProjectTask::with(['taskUser', 'taskTag']);
$builder->whereIn("project_tasks.id", $visibility_task_ids);
// //
$parent_id = intval(Request::input('parent_id')); $parent_id = intval(Request::input('parent_id'));
$project_id = intval(Request::input('project_id')); $project_id = intval(Request::input('project_id'));
@ -919,6 +909,12 @@ class ProjectController extends AbstractController
$sorts = Request::input('sorts'); $sorts = Request::input('sorts');
$keys = is_array($keys) ? $keys : []; $keys = is_array($keys) ? $keys : [];
$sorts = is_array($sorts) ? $sorts : []; $sorts = is_array($sorts) ? $sorts : [];
// 任务可见性
$visibility_task_ids = ProjectTask::getVisibleUserids($userid, $project_id);
$builder = ProjectTask::with(['taskUser', 'taskTag']);
$builder->whereIn("project_tasks.id", $visibility_task_ids);
// //
if ($keys['name']) { if ($keys['name']) {
if (Base::isNumber($keys['name'])) { if (Base::isNumber($keys['name'])) {
@ -1361,8 +1357,9 @@ class ProjectController extends AbstractController
// 项目可见性 // 项目可见性
$project_userid = Project::whereId($task->project_id)->value('userid'); // 项目负责人 $project_userid = Project::whereId($task->project_id)->value('userid'); // 项目负责人
if ($task->is_all_visible != 1 && $user->userid != $project_userid) { if ($task->is_all_visible != 1 && $user->userid != $project_userid) {
$visibleUserids = ProjectTaskUser::whereTaskId($task_id)->pluck('userid')->toArray(); $visibleUserids = ProjectTaskUser::whereTaskId($task_id)->pluck('userid')->toArray(); // 是否任务负责人、协助人、可见人
if (!in_array($user->userid, $visibleUserids)) { $subVisibleUserids = ProjectTaskUser::whereTaskPid($task_id)->pluck('userid')->toArray(); // 是否子任务负责人、协助人
if (!in_array($user->userid, $visibleUserids) && !in_array($user->userid, $subVisibleUserids)) {
return Base::retError('无任务权限'); return Base::retError('无任务权限');
} }
} }
@ -1670,10 +1667,16 @@ class ProjectController extends AbstractController
'project_id' => $task->project_id, 'project_id' => $task->project_id,
'column_id' => $task->column_id, 'column_id' => $task->column_id,
'times' => [$task->start_at, $task->end_at], 'times' => [$task->start_at, $task->end_at],
'owner' => [User::userid()] 'owner' => [User::userid()],
'is_all_visible' => 0,
]); ]);
$data = ProjectTask::oneTask($task->id); $data = ProjectTask::oneTask($task->id);
$task->pushMsg('add', $data); $projectUserid = Project::whereId($data->project_id)->value('userid');
$pushUserIds = ProjectTaskUser::whereTaskId($task->id)->pluck('userid')->toArray();
$pushUserIds[] = $projectUserid;
foreach ($pushUserIds as $userId) {
$task->pushMsg('add', $data, $userId);
}
return Base::retSuccess('添加成功', $data); return Base::retSuccess('添加成功', $data);
} }
@ -1727,7 +1730,7 @@ class ProjectController extends AbstractController
$data['visibility_appointor'] = $data['is_all_visible'] == 1 ? [0] : ProjectTaskUser::whereTaskId($task->id)->whereOwner(2)->pluck('userid'); $data['visibility_appointor'] = $data['is_all_visible'] == 1 ? [0] : ProjectTaskUser::whereTaskId($task->id)->whereOwner(2)->pluck('userid');
$task->pushMsg('update', $data); $task->pushMsg('update', $data);
// 可见性推送 // 可见性推送
if (Arr::exists($param, 'visibility_appointor')) { if (Arr::exists($param, 'is_all_visible')) {
if ($data['is_all_visible'] == 1) { if ($data['is_all_visible'] == 1) {
$task->pushMsgVisibleAdd($data); $task->pushMsgVisibleAdd($data);
} }
@ -1738,9 +1741,16 @@ class ProjectController extends AbstractController
$task->pushMsgVisibleRemove(); $task->pushMsgVisibleRemove();
} }
} }
} elseif (Arr::exists($param, 'visibility_appointor')) {
if ($param['visibility_appointor']) {
$task->pushMsgVisibleUpdate($data);
} else {
$task->pushMsgVisibleRemove();
}
} }
if (Arr::exists($param, 'owner') && $data['is_all_visible'] == 0) { if (Arr::exists($param, 'owner') && $data['is_all_visible'] == 0) {
$diff = array_diff($owners, $param['owner']); $subUserids = ProjectTaskUser::whereTaskPid($data['id'])->pluck('userid')->toArray();
$diff = array_diff($owners, $param['owner'], $subUserids);
if ($diff) { if ($diff) {
$task->pushMsgVisibleRemove($diff); $task->pushMsgVisibleRemove($diff);
} }

View File

@ -716,10 +716,11 @@ class ProjectTask extends AbstractModel
$this->syncDialogUser(); $this->syncDialogUser();
} }
// 可见性 // 可见性
if (Arr::exists($data, 'visibility_appointor')) { if (Arr::exists($data, 'visibility_appointor') || Arr::exists($data, 'is_all_visible')) {
if (in_array(0, $data['visibility_appointor'])) { if ($data['is_all_visible'] == 1) {
ProjectTask::whereId($data['task_id'])->update(['is_all_visible' => 1]); ProjectTask::whereId($data['task_id'])->update(['is_all_visible' => 1]);
} else { ProjectTaskUser::whereTaskId($data['task_id'])->whereOwner(2)->delete();
} elseif ( isset($data['visibility_appointor']) || $data['is_all_visible'] == 0) {
ProjectTask::whereId($data['task_id'])->update(['is_all_visible' => 0]); ProjectTask::whereId($data['task_id'])->update(['is_all_visible' => 0]);
// 覆盖 // 覆盖
ProjectTaskUser::whereTaskId($data['task_id'])->whereOwner(2)->delete(); ProjectTaskUser::whereTaskId($data['task_id'])->whereOwner(2)->delete();
@ -1437,8 +1438,6 @@ class ProjectTask extends AbstractModel
]; ];
} }
// 协助人 // 协助人
// $assists = $taskUser->pluck('userid')->toArray();
// $assists = array_intersect($userids, array_diff($assists, $owners));
$assists = $taskUser->where('owner', 0)->pluck('userid')->toArray(); $assists = $taskUser->where('owner', 0)->pluck('userid')->toArray();
$assists = array_intersect($userids, $assists); $assists = array_intersect($userids, $assists);
if ($assists) { if ($assists) {
@ -1456,8 +1455,7 @@ class ProjectTask extends AbstractModel
$userids = array_diff($userids, $owners, $assists); $userids = array_diff($userids, $owners, $assists);
} else { } else {
// 指定可见 // 指定可见
$visible = $taskUser->where('owner', 2)->pluck('userid')->toArray(); $userids = $taskUser->where('owner', 2)->pluck('userid')->toArray();
$userids = $visible;
} }
$data = array_merge($data, [ $data = array_merge($data, [
'owner' => 0, 'owner' => 0,
@ -1492,6 +1490,7 @@ class ProjectTask extends AbstractModel
*/ */
public function pushMsgVisibleAdd($data = null) public function pushMsgVisibleAdd($data = null)
{ {
\Log::info('222222');
if (!$this->project) { if (!$this->project) {
return; return;
} }
@ -1509,7 +1508,8 @@ class ProjectTask extends AbstractModel
// //
$array = []; $array = [];
if ($this->is_all_visible == 0) { if ($this->is_all_visible == 0) {
$userids = ProjectTaskUser::select(['userid', 'owner'])->whereTaskId($this->id)->pluck('userid')->toArray(); $userids = ProjectTaskUser::select(['userid', 'owner'])->whereTaskId($this->id)->orWhere('task_pid' , '=', $this->id)->pluck('userid')->toArray();
\Log::info($userids);
} else { } else {
$userids = ProjectUser::whereProjectId($this->project_id)->pluck('userid')->toArray(); // 项目成员 $userids = ProjectUser::whereProjectId($this->project_id)->pluck('userid')->toArray(); // 项目成员
} }
@ -1521,9 +1521,8 @@ class ProjectTask extends AbstractModel
// //
foreach ($array as $item) { foreach ($array as $item) {
$params = [ $params = [
// 'ignoreFd' => Request::header('fd'),
'ignoreFd' => '0', 'ignoreFd' => '0',
'userid' => array_values($item), 'userid' => $item['userid'],
'msg' => [ 'msg' => [
'type' => 'projectTask', 'type' => 'projectTask',
'action' => 'add', 'action' => 'add',
@ -1569,9 +1568,8 @@ class ProjectTask extends AbstractModel
// //
foreach ($array as $item) { foreach ($array as $item) {
$params = [ $params = [
// 'ignoreFd' => Request::header('fd'),
'ignoreFd' => '0', 'ignoreFd' => '0',
'userid' => array_values($item), 'userid' => $item['userid'],
'msg' => [ 'msg' => [
'type' => 'projectTask', 'type' => 'projectTask',
'action' => 'delete', 'action' => 'delete',
@ -1723,4 +1721,27 @@ class ProjectTask extends AbstractModel
// //
return $task; return $task;
} }
/**
* 获取用户任务可见性
* @param $userid
* @param $project_id
* @return array
*/
public static function getVisibleUserids($userid, $project_id = 0)
{
return (new ProjectTask)->setTable('pt')->from('project_tasks as pt')
->leftJoin('project_task_users as b', 'b.task_id', '=', 'pt.id')
->Join('projects as p', 'p.id', '=', 'pt.project_id')
->when($project_id, function ($q) use ($project_id) {
$q->where('pt.project_id', '=', $project_id); // 负责人项目ids
})
->where(function ($q) use ($userid){
$q->where("pt.is_all_visible", '=', 1);
$q->OrWhere("p.userid", '=', $userid);
$q->OrWhere("b.userid", '=', $userid);
})
->pluck("pt.id")
->toArray();
}
} }

View File

@ -94,23 +94,20 @@
</div> </div>
</FormItem> </FormItem>
<FormItem :label="$L('可见性')"> <FormItem :label="$L('可见性')">
<Checkbox disabled v-model="addData.visibility_principal" :true-value="1" :false-value="0">{{$L('项目负责人')}}</Checkbox> <Checkbox disabled v-model="addData.visibility_principal" :true-value="1" :false-value="0">{{$L('任务负责人')}}</Checkbox>
<Checkbox disabled v-model="addData.visibility_assist" :true-value="1" :false-value="0">{{$L('项目协助人')}}</Checkbox> <Checkbox disabled v-model="addData.visibility_assist" :true-value="1" :false-value="0">{{$L('任务协助人')}}</Checkbox>
<Checkbox v-model="addData.visibility_appoint" :true-value="1" :false-value="0">{{$L('指定人员')}}</Checkbox> <RadioGroup v-model="addData.is_all_visible">
<UserInput <Radio :label=1>{{$L('所有人员')}}</Radio>
v-show="addData.visibility_appoint" <Radio :label=0>{{$L('指定成员')}}</Radio>
</RadioGroup>
<UserSelect
class="item-content user"
v-show="!addData.is_all_visible"
v-model="addData.visibility_appointor" v-model="addData.visibility_appointor"
:placeholder="$L('选择指定人员')" :avatar-size="28"
:project-id="addData.project_id" :title="$L('选择指定人员')"
:transfer="false"> :project-id="addData.project_id"/>
<Option slot="option-prepend" :value="0" :label="$L('所有人')" > <!-- <Button size="small" type="primary" @click="updateVisible">{{$L('提交修改')}}</Button>-->
<div class="user-input-option">
<div class="user-input-avatar"><EAvatar class="avatar" icon="el-icon-s-custom"/></div>
<div class="user-input-nickname">{{ $L('所有人') }}</div>
<div class="user-input-userid">All</div>
</div>
</Option>
</UserInput>
</FormItem> </FormItem>
<div class="subtasks"> <div class="subtasks">
<div v-if="addData.subtasks.length > 0" class="sublist"> <div v-if="addData.subtasks.length > 0" class="sublist">
@ -209,7 +206,8 @@ export default {
visibility_principal: 1, visibility_principal: 1,
visibility_assist: 1, visibility_assist: 1,
visibility_appoint: 1, visibility_appoint: 1,
visibility_appointor: [0], is_all_visible: 1,
visibility_appointor: [],
}, },
cascaderShow: false, cascaderShow: false,

View File

@ -1,6 +1,7 @@
<template> <template>
<!--子任务--> <!--子任务-->
<li v-if="ready && taskDetail.parent_id > 0"> <li style="display: block;margin-bottom: 16px;" v-if="ready && taskDetail.parent_id > 0">
<div style="display: flex; margin-left: 6px;">
<div class="subtask-icon"> <div class="subtask-icon">
<TaskMenu <TaskMenu
:ref="`taskMenu_${taskDetail.id}`" :ref="`taskMenu_${taskDetail.id}`"
@ -9,9 +10,9 @@
:load-status="taskDetail.loading === true" :load-status="taskDetail.loading === true"
@on-update="getLogLists"/> @on-update="getLogLists"/>
</div> </div>
<div v-if="taskDetail.flow_item_name" class="subtask-flow"> <!-- <div v-if="taskDetail.flow_item_name" class="subtask-flow">-->
<span :class="taskDetail.flow_item_status" @click.stop="openMenu($event, taskDetail)">{{taskDetail.flow_item_name}}</span> <!-- <span :class="taskDetail.flow_item_status" @click.stop="openMenu($event, taskDetail)">{{taskDetail.flow_item_name}}</span>-->
</div> <!-- </div>-->
<div class="subtask-name"> <div class="subtask-name">
<Input <Input
v-model="taskDetail.name" v-model="taskDetail.name"
@ -24,6 +25,12 @@
@on-blur="updateBlur('name')" @on-blur="updateBlur('name')"
@on-keydown="onNameKeydown"/> @on-keydown="onNameKeydown"/>
</div> </div>
</div>
<div style="display: flex;justify-content: space-between;">
<div style="display: flex;">
<div style="margin-left: 28px;" class="item-label" slot="label">
<i class="taskfont">&#xe6e8;</i>
</div>
<DatePicker <DatePicker
v-model="timeValue" v-model="timeValue"
:open="timeOpen" :open="timeOpen"
@ -36,11 +43,19 @@
@on-clear="timeClear" @on-clear="timeClear"
@on-ok="timeOk" @on-ok="timeOk"
transfer> transfer>
<div v-if="!taskDetail.complete_at && taskDetail.end_at && taskDetail.end_at != mainEndAt" @click="openTime" :class="['time', taskDetail.today ? 'today' : '', taskDetail.overdue ? 'overdue' : '']"> <!-- <div v-if="!taskDetail.complete_at && taskDetail.end_at && taskDetail.end_at != mainEndAt" @click="openTime" :class="['time', taskDetail.today ? 'today' : '', taskDetail.overdue ? 'overdue' : '']">-->
{{expiresFormat(taskDetail.end_at)}} <!-- {{expiresFormat(taskDetail.end_at)}}-->
<!-- </div>-->
<!-- <Icon v-else class="clock" type="ios-clock-outline" @click="openTime" />-->
<div class="picker-time">
<div @click="openTime" class="time sub-time">{{taskDetail.end_at ? cutTime : '--'}}</div>
<!-- <template v-if="!taskDetail.complete_at && taskDetail.end_at">-->
<!-- <Tag v-if="within24Hours(taskDetail.end_at)" color="blue"><i class="taskfont">&#xe71d;</i>{{expiresFormat(taskDetail.end_at)}}</Tag>-->
<!-- <Tag v-if="isOverdue(taskDetail)" color="red">{{$L('超期未完成')}}</Tag>-->
<!-- </template>-->
</div> </div>
<Icon v-else class="clock" type="ios-clock-outline" @click="openTime" />
</DatePicker> </DatePicker>
</div>
<UserSelect <UserSelect
class="subtask-avatar" class="subtask-avatar"
v-model="ownerData.owner_userid" v-model="ownerData.owner_userid"
@ -50,6 +65,7 @@
:add-icon="false" :add-icon="false"
:project-id="taskDetail.project_id" :project-id="taskDetail.project_id"
:before-submit="onOwner"/> :before-submit="onOwner"/>
</div>
</li> </li>
<!--主任务--> <!--主任务-->
<div <div
@ -200,6 +216,25 @@
:add-icon="false" :add-icon="false"
:before-submit="onAssist"/> :before-submit="onAssist"/>
</FormItem> </FormItem>
<FormItem>
<div class="item-label" slot="label">
<i class="taskfont">&#xe63f;</i>{{$L('可见性')}}
</div>
<Checkbox disabled v-model="visibility_principal" :true-value="1" :false-value="0">{{$L('任务负责人')}}</Checkbox>
<Checkbox disabled v-model="visibility_assist" :true-value="1" :false-value="0">{{$L('任务协助人')}}</Checkbox>
<RadioGroup v-model="taskDetail.is_all_visible">
<Radio :label=1>{{$L('所有人员')}}</Radio>
<Radio :label=0>{{$L('指定成员')}}</Radio>
</RadioGroup>
<UserSelect
class="item-content user"
v-show="!taskDetail.is_all_visible"
v-model="taskDetail.visibility_appointor"
:avatar-size="28"
:title="$L('选择指定人员')"
:project-id="taskDetail.project_id"/>
<Button size="small" type="primary" @click="updateVisible">{{$L('提交修改')}}</Button>
</FormItem>
<FormItem v-if="taskDetail.end_at || timeForce"> <FormItem v-if="taskDetail.end_at || timeForce">
<div class="item-label" slot="label"> <div class="item-label" slot="label">
<i class="taskfont">&#xe6e8;</i>{{$L('截止时间')}} <i class="taskfont">&#xe6e8;</i>{{$L('截止时间')}}
@ -285,11 +320,11 @@
</li> </li>
</ul> </ul>
</FormItem> </FormItem>
<FormItem v-if="subList.length > 0 || addsubForce"> <div v-if="subList.length > 0 || addsubForce">
<div class="item-label" slot="label"> <div class="item-label" slot="label">
<i class="taskfont">&#xe6f0;</i>{{$L('子任务')}} <i class="taskfont">&#xe6f0;</i>{{$L('子任务')}}
</div> </div>
<ul class="item-content subtask"> <ul style="overflow: hidden;" class="item-content subtask">
<TaskDetail <TaskDetail
v-for="(task, key) in subList" v-for="(task, key) in subList"
:ref="`subTask_${task.id}`" :ref="`subTask_${task.id}`"
@ -300,7 +335,7 @@
:can-update-blur="canUpdateBlur"/> :can-update-blur="canUpdateBlur"/>
</ul> </ul>
<ul :class="['item-content', subList.length === 0 ? 'nosub' : '']"> <ul :class="['item-content', subList.length === 0 ? 'nosub' : '']">
<li> <li style="margin-left: 8px;">
<Input <Input
v-if="addsubShow" v-if="addsubShow"
v-model="addsubName" v-model="addsubName"
@ -317,7 +352,7 @@
</div> </div>
</li> </li>
</ul> </ul>
</FormItem> </div>
</Form> </Form>
<div v-if="menuList.length > 0" class="add"> <div v-if="menuList.length > 0" class="add">
<EDropdown <EDropdown
@ -526,7 +561,12 @@ export default {
{key: 'month', label: '每月'}, {key: 'month', label: '每月'},
{key: 'year', label: '每年'}, {key: 'year', label: '每年'},
{key: 'custom', label: '自定义'}, {key: 'custom', label: '自定义'},
] ],
//
visibility_principal: 1,
visibility_assist: 1,
visibility_appoint: 1,
} }
}, },
@ -682,7 +722,7 @@ export default {
if (!$A.isArray(taskDetail.task_user)) { if (!$A.isArray(taskDetail.task_user)) {
return []; return [];
} }
return taskDetail.task_user.filter(({owner}) => owner !== 1).sort((a, b) => { return taskDetail.task_user.filter(({owner}) => owner === 0).sort((a, b) => {
return a.id - b.id; return a.id - b.id;
}); });
}, },
@ -933,6 +973,7 @@ export default {
break; break;
} }
// //
let dataJson = {task_id: this.taskDetail.id}; let dataJson = {task_id: this.taskDetail.id};
($A.isArray(action) ? action : [action]).forEach(key => { ($A.isArray(action) ? action : [action]).forEach(key => {
let newData = this.taskDetail[key]; let newData = this.taskDetail[key];
@ -1488,7 +1529,19 @@ export default {
this.$store.dispatch('downUrl', $A.apiUrl(`project/task/filedown?file_id=${file.id}`)) this.$store.dispatch('downUrl', $A.apiUrl(`project/task/filedown?file_id=${file.id}`))
} }
}); });
},
updateVisible() {
this.updateData(['is_all_visible', 'visibility_appointor'])
} }
} }
} }
</script> </script>
<style scoped>
::v-deep .ivu-poptip-rel {
display: flex;
}
::v-deep .sub-time {
color: #BBBBBB;
}
</style>