|
@@ -0,0 +1,275 @@
|
|
|
+<script setup>
|
|
|
+import { ref, onMounted,watch, computed } from 'vue';
|
|
|
+import { useRoute } from 'vue-router';
|
|
|
+import { Sticky,Popup } from 'vant';
|
|
|
+
|
|
|
+import '@fullcalendar/core/vdom'; // solve problem with Vite
|
|
|
+import FullCalendar from '@fullcalendar/vue3';
|
|
|
+import timeGridPlugin from '@fullcalendar/timegrid';
|
|
|
+import interactionPlugin from '@fullcalendar/interaction';
|
|
|
+
|
|
|
+import moment from 'moment';
|
|
|
+import 'moment/dist/locale/zh-cn';
|
|
|
+moment.locale('zh-cn');
|
|
|
+import swiperCalendar from './swiperCalendar.vue';
|
|
|
+
|
|
|
+/* props */
|
|
|
+const props = defineProps({
|
|
|
+ eventList: {
|
|
|
+ type: Array,
|
|
|
+ required: true
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+const emits = defineEmits(['dateChange','cellClick']);
|
|
|
+
|
|
|
+const route = useRoute();
|
|
|
+const swiperCalendarRef = ref(null);
|
|
|
+
|
|
|
+const isSeller = computed(()=> ['ficc_seller', 'rai_seller', 'ficc_group', 'rai_group'].includes(localStorage.getItem('ssbg-role')))
|
|
|
+
|
|
|
+
|
|
|
+let isShowPopup = ref(false);//日程弹窗
|
|
|
+const selectEventInfo = ref(null)//日程信息
|
|
|
+
|
|
|
+/* 点击表格日期 */
|
|
|
+const handleDateClick = ({date}) => {
|
|
|
+ emits('cellClick',date)
|
|
|
+};
|
|
|
+
|
|
|
+/* 点击日程 */
|
|
|
+const handleEventClick = (_) => {
|
|
|
+ let id = _.event.id; // 获取当前点击日程的ID
|
|
|
+
|
|
|
+ let event_item = props.eventList.find(item => item.id === Number(id));
|
|
|
+
|
|
|
+ //标题拼接
|
|
|
+ let title = setDynamicTitle(event_item);
|
|
|
+
|
|
|
+ selectEventInfo.value = {...event_item,title};
|
|
|
+ isShowPopup.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+let calendarOptions = ref({
|
|
|
+ height: 'auto',
|
|
|
+ headerToolbar: false, // 顶部工具栏
|
|
|
+ allDaySlot: false, // 全天日程(不需要)
|
|
|
+ locale: 'zh-cn', // 语言
|
|
|
+ nowIndicator: true,
|
|
|
+ plugins: [
|
|
|
+ timeGridPlugin,
|
|
|
+ interactionPlugin, // needed for dateClick
|
|
|
+ ],
|
|
|
+ initialView: 'timeGridDay', //默认显示格式
|
|
|
+ editable: true,
|
|
|
+ selectable: true,
|
|
|
+ selectMirror: true,
|
|
|
+ dayMaxEvents: true,
|
|
|
+ weekends: true,
|
|
|
+ dateClick: handleDateClick,
|
|
|
+ eventClick: handleEventClick,
|
|
|
+ events: [], //日程表
|
|
|
+ eventTimeFormat: {
|
|
|
+ // 格式化日程显示时间,如'14:30'
|
|
|
+ hour: '2-digit',
|
|
|
+ minute: '2-digit',
|
|
|
+ hour12: false,
|
|
|
+ },
|
|
|
+ slotMinTime: '08:00:00', //每天最早8点
|
|
|
+ dayHeaderFormat: {
|
|
|
+ weekday: 'short',
|
|
|
+ // year: 'numeric',
|
|
|
+ month: 'numeric',
|
|
|
+ day: 'numeric',
|
|
|
+ omitCommas: true,
|
|
|
+ }, //顶部显示格式
|
|
|
+ slotLabelFormat: {
|
|
|
+ //格式化左侧显示时间
|
|
|
+ hour12: false, // 14:00 true = 2pm
|
|
|
+ hour: '2-digit', //'06:xx'
|
|
|
+ minute: '2-digit', // 'xx:10'
|
|
|
+ },
|
|
|
+ slotDuration: '01:00:00',//一小时分割
|
|
|
+ eventColor: '#D5E6FF', // 默认日程背景色
|
|
|
+ eventTextColor: '#333', // 默认日程文本颜色
|
|
|
+ weekNumberCalculation: "ISO"
|
|
|
+ // eventClassNames: [ 'myclassname', 'otherclassname' ], // 自定义日程类名
|
|
|
+}); //配置
|
|
|
+
|
|
|
+let calendarApi = ref(null); //日历api
|
|
|
+let FullCalendarRef = ref(null); //ref
|
|
|
+
|
|
|
+
|
|
|
+/* 选中日期改变 更新日历 */
|
|
|
+const datechangeHandle = (date) => {
|
|
|
+
|
|
|
+ calendarApi.value.gotoDate(date)
|
|
|
+ emits('dateChange',date)
|
|
|
+ // document.title = date.substr(0,7);
|
|
|
+}
|
|
|
+
|
|
|
+/* 切换日历和周为本日 */
|
|
|
+const toogeCurrentWeek = () => {
|
|
|
+ swiperCalendarRef.value.getRecentWeek(moment().format('YYYY-MM-DD'))
|
|
|
+ swiperCalendarRef.value.selectDateHandle(moment().format('YYYY-MM-DD'),1)
|
|
|
+}
|
|
|
+
|
|
|
+// 处理数据结构
|
|
|
+const getReservationList = () => {
|
|
|
+ const arr = props.eventList.map((item) => {
|
|
|
+ // let title = (this.isSeller && item.ActivityType==='路演')
|
|
|
+ // ? `${item.CompanyName}${item.CompanyStatus ? '('+ item.CompanyStatus + ')' : ''}` : (this.isSeller && item.ActivityType==='公开会议')
|
|
|
+ // ? item.Theme : setDynamicTitle(item);
|
|
|
+ let title = item.ActivityType==='路演'
|
|
|
+ ? `${item.CompanyName}${item.CompanyStatus ? '('+ item.CompanyStatus + ')' : ''}` : item.ActivityType==='公开会议'
|
|
|
+ ? item.Theme : setDynamicTitle(item);
|
|
|
+
|
|
|
+ return {
|
|
|
+ start: item.StartDate+'T'+item.StartTime ,
|
|
|
+ end: item.EndDate+'T'+item.EndTime,
|
|
|
+ event_id: item.RsCalendarId || item.RsMattersId,
|
|
|
+ id: item.id,
|
|
|
+ title,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ calendarOptions.value.events = arr
|
|
|
+}
|
|
|
+
|
|
|
+// 拼接标题 type 内部会议 公开会议 路演 报告电话会 事项
|
|
|
+const setDynamicTitle = ({ActivityType,RsMattersId,MatterContent,RoadshowType,RoadshowPlatform,Province,City,ActivityCategory,Source,Title}) => {
|
|
|
+
|
|
|
+ //第三方添加的日历活动
|
|
|
+ if(Source === 1) return Title;
|
|
|
+
|
|
|
+ switch(ActivityType || RsMattersId) {
|
|
|
+ case '内部会议': return ActivityType;
|
|
|
+ case '公开会议': return `${RoadshowType}${ActivityType}(${RoadshowType==='线上' ? RoadshowPlatform : Province+City})`;
|
|
|
+ case '路演': return `${RoadshowType}${ActivityType}(${RoadshowType==='线上' ? RoadshowPlatform : Province+City})`;
|
|
|
+ case '报告电话会': return `${ActivityCategory}电话会`;
|
|
|
+ case RsMattersId: return MatterContent;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.eventList,
|
|
|
+ (newval) => {
|
|
|
+ getReservationList();
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ calendarApi.value = FullCalendarRef.value.getApi();
|
|
|
+ datechangeHandle(moment().format('YYYY-MM-DD'))
|
|
|
+});
|
|
|
+
|
|
|
+defineExpose({ toogeCurrentWeek,calendarApi });
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <Sticky>
|
|
|
+ <div class="header">
|
|
|
+ <swiperCalendar @dateChange="datechangeHandle" ref="swiperCalendarRef"/>
|
|
|
+ </div>
|
|
|
+ </Sticky>
|
|
|
+ <FullCalendar :options="calendarOptions" ref="FullCalendarRef">
|
|
|
+ <template #eventContent="arg">
|
|
|
+ <div class="popper-content">
|
|
|
+ <!-- <p>{{ arg.timeText }}</p> -->
|
|
|
+ <p>{{ arg.event.title }}</p>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </FullCalendar>
|
|
|
+
|
|
|
+<!-- 弹窗层 -->
|
|
|
+ <Popup
|
|
|
+ v-model:show="isShowPopup"
|
|
|
+ closeable
|
|
|
+ >
|
|
|
+ <div class="dialog-cont">
|
|
|
+ <p>
|
|
|
+
|
|
|
+ <template v-if="selectEventInfo.StartDate === selectEventInfo.EndDate">
|
|
|
+ {{
|
|
|
+ `${moment(selectEventInfo.StartDate).format("MM.DD")}
|
|
|
+ (${moment(selectEventInfo.StartDate).format('ddd')})
|
|
|
+ ${selectEventInfo.StartTime&&selectEventInfo.StartTime.substr(0,5)} -
|
|
|
+ ${selectEventInfo.EndTime&&selectEventInfo.EndTime.substr(0,5)}`
|
|
|
+ }}
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ {{
|
|
|
+ `${moment(selectEventInfo.StartDate).format("MM.DD")}
|
|
|
+ (${moment(selectEventInfo.StartDate).format('ddd')})
|
|
|
+ ${selectEventInfo.StartTime&&selectEventInfo.StartTime.substr(0,5)} -
|
|
|
+ ${moment(selectEventInfo.EndDate).format("MM.DD")}
|
|
|
+ (${moment(selectEventInfo.EndDate).format('ddd')})
|
|
|
+ ${selectEventInfo.EndTime&&selectEventInfo.EndTime.substr(0,5)}`
|
|
|
+ }}
|
|
|
+ </template>
|
|
|
+
|
|
|
+ </p>
|
|
|
+ <p v-if="isSeller">{{ selectEventInfo.ResearcherName }}</p>
|
|
|
+ <p>{{ selectEventInfo.title }}</p>
|
|
|
+ <p v-if="selectEventInfo.CompanyName" >{{ `${selectEventInfo.CompanyName}${selectEventInfo.CompanyStatus ? '('+ selectEventInfo.CompanyStatus + ')' : ''}` }}</p>
|
|
|
+ <p v-if="selectEventInfo.Theme">{{ selectEventInfo.Theme }}</p>
|
|
|
+ <p v-if="selectEventInfo.CooperationName">{{ selectEventInfo.CooperationName }}</p>
|
|
|
+ <p v-if="['公开会议','内部会议','路演'].includes(selectEventInfo.ActivityType)">发起人:{{selectEventInfo.SysUserRealName}}</p>
|
|
|
+ </div>
|
|
|
+ </Popup>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+
|
|
|
+.header {
|
|
|
+ background: #fff;
|
|
|
+ padding-bottom: 20px;
|
|
|
+ box-shadow: 0px 3px 6px rgba(172, 172, 172, 0.16);
|
|
|
+ .tab-cont {
|
|
|
+ padding: 30px;
|
|
|
+ background: #fff;
|
|
|
+ box-shadow: 0px 3px 12px rgba(175, 175, 175, 0.16);
|
|
|
+ border-bottom: 6px solid #f6f6f6;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ .tab-ul {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ li {
|
|
|
+ margin-right: 50px;
|
|
|
+ color: #666;
|
|
|
+ text-align: center;
|
|
|
+ .item-img {
|
|
|
+ width: 78px;
|
|
|
+ height: 78px;
|
|
|
+ display:block;
|
|
|
+ margin: 0 auto 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.fc {
|
|
|
+ margin: 0 0 160px;
|
|
|
+ ::v-deep(.fc-timegrid-slot) {
|
|
|
+ height: 120px;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep(.fc-timegrid-slot-label) {
|
|
|
+ border-right: none;
|
|
|
+ }
|
|
|
+ ::v-deep(.fc-timegrid-slot) {
|
|
|
+ border-left: none;
|
|
|
+ }
|
|
|
+ ::v-deep(.fc-timegrid-event ) {
|
|
|
+ border-left: 8px solid #3385FF !important;
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.dialog-cont {
|
|
|
+ width: 550px;
|
|
|
+ padding: 40px;
|
|
|
+ p {
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|