Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3b89a88

Browse files
authored
Merge pull request#1369 from lowcoder-org/calendar-updates
Expose toUpdatedEvents, toInsertedEvents, toDeletedEvents + Fixed event drag/drop issues.
2 parentsb06d729 +0ec2a69 commit3b89a88

File tree

2 files changed

+178
-34
lines changed

2 files changed

+178
-34
lines changed

‎client/packages/lowcoder-comps/src/comps/calendarComp/calendarComp.tsx

Lines changed: 175 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import{defaultasForm}from"antd/es/form";
22
import{defaultasInput}from"antd/es/input";
33
import{defaultasColorPicker}from"antd/es/color-picker";
4+
import{defaultasSwitch}from"antd/es/switch";
45
import{trans,getCalendarLocale}from"../../i18n/comps";
56
import{createRef,useContext,useRef,useState,useEffect,useCallback,useMemo,Suspense}from"react";
67
importdayjsfrom"dayjs";
@@ -11,14 +12,15 @@ import adaptivePlugin from "@fullcalendar/adaptive";
1112
importdayGridPluginfrom"@fullcalendar/daygrid";
1213
importmultiMonthPluginfrom'@fullcalendar/multimonth';
1314
importtimeGridPluginfrom"@fullcalendar/timegrid";
14-
importinteractionPluginfrom"@fullcalendar/interaction";
15+
importinteractionPlugin,{EventResizeDoneArg}from"@fullcalendar/interaction";
1516
importlistPluginfrom"@fullcalendar/list";
1617
importallLocalesfrom"@fullcalendar/core/locales-all";
17-
import{EventContentArg,DateSelectArg}from"@fullcalendar/core";
18+
import{EventContentArg,DateSelectArg,EventDropArg}from"@fullcalendar/core";
1819
importmomentPluginfrom"@fullcalendar/moment";
1920

2021
importErrorBoundaryfrom"./errorBoundary";
2122
import{defaultasTabs}from"antd/es/tabs";
23+
import{differenceBy,differenceWith,isEqual,filter,includes}from"lodash";
2224

2325
import{
2426
isValidColor,
@@ -54,6 +56,8 @@ import {
5456
migrateOldData,
5557
controlItem,
5658
depsConfig,
59+
stateComp,
60+
JSONObject,
5761
}from'lowcoder-sdk';
5862

5963
import{
@@ -79,6 +83,7 @@ import {
7983
resourceTimeGridHeaderToolbar,
8084
}from"./calendarConstants";
8185
import{EventOptionControl}from"./eventOptionsControl";
86+
import{EventImpl}from"@fullcalendar/core/internal";
8287

8388
functionfixOldData(oldData:any){
8489
if(!Boolean(oldData))return;
@@ -196,6 +201,10 @@ let childrenMap: any = {
196201
currentPremiumView:dropdownControl(DefaultWithPremiumViewOptions,"resourceTimelineDay"),
197202
animationStyle:styleControl(AnimationStyle,'animationStyle'),
198203
showVerticalScrollbar:withDefault(BoolControl,false),
204+
initialData:stateComp<JSONObject>({}),
205+
updatedEvents:stateComp<JSONObject>({}),
206+
insertedEvents:stateComp<JSONObject>({}),
207+
deletedEvents:stateComp<JSONObject>({}),
199208
};
200209

201210
// this should ensure backwards compatibility with older versions of the SDK
@@ -233,8 +242,9 @@ let CalendarBasicComp = (function () {
233242
currentFreeView?:string;
234243
currentPremiumView?:string;
235244
animationStyle?:any;
236-
modalStyle?:any
237-
showVerticalScrollbar?:boolean
245+
modalStyle?:any;
246+
showVerticalScrollbar?:boolean;
247+
initialData:Array<EventType>;
238248
},dispatch:any)=>{
239249
constcomp=useContext(EditorContext)?.getUICompByName(
240250
useContext(CompNameContext)
@@ -243,11 +253,13 @@ let CalendarBasicComp = (function () {
243253
consttheme=useContext(ThemeContext);
244254
constref=createRef<HTMLDivElement>();
245255
consteditEvent=useRef<EventType>();
256+
constinitData=useRef<boolean>(false);
246257
const[form]=Form.useForm();
247258
const[left,setLeft]=useState<number|undefined>(undefined);
248259
const[licensed,setLicensed]=useState<boolean>(props.licenseKey!=="");
249260
const[currentSlotLabelFormat,setCurrentSlotLabelFormat]=useState(slotLabelFormat);
250-
261+
const[initDataMap,setInitDataMap]=useState<Record<string,number>>({});
262+
251263
useEffect(()=>{
252264
setLicensed(props.licenseKey!=="");
253265
},[props.licenseKey]);
@@ -290,27 +302,53 @@ let CalendarBasicComp = (function () {
290302
start:dayjs(item.start,DateParser).format(),
291303
end:dayjs(item.end,DateParser).format(),
292304
allDay:item.allDay,
293-
resourceId:item.resourceId ?item.resourceId:null,
294-
groupId:item.groupId ?item.groupId:null,
305+
...(item.resourceId ?{resourceId:item.resourceId} :{}),
306+
...(item.groupId ?{groupId:item.groupId} :{}),
295307
backgroundColor:item.backgroundColor,
296-
extendedProps:{
297-
color:isValidColor(item.color||"") ?item.color :theme?.theme?.primary,
298-
...(item.groupId ?{groupId:item.groupId} :{}),// Ensure color is in extendedProps
299-
detail:item.detail,
300-
titleColor:item.titleColor,
301-
detailColor:item.detailColor,
302-
titleFontWeight:item.titleFontWeight,
303-
titleFontStyle:item.titleFontStyle,
304-
detailFontWeight:item.detailFontWeight,
305-
detailFontStyle:item.detailFontStyle,
306-
animation:item?.animation,
307-
animationDelay:item?.animationDelay,
308-
animationDuration:item?.animationDuration,
309-
animationIterationCount:item?.animationIterationCount
310-
}}
308+
extendedProps:{// Ensure color is in extendedProps
309+
color:isValidColor(item.color||"") ?item.color :theme?.theme?.primary,
310+
detail:item.detail,
311+
titleColor:item.titleColor,
312+
detailColor:item.detailColor,
313+
titleFontWeight:item.titleFontWeight,
314+
titleFontStyle:item.titleFontStyle,
315+
detailFontWeight:item.detailFontWeight,
316+
detailFontStyle:item.detailFontStyle,
317+
animation:item?.animation,
318+
animationDelay:item?.animationDelay,
319+
animationDuration:item?.animationDuration,
320+
animationIterationCount:item?.animationIterationCount
321+
}
322+
}
311323
}) :[currentEvents];
312324
},[currentEvents,theme])
313325

326+
useEffect(()=>{
327+
constmapData:Record<string,number>={};
328+
events?.forEach((item:any,index:number)=>{
329+
mapData[`${item.id}`]=index;
330+
})
331+
332+
if(initData.current){
333+
constdifference=differenceWith(events,props.initialData,isEqual);
334+
constinserted=differenceBy(difference,Object.keys(initDataMap)?.map(id=>({ id})),'id')
335+
constupdated=filter(difference,obj=>includes(Object.keys(initDataMap),String(obj.id)));
336+
constdeleted=differenceBy(props.initialData,Object.keys(mapData)?.map(id=>({ id})),'id')
337+
338+
comp.children?.comp.children?.updatedEvents.dispatchChangeValueAction(updated);
339+
comp.children?.comp.children?.insertedEvents.dispatchChangeValueAction(inserted);
340+
comp.children?.comp.children?.deletedEvents.dispatchChangeValueAction(deleted);
341+
}
342+
343+
if(!initData.current&&events?.length&&comp?.children?.comp?.children?.initialData){
344+
setInitDataMap(mapData);
345+
comp?.children?.comp?.children?.initialData?.dispatch?.(
346+
comp?.children?.comp?.children?.initialData?.changeValueAction?.([...events])
347+
);
348+
initData.current=true;
349+
}
350+
},[JSON.stringify(events),comp?.children?.comp?.children?.initialData]);
351+
314352
constresources=useMemo(()=>props.resources.value,[props.resources.value]);
315353

316354
// list all plugins for Fullcalendar
@@ -370,12 +408,12 @@ let CalendarBasicComp = (function () {
370408
},[slotLabelFormat,slotLabelFormatWeek,slotLabelFormatMonth]);
371409

372410
consthandleEventDataChange=useCallback((data:Array<Record<string,any>>)=>{
373-
comp.children?.comp.children.events.children.manual.children.manual.dispatch(
374-
comp.children?.comp.children.events.children.manual.children.manual.setChildrensAction(
411+
comp?.children?.comp.children.events.children.manual.children.manual.dispatch(
412+
comp?.children?.comp.children.events.children.manual.children.manual.setChildrensAction(
375413
data
376414
)
377415
);
378-
comp.children?.comp.children.events.children.mapData.children.data.dispatchChangeValueAction(
416+
comp?.children?.comp.children.events.children.mapData.children.data.dispatchChangeValueAction(
379417
JSON.stringify(data)
380418
);
381419
props.onEvent("change");
@@ -506,6 +544,24 @@ let CalendarBasicComp = (function () {
506544
>
507545
<Input/>
508546
</Form.Item>
547+
<Form.Item
548+
label={trans("calendar.eventStartTime")}
549+
name="start"
550+
>
551+
<Input/>
552+
</Form.Item>
553+
<Form.Item
554+
label={trans("calendar.eventEndTime")}
555+
name="end"
556+
>
557+
<Input/>
558+
</Form.Item>
559+
<Form.Item
560+
label={trans("calendar.eventAllDay")}
561+
name="allDay"
562+
>
563+
<Switch/>
564+
</Form.Item>
509565
</FormWrapper>
510566
</Tabs.TabPane>
511567
<Tabs.TabPanetab={trans("calendar.colorStyles")}key="2">
@@ -768,12 +824,35 @@ let CalendarBasicComp = (function () {
768824
showModal(event,false);
769825
},[editEvent,showModal]);
770826

771-
consthandleDrop=useCallback(()=>{
827+
constupdateEventsOnDragOrResize=useCallback((eventInfo:EventImpl)=>{
828+
const{extendedProps, title, ...event}=eventInfo.toJSON();
829+
830+
leteventsList=[...props.events];
831+
consteventIdx=eventsList.findIndex(
832+
(item:EventType)=>item.id===event.id
833+
);
834+
if(eventIdx>-1){
835+
eventsList[eventIdx]={
836+
label:title,
837+
...event,
838+
...extendedProps,
839+
};
840+
handleEventDataChange(eventsList);
841+
}
842+
},[props.events,handleEventDataChange]);
843+
844+
consthandleDrop=useCallback((eventInfo:EventDropArg)=>{
845+
updateEventsOnDragOrResize(eventInfo.event);
846+
772847
if(typeofprops.onDropEvent==='function'){
773-
props.onDropEvent("dropEvent");
848+
props.onDropEvent("drop");
774849
}
775-
},[props.onDropEvent]);
776-
850+
},[props.onDropEvent,updateEventsOnDragOrResize]);
851+
852+
consthandleResize=useCallback((eventInfo:EventResizeDoneArg)=>{
853+
updateEventsOnDragOrResize(eventInfo.event);
854+
},[props.onDropEvent,updateEventsOnDragOrResize]);
855+
777856
return(
778857
<Wrapper
779858
ref={ref}
@@ -790,7 +869,7 @@ let CalendarBasicComp = (function () {
790869
slotEventOverlap={false}
791870
events={events}
792871
dayHeaders={true}
793-
dayHeaderFormat={{weekday:'short',month:'numeric',day:'numeric',omitCommas:true}}
872+
//dayHeaderFormat={{ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }}
794873
expandRows={true}
795874
multiMonthMinWidth={250}
796875
nowIndicator={true}
@@ -880,11 +959,13 @@ let CalendarBasicComp = (function () {
880959
props.onEvent("change");
881960
}
882961
}}
883-
eventDragStop={(info)=>{
884-
if(info.view){
885-
handleDrop();
962+
eventDragStart={()=>{
963+
if(typeofprops.onDropEvent==='function'){
964+
props.onDropEvent("drag");
886965
}
887966
}}
967+
eventDrop={handleDrop}
968+
eventResize={handleResize}
888969
/>
889970
</ErrorBoundary>
890971
</Wrapper>
@@ -1007,6 +1088,30 @@ const TmpCalendarComp = withExposingConfigs(CalendarBasicComp, [
10071088
returninput.events.filter(event=>Boolean(event.resourceId));
10081089
},
10091090
}),
1091+
depsConfig({
1092+
name:"toUpdatedEvents",
1093+
desc:trans("calendar.updatedEvents"),
1094+
depKeys:["updatedEvents"],
1095+
func:(input:{updatedEvents:any[];})=>{
1096+
returninput.updatedEvents;
1097+
},
1098+
}),
1099+
depsConfig({
1100+
name:"toInsertedEvents",
1101+
desc:trans("calendar.insertedEvents"),
1102+
depKeys:["insertedEvents"],
1103+
func:(input:{insertedEvents:any[];})=>{
1104+
returninput.insertedEvents;
1105+
},
1106+
}),
1107+
depsConfig({
1108+
name:"toDeletedEvents",
1109+
desc:trans("calendar.deletedEvents"),
1110+
depKeys:["deletedEvents"],
1111+
func:(input:{deletedEvents:any[];})=>{
1112+
returninput.deletedEvents;
1113+
},
1114+
}),
10101115
]);
10111116

10121117
letCalendarComp=withMethodExposing(TmpCalendarComp,[
@@ -1124,7 +1229,43 @@ let CalendarComp = withMethodExposing(TmpCalendarComp, [
11241229
constviewKey=comp.children.licenseKey.getView()==="" ?'defaultFreeView' :'defaultPremiumView';
11251230
comp.children["viewKey"].dispatchChangeValueAction("multiMonthYear");
11261231
}
1127-
}
1232+
},
1233+
{
1234+
method:{
1235+
name:"clearUpdatedEvents",
1236+
detail:"Clear updated events list",
1237+
params:[],
1238+
},
1239+
execute:(comp)=>{
1240+
comp?.children?.updatedEvents.dispatch(
1241+
comp?.children?.updatedEvents.changeValueAction([])
1242+
);
1243+
}
1244+
},
1245+
{
1246+
method:{
1247+
name:"clearInsertedEvents",
1248+
detail:"Clear inserted events list",
1249+
params:[],
1250+
},
1251+
execute:(comp)=>{
1252+
comp?.children?.insertedEvents.dispatch(
1253+
comp?.children?.insertedEvents.changeValueAction([])
1254+
);
1255+
}
1256+
},
1257+
{
1258+
method:{
1259+
name:"clearDeletedEvents",
1260+
detail:"Clear deleted events list",
1261+
params:[],
1262+
},
1263+
execute:(comp)=>{
1264+
comp?.children?.deletedEvents.dispatch(
1265+
comp?.children?.deletedEvents.changeValueAction([])
1266+
);
1267+
}
1268+
},
11281269
]);
11291270

11301271

‎client/packages/lowcoder-comps/src/i18n/comps/locales/en.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@ export const en = {
271271
resourcesDefault:"Rooms",
272272
resourcesName:"Resource Name",
273273
resourcesEvents :"Resources Events Data",
274+
deletedEvents :"List of deleted events",
275+
updatedEvents :"List of updated events",
276+
insertedEvents :"List of inserted events",
274277
editable:"Editable",
275278
license:"Licence Key",
276279
licenseTooltip:"Get your licence key from https://fullcalendar.io/purchase to enable premium views like Resource Timeline and Resource Grid.",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp