mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-12 19:35:50 +00:00
feat:添加任务 - 提示功能 - 60%
This commit is contained in:
parent
04cb03e0b2
commit
f8e70bd7f7
@ -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] 用户ID(如:1,2)
|
* @apiParam {String} [userid] 用户ID(如:1,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));
|
||||||
//
|
//
|
||||||
|
|||||||
@ -1249,3 +1249,4 @@ Markdown 格式发送
|
|||||||
继续
|
继续
|
||||||
退出
|
退出
|
||||||
会议组件加载失败!
|
会议组件加载失败!
|
||||||
|
以下人员以存在任务
|
||||||
@ -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)">×</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)">×</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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user