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 {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";
// 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,
}));
import {addStepItemAPI} from "@/components/service/StepSort";
const reorder = (list: TaskStepSortVO[], startIndex: number, endIndex: number) => {
const result = Array.from(list);
@ -34,11 +27,23 @@ const getListStyle = (isDraggingOver: boolean) => ({
width: "100%"
});
const StepSort = (props: { taskId: string }) => {
const [state, setState] = useState<TaskStepSortVO[]>(getItems(5, 10));
const StepSort = (props: { taskId: string, stepList: TaskStepSortVO[] }) => {
const [state, setState] = useState<TaskStepSortVO[]>(props.stepList);
// 抽屉 start
const [open, setOpen] = 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) {
const {source, destination} = result;
@ -50,16 +55,64 @@ const StepSort = (props: { taskId: string }) => {
let newState = [...state];
newState = items;
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 (
<Fragment>
<Modal
title={`步骤`}
closable={false}
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>
<Button type={open ? "primary" : "default"} onClick={() => setOpen(!open)}>
@ -107,14 +160,11 @@ const StepSort = (props: { taskId: string }) => {
{`步骤${index + 1}`}
</div>
<div
style={{
display: "flex",
justifyContent: "space-around",
border: "solid",
borderRadius: grid * 2,
}}
>
{item.stepDesc}
<div style={{whiteSpace: 'pre-line',border: "solid",
borderRadius: grid,}}>
{item.stepDesc}
</div>
</div>
</div>
)}

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 = {
id: string,
sortIndex: number,
stepDesc: string
sortIndex: number|undefined,
stepDesc: string|undefined,
taskId:string
}

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
'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 dayjs, {Dayjs} from 'dayjs'
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 {TaskEvent} from "@/lib/task/calendar/data";
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
@ -116,7 +118,7 @@ const CalShow: React.FC = () => {
return {
start: dayjs(taskState.expectedStartTime).toDate(),
end: dayjs(taskState.expectedEndTime).toDate(),
title: taskState.name,
title: <TaskNameAndIcon task={taskState}/>,
resource: taskState.id,
id: taskState.id,
state: taskState.state,
@ -271,7 +273,7 @@ const CalShow: React.FC = () => {
haveButton={false}
itemId={itemId}
reloadData={reloadData} expectedStartTime={expectedStartTime}
closeOpen={()=>setOpen(false)}
closeOpen={() => setOpen(false)}
expectedEndTime={expectedEndTime}/>}
<DragAndDropCalendar
// 本地设置

View File

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

View File

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