assistant-todo/src/ui/task/calendar/CalShow.tsx

318 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import React, {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 {number} from "prop-types";
import {DATE_TIME} from "@/lib/constants";
/**
* 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<View>('week');
const [date, setDate] = useState<Date>(new Date());
const clickRef = useRef<number|undefined|null>(null)
// 展示在页面的任务,默认获取当前月的信息。
const [events, setEvents] = useState<TaskEvent[]>([]);
const [open, setOpen] = useState(false);
const [description, setDescription] = useState('');
const [operationId, setOperationId] = useState(-1);
const [itemId, setItemId] = useState('-1');
const [expectedStartTime, setExpectedStartTime] = useState<Dayjs>();
const [expectedEndTime, setExpectedEndTime] = useState<Dayjs>();
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<TaskEvent>(taskState => {
return {
start: dayjs(taskState.expectedStartTime).toDate(),
end: dayjs(taskState.expectedEndTime).toDate(),
title: taskState.name,
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<HTMLElement>) => {
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<HTMLElement>) => {
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(
({event, start, end, isAllDay: droppedOnAllDaySlot = false}: EventInteractionArgs<TaskEvent>) => {
console.log("onEventResize || onEventDrop :",start,end)
const {allDay} = event
if (!allDay && droppedOnAllDaySlot) {
event.allDay = true
}
// 数据落库
commonUpdate({
updateColumnList: [{
name: 'expectedStartTime',
code: '',
value: start.toLocaleString()
}, {
name: 'expectedEndTime',
code: '',
value: end.toLocaleString()
}],
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);
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 <div className="App" style={{height: '90vh'}}>
{open && <DetailModelForm operationId={operationId} description={description} open={open} haveButton={false}
itemId={itemId} pid={pid?pid:'0'}
reloadData={reloadData} expectedStartTime={expectedStartTime}
expectedEndTime={expectedEndTime}/>}
<DragAndDropCalendar
// 本地设置
localizer={localizer}
messages={message}
// 修改style
eventPropGetter={eventPropGetter}
events={events}
// 界面
view={view}
// 界面改变
onView={handleViewChange}
onRangeChange={rangeChange}
// 时间
date={date}
// 条目信息改变
onNavigate={handleNavigate}
// 点击
selectable
scrollToTime={scrollToTime}
// 双击
onDoubleClickEvent={doubleClick}
// 点击任务
onSelectEvent={handleSelectEvent}
// 点击空白处
onSelectSlot={handleSelectSlot}
// 改变时间长短
resizable
onEventResize={moveEvent}
onEventDrop={moveEvent}
/>
</div>
}
export default CalShow;