diff --git a/.gitignore b/.gitignore index dbfa41f..6d250a4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ # next.js /.next/ /out/ - +/docker/out/ # production /build diff --git a/package-lock.json b/package-lock.json index 59be224..f233081 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "react-big-calendar": "^1.12.2", "react-device-detect": "^2.2.3", "react-dom": "^18", + "react-virtualized": "^9.22.6", "sass": "^1.77.3", "tailwindcss": "3.3.3" }, @@ -31,6 +32,7 @@ "@types/react": "^18", "@types/react-big-calendar": "^1.8.9", "@types/react-dom": "^18", + "@types/react-virtualized": "^9.22.2", "@vercel/style-guide": "^5.0.1", "eslint": "^8", "eslint-config-next": "14.2.29", @@ -1647,6 +1649,16 @@ "redux": "^4.0.0" } }, + "node_modules/@types/react-virtualized": { + "version": "9.22.2", + "resolved": "https://registry.npmmirror.com/@types/react-virtualized/-/react-virtualized-9.22.2.tgz", + "integrity": "sha512-0Eg/ME3OHYWGxs+/n4VelfYrhXssireZaa1Uqj5SEkTpSaBu5ctFGOCVxcOqpGXRiEdrk/7uho9tlZaryCIjHA==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -6318,6 +6330,23 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/react-virtualized": { + "version": "9.22.6", + "resolved": "https://registry.npmmirror.com/react-virtualized/-/react-virtualized-9.22.6.tgz", + "integrity": "sha512-U5j7KuUQt3AaMatlMJ0UJddqSiX+Km0YJxSqbAzIiGw5EmNz0khMyqP2hzgu4+QUtm+QPIrxzUX4raJxmVJnHg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "clsx": "^1.0.4", + "dom-helpers": "^5.1.3", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/reactcss": { "version": "1.2.3", "resolved": "https://registry.npmmirror.com/reactcss/-/reactcss-1.2.3.tgz", @@ -8919,6 +8948,16 @@ "redux": "^4.0.0" } }, + "@types/react-virtualized": { + "version": "9.22.2", + "resolved": "https://registry.npmmirror.com/@types/react-virtualized/-/react-virtualized-9.22.2.tgz", + "integrity": "sha512-0Eg/ME3OHYWGxs+/n4VelfYrhXssireZaa1Uqj5SEkTpSaBu5ctFGOCVxcOqpGXRiEdrk/7uho9tlZaryCIjHA==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.8.tgz", @@ -12437,6 +12476,19 @@ } } }, + "react-virtualized": { + "version": "9.22.6", + "resolved": "https://registry.npmmirror.com/react-virtualized/-/react-virtualized-9.22.6.tgz", + "integrity": "sha512-U5j7KuUQt3AaMatlMJ0UJddqSiX+Km0YJxSqbAzIiGw5EmNz0khMyqP2hzgu4+QUtm+QPIrxzUX4raJxmVJnHg==", + "requires": { + "@babel/runtime": "^7.7.2", + "clsx": "^1.0.4", + "dom-helpers": "^5.1.3", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.4" + } + }, "reactcss": { "version": "1.2.3", "resolved": "https://registry.npmmirror.com/reactcss/-/reactcss-1.2.3.tgz", diff --git a/package.json b/package.json index 54133b5..357f44d 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "react-big-calendar": "^1.12.2", "react-device-detect": "^2.2.3", "react-dom": "^18", + "react-virtualized": "^9.22.6", "sass": "^1.77.3", "tailwindcss": "3.3.3" }, @@ -32,6 +33,7 @@ "@types/react": "^18", "@types/react-big-calendar": "^1.8.9", "@types/react-dom": "^18", + "@types/react-virtualized": "^9.22.2", "@vercel/style-guide": "^5.0.1", "eslint": "^8", "eslint-config-next": "14.2.29", diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 863b8d6..cdf367c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -21,8 +21,11 @@ export default function RootLayout({ 任务管理 + {/*FOUC,Flash of Unstyled Content*/} + {/**/} + {/**/} - {children} + {children} ); } diff --git a/src/app/task/drag/layout.tsx b/src/app/task/drag/layout.tsx index 9207eb8..bfad5e6 100644 --- a/src/app/task/drag/layout.tsx +++ b/src/app/task/drag/layout.tsx @@ -2,11 +2,10 @@ * A layout is UI that is shared between multiple routes. On navigation, layouts preserve state, remain interactive, and do not re-render. */ 'use client' -import React, { useState} from 'react'; +import React, {useEffect, useState} from 'react'; import {DragDropContext, DropResult} from 'react-beautiful-dnd'; import {DroppableTable} from "@/ui/task/drag/DroppableTable"; import {DataType, Request} from "@/lib/definitions"; -import {useEffect} from "react"; import {TaskSelectVO} from "@/lib/task/drag/data"; import {selectTaskAPI} from "@/lib/task/drag/service"; @@ -14,13 +13,13 @@ export default function Layout({children}: { children: React.ReactNode }) { const [allTaskList, setAllTaskList] = useState([]); useEffect(() => { addData() - },[]) + }, []) async function addData() { const requestParam: Request = { pageSize: 1000, pageNumber: 1, - data: {state:'9'} + data: {state: '9'} } const res = await selectTaskAPI(requestParam) setAllTaskList(res.data.content) @@ -41,9 +40,8 @@ export default function Layout({children}: { children: React.ReactNode }) { } }; - return ( - -
+ return (
+ {/* 紧急重要 */} task.priority == '3')}/> {/* 不紧急重要 */} @@ -52,7 +50,7 @@ export default function Layout({children}: { children: React.ReactNode }) { task.priority == '1')}/> {/* 不紧急不重要 */} task.priority == '0')}/> -
- - ); +
+ ) + ; } diff --git a/src/app/task/dragtest/page.tsx b/src/app/task/dragtest/page.tsx deleted file mode 100644 index b8f0fd8..0000000 --- a/src/app/task/dragtest/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Page() { - return

Dashboard test

; -} diff --git a/src/lib/task/project/data.tsx b/src/lib/task/project/data.tsx index 139b0ff..3b85a48 100644 --- a/src/lib/task/project/data.tsx +++ b/src/lib/task/project/data.tsx @@ -88,6 +88,15 @@ export async function deleteTaskAPI(id: string): Promise> { return response.data; } +export function getTaskState(code:string){ + return taskStateList.filter(taskState => code==taskState.code)[0]; +} +export const TASK_TYPE:{label:string,value:string}[]=[ + {label:"常规",value:"0"}, + {label:"团队",value:"1"}, + {label:"顺序",value:"2"}, + {label:"周期",value:"3"} +] //0,重要紧急红色,1,重要不紧急黄色,2,不重要紧急灰色,3不重要,不紧急绿色 export const taskPriorityList: DictType[] = [ { diff --git a/src/ui/globals.css b/src/ui/globals.css index 38aba85..32fa431 100644 --- a/src/ui/globals.css +++ b/src/ui/globals.css @@ -30,4 +30,24 @@ html { fill: currentColor; overflow: hidden; padding-right: 0.5em; +} +.displayFlexRow{ + display: flex; + justify-content: flex-start; /* 水平居中 */ + align-items: center; /* 垂直居中 */ +} + +.displayFlexColumn{ + display: flex; + flex-direction: column; + justify-content: flex-start; /* 水平居中 */ + align-items: center; /* 垂直居中 */ +} +.scrollHidden{ + overflow: auto; + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE和Edge */ +} +.scrollHidden::-webkit-scrollbar { + display: none; /* Chrome, Safari, Opera */ } \ No newline at end of file diff --git a/src/ui/task/OperationButton.tsx b/src/ui/task/OperationButton.tsx index bd6c619..73fbea4 100644 --- a/src/ui/task/OperationButton.tsx +++ b/src/ui/task/OperationButton.tsx @@ -163,7 +163,7 @@ class OperationButton extends React.Component四象限显示子任务, + label: 四象限显示子任务, }, { key: OPERATION_BUTTON_TYPE.SHOW_CALENDAR, diff --git a/src/ui/task/TitleOperation.tsx b/src/ui/task/TitleOperation.tsx index 4687f93..0a106f6 100644 --- a/src/ui/task/TitleOperation.tsx +++ b/src/ui/task/TitleOperation.tsx @@ -43,9 +43,9 @@ export const TitleOperation: React.FC = ({ }}>任务树 } { - !usePathname().startsWith("/task/four") && + !usePathname().startsWith("/task/drag") && } @@ -78,7 +78,7 @@ export const TitleOperation: React.FC = ({ } { /*四相线需要状态时间*/ - usePathname().startsWith("/task/four") && + usePathname().startsWith("/task/drag") && 期望开始时间范围: = ({ /> } + { + /*日历需要状态*/ + !usePathname().startsWith("/task/project") && + + + }
- 止:{record.expectedStartTime? dayjs(record.expectedStartTime).format("YYYY-MM-DD HH:mm") : ""} - - )} - - ); - }; - const calculateScrollHeight = () => { - // 计算50%视窗高度减去21px - const height = `calc(50vh - 80px)`; - return { y: height }; - }; + return ( + + {(provided, snapshot) => ( +
+
+ +
{record.name}
+
+
+
+ +
{record.description}
+
+
+
{getTaskState(record.state) ? getTaskState(record.state).name : ""}
+
+
起: {record.expectedStartTime ? dayjs(record.expectedStartTime).format("YYYY-MM-DD HH:mm") : ""}
+
止: {record.expectedStartTime ? dayjs(record.expectedStartTime).format("YYYY-MM-DD HH:mm") : ""}
+
+
+ +
+
+ )} +
+ ); + }, [props.taskList, getItemStyle]); + + const headerStyle = React.useMemo(() => ({ + backgroundColor: taskPriorityList.find((item) => item.code === props.tableCode)?.color, + height: '55px', + borderBottom: '1px solid #f0f0f0', + fontWeight: 'bold' + }), [props.tableCode]); return ( - - {(provided,snapshot) => ( -
+ {(provided, snapshot) => ( +
- item.code === props.tableCode)?.color - /* 这里是你的组件 token */ - }, - }, - }} - > - - dataSource={props.taskList} - scroll={calculateScrollHeight()} - columns={[ - // { - // title: '任务编码', - // dataIndex: 'code', - // key: 'code', - // width: '10%', - // }, - { - title: stateName, - dataIndex: 'name', - key: 'name', - width: '10%', - ellipsis: { - showTitle: false, - }, - render: (address) => ( - - {address} - - ), - }, - { - title: '任务描述', - dataIndex: 'description', - key: 'description', - width: '20%', - ellipsis: { - showTitle: false, - }, - render: (description) => ( - - {description} - - ), - }, - { - title: '任务状态', - dataIndex: 'state', - width: '5%', - key: 'state', - }, - { - title: '期望时间', - dataIndex: 'expectedStartTime', - width: '10%', - key: 'expectedStartTime', - }, - ]} - rowKey="id" - components={{ - body: { - row: renderTableRow(props.taskList, props.tableCode), - }, - }} - pagination={false} - /> + + {/* 表头 */} +
+
{stateName}
+
任务描述
+
任务状态
+
期望时间
+
操作
+
+ {/* 虚拟列表主体 */} +
+ + {({height, width}) => ( + + )} + +
{provided.placeholder}
)} ) -} \ No newline at end of file +}); \ No newline at end of file diff --git a/src/ui/task/drag/index.modules.css b/src/ui/task/drag/index.modules.css index e653f9c..eee2bb2 100644 --- a/src/ui/task/drag/index.modules.css +++ b/src/ui/task/drag/index.modules.css @@ -1,5 +1,36 @@ -.droppable-table{ - width: 50vw; - height: calc(50vh - 21px); - overflow-y: auto; +.droppable-table { + box-sizing: border-box; + border: 1px solid #f0f0f0; + border-radius: 4px; + overflow: hidden; +} + +.virtualized-row { + display: flex; + align-items: center; +} + +.text-ellipsis { + /* 单行省略 */ + /*width: 100%;*/ + /*box-sizing: border-box;*/ + /*white-space: nowrap;*/ + /*overflow: hidden;*/ + /*text-overflow: ellipsis;*/ + + width: 100%; + box-sizing: border-box; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + line-height: 1.5em; /* 根据实际字体大小调整 */ + max-height: 3em; /* 2行 x 1.5em */ + word-break: break-word; /* 允许长单词换行 */ +} + +/* 拖拽时的样式增强 */ +.ReactVirtualized__List { + outline: none; } \ No newline at end of file diff --git a/src/ui/task/project/DetailModelForm.tsx b/src/ui/task/project/DetailModelForm.tsx index f68a2bb..275bc7f 100644 --- a/src/ui/task/project/DetailModelForm.tsx +++ b/src/ui/task/project/DetailModelForm.tsx @@ -11,7 +11,7 @@ import React, {useEffect, useState} from "react"; import { addTask, deleteTask, getTask, getTaskTreeResult, - OPERATION_BUTTON_TYPE, + OPERATION_BUTTON_TYPE, TASK_TYPE, taskPriorityList, taskStateList, updateTask } from "@/lib/task/project/data"; @@ -44,6 +44,8 @@ export const DetailModelForm: React.FC = (props) => { const [form] = Form.useForm(); const [pid, setPid] = useState(props.pid?props.pid:'0'); const [editFormDisable, setEditFormDisable] = useState(props.operationId === OPERATION_BUTTON_TYPE.DETAIL) + // 团队第一层 pid必须为0 + const [taskType, setTaskType] = useState('0') useEffect(() => { if (props.itemId!=undefined&&( props.operationId === OPERATION_BUTTON_TYPE.DETAIL || props.operationId === OPERATION_BUTTON_TYPE.UPDATE)) { @@ -209,8 +211,31 @@ export const DetailModelForm: React.FC = (props) => {