!72 czh-20260701-优化未收藏的计划的显示
Merge pull request !72 from 陈志浩/refactor/tasklist-20260701
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -274,7 +274,7 @@
|
|||||||
<div class="list-group-col list-group-col-secret">密级</div>
|
<div class="list-group-col list-group-col-secret">密级</div>
|
||||||
<div class="list-group-col list-group-col-time">创建时间</div>
|
<div class="list-group-col list-group-col-time">创建时间</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="list in allTaskLists" :key="list.id" class="list-group-row" @click="emit('list-select', list.id)">
|
<div v-for="list in allTaskLists" :key="list.id" class="list-group-row" @click="onListRowClick(list)">
|
||||||
<div class="list-group-col list-group-col-name">
|
<div class="list-group-col list-group-col-name">
|
||||||
<Icon icon="ant-design:file-text-outlined" class="list-icon" size="16" />
|
<Icon icon="ant-design:file-text-outlined" class="list-icon" size="16" />
|
||||||
<span class="list-name-text">{{ list.name }}</span>
|
<span class="list-name-text">{{ list.name }}</span>
|
||||||
@@ -915,6 +915,7 @@
|
|||||||
'create-list': [];
|
'create-list': [];
|
||||||
'load-more': [];
|
'load-more': [];
|
||||||
'search-keyword': [keyword: string];
|
'search-keyword': [keyword: string];
|
||||||
|
'preview-list': [list: TaskList];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@@ -1255,6 +1256,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onListRowClick(list: TaskList) {
|
||||||
|
if (isFavorited(list.id)) {
|
||||||
|
emit('list-select', list.id);
|
||||||
|
} else {
|
||||||
|
emit('preview-list', list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const _isOwner = computed(() => props.currentList?.myPermission === '1');
|
const _isOwner = computed(() => props.currentList?.myPermission === '1');
|
||||||
const canEdit = computed(() => props.currentList?.myPermission === '1' || props.currentList?.myPermission === '2');
|
const canEdit = computed(() => props.currentList?.myPermission === '1' || props.currentList?.myPermission === '2');
|
||||||
const isReadOnly = computed(() => props.currentList?.myPermission === '3');
|
const isReadOnly = computed(() => props.currentList?.myPermission === '3');
|
||||||
|
|||||||
@@ -205,7 +205,7 @@
|
|||||||
<Icon icon="tasklist-desc|svg" />
|
<Icon icon="tasklist-desc|svg" />
|
||||||
</span>
|
</span>
|
||||||
<div class="detail-row-content">
|
<div class="detail-row-content">
|
||||||
<a-textarea v-if="showDescEditor && !isFullReadOnly" v-model:value="taskData.taskDesc" :rows="3" placeholder="添加描述..." autofocus @blur="onDescBlur" />
|
<a-textarea ref="descTextareaRef" v-if="showDescEditor && !isFullReadOnly" v-model:value="taskData.taskDesc" :rows="3" placeholder="添加描述..." @blur="onDescBlur" />
|
||||||
<span v-else class="desc-trigger" :class="{ 'readonly-field': isFullReadOnly }" @click="!isFullReadOnly && (showDescEditor = true)">
|
<span v-else class="desc-trigger" :class="{ 'readonly-field': isFullReadOnly }" @click="!isFullReadOnly && (showDescEditor = true)">
|
||||||
{{ taskData.taskDesc || '添加描述' }}
|
{{ taskData.taskDesc || '添加描述' }}
|
||||||
</span>
|
</span>
|
||||||
@@ -218,11 +218,11 @@
|
|||||||
</span>
|
</span>
|
||||||
<div class="detail-row-content">
|
<div class="detail-row-content">
|
||||||
<a-textarea
|
<a-textarea
|
||||||
|
ref="remarkTextareaRef"
|
||||||
v-if="showRemarkEditor && !isFullReadOnly"
|
v-if="showRemarkEditor && !isFullReadOnly"
|
||||||
v-model:value="taskData.remark"
|
v-model:value="taskData.remark"
|
||||||
:rows="3"
|
:rows="3"
|
||||||
placeholder="添加其他事项说明..."
|
placeholder="添加其他事项说明..."
|
||||||
autofocus
|
|
||||||
@blur="onRemarkBlur"
|
@blur="onRemarkBlur"
|
||||||
/>
|
/>
|
||||||
<span v-else class="desc-trigger" :class="{ 'readonly-field': isFullReadOnly }" @click="!isFullReadOnly && (showRemarkEditor = true)">
|
<span v-else class="desc-trigger" :class="{ 'readonly-field': isFullReadOnly }" @click="!isFullReadOnly && (showRemarkEditor = true)">
|
||||||
@@ -309,10 +309,10 @@
|
|||||||
<span class="feishu-subtask-drag-placeholder"></span>
|
<span class="feishu-subtask-drag-placeholder"></span>
|
||||||
<span class="feishu-subtask-check feishu-subtask-check-empty"></span>
|
<span class="feishu-subtask-check feishu-subtask-check-empty"></span>
|
||||||
<a-input
|
<a-input
|
||||||
|
ref="subTaskInputRef"
|
||||||
v-model:value="newSubTaskName"
|
v-model:value="newSubTaskName"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="输入子事项标题,按回车确认..."
|
placeholder="输入子事项标题,按回车确认..."
|
||||||
autofocus
|
|
||||||
class="feishu-subtask-input"
|
class="feishu-subtask-input"
|
||||||
@press-enter="handleSubmitSubTask"
|
@press-enter="handleSubmitSubTask"
|
||||||
@blur="showNewSubTaskInput = false"
|
@blur="showNewSubTaskInput = false"
|
||||||
@@ -330,16 +330,10 @@
|
|||||||
<span class="detail-row-icon">
|
<span class="detail-row-icon">
|
||||||
<Icon icon="tasklist-followers|svg" />
|
<Icon icon="tasklist-followers|svg" />
|
||||||
</span>
|
</span>
|
||||||
<div v-if="!isFullReadOnly" class="follower-clickable" @click="openDrawerUserSelect('followers')">
|
<div class="follower-clickable" @click="isFullReadOnly ? toggleFollow() : openDrawerUserSelect('followers')">
|
||||||
<span class="follower-label">添加关注人</span>
|
<span class="follower-label">添加关注人</span>
|
||||||
<AvatarDisplay v-if="followers.length > 0" :names="taskData.followersName" :size="24" :show-name="false" />
|
<AvatarDisplay v-if="followers.length > 0" :names="taskData.followersName" :size="24" :show-name="followers.length === 1" />
|
||||||
</div>
|
</div>
|
||||||
<template v-else>
|
|
||||||
<span v-if="followers.length === 0" class="follower-empty">无关注人</span>
|
|
||||||
<a-tooltip v-else :title="taskData.followersName" placement="top">
|
|
||||||
<AvatarDisplay :names="taskData.followersName" :size="24" :show-name="false" />
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -408,11 +402,14 @@
|
|||||||
const isFullReadOnly = computed(() => isReadOnly.value && !isAssigneeEdit.value);
|
const isFullReadOnly = computed(() => isReadOnly.value && !isAssigneeEdit.value);
|
||||||
const showNewSubTaskInput = ref(false);
|
const showNewSubTaskInput = ref(false);
|
||||||
const newSubTaskName = ref('');
|
const newSubTaskName = ref('');
|
||||||
|
const subTaskInputRef = ref();
|
||||||
const startTimeDayjs = ref<string | null>(null);
|
const startTimeDayjs = ref<string | null>(null);
|
||||||
const endTimeDayjs = ref<string | null>(null);
|
const endTimeDayjs = ref<string | null>(null);
|
||||||
const editingTitle = ref(false);
|
const editingTitle = ref(false);
|
||||||
const showDescEditor = ref(false);
|
const showDescEditor = ref(false);
|
||||||
const showRemarkEditor = ref(false);
|
const showRemarkEditor = ref(false);
|
||||||
|
const descTextareaRef = ref();
|
||||||
|
const remarkTextareaRef = ref();
|
||||||
const subtaskExpanded = ref(true);
|
const subtaskExpanded = ref(true);
|
||||||
|
|
||||||
const subTaskUserSelectId = ref<string>('');
|
const subTaskUserSelectId = ref<string>('');
|
||||||
@@ -526,6 +523,27 @@
|
|||||||
endTimeDayjs.value = data?.task?.endTime || null;
|
endTimeDayjs.value = data?.task?.endTime || null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(showNewSubTaskInput, async (val) => {
|
||||||
|
if (val) {
|
||||||
|
await nextTick();
|
||||||
|
subTaskInputRef.value?.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(showDescEditor, async (val) => {
|
||||||
|
if (val) {
|
||||||
|
await nextTick();
|
||||||
|
descTextareaRef.value?.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(showRemarkEditor, async (val) => {
|
||||||
|
if (val) {
|
||||||
|
await nextTick();
|
||||||
|
remarkTextareaRef.value?.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function autoSave() {
|
function autoSave() {
|
||||||
if (taskData.value) {
|
if (taskData.value) {
|
||||||
const updated = {
|
const updated = {
|
||||||
@@ -589,7 +607,7 @@
|
|||||||
}
|
}
|
||||||
taskData.value.followersId = idList.join(',');
|
taskData.value.followersId = idList.join(',');
|
||||||
taskData.value.followersName = nameList.join(',');
|
taskData.value.followersName = nameList.join(',');
|
||||||
autoSave();
|
emit('unfollow-task', taskData.value.id);
|
||||||
} else {
|
} else {
|
||||||
const idList = (taskData.value.followersId || '').split(',').filter(Boolean);
|
const idList = (taskData.value.followersId || '').split(',').filter(Boolean);
|
||||||
const nameList = (taskData.value.followersName || '').split(/[,,、]/).map((s) => s.trim()).filter(Boolean);
|
const nameList = (taskData.value.followersName || '').split(/[,,、]/).map((s) => s.trim()).filter(Boolean);
|
||||||
@@ -599,7 +617,7 @@
|
|||||||
}
|
}
|
||||||
taskData.value.followersId = idList.join(',');
|
taskData.value.followersId = idList.join(',');
|
||||||
taskData.value.followersName = nameList.join(',');
|
taskData.value.followersName = nameList.join(',');
|
||||||
autoSave();
|
emit('follow-task', taskData.value.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
@create-list="onCreateListModal('')"
|
@create-list="onCreateListModal('')"
|
||||||
@load-more="onLoadMoreListViews"
|
@load-more="onLoadMoreListViews"
|
||||||
@search-keyword="onSearchKeywordChange"
|
@search-keyword="onSearchKeywordChange"
|
||||||
|
@preview-list="onPreviewList"
|
||||||
/>
|
/>
|
||||||
<TaskFlatView
|
<TaskFlatView
|
||||||
v-else
|
v-else
|
||||||
@@ -103,6 +104,19 @@
|
|||||||
@move-task="onMoveTask"
|
@move-task="onMoveTask"
|
||||||
/>
|
/>
|
||||||
<CollaboratorModal ref="collaboratorModalRef" :task-list-id="collaboratorTargetListId || currentListId" :secret-level="collaboratorTargetList ? collaboratorTargetList.secretLevel || 1 : currentList?.secretLevel || 1" @changed="onCollaboratorsChanged" />
|
<CollaboratorModal ref="collaboratorModalRef" :task-list-id="collaboratorTargetListId || currentListId" :secret-level="collaboratorTargetList ? collaboratorTargetList.secretLevel || 1 : currentList?.secretLevel || 1" @changed="onCollaboratorsChanged" />
|
||||||
|
<PlanPreviewModal
|
||||||
|
:visible="previewModalVisible"
|
||||||
|
:list-id="previewListId"
|
||||||
|
:list-name="previewListName"
|
||||||
|
:secret-level="previewSecretLevel"
|
||||||
|
:secret-text="previewSecretText"
|
||||||
|
:collaborator-names="previewCollaboratorNames"
|
||||||
|
:is-favorited="previewIsFavorited"
|
||||||
|
@update:visible="(v) => (previewModalVisible = v)"
|
||||||
|
@add-to-favorites="onAddToFavorites"
|
||||||
|
@remove-from-favorites="onRemoveFavorite"
|
||||||
|
@task-click="onPreviewTaskClick"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -119,6 +133,7 @@
|
|||||||
import CreateListModal from './components/CreateListModal.vue';
|
import CreateListModal from './components/CreateListModal.vue';
|
||||||
import TaskDetailDrawer from './components/TaskDetailDrawer.vue';
|
import TaskDetailDrawer from './components/TaskDetailDrawer.vue';
|
||||||
import CollaboratorModal from './components/CollaboratorModal.vue';
|
import CollaboratorModal from './components/CollaboratorModal.vue';
|
||||||
|
import PlanPreviewModal from './components/PlanPreviewModal.vue';
|
||||||
import {
|
import {
|
||||||
getMyFavorites,
|
getMyFavorites,
|
||||||
addTaskListGroup,
|
addTaskListGroup,
|
||||||
@@ -198,6 +213,14 @@
|
|||||||
const collaboratorTargetListId = ref('');
|
const collaboratorTargetListId = ref('');
|
||||||
const defaultGroupRealIdMap = ref<Record<string, string>>({});
|
const defaultGroupRealIdMap = ref<Record<string, string>>({});
|
||||||
|
|
||||||
|
const previewModalVisible = ref(false);
|
||||||
|
const previewListId = ref('');
|
||||||
|
const previewListName = ref('');
|
||||||
|
const previewSecretLevel = ref(1);
|
||||||
|
const previewSecretText = ref('非密');
|
||||||
|
const previewCollaboratorNames = ref('');
|
||||||
|
const previewIsFavorited = computed(() => favoriteIdMap.value.has(previewListId.value));
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const currentUserSecurityLevel = ref<number>(3);
|
const currentUserSecurityLevel = ref<number>(3);
|
||||||
@@ -531,6 +554,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onPreviewList(list: TaskList) {
|
||||||
|
previewListId.value = list.id;
|
||||||
|
previewListName.value = list.name;
|
||||||
|
previewSecretLevel.value = (list as any).secretLevel || 1;
|
||||||
|
previewSecretText.value = (list as any).secretText || '非密';
|
||||||
|
previewCollaboratorNames.value = list.collaboratorNames || '';
|
||||||
|
previewModalVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPreviewTaskClick(task: TaskItem, allPreviewTasks: TaskItem[]) {
|
||||||
|
currentDrawerTaskId.value = task.id;
|
||||||
|
const readOnly = false;
|
||||||
|
openDetailDrawer(true, { task, allTasks: allPreviewTasks, readOnly, secretLevel: previewSecretLevel.value || 1 });
|
||||||
|
}
|
||||||
|
|
||||||
function onOpenCollaborator() {
|
function onOpenCollaborator() {
|
||||||
collaboratorTargetListId.value = '';
|
collaboratorTargetListId.value = '';
|
||||||
collaboratorModalRef.value?.open(currentListId.value);
|
collaboratorModalRef.value?.open(currentListId.value);
|
||||||
@@ -600,6 +638,11 @@
|
|||||||
try {
|
try {
|
||||||
await addToFavorites({ taskListId, pid: pid || undefined });
|
await addToFavorites({ taskListId, pid: pid || undefined });
|
||||||
await loadFavorites();
|
await loadFavorites();
|
||||||
|
if (previewModalVisible.value) {
|
||||||
|
previewModalVisible.value = false;
|
||||||
|
onListSelect(taskListId);
|
||||||
|
}
|
||||||
|
message.success('已添加收藏');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[TaskList] 添加收藏失败', e);
|
console.error('[TaskList] 添加收藏失败', e);
|
||||||
}
|
}
|
||||||
@@ -1386,8 +1429,7 @@
|
|||||||
await deleteTaskListApi({ id: listId });
|
await deleteTaskListApi({ id: listId });
|
||||||
}
|
}
|
||||||
if (currentListId.value === listId) {
|
if (currentListId.value === listId) {
|
||||||
const firstAvailable = findFirstAvailableList();
|
onQuickAccessTabClick('all');
|
||||||
currentListId.value = firstAvailable?.id || '';
|
|
||||||
}
|
}
|
||||||
await loadFavorites();
|
await loadFavorites();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user