diff --git a/app.json b/app.json index a5b527d..7e78fa6 100644 --- a/app.json +++ b/app.json @@ -1,6 +1,6 @@ { "pages": [ - "pages/scheduleList/scheduleList", + "pages/index/index", "pages/meetingRoomList/meetingRoomList", "pages/bindingOutlook/bindingOutlook", "pages/meetingDetail/meetingDetail", @@ -17,4 +17,4 @@ "window": { "allowsBounceVertical": "YES" } -} +} \ No newline at end of file diff --git a/pages/index/index.acss b/pages/index/index.acss new file mode 100644 index 0000000..a8ff959 --- /dev/null +++ b/pages/index/index.acss @@ -0,0 +1,398 @@ +@import "../../template/loading/loading.acss"; +@import "../../template/affairBlank/index.acss"; +@import "../../template/fullScreen/fullScreen.acss"; +.dynamicBox { + width: 100%; + overflow: hidden; + box-sizing: border-box; + padding-bottom: 120rpx; + height: 100vh; +} + +.dynamicList { + width: 100%; +} + +.dynamicDetails { + background: #FFFFFF; + border-radius: 16rpx; + width: 702rpx; + margin: 24rpx 24rpx 0px 24rpx; + padding: 32rpx 24rpx 24rpx 24rpx; + box-sizing: border-box; +} + +.meetingtitle { + font-family: PingFangSC-Medium; + font-size: 34rpx; + color: #1B263D; + line-height: 34rpx; + margin-bottom: 24rpx; + display: flex; + justify-content: space-between; + align-items: center; +} + +.userDynamic { + margin-bottom: 34rpx; +} + +.dynamicDetails .userDynamic:nth-last-child(1) { + margin-bottom: 0; +} + +.dynamicTime { + margin-bottom: 24rpx; +} + +.dynamicTime text:nth-of-type(1) { + opacity: 0.56; + font-size: 26rpx; + color: #1B263D; + letter-spacing: 0; + line-height: 28rpx; + margin-right: 16rpx; +} + +.dynamicTime text:nth-of-type(2) { + font-size: 24rpx; + color: rgba(25, 31, 37, 0.40); + line-height: 24rpx; +} + +.placedTop { + width: 84rpx; + height: 84rpx; + background: #FFFFFF; + border-radius: 50%; + margin-left: 24rpx; + text-align: center; + line-height: 84rpx; +} + +.dynamicContent { + display: flex; + align-items: center; + width: 906rpx; +} + +.isMove { + transform: translateX(-156rpx); + transition: all 150ms linear 0s; +} + +.placedTop .iconicon_top1 { + font-size: 48rpx; + color: rgb(234, 12, 40); +} + +.placedTop .isTopIcon { + color: rgba(10, 10, 10, 0.72); +} + +.noDate { + position: fixed; + left: 0; + top: 0; + background: #FFFFFF; + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.scroll-lock { + height: 100%; + overflow-y: hidden; + position: fixed; + top: 0; + left: 0; + bottom: 0; +} + +.icon-color { + opacity: 0.4; +} + +.index { + background: #FFFFFF; +} + +.scheduleHeader { + width: 100%; + height: 88rpx; + background: #FFFFFF; + line-height: 88rpx; + padding: 0 32rpx; + display: flex; + justify-content: space-between; + box-shadow: 0 2rpx 10rpx 3rpx rgba(0, 0, 0, 0.04); + z-index: 9; + position: relative; +} + +.scheduleHeader view:nth-of-type(1) { + flex: 1; + color: rgba(10, 10, 10, 1); + font-size: 40rpx; + font-weight: bold; +} + +.scheduleHeader view:nth-of-type(2) { + width: 40rpx; + height: 40rpx; +} + +.headerIcon { + position: relative; +} + +.headerIcon>view { + position: absolute; + left: 28rpx; + top: 52rpx; + width: 12rpx; + height: 12rpx; + border: 2rpx solid #FFFFFF; + border-radius: 50%; + background: #EA0C28; +} + +.headerIcon .iconicon_app1 { + font-size: 44rpx; + color: rgba(27, 38, 61, 0.4); +} + +.year, .month, .week, .date { + height: 96rpx; + font-size: 48rpx; +} + +.year, .month, .week { + line-height: 96rpx; + padding-left: 32rpx; +} + +.year, .month { + font-weight: bold; + font-family: 'DINAlternate-Bold'; +} + +.week { + font-size: 26rpx; + color: rgba(25, 31, 37, 0.39); + padding-left: 120rpx; +} + +.date { + display: flex; + padding: 0 32rpx 0 0; + margin-bottom: 32rpx; +} + +.today { + border-left: 8rpx solid rgba(234, 12, 40, 1); +} + +.todayNoData { + height: 96rpx; + line-height: 96rpx; + padding-left: 16rpx; + font-size: 28rpx; + color: rgba(25, 31, 37, 0.39); +} + +.todayNoData text:nth-of-type(2) { + color: rgba(25, 31, 37, 0.39); +} + +.todayNoData text:nth-of-type(2) { + color: #191F25; +} + +.overdue { + background: rgba(10, 10, 10, .034) !important; + color: rgba(10, 10, 10, .353) !important; +} + +.overdue text { + color: rgba(10, 10, 10, .353) !important; +} + +.overdueLabel { + color: rgba(10, 10, 10, .353) !important; +} + +.cancel { + background: url(../../assests/cancel.png) center /100% 100% !important; + border: 1rpx solid rgba(97, 155, 212, 0.28) !important; + color: rgba(25, 31, 37, 0.56) !important; +} + +.cancel text { + text-decoration: line-through; +} + +.hasDateTitle { + display: flex; + align-items: center; + justify-content: center; + height: 96rpx; + width: 112rpx; + flex-direction: column; + font-family: DINAlternate-Bold, DINAlternate; + font-weight: bold; + padding-top: 6rpx; +} + +.hasDateTitle view:nth-of-type(1) { + font-size: 24rpx; +} + +.hasDateTitle view:nth-of-type(2) { + font-size: 48rpx; +} + +.scheduleBox { + flex: 1; + height: 96rpx; + padding: 16rpx; + background: rgba(10, 10, 10, 0.05); + border-radius: 4px; +} + +.scheduleTitle { + font-weight: 500; + color: rgba(10, 10, 10, .72); + font-size: 28rpx; + margin-bottom: 10rpx; + line-height: 28rpx; +} + +.scheduleTime { + font-size: 26rpx; + font-weight: 400; + color: rgba(10, 10, 10, .72); + line-height: 26rpx; +} + +.cancel { + width: 602rpx; + overflow: hidden; + background: url(../../assests/cancel.png) center /100% 100%; + border: 1rpx solid rgba(25, 31, 37, 0.28); + color: rgba(25, 31, 37, 0.56); +} + +.indexScrollView { + height: calc( 100vh - 88rpx); + background: #Fff; +} + +.tabBarContent { + width: 100%; + position: fixed; + left: 0; + bottom: 0; +} + +.tabBar { + height: 120rpx; + width: 100%; + background: url('../../assests/tabBarBg.png'); + background-size: cover; + display: flex; + padding-top: 4rpx; + /* box-shadow: 0 -4rpx 8rpx 0 rgba(0,0,0,0.04); + border-radius: 0 64rpx 0 64rpx 0 0 0; */ +} + +.tabBar>view { + flex: 1; + font-size: 28rpx; +} + +.tabBar>view:nth-of-type(1) { + text-align: left; +} + +.tabBar>view:nth-of-type(2) { + text-align: right; +} + +.createMeeting { + position: absolute; + left: 50%; + top: 8rpx; + font-size: 32rpx; + border-radius: 50%; + height: 84rpx; + width: 84rpx; + background: #EA0C28; + box-shadow: 0 4px 7px 0 rgba(234, 12, 40, 0.30); + margin-left: -42rpx; + color: #FFFFFF; + text-align: center; + display: flex; + align-items: center; + justify-content: center; +} + +.createMeeting .iconfont { + font-size: 34rpx; + display: block +} + +.tabBarView { + display: flex; + flex-direction: column; + height: 116rpx; + justify-content: center; +} + +.tabBarView1 { + padding-left: 140rpx; + align-items: flex-start; +} + +.tabBarView2 { + padding-right: 140rpx; + align-items: flex-end; +} + +.tabBarView>view { + display: block; + color: rgba(10, 10, 10, .4) +} + +.tabBarView>view:nth-of-type(1) { + width: 42rpx; + height: 42rpx; + font-size: 42rpx; + margin-bottom: 11rpx; +} + +.tabBarView>view:nth-of-type(2) { + height: 10rpx; + font-size: 20rpx; +} + +.ischooseTabBar>view { + color: rgba(10, 10, 10, 1) !important; +} + +.iconicon_Calendarbox1 { + position: relative; +} + +.iconicon_days { + position: absolute; + left: 7rpx; + top: 10rpx; + font-size: 27rpx; +} + +.tabBarView .iconicon_days { + color: #FFFFFF !important; +} \ No newline at end of file diff --git a/pages/index/index.axml b/pages/index/index.axml new file mode 100644 index 0000000..c8595bc --- /dev/null +++ b/pages/index/index.axml @@ -0,0 +1,149 @@ +<import src="../../template/loading/loading.axml"/> +<import src="../../template/fullScreen/fullScreen.axml"/> +<view hidden="{{$data.tabBarIndex === '1'}}"> + <import src="../../template/affairBlank/index.axml"/> + <view class="{{isStopBodyScroll ? 'scroll-lock' : ''}}" onTap="closeSwipe" onTouchStart="closeSwipe" onTouchMove="closeSwipe" onTouchEnd="closeSwipe"> + <block a:if="{{!listLoading}}"> + <scroll-view a:if="{{dynamicList.length > 0}}" scroll-y="{{true}}" lower-threshold="{{400}}" class="dynamicBox" onScrollToLower="onScrollToLower"> + <view class="dynamicList"> + <swipe onSetBodyDisableScroll="setBodyDisableScroll" rightWidth="{{ 78 }}" leftWidth="{{ 0 }}" a:for="{{dynamicList}}" class="dynamicContent" key="{{item.scheduleId}}"> + <view class="dynamicDetails"> + <view class="meetingtitle" catchTap="nextDetail" data-item="{{item}}"> + <view> + {{item.title}} + </view> + <view> + <text a:if="{{item.traceTime !== traceTime}}" class="iconfont iconicon_top1 icon-color"></text> + </view> + </view> + <block a:for="{{item.meetingLogDataList.slice(0,2)}}" a:for-item="dynamicItem" key="{{item.id}}"> + <view class="userDynamic"> + <view class="dynamicTime" catchTap="nextDetail" data-item="{{dynamicItem}}"> + <text>{{dynamicItem.content}}</text> + <text>{{dynamicItem.createTime}}</text> + </view> + <file-list a:if="{{dynamicItem.category === '2'}}" fileView="{{dynamicItem.meetingLogResource}}" isCanEdit="{{false}}"/> + <view class="dynamicFile" a:if="{{dynamicItem.category === '3'}}"> + <task-list onChangeTaskStatusOnList="onChangeTaskStatusOnList" taskList="{{[dynamicItem.meetingLogResource]}}" isCanEdit="{{false}}"/> + </view> + </view> + </block> + </view> + <view slot="right" class="placedTop" onTap="changeCollection" data-scheduleId="{{item.scheduleId}}" data-index="{{index}}" data-collection="{{item.traceTime === traceTime ? 'Y':'N'}}"> + <text class="iconfont iconicon_top1 {{item.traceTime === traceTime ? '': 'isTopIcon'}}"></text> + </view> + </swipe> + </view> + </scroll-view> + <view class="noDate" a:else> + <template is="affair-placeholder" data="{{title: '展示安排的所有动态', tip: '实时同步所有事件的最新动态,便于随时处理工作内容'}}"/> + </view> + </block> + <template is="loading" a:else> + </template> + </view> +</view> +<view hidden="{{$data.tabBarIndex === '0'}}"> + <view a:if="{{!loading}}"> + <view class="scheduleHeader"> + <view>{{currentData.split('/')[0]}}年{{currentData.split('/')[1] || '1'}}月</view> + <view onTap="changesidebar" class="headerIcon"> + <text class="iconfont iconicon_app1"> + </text> + <view> + </view> + </view> + </view> + <scroll-view class="indexScrollView" scroll-y="{{true}}" onScroll="scroll" lower-threshold="{{400}}" onScrollToLower="lower" scroll-into-view="{{todayStr}}"> + <block a:for="{{scheduleList}}" key="{{item.dateStr}}"> + <!-- 年 --> + <block a:if="{{item.type == 'year'}}"> + <view class="year li" id="{{item.dateStr}}"> + {{item.value}}年 + </view> + </block> + <!-- 月 --> + <block a:elif="{{item.type == 'month'}}"> + <view class="month li" id="{{item.dateStr}}"> + {{item.value}}月 + </view> + </block> + <!-- 周 --> + <block a:elif="{{item.type == 'week'}}"> + <view class="week li" id="{{item.dateStr}}"> + {{item.value}} + </view> + </block> + <!-- 天 --> + <block a:elif="{{item.type == 'day' || item.type == 'today'}}"> + <view class="date li" id="{{ item.dateStr}}"> + <view class="hasDateTitle {{item.type == 'today' && item.hasDateLabel ? 'today' : ''}} {{item.value.isBeOverdue ? 'overdueLabel':''}}"> + <view> + {{item.week}} + </view> + <view>{{item.hasDateLabel}}</view> + </view> + <view class="scheduleBox {{item.value.isBeOverdue ? 'overdue' : item.value.confirmAttendance === 0 ? 'cancel' : ''}}" data-item="{{item.value}}" onTap="nextDetail"> + <view class="scheduleTitle"> + <text>{{item.value.title}}{{item.value.isDaySpan ? `(第${item.value.isFewDays}天,共${item.value.duration}天)` : '' }}</text> + </view> + <view class="scheduleTime"> + <text a:if="{{item.value.isDaySpan && item.value.isfirstDayOrEndDay === '0'}}">{{item.value.thisDayStartTime}}</text> + <text a:elif="{{item.value.isDaySpan && item.value.isfirstDayOrEndDay === '1'}}">全天</text> + <text a:elif="{{item.value.isDaySpan && item.value.isfirstDayOrEndDay === '2'}}">直到{{item.value.thisDayEndTime}}</text> + <text a:else>{{item.value.thisDayStartTime}} - {{item.value.thisDayEndTime}}</text> + </view> + </view> + </view> + </block> + <!-- 今天有无会议 --> + <block a:elif="{{item.type == 'thisday'}}"> + <view class="date li" id="{{item.dateStr}}"> + <view class="hasDateTitle today"> + <view> + {{item.week}} + </view> + <view>{{item.hasDateLabel}}</view> + </view> + <view class="todayNoData"> + <text>暂无日程安排,</text> + <text onTap="createMeeting">创建日程</text> + </view> + </view> + </block> + </block> + </scroll-view> + <popup show="{{show}}" onClose="closePop" position="left"> + <related-app/> + </popup> + </view> + <template is="loading" a:else> + </template> +</view> +<view class="tabBarContent"> + <view class="tabBar"> + <view onTap="changeTabBar" data-tabbar='0' data-title='动态'> + <view class="tabBarView tabBarView1 {{$data.tabBarIndex === '0' ? 'ischooseTabBar' : ''}}"> + <view class="iconfont iconicon_dynamic"></view> + <view>动态</view> + </view> + </view> + <view onTap="changeTabBar" data-tabbar='1' data-title='日程'> + <view class="tabBarView tabBarView2 {{$data.tabBarIndex === '1' ? 'ischooseTabBar' : ''}}"> + <view class="iconfont iconicon_Calendarbox1"> + <text a:if="{{offset == 'before'}}" class="iconfont iconicon_days iconicon_open"> + </text> + <text a:elif="{{offset == 'next'}}" class="iconfont iconicon_days iconicon_Packup"> + </text> + <text a:else class="iconfont iconicon_days iconicon_days{{iconDay}}"> + </text> + </view> + <view>日程</view> + </view> + </view> + <view class="createMeeting" onTap="createMeeting"> + <text class="iconfont iconicon_add1"></text> + </view> + </view> + <template is="fullScreen" data="{{isIPX:isFullscreen}}" /> +</view> \ No newline at end of file diff --git a/pages/index/index.js b/pages/index/index.js new file mode 100644 index 0000000..e080581 --- /dev/null +++ b/pages/index/index.js @@ -0,0 +1,747 @@ +import { RRule } from "rrule"; +import { + getDynamicList, + meetingCollection, + updateMeetingTask, + getHomeUserSchedule1 +} from "../../api/request"; +import { + getDateMap, + getExcludeDate, + getNextDateList, + getWeekNumber, + getBlankList, + toLocaleDateString +} from "./schedule.js"; +import { + getFormatDate, + throttle, + padZero, + getCreateShowTime +} from "../../utils/utils"; +const currentDate = new Date(); +const minYear = 2020; +const maxYear = currentDate.getFullYear() + 1; +let DateMap = getDateMap(minYear, maxYear); +const weekList = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]; +import create from "dd-store"; +let maxClickCount = 5; +create.Page({ + data: { + $data: null, + iconDay: currentDate.getDate(), + scheduleList: [], + todayStr: toLocaleDateString(currentDate), + currentData: toLocaleDateString(currentDate), + currentDataIndex: 0, + offset: "stop", + show: false, + loading: true, + traceTime: "1970-03-01 00:00:00", + isStopBodyScroll: false, + dynamicList: [], + current: 1, + pages: 1, + listLoading: true, + isFullscreen: false + }, + scrollTop: 0, + pageSize: 10, + totalPages: 1, + currentPage: 1, + firstPage: 1, + scheduleList: [], + timer: null, + isFirstLoad: true, + blankDataLength: 0, + blankDataLengthAfter: 0, + minYear: minYear, + maxYear: maxYear, + todayIndex: 0, + onShow() { + //如果是重复会议重新算 + if (this.$store.data.indexNeedUpdate) { + dd.setNavigationBar({ + title: "日程" + }); + DateMap = getDateMap(this.minYear, this.maxYear); + this.getData(); + this.isFirstLoad = true; + this.$store.data.indexNeedUpdate = false; + this.update(); + } + //单次会议往DateMap中添加 + if (this.$store.data.onceMeetingContent) { + this.getScheduleList(this.$store.data.onceMeetingContent, "once"); + this.$store.data.onceMeetingContent = null; + this.update(); + } + //刷新动态列表 + if (this.$store.data.isIndexAffairListNeedUpdate) { + this.getPages(1); + this.$store.data.isIndexAffairListNeedUpdate = false; + this.update(); + } + }, + onLoad() { + this.setData({ + isFullscreen: getApp().globalData.isFullscreen + }); + dd.setNavigationBar({ + title: "动态" + }); + //获取动态列表 + this.getPages(1); + //获取日程列表 + this.getData(); + this.isFirstLoad = true; + }, + //动态列表侧滑的时候禁止页面上下滑动 + setBodyDisableScroll(isStopBodyScroll) { + this.setData({ + isStopBodyScroll + }); + }, + //点击页面关闭侧滑模块 + closeSwipe() { + if (this.$store.closeActiveSwipe) { + this.$store.closeActiveSwipe(); + } + }, + getPages(current, callBack) { + getDynamicList({ + current, + size: 10 + }).then(res => { + if (!res.data.data) { + this.setData({ + listLoading: false + }); + return; + } + const dynamicList = res.data.data.records.map((item, index) => { + for (let i = 0; i < item.meetingLogDataList.length; i++) { + if (item.meetingLogDataList[i].creatorInfo) { + item.meetingLogDataList[i].creatorInfo = JSON.parse( + item.meetingLogDataList[i].creatorInfo + ); + } + if (item.meetingLogDataList[i].createTime) { + item.meetingLogDataList[i].createTime = getCreateShowTime( + item.meetingLogDataList[i].createTime + ); + } + let itemData = item.meetingLogDataList[i].meetingLogResource; + if (itemData) { + itemData.groupId = item.groupId; + if (itemData.taskInfos || itemData.fileInfos) { + if (itemData.creatorInfo) { + itemData.creatorInfo = JSON.parse(itemData.creatorInfo); + } + if (itemData.fileInfos) { + itemData.fileInfos = JSON.parse(itemData.fileInfos); + } + if (itemData.taskInfos) { + itemData.taskInfos = JSON.parse(itemData.taskInfos); + } + if (itemData.acceptorInfo) { + itemData.acceptorInfo = JSON.parse(itemData.acceptorInfo); + } + } + } + } + return item; + }); + + //第一页数据会重新请求需要替换 + if (current === 1) { + this.setData({ + dynamicList + }); + } else { + const newDynamicList = this.data.dynamicList.concat(dynamicList); + this.setData({ + dynamicList: newDynamicList + }); + } + this.setData({ + listLoading: false, + current: res.data.data.current, + pages: res.data.data.pages + }); + if (callBack) { + callBack(); + } + }); + }, + //动态置顶 + changeCollection(e) { + const { index, scheduleId, collection } = e.target.dataset; + meetingCollection({ + scheduleId, + collection + }).then(res => { + //取消置顶 + if (collection === "N") { + // 重新获取第一页的数据 + this.getPages(1, () => { + dd.showToast({ + content: "取消成功" + }); + }); + } else { + //置顶 + const dynamicList = this.data.dynamicList; + const replaceItem = dynamicList[index]; + dynamicList[index].traceTime = res.data.data; + dynamicList.splice(index, 1); + dynamicList.unshift(replaceItem); + this.setData( + { + dynamicList: dynamicList + }, + () => { + dd.showToast({ + content: "置顶成功" + }); + } + ); + } + }); + }, + //动态上拉加载分页数据 + onScrollToLower() { + if (this.data.current < this.data.pages) { + this.getPages(this.data.current + 1); + } + }, + //动态修改状态 + onChangeTaskStatusOnList(e) { + const data = { + groupId: e.groupId, + scheduleId: e.scheduleId, + resourceType: "task", + creatorId: getApp().globalData.userid, + creatorInfo: getApp().globalData.userInfo, + id: e.id, + logType: "task_status_modify", + taskStatus: e.status + }; + updateMeetingTask(data).then(res => { + if (res.data.code === 0) { + let dataIndex1 = ""; + let dataIndex2 = ""; + this.data.dynamicList.forEach((item, index) => { + if (item.scheduleId === e.scheduleId) { + dataIndex1 = index; + item.meetingLogDataList.forEach((it, index2) => { + if (it.meetingLogResource.id == e.id) { + dataIndex2 = index2; + } + }); + } + }); + const setData = `dynamicList[${dataIndex1}].meetingLogDataList[${dataIndex2}].meetingLogResource.taskStatus`; + this.setData({ + [setData]: e.status + }); + } + }); + }, + //日程获取分页数据 + getPagination(scheduleList = []) { + this.totalPages = Math.ceil(scheduleList.length / this.pageSize); + for (let i = 0; i < scheduleList.length; i++) { + if (scheduleList[i].dateStr == toLocaleDateString(currentDate)) { + const centerPage = Math.floor(i / this.pageSize); + this.todayIndex = i; + this.setData({ + currentDataIndex: i + }) + // firstPage转为4的倍数,一次下拉加载40条 + const firstPage = centerPage - 2; + this.firstPage = + firstPage % 4 == 0 ? firstPage : firstPage - (firstPage % 4); + this.currentPage = centerPage + 2; + break; + } + } + }, + getData() { + getHomeUserSchedule1({ + startTime: "2020-01-01 00:00:00", + endTime: "2025-12-30 23:59:59" + }).then(res => { + this.getScheduleList(res.data.data); + }); + }, + //生成DateMap值 + setDateMapValue(startTime, endTime, item, type) { + const pushItem = { + endTime: endTime, + startTime: startTime, + planDate: getFormatDate(startTime, "yyyyMMdd", "-"), + thisDayStartTime: getFormatDate(startTime, "HH:mm"), + thisDayEndTime: getFormatDate(endTime, "HH:mm"), + confirmAttendance: item.confirmAttendance, + title: item.title, + id: item.id, + isBeOverdue: currentDate.getTime() > endTime.getTime() ? true : false + }; + //模板会议id为空 + if (type == "repeat") { + pushItem.scheduleTemplateId = item.id; + pushItem.id = ""; + } + + // 如果是跨天会议,需要手动在起始天以后的其他天 添加会议日程 + const nextDateList = getNextDateList(startTime, endTime); //返回日期包括起始天 + if (nextDateList.length > 1) { + pushItem.isDaySpan = true; + pushItem.isFewDays = 1; + pushItem.isfirstDayOrEndDay = "0"; // 0 第一天,1中间的天,2结束的天 + pushItem.duration = nextDateList.length; + for (let i = 1; i < nextDateList.length; i++) { + if (DateMap.has(nextDateList[i])) { + DateMap.get(nextDateList[i]).unshift({ + ...pushItem, + isFewDays: i + 1, + isfirstDayOrEndDay: nextDateList.length - 1 === i ? "2" : "1" // 0 第一天,1中间的天,2结束的天 + }); + } + } + } + + if (DateMap.has(toLocaleDateString(startTime))) { + DateMap.get(toLocaleDateString(startTime)).push(pushItem); + } + }, + // 根据接口返回数据生成填充DateMap + setDateMapByResponse(response) { + if (response) { + // 处理单次会议 scheduleList + const scheduleListWithTemplateId = []; + response.scheduleList.forEach(item => { + // 有scheduleTemplateId则是虚拟会议转成实体会议,需要替换rrule生成的模板会议 + if (item.scheduleTemplateId) { + scheduleListWithTemplateId.push(item); + } else { + this.setDateMapValue( + new Date(item.startTime.replace(/-/g, "/")), + new Date(item.endTime.replace(/-/g, "/")), + item + ); + } + }); + + // 处理重复会议 templateList + response.templateList.forEach(item => { + //日程会议 + const itemScheduleList = scheduleListWithTemplateId.filter( + it => it.scheduleTemplateId == item.id + ); + // 生成rrules规则 + const initialTimeList = item.initialTime.split("-"); + const startTimeList = item.startTime.split(":"); + const DTSTART = `${initialTimeList[0]}${initialTimeList[1]}${initialTimeList[2]}T${startTimeList[0]}${startTimeList[1]}00Z`; + const rule = RRule.fromString( + `${item.recurrenceModel.recurrenceRule};DTSTART=${DTSTART}` + ); + + const setDateMapValueAll = (startTime, endTime, item) => { + //如果有日程会议则用日程会议替换 + let replaceItem = []; + if (itemScheduleList.length > 0) { + replaceItem = itemScheduleList.filter( + it => it.planDate == getFormatDate(startTime, "yyyyMMdd", "-") + ); + } + if (replaceItem.length > 0) { + this.setDateMapValue( + new Date(replaceItem[0].startTime.replace(/-/g, "/")), + new Date(replaceItem[0].endTime.replace(/-/g, "/")), + replaceItem[0] + ); + } else { + this.setDateMapValue(startTime, endTime, item, "repeat"); + } + }; + // 需要剔除某一天 + if (item.excludePlanDates) { + const excludeData = getExcludeDate(item.excludePlanDates.split(",")); + rule.all().forEach(startTime => { + //修正时间(时间有8小时时差) + startTime.setHours(startTime.getHours() - 8); + // 生成结束时间 + const endTime = new Date(startTime); + endTime.setMinutes( + endTime.getMinutes() + item.recurrenceModel.duration + ); + // 剔除规则: 时间小于futureTime 时间不在单个排除日期里面 + if ( + startTime.getTime() < excludeData.minFutureTime && + !excludeData.excludeDateList.includes( + getFormatDate(startTime, "yyyyMMdd", "-") + ) + ) { + setDateMapValueAll(startTime, endTime, item); + } + }); + } + // 正常生成数据 + else { + rule.all().forEach(startTime => { + //修正时间(时间有8小时时差) + startTime.setHours(startTime.getHours() - 8); + // 生成结束时间 + const endTime = new Date(startTime); + endTime.setMinutes( + endTime.getMinutes() + item.recurrenceModel.duration + ); + setDateMapValueAll(startTime, endTime, item); + }); + } + }); + } + }, + //日程数据 + getScheduleList(response, type) { + if (type == "once") { + this.setDateMapValue(response.startTime, response.endTime, response); + } else { + this.setDateMapByResponse(response); + } + // 取出DateMap的value值平铺到DateList + const DateList = []; + DateMap.forEach(function (value, key) { + const keyDate = new Date(key); + const year = keyDate.getFullYear(); + const month = keyDate.getMonth(); + const date = keyDate.getDate(); + const day = keyDate.getDay(); + + // 生成年 + if (month === 0 && date === 1) { + DateList.push({ + type: "year", + value: year, + dateStr: `${year}` + }); + } + //生成月 + if (date === 1) { + DateList.push({ + type: "month", + value: month + 1, + dateStr: `${year}/${month + 1}` + }); + } + //生成周 + if (day === 0) { + const rangeDate = new Date(year, month, date + 6); + const rangeMonth2 = new Date(rangeDate).getMonth(); + const rangeDay2 = new Date(rangeDate).getDate(); + DateList.push({ + type: "week", + value: `第${getWeekNumber(year, month, date)}周,${month + + 1}月${date}日 - ${ + rangeMonth2 == month ? "" : rangeMonth2 + 1 + "月" + }${rangeDay2}日`, + dateStr: `${year}/${month + 1}/${date}-week` + }); + } + // 有日程长度 + if (value.length !== 0) { + value.forEach((item, index) => { + if (index === 0) { + DateList.push({ + type: key !== toLocaleDateString(currentDate) ? "day" : "today", + week: weekList[day], + hasDateLabel: padZero(date), + value: item, + dateStr: `${key}` + }); + } else { + DateList.push({ + type: "day", + value: item, + dateStr: `${key}/${item.id || item.scheduleTemplateId}` + }); + } + }); + } else if ( + value.length === 0 && + key === toLocaleDateString(currentDate) + ) { + DateList.push({ + type: "thisday", + value: "", + hasDateLabel: padZero(date), + week: weekList[day], + dateStr: key + }); + } + }); + this.scheduleList = DateList; + + this.getPagination(this.scheduleList); + // 第一次加载 + this.setData({ + scheduleList: this.scheduleList.slice( + this.firstPage * this.pageSize, + this.currentPage * this.pageSize + ), + loading: false + }); + }, + //日程上拉加载 + lower() { + if (this.currentPage < this.totalPages) { + this.currentPage++; + this.setData({ + scheduleList: this.scheduleList.slice( + this.firstPage * this.pageSize, + this.currentPage * this.pageSize + ) + }); + } else { + //超出加载一年的数据 + this.maxYear++; + const yearData = getBlankList(this.maxYear); + this.blankDataLengthAfter += yearData.length; + this.scheduleList.push(...yearData); + this.setData({ + scheduleList: this.scheduleList.slice(this.firstPage * this.pageSize) + }); + } + }, + onPullDownRefresh() { + if (this.$store.data.tabBarIndex == "0") { + this.getPages(1); + dd.stopPullDownRefresh(); + return; + } + //日程页面到顶部的时候才下拉加载数据,否则定位距离太长 + if (this.$store.data.tabBarIndex == "1" && this.scrollTop !== 0) { + dd.stopPullDownRefresh(); + return; + } + // const todayStr = this.data.scheduleList[0].dateStr; + if (this.firstPage > 0) { + this.firstPage -= 4; + this.currentPage -= 4; + this.setData( + { + todayStr: "", + scheduleList: this.scheduleList.slice( + this.firstPage * this.pageSize, + this.currentPage * this.pageSize + ) + }, + () => { + this.setData({ + todayStr: this.data.scheduleList[this.pageSize * 4 - 1].dateStr + }); + dd.stopPullDownRefresh(); + } + ); + } else { + this.minYear--; + const yearData = getBlankList(this.minYear); + this.blankDataLength += yearData.length; + this.todayIndex += yearData.length; + this.scheduleList.unshift(...yearData); + this.totalPages = Math.ceil(this.scheduleList.length / this.pageSize); + this.currentPage = Math.floor((yearData.length * 2) / this.pageSize); + this.setData( + { + todayStr: "", + scheduleList: this.scheduleList.slice(0, yearData.length * 2) + }, + () => { + this.setData({ + //加载一年的数据重定位可能会有点问题,重置一下 + currentData: this.scheduleList[yearData.length - 1].dateStr, + currentDataIndex: yearData.length - 1, + todayStr: this.scheduleList[yearData.length - 1].dateStr + }); + dd.stopPullDownRefresh(); + } + ); + } + }, + scroll(e) { + // 一次性惯性拉到顶速度跟不上,重置 + if (e.detail.scrollTop == 0) { + this.setData({ + currentData: this.data.scheduleList[0].dateStr, + currentDataIndex: 0 + }); + } + //每次计算偏移值 + const offset = this.getScrollOffset(e.detail.scrollTop); + dd.createSelectorQuery().selectAll('.li').boundingClientRect().exec((rect) => { + //日程的上下箭头 + if (rect[0]) { + this.setScrollOffset(rect); + } + if (offset == 'next') { + for (let i = this.data.currentDataIndex; i < rect[0].length; i++) { + if (rect[0][i].top > 0) { + if (this.data.scheduleList[i].dateStr.split('/')[1] !== this.data.currentData.split('/')[1]) { + this.setData({ + currentData: this.data.scheduleList[i].dateStr, + currentDataIndex: i + }) + } + break; + } + } + } else if (offset == "before") { + let i = Math.min(this.data.currentDataIndex, this.data.scheduleList.length - 1); + for (; i > 0; i--) { + if (rect[0][i].top < 50) { + if (this.data.scheduleList[i].dateStr.split("/")[1] !== this.data.currentData.split("/")[1]) { + this.setData({ + currentData: this.data.scheduleList[i].dateStr, + currentDataIndex: i + }); + } + break; + } + } + } + }); + }, + //判断滚动方向 + getScrollOffset(scrollTop) { + let offset = "stop"; + if (scrollTop > this.scrollTop) { + //向下滚动 + offset = "next"; + } else { + //向上滚动 + offset = "before"; + } + this.scrollTop = scrollTop; + return offset; + }, + setScrollOffset(rect) { + if (rect[0][this.todayIndex]) { + if (rect[0][this.todayIndex].top <= 60 && rect[0][this.todayIndex].top >= 30) { + if (this.data.offset !== 'stop') { + this.setData({ offset: 'stop' }) + } + } else if (rect[0][this.todayIndex].top < 60) { + if (this.data.offset !== 'next') { + this.setData({ offset: 'next' }) + } + + } else if (rect[0][this.todayIndex].top > 30) { + if (this.data.offset !== 'before') { + this.setData({ offset: 'before' }) + } + } + } else { + if (this.data.offset !== 'before') { + this.setData({ offset: 'before' }) + } + } + }, + closePop() { + this.setData({ + show: false + }); + }, + changesidebar() { + this.setData({ + show: true + }); + }, + createMeeting() { + dd.navigateTo({ url: "./../createMeeting/createMeeting" }); + }, + nextDetail: throttle(function (e) { + dd.navigateTo({ + url: `./../meetingDetail/meetingDetail?scheduleItem=${encodeURIComponent( + JSON.stringify(e.target.dataset.item) + )}` + }); + }, 1000), + backToToday(type) { + if (!type) { + //如果当前的日期还没加载出来点击无效 + const isFindArr = this.data.scheduleList.filter(it => it.dateStr == toLocaleDateString(currentDate)); + if (isFindArr.length == 0) { + //去掉头部空数据 + if (this.minYear < minYear) { + this.scheduleList.splice(0, this.blankDataLength); + this.minYear = minYear; + } + //去掉尾部数据 + if (this.maxYear > maxYear) { + this.scheduleList.splice(-this.blankDataLengthAfter); + this.maxYear = maxYear; + } + this.getPagination(this.scheduleList); + this.setData({ + scheduleList: this.scheduleList.slice(this.firstPage * this.pageSize, this.currentPage * this.pageSize) + }); + } + } + //需要先清空todayStr再设置才有效 + this.setData( + { + todayStr: "" + }, + () => { + this.setData({ + todayStr: toLocaleDateString(currentDate) + }); + } + ); + }, + // 修改tabBar + changeTabBar(e) { + const { tabbar, title } = e.currentTarget.dataset; + const lastTimeTabBarIndex = this.$store.data.tabBarIndex; + this.$store.data.tabBarIndex = tabbar; + this.update(); + + dd.setNavigationBar({ + title: title + }); + + if (this.isFirstLoad) { + this.backToToday("first"); + this.isFirstLoad = false; + } + if (lastTimeTabBarIndex == tabbar) { + if (tabbar == "1") { + this.backToToday(); + } + } else { + //切换到动态页面时,日程重置成当前日期 + if (tabbar == "0") { + this.lastOffset = this.data.offset; + this.setData({ + offset: 'stop' + }) + } else if (!this.isFirstLoad) { + this.setData({ + offset: this.lastOffset + }) + } + } + }, + + onTitleClick() { + maxClickCount--; + if (maxClickCount == 0) { + dd.alert({ + content: "版本号199" + }); + maxClickCount = 5; + } + } +}); diff --git a/pages/index/index.json b/pages/index/index.json new file mode 100644 index 0000000..411584b --- /dev/null +++ b/pages/index/index.json @@ -0,0 +1,11 @@ +{ + "allowsBounceVertical": "YES", + "pullRefresh": true, + "usingComponents": { + "task-list": "../../components/taskList/taskList", + "file-list": "../../components/fileList/fileList", + "swipe": "../../components/swipe/swipe", + "popup": "../../components/popup/index", + "related-app": "../../components/relatedApp/relatedApp" + } +} \ No newline at end of file diff --git a/pages/index/schedule.js b/pages/index/schedule.js new file mode 100644 index 0000000..c6c0e42 --- /dev/null +++ b/pages/index/schedule.js @@ -0,0 +1,141 @@ +export function getDateMap(minYear, maxYear) { + const DateMap = new Map(); + const getOneYear = (year) => { + const yearDays = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ? 366 : 365; + for (let i = 1; i <= yearDays; i++) { + DateMap.set(toLocaleDateString(new Date(year, 0, i)), []); + } + } + for (let i = minYear; i <= maxYear; i++) { + getOneYear(i); + } + return DateMap +} + +// 返回删除的日期 +/** + * 如果删除单次重复会议返回['2020-04-20'], + * 如果删除此次及以后重复会议返回['future2020-04-20'] + */ +export function getExcludeDate(data = []) { + const excludeDateList = []; + const futureList = []; + data.forEach(item => { + //删除此次及以后 + if (item.length > 10) { + futureList.push(new Date(item.slice(6, 16).replace(/-/g, "/")).getTime()); + } + //删除单次 + else { + excludeDateList.push(item); + } + }); + return { + excludeDateList, + minFutureTime: Math.min(...futureList) + }; +} + +// 返回跨天数 +export function getNextDateList(startTime, endTime) { + let days = 0; + const nextDateList = []; + if (startTime.getDate() !== endTime.getDate()) { + //同一个月 + if (startTime.getMonth() == endTime.getMonth()) { + days = endTime.getDate() - startTime.getDate(); + } + //跨月 + else { + // 一个月份有多少天new Date(year, month, 0).getDate() + const startMonth = new Date(startTime.getFullYear(), startTime.getMonth(), 0).getDate(); + days = startMonth - startTime.getDate() + endTime.getDate() + } + } else { + //跨一个月 不考虑 + } + //返回跨天的日期数组 + for (let i = 0; i <= days; i++) { + const newDate = new Date(startTime); + const nextDate = toLocaleDateString(new Date(newDate.setDate(newDate.getDate() + i))); + nextDateList.push(nextDate) + } + return nextDateList +} + + + +export function getWeekNumber(year, month, days) { + + const isLeapYear = (year) => (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0) + + const getMonthDays = (year, month) => [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] || (isLeapYear(year) ? 29 : 28); + //那一天是那一年中的第多少天 + for (var i = 0; i < month; i++) { + days += getMonthDays(year, i); + } + + //那一年第一天是星期几 + var yearFirstDay = new Date(year, 0, 1).getDay(); + + var week = null; + if (yearFirstDay == 0) { + week = Math.ceil(days / 7); + } else { + days -= (6 - yearFirstDay + 1); + week = Math.ceil(days / 7); + } + + return week; +} + + +export function getBlankList(year) { + const dateMap = getDateMap(year, year); + const DateList = []; + dateMap.forEach(function (value, key) { + const keyDate = new Date(key); + + const year = keyDate.getFullYear(); + const month = keyDate.getMonth(); + const date = keyDate.getDate(); + const day = keyDate.getDay(); + // 生成年 + if (month === 0 && date === 1) { + DateList.push({ + type: "year", + value: year, + dateStr: `${year}` + }); + } + //生成月 + if (date === 1) { + DateList.push({ + type: "month", + value: month + 1, + dateStr: `${year}/${month + 1}` + }); + } + //生成周 + if (day === 0) { + const rangeDate = new Date(year, month, date + 6); + const rangeMonth2 = new Date(rangeDate).getMonth(); + const rangeDay2 = new Date(rangeDate).getDate(); + DateList.push({ + type: "week", + value: `第${getWeekNumber(year, month, date)}周,${month + 1}月${date}日 - ${ + rangeMonth2 == month ? "" : rangeMonth2 + 1 + "月" + }${rangeDay2}日`, + dateStr: `${year}/${month + 1}/${date}-week` + }); + } + }) + return DateList; +} + +export function toLocaleDateString(date) { + if (typeof date === 'string') { + date = new Date(date) + } + return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}` +}