feat:添加任务 - 提示功能 - 60%

This commit is contained in:
weifashi 2023-07-18 19:03:09 +08:00
parent 04cb03e0b2
commit f8e70bd7f7
5 changed files with 635 additions and 442 deletions

View File

@ -1051,6 +1051,7 @@ class ProjectController extends AbstractController
* @apiGroup project * @apiGroup project
* @apiName task__easylists * @apiName task__easylists
* @apiParam {String} [taskid] 排除的任务ID
* @apiParam {String} [userid] 用户ID1,2 * @apiParam {String} [userid] 用户ID1,2
* @apiParam {String} [timerange] 时间范围2022-03-01 12:12:12,2022-05-01 12:12:12 * @apiParam {String} [timerange] 时间范围2022-03-01 12:12:12,2022-05-01 12:12:12
* *
@ -1062,24 +1063,31 @@ class ProjectController extends AbstractController
{ {
User::auth(); User::auth();
// //
$userid = trim(Request::input('userid')); $taskid = trim(Request::input('taskid'));
$userid = Request::input('userid');
$timerange = Request::input('timerange'); $timerange = Request::input('timerange');
// //
$list = ProjectTask::query() $list = ProjectTask::with(['taskUser'])
->select('project_tasks.id', 'project_tasks.name', 'project_tasks.created_at', 'project_tasks.updated_at') ->select('projects.name as project_name', 'project_tasks.id', 'project_tasks.name', 'project_tasks.start_at', 'project_tasks.end_at')
->join('projects','project_tasks.project_id','=','projects.id')
->leftJoin('project_task_users', function ($query) { ->leftJoin('project_task_users', function ($query) {
$query->on('project_tasks.id', '=', 'project_task_users.task_id'); $query->on('project_tasks.id', '=', 'project_task_users.task_id')->where('project_task_users.owner', '=', 1);
}) })
->whereIn('project_task_users.userid', explode(',', $userid)) ->whereIn('project_task_users.userid', is_array($userid) ? $userid : explode(',', $userid) )
->when(!empty($timerange), function ($query) use ($timerange) { ->when(!empty($timerange), function ($query) use ($timerange) {
if (!is_array($timerange)) { if (!is_array($timerange)) {
$timerange = explode(',', $timerange); $timerange = explode(',', $timerange);
} }
if (Base::isDateOrTime($timerange[0]) && Base::isDateOrTime($timerange[1])) { if (Base::isDateOrTime($timerange[0]) && Base::isDateOrTime($timerange[1])) {
$query->whereBetween('project_tasks.created_at', [Carbon::parse($timerange[0])->startOfDay(), Carbon::parse($timerange[1])->endOfDay()]); $query->where('project_tasks.start_at', '>=', Carbon::parse($timerange[0])->startOfDay());
$query->where('project_tasks.end_at', '<=', Carbon::parse($timerange[1])->endOfDay());
} }
}) })
->when(!empty($taskid), function ($query) use ($taskid) {
$query->where('project_tasks.id', "!=", $taskid);
})
->whereNull('complete_at') ->whereNull('complete_at')
->distinct()
->orderByDesc('project_tasks.id') ->orderByDesc('project_tasks.id')
->paginate(Base::getPaginate(200, 100)); ->paginate(Base::getPaginate(200, 100));
// //

View File

@ -1249,3 +1249,4 @@ Markdown 格式发送
继续 继续
退出 退出
会议组件加载失败! 会议组件加载失败!
以下人员以存在任务

View File

@ -1,8 +1,15 @@
<template> <template>
<div class="common-tag-input" :class="{focus:isFocus}" @paste="pasteText($event)" @click="focus"> <div class="common-tag-input" :class="{focus:isFocus}" @paste="pasteText($event)" @click="focus">
<div class="tags-item" v-for="(text, index) in disSource"> <Draggable
<span class="tags-content" @click.stop="">{{text}}</span><span class="tags-del" @click.stop="delTag(index)">&times;</span> :list="disSource"
:animation="150"
tag="ul"
draggable=".column-item"
>
<div class="tags-item column-item" v-for="(text, index) in disSource">
<span class="tags-content" @click.stop="edit(disSource,index)">{{text}}</span><span class="tags-del" @click.stop="delTag(index)">&times;</span>
</div> </div>
</Draggable>
<textarea <textarea
ref="myTextarea" ref="myTextarea"
class="tags-input" class="tags-input"
@ -22,8 +29,10 @@
</template> </template>
<script> <script>
import Draggable from 'vuedraggable'
export default { export default {
name: 'TagInput', name: 'TagInput',
components: {Draggable},
props: { props: {
value: { value: {
default: '' default: ''
@ -52,11 +61,13 @@
}, },
data() { data() {
const disSource = []; const disSource = [];
if( this.value ){
this.value?.split(",").forEach(item => { this.value?.split(",").forEach(item => {
if (item) { if (item) {
disSource.push(item) disSource.push(item)
} }
}); });
}
return { return {
minWidth: 80, minWidth: 80,
@ -69,7 +80,19 @@
disSource, disSource,
isFocus: false isFocus: false,
editShow: false,
editData:{
index:0,
disSource:[],
name:""
},
addRule: {
name: [
{ required: true, message: this.$L('请填写名称!'), trigger: 'change' },
]
},
} }
}, },
mounted() { mounted() {
@ -80,6 +103,7 @@
this.wayMinWidth(); this.wayMinWidth();
}, },
value(val) { value(val) {
if( val && typeof val == 'string' ){
let disSource = []; let disSource = [];
val?.split(",").forEach(item => { val?.split(",").forEach(item => {
if (item) { if (item) {
@ -87,6 +111,7 @@
} }
}); });
this.disSource = disSource; this.disSource = disSource;
}
}, },
disSource(val) { disSource(val) {
let temp = ''; let temp = '';
@ -109,6 +134,26 @@
} }
}, },
methods: { methods: {
edit(disSource,index){
this.editData.disSource = disSource
this.editData.index = index
this.editData.name = disSource[index] + ''
$A.modalInput({
title: `编辑`,
placeholder: `请输入名称`,
okText: "确定",
value: disSource[index] + '',
onOk: (desc) => {
if (!desc) {
return `请输入名称`
}
this.editData.name = desc
this.editData.disSource[this.editData.index] = desc
this.$set(this.disSource,this.editData.index,desc)
return false
},
});
},
focus(option) { focus(option) {
const $el = this.$refs.myTextarea; const $el = this.$refs.myTextarea;
$el.focus(option); $el.focus(option);

View File

@ -199,6 +199,28 @@
</ButtonGroup> </ButtonGroup>
</div> </div>
</div> </div>
<Modal v-model="showTips" :title="$L('以下人员已存在任务')" >
<List :split="false" size="small">
<ListItem v-for="(items, userid) in tipsTask" :key="userid" >
<div style="flex: 1;width: 100%;">
<UserAvatar :userid="userid" :size="28" :show-icon="true" :show-name="true" tooltipDisabled/>
<div style="margin-left: 35px;margin-top: 10px;width: calc(100% - 35px);" v-for="(item, key) in items" :key="key" >
<div style="min-width: 135px; flex: 1; white-space: nowrap; text-overflow: ellipsis;overflow: hidden;">
<span style="color: #A7ABB5;">{{item.project_name}}</span>
<span>{{item.name}}</span>
</div>
<div style="min-width: 135px;text-align: left;">{{getCutTime(item)}}</div>
</div>
</div>
</ListItem>
</List>
<div slot="footer">
<Button type="default" @click="showTips=false">{{$L('取消')}}</Button>
<Button type="primary" :loading="loadIng > 0" @click="onAdd(again,true)">{{$L('确认添加')}}</Button>
</div>
</Modal>
</div> </div>
</template> </template>
@ -276,6 +298,10 @@ export default {
isMounted: false, isMounted: false,
beforeClose: [], beforeClose: [],
again: false,
showTips: false,
tipsTask: [],
} }
}, },
@ -515,12 +541,67 @@ export default {
this.addData = Object.assign({}, this.addData, data); this.addData = Object.assign({}, this.addData, data);
}, },
onAdd(again) { getCutTime(item) {
let start_at = $A.Date(item.start_at, true);
let end_at = $A.Date(item.end_at, true);
let string = "";
console.log(start_at)
if ($A.formatDate('Y/m/d', start_at) == $A.formatDate('Y/m/d', end_at)) {
string = $A.formatDate('Y/m/d H:i', start_at) + " ~ " + $A.formatDate('H:i', end_at)
} else if ($A.formatDate('Y', start_at) == $A.formatDate('Y', end_at)) {
string = $A.formatDate('Y/m/d', start_at) + " ~ " + $A.formatDate('m/d', end_at)
string = string.replace(/( 00:00| 23:59)/g, "")
} else {
string = $A.formatDate('Y/m/d H:i', start_at) + " ~ " + $A.formatDate('Y/m/d H:i', end_at)
string = string.replace(/( 00:00| 23:59)/g, "")
}
return string
},
async onAddBefore(){
let isExistTask = false;
await this.$store.dispatch("call", {
url: 'project/task/easylists',
data: {
userid: this.addData.owner,
timerange: this.addData.times
},
method: 'get',
}).then(({data}) => {
if(data.data.length > 0) {
this.showTips = true;
let taskObj = {}
this.addData.owner.map(userid=>{
data.data.map(h=>{
if( (h.task_user || []).map(k=>k.owner ? k.userid : 0).indexOf(userid) !== -1 ){
if( !taskObj[userid] ){
taskObj[userid] = [];
}
taskObj[userid].push(h);
}
});
});
this.tipsTask = taskObj
isExistTask = true;
}
});
return isExistTask
},
async onAdd(again,affirm=false) {
if (!this.addData.name) { if (!this.addData.name) {
$A.messageError("任务描述不能为空"); $A.messageError("任务描述不能为空");
return; return;
} }
this.loadIng++;
//
this.showTips = false;
this.again = false;
if(!affirm && this.addData.owner.length>0 && await this.onAddBefore()){
this.again = again;
return;
}
this.$store.dispatch("taskAdd", this.addData).then(({msg}) => { this.$store.dispatch("taskAdd", this.addData).then(({msg}) => {
this.loadIng--; this.loadIng--;
$A.messageSuccess(msg); $A.messageSuccess(msg);

View File

@ -1,4 +1,5 @@
<template> <template>
<div>
<!--子任务--> <!--子任务-->
<li v-if="ready && taskDetail.parent_id > 0"> <li v-if="ready && taskDetail.parent_id > 0">
<div class="subtask-icon"> <div class="subtask-icon">
@ -452,6 +453,28 @@
</div> </div>
<div v-if="!taskDetail.id" class="task-load"><Loading/></div> <div v-if="!taskDetail.id" class="task-load"><Loading/></div>
</div> </div>
<!-- 提示 -->
<Modal v-model="showTips" title="提示" >
<p>以下人员时间段中已存在任务</p>
<List :split="false" size="small">
<ListItem v-for="(item, key) in tipsTaskList" :key="key">
<UserAvatar v-for="(user, index) in item.task_user"
v-if="(taskDetail.owner_userid || []).indexOf(user.userid) !== -1"
:userid="user.userid"
:size="28"
:show-icon="true"
:show-name="false"
:key="index"
/>
<p style="margin-left: 10px;"> 项目{{item.project_name}} 任务{{item.name}}</p>
</ListItem>
</List>
<div slot="footer">
<Button type="default" @click="showTips=false">{{$L('取消')}}</Button>
<Button type="primary" :loading="loadIng > 0" @click="onAdd()">{{$L('确认添加')}}</Button>
</div>
</Modal>
</div>
</template> </template>
<script> <script>
@ -574,6 +597,10 @@ export default {
{key: 'year', label: '每年'}, {key: 'year', label: '每年'},
{key: 'custom', label: '自定义'}, {key: 'custom', label: '自定义'},
], ],
showTips: false,
tipsTaskList: [],
loadIng: 0,
} }
}, },
@ -702,6 +729,8 @@ export default {
let start_at = $A.Date(taskDetail.start_at, true); let start_at = $A.Date(taskDetail.start_at, true);
let end_at = $A.Date(taskDetail.end_at, true); let end_at = $A.Date(taskDetail.end_at, true);
let string = ""; let string = "";
console.log(start_at)
console.log(end_at)
if ($A.formatDate('Y/m/d', start_at) == $A.formatDate('Y/m/d', end_at)) { if ($A.formatDate('Y/m/d', start_at) == $A.formatDate('Y/m/d', end_at)) {
string = $A.formatDate('Y/m/d H:i', start_at) + " ~ " + $A.formatDate('H:i', end_at) string = $A.formatDate('Y/m/d H:i', start_at) + " ~ " + $A.formatDate('H:i', end_at)
} else if ($A.formatDate('Y', start_at) == $A.formatDate('Y', end_at)) { } else if ($A.formatDate('Y', start_at) == $A.formatDate('Y', end_at)) {
@ -935,6 +964,26 @@ export default {
} }
}, },
async onUpdateDataBefore(params){
let isExistTask = false;
this.$store.dispatch("call", {
url: 'project/task/easylists',
data: {
taskid: this.taskDetail.id,
userid: this.taskDetail.owner_userid,
timerange: [params.start_at,params.end_at]
},
method: 'get',
}).then(({data}) => {
if(data.data.length > 0) {
this.showTips = true;
this.tipsTaskList = data.data
isExistTask = true;
}
});
return isExistTask
},
updateData(action, params) { updateData(action, params) {
let successCallback = null; let successCallback = null;
switch (action) { switch (action) {
@ -957,7 +1006,16 @@ export default {
if (!desc) { if (!desc) {
return `请输入修改备注` return `请输入修改备注`
} }
this.updateData("times", Object.assign(params, {desc}))
console.log( this.onUpdateDataBefore(params) )
if(this.taskDetail.owner_userid.length>0 && this.onUpdateDataBefore(params)){
this.again = again;
console.log(11111)
return false;
}
console.log(22222)
// this.updateData("times", Object.assign(params, {desc}))
return false return false
}, },
}); });