From c15be6a79bf9cdadcac6f1fe47d85d8ad451d58c Mon Sep 17 00:00:00 2001 From: zhihao <18915542763@163.com> Date: Fri, 1 May 2026 03:10:47 +0800 Subject: [PATCH] =?UTF-8?q?czh-20260501-=E5=A2=9E=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E7=BA=A7=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/tasklist/TaskList.api.ts | 3 + src/views/tasklist/TaskList.data.ts | 35 +- .../tasklist/components/CollaboratorModal.vue | 122 ++++- .../tasklist/components/CreateListModal.vue | 22 +- .../tasklist/components/CreateTaskModal.vue | 62 ++- .../components/TaskAttachmentUpload.vue | 462 ++++++++++++++++++ .../components/TaskAttachmentUploadModal.vue | 253 ++++++++++ src/views/tasklist/components/TaskContent.vue | 44 +- .../tasklist/components/TaskDetailDrawer.vue | 133 +++-- src/views/tasklist/components/TaskSidebar.vue | 46 +- .../tasklist/components/UserSelectModal.vue | 27 +- src/views/tasklist/index.vue | 92 +++- src/views/tasklist/types.ts | 27 + src/views/tasklist/utils/taskUtils.ts | 31 ++ 14 files changed, 1197 insertions(+), 162 deletions(-) create mode 100644 src/views/tasklist/components/TaskAttachmentUpload.vue create mode 100644 src/views/tasklist/components/TaskAttachmentUploadModal.vue diff --git a/src/views/tasklist/TaskList.api.ts b/src/views/tasklist/TaskList.api.ts index c503aaf..9d0648e 100644 --- a/src/views/tasklist/TaskList.api.ts +++ b/src/views/tasklist/TaskList.api.ts @@ -45,6 +45,7 @@ enum Api { listAllByMainId = '/tasklist/taskListDetial/listAllByMainId', myResponsibleTasks = '/tasklist/taskList/myResponsibleTasks', myFollowedTasks = '/tasklist/taskList/myFollowedTasks', + getCurrentUserSecurityLevel = '/tasklist/taskList/getCurrentUserSecurityLevel', } export const getExportUrl = Api.exportXls; @@ -150,3 +151,5 @@ export const listAllByMainId = (params) => defHttp.get({ url: Api.listAllByMainI export const myResponsibleTasks = () => defHttp.get({ url: Api.myResponsibleTasks }); export const myFollowedTasks = () => defHttp.get({ url: Api.myFollowedTasks }); + +export const getCurrentUserSecurityLevel = () => defHttp.get({ url: Api.getCurrentUserSecurityLevel }); diff --git a/src/views/tasklist/TaskList.data.ts b/src/views/tasklist/TaskList.data.ts index 7d2894e..40c50d6 100644 --- a/src/views/tasklist/TaskList.data.ts +++ b/src/views/tasklist/TaskList.data.ts @@ -2,6 +2,7 @@ import { BasicColumn } from '/@/components/Table'; import { FormSchema } from '/@/components/Table'; import { JVxeTypes, JVxeColumn } from '/@/components/jeecg/JVxeTable/types'; import type { TaskListGroup } from './types'; +import { getAvailableSecretLevels } from './types'; export const columns: BasicColumn[] = [ { @@ -300,14 +301,32 @@ export const createTaskFormSchema: FormSchema[] = [ }, ]; -export const createListFormSchema: FormSchema[] = [ - { - label: '清单名称', - field: 'tasklistName', - component: 'Input', - required: true, - }, -]; +export function getCreateListFormSchema(userSecurityLevel: number): FormSchema[] { + if (!userSecurityLevel) userSecurityLevel = 3; + return [ + { + label: '清单名称', + field: 'tasklistName', + component: 'Input', + required: true, + componentProps: { + placeholder: '请输入清单名称', + }, + }, + { + label: '密级', + field: 'secretLevel', + component: 'Select', + required: true, + defaultValue: 1, + componentProps: { + getPopupContainer: () => document.body, + options: getAvailableSecretLevels(userSecurityLevel), + placeholder: '请选择密级', + }, + }, + ]; +} export const mockTaskListGroups: TaskListGroup[] = [ { diff --git a/src/views/tasklist/components/CollaboratorModal.vue b/src/views/tasklist/components/CollaboratorModal.vue index 2e6788d..a3f536b 100644 --- a/src/views/tasklist/components/CollaboratorModal.vue +++ b/src/views/tasklist/components/CollaboratorModal.vue @@ -12,7 +12,7 @@
-
+
{{ (item.username || '?').charAt(0) }}
@@ -26,7 +26,7 @@ - + + diff --git a/src/views/tasklist/components/TaskAttachmentUpload.vue b/src/views/tasklist/components/TaskAttachmentUpload.vue new file mode 100644 index 0000000..07f132a --- /dev/null +++ b/src/views/tasklist/components/TaskAttachmentUpload.vue @@ -0,0 +1,462 @@ + + + + + + diff --git a/src/views/tasklist/components/TaskAttachmentUploadModal.vue b/src/views/tasklist/components/TaskAttachmentUploadModal.vue new file mode 100644 index 0000000..5f5c8fc --- /dev/null +++ b/src/views/tasklist/components/TaskAttachmentUploadModal.vue @@ -0,0 +1,253 @@ + + + + + + diff --git a/src/views/tasklist/components/TaskContent.vue b/src/views/tasklist/components/TaskContent.vue index 9dcef26..f842bc4 100644 --- a/src/views/tasklist/components/TaskContent.vue +++ b/src/views/tasklist/components/TaskContent.vue @@ -36,6 +36,9 @@
+ + {{ currentList.secretText }} +
名称
所有者
协作者
+
密级
创建时间
@@ -273,6 +277,16 @@ -
+
+ + {{ list.secretText }} + + - +
{{ getFormattedCreateTime(list) }}
@@ -790,6 +804,7 @@ :user-ids="userSelectModalCurrentIds" :user-names="userSelectModalCurrentNames" :multiple="true" + :secret-level="currentList?.secretLevel || 1" @confirm="onUserSelectConfirm" />
@@ -804,7 +819,7 @@ import UserSelectModal from './UserSelectModal.vue'; import { useUserStore } from '/@/store/modules/user'; import { useMessage } from '/@/hooks/web/useMessage'; - import { FIELD_CONFIG, GROUP_OPTIONS, SORT_OPTIONS, MAX_TASK_DEPTH, FILTER_FIELD_CONFIGS, FILTER_OPERATOR_LABELS } from '../types'; + import { FIELD_CONFIG, GROUP_OPTIONS, SORT_OPTIONS, MAX_TASK_DEPTH, FILTER_FIELD_CONFIGS, FILTER_OPERATOR_LABELS, SECRET_LEVEL_COLOR } from '../types'; import { PRIORITY_OPTIONS, getPriorityBg, getPriorityLabel, isOverdue } from '../utils/taskUtils'; import type { TaskList, @@ -1851,6 +1866,15 @@ gap: 8px; } + .header-secret-badge { + font-size: 11px; + padding: 0 6px; + border-radius: 3px; + border: 1px solid; + line-height: 18px; + flex-shrink: 0; + } + .collaborator-bar { display: flex; align-items: center; @@ -2150,6 +2174,9 @@ .content-body { flex: 1; overflow: auto; + display: flex; + flex-direction: column; + min-height: 0; } .task-group-header { @@ -2651,6 +2678,21 @@ padding: 0 12px; } + .list-group-col-secret { + width: 80px; + padding: 0 12px; + text-align: center; + } + + .secret-badge-inline { + font-size: 11px; + padding: 1px 6px; + border-radius: 3px; + border: 1px solid; + line-height: 16px; + white-space: nowrap; + } + .list-group-col-time { width: 160px; padding: 0 12px; diff --git a/src/views/tasklist/components/TaskDetailDrawer.vue b/src/views/tasklist/components/TaskDetailDrawer.vue index 060f609..42db2f2 100644 --- a/src/views/tasklist/components/TaskDetailDrawer.vue +++ b/src/views/tasklist/components/TaskDetailDrawer.vue @@ -76,12 +76,19 @@
负责人 -
+
+ + 未指定 +
+
- 添加 -
@@ -94,12 +101,19 @@
参与人 -
+
+ + 未指定 +
+
- 添加 -
@@ -222,7 +236,14 @@
- 添加附件 + 添加附件 +
@@ -323,32 +344,29 @@ - +
+ + 将通知 0 人 +
+ 将通知 0 人 - - -
+ @@ -357,7 +375,8 @@ import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; import Icon from '/@/components/Icon/index'; import AvatarDisplay from './AvatarDisplay.vue'; - import UserSelectModal from './UserSelectModal.vue'; + import SzUserSelectBySecLevel from '/@/components/semri/userComponent/SzUserSelectBySecLevel.vue'; + import TaskAttachmentUpload from './TaskAttachmentUpload.vue'; import TaskDateRangePicker from './TaskDateRangePicker.vue'; import draggable from 'vuedraggable'; import dayjs from 'dayjs'; @@ -412,16 +431,20 @@ const editingSubTaskValue = ref(null); const editingSubTaskStartValue = ref(null); const editingSubTaskEndValue = ref(null); - const subTaskDatePickerOpen = ref(false); const subTaskUserSelectId = ref(''); + const subTaskDatePickerOpen = ref(false); const drawerDatePickerVisible = ref(false); + const drawerDateEditMode = ref<'start' | 'end' | null>(null); const drawerPickerEpoch = ref(0); - const drawerUserSelectRef = ref(); + const currentListSecretLevel = ref(1); + const drawerUserSelectType = ref<'assignee' | 'followers' | 'participant'>('assignee'); - const drawerUserSelectCurrentIds = ref(''); - const drawerUserSelectCurrentNames = ref(''); + const drawerUserSelectCurrentIds = ref(''); + const drawerUserSelectCurrentNames = ref(''); + const userSelectModalRef = ref | null>(null); + const fileUploadRef = ref | null>(null); const parentTask = computed(() => { if (!taskData.value || !taskData.value.pid) return null; @@ -508,6 +531,7 @@ taskData.value = data?.task ? { ...data.task } : null; allTasks.value = data?.allTasks ? [...data.allTasks] : []; isReadOnly.value = data?.readOnly === true; + currentListSecretLevel.value = data?.secretLevel || 1; showNewSubTaskInput.value = false; newSubTaskName.value = ''; editingTitle.value = false; @@ -681,62 +705,71 @@ } function openDrawerUserSelect(type: 'assignee' | 'followers' | 'participant') { + if (!taskData.value) return; drawerUserSelectType.value = type; if (type === 'assignee') { - drawerUserSelectCurrentIds.value = taskData.value?.assigneeId || ''; - drawerUserSelectCurrentNames.value = taskData.value?.assigneeName || ''; + drawerUserSelectCurrentIds.value = taskData.value.assigneeId || ''; + drawerUserSelectCurrentNames.value = taskData.value.assigneeName || ''; } else if (type === 'participant') { - drawerUserSelectCurrentIds.value = taskData.value?.participantId || ''; - drawerUserSelectCurrentNames.value = taskData.value?.participantName || ''; + drawerUserSelectCurrentIds.value = taskData.value.participantId || ''; + drawerUserSelectCurrentNames.value = taskData.value.participantName || ''; } else { - drawerUserSelectCurrentIds.value = taskData.value?.followersId || ''; - drawerUserSelectCurrentNames.value = taskData.value?.followersName || ''; + drawerUserSelectCurrentIds.value = taskData.value.followersId || ''; + drawerUserSelectCurrentNames.value = taskData.value.followersName || ''; } nextTick(() => { - drawerUserSelectRef.value?.open(); + userSelectModalRef.value?.open(); }); } - function onDrawerUserSelectConfirm(userIds: string, userNames: string) { + function onUserSelectModalConfirm(userIds: string, userNames: string) { if (subTaskUserSelectId.value) { - emit('update-sub-task-fields', subTaskUserSelectId.value, { - assigneeId: userIds, - assigneeName: userNames, - }); - const child = allTasks.value.find((t) => t.id === subTaskUserSelectId.value); - if (child) { - child.assigneeId = userIds; - child.assigneeName = userNames; - } - subTaskUserSelectId.value = ''; - return; + onSubTaskUserSelectConfirm(userIds, userNames); + } else { + onDrawerUserSelectConfirm(userIds, userNames); } + } + + function onDrawerUserSelectConfirm(userIds: string, userNames: string) { if (!taskData.value) return; const type = drawerUserSelectType.value; if (type === 'assignee') { taskData.value.assigneeId = userIds; taskData.value.assigneeName = userNames; - autoSave(); } else if (type === 'participant') { taskData.value.participantId = userIds; taskData.value.participantName = userNames; - autoSave(); } else { taskData.value.followersId = userIds; taskData.value.followersName = userNames; - autoSave(); } + autoSave(); } function openSubTaskUserSelect(child: TaskItem) { subTaskUserSelectId.value = child.id; drawerUserSelectCurrentIds.value = child.assigneeId || ''; drawerUserSelectCurrentNames.value = child.assigneeName || ''; + drawerUserSelectType.value = 'assignee'; nextTick(() => { - drawerUserSelectRef.value?.open(); + userSelectModalRef.value?.open(); }); } + function onSubTaskUserSelectConfirm(userIds: string, userNames: string) { + if (!subTaskUserSelectId.value) return; + emit('update-sub-task-fields', subTaskUserSelectId.value, { + assigneeId: userIds, + assigneeName: userNames, + }); + const child = allTasks.value.find((t) => t.id === subTaskUserSelectId.value); + if (child) { + child.assigneeId = userIds; + child.assigneeName = userNames; + } + subTaskUserSelectId.value = ''; + } + function openSubTaskDateEditor(childId: string) { editingSubTask.value = childId; editingSubTaskField.value = 'dateRange'; @@ -780,6 +813,10 @@ showNewSubTaskInput.value = false; } } + + function openFileUploadModal() { + fileUploadRef.value?.handleOpenUploadModal(); + }