czh-20260521-更改计划名称以及优化新增分组流程
This commit is contained in:
@@ -103,7 +103,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import { ref, reactive, computed, nextTick } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon/index';
|
||||
import SzUserSelect from '/@/components/semri/userComponent/SzUserSelect.vue';
|
||||
@@ -135,7 +135,7 @@
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
changed: [];
|
||||
changed: [collaboratorNames: string];
|
||||
}>();
|
||||
|
||||
const visible = ref(false);
|
||||
@@ -147,6 +147,8 @@
|
||||
permission: '2',
|
||||
});
|
||||
const pendingAddList = ref<PendingAddItem[]>([]);
|
||||
const pendingRemoveIds = ref<Set<string>>(new Set());
|
||||
const pendingPermissionMap = ref<Map<string, string>>(new Map());
|
||||
|
||||
const allMembers = computed(() => {
|
||||
const pendingAsCollab: CollaboratorItem[] = pendingAddList.value.map((p) => ({
|
||||
@@ -155,7 +157,22 @@
|
||||
username: p.username,
|
||||
permission: p.permission,
|
||||
}));
|
||||
return [...collaborators.value, ...pendingAsCollab];
|
||||
return [...collaborators.value, ...pendingAsCollab]
|
||||
.filter((m) => (m.permission !== '1' ? !pendingRemoveIds.value.has(m.permissionId) : true))
|
||||
.map((m) => {
|
||||
if (m.permissionId && pendingPermissionMap.value.has(m.permissionId)) {
|
||||
return { ...m, permission: pendingPermissionMap.value.get(m.permissionId)! };
|
||||
}
|
||||
return m;
|
||||
});
|
||||
});
|
||||
|
||||
const collaboratorNamesSnapshot = computed(() => {
|
||||
return allMembers.value
|
||||
.filter((m) => m.permission !== '1')
|
||||
.map((m) => m.username)
|
||||
.filter(Boolean)
|
||||
.join(',');
|
||||
});
|
||||
|
||||
function getColor(name: string): string {
|
||||
@@ -163,11 +180,15 @@
|
||||
}
|
||||
|
||||
async function open() {
|
||||
visible.value = true;
|
||||
collaborators.value = [];
|
||||
showAddPanel.value = false;
|
||||
pendingAddList.value = [];
|
||||
pendingRemoveIds.value.clear();
|
||||
pendingPermissionMap.value.clear();
|
||||
addForm.userIds = '';
|
||||
addForm.permission = '2';
|
||||
visible.value = true;
|
||||
await nextTick();
|
||||
await loadCollaborators();
|
||||
}
|
||||
|
||||
@@ -177,11 +198,14 @@
|
||||
addForm.userIds = '';
|
||||
addForm.permission = '2';
|
||||
pendingAddList.value = [];
|
||||
pendingRemoveIds.value.clear();
|
||||
pendingPermissionMap.value.clear();
|
||||
}
|
||||
|
||||
async function loadCollaborators() {
|
||||
try {
|
||||
const data: any[] = await getCollaborators({ taskListId: props.taskListId });
|
||||
const options = { successMessageMode: 'none' as const };
|
||||
const data: any[] = await getCollaborators({ taskListId: props.taskListId }, options);
|
||||
collaborators.value = data;
|
||||
} catch (e) {
|
||||
console.error('[CollaboratorModal] load failed', e);
|
||||
@@ -196,7 +220,7 @@
|
||||
const secretLevel = props.secretLevel || 1;
|
||||
const { ok, invalidNames } = await checkUserSecLevel(addForm.userIds, secretLevel);
|
||||
if (!ok) {
|
||||
message.warning(`以下人员的密级不满足当前清单(${props.secretText || '非密'})要求:${invalidNames.join('、')}`);
|
||||
message.warning(`以下人员的密级不满足当前计划(${props.secretText || '非密'})要求:${invalidNames.join('、')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,7 +240,6 @@
|
||||
const existingIds = new Set(collaborators.value.map((c) => c.userId));
|
||||
const pendingIds = new Set(pendingAddList.value.map((p) => p.userId));
|
||||
|
||||
let addedCount = 0;
|
||||
for (const uid of ids) {
|
||||
if (!existingIds.has(uid) && !pendingIds.has(uid)) {
|
||||
pendingAddList.value.push({
|
||||
@@ -224,72 +247,82 @@
|
||||
username: nameMap[uid] || uid,
|
||||
permission: addForm.permission,
|
||||
});
|
||||
addedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (addedCount > 0) {
|
||||
createMessage.success(`已添加 ${addedCount} 位协作人`);
|
||||
} else {
|
||||
createMessage.warning('所选用户均已是协作人');
|
||||
}
|
||||
|
||||
addForm.userIds = '';
|
||||
addForm.permission = '2';
|
||||
showAddPanel.value = false;
|
||||
}
|
||||
|
||||
async function onDone() {
|
||||
if (pendingAddList.value.length > 0) {
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
for (const item of pendingAddList.value) {
|
||||
try {
|
||||
await addCollaborator({
|
||||
taskListId: props.taskListId,
|
||||
userId: item.userId,
|
||||
permission: item.permission,
|
||||
});
|
||||
successCount++;
|
||||
} catch {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
function onDone() {
|
||||
const hasChanges =
|
||||
pendingAddList.value.length > 0 || pendingRemoveIds.value.size > 0 || pendingPermissionMap.value.size > 0;
|
||||
|
||||
if (successCount > 0) {
|
||||
createMessage.success(`成功添加 ${successCount} 位协作人${failCount > 0 ? `,${failCount} 位失败` : ''}`);
|
||||
} else {
|
||||
createMessage.warning('添加协作人失败');
|
||||
}
|
||||
const itemsToAdd = [...pendingAddList.value];
|
||||
const idsToRemove = [...pendingRemoveIds.value];
|
||||
const permsToChange = [...pendingPermissionMap.value];
|
||||
const listId = props.taskListId;
|
||||
|
||||
pendingAddList.value = [];
|
||||
emit('changed');
|
||||
}
|
||||
pendingAddList.value = [];
|
||||
pendingRemoveIds.value.clear();
|
||||
pendingPermissionMap.value.clear();
|
||||
|
||||
visible.value = false;
|
||||
showAddPanel.value = false;
|
||||
addForm.userIds = '';
|
||||
addForm.permission = '2';
|
||||
|
||||
if (!hasChanges) return;
|
||||
|
||||
const suppressOptions = { successMessageMode: 'none' as const };
|
||||
let errorMsg = '';
|
||||
|
||||
(async () => {
|
||||
for (const item of itemsToAdd) {
|
||||
try {
|
||||
await addCollaborator(
|
||||
{ taskListId: listId, userId: item.userId, permission: item.permission },
|
||||
suppressOptions,
|
||||
);
|
||||
} catch {
|
||||
errorMsg = '部分协作人添加失败';
|
||||
}
|
||||
}
|
||||
|
||||
for (const permissionId of idsToRemove) {
|
||||
try {
|
||||
await removeCollaborator({ permissionId }, suppressOptions);
|
||||
} catch {
|
||||
errorMsg = '部分协作人移除失败';
|
||||
}
|
||||
}
|
||||
|
||||
for (const [permissionId, newPermission] of permsToChange) {
|
||||
try {
|
||||
await updateCollaboratorPermission({ permissionId, permission: newPermission }, suppressOptions);
|
||||
} catch {
|
||||
errorMsg = '部分权限修改失败';
|
||||
}
|
||||
}
|
||||
|
||||
await loadCollaborators();
|
||||
emit('changed', collaboratorNamesSnapshot.value);
|
||||
|
||||
if (errorMsg) {
|
||||
createMessage.warning(errorMsg);
|
||||
} else {
|
||||
createMessage.success('编辑成功');
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
async function onRemove(permissionId: string) {
|
||||
try {
|
||||
await removeCollaborator({ permissionId });
|
||||
await loadCollaborators();
|
||||
emit('changed');
|
||||
} catch (e: any) {
|
||||
createMessage.error(e?.message || '移除失败');
|
||||
}
|
||||
function onRemove(permissionId: string) {
|
||||
pendingRemoveIds.value.add(permissionId);
|
||||
}
|
||||
|
||||
async function onPermissionChange(permissionId: string, newPermission: string) {
|
||||
try {
|
||||
await updateCollaboratorPermission({ permissionId, permission: newPermission });
|
||||
await loadCollaborators();
|
||||
emit('changed');
|
||||
} catch (e: any) {
|
||||
createMessage.error(e?.message || '修改失败');
|
||||
}
|
||||
function onPermissionChange(permissionId: string, newPermission: string) {
|
||||
pendingPermissionMap.value.set(permissionId, newPermission);
|
||||
}
|
||||
|
||||
defineExpose({ open });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" destroy-on-close title="创建清单" :width="500" @ok="handleSubmit">
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" destroy-on-close title="创建计划" :width="500" @ok="handleSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" destroy-on-close title="创建任务" :width="600" @ok="handleSubmit">
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" destroy-on-close title="创建事项" :width="600" @ok="handleSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
<div class="attachment-row">
|
||||
<span class="attachment-label">附件</span>
|
||||
@@ -58,7 +58,7 @@
|
||||
if (values.assigneeId) {
|
||||
const { ok, invalidNames } = await checkUserSecLevel(values.assigneeId, currentSecretLevel.value);
|
||||
if (!ok) {
|
||||
message.warning(`以下人员的密级不满足当前清单(${currentSecretText.value})要求:${invalidNames.join('、')}`);
|
||||
message.warning(`以下人员的密级不满足当前计划(${currentSecretText.value})要求:${invalidNames.join('、')}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="task-content">
|
||||
<div class="content-header">
|
||||
<template v-if="showListGroupView">
|
||||
<h2 class="content-title">任务清单</h2>
|
||||
<h2 class="content-title">计划列表</h2>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="content-header-left">
|
||||
@@ -16,7 +16,7 @@
|
||||
@blur="confirmHeaderRename"
|
||||
/>
|
||||
</div>
|
||||
<h2 v-else class="content-title">{{ currentList?.name || '请选择清单' }}</h2>
|
||||
<h2 v-else class="content-title">{{ currentList?.name || '请选择计划' }}</h2>
|
||||
<a-dropdown v-if="currentList && canShowHeaderMore" :trigger="['click']">
|
||||
<a-button type="text" size="small" class="header-more-btn">
|
||||
<Icon icon="ant-design:ellipsis-outlined" />
|
||||
@@ -39,7 +39,7 @@
|
||||
<span v-if="currentList.secretText" class="header-secret-badge" :style="{ color: SECRET_LEVEL_COLOR[currentList.secretLevel || 1] || '#8c8c8c', borderColor: SECRET_LEVEL_COLOR[currentList.secretLevel || 1] || '#8c8c8c' }">
|
||||
{{ currentList.secretText }}
|
||||
</span>
|
||||
<div class="collaborator-bar" @click="emit('open-collaborator')">
|
||||
<div class="collaborator-bar" :class="{ disabled: !_isOwner }" @click="_isOwner && emit('open-collaborator')">
|
||||
<AvatarDisplay
|
||||
v-if="collaboratorDisplayNames"
|
||||
:names="collaboratorDisplayNames"
|
||||
@@ -60,7 +60,7 @@
|
||||
<a-dropdown>
|
||||
<template #overlay>
|
||||
<a-menu @click="onStatusFilterChange">
|
||||
<a-menu-item key="all" :class="{ 'ant-dropdown-menu-item-selected': statusFilter === 'all' }">全部清单</a-menu-item>
|
||||
<a-menu-item key="all" :class="{ 'ant-dropdown-menu-item-selected': statusFilter === 'all' }">全部</a-menu-item>
|
||||
<a-menu-item key="completed" :class="{ 'ant-dropdown-menu-item-selected': statusFilter === 'completed' }">已完成</a-menu-item>
|
||||
<a-menu-item key="uncompleted" :class="{ 'ant-dropdown-menu-item-selected': statusFilter === 'uncompleted' }">未完成</a-menu-item>
|
||||
</a-menu>
|
||||
@@ -269,13 +269,13 @@
|
||||
</template>
|
||||
<span v-else class="field-placeholder">-</span>
|
||||
</div>
|
||||
<div class="list-group-col list-group-col-collaborators">
|
||||
<div class="list-group-col list-group-col-collaborators clickable" @click.stop="emit('open-collaborator-for-list', list.id)">
|
||||
<template v-if="getAllCollaborators(list)">
|
||||
<a-tooltip :title="getAllCollaborators(list)" placement="top"
|
||||
><AvatarDisplay :names="getAllCollaborators(list)" :size="24" :show-name="false"
|
||||
/></a-tooltip>
|
||||
<a-tooltip title="点击管理协作者" placement="top">
|
||||
<AvatarDisplay :names="getAllCollaborators(list)" :size="24" :show-name="getCollaboratorCount(list) === 1" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<span v-else class="field-placeholder">-</span>
|
||||
<Icon v-else icon="tasklist-add-user|svg" class="collab-add-icon" />
|
||||
</div>
|
||||
<div class="list-group-col list-group-col-secret">
|
||||
<span
|
||||
@@ -293,7 +293,7 @@
|
||||
</div>
|
||||
<div v-if="allTaskLists.length === 0" class="empty-state">
|
||||
<Icon icon="ant-design:inbox-outlined" class="empty-icon" />
|
||||
<p>暂无任务清单</p>
|
||||
<p>暂无可见计划</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -303,7 +303,7 @@
|
||||
<div class="table-col table-col-drag-handle"></div>
|
||||
<div class="table-col table-col-title">
|
||||
<Icon icon="tasklist-title|svg" class="header-icon" />
|
||||
<span class="header-label">任务标题</span>
|
||||
<span class="header-label">事项标题</span>
|
||||
</div>
|
||||
<template v-for="field in visibleFieldConfigs" :key="field.key">
|
||||
<div class="table-col header-col" :style="{ width: fieldWidthMap[field.key] || '100px' }">
|
||||
@@ -387,7 +387,7 @@
|
||||
<span
|
||||
v-if="canEdit && groupDimension === 'custom'"
|
||||
class="group-action-btn group-action-add"
|
||||
title="新建任务"
|
||||
title="新建事项"
|
||||
@click.stop="showNewTaskInput = group.id"
|
||||
>
|
||||
<Icon icon="ant-design:plus-outlined" />
|
||||
@@ -744,7 +744,7 @@
|
||||
ref="newTaskInputRef"
|
||||
v-model:value="newTaskTitle"
|
||||
size="small"
|
||||
placeholder="输入任务标题,按回车确认..."
|
||||
placeholder="输入事项标题,按回车确认..."
|
||||
autofocus
|
||||
@press-enter="submitNewTask(group.id)"
|
||||
@blur="submitNewTask(group.id)"
|
||||
@@ -764,7 +764,7 @@
|
||||
<span class="expand-arrow-placeholder"></span>
|
||||
</div>
|
||||
<Icon icon="ant-design:plus-outlined" class="new-task-plus" />
|
||||
<span class="new-task-text">新建任务</span>
|
||||
<span class="new-task-text">新建事项</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -793,7 +793,7 @@
|
||||
|
||||
<div v-else class="empty-state">
|
||||
<Icon icon="ant-design:inbox-outlined" class="empty-icon" />
|
||||
<p>请从左侧选择一个任务清单</p>
|
||||
<p>请从左侧选择一个计划</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -864,6 +864,7 @@
|
||||
'update:list-group-tab': [value: string];
|
||||
'list-select': [listId: string];
|
||||
'open-collaborator': [];
|
||||
'open-collaborator-for-list': [listId: string];
|
||||
'add-to-favorites': [taskListId: string];
|
||||
'remove-from-favorites': [favoriteId: string];
|
||||
'move-task': [taskId: string, targetPid: string, targetSortOrder: number];
|
||||
@@ -920,7 +921,7 @@
|
||||
|
||||
function showDragBlockedMessage() {
|
||||
import('ant-design-vue').then(({ message }) => {
|
||||
message.warning('子任务只能在当前父任务下移动');
|
||||
message.warning('子事项只能在当前父事项下移动');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -981,6 +982,12 @@
|
||||
return names.join(',');
|
||||
}
|
||||
|
||||
function getCollaboratorCount(list: TaskList): number {
|
||||
const names = getAllCollaborators(list);
|
||||
if (!names) return 0;
|
||||
return names.split(/[,,、]/).filter(Boolean).length;
|
||||
}
|
||||
|
||||
function getFormattedCreateTime(list: TaskList): string {
|
||||
if (list.createTimeStr) {
|
||||
return list.createTimeStr;
|
||||
@@ -1137,6 +1144,10 @@
|
||||
const canEdit = computed(() => props.currentList?.myPermission === '1' || props.currentList?.myPermission === '2');
|
||||
const isReadOnly = computed(() => props.currentList?.myPermission === '3');
|
||||
|
||||
function isListOwner(list: TaskList): boolean {
|
||||
return list.myPermission === '1';
|
||||
}
|
||||
|
||||
const canShowHeaderMore = computed(() => {
|
||||
if (!props.currentList) return false;
|
||||
const perm = props.currentList.myPermission;
|
||||
@@ -1162,7 +1173,7 @@
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '删除任务清单后,其下所有任务也将被删除,确定要删除吗?',
|
||||
content: '删除计划后,其下所有事项也将被删除,确定要删除吗?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
@@ -1238,7 +1249,7 @@
|
||||
};
|
||||
|
||||
const statusFilterLabel = computed(() => {
|
||||
const map: Record<StatusFilter, string> = { all: '全部清单', completed: '已完成', uncompleted: '未完成' };
|
||||
const map: Record<StatusFilter, string> = { all: '全部', completed: '已完成', uncompleted: '未完成' };
|
||||
return map[props.statusFilter];
|
||||
});
|
||||
|
||||
@@ -1780,7 +1791,7 @@
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '删除分组后,分组内的任务将合并到默认分组,确定要删除吗?',
|
||||
content: '删除分组后,分组内的事项将合并到默认分组,确定要删除吗?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
@@ -1889,6 +1900,16 @@
|
||||
border-color: #d0d0d0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
|
||||
&:hover {
|
||||
border-color: #e8e8e8;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.collab-btn {
|
||||
@@ -2676,6 +2697,29 @@
|
||||
.list-group-col-collaborators {
|
||||
width: 120px;
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
&.clickable {
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: background 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: #f0f5ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.collab-add-icon {
|
||||
font-size: 20px;
|
||||
color: #bfbfbf;
|
||||
transition: color 0.15s;
|
||||
|
||||
.clickable:hover & {
|
||||
color: #3370ff;
|
||||
}
|
||||
}
|
||||
|
||||
.list-group-col-secret {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<div class="detail-toolbar">
|
||||
<a-button size="small" :type="taskData.completed ? 'primary' : 'default'" :disabled="isFullReadOnly" @click="toggleComplete">
|
||||
<Icon icon="ant-design:check-outlined" class="mr-1" />
|
||||
{{ taskData.completed ? '已完成' : '完成任务' }}
|
||||
{{ taskData.completed ? '已完成' : '完成事项' }}
|
||||
</a-button>
|
||||
<div class="toolbar-spacer"></div>
|
||||
<div class="toolbar-actions">
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<div v-if="parentTask && parentTask.completed" class="detail-parent-completed-notice">
|
||||
<Icon icon="ant-design:info-circle-outlined" />
|
||||
<span>该任务的上级任务已被完成</span>
|
||||
<span>该事项的上级事项已被完成</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-parent-nav" v-if="taskPath.length > 1">
|
||||
@@ -59,7 +59,7 @@
|
||||
size="large"
|
||||
:bordered="true"
|
||||
class="detail-title-input"
|
||||
placeholder="请输入任务标题"
|
||||
placeholder="请输入事项标题"
|
||||
@blur="onTitleBlur"
|
||||
@press-enter="editingTitle = false"
|
||||
/>
|
||||
@@ -254,12 +254,12 @@
|
||||
<span class="feishu-subtask-icon">
|
||||
<Icon icon="tasklist-subtask|svg" />
|
||||
</span>
|
||||
<span class="feishu-subtask-title">子任务</span>
|
||||
<span class="feishu-subtask-title">子事项</span>
|
||||
<span v-if="subtaskProgress.text" class="feishu-subtask-count">{{ subtaskProgress.text }}</span>
|
||||
<div v-if="subtaskProgress.text" class="feishu-subtask-progress">
|
||||
<div class="feishu-subtask-progress-bar" :style="{ width: subtaskProgress.percent + '%' }"></div>
|
||||
</div>
|
||||
<span v-if="!canAddSubTask" class="feishu-subtask-limit">当前最多创建{{ MAX_TASK_DEPTH }}层任务</span>
|
||||
<span v-if="!canAddSubTask" class="feishu-subtask-limit">当前最多创建{{ MAX_TASK_DEPTH }}层事项</span>
|
||||
<Icon v-if="canAddSubTask" :icon="subtaskExpanded ? 'ant-design:down-outlined' : 'ant-design:right-outlined'" class="feishu-subtask-arrow" />
|
||||
</div>
|
||||
|
||||
@@ -325,7 +325,7 @@
|
||||
<a-input
|
||||
v-model:value="newSubTaskName"
|
||||
size="small"
|
||||
placeholder="输入子任务标题,按回车确认..."
|
||||
placeholder="输入子事项标题,按回车确认..."
|
||||
autofocus
|
||||
class="feishu-subtask-input"
|
||||
@press-enter="handleSubmitSubTask"
|
||||
@@ -334,7 +334,7 @@
|
||||
</div>
|
||||
<div v-else-if="canAddSubTask && !isFullReadOnly" class="feishu-subtask-add" @click="showNewSubTaskInput = true">
|
||||
<Icon icon="ant-design:plus-outlined" class="feishu-subtask-add-icon" />
|
||||
<span>添加子任务</span>
|
||||
<span>添加子事项</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -628,7 +628,7 @@
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '删除后无法恢复,确定要删除这个任务吗?',
|
||||
content: '删除后无法恢复,确定要删除这个事项吗?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<a-dropdown>
|
||||
<template #overlay>
|
||||
<a-menu @click="onStatusFilterChange">
|
||||
<a-menu-item key="all" :class="{ 'ant-dropdown-menu-item-selected': statusFilter === 'all' }">全部任务</a-menu-item>
|
||||
<a-menu-item key="all" :class="{ 'ant-dropdown-menu-item-selected': statusFilter === 'all' }">全部事项</a-menu-item>
|
||||
<a-menu-item key="completed" :class="{ 'ant-dropdown-menu-item-selected': statusFilter === 'completed' }">已完成</a-menu-item>
|
||||
<a-menu-item key="uncompleted" :class="{ 'ant-dropdown-menu-item-selected': statusFilter === 'uncompleted' }">未完成</a-menu-item>
|
||||
</a-menu>
|
||||
@@ -79,7 +79,7 @@
|
||||
<div class="table-col table-col-drag-handle"></div>
|
||||
<div class="table-col table-col-title">
|
||||
<Icon icon="tasklist-title|svg" class="header-icon" />
|
||||
<span class="header-label">任务标题</span>
|
||||
<span class="header-label">事项标题</span>
|
||||
</div>
|
||||
<template v-for="field in visibleFieldConfigs" :key="field.key">
|
||||
<div class="table-col header-col" :style="{ width: fieldWidthMap[field.key] || '100px' }">
|
||||
@@ -331,7 +331,7 @@
|
||||
|
||||
<div v-if="flattenedTasks.length === 0" class="empty-state">
|
||||
<Icon icon="ant-design:inbox-outlined" class="empty-icon" />
|
||||
<p>暂无任务</p>
|
||||
<p>暂无事项</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -436,7 +436,7 @@
|
||||
});
|
||||
|
||||
const statusFilterLabel = computed(() => {
|
||||
const map: Record<StatusFilter, string> = { all: '全部任务', completed: '已完成', uncompleted: '未完成' };
|
||||
const map: Record<StatusFilter, string> = { all: '全部事项', completed: '已完成', uncompleted: '未完成' };
|
||||
return map[props.statusFilter];
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<BasicForm @register="registerForm" ref="formRef" />
|
||||
<!-- 子表单区域 -->
|
||||
<a-tabs v-model:activeKey="activeKey" animated @change="handleChangeTabs">
|
||||
<a-tab-pane tab="工作任务清单详情" key="taskListDetial" :forceRender="true">
|
||||
<a-tab-pane tab="计划详情" key="taskListDetial" :forceRender="true">
|
||||
<JVxeTable
|
||||
keep-source
|
||||
resizable
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<BasicForm @register="registerForm" ref="formRef" name="TaskListForm" />
|
||||
<!-- 子表单区域 -->
|
||||
<a-tabs v-model:activeKey="activeKey" animated @change="handleChangeTabs">
|
||||
<a-tab-pane tab="工作任务清单详情" key="taskListDetial" :forceRender="true">
|
||||
<a-tab-pane tab="计划详情" key="taskListDetial" :forceRender="true">
|
||||
<JVxeTable
|
||||
keep-source
|
||||
resizable
|
||||
|
||||
@@ -1,33 +1,11 @@
|
||||
<template>
|
||||
<div class="task-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<span class="sidebar-title">
|
||||
<Icon icon="ant-design:menu-outlined" class="mr-1" />
|
||||
任务
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-nav">
|
||||
<div
|
||||
v-for="item in NAV_ITEMS"
|
||||
:key="item.id"
|
||||
class="sidebar-item"
|
||||
:class="{ active: currentView === item.id }"
|
||||
@click="emit('view-select', item.id)"
|
||||
>
|
||||
<Icon :icon="item.icon" class="sidebar-item-icon" />
|
||||
<span>{{ item.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-divider"></div>
|
||||
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-quick-header" @click="quickAccessExpanded = !quickAccessExpanded">
|
||||
<Icon icon="tasklist-arrow-down|svg" class="quick-access-arrow" :class="{ expanded: quickAccessExpanded }" />
|
||||
<span class="sidebar-quick-title">快速访问</span>
|
||||
<div class="sidebar-quick-header" @click="planExpanded = !planExpanded">
|
||||
<Icon icon="tasklist-arrow-down|svg" class="quick-access-arrow" :class="{ expanded: planExpanded }" />
|
||||
<span class="sidebar-quick-title">计划总览</span>
|
||||
</div>
|
||||
<template v-if="quickAccessExpanded">
|
||||
<template v-if="planExpanded">
|
||||
<div
|
||||
v-for="item in QUICK_ACCESS_ITEMS"
|
||||
:key="item.id"
|
||||
@@ -43,17 +21,38 @@
|
||||
|
||||
<div class="sidebar-divider"></div>
|
||||
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-quick-header" @click="taskExpanded = !taskExpanded">
|
||||
<Icon icon="tasklist-arrow-down|svg" class="quick-access-arrow" :class="{ expanded: taskExpanded }" />
|
||||
<span class="sidebar-quick-title">事项总览</span>
|
||||
</div>
|
||||
<template v-if="taskExpanded">
|
||||
<div
|
||||
v-for="item in NAV_ITEMS"
|
||||
:key="item.id"
|
||||
class="sidebar-item sidebar-quick-access-sub"
|
||||
:class="{ active: currentView === item.id }"
|
||||
@click="emit('view-select', item.id)"
|
||||
>
|
||||
<Icon :icon="item.icon" class="sidebar-item-icon" />
|
||||
<span>{{ item.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-divider"></div>
|
||||
|
||||
<div class="sidebar-section sidebar-lists-section">
|
||||
<div class="sidebar-favorites-header">
|
||||
<Icon icon="tasklist-task-list|svg" class="sidebar-favorites-icon" />
|
||||
<span class="sidebar-favorites-name">收藏清单</span>
|
||||
<span class="sidebar-favorites-name">常用计划</span>
|
||||
<a-dropdown :trigger="['click']">
|
||||
<Icon icon="ant-design:plus-outlined" class="sidebar-group-add" @click.stop />
|
||||
<template #overlay>
|
||||
<a-menu @click="onAddMenuClick">
|
||||
<a-menu-item key="new-list">
|
||||
<Icon icon="ant-design:file-add-outlined" class="mr-1" />
|
||||
新建清单
|
||||
新建计划
|
||||
</a-menu-item>
|
||||
<a-menu-item key="new-group">
|
||||
<Icon icon="ant-design:folder-add-outlined" class="mr-1" />
|
||||
@@ -190,7 +189,7 @@
|
||||
v-if="getLocalGroupTaskLists(group).length === 0"
|
||||
class="sidebar-empty-hint"
|
||||
>
|
||||
可拖拽清单加入该分组
|
||||
可拖拽计划加入该分组
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -258,7 +257,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
const quickAccessExpanded = ref(true);
|
||||
const planExpanded = ref(true);
|
||||
const taskExpanded = ref(true);
|
||||
|
||||
const ungroupedTaskLists = computed(() => {
|
||||
const group = props.taskListGroups.find((g) => g.id === '__ungrouped__');
|
||||
@@ -424,7 +424,7 @@
|
||||
createConfirm({
|
||||
iconType: 'warning',
|
||||
title: '确认移除',
|
||||
content: '确定从收藏清单中移除吗?',
|
||||
content: '确定从常用计划移除吗?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
const { ok, invalidNames } = await checkUserSecLevel(addForm.userIds, secretLevel);
|
||||
if (!ok) {
|
||||
const map: Record<number, string> = { 1: '非密', 2: '内部', 3: '秘密', 4: '机密' };
|
||||
message.warning(`以下人员的密级不满足当前清单(${map[secretLevel] || '非密'})要求:${invalidNames.join('、')}`);
|
||||
message.warning(`以下人员的密级不满足当前计划(${map[secretLevel] || '非密'})要求:${invalidNames.join('、')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user