<#ibizinclude> ../../@MACRO/LANG_FUN.ftl </#ibizinclude> <template> <div :class='calendarClass'> <#if ctrl.getCalendarStyle?? && ctrl.getCalendarStyle() == 'TIMELINE'> <el-timeline> <el-timeline-item v-for="(item, index) in events" :key="item.title+index" :color="item.color" :timestamp="item.start" placement="top"> <el-card @click.native="onEventClick(item,true,$event)" :class="item.className"> <h4>{{item.title}}</h4> <p>从 {{item.start}} 至 {{item.end}}</p> </el-card> </el-timeline-item> </el-timeline> <#else> <FullCalendar ref="calendar" :locale="$i18n.locale" height="parent" :firstDay="1" :eventLimit="true" :editable="!isSelectFirstDefault && true" :buttonText="buttonText" :header="header" :plugins="calendarPlugins" :events="searchEvents" :customButtons="customButtons" :validRange="validRange" :defaultDate="defaultDate" @dateClick="onDateClick" @eventClick="onEventClick" @eventDrop="onEventDrop" defaultView="dayGridMonth"/> <modal v-model="modalVisible" width="250px" :title="$t('app.calendar.dateSelectModalTitle')" class-name='date-select-modal' @on-ok="gotoDate"> <el-date-picker style="width: 200px;" v-model="selectedGotoDate" type="date"></el-date-picker> </modal> </#if> </div> </template> <#assign import_block> import FullCalendar from '@fullcalendar/vue' import dayGridPlugin from '@fullcalendar/daygrid' import timeGridPlugin from '@fullcalendar/timegrid'; import listPlugin from '@fullcalendar/list'; import interactionPlugin from '@fullcalendar/interaction' </#assign> <#assign component_block> FullCalendar, </#assign> <#ibizinclude> ../@MACRO/CONTROL/CONTROL_HEADER-BASE.vue.ftl </#ibizinclude> /** * 是否默认选中第一条数据 * * @type {boolean} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop({ default: false }) public isSelectFirstDefault!: boolean; /** * 显示处理提示 * * @type {boolean} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop({ default: true }) public showBusyIndicator?: boolean; /** * 部件行为--load * * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ @Prop() public loadAction!: string; /** * 日历部件样式名 * * @public * @type {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ public calendarClass: string = "calendar"; /** * 选中事件element元素 * * @public * @type {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ public selectedEventElement:any; /** * 引用插件集合 * * @public * @type {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ public calendarPlugins: any[] = [ dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin ]; /** * 设置头部显示 * * @public * @type {} * @memberof ${srfclassname('${ctrl.codeName}')} */ public header: any = { left: 'prev,next today gotoDate', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' }; /** * 按钮文本集合 * * @public * @type {} * @memberof ${srfclassname('${ctrl.codeName}')} */ public buttonText: any = { today: '今天', month: '月', week: '周', day: '天', list: '列' }; /** * 自定义按钮集合 * * @public * @type {} * @memberof ${srfclassname('${ctrl.codeName}')} */ public customButtons: any = { gotoDate: { text: "跳转", click: this.openDateSelect } }; /** * 模态显示控制变量 * * @public * @type boolean * @memberof ${srfclassname('${ctrl.codeName}')} */ public modalVisible: boolean = false; /** * 跳转日期 * * @public * @type Date * @memberof ${srfclassname('${ctrl.codeName}')} */ public selectedGotoDate: Date = new Date(); /** * 打开时间选择模态 * * @public * @memberof ${srfclassname('${ctrl.codeName}')} */ public openDateSelect(){ this.modalVisible = true; } /** * 跳转到指定时间 * * @public * @memberof ${srfclassname('${ctrl.codeName}')} */ public gotoDate(){ let appCalendar: any = this.$refs.calendar; let api = appCalendar.getApi(); api.gotoDate(this.selectedGotoDate); } /** * 有效日期范围 * * @public * @type {} * @memberof ${srfclassname('${ctrl.codeName}')} */ public validRange: any = { start:"0000-01-01", end:"9999-12-31" }; /** * 默认加载日期 * * @public * @type {} * @memberof ${srfclassname('${ctrl.codeName}')} */ public defaultDate: any = this.$util.dateFormat(new Date()); /** * 设置按钮文本 * * @public * @memberof ${srfclassname('${ctrl.codeName}')} */ 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 ${srfclassname('${ctrl.codeName}')} */ @Watch('$i18n.locale') public onLocaleChange(newval: any, val: any) { this.setButtonText(); } /** * 日程事件集合 * * @public * @type {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ public events: any[] = []; /** * 日历样式类型 * * @public * @type {string} * @memberof ${srfclassname('${ctrl.codeName}')} */ public calendarType: string = "${ctrl.getCalendarStyle()}"; /** * 搜索获取日程事件 * * @param {*} $event 日期信息 * @memberof ${srfclassname('${ctrl.codeName}')} */ public searchEvents(fetchInfo?:any, successCallback?:any, failureCallback?:any ) { let start = (fetchInfo && fetchInfo.start) ? this.$util.dateFormat(fetchInfo.start) : null; let end = (fetchInfo && fetchInfo.end) ? this.$util.dateFormat(fetchInfo.end) : null; let arg = { start: start, end: end }; if(fetchInfo && fetchInfo.query){ Object.assign(arg,{query : fetchInfo.query}); } Object.assign(arg,{viewparams:this.viewparams}); const post: Promise<any> = this.service.search(this.loadAction, JSON.parse(JSON.stringify(this.context)), arg, this.showBusyIndicator); post.then((response: any) => { if (!response || response.status !== 200) { if (response.errorMessage) { this.$Notice.error({ title: '错误', desc: response.errorMessage }); } return; } // 默认选中第一项 this.events = response.data; if(this.isSelectFirstDefault){ // 模拟$event数据 let tempEvent = JSON.parse(JSON.stringify(this.events[0])); this.onEventClick(tempEvent,true); this.events[0].className = "select-first-event"; this.calendarClass = "calendar select-first-calendar"; } if(successCallback){ successCallback(this.events); } // 刷新日历的大小(仅fullcalendar组件使用) if(!Object.is(this.calendarType,"TIMELINE")){ let appCalendar: any = this.$refs.calendar; let api = appCalendar.getApi(); api.updateSize(); } }, (response: any) => { if (response && response.status === 401) { return; } this.$Notice.error({ title: '错误', desc: response.errorMessage }); }); } /** * 日期点击事件 * * @param {*} $event 日期信息 * @memberof ${srfclassname('${ctrl.codeName}')} */ public onDateClick($event: any) { let date = $event.date; let datestr = $event.dateStr; } /** * 获取编辑视图信息 * * @param {*} $event 事件信息 * @memberof ${srfclassname('${ctrl.codeName}')} */ public getEditView(deName: string) { let view: any = {}; switch(deName){ <#if view.getAllRelatedPSAppViews?? && view.getAllRelatedPSAppViews()??> <#list view.getAllRelatedPSAppViews() as editview> case "${editview.getPSDataEntity().getCodeName()?lower_case}": view = { viewname: '${srffilepath2(editview.getCodeName())}', height: ${editview.getHeight()?c}, width: ${editview.getWidth()?c}, title: this.<@getViewLanguageTitle editview />, placement: '${editview.getOpenMode()}', deResParameters: <#rt> <#if editview.isPSDEView()> [<#t> <#if editview.getPSAppDERSPathCount() gt 0> <#list editview.getPSAppDERSPath(editview.getPSAppDERSPathCount() - 1) as deRSPath> <#assign majorPSAppDataEntity = deRSPath.getMajorPSAppDataEntity()/><#t> { pathName: '${srfpluralize(majorPSAppDataEntity.codeName)?lower_case}', parameterName: '${majorPSAppDataEntity.getCodeName()?lower_case}' }, <#t> </#list> </#if> ],<#lt> <#else> [],<#lt> </#if> parameters: <#rt> [<#t> <#if editview.isPSDEView()> <#assign appDataEntity = editview.getPSAppDataEntity()/> { pathName: '${srfpluralize(appDataEntity.codeName)?lower_case}', parameterName: '${appDataEntity.getCodeName()?lower_case}' }, <#t> { pathName: '${editview.getPSDEViewCodeName()?lower_case}', parameterName: '${editview.getPSDEViewCodeName()?lower_case}' } <#t> <#else> { pathName: '${editview.getCodeName()?lower_case}', parameterName: '${editview.getCodeName()?lower_case}' } <#t> </#if> ],<#lt> }; break; </#list> </#if> } return view; } /** * 日程点击事件 * * @param {*} $event calendar事件对象或event数据 * @param {*} isOriginData true:$event是原始event数据,false:是组件 * @param {*} $event timeline事件对象 * @memberof ${srfclassname('${ctrl.codeName}')} */ public onEventClick($event: any, isOriginData:boolean = false, $event2?: any) { // 处理event数据 let event: any = {}; if(isOriginData){ event = JSON.parse(JSON.stringify($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; } if(JSelement){ this.calendarClass = "calendar"; if(this.selectedEventElement){ this.selectedEventElement.classList.remove("selected-event"); } this.selectedEventElement = JSelement; this.selectedEventElement.classList.add("selected-event"); } // 处理上下文数据 let _this = this; let view: any = {}; let _context: any = Object.assign({},this.context); let itemType = event.itemType; switch(itemType) { <#if ctrl.getPSSysCalendarItems()??> <#list ctrl.getPSSysCalendarItems() as calendarItem> <#if calendarItem.getPSAppDataEntity()??> <#assign _appde = calendarItem.getPSAppDataEntity() /> case "${calendarItem.getItemType()}": _context.${_appde.getCodeName()?lower_case} = event.${_appde.getCodeName()?lower_case}; view = this.getEditView("${_appde.getCodeName()?lower_case}"); break; </#if> </#list> </#if> } // 导航栏中不需要打开视图,只要抛出选中数据 if(this.isSelectFirstDefault){ _context.itemType = itemType; this.selections = [_context]; this.$emit("selectionchange",[_context]); return; } // 根据打开模式打开视图 if (Object.is(view.placement, 'INDEXVIEWTAB') || Object.is(view.placement, '')) { const routePath = this.$viewTool.buildUpRoutePath(this.$route, this.context, view.deResParameters, view.parameters, [JSON.parse(JSON.stringify(_context))] , JSON.parse(JSON.stringify(this.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,JSON.parse(JSON.stringify(_context)), JSON.parse(JSON.stringify(this.viewparams))); } else if (Object.is(view.placement, 'POPUPMODAL')) { container = this.$appmodal.openModal(view, JSON.parse(JSON.stringify(_context)), JSON.parse(JSON.stringify(this.viewparams))); } else if (view.placement.startsWith('DRAWER')) { container = this.$appdrawer.openDrawer(view, JSON.parse(JSON.stringify(_context)), JSON.parse(JSON.stringify(this.viewparams))); } container.subscribe((result: any) => { if (!result || !Object.is(result.ret, 'OK')) { return; } // 刷新日历 _this.refresh(); }); } } /** * 日历刷新 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public refresh() { if(Object.is(this.calendarType,"TIMELINE")){ this.searchEvents(); } else { let calendarApi = (this.$refs.calendar as any).getApi(); calendarApi.refetchEvents(); } } /** * 日程拖动事件 * * @param {*} $event 事件信息 * @memberof ${srfclassname('${ctrl.codeName}')} */ public onEventDrop($event: any) { if(this.isSelectFirstDefault){ return; } let arg: any = {}; let _context: any = Object.assign({},this.context); arg.start = this.$util.dateFormat($event.event.start); arg.end = this.$util.dateFormat($event.event.end); let itemType = $event.event._def.extendedProps.itemType; switch(itemType) { <#if ctrl.getPSSysCalendarItems()??> <#list ctrl.getPSSysCalendarItems() as calendarItem> <#if calendarItem.getPSAppDataEntity()??> <#assign _appde = calendarItem.getPSAppDataEntity() /> case "${calendarItem.getItemType()}": arg.${_appde.getCodeName()?lower_case} = $event.event._def.extendedProps.${_appde.getCodeName()?lower_case}; _context.${_appde.getCodeName()?lower_case} = $event.event._def.extendedProps.${_appde.getCodeName()?lower_case}; break; </#if> </#list> </#if> } Object.assign(arg,{viewparams:this.viewparams}); const post: Promise<any> = this.service.update(itemType, JSON.parse(JSON.stringify(_context)), arg, this.showBusyIndicator); post.then((response: any) => { if (!response || response.status !== 200) { if (response.errorMessage) { this.$Notice.error({ title: '错误', desc: response.errorMessage }); } return; } }, (response: any) => { if (response && response.status === 401) { return; } this.$Notice.error({ title: '错误', desc: response.errorMessage }); }); } /** * 选中的数据 * * @returns {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ public selections: any[] = []; /** * 获取多项数据 * * @returns {any[]} * @memberof ${srfclassname('${ctrl.codeName}')} */ public getDatas(): any[] { return this.selections; } /** * 获取单项树 * * @returns {*} * @memberof ${srfclassname('${ctrl.codeName}')} */ public getData(): any { return null; } /** * vue 生命周期 * * @returns * @memberof ${srfclassname('${ctrl.codeName}')} */ public created() { <#if ctrl.getCalendarStyle?? && ctrl.getCalendarStyle() == 'TIMELINE'> this.searchEvents(); <#else> this.setButtonText(); </#if> this.afterCreated(); } /** * 执行created后的逻辑 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public afterCreated(){ if (this.viewState) { this.viewStateEvent = this.viewState.subscribe(({ tag, action, data }) => { if (!Object.is(tag, this.name)) { return; } }); } } /** * vue 生命周期 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public destroyed() { this.afterDestroy(); } /** * 执行destroyed后的逻辑 * * @memberof ${srfclassname('${ctrl.codeName}')} */ public afterDestroy() { if (this.viewStateEvent) { this.viewStateEvent.unsubscribe(); } <#if destroyed_block??> ${destroyed_block} </#if> } <#ibizinclude> ../@MACRO/CONTROL/CONTROL_BOTTOM-BASE.vue.ftl </#ibizinclude> <#ibizinclude> ../@MACRO/CONTROL/CONTROL-BASE.style.ftl </#ibizinclude>