'use client' import React, {Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState} from "react"; import {Calendar, dateFnsLocalizer, dayjsLocalizer, Event, SlotInfo, View} from 'react-big-calendar' import dayjs, {Dayjs} from 'dayjs' import 'react-big-calendar/lib/css/react-big-calendar.css' import 'react-big-calendar/lib/sass/styles.scss' import 'react-big-calendar/lib/addons/dragAndDrop/styles.scss' import '@/ui/task/calendar/index.modules.css' import {commonUpdate, OPERATION_BUTTON_TYPE} from "@/lib/task/project/data"; import {useSearchParams} from "next/dist/client/components/navigation"; import {DetailModelForm} from "@/ui/task/project/DetailModelForm"; import {Request, SearchObject} from "@/lib/definitions"; import LocalContext from "@/ui/LocalContent"; import withDragAndDrop, {EventInteractionArgs} from "react-big-calendar/lib/addons/dragAndDrop"; import {TaskEvent} from "@/lib/task/calendar/data"; import {editExpectAPI, getTaskAndScheduleRecordAPI} from "@/lib/task/calendar/service"; import TaskNameAndIcon from "@/components/TaskNameAndIcon"; import {TaskWebSelectVO} from "@/lib/task/project/definitions"; import {message} from "antd"; import ClickRecord from "@/components/ClickRecord"; import {editClickRecordRangeAPI} from "@/components/service/ScheduleTask"; /** * https://github.com/jquense/react-big-calendar?tab=readme-ov-file * @constructor */ const localizer = dayjsLocalizer(dayjs) const DragAndDropCalendar = withDragAndDrop(Calendar) const CalShow: React.FC = () => { dayjs.locale('zh-cn') const [view, setView] = useState('week'); const [date, setDate] = useState(new Date()); const clickRef = useRef(null) // 展示在页面的任务,默认获取当前月的信息。 const [events, setEvents] = useState([]); const [open, setOpen] = useState(false); const [openClickRecord, setOpenClickRecord] = useState(false); const [description, setDescription] = useState(''); const [operationId, setOperationId] = useState(-1); const [itemId, setItemId] = useState('-1'); const [recordId,setRecordId] = useState(); const [taskName, setTaskName] = useState(""); const [expectedStartTime, setExpectedStartTime] = useState(); const [expectedEndTime, setExpectedEndTime] = useState(); const [range, setRange] = useState<{ start: Date; end: Date }>({ start: dayjs(date).startOf('week').toDate(), end: dayjs(date).endOf('week').toDate() }); const {taskState:state,taskTypeList} = useContext(LocalContext); const [searchObject,setSearchObject] = useState>({ pageSize: 9999, pageNumber: 1, data:{ treeList:true, treeFilter:true, treeOrList:false, expectedStartTime:range.start, expectedEndTime:range.end } }) const handleViewChange = (newView: View) => { setView(newView); }; var pid = useSearchParams().get('pid'); function clearClickTimeout() { clickRef && typeof clickRef.current === 'number' && !isNaN(clickRef.current) && isFinite(clickRef.current) && window.clearTimeout(clickRef.current) } const handleNavigate = (newDate: Date) => { console.log('handleNavigate', newDate) setDate(newDate); const searchList: SearchObject[] = [] if (pid != null) { searchList.push({name: "pid", value: pid, operateType: "="}, {name: 'ALL-CHILD', value: "true", operateType: "ALL-CHILD"}, {name: 'TREE-FILTER', value: "true", operateType: "TREE-FILTER"}, ); searchObject.data.pid=pid setSearchObject({...searchObject}) } loadData(searchList); }; useEffect(() => { console.log("CalShow:useEffect:range", range) // const searchListE = [] if (pid != null) { // searchListE.push( // {name: "pid", value: pid, operateType: "="}, // {name: 'ALL-CHILD', value: "true", operateType: "ALL-CHILD"}, // {name: 'TREE-FILTER', value: "true", operateType: "TREE-FILTER"}, // ); searchObject.data.pid=pid setSearchObject({...searchObject}) } // searchListE.push({name: 'expectedStartTime', value: range.start, operateType: ">="}) // searchListE.push({name: 'expectedStartTime', value: range.end, operateType: "<="}) // loadData(searchListE); loadData() /** * What Is This? * This is to prevent a memory leak, in the off chance that you * teardown your interface prior to the timed method being called. */ return () => { clearClickTimeout() } }, [useContext(LocalContext), range]); const calMessages = { week: '周', work_week: '工作周', day: '天', month: '月', previous: '前', next: '后', today: '当下', agenda: '日程' } const loadData = (searchList?: SearchObject[]) => { if (state.length > 0) { // searchList.push({name: 'state', value: state, operateType: "IN"}) searchObject.data.state=state } if (taskTypeList.length>0){ searchObject.data.taskTypeList=taskTypeList } searchObject.data.expectedStartTime=range.start searchObject.data.expectedEndTime=range.end setSearchObject({...searchObject}) getTaskAndScheduleRecordAPI(searchObject).then(responseD => { if (responseD.status.success) { let result: TaskEvent[] = responseD.data.content.map(taskState => { return { start: dayjs(taskState.expectedStartTime).toDate(), end: dayjs(taskState.expectedEndTime).toDate(), title:
{taskState.description}
, // style: { // backgroundColor: 'green', // color: 'white', // }, name:taskState.name, resource: taskState.id, id: taskState.id, state: taskState.state, priority: taskState.priority, taskType:taskState.taskType } }); console.log('responseD.data.content:', result) setEvents([...result]) } }) // searchList.push({name: 'expectedEndTime', value: dayjs(date).endOf('month'), operateType: "NOT NULL"}) // let request = JSON.stringify({ // pageSize: 9999, // pageNumber: 1, // data: searchList, // startTime: range.start, // // startTime:dayjs(range.start).format('YYYY-MM-DD HH:mm:ss'), // endTime: range.end, // // endTime:dayjs(range.end).format('YYYY-MM-DD HH:mm:ss'), // startColumn: "expected_start_time", // endColumn: "expected_end_time" // }) // getTaskTreeResult(request).then(responseD => { // if (responseD.status.success) { // let result: TaskEvent[] = responseD.data.content.map(taskState => { // return { // start: dayjs(taskState.expectedStartTime).toDate(), // end: dayjs(taskState.expectedEndTime).toDate(), // title: , // resource: taskState.id, // id: taskState.id, // state: taskState.state, // priority: taskState.priority // } // }); // console.log('responseD.data.content:', result) // setEvents([...result]) // } // }) } const reloadData = () => { setOpen(false) handleNavigate(expectedStartTime ? expectedStartTime.toDate() : date) } const handleSelectSlot = useCallback( ({start, end}: SlotInfo) => { setExpectedEndTime(dayjs(end)) setExpectedStartTime(dayjs(start)) setOperationId(OPERATION_BUTTON_TYPE.ADD) setDescription("添加任务") setOpen(true); }, [setEvents] ) const handleSelectEvent = useCallback( (event: TaskEvent, e: React.SyntheticEvent) => { clearClickTimeout() clickRef.current = window.setTimeout(() => { if(event.taskType=='4'){ setTaskName(event.name||"") setRecordId(event.id) setOpenClickRecord(true); }else { setOperationId(OPERATION_BUTTON_TYPE.DETAIL) setDescription("任务详情") setItemId(event.resource) setOpen(true); } }, 250) }, [] ) const {defaultDate, scrollToTime} = useMemo( () => ({ defaultDate: new Date(2015, 3, 12), scrollToTime: new Date(1970, 1, 1, 6), }), [] ) const doubleClick = (event: TaskEvent, e: React.SyntheticEvent) => { clearClickTimeout() clickRef.current = window.setTimeout(() => { if (event.taskType=='4'||event.taskType=='5'){ message.error("计划双击完成,非计划双击无效果。") return; } // 数据落库 commonUpdate({ updateColumnList: [{ name: '任务状态', code: 'state', value: 7 }], conditionColumnList: [{ name: 'id', code: 'id', operateType: '=', value: event.resource }] }) setEvents((prev: TaskEvent[]) => { const existing: TaskEvent | undefined = prev.find((ev: TaskEvent) => ev.resource === event.resource); const filtered: TaskEvent[] | undefined = prev.filter((ev: TaskEvent) => ev.resource !== event.resource); let result: TaskEvent[] = []; if (existing !== undefined && filtered !== undefined) { result = [...filtered, {...existing, state: 7}]; } let strings = state.split(","); console.log('result', result, strings) return result.filter((ev: TaskEvent) => !ev.state || strings.indexOf(ev.state.toString()) >= 0); }) }, 250) } const moveEvent = useCallback( async ({event, start, end, isAllDay: droppedOnAllDaySlot = false}: EventInteractionArgs) => { console.log("onEventResize || onEventDrop :", start, end, event) const {allDay} = event if (!allDay && droppedOnAllDaySlot) { event.allDay = true } if (event.taskType=='4'){ editClickRecordRangeAPI({ id:event.id, startDate:dayjs(start!).toDate(), recordDate:dayjs(end!).toDate(), }); }else { editExpectAPI({ expectedStartTime: start, expectedEndTime: end, id: event.resource }) } setEvents((prev: TaskEvent[]) => { const existing: TaskEvent | undefined = prev.find((ev: TaskEvent) => ev.resource === event.resource); const filtered: TaskEvent[] | undefined = prev.filter((ev: TaskEvent) => ev.resource !== event.resource); if (start instanceof Date && end instanceof Date && existing !== undefined) { return [...filtered, {...existing, start, end, allDay}]; } if (filtered !== undefined) { return [...filtered]; } return []; }) }, [setEvents] ) const eventPropGetter = useCallback( (event: TaskEvent) => ({ ...(event.state === '7' ? {className: 'completeTask'} : event.priority === '3' ? {className: 'importantUrgentTask'} : event.priority === '2' ? {className: 'importantNotUrgentTask'} : event.priority === '1' ? {className: 'notImportantUrgentTask'} : {className: 'notImportantNotUrgentTask'}), }), [setEvents] ) const rangeChange = (rangeLet: Date[] | { start: Date; end: Date }, current?: View | undefined) => { console.log("rangeChange:", rangeLet, (current ? current : view)) // view 为天的时候类型为数组,index:0为当天 if ((current ? current : view) === "day" && Array.isArray(rangeLet)) { if (range.start.valueOf() > rangeLet[0].valueOf()) { setRange({...range, start: rangeLet[0]}) } else if (range.end.valueOf() < rangeLet[0].valueOf()) { setRange({...range, end: rangeLet[0]}) } } // 为周的时候类型为数组,周一到周日七天 if ((current ? current : view) === "week" && Array.isArray(rangeLet)) { if (range.start.valueOf() > rangeLet[0].valueOf()) { setRange({...range, start: rangeLet[0]}) } if (range.end.valueOf() < rangeLet[6].valueOf()) { setRange({...range, end: rangeLet[6]}) } } // 为周的时候类型为对象 if ((current ? current : view) === "month" && rangeLet && !Array.isArray(rangeLet)) { if (range.start.valueOf() > rangeLet.start.valueOf()) { setRange({...range, start: rangeLet.start}) } if (range.end.valueOf() < rangeLet.end.valueOf()) { setRange({...range, end: rangeLet.end}) } } } return
{open && setOpen(false)} expectedEndTime={expectedEndTime}/>} {openClickRecord && }
} export default CalShow;