'use client' 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' 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, getTaskTreeResult, OPERATION_BUTTON_TYPE} from "@/lib/task/project/data"; import {useSearchParams} from "next/dist/client/components/navigation"; import {DetailModelForm} from "@/ui/task/project/DetailModelForm"; import {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} 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 * @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 [description, setDescription] = useState(''); const [operationId, setOperationId] = useState(-1); const [itemId, setItemId] = useState('-1'); 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 state = useContext(LocalContext).taskState; 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"}, ); } 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"}, ); } // searchListE.push({name: 'expectedStartTime', value: range.start, operateType: ">="}) // searchListE.push({name: 'expectedStartTime', value: range.end, operateType: "<="}) loadData(searchListE); /** * 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 message = { 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"}) } // 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: Event, e: React.SyntheticEvent) => { clearClickTimeout() clickRef.current = window.setTimeout(() => { // window.alert(event.title); console.log("event") 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(() => { // 数据落库 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) => 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 } 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}/>}
} export default CalShow;