import { Vue, Watch } from 'vue-property-decorator';
import { Subject, Subscription } from 'rxjs';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import listPlugin from '@fullcalendar/list';
import interactionPlugin from '@fullcalendar/interaction';
import { Util, ViewTool, ModelTool, LogUtil, throttle, CalendarControlInterface, DataServiceHelp, AppServiceBase, AppItemEngine } from 'ibiz-core';
import { MDControlBase } from './md-control-base';
import { AppCalendarService } from '../ctrl-service';
import { ContextMenu } from '../components/common/context-menu/context-menu';
import { AppGlobalService, AppViewLogicService } from '../app-service';
import { IPSAppDataEntity, IPSControlLogic, IPSDECalendar, IPSDECMUIActionItem, IPSDEContextMenu, IPSDETBUIActionItem, IPSDEToolbar, IPSDEToolbarItem, IPSDEUIAction, IPSSysCalendar, IPSSysCalendarItem } from '@ibiz/dynamic-model-api';
import moment from 'moment';

/**
 * 应用日历部件基类
 *
 * @export
 * @class CalendarControlBase
 * @extends {MDControlBase}
 */
export class CalendarControlBase extends MDControlBase implements CalendarControlInterface {

    /**
     * 日历部件模型实例
     * 
     * @type {IPSDECalendar}
     * @memberof CalendarControlBase
     */
    public declare controlInstance: IPSDECalendar;

    /**
     * 是否初始化完成
     *
     * @type {boolean}
     * @memberof CalendarControlBase
     */
    public inited: boolean = false;

    /**
     * 日历默认打开样式
     * 
     * @type {string}
     * @memberof CalendarControlBase
     */
    public defaultView: string = 'dayGridMonth';

    /**
     * this引用
     *
     * @type {any}
     * @memberof CalendarControlBase
     */
    public thisRef: any = this;

    /**
     * 自定义按钮
     *
     * @type {*}
     * @memberof CalendarControlBase
     */
    public customButtons: any = {};

    /**
     * 引用插件集合
     *
     * @public
     * @type {any[]}
     * @memberof CalendarControlBase
     */
    public calendarPlugins: any[] = [
        dayGridPlugin,
        timeGridPlugin,
        listPlugin,
        interactionPlugin
    ];

    /**
     * 设置头部显示
     *
     * @public
     * @type {}
     * @memberof CalendarControlBase
     */
    public header: any = {
        left: 'prev,next today gotoDate',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
    };

    /**
     * 按钮文本集合
     *
     * @public
     * @type {}
     * @memberof CalendarControlBase
     */
    public buttonText: any = {
        today: this.$t('app.calendar.today'),
        month: this.$t('app.calendar.month'),
        week: this.$t('app.calendar.week'),
        day: this.$t('app.calendar.day'),
        list: this.$t('app.calendar.list'),
    };

    /**
     * 模态显示控制变量
     *
     * @public
     * @type boolean
     * @memberof CalendarControlBase
     */
    public modalVisible: boolean = false;

    /**
     * 跳转日期
     *
     * @public
     * @type Date
     * @memberof CalendarControlBase
     */
    public selectedGotoDate: Date = new Date();

    /**
     * 日历部件动态参数
     * 
     * @type {any}
     * @memberof CalendarControlBase
     */
    public ctrlParams: any;

    /**
     * 有效日期范围
     *
     * @public
     * @type {}
     * @memberof CalendarControlBase
     */
    public validRange: any = {
        start: "0000-01-01",
        end: "9999-12-31"
    };

    /**
     * 默认加载日期
     *
     * @public
     * @type {}
     * @memberof CalendarControlBase
     */
    public defaultDate: any = Util.dateFormat(new Date());

    /**
     * 快速工具栏项
     * 
     * @type {Array<any>}
     * @memberof CalendarControlBase
     */
    public quickToolbarItems: Array<any> = [];

    /**
     * 快速工具栏模型
     * 
     * @type {*}
     * @memberof CalendarControlBase
     */
    public quickToolbarModels: any = {};


    /**
     * 日程事件集合
     *
     * @public
     * @type {any[]}
     * @memberof CalendarControlBase
     */
    public events: any[] = [];

    /**
     * 日历项上下文菜单集合
     *
     * @type {string[]}
     * @memberof CalendarControlBase
     */
    public actionModel: any = {
        //TODO待补充
    }

    /**
     * 备份日历项上下文菜单
     *
     * @type {string[]}
     * @memberof CalendarControlBase
     */
    public copyActionModel: any;

    /**
     * 日历样式类型
     *
     * @public
     * @type {string}
     * @memberof CalendarControlBase
     */
    public calendarType: string = '';

    /**
     * 图例显示控制
     *
     * @public
     * @type {any}
     * @memberof CalendarControlBase
     */
    public isShowlegend: any = {};

    /**
     * 是否已经选中第一条数据
     *
     * @type {boolean}
     * @memberof CalendarControlBase
     */
    public isSelectFirst: boolean = false;

    /**
     * 事件id
     *
     * @type {string}
     * @memberof CalendarControlBase
     */
    public eventid: string = "";

    /**
     * 事件类型map
     *
     * @type {any}
     * @memberof CalendarControlBase
     */
    public eventKey: any = new Map();

    /**
     * 查询参数缓存
     *
     * @public
     * @type {any}
     * @memberof CalendarControlBase
     */
    public searchArgCache: any = {};

    /**
     * @description 日历部件事件
     * @type {(Subscription | undefined)}
     * @memberof CalendarControlBase
     */
    public calendarControlEvent: Subscription | undefined;

    /**
     * @description 日历模态事件
     * @type {(Subscription | undefined)}
     * @memberof CalendarControlBase
     */
    public calendarModalEvent: Subscription | undefined;

    /**
     * 监听部件参数变化
     *
     * @param {*} newVal
     * @param {*} oldVal
     * @memberof CalendarControlBase
     */
    public onStaticPropsChange(newVal: any, oldVal: any) {
        this.isSelectFirstDefault = newVal.isSelectFirstDefault ? true : false;
        super.onStaticPropsChange(newVal, oldVal)
    }

    /**
     * 部件模型数据初始化
     *
     * @memberof CalendarControlBase
     */
    public async ctrlModelInit(args?: any) {
        await super.ctrlModelInit();
        if (!(this.Environment && this.Environment.isPreviewMode)) {
            this.service = new AppCalendarService(this.controlInstance, this.context);
            this.appEntityService = await DataServiceHelp.getInstance().getService(this.controlInstance?.getPSAppDataEntity(), { context: this.context });
        }
        this.initShowLegend();
        this.initActionModel();
        this.initQuickToolbar();
        this.initEventKey();
        this.calendarType = this.controlInstance?.calendarStyle;
        this.ctrlParams = this.controlInstance?.getPSControlParam()?.ctrlParams;
        this.customButtons = {
            gotoDate: {
                text: this.$t('app.calendar.gotodate'),
                click: this.openDateSelect.bind(this)
            }
        };
        if (Object.is(this.calendarType, 'WEEK')) {
            this.defaultView = 'timeGridWeek';
        } else if (Object.is(this.calendarType, 'DAY')) {
            this.defaultView = 'timeGridDay';
        }
    }

    /**
     * 部件模型数据加载
     *
     * @memberof CalendarControlBase
     */
    public async ctrlModelLoad() {
        const calendarItems = (this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || [];
        if (calendarItems.length > 0) {
            for (const item of calendarItems) {
                await item.getPSAppDataEntity?.()?.fill?.();
                await item.getNavPSAppView?.()?.fill?.();
            }
        }
    }

    /**
     * 日历视图部件初始化
     *
     * @memberof CalendarControlBase
     */
    public ctrlInit() {
        super.ctrlInit();
        if (!Object.is(this.calendarType, 'TIMELINE')) {
            this.setButtonText();
        }
        if (this.viewState) {
            this.calendarControlEvent = this.viewState.subscribe(({ tag, action, data }: any) => {
                if (!Object.is(tag, this.name)) {
                    return;
                }
                if (Object.is(action, 'load')) {
                    if (this.inited) {
                        this.refresh();
                    } else {
                        this.inited = true;
                        if (Object.is(this.calendarType, 'TIMELINE')) {
                            this.load();
                        }
                    }
                }
                if (Object.is(action, 'updateSize')) {
                    this.updateSize();
                }
            });
        }
    }

    /**
     * 部件挂载
     *
     * @memberof CalendarControlBase
     */
    public ctrlMounted() {
        super.ctrlMounted();
        this.updateSize();
    }

    /**
     * 初始化日历项上下文菜单集合
     * 
     * @memberof CalendarControlBase
     */
    public initActionModel() {
        const calendarItems: Array<IPSSysCalendarItem> = (this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || [];
        let tempModel: any = {};
        if (calendarItems.length > 0) {
            calendarItems.forEach((item: IPSSysCalendarItem) => {
                const contextMenuItems: Array<IPSDEToolbarItem> = (item.getPSDEContextMenu() as IPSDEContextMenu)?.getPSDEToolbarItems() || [];
                if (contextMenuItems.length > 0) {
                    this.initContextMenuUILogic(item.getPSDEContextMenu()!);
                    contextMenuItems.forEach((toolbarItem: IPSDEToolbarItem) => {
                        this.initActionModelItem(toolbarItem, item, tempModel)
                    })
                }
            })
        }
        this.actionModel = {};
        Object.assign(this.actionModel, tempModel);
    }
    
    /**
     * 初始化上下菜单项
     * 
     * @param toolbarItem 
     * @param item 
     * @param tempModel 
     * @memberof CalendarControlBase
     */
    public initActionModelItem(toolbarItem: IPSDEToolbarItem, item: IPSSysCalendarItem, tempModel: any) {
        let tempItem: any = {
            name: toolbarItem.name,
            nodeOwner: item.itemType
        }
        if (toolbarItem.itemType == 'DEUIACTION') {
            const uiAction: IPSDEUIAction = (toolbarItem as IPSDECMUIActionItem).getPSUIAction() as IPSDEUIAction;
            if (uiAction) {
                Object.assign(tempItem, {
                    type: item.itemType,
                    tag: uiAction.id,
                    visabled: true,
                    disabled: false,
                    actiontarget: uiAction.actionTarget,
                    noprivdisplaymode: uiAction.noPrivDisplayMode,
                    dataaccaction: uiAction.dataAccessAction
                })
            }
        }
        tempModel[`${item.itemType}_${toolbarItem.name}`] = tempItem;
        //TODO YY 上下文菜单子项
        // if(toolbarItem.getPSDEToolbarItems?.length > 0){
        //     for(let toolBarChild of toolbarItem.getPSDEToolbarItems){
        //         this.initActionModelItem(toolBarChild,item,tempModel)               
        //     }
        // }
    }

    /**
     * 初始化快速工具栏
     *
     * @memberof CalendarControlBase
     */
    public initQuickToolbar() {
        const quickToolbaItems: Array<IPSDEToolbarItem> = (ModelTool.findPSControlByType('QUICKTOOLBAR', this.controlInstance.getPSControls() || []) as IPSDEToolbar)?.getPSDEToolbarItems() || [];
        if (quickToolbaItems.length > 0) {
            let items: Array<any> = quickToolbaItems.filter((item: IPSDEToolbarItem) => {
                return item.itemType == "DEUIACTION";
            });
            this.quickToolbarItems = [...items];
        }
        this.initQuickToolbarItemModel();
    }


    /**
     * 初始化快速工具栏模型
     *
     * @memberof CalendarControlBase
     */
    public initQuickToolbarItemModel() {
        const items: Array<IPSDEToolbarItem> = this.quickToolbarItems;
        let models: any = {};
        if (items.length > 0) {
            items.forEach((_item: IPSDEToolbarItem) => {
                const item: IPSDETBUIActionItem = _item as IPSDETBUIActionItem;
                const uiAction: IPSDEUIAction = item.getPSUIAction() as IPSDEUIAction;
                let model: any = {};
                Object.assign(model, {
                    name: item.name?.toLowerCase(),
                    actiontarget: "NONE",
                    disabled: false,
                    visabled: true,
                    type: item.itemType,
                    noprivdisplaymode: uiAction?.noPrivDisplayMode,
                    dataaccaction: uiAction?.dataAccessAction,
                    uiaction: {
                        tag: uiAction?.uIActionTag ? uiAction.uIActionTag : uiAction.id ? uiAction.id : '',
                        target: uiAction?.actionTarget
                    }
                });
                Object.assign(models, { [`${item.name?.toLowerCase()}`]: model });
            })
        }
        this.quickToolbarModels = {};
        Object.assign(this.quickToolbarModels, models);
    }

    /**
     * 初始化事件map对象
     *
     * @memberof CalendarControlBase
     */
    public initEventKey() {
        const calendarItems: Array<IPSSysCalendarItem> = (this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || [];
        if (calendarItems.length > 0) {
            calendarItems.forEach((calendarItem) => {
                let eventKey = ModelTool.getAppEntityKeyField(calendarItem?.getPSAppDataEntity())?.codeName?.toLowerCase() || '';
                this.eventKey.set(calendarItem.itemType, eventKey);
            })

        }
    }

    /**
     * 初始化图例显示控制
     * 
     * @memberof CalendarControlBase
     */
    public initShowLegend() {
        if (Object.keys(this.isShowlegend).length > 0) {
            return;
        }
        const calendarItems: Array<IPSSysCalendarItem> = (this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || [];
        if (calendarItems.length > 0) {
            calendarItems.forEach((item: IPSSysCalendarItem) => {
                this.isShowlegend[item.itemType as string] = true;
            })
        }
    }

    /**
     * 图例点击事件
     *
     * @param {string} itemType 日历项类型
     * @return {*} 
     * @memberof CalendarControlBase
     */
    public legendTrigger(itemType: string) {
        const eventDisabled = this.$el.getElementsByClassName('event-disabled').length;
        if (Object.keys(this.isShowlegend).length != 1 && eventDisabled == Object.keys(this.isShowlegend).length - 1 && this.isShowlegend[itemType]) {
            return;
        }
        this.isShowlegend[itemType] = !this.isShowlegend[itemType];
        this.refresh();
        this.$forceUpdate();
    }

    /**
     * 面板数据变化处理事件
     * @param {any} item 当前数据
     * @param {any} $event 面板事件数据
     *
     * @memberof CalendarControlBase
     */
    public onPanelDataChange(item: any, $event: any) {
        Object.assign(item, $event, { rowDataState: 'update' });
    }

    /**
     * 搜索获取日程事件
     *
     * @param {*} [fetchInfo] 日期信息
     * @param {*} [successCallback] 成功回调
     * @return {*} 
     * @memberof CalendarControlBase
     */
    public load(fetchInfo: any = {}, successCallback?: any) {
        if (this.Environment && this.Environment.isPreviewMode) {
            this.events = [];
            return;
        }
        // 处理请求参数
        let start = (fetchInfo && fetchInfo.start) ? Util.dateFormat(fetchInfo.start) : null;
        let end = (fetchInfo && fetchInfo.end) ? Util.dateFormat(fetchInfo.end) : null;
        let arg = { start: start, end: end };
        if (fetchInfo && fetchInfo.query) {
            Object.assign(arg, { query: fetchInfo.query });
        }
        const parentdata: any = {};
        this.$emit("ctrl-event", { controlname: this.controlInstance?.name, action: "beforeload", data: parentdata });
        Object.assign(arg, parentdata);
        let tempViewParams: any = parentdata.viewparams ? parentdata.viewparams : {};
        Object.assign(tempViewParams, Util.deepCopy(this.viewparams ? this.viewparams : ''));
        Object.assign(arg, { viewparams: tempViewParams });
        // 处理events数据
        let _this = this;
        let handleEvents = () => {
            if (_this.isSelectFirstDefault) {
                _this.isSelectFirst = true;
            }
            let filterEvents = this.events.filter((event: any) => {
                return _this.isShowlegend[event.itemType];
            });
            if (successCallback) {
                successCallback(filterEvents);
            }
            // 刷新日历的大小(仅fullcalendar组件使用)
            if (!Object.is(_this.calendarType, "TIMELINE") && !this.ctrlParams) {
                let appCalendar: any = _this.$refs[this.controlInstance?.codeName];
                let api = appCalendar.getApi();
                if (api) {
                    api.updateSize();
                }
            }
        }
        if (JSON.stringify(arg) === JSON.stringify(this.searchArgCache)) {
            handleEvents();
            return;
        } else {
            this.searchArgCache = arg;
        }
        let tempContext: any = Util.deepCopy(this.context);
        this.handleCtrlEvents('onbeforeload', { action: this.loadAction, navContext: tempContext, navParam: arg }).then((res: boolean) => {
            if (res) {
                this.onControlRequset('load', tempContext, arg);
                const post: Promise<any> = this.service.search(this.loadAction, tempContext, arg, this.showBusyIndicator);
                post.then((response: any) => {
                    this.onControlResponse('load', response);
                    if (!response || response.status !== 200) {
                        this.handleCtrlEvents('onloaderror', { action: this.loadAction, navParam: arg, data: response?.data }).then((res: boolean) => {
                            if (res) {
                                this.$throw(response, 'searchEvents');
                            }
                        })
                    } else {
                        // 默认选中第一项
                        this.events = response.data;
                        this.handleCtrlEvents('onloadsuccess', { action: this.loadAction, navParam: arg, data: this.events }).then((res: boolean) => {
                            if (res) {
                                this.ctrlEvent({
                                    controlname: this.name,
                                    action: 'load',
                                    data: this.events,
                                });
                                handleEvents();
                                this.scheduleSort();
                            }
                        })
                    }
                }, (error: any) => {
                    this.onControlResponse('load', error);
                    this.handleCtrlEvents('onloaderror', { action: this.loadAction, navParam: arg, data: error?.data }).then((res: boolean) => {
                        if (res) {
                            this.$throw(error, 'searchEvents');
                        }
                    })
                });
            }
        })
    }

    /**
     * 日期点击事件
     *
     * @param {*} $event 日期信息
     * @memberof CalendarControlBase
     */
    public onDateClick($event: any) {
        let date = $event.date;
        let datestr = $event.dateStr;
    }

    /**
     * 时间轴点击事件
     * 
     * @param {*} item 项数据
     * @memberof CalendarControlBase
     */
    public onTimeLineClick(item: any) {
        this.events.forEach((event: any) => {
            event.srfchecked = 0;
        })
        item.srfchecked = Number(!item.srfchecked);
        this.onEventClick(item, true);
        this.$forceUpdate();
    }

    /**
     * 处理日历日程选中样式
     * 
     * @param {*} item 项数据
     * @memberof CalendarControlBase
     */
    public handleEventSelectStyle($event: any) {
        const calendarApi: any = (this.$refs[this.controlInstance?.codeName] as any)?.getApi();
        if (!calendarApi) {
            return;
        }
        const findApis = (id: any) => {
            if (!id) {
                return [];
            }
            return calendarApi.getEvents().filter((event: any) => {
                return event.extendedProps.curdata[this.getEventKey(event.extendedProps)] === id;
            });
        }
        const eventId: any = $event.event.extendedProps.curdata[this.getEventKey($event.event.extendedProps)];
        const eventApis: any[] = findApis(eventId);
        eventApis.forEach((api: any) => {
            const classNames: any[] = [...api.classNames];
            if (classNames.findIndex((className: any) => { return className == 'selected-event'; }) === -1) {
                classNames.push('selected-event')
            }
            api.setProp('classNames', classNames);
        })
        if (this.isSelectFirstDefault && this.eventid != eventId || (!this.isSelectFirstDefault)) {
            const _eventApis: any[] = findApis(this.eventid);
            _eventApis.forEach((api: any) => {
                const _temp: any[] = [...api.classNames];
                const index = _temp.findIndex((className: any) => { return className == 'selected-event'; });
                if (index !== -1) {
                    _temp.splice(index, 1);
                    api.setProp('classNames', _temp);
                }
            })
        }
        this.eventid = this.eventid && this.eventid == eventId && !this.isSelectFirstDefault ? '' : eventId;
    }

    /**
     * 日程点击事件
     *
     * @param {*} $event calendar事件对象或event数据
     * @param {*} isOriginData true:$event是原始event数据,false:是组件
     * @param {*} $event timeline事件对象
     * @memberof CalendarControlBase
     */
    public onEventClick($event: any, isOriginData: boolean = false, $event2?: any) {
        this.handleCtrlEvents('onselectionchange', { action: 'SelectionChange', data: $event }).then((res: boolean) => {
            if (!res) {
                return;
            }
            // 处理event数据
            let event: any = {};
            if (isOriginData) {
                event = Util.deepCopy($event);
            } else {
                event = Object.assign({ title: $event.event.title, start: $event.event.start, end: $event.event.end }, $event.event.extendedProps);
            }
            // 点击选中样式
            let JSelement: any = null;
            if (!isOriginData && $event.el) {
                JSelement = $event.el;
            } else if (isOriginData && $event2 && $event2.currentTarget) {
                JSelement = $event2.currentTarget;
            }
            const eventId: any = event.curdata[this.getEventKey(event)];
            let tempItem = this.events.find((_item: any) => { return _item.curdata[this.getEventKey(_item)] == eventId });
            if (this.eventid && this.eventid == eventId) {
                if (tempItem) tempItem.curdata.srfchecked = 0;
            } else {
                if (tempItem) tempItem.curdata.srfchecked = 1;
            }
            this.selections = this.eventid && this.eventid == eventId ? [] : [event];
            this.handleEventSelectStyle($event);
            // 处理上下文数据
            let _this: any = this;
            let view: any = {};
            let _context: any = Object.assign({}, this.context);
            let _viewparams: any = Object.assign({ start: event.start, end: event.end }, this.viewparams);
            const item: IPSSysCalendarItem = (((this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || []) as Array<IPSSysCalendarItem>).find((_item: IPSSysCalendarItem) => {
                return _item.itemType == event.itemType;
            }) as IPSSysCalendarItem;
            if (item) {
                const codeName = ((item.getPSAppDataEntity() as IPSAppDataEntity)?.codeName as string).toLowerCase();
                if (codeName) {
                    _context[codeName] = event[codeName];
                    view = this.getEditView(codeName);
                }
            }
            // 导航栏中不需要打开视图,只要抛出选中数据
            this.$emit("ctrl-event", { controlname: this.controlInstance.name, action: "selectionchange", data: this.selections });
            if (this.isSelectFirstDefault) {
                return;
            }
            // 根据打开模式打开视图
            if (!view.viewname) {
                return;
            } else if (Object.is(view.placement, 'INDEXVIEWTAB') || Util.isEmpty(view.placement)) {
                const routePath = ViewTool.buildUpRoutePath(_this.$route, this.context, view.deResParameters, view.parameters, [Util.deepCopy(_context)], _viewparams);
                _this.$router.push(routePath);
            } else {
                let container: Subject<any> = new Subject();
                if (Object.is(view.placement, 'POPOVER')) {
                    container = _this.$apppopover.openPop(isOriginData ? $event2 : $event.jsEvent, view, Util.deepCopy(_context), _viewparams);
                } else if (Object.is(view.placement, 'POPUPMODAL')) {
                    container = _this.$appmodal.openModal(view, Util.deepCopy(_context), _viewparams);
                } else if (view.placement.startsWith('DRAWER')) {
                    container = _this.$appdrawer.openDrawer(view, Util.getViewProps(_context, _viewparams));
                }
                this.calendarModalEvent = container.subscribe((result: any) => {
                    if (!result || !Object.is(result.ret, 'OK')) {
                        return;
                    }
                    // 刷新日历
                    _this.refresh();
                });
            }
        });
    }

    /**
     * 日历刷新
     *
     * @param {*} [args] 额外参数
     * @memberof CalendarControlBase
     */
    public refresh(args?: any) {
        if (Object.is(this.calendarType, 'TIMELINE')) {
            this.searchArgCache = {}
            this.load();
        } else if (this.ctrlParams) {
            let calendarTimeLine: any = this.$refs['appCalendarTimeline'];
            if (calendarTimeLine) {
                calendarTimeLine.refetchEvents();
            }
        } else {
            let calendarApi = (this.$refs[this.controlInstance?.codeName] as any).getApi();
            calendarApi.refetchEvents();
        }
    }

    /**
     * 日程拖动事件
     *
     * @param {*} $event 事件信息
     * @memberof CalendarControlBase
     */
    public onEventDrop($event: any) {
        if (this.isSelectFirstDefault) {
            return;
        }
        let arg: any = {};
        let _context: any = Object.assign({}, this.context);
        arg.start = Util.dateFormat($event.event.start);
        arg.end = Util.dateFormat($event.event.end);
        let itemType = $event.event._def.extendedProps.itemType;
        const item: IPSSysCalendarItem = (((this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || []) as Array<IPSSysCalendarItem>).find((_item: IPSSysCalendarItem) => {
            return _item.itemType == itemType;
        }) as IPSSysCalendarItem;
        if (item) {
            const codeName = ((item.getPSAppDataEntity() as IPSAppDataEntity)?.codeName as string).toLowerCase();
            if (codeName) {
                arg[codeName] = $event.event._def.extendedProps[codeName];
                _context[codeName] = $event.event._def.extendedProps[codeName];
            }
        }
        Object.assign(arg, { viewparams: this.viewparams });
        let tempContext: any = Util.deepCopy(this.context);
        this.handleCtrlEvents('onbeforedrop', { action: itemType, navContext: tempContext, navParam: arg }).then((res: boolean) => {
            if (res) {
                this.onControlRequset('onEventDrop', tempContext, arg);
                const post: Promise<any> = this.service.update(itemType, tempContext, arg, this.showBusyIndicator);
                post.then((response: any) => {
                    this.onControlResponse('onEventDrop', response);
                    if (!response || response.status !== 200) {
                        this.handleCtrlEvents('ondroperror', { action: itemType, navParam: arg, data: response?.data }).then((res: boolean) => {
                            if (res) {
                                this.$throw(response, 'onEventDrop');
                            }
                        })
                    } else {
                        this.handleCtrlEvents('ondropsuccess', { action: itemType, navParam: arg, data: response?.data }).then((res: boolean) => {
                            if (res) {
                                // TODO
                            }
                        })
                    }
                }, (response: any) => {
                    this.onControlResponse('onEventDrop', response);
                    this.handleCtrlEvents('ondroperror', { action: itemType, navParam: arg, data: response?.data }).then((res: boolean) => {
                        if (res) {
                            this.$throw(response, 'onEventDrop');
                        }
                    })
                });
            }
        })
    }

    /**
     * 快速工具栏菜单项点击
     * 
     * @param {*} tag 菜单项标识
     * @param {*} $event 事件源
     * @memberof CalendarControlBase
     */
    public itemClick(tag: any, $event: any) {
        if (AppServiceBase.getInstance().getEnableUIModelEx()) {
            const uiAction = ModelTool.getToolBarUIActionByItemName(this.quickToolbarInstance, tag);
            AppGlobalService.getInstance().executeGlobalUIAction(uiAction, $event, this);
        } else {
            AppViewLogicService.getInstance().executeViewLogic(`calendar_quicktoolbar_${tag}_click`, $event, this, {}, this.controlInstance.getPSAppViewLogics() || []);
        }
    }

    /**
     * 时间点击
     *
     * @param {*} $event 当前时间
     * @param {*} jsEvent 原生事件对象  
     * @returns
     * @memberof CalendarControlBase
     */
    public onDayClick($event: any, jsEvent: any) {
        let _this: any = this;
        let content: any = this.renderBarMenu;
        const container: any = _this.$apppopover.openPopover(jsEvent, content, "left-end", true, 103, _this.quickToolbarItems.length * 34);
    }

    /**
     * 计算节点右键权限
     *
     * @param {*} data 日历项数据
     * @param {*} appEntityName 应用实体名称  
     * @returns
     * @memberof CalendarControlBase
     */
    public async computeNodeState(data: any, appEntity: IPSAppDataEntity) {
        let service = await DataServiceHelp.getInstance().getService(appEntity, { context: this.context });
        if (this.copyActionModel && Object.keys(this.copyActionModel).length > 0) {
            if (service) {
                let tempContext: any = Util.deepCopy(this.context);
                tempContext[appEntity.codeName.toLowerCase()] = data[appEntity.codeName.toLowerCase()];
                let targetData = await service.execute('Get', tempContext, {});
                ViewTool.calcTreeActionItemAuthState(targetData.data, this.copyActionModel, this.appUIService);
                this.handleContextMenuLogic([targetData.data], this.copyActionModel);
                return this.copyActionModel;
            } else {
                LogUtil.warn(this.$t('app.warn.geterror'));
                return this.copyActionModel;
            }
        }
        return this.copyActionModel;
    }

    /**
     * 计算日历日程样式
     * 
     * @param info 
     */
    public handleEventStyle(info?: any) {
        if (!info) {
            return;
        }
        const calendarApi: any = (this.$refs[this.controlInstance?.codeName] as any)?.getApi();
        if (!calendarApi) {
            return;
        }
        const data = info.event.extendedProps.curdata;
        let calendarItem: IPSSysCalendarItem = (((this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || []) as Array<IPSSysCalendarItem>).find((_item: IPSSysCalendarItem) => {
            return _item.itemType == data.itemType;
        }) as IPSSysCalendarItem;
        const cssName = calendarItem?.getPSSysCss?.()?.cssName;
        const calendarEvents: any[] = calendarApi.getEvents().filter((event: any) => {
            return event.extendedProps.curdata[this.getEventKey(event.extendedProps)] === data[this.getEventKey(info.event.extendedProps)];
        });
        if (cssName && calendarEvents.length > 0) {
            calendarEvents.forEach((event: any) => {
                const classNames: any[] = [...event.classNames];
                if (classNames.findIndex((className: any) => { return className == cssName; }) === -1) {
                    classNames.push(cssName);
                    event.setProp('classNames', classNames);
                }
            })
        }
    }

    /**
     * 事件绘制回调
     *
     * @param {*} info 信息
     * @memberof CalendarControlBase
     */
    public eventRender(info?: any,) {
        if (this.isSelectFirstDefault && this.isSelectFirst) {
            this.isSelectFirst = false;
            this.onEventClick(info);
        }
        this.handleEventStyle(info);
        let data = Object.assign({ title: info.event.title, start: info.event.start, end: info.event.end }, info.event.extendedProps);
        info.el.addEventListener('contextmenu', (event: MouseEvent) => {
            this.showContext(data, event);
        });
    }

    /**
     * 显示上下文菜单
     *
     * @param {*} data
     * @param {*} event
     * @return {*} 
     * @memberof CalendarControlBase
     */
    public showContext(data: any, event: any) {
        this.copyActionModel = {};
        Object.values(this.actionModel).forEach((item: any) => {
            if (Object.is(item.nodeOwner, data.itemType)) {
                this.copyActionModel[item.name] = item;
            }
        })
        if (Object.keys(this.copyActionModel).length === 0) {
            return;
        }
        let dataMapping: IPSSysCalendarItem = (((this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || []) as Array<IPSSysCalendarItem>).find((_item: IPSSysCalendarItem) => {
            return _item.itemType == data.itemType;
        }) as IPSSysCalendarItem;
        const appDECodeName = (dataMapping.getPSAppDataEntity() as IPSAppDataEntity)?.codeName as string;
        if (!appDECodeName) {
            return;
        }
        this.computeNodeState(data, (dataMapping.getPSAppDataEntity() as IPSAppDataEntity)).then((result: any) => {
            let flag: boolean = false;
            if (Object.values(result).length > 0) {
                flag = Object.values(result).some((item: any) => {
                    return item.visabled === true;
                })
            }
            if (flag) {
                let props = { data: data, renderContent: this.renderContextMenu };
                let component = ContextMenu;
                const vm: any = new Vue({
                    render(h) {
                        return h(component, { props });
                    }
                }).$mount();
                document.body.appendChild(vm.$el);
                const comp: any = vm.$children[0];
                comp.showContextMenu(event.clientX, event.clientY);
            }
        });
    }

    /**
     * 绘制右键菜单
     *
     * @param {*} event
     * @returns
     * @memberof CalendarControlBase
     */
    public renderContextMenu(event: any) {
        if (!event || !event.itemType) {
            return null;
        }
        this.selections = [event];
        const calendarItems: Array<IPSSysCalendarItem> = (this.controlInstance as IPSSysCalendar).getPSSysCalendarItems() || [];
        if (calendarItems.length > 0) {
            let item: IPSSysCalendarItem = calendarItems.find((_item: IPSSysCalendarItem) => {
                return _item.itemType == event.itemType;
            }) as IPSSysCalendarItem;
            const contextMenu = item.getPSDEContextMenu() as IPSDEContextMenu;
            if (contextMenu && contextMenu.controlType == "CONTEXTMENU") {
                let { targetCtrlName, targetCtrlParam, targetCtrlEvent }: { targetCtrlName: string, targetCtrlParam: any, targetCtrlEvent: any } = this.computeTargetCtrlData(contextMenu, event);
                targetCtrlParam.dynamicProps.contextMenuActionModel = this.copyActionModel;
                return this.$createElement(targetCtrlName, { props: targetCtrlParam, ref: contextMenu.name, on: targetCtrlEvent });
            }
        }
        return null;
    }

    /**
     * 绘制快速工具栏项
     * 
     * @returns
     * @memberof CalendarControlBase
     */
    public renderBarMenu() {
        return (
            <div class="calendar-popover">
                <dropdown
                    class="quick-toolbar"
                    trigger="custom"
                    visible={true}
                    on-on-click={($event: any, $event2: any) => throttle(this.itemClick, [$event, $event2], this)}>
                    <dropdown-menu slot="list">
                        {this.quickToolbarItems.map((item: any) => {
                            return (
                                <dropdown-item
                                    name={item.name}
                                    v-show={this.quickToolbarModels[item.name].visabled}
                                    disabled={this.quickToolbarModels[item.name].disabled}>
                                    {item.showIcon && item.getPSSysImage ?
                                        <i class={item.getPSSysImage?.cssClass}></i> : null}
                                    {item.showCaption ?
                                        <span title={item.tooltip}>{item.caption}</span> : null}
                                </dropdown-item>
                            );
                        })}
                    </dropdown-menu>
                </dropdown>
            </div>
        );
    }

    /**
     * 部件事件
     * @param ctrl 部件 
     * @param action  行为
     * @param data 数据
     * 
     * @memberof CalendarControlBase
     */
    public onCtrlEvent(controlname: string, action: string, data: any) {
        if (action == 'contextMenuItemClick') {
            if (AppServiceBase.getInstance().getEnableUIModelEx()) {
                const itemType = this.copyActionModel[data.data].nodeOwner;
                if (itemType) {
                    const calendarItem = (this.controlInstance as IPSSysCalendar).getPSSysCalendarItems()?.find((item: IPSSysCalendarItem) => item.itemType === itemType);
                    if (calendarItem && calendarItem.getPSDEContextMenu()) {
                        const uiAction = ModelTool.getToolBarUIActionByItemName(calendarItem.getPSDEContextMenu()!, data.data);
                        AppGlobalService.getInstance().executeGlobalUIAction(uiAction, undefined, this, undefined, this.selections);
                    }
                }
            } else {
                AppViewLogicService.getInstance().executeViewLogic(`${controlname}_${data?.data}_click`, undefined, this, {}, this.controlInstance?.getPSAppViewLogics() || []);
            }
        } else if (action == 'panelDataChange') {
            this.onPanelDataChange(data.item, data.data);
        } else {
            this.ctrlEvent({ controlname, action, data });
        }
    }

    /**
     * 设置按钮文本
     *
     * @public
     * @memberof CalendarControlBase
     */
    public setButtonText() {
        this.buttonText.today = this.$t('app.calendar.today');
        this.buttonText.month = this.$t('app.calendar.month');
        this.buttonText.week = this.$t('app.calendar.week');
        this.buttonText.day = this.$t('app.calendar.day');
        this.buttonText.list = this.$t('app.calendar.list');
        this.customButtons.gotoDate.text = this.$t('app.calendar.gotodate');
    }

    /**
     * 监听语言变化
     *
     * @public
     * @memberof CalendarControlBase
     */
    @Watch('$i18n.locale')
    public onLocaleChange(newval: any, val: any) {
        this.setButtonText();
    }

    /**
     * 打开时间选择模态
     *
     * @public
     * @memberof CalendarControlBase
     */
    public openDateSelect() {
        this.modalVisible = true;
    }

    /**
     * 跳转到指定时间
     *
     * @public
     * @memberof CalendarControlBase
     */
    public gotoDate() {
        let appCalendar: any = this.$refs[this.controlInstance?.codeName];
        let api = appCalendar?.getApi();
        if (api) {
            api.gotoDate(this.selectedGotoDate);
        }
    }

    /**
     * 获取事件key
     *
     * @param {*} event 事件对象
     * @return {*} 
     * @memberof CalendarControlBase
     */
    public getEventKey(event: any) {
        if (event?.itemType && this.eventKey.has(event.itemType)) {
            return this.eventKey.get(event.itemType)
        }
        return "";
    }

    /**
     * 获取编辑视图信息
     *
     * @param {string} deName 视图名称
     * @return {*} 
     * @memberof CalendarControlBase
     */
    public getEditView(deName: string) {
        let view: any = {};
        //TODO
        return view;
    }

    /**
     * 重置日历尺寸
     *
     * @memberof CalendarControlBase
     */
    public updateSize() {
        const calendar: any = this.$refs[this.controlInstance?.codeName];
        if (calendar) {
            const api = calendar.getApi();
            api.updateSize()
        }
    }

    /**
     * 计算部件所需参数
     *
     * @param {*} controlInstance 部件模型对象
     * @param {*} item 日历项数据
     * @returns
     * @memberof CalendarControlBase
     */
    public computeTargetCtrlData(controlInstance: any, item?: any) {
        const { targetCtrlName, targetCtrlParam, targetCtrlEvent } = super.computeTargetCtrlData(controlInstance);
        Object.assign(targetCtrlParam.dynamicProps, {
            navdatas: [item?.curdata],
        })
        Object.assign(targetCtrlParam.staticProps, {
            transformData: this.transformData,
            opendata: this.opendata,
            newdata: this.newdata,
            refresh: this.refresh,
        })
        targetCtrlEvent['ctrl-event'] = ({ controlname, action, data }: { controlname: string, action: string, data: any }) => {
            this.onCtrlEvent(controlname, action, { item: item.curdata, data: data });
        };
        return { targetCtrlName, targetCtrlParam, targetCtrlEvent };
    }

    /**
     * 日程排序
     * 
     * @memberof CalendarControlBase
     */
    public scheduleSort() {
        if (Object.is(this.calendarType, 'TIMELINE') && this.events.length > 0) {
            this.events.sort((a: any, b: any) => {
                const x: any = a.start;
                const y: any = b.start;
                return moment(x).isAfter(y) ? -1 : moment(x).isBefore(y) ? 1 : 0;
            })
            // 默认选中第一项
            if (this.isSelectFirstDefault) {
                this.onTimeLineClick(this.events[0]);
            }
        }
    }

    /**
     * @description 部件销毁
     * @memberof CalendarControlBase
     */
    public ctrlDestroyed() {
        super.ctrlDestroyed();
        if (this.calendarControlEvent) {
            this.calendarControlEvent.unsubscribe();
        }
        if (this.calendarModalEvent) {
            this.calendarModalEvent.unsubscribe();
        }
    }
}