mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-12 03:01:12 +00:00
perf: 添加项目任务标签功能
This commit is contained in:
parent
bca0410a08
commit
24c5200a90
@ -1239,6 +1239,7 @@ class ProjectController extends AbstractController
|
||||
$headings[] = Doo::translate('父级任务ID');
|
||||
$headings[] = Doo::translate('所属项目');
|
||||
$headings[] = Doo::translate('任务标题');
|
||||
$headings[] = Doo::translate('任务标签');
|
||||
$headings[] = Doo::translate('任务开始时间');
|
||||
$headings[] = Doo::translate('任务结束时间');
|
||||
$headings[] = Doo::translate('完成时间');
|
||||
@ -1259,7 +1260,7 @@ class ProjectController extends AbstractController
|
||||
'style' => 'font-weight: bold;padding-bottom: 4px;',
|
||||
];
|
||||
//
|
||||
$builder = ProjectTask::select(['project_tasks.*', 'project_task_users.userid as ownerid'])
|
||||
$builder = ProjectTask::with(['taskTag'])->select(['project_tasks.*', 'project_task_users.userid as ownerid'])
|
||||
->join('project_task_users', 'project_tasks.id', '=', 'project_task_users.task_id')
|
||||
->where('project_task_users.owner', 1)
|
||||
->whereIn('project_task_users.userid', $userid)
|
||||
@ -1341,6 +1342,9 @@ class ProjectController extends AbstractController
|
||||
$task->parent_id ?: '-',
|
||||
Base::filterEmoji($task->project?->name) ?: '-',
|
||||
Base::filterEmoji($task->name),
|
||||
$task->taskTag->map(function ($tag) {
|
||||
return Base::filterEmoji($tag->name);
|
||||
})->join(', ') ?: '-',
|
||||
$task->start_at ?: '-',
|
||||
$task->end_at ?: '-',
|
||||
$task->complete_at ?: '-',
|
||||
@ -1463,6 +1467,7 @@ class ProjectController extends AbstractController
|
||||
$headings[] = Doo::translate('父级任务ID');
|
||||
$headings[] = Doo::translate('所属项目');
|
||||
$headings[] = Doo::translate('任务标题');
|
||||
$headings[] = Doo::translate('任务标签');
|
||||
$headings[] = Doo::translate('任务开始时间');
|
||||
$headings[] = Doo::translate('任务结束时间');
|
||||
$headings[] = Doo::translate('任务计划用时');
|
||||
@ -1471,7 +1476,8 @@ class ProjectController extends AbstractController
|
||||
$headings[] = Doo::translate('创建人');
|
||||
$data = [];
|
||||
//
|
||||
ProjectTask::whereNull('complete_at')
|
||||
ProjectTask::with(['taskTag'])
|
||||
->whereNull('complete_at')
|
||||
->whereNotNull('end_at')
|
||||
->where('end_at', '<=', Carbon::now())
|
||||
->orderBy('end_at')
|
||||
@ -1502,11 +1508,14 @@ class ProjectController extends AbstractController
|
||||
$task->parent_id ?: '-',
|
||||
Base::filterEmoji($task->project?->name) ?: '-',
|
||||
Base::filterEmoji($task->name),
|
||||
$task->taskTag->map(function ($tag) {
|
||||
return Base::filterEmoji($tag->name);
|
||||
})->join(', ') ?: '-',
|
||||
$task->start_at ?: '-',
|
||||
$task->end_at ?: '-',
|
||||
$planTime,
|
||||
$overTime,
|
||||
implode("、", $ownerNames),
|
||||
implode(', ', $ownerNames),
|
||||
Base::filterEmoji(User::userid2nickname($task->userid)) . " (ID: {$task->userid})",
|
||||
];
|
||||
}
|
||||
|
||||
@ -58,6 +58,12 @@ import Tags from "./tags.vue";
|
||||
export default {
|
||||
name: "TaskTagAdd",
|
||||
components: {Tags},
|
||||
props: {
|
||||
projectId: {
|
||||
type: [Number, String],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loadIng: 0,
|
||||
@ -89,11 +95,25 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(tag) {
|
||||
onOpen(tag = null) {
|
||||
if (tag === null) {
|
||||
tag = this.getEmptyTag()
|
||||
}
|
||||
this.editingTag = { ...tag }
|
||||
this.showEditModal = true
|
||||
},
|
||||
|
||||
// 获取空标签对象
|
||||
getEmptyTag() {
|
||||
return {
|
||||
id: null,
|
||||
project_id: this.projectId,
|
||||
name: '',
|
||||
desc: '',
|
||||
color: ''
|
||||
}
|
||||
},
|
||||
|
||||
// 保存标签
|
||||
async handleSave() {
|
||||
if (!this.editingTag.name) {
|
||||
@ -118,7 +138,7 @@ export default {
|
||||
const results = await Promise.all(savePromises)
|
||||
$A.messageSuccess(results.length === 1 ? results[0].msg : '全部保存成功')
|
||||
this.showEditModal = false
|
||||
this.$emit('on-save')
|
||||
this.$emit('on-save', results)
|
||||
} catch (error) {
|
||||
$A.messageError(error.msg || '保存失败')
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<Loading v-if="loadIng > 0"/>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<Button type="primary" icon="md-add" @click="handleAdd">
|
||||
<Button type="primary" icon="md-add" @click="handleAdd(null)">
|
||||
{{$L('新建标签')}}
|
||||
</Button>
|
||||
</div>
|
||||
@ -16,7 +16,7 @@
|
||||
<div class="content">
|
||||
<div v-if="!tags.length" class="empty">
|
||||
<div class="empty-text">{{$L('当前项目暂无任务标签')}}</div>
|
||||
<Button type="primary" icon="md-add" @click="handleAdd">{{$L('新建标签')}}</Button>
|
||||
<Button type="primary" icon="md-add" @click="handleAdd(null)">{{$L('新建标签')}}</Button>
|
||||
</div>
|
||||
<div v-else class="template-list">
|
||||
<div v-for="item in tags" :key="item.id" class="tag-item">
|
||||
@ -27,7 +27,7 @@
|
||||
<div v-if="item.desc" class="tag-desc">{{ item.desc }}</div>
|
||||
</div>
|
||||
<div class="tag-actions">
|
||||
<Button @click="handleEdit(item)" type="primary">
|
||||
<Button @click="handleAdd(item)" type="primary">
|
||||
{{$L('编辑')}}
|
||||
</Button>
|
||||
<Button @click="handleDelete(item)" type="error">
|
||||
@ -38,8 +38,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑标签弹窗 -->
|
||||
<TaskTagAdd ref="addTag" @on-save="loadTags"/>
|
||||
<!-- 标签添加/编辑 -->
|
||||
<TaskTagAdd ref="addTag" :project-id="projectId" @on-save="loadTags"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -73,17 +73,6 @@ export default {
|
||||
this.loadTags()
|
||||
},
|
||||
methods: {
|
||||
// 获取空标签对象
|
||||
getEmptyTag() {
|
||||
return {
|
||||
id: null,
|
||||
project_id: this.projectId,
|
||||
name: '',
|
||||
desc: '',
|
||||
color: ''
|
||||
}
|
||||
},
|
||||
|
||||
// 加载标签列表
|
||||
async loadTags() {
|
||||
this.loadIng++
|
||||
@ -103,13 +92,8 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
// 新建标签
|
||||
handleAdd() {
|
||||
this.$refs.addTag.onOpen(this.getEmptyTag())
|
||||
},
|
||||
|
||||
// 编辑标签
|
||||
handleEdit(tag) {
|
||||
// 新建、编辑标签
|
||||
handleAdd(tag) {
|
||||
this.$refs.addTag.onOpen(tag)
|
||||
},
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TaskSelect",
|
||||
name: "TaskTagSelect",
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
|
||||
@ -153,11 +153,12 @@
|
||||
</div>
|
||||
<div class="item-content tags">
|
||||
<EPopover v-model="tagShow" class="tags-select" placement="bottom">
|
||||
<TagSelect
|
||||
<TaskTagSelect
|
||||
v-model="tagValue"
|
||||
:data-sources="tagData"
|
||||
:loading="tagLoad > 0"
|
||||
:max="10"/>
|
||||
:max="10"
|
||||
@add="onTagAdd"/>
|
||||
<div slot="reference">
|
||||
<TaskTag :tags="getTag">
|
||||
<li v-if="getTag.length === 0" slot="end" class="add-icon"></li>
|
||||
@ -547,6 +548,8 @@
|
||||
<Button @click="historyShow=false">{{$L('关闭')}}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
<!--标签添加-->
|
||||
<TaskTagAdd ref="addTag" :project-id="taskDetail.project_id" @on-save="onTagAddSave"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -561,19 +564,21 @@ import TaskMenu from "./TaskMenu";
|
||||
import ChatInput from "./ChatInput";
|
||||
import UserSelect from "../../../components/UserSelect.vue";
|
||||
import TaskTag from "./ProjectTaskTag/tags.vue";
|
||||
import TagSelect from "./ProjectTaskTag/select.vue";
|
||||
import TaskTagSelect from "./ProjectTaskTag/select.vue";
|
||||
import TaskExistTips from "./TaskExistTips.vue";
|
||||
import TEditorTask from "../../../components/TEditorTask.vue";
|
||||
import TaskContentHistory from "./TaskContentHistory.vue";
|
||||
import TaskTagAdd from "./ProjectTaskTag/add.vue";
|
||||
|
||||
export default {
|
||||
name: "TaskDetail",
|
||||
components: {
|
||||
TaskTagAdd,
|
||||
TaskContentHistory,
|
||||
TEditorTask,
|
||||
UserSelect,
|
||||
TaskTag,
|
||||
TagSelect,
|
||||
TaskTagSelect,
|
||||
TaskExistTips,
|
||||
ChatInput,
|
||||
TaskMenu,
|
||||
@ -1988,6 +1993,27 @@ export default {
|
||||
onTaskQuick(time, type) {
|
||||
this.$set(this.delayTaskForm, 'time', Math.round(time * 100) / 100)
|
||||
this.$set(this.delayTaskForm, 'type', type)
|
||||
},
|
||||
|
||||
onTagAdd() {
|
||||
// 避免关闭选择框时触发更新
|
||||
this.tagValue = this.getTag;
|
||||
this.tagBakValue = $A.cloneJSON(this.tagValue);
|
||||
// 隐藏选择框并打开添加框
|
||||
this.tagShow = false
|
||||
this.$refs.addTag.onOpen(null)
|
||||
},
|
||||
|
||||
onTagAddSave(result) {
|
||||
const current = this.tagValue;
|
||||
const addData = result.filter(({data}) => data && data.id > 0).map(({data}) => data);
|
||||
// 合并数组,如果有重名标签则使用新添加的标签数据
|
||||
const mergedTags = [
|
||||
...addData,
|
||||
...current.filter(tag => !addData.some(newTag => newTag.name === tag.name))
|
||||
];
|
||||
// 触发更新
|
||||
this.updateData('tag', mergedTags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user