feat:排序处理,添加计划名称前缀组件

This commit is contained in:
1708-huayu 2025-07-31 19:18:20 +08:00
parent 88777b39be
commit b90b63853f
11 changed files with 125 additions and 38 deletions

View File

@ -1,16 +1,9 @@
import React, {CSSProperties, Fragment, useState} from "react"; import React, {CSSProperties, Fragment, useEffect, useState} from "react";
import {DragDropContext, Droppable, Draggable, DropResult, DraggingStyle, NotDraggingStyle} from "react-beautiful-dnd"; import {DragDropContext, Droppable, Draggable, DropResult, DraggingStyle, NotDraggingStyle} from "react-beautiful-dnd";
import {TaskStepSortVO} from "@/components/type/TaskSort.d"; import {TaskStepSortVO} from "@/components/type/TaskSort.d";
import {Button, Drawer, Modal} from "antd"; import {Button, Drawer, message, Modal} from "antd";
import TextArea from "antd/es/input/TextArea"; import TextArea from "antd/es/input/TextArea";
import {addStepItemAPI} from "@/components/service/StepSort";
// fake data generator
const getItems = (count: number, offset = 0) =>
Array.from({length: count}, (v, k) => k).map(k => ({
id: `item-${k + offset}-${new Date().getTime()}`,
stepDesc: `item ${k + offset}`,
sortIndex: k + offset,
}));
const reorder = (list: TaskStepSortVO[], startIndex: number, endIndex: number) => { const reorder = (list: TaskStepSortVO[], startIndex: number, endIndex: number) => {
const result = Array.from(list); const result = Array.from(list);
@ -34,11 +27,23 @@ const getListStyle = (isDraggingOver: boolean) => ({
width: "100%" width: "100%"
}); });
const StepSort = (props: { taskId: string }) => { const StepSort = (props: { taskId: string, stepList: TaskStepSortVO[] }) => {
const [state, setState] = useState<TaskStepSortVO[]>(getItems(5, 10)); const [state, setState] = useState<TaskStepSortVO[]>(props.stepList);
// 抽屉 start // 抽屉 start
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [dialogueOpen, setDialogueOpen] = useState(false); const [dialogueOpen, setDialogueOpen] = useState(false);
const [sortItemList, setSortItemList] = useState<TaskStepSortVO[]>([]);
const [modalText, setModalText] = useState<TaskStepSortVO>({
id: "",
stepDesc: undefined,
sortIndex: undefined,
taskId: props.taskId,
});
useEffect(() => {
// 根据任务id查找步骤
}, []);
function onDragEnd(result: DropResult) { function onDragEnd(result: DropResult) {
const {source, destination} = result; const {source, destination} = result;
@ -50,16 +55,64 @@ const StepSort = (props: { taskId: string }) => {
let newState = [...state]; let newState = [...state];
newState = items; newState = items;
setState(newState); setState(newState);
props.stepList.length=0
props.stepList.push(...newState)
}
const [confirmButtonLoading, setConfirmButtonLoading] = useState(false);
const confirmModalTextArea = () => {
setConfirmButtonLoading(true)
addStepItemAPI(modalText).then(res => {
if (res.data.status.success) {
message.info("添加步骤成功")
setModalText(
{...modalText, stepDesc: undefined})
setState([...state, res.data.data])
props.stepList.length=0
props.stepList.push(...state, res.data.data)
setDialogueOpen(false);
} else {
message.error(res.data.status.message)
}
}).finally(()=>{
setConfirmButtonLoading(false)
})
} }
return ( return (
<Fragment> <Fragment>
<Modal <Modal
title={`步骤`}
closable={false} closable={false}
open={dialogueOpen} open={dialogueOpen}
confirmLoading={confirmButtonLoading}
onCancel={
() => {
setDialogueOpen(false);
}
}
destroyOnClose={true}
onOk={confirmModalTextArea}
> >
<TextArea autoSize={{ minRows: 4, maxRows: 20 }} placeholder="最大长度255" maxLength={255} autoFocus /> <TextArea autoSize={{minRows: 4, maxRows: 20}}
placeholder="最大长度255"
showCount
styles={{
count: {
// color:"red",
bottom: "0px"
}
}}
value={modalText.sortIndex}
maxLength={255} autoFocus
onChange={(e) => setModalText(
{...modalText, stepDesc: e.target.value})}
onKeyDown={event => {
if (event.ctrlKey && event.key === 'Enter') {
confirmModalTextArea();
}
}}
/>
</Modal> </Modal>
<Button type={open ? "primary" : "default"} onClick={() => setOpen(!open)}> <Button type={open ? "primary" : "default"} onClick={() => setOpen(!open)}>
@ -107,16 +160,13 @@ const StepSort = (props: { taskId: string }) => {
{`步骤${index + 1}`} {`步骤${index + 1}`}
</div> </div>
<div <div
style={{
display: "flex",
justifyContent: "space-around",
border: "solid",
borderRadius: grid * 2,
}}
> >
<div style={{whiteSpace: 'pre-line',border: "solid",
borderRadius: grid,}}>
{item.stepDesc} {item.stepDesc}
</div> </div>
</div> </div>
</div>
)} )}
</Draggable> </Draggable>
))} ))}

View File

@ -0,0 +1,24 @@
import {TaskMessage} from "@/lib/definitions";
import React, {Fragment} from "react";
const TaskNameAndIcon = (props: {task:TaskMessage}) => {
return (<Fragment>
{props.task.fId &&
<svg className="icon" aria-hidden="true">
<use xlinkHref="#icon-tuandui"></use>
</svg>
}
{props.task.taskType == '2' &&
<svg className="icon" aria-hidden="true">
<use xlinkHref="#icon-youxuliebiao"></use>
</svg>
}
{props.task.taskType == '3' &&
<svg className="icon" aria-hidden="true">
<use xlinkHref="#icon-dingshi"></use>
</svg>
}
<text>{props.task.name}</text>
</Fragment>)
}
export default TaskNameAndIcon;

View File

@ -0,0 +1,9 @@
import {AxiosResponse} from "axios";
import {ResponseVO} from "@/lib/definitions";
import {httpReq} from "@/utils/axiosReq";
import {TaskStepSortVO} from "@/components/type/TaskSort.d";
export const addStepItemAPI= (data:TaskStepSortVO):Promise<AxiosResponse<ResponseVO<TaskStepSortVO>>> =>{
return httpReq.post(process.env.NEXT_PUBLIC_TODO_REQUEST_URL + `/task/step/sort/item`,
data)
}

View File

@ -1,5 +1,6 @@
export type TaskStepSortVO = { export type TaskStepSortVO = {
id: string, id: string,
sortIndex: number, sortIndex: number|undefined,
stepDesc: string stepDesc: string|undefined,
taskId:string
} }

View File

@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import {Dayjs} from "dayjs"; import {Dayjs} from "dayjs";
import {TaskStepSortVO} from "@/components/type/TaskSort.d";
export type Request<T>={ export type Request<T>={
data:T, data:T,
@ -36,6 +37,7 @@ export type TaskMessage ={
fId?:string; fId?:string;
fName?:string; fName?:string;
taskType?:string; taskType?:string;
stepList?:TaskStepSortVO[];
} }
@ -51,6 +53,7 @@ export type DataType = TaskMessage&{
actualTimeRange?:(string|Dayjs|undefined)[] actualTimeRange?:(string|Dayjs|undefined)[]
children: DataType[]|undefined; children: DataType[]|undefined;
sortNo?:number; sortNo?:number;
} }
export type DictType={ export type DictType={
id:number; id:number;

View File

@ -52,7 +52,7 @@ export async function getTask(id: string): Promise<ResponseVO<DataType>> {
return response.data; return response.data;
} }
export function addTask(task: DataType): Promise<AxiosResponse<ResponseVO<TaskMessage>>> { export function addTask(task: DataType): Promise<AxiosResponse<ResponseVO<DataType>>> {
noStore(); noStore();
// 使用 Axios 发送 POST 请求添加数据 // 使用 Axios 发送 POST 请求添加数据
switch(task.taskType){ switch(task.taskType){

View File

@ -24,7 +24,7 @@ html {
} }
.icon { .icon {
/* em 当前元素的 font-size 值,如果元素没有显式设置 font-size则继承父元素的 font-size。 控制与字体大小相关的属性*/ /* em 当前元素的 font-size 值,如果元素没有显式设置 font-size则继承父元素的 font-size。 控制与字体大小相关的属性*/
width: 1em; width: 2em;
height: 1em; height: 1em;
vertical-align: -0.15em; vertical-align: -0.15em;
fill: currentColor; fill: currentColor;

View File

@ -1,5 +1,5 @@
'use client' 'use client'
import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from "react"; import React, {Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState} from "react";
import {Calendar, dayjsLocalizer, Event, SlotInfo, View} from 'react-big-calendar' import {Calendar, dayjsLocalizer, Event, SlotInfo, View} from 'react-big-calendar'
import dayjs, {Dayjs} from 'dayjs' import dayjs, {Dayjs} from 'dayjs'
import 'react-big-calendar/lib/css/react-big-calendar.css' import 'react-big-calendar/lib/css/react-big-calendar.css'
@ -14,6 +14,8 @@ import LocalContext from "@/ui/LocalContent";
import withDragAndDrop, {EventInteractionArgs} from "react-big-calendar/lib/addons/dragAndDrop"; import withDragAndDrop, {EventInteractionArgs} from "react-big-calendar/lib/addons/dragAndDrop";
import {TaskEvent} from "@/lib/task/calendar/data"; import {TaskEvent} from "@/lib/task/calendar/data";
import {editExpectAPI} from "@/lib/task/calendar/service"; import {editExpectAPI} from "@/lib/task/calendar/service";
import TaskNamePrefixIcon from "@/components/TaskNameAndIcon";
import TaskNameAndIcon from "@/components/TaskNameAndIcon";
/** /**
* https://github.com/jquense/react-big-calendar?tab=readme-ov-file * https://github.com/jquense/react-big-calendar?tab=readme-ov-file
@ -116,7 +118,7 @@ const CalShow: React.FC = () => {
return { return {
start: dayjs(taskState.expectedStartTime).toDate(), start: dayjs(taskState.expectedStartTime).toDate(),
end: dayjs(taskState.expectedEndTime).toDate(), end: dayjs(taskState.expectedEndTime).toDate(),
title: taskState.name, title: <TaskNameAndIcon task={taskState}/>,
resource: taskState.id, resource: taskState.id,
id: taskState.id, id: taskState.id,
state: taskState.state, state: taskState.state,
@ -271,7 +273,7 @@ const CalShow: React.FC = () => {
haveButton={false} haveButton={false}
itemId={itemId} itemId={itemId}
reloadData={reloadData} expectedStartTime={expectedStartTime} reloadData={reloadData} expectedStartTime={expectedStartTime}
closeOpen={()=>setOpen(false)} closeOpen={() => setOpen(false)}
expectedEndTime={expectedEndTime}/>} expectedEndTime={expectedEndTime}/>}
<DragAndDropCalendar <DragAndDropCalendar
// 本地设置 // 本地设置

View File

@ -189,7 +189,7 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
onClick={() => props.closeOpen?.()}></Button>) onClick={() => props.closeOpen?.()}></Button>)
} }
if (taskType == '2') { if (taskType == '2') {
result.push(<StepSort taskId={props.itemId!}/>) result.push(<StepSort taskId={props.itemId!} stepList={requestTask?.stepList||[]}/>)
} }
return result; return result;
}, },
@ -205,9 +205,9 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
// } // }
// return defaultDoms; // return defaultDoms;
const result = defaultDoms.filter(defaultButton => defaultButton.key == 'rest'); const result = defaultDoms.filter(defaultButton => defaultButton.key == 'rest');
if (taskType == '2') { // if (taskType == '2') {
result.push(<StepSort taskId={props.itemId!}/>) // result.push(<StepSort taskId={props.itemId!} stepList={requestTask?.stepList||[]}/>)
} // }
result.push(<Button type="primary" key="create-team" loading={operationRequest} result.push(<Button type="primary" key="create-team" loading={operationRequest}
onClick={() => form.submit()}>{taskType == '1' ? "创建团队" : "确认"} onClick={() => form.submit()}>{taskType == '1' ? "创建团队" : "确认"}
</Button>) </Button>)
@ -270,6 +270,8 @@ export const DetailModelForm: React.FC<DetailModelFormProps> = (props) => {
await addTask(values).then(response => { await addTask(values).then(response => {
console.log('response', response) console.log('response', response)
if (response.data.status.success) { if (response.data.status.success) {
setRequestTask(response.data.data)
message.success(`添加计划${response.data.data.name}成功`) message.success(`添加计划${response.data.data.name}成功`)
// 树任务重新刷新 // 树任务重新刷新
// 四象限任务重新刷新 // 四象限任务重新刷新

View File

@ -20,6 +20,7 @@ import dayjs from "dayjs";
import '@/ui/task/project/TreeTablePro.modules.css' import '@/ui/task/project/TreeTablePro.modules.css'
import {useSearchParams} from "next/navigation"; import {useSearchParams} from "next/navigation";
import {TaskWebSelectVO} from "@/lib/task/project/definitions"; import {TaskWebSelectVO} from "@/lib/task/project/definitions";
import TaskNameAndIcon from "@/components/TaskNameAndIcon";
const TreeTablePro: React.FC = (props:{joinId?:string}) => { const TreeTablePro: React.FC = (props:{joinId?:string}) => {
// 刷新表格 // 刷新表格
@ -55,12 +56,7 @@ const TreeTablePro: React.FC = (props:{joinId?:string}) => {
], ],
}, },
render: (_, record) => { render: (_, record) => {
return <Fragment> return <TaskNameAndIcon task={record}/>
{record.fId && <svg className="icon" aria-hidden="true">
<use xlinkHref="#icon-tuandui"></use>
</svg>}
<text>{record.name}</text>
</Fragment>
} }
}, },
{ {