czh-20260429-实现任务管理的前端功能

This commit is contained in:
zhihao
2026-04-30 09:24:45 +08:00
parent dd88adab73
commit 2641522dcd
35 changed files with 8355 additions and 0 deletions
+982
View File
@@ -0,0 +1,982 @@
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<div class="task-page">
<TaskSidebar
:task-list-groups="taskListGroups"
:current-view="currentView"
:current-list-id="currentListId"
:favorite-id-map="favoriteIdMap"
:permission-map="permissionMap"
@view-select="onViewSelect"
@list-select="onListSelect"
@create-list="onCreateList"
@create-group="onCreateGroup"
@rename-list="onRenameList"
@delete-list="onDeleteList"
@rename-group="onRenameGroup"
@delete-group="onDeleteGroup"
@quick-access-tab-click="onQuickAccessTabClick"
@move-list="onMoveList"
@move-group="onMoveGroup"
/>
<TaskContent
:current-list="currentList"
:task-list-groups="showListGroupView ? quickAccessGroups : taskListGroups"
:status-filter="statusFilter"
:group-dimension="groupDimension"
:sort-field="sortField"
:sort-direction="sortDirection"
:visible-fields="visibleFields"
:show-list-group-view="showListGroupView"
:list-group-tab="listGroupTab"
:favorite-id-map="favoriteIdMap"
@create-task="onCreateTask"
@toggle-task="onToggleTask"
@task-click="onTaskClick"
@create-group="onCreateGroupFromContent"
@add-group="onAddGroup"
@update-task-field="onUpdateTaskField"
@update-task-fields="onUpdateTaskFields"
@update:status-filter="(v) => (statusFilter = v)"
@update:group-dimension="(v) => (groupDimension = v)"
@update:sort-field="(v) => (sortField = v)"
@update:sort-direction="(v) => (sortDirection = v)"
@update:visible-fields="(v) => (visibleFields = v)"
@update:list-group-tab="onQuickAccessTabClick"
@list-select="onListSelect"
@open-collaborator="onOpenCollaborator"
@add-to-favorites="onAddToFavorites"
@remove-from-favorites="onRemoveFromFavorites"
@move-task="onMoveTask"
@move-task-group="onMoveTaskGroup"
@rename-list="onRenameList"
@delete-list="onDeleteList"
@rename-group="onRenameTaskGroup"
@delete-group="onDeleteTaskGroup"
/>
<CreateTaskModal @register="registerTaskModal" @success="onTaskCreated" />
<CreateListModal @register="registerListModal" @success="onListCreated" />
<TaskDetailDrawer
@register="registerDetailDrawer"
@save-task="onSaveTask"
@create-sub-task="onCreateSubTask"
@toggle-sub-task="onToggleSubTask"
@toggle-task="onToggleTask"
@navigate-task="onNavigateTask"
@delete-task="onDeleteTask"
@delete-sub-task="onDeleteSubTaskRecord"
@update-sub-task-field="onUpdateSubTaskField"
@update-sub-task-fields="onUpdateSubTaskFields"
@follow-task="onFollowTask"
@unfollow-task="onUnfollowTask"
@move-task="onMoveTask"
/>
<CollaboratorModal ref="collaboratorModalRef" :task-list-id="currentListId" :is-owner="isCurrentOwner" @changed="onCollaboratorsChanged" />
</div>
</template>
<script lang="ts" name="tasklist-index-page" setup>
import { ref, reactive, computed, onMounted } from 'vue';
import { useModal } from '/@/components/Modal';
import { useDrawer } from '/@/components/Drawer';
import TaskSidebar from './components/TaskSidebar.vue';
import TaskContent from './components/TaskContent.vue';
import CreateTaskModal from './components/CreateTaskModal.vue';
import CreateListModal from './components/CreateListModal.vue';
import TaskDetailDrawer from './components/TaskDetailDrawer.vue';
import CollaboratorModal from './components/CollaboratorModal.vue';
import {
getMyFavorites,
addTaskListGroup,
addTaskList,
removeFavorite,
removeFavoriteGroup,
deleteTaskListApi,
renameTaskList,
saveOrUpdate,
renameGroup,
getMyOwnLists,
getMyCollabLists,
getAllLists,
moveTaskList,
moveGroup,
getMyPermission,
getCollaborators,
addToFavorites,
addTask,
editTask,
deleteTask as deleteTaskApi,
toggleTaskStatus,
followTask as followTaskApi,
unfollowTask as unfollowTaskApi,
listAllByMainId,
myResponsibleTasks,
myFollowedTasks,
moveTask,
moveTaskGroup,
} from './TaskList.api';
import { DEFAULT_VISIBLE_FIELDS } from './types';
import type {
TaskListGroup,
StatusFilter,
GroupDimension,
SortField,
SortDirection,
FieldKey,
TaskList,
ViewType,
TaskItem,
TaskGroup,
} from './types';
const taskListGroups = ref<TaskListGroup[]>([]);
const quickAccessGroups = ref<TaskListGroup[]>([]);
const currentView = ref<ViewType>('my-tasks');
const currentListId = ref<string>('');
const statusFilter = ref<StatusFilter>('all');
const groupDimension = ref<GroupDimension>('custom');
const sortField = ref<SortField>('sortOrder');
const sortDirection = ref<SortDirection>('asc');
const showListGroupView = ref(false);
const listGroupTab = ref('all');
const visibleFields = ref<FieldKey[]>([...DEFAULT_VISIBLE_FIELDS]);
const currentDrawerTaskId = ref<string>('');
const [registerTaskModal, { openModal: openTaskModal }] = useModal();
const [registerListModal, { openModal: _openListModal }] = useModal();
const [registerDetailDrawer, { openDrawer: openDetailDrawer }] = useDrawer();
const collaboratorModalRef = ref<InstanceType<typeof CollaboratorModal> | null>(null);
const favoriteIdMap = reactive(new Map<string, string>());
const permissionMap = reactive(new Map<string, string>());
async function loadFavorites() {
try {
const data: any[] = await getMyFavorites();
favoriteIdMap.clear();
permissionMap.clear();
for (const fav of data) {
if (fav.type === '1' && fav.mainId) {
favoriteIdMap.set(fav.mainId, fav.id);
if (fav.permission) {
permissionMap.set(fav.mainId, fav.permission);
}
}
}
taskListGroups.value = buildTree(data);
} catch (e) {
console.error('[TaskList] 加载收藏列表失败', e);
}
}
function buildTree(favorites: any[]): TaskListGroup[] {
const groups: TaskListGroup[] = [];
const ungroupedLists: TaskList[] = [];
for (const fav of favorites) {
if (fav.type === '0') {
groups.push({
id: fav.id,
name: fav.tasklistName || '',
pid: '0',
hasChild: fav.hasChild || '0',
type: 0,
sortOrder: fav.sortOrder || 0,
delFlag: 0,
taskLists: [],
});
} else if (fav.type === '1') {
const list: TaskList = {
id: fav.mainId,
name: fav.tasklistName || '',
pid: fav.pid || '',
hasChild: '0',
type: 1,
sortOrder: fav.sortOrder || 0,
delFlag: 0,
groups: [],
};
if (fav.pid) {
const parentGroup = groups.find((g) => g.id === fav.pid);
if (parentGroup) {
parentGroup.taskLists.push(list);
} else {
ungroupedLists.push(list);
}
} else {
ungroupedLists.push(list);
}
}
}
if (ungroupedLists.length > 0) {
const virtualGroup: TaskListGroup = {
id: '__ungrouped__',
name: '__ungrouped__',
pid: '0',
hasChild: '0',
type: 0,
sortOrder: -1,
delFlag: 0,
taskLists: ungroupedLists,
};
groups.unshift(virtualGroup);
}
groups.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
return groups;
}
onMounted(() => {
loadFavorites();
});
function findListInGroups(groups: TaskListGroup[], listId: string): TaskList | null {
for (const group of groups) {
for (const list of group.taskLists) {
if (list.id === listId) return list;
}
}
return null;
}
const currentList = computed<TaskList | null>(() => {
if (!currentListId.value) return null;
return findListInGroups(taskListGroups.value, currentListId.value) || findListInGroups(quickAccessGroups.value, currentListId.value);
});
const isCurrentOwner = computed(() => currentList.value?.myPermission === '1');
async function loadPermissionForList(listId: string) {
try {
const perm = await getMyPermission({ taskListId: listId });
const list = findListById(listId);
if (list) {
list.myPermission = perm || '';
}
const collabs: any[] = await getCollaborators({ taskListId: listId });
const names = collabs.map((c: any) => c.username).filter(Boolean);
if (list) {
list.collaboratorNames = names.join(',');
}
} catch (e) {
console.error('[TaskList] 获取权限失败', e);
}
}
function buildTaskItem(tr: any): TaskItem {
return {
id: tr.id,
taskName: tr.taskName || '',
taskDesc: tr.taskDesc || '',
completed: tr.taskStatus === 1,
priority: tr.priority || '',
assigneeId: tr.assigneeId || '',
assigneeName: tr.assigneeName || '',
assignId: tr.assignId || '',
assignName: tr.assignName || '',
participantId: tr.participantId || '',
participantName: tr.participantName || '',
followersId: tr.followersId || '',
followersName: tr.followersName || '',
createBy: tr.createByName || tr.createBy_dictText || tr.createBy || '',
startTime: tr.startTime ? tr.startTime.split(' ')[0] : '',
endTime: tr.endTime ? tr.endTime.split(' ')[0] : '',
completeTime: tr.completeTime ? tr.completeTime.split(' ')[0] : '',
createTime: tr.createTime ? tr.createTime.split(' ')[0] : '',
updateTime: tr.updateTime ? tr.updateTime.split(' ')[0] : '',
type: tr.type || '',
subTaskCount: tr.subTaskCount || 0,
completedSubTaskCount: tr.completedSubTaskCount || 0,
remark: tr.remark || '',
groupId: '',
groupName: '',
childCount: tr.subTaskCount || 0,
completedChildCount: tr.completedSubTaskCount || 0,
pid: tr.pid || '',
hasChild: tr.hasChild || '0',
sortOrder: tr.sortOrder ?? 0,
};
}
async function loadTasks(listId: string) {
try {
const res = await listAllByMainId({ mainId: listId });
const data: any[] = Array.isArray(res) ? res : Array.isArray(res?.result) ? res.result : [];
const list = findListById(listId);
if (!list) return;
const groupRecords = data.filter((d: any) => d.type === '0');
const taskRecords = data.filter((d: any) => d.type === '1');
const groupMap = new Map<string, TaskGroup>();
let defaultGroup: TaskGroup | null = null;
for (const gr of groupRecords) {
const tg: TaskGroup = {
id: gr.id,
name: gr.taskName || '',
taskListId: listId,
collapsed: false,
tasks: [],
};
groupMap.set(gr.id, tg);
if (gr.taskName === '默认分组') {
defaultGroup = tg;
}
}
if (!defaultGroup) {
defaultGroup = {
id: '__default__',
name: '默认分组',
taskListId: listId,
collapsed: false,
tasks: [],
};
}
const groupIds = new Set(groupRecords.map((g: any) => g.id));
const allTaskItems = new Map<string, TaskItem>();
for (const tr of taskRecords) {
allTaskItems.set(tr.id, buildTaskItem(tr));
}
function getGroupForTask(taskId: string): { groupId: string; groupName: string } {
const item = allTaskItems.get(taskId);
if (!item) return { groupId: defaultGroup!.id, groupName: defaultGroup!.name };
if (!item.pid) return { groupId: defaultGroup!.id, groupName: defaultGroup!.name };
if (groupIds.has(item.pid)) {
const tg = groupMap.get(item.pid);
return { groupId: tg!.id, groupName: tg!.name };
}
return getGroupForTask(item.pid);
}
for (const [id, taskItem] of allTaskItems) {
const { groupId, groupName } = getGroupForTask(id);
taskItem.groupId = groupId;
taskItem.groupName = groupName;
const targetGroup = groupMap.get(groupId) || defaultGroup!;
targetGroup.tasks.push(taskItem);
}
const resultGroups: TaskGroup[] = [];
if (defaultGroup) {
resultGroups.push(defaultGroup);
}
for (const [_gid, tg] of groupMap) {
if (tg !== defaultGroup) {
resultGroups.push(tg);
}
}
resultGroups.sort((a, b) => {
if (a.id === '__default__') return -1;
if (b.id === '__default__') return 1;
return (a.sortOrder ?? 0) - (b.sortOrder ?? 0);
});
list.groups = resultGroups;
} catch (e) {
console.error('[TaskList] 加载任务失败', e);
}
}
async function onViewSelect(view: ViewType) {
currentView.value = view;
showListGroupView.value = false;
currentListId.value = '';
if (view === 'my-tasks') {
try {
const data: any[] = await myResponsibleTasks();
quickAccessGroups.value = buildGroupsFromTasks(data, '我负责的任务');
showListGroupView.value = true;
} catch (e) {
console.error('[TaskList] 加载我负责的任务失败', e);
}
} else if (view === 'followed') {
try {
const data: any[] = await myFollowedTasks();
quickAccessGroups.value = buildGroupsFromTasks(data, '我关注的任务');
showListGroupView.value = true;
} catch (e) {
console.error('[TaskList] 加载我关注的任务失败', e);
}
}
}
function buildGroupsFromTasks(tasks: any[], virtualGroupName: string): TaskListGroup[] {
const taskItems: TaskItem[] = (tasks || []).map((tr: any) => ({
id: tr.id,
taskName: tr.taskName || '',
taskDesc: tr.taskDesc || '',
completed: tr.taskStatus === 1,
priority: tr.priority || '',
assigneeId: tr.assigneeId || '',
assigneeName: tr.assigneeName || '',
assignId: tr.assignId || '',
assignName: tr.assignName || '',
participantId: tr.participantId || '',
participantName: tr.participantName || '',
followersId: tr.followersId || '',
followersName: tr.followersName || '',
createBy: tr.createBy || '',
startTime: tr.startTime ? tr.startTime.split(' ')[0] : '',
endTime: tr.endTime ? tr.endTime.split(' ')[0] : '',
completeTime: tr.completeTime ? tr.completeTime.split(' ')[0] : '',
createTime: tr.createTime ? tr.createTime.split(' ')[0] : '',
updateTime: tr.updateTime ? tr.updateTime.split(' ')[0] : '',
type: tr.type || '',
subTaskCount: tr.subTaskCount || 0,
completedSubTaskCount: tr.completedSubTaskCount || 0,
remark: tr.remark || '',
groupId: '',
groupName: '',
childCount: tr.subTaskCount || 0,
completedChildCount: tr.completedSubTaskCount || 0,
pid: tr.pid || '',
hasChild: tr.hasChild || '0',
sortOrder: tr.sortOrder ?? 0,
}));
const taskList: TaskList = {
id: '__virtual_view__',
name: virtualGroupName,
pid: '',
hasChild: '0',
type: 1,
sortOrder: 0,
delFlag: 0,
groups: [
{
id: '__default__',
name: virtualGroupName,
taskListId: '__virtual_view__',
collapsed: false,
tasks: taskItems,
},
],
};
return [
{
id: '__virtual_view_group__',
name: virtualGroupName,
pid: '0',
hasChild: '0',
type: 0,
sortOrder: 0,
delFlag: 0,
taskLists: [taskList],
},
];
}
function onListSelect(listId: string) {
currentView.value = '';
currentListId.value = listId;
showListGroupView.value = false;
loadPermissionForList(listId);
loadTasks(listId);
}
function onOpenCollaborator() {
collaboratorModalRef.value?.open();
}
async function onCollaboratorsChanged() {
if (currentListId.value) {
await loadPermissionForList(currentListId.value);
}
}
async function onAddToFavorites(taskListId: string) {
try {
await addToFavorites({ taskListId });
await loadFavorites();
} catch (e) {
console.error('[TaskList] 添加收藏失败', e);
}
}
async function onRemoveFromFavorites(favoriteId: string) {
try {
await removeFavorite({ favoriteId });
await loadFavorites();
} catch (e) {
console.error('[TaskList] 取消收藏失败', e);
}
}
async function onQuickAccessTabClick(tabKey: string) {
const quickAccessViewMap: Record<string, ViewType> = {
all: 'all-tasks',
own: 'created',
collab: 'assigned',
};
currentView.value = quickAccessViewMap[tabKey] || currentView.value;
showListGroupView.value = true;
currentListId.value = '';
listGroupTab.value = tabKey;
try {
if (tabKey === 'all') {
const data: TaskList[] = await getAllLists();
quickAccessGroups.value = wrapAsVirtualGroupsWithDetails(data);
} else if (tabKey === 'own') {
const data: TaskList[] = await getMyOwnLists();
quickAccessGroups.value = wrapAsVirtualGroupsWithDetails(data);
} else if (tabKey === 'collab') {
const data: TaskList[] = await getMyCollabLists();
quickAccessGroups.value = wrapAsVirtualGroupsWithDetails(data);
}
} catch (e) {
console.error('[TaskList] 加载清单失败', e);
}
}
function wrapAsVirtualGroupsWithDetails(lists: TaskList[]): TaskListGroup[] {
return lists.map((item: TaskList) => ({
id: `_virtual_${item.id}`,
name: item.tasklistName || '',
pid: '0',
hasChild: '0',
type: 0,
sortOrder: 0,
delFlag: 0,
taskLists: [
{
id: item.id,
name: item.tasklistName || '',
pid: '',
hasChild: '0',
type: 1,
sortOrder: 0,
delFlag: 0,
groups: [],
ownerName: item.ownerName || '',
collaboratorNames: item.collaboratorNames || '',
createTimeStr: item.createTimeStr || '',
},
],
}));
}
async function onCreateTask(groupId: string, taskName: string, sortOrder?: number) {
if (taskName && taskName.trim()) {
try {
console.log('[TaskList] onCreateTask:', { groupId, taskName, mainId: currentListId.value, sortOrder });
const params: any = {
mainId: currentListId.value,
taskName: taskName.trim(),
type: '1',
pid: groupId && groupId !== '__default__' ? groupId : '',
};
if (sortOrder !== undefined) {
params.sortOrder = sortOrder;
}
await addTask(params);
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 创建任务失败', e);
}
} else {
openTaskModal(true, { groupId, mainId: currentListId.value });
}
}
async function onCreateList(name: string, groupId: string) {
if (!name || !name.trim()) return;
try {
await addTaskList({
tasklistName: name.trim(),
pid: groupId || undefined,
sortOrder: 1,
});
await loadFavorites();
} catch (e) {
console.error('[TaskList] 创建清单失败', e);
}
}
function onListCreated() {
loadFavorites();
}
async function onTaskCreated() {
if (currentListId.value) {
await loadTasks(currentListId.value);
}
}
async function onCreateGroup(name: string) {
const groupName = name?.trim() || '新建分组';
try {
await addTaskListGroup({ tasklistName: groupName });
await loadFavorites();
} catch (e) {
console.error('[TaskList] 创建分组失败', e);
}
}
async function onCreateGroupFromContent(_name: string) {
const groupName = '新建分组';
try {
if (!currentListId.value) return;
await addTask({
mainId: currentListId.value,
taskName: groupName,
type: '0',
sortOrder: 1,
});
await loadTasks(currentListId.value);
} catch (e) {
console.error('[TaskList] 创建任务分组失败', e);
}
}
async function onRenameGroup(groupId: string, newName: string) {
try {
await renameGroup({ groupId, newName });
await loadFavorites();
} catch (e) {
console.error('[TaskList] 重命名分组失败', e);
}
}
async function onDeleteGroup(groupId: string) {
try {
await removeFavoriteGroup({ groupId });
await loadFavorites();
const hasCurrentList = taskListGroups.value.some((g) => g.taskLists.some((l) => l.id === currentListId.value));
if (!hasCurrentList) {
const firstAvailable = findFirstAvailableList();
currentListId.value = firstAvailable?.id || '';
}
} catch (e) {
console.error('[TaskList] 移除分组失败', e);
}
}
async function onMoveList(favoriteId: string, targetGroupId: string, sortOrder: number) {
try {
await moveTaskList({ favoriteId, targetGroupId: targetGroupId || undefined, sortOrder });
await loadFavorites();
} catch (e) {
console.error('[TaskList] 移动清单失败', e);
}
}
async function onMoveGroup(groupId: string, sortOrder: number) {
try {
await moveGroup({ groupId, sortOrder });
await loadFavorites();
} catch (e) {
console.error('[TaskList] 移动分组失败', e);
}
}
async function onMoveTask(taskId: string, targetPid: string, targetSortOrder: number) {
try {
await moveTask({ taskId, targetPid, targetSortOrder });
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 移动任务失败', e);
}
}
async function onMoveTaskGroup(taskGroupId: string, targetSortOrder: number) {
try {
await moveTaskGroup({ taskGroupId, targetSortOrder });
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 移动任务分组失败', e);
}
}
async function onToggleTask(taskId: string) {
try {
await toggleTaskStatus({ id: taskId });
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 切换任务状态失败', e);
}
}
function onTaskClick(taskId: string) {
currentDrawerTaskId.value = taskId;
const allTasks = getAllTasks();
const task = allTasks.find((t) => t.id === taskId);
if (task) {
openDetailDrawer(true, { task, allTasks });
}
}
function refreshDrawer() {
if (!currentDrawerTaskId.value) return;
const allTasks = getAllTasks();
const task = allTasks.find((t) => t.id === currentDrawerTaskId.value);
if (task) {
openDetailDrawer(true, { task, allTasks });
}
}
async function onUpdateTaskField(taskId: string, field: string, value: any) {
try {
await editTask({ id: taskId, [field]: value });
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 更新任务字段失败', e);
}
}
async function onUpdateTaskFields(taskId: string, fields: Record<string, any>) {
try {
await editTask({ id: taskId, ...fields });
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 批量更新任务字段失败', e);
}
}
async function onSaveTask(updatedTask: TaskItem) {
try {
await editTask({
id: updatedTask.id,
taskName: updatedTask.taskName,
taskDesc: updatedTask.taskDesc,
priority: updatedTask.priority,
assigneeId: updatedTask.assigneeId,
assigneeName: updatedTask.assigneeName,
participantId: updatedTask.participantId,
participantName: updatedTask.participantName,
followersId: updatedTask.followersId,
followersName: updatedTask.followersName,
startTime: updatedTask.startTime || null,
endTime: updatedTask.endTime || null,
type: updatedTask.type,
remark: updatedTask.remark,
});
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 保存任务失败', e);
}
}
async function onCreateSubTask(parentTaskId: string, taskName: string) {
try {
await addTask({
mainId: currentListId.value,
taskName,
type: '1',
pid: parentTaskId,
});
if (currentListId.value) {
await loadTasks(currentListId.value);
refreshDrawer();
}
} catch (e) {
console.error('[TaskList] 创建子任务失败', e);
}
}
async function onToggleSubTask(taskId: string) {
try {
await toggleTaskStatus({ id: taskId });
if (currentListId.value) {
await loadTasks(currentListId.value);
refreshDrawer();
}
} catch (e) {
console.error('[TaskList] 切换子任务状态失败', e);
}
}
function onNavigateTask(taskId: string) {
currentDrawerTaskId.value = taskId;
const allTasks = getAllTasks();
const task = allTasks.find((t) => t.id === taskId);
if (task) {
openDetailDrawer(true, { task, allTasks });
}
}
async function onDeleteTask(taskId: string) {
try {
await deleteTaskApi({ id: taskId }, () => {});
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 删除任务失败', e);
}
}
async function onDeleteSubTaskRecord(taskId: string) {
try {
await deleteTaskApi({ id: taskId }, () => {});
if (currentListId.value) {
await loadTasks(currentListId.value);
refreshDrawer();
}
} catch (e) {
console.error('[TaskList] 删除子任务失败', e);
}
}
async function onUpdateSubTaskField(taskId: string, field: string, value: any) {
try {
await editTask({ id: taskId, [field]: value || '' });
if (currentListId.value) {
await loadTasks(currentListId.value);
refreshDrawer();
}
} catch (e) {
console.error('[TaskList] 更新子任务字段失败', e);
}
}
async function onUpdateSubTaskFields(taskId: string, fields: Record<string, any>) {
try {
await editTask({ id: taskId, ...fields });
if (currentListId.value) {
await loadTasks(currentListId.value);
refreshDrawer();
}
} catch (e) {
console.error('[TaskList] 批量更新子任务字段失败', e);
}
}
async function onFollowTask(taskId: string) {
try {
await followTaskApi({ id: taskId });
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 关注任务失败', e);
}
}
async function onUnfollowTask(taskId: string) {
try {
await unfollowTaskApi({ id: taskId });
if (currentListId.value) {
await loadTasks(currentListId.value);
}
} catch (e) {
console.error('[TaskList] 取消关注失败', e);
}
}
async function onAddGroup(listId: string, groupName: string) {
try {
await addTask({
mainId: listId,
taskName: groupName,
type: '0',
sortOrder: 1,
});
await loadTasks(listId);
} catch (e) {
console.error('[TaskList] 创建任务分组失败', e);
}
}
async function onRenameList(listId: string, newName: string) {
const list = findListById(listId);
if (list) {
list.name = newName;
}
try {
await renameTaskList({ taskListId: listId, newName });
} catch (e) {
console.error('[TaskList] 重命名清单失败', e);
}
}
async function onDeleteList(listId: string) {
try {
if (showListGroupView.value) {
const favId = favoriteIdMap.get(listId);
if (favId) {
await removeFavorite({ favoriteId: favId });
}
} else {
await deleteTaskListApi({ id: listId });
}
if (currentListId.value === listId) {
const firstAvailable = findFirstAvailableList();
currentListId.value = firstAvailable?.id || '';
}
await loadFavorites();
} catch (e) {
console.error('[TaskList] 删除清单失败', e);
}
}
function getAllTasks(): TaskItem[] {
const allTasks: TaskItem[] = [];
for (const group of taskListGroups.value) {
for (const list of group.taskLists) {
for (const taskGroup of list.groups) {
allTasks.push(...taskGroup.tasks);
}
}
}
return allTasks;
}
function findListById(listId: string): TaskList | null {
for (const group of taskListGroups.value) {
for (const list of group.taskLists) {
if (list.id === listId) return list;
}
}
for (const group of quickAccessGroups.value) {
for (const list of group.taskLists) {
if (list.id === listId) return list;
}
}
return null;
}
function findFirstAvailableList(): TaskList | null {
for (const group of taskListGroups.value) {
for (const list of group.taskLists) {
if (list.delFlag !== 1) return list;
}
}
return null;
}
</script>
<style lang="less" scoped>
.task-page {
display: flex;
height: calc(100vh - 120px);
background: #f5f5f5;
overflow: hidden;
}
</style>