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()
{
$user = User::auth();
// 任务可见性
$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);
$userid = $user->userid;
//
$parent_id = intval(Request::input('parent_id'));
$project_id = intval(Request::input('project_id'));
@ -919,6 +909,12 @@ class ProjectController extends AbstractController
$sorts = Request::input('sorts');
$keys = is_array($keys) ? $keys : [];
$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 (Base::isNumber($keys['name'])) {
@ -1361,8 +1357,9 @@ class ProjectController extends AbstractController
// 项目可见性
$project_userid = Project::whereId($task->project_id)->value('userid'); // 项目负责人
if ($task->is_all_visible != 1 && $user->userid != $project_userid) {
$visibleUserids = ProjectTaskUser::whereTaskId($task_id)->pluck('userid')->toArray();
if (!in_array($user->userid, $visibleUserids)) {
$visibleUserids = ProjectTaskUser::whereTaskId($task_id)->pluck('userid')->toArray(); // 是否任务负责人、协助人、可见人
$subVisibleUserids = ProjectTaskUser::whereTaskPid($task_id)->pluck('userid')->toArray(); // 是否子任务负责人、协助人
if (!in_array($user->userid, $visibleUserids) && !in_array($user->userid, $subVisibleUserids)) {
return Base::retError('无任务权限');
}
}
@ -1670,10 +1667,16 @@ class ProjectController extends AbstractController
'project_id' => $task->project_id,
'column_id' => $task->column_id,
'times' => [$task->start_at, $task->end_at],
'owner' => [User::userid()]
'owner' => [User::userid()],
'is_all_visible' => 0,
]);
$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);
}
@ -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');
$task->pushMsg('update', $data);
// 可见性推送
if (Arr::exists($param, 'visibility_appointor')) {
if (Arr::exists($param, 'is_all_visible')) {
if ($data['is_all_visible'] == 1) {
$task->pushMsgVisibleAdd($data);
}
@ -1738,9 +1741,16 @@ class ProjectController extends AbstractController
$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) {
$diff = array_diff($owners, $param['owner']);
$subUserids = ProjectTaskUser::whereTaskPid($data['id'])->pluck('userid')->toArray();
$diff = array_diff($owners, $param['owner'], $subUserids);
if ($diff) {
$task->pushMsgVisibleRemove($diff);
}

View File

@ -716,10 +716,11 @@ class ProjectTask extends AbstractModel
$this->syncDialogUser();
}
// 可见性
if (Arr::exists($data, 'visibility_appointor')) {
if (in_array(0, $data['visibility_appointor'])) {
if (Arr::exists($data, 'visibility_appointor') || Arr::exists($data, 'is_all_visible')) {
if ($data['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]);
// 覆盖
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 = array_intersect($userids, $assists);
if ($assists) {
@ -1456,8 +1455,7 @@ class ProjectTask extends AbstractModel
$userids = array_diff($userids, $owners, $assists);
} else {
// 指定可见
$visible = $taskUser->where('owner', 2)->pluck('userid')->toArray();
$userids = $visible;
$userids = $taskUser->where('owner', 2)->pluck('userid')->toArray();
}
$data = array_merge($data, [
'owner' => 0,
@ -1492,6 +1490,7 @@ class ProjectTask extends AbstractModel
*/
public function pushMsgVisibleAdd($data = null)
{
\Log::info('222222');
if (!$this->project) {
return;
}
@ -1509,7 +1508,8 @@ class ProjectTask extends AbstractModel
//
$array = [];
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 {
$userids = ProjectUser::whereProjectId($this->project_id)->pluck('userid')->toArray(); // 项目成员
}
@ -1521,9 +1521,8 @@ class ProjectTask extends AbstractModel
//
foreach ($array as $item) {
$params = [
// 'ignoreFd' => Request::header('fd'),
'ignoreFd' => '0',
'userid' => array_values($item),
'userid' => $item['userid'],
'msg' => [
'type' => 'projectTask',
'action' => 'add',
@ -1569,9 +1568,8 @@ class ProjectTask extends AbstractModel
//
foreach ($array as $item) {
$params = [
// 'ignoreFd' => Request::header('fd'),
'ignoreFd' => '0',
'userid' => array_values($item),
'userid' => $item['userid'],
'msg' => [
'type' => 'projectTask',
'action' => 'delete',
@ -1723,4 +1721,27 @@ class ProjectTask extends AbstractModel
//
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>
</FormItem>
<FormItem :label="$L('可见性')">
<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 v-model="addData.visibility_appoint" :true-value="1" :false-value="0">{{$L('指定人员')}}</Checkbox>
<UserInput
v-show="addData.visibility_appoint"
<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>
<RadioGroup v-model="addData.is_all_visible">
<Radio :label=1>{{$L('所有人员')}}</Radio>
<Radio :label=0>{{$L('指定成员')}}</Radio>
</RadioGroup>
<UserSelect
class="item-content user"
v-show="!addData.is_all_visible"
v-model="addData.visibility_appointor"
:placeholder="$L('选择指定人员')"
:project-id="addData.project_id"
:transfer="false">
<Option slot="option-prepend" :value="0" :label="$L('所有人')" >
<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>
:avatar-size="28"
:title="$L('选择指定人员')"
:project-id="addData.project_id"/>
<!-- <Button size="small" type="primary" @click="updateVisible">{{$L('提交修改')}}</Button>-->
</FormItem>
<div class="subtasks">
<div v-if="addData.subtasks.length > 0" class="sublist">
@ -209,7 +206,8 @@ export default {
visibility_principal: 1,
visibility_assist: 1,
visibility_appoint: 1,
visibility_appointor: [0],
is_all_visible: 1,
visibility_appointor: [],
},
cascaderShow: false,

View File

@ -1,55 +1,71 @@
<template>
<!--子任务-->
<li v-if="ready && taskDetail.parent_id > 0">
<div class="subtask-icon">
<TaskMenu
:ref="`taskMenu_${taskDetail.id}`"
:disabled="taskId === 0"
:task="taskDetail"
:load-status="taskDetail.loading === true"
@on-update="getLogLists"/>
</div>
<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>
</div>
<div class="subtask-name">
<Input
v-model="taskDetail.name"
ref="name"
type="textarea"
:rows="1"
:autosize="{ minRows: 1, maxRows: 8 }"
:maxlength="255"
enterkeyhint="done"
@on-blur="updateBlur('name')"
@on-keydown="onNameKeydown"/>
</div>
<DatePicker
v-model="timeValue"
:open="timeOpen"
:options="timeOptions"
format="yyyy/MM/dd HH:mm"
type="datetimerange"
class="subtask-time"
placement="bottom-end"
@on-open-change="timeChange"
@on-clear="timeClear"
@on-ok="timeOk"
transfer>
<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)}}
<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">
<TaskMenu
:ref="`taskMenu_${taskDetail.id}`"
:disabled="taskId === 0"
:task="taskDetail"
:load-status="taskDetail.loading === true"
@on-update="getLogLists"/>
</div>
<Icon v-else class="clock" type="ios-clock-outline" @click="openTime" />
</DatePicker>
<UserSelect
class="subtask-avatar"
v-model="ownerData.owner_userid"
:multiple-max="10"
:avatar-size="20"
:title="$L('修改负责人')"
:add-icon="false"
:project-id="taskDetail.project_id"
:before-submit="onOwner"/>
<!-- <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>-->
<!-- </div>-->
<div class="subtask-name">
<Input
v-model="taskDetail.name"
ref="name"
type="textarea"
:rows="1"
:autosize="{ minRows: 1, maxRows: 8 }"
:maxlength="255"
enterkeyhint="done"
@on-blur="updateBlur('name')"
@on-keydown="onNameKeydown"/>
</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
v-model="timeValue"
:open="timeOpen"
:options="timeOptions"
format="yyyy/MM/dd HH:mm"
type="datetimerange"
class="subtask-time"
placement="bottom-end"
@on-open-change="timeChange"
@on-clear="timeClear"
@on-ok="timeOk"
transfer>
<!-- <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)}}-->
<!-- </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>
</DatePicker>
</div>
<UserSelect
class="subtask-avatar"
v-model="ownerData.owner_userid"
:multiple-max="10"
:avatar-size="20"
:title="$L('修改负责人')"
:add-icon="false"
:project-id="taskDetail.project_id"
:before-submit="onOwner"/>
</div>
</li>
<!--主任务-->
<div
@ -200,6 +216,25 @@
:add-icon="false"
:before-submit="onAssist"/>
</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">
<div class="item-label" slot="label">
<i class="taskfont">&#xe6e8;</i>{{$L('截止时间')}}
@ -285,11 +320,11 @@
</li>
</ul>
</FormItem>
<FormItem v-if="subList.length > 0 || addsubForce">
<div v-if="subList.length > 0 || addsubForce">
<div class="item-label" slot="label">
<i class="taskfont">&#xe6f0;</i>{{$L('子任务')}}
</div>
<ul class="item-content subtask">
<ul style="overflow: hidden;" class="item-content subtask">
<TaskDetail
v-for="(task, key) in subList"
:ref="`subTask_${task.id}`"
@ -300,7 +335,7 @@
:can-update-blur="canUpdateBlur"/>
</ul>
<ul :class="['item-content', subList.length === 0 ? 'nosub' : '']">
<li>
<li style="margin-left: 8px;">
<Input
v-if="addsubShow"
v-model="addsubName"
@ -317,7 +352,7 @@
</div>
</li>
</ul>
</FormItem>
</div>
</Form>
<div v-if="menuList.length > 0" class="add">
<EDropdown
@ -526,7 +561,12 @@ export default {
{key: 'month', label: '每月'},
{key: 'year', 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)) {
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;
});
},
@ -933,6 +973,7 @@ export default {
break;
}
//
let dataJson = {task_id: this.taskDetail.id};
($A.isArray(action) ? action : [action]).forEach(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}`))
}
});
},
updateVisible() {
this.updateData(['is_all_visible', 'visibility_appointor'])
}
}
}
</script>
<style scoped>
::v-deep .ivu-poptip-rel {
display: flex;
}
::v-deep .sub-time {
color: #BBBBBB;
}
</style>