uniapp如何实现时间轴会议预约显示?

33 篇文章 1 订阅
29 篇文章 1 订阅

uniapp实现时间轴会议预约显示:

 效果图如下:

<template>
	<view class="daily-schedule ">
		<block v-for="(v, k) in timeNewArr">
			<view class="timelineItem" :key="k">
				<view class="timeItem">
					<view style="display: flex;width: 120rpx;">
						<view class="leftTime" :style="{ opacity: k%12 === 0 || v.isShow ? 1 : 0 }">
							<text>{{ v.time }}</text>
						</view>
						<view class="scale"><text :style="{ width: k%12 === 0 ? '16rpx' : '8rpx' }"></text></view>
					</view>
					<view class="line"></view>
					<view class="rightContent" :style="{ borderTop: k%12 === 0 ? '2rpx dotted #D9D9D9' : '' }">
						<block v-for="(m,n) in listInfo" :key="n" v-if="scheduleFmt(v, m)">
							<!-- 冲突行程显示 -->
							<view v-if="m.clashArr && m.clashArr.length && v.time === m.startTime" class="tripItem-box"
								:style="{borderLeft: '8rpx dotted' + colorTypeFmt(m.scheduleType, m.isClash), height: v.height *22 + 'rpx'}">
								<!-- clashShow 判断冲突时间小于一个小时样式另一种显示 -->
								<view class="tripItem-conflict"
									:style="{borderLeft: borderLeftFmt(m.scheduleType, m.isClash), height: clashShow(m) ? '' : '128rpx'}"
									@click="handleDetails(m)">
									<view style="display: flex;">
										<view class="text"
											:style="{ border: '2rpx solid' + colorTypeFmt(m.scheduleType), color: colorTypeFmt(m.scheduleType)}">
											{{ textFmt(m.scheduleType) }}
										</view>
										<view class="title-ellipsis" style="width: calc(100% - 90rpx);">
											{{ m.scheduleTitle }}
										</view>
									</view>
									<view class="time-addr">
										<view style="width: 36%;">
											{{ m.conflictStartTime ?
											m.conflictStartTime : m.startTime }}-{{
												m.conflictEndTime ?
												m.conflictEndTime : m.endTime }}
										</view>
										<view style="width: 64%;" class="title-ellipsis">
											{{ m.scheduleAddr }}
										</view>
									</view>
									<!-- 行程大于1个小时行程冲突显示 -->
									<view v-if="clashShow(m) || m.clashIndex === n + 1"
										:class="[m.clashIndex === n + 1 ? 'show-box fadeInUp' : '']">
										<view class="tip">
											<u-icon name="error-circle" color="#FC4242" size="16"></u-icon>
											<text>当前有多个行程冲突,请点击行程查看</text>
										</view>
										<view class="conflict-box">
											<view v-for="(q,w) in m.clashArr" :key="w"
												:class="['btn-schedule', m.index && m.index === w + 1  ? 'active' : '', !m.index && w === 0 ? 'active' : '' ]"
												@click.stop="handleItem(m, q, w)">
												<text>{{ w >= 5 ? '' : '行程' }}{{ w + 1 }}</text>
											</view>
										</view>
									</view>
									<!-- 行程冲突小于一个小时显示 -->
									<template v-if="!clashShow(m)">
										<view class="clash-tip" @click.stop="handleClashTip(m, n)">
											<u-icon name="error-circle" color="#FC4242" size="28"></u-icon>
										</view>
									</template>
								</view>
							</view>
							<!-- 正常行程显示 -->
							<view v-if="v.time === m.startTime && !(m.clashArr && m.clashArr.length)"
								class="tripItem-box"
								:style="{borderLeft: '8rpx dotted' + colorTypeFmt(m.scheduleType), height: v.height *22 + 'rpx'}">
								<view class="tripItem" :style="{borderLeft: borderLeftFmt(m.scheduleType, m.isClash)}"
									@click="handleDetails(m)">
									<view style="display: flex;">
										<view>
											<view class="text"
												:style="{ border: '2rpx solid' + colorTypeFmt(m.scheduleType), color: colorTypeFmt(m.scheduleType)}">
												{{ textFmt(m.scheduleType) }}
											</view>
										</view>
										<view class="title-ellipsis">{{ m.scheduleTitle }}</view>
									</view>
									<view class="time-addr">
										<view style="width: 36%;">{{ m.startTime }} - {{ m.endTime }}</view>
										<view style="width: 64%;" class="title-ellipsis">{{ m.scheduleAddr }}</view>
									</view>
								</view>
							</view>
						</block>
						<view v-if="listInfo.length">
							<view :style="{borderLeft: '8rpx dotted' + colorTypeFmt(), height: v.height *22 + 'rpx'}"
								v-if="v.free">
								<view class="routine-work" :style="{background: v.isLine ? '#fff': ''}">
									{{ v.isLine ? '' : '日常工作' }}
								</view>
							</view>
						</view>
						<!-- 没有数据全天时间段显示日常工作中 -->
						<view v-else>
							<view
								:style="{borderLeft: '8rpx dotted' + colorTypeFmt(), height: timeDifference(timeStart, timeEnd) *22 + 'rpx'}"
								v-if="v.time <= timeEnd && v.time === timeStart">
								<view class="routine-work">日常工作</view>
							</view>
						</view>
					</view>
				</view>
			</view>
		</block>
	</view>
</template>

<script>
	export default {
		props: {
			listInfo: {
				type: Array,
				default: () => []
			}
		},
		data() {
			return {
				timeStart: '08:30',
				timeEnd: '18:00',
				timeArr: [],
				timeNewArr: []
			}
		},
		watch: {
			listInfo: {
				deep: true,
				immediate: true,
				handler(listArr) {
					if (listArr.length) {
						if (listArr[0].startTime >= '08:30') {
							this.timeStart = "08:30"
						} else {
							this.timeStart = listArr[0].startTime
						}
						if (listArr[0].endTime <= '18:00') {
							this.timeEnd = "18:00"
						} else {
							this.timeEnd = listArr[listArr.length - 1].endTime
						}
						this.timeFun(5, this.timeStart, this.timeEnd)

						this.timeNewArr = this.timeArr.map((v, k) => {
							listArr.forEach((t, i) => {
								if (v.time === t.startTime) {
									this.timeArr[k].isShow = true
									this.timeArr[k].height = this.timeDifference(t.startTime, t.endTime)
								}
								// 和第一个对比计算空余时间
								const {
									startTime
								} = this.listInfo[0]
								const minTime = this.timeDifference(this.timeStart, startTime)
								if (startTime > this.timeStart && v.time === this.timeStart) {
									this.timeArr[k].free = true
									this.timeArr[k].height = minTime
									// 空余时间小于20分钟只显示左边框,不显示日常工作中文字
									if (minTime <= 4) {
										this.timeArr[k].isLine = true
									}
								}

								// 除开第一个和最后一个进行对比计算空闲时间
								if (v.time === t.endTime) {
									const t1 = this.listInfo[i]
									const t2 = this.listInfo[i + 1]
									if (t2) {
										const minT = this.timeDifference(t1.endTime, t2.startTime)
										this.timeArr[k].free = true
										this.timeArr[k].height = minT
										if (minT <= 4) {
											this.timeArr[k].isLine = true
										}
									}
								}

								// 和最后一个对比,计算空余时间
								const len = this.listInfo.length
								const time = this.listInfo[len - 1].endTime
								const minT2 = this.timeDifference(time, this.timeEnd)
								if (time === v.time) {
									this.timeArr[k].free = true
									this.timeArr[k].height = minT2
									if (minT2 <= 4) {
										this.timeArr[k].isLine = true
									}
								}
							})
							return {
								...v
							}
						})
					} else {
						this.timeFun(5, '08:30', '18:00')
					}
				}
			}
		},
		created() {},
		methods: {
			// 行程详情
			handleDetails(v) {
				this.$emit('click', v)
			},
			clashShow(m) {
				if (this.timeDifference(m.startTime, m.endTime) >= 12) {
					return true
				} else {
					return false
				}
			},
			// 计算时间间隔相差5分钟个数(时间轴已5分钟间隔)
			timeDifference(time1 = "12:00", time2 = "14:00") {
				var s = time1.split(":")
				var e = time2.split(":")
				var daya = new Date()
				var dayb = new Date()
				daya.setHours(s[0])
				dayb.setHours(e[0])
				daya.setMinutes(s[1])
				dayb.setMinutes(e[1])
				const nun = (dayb - daya) / 1000 / 60
				return nun / 5
			},
			// 左边边框颜色
			borderLeftFmt(v, isClash) {
				return '8rpx solid' + this.colorTypeFmt(v, isClash)
			},
			// 限制显示时间
			overflowTime(item) {
				if (item >= this.timeStart && item <= this.timeEnd) return true
			},
			scheduleFmt(v, m) {
				if (v.time >= m.startTime && v.time < m.endTime) {
					return true
				}
			},
			handleItem(m, q, k) {
				// 防止行程冲突时间段出现混乱(字段需不一样)
				this.$set(m, 'conflictStartTime', q.startTime)
				this.$set(m, 'conflictEndTime', q.endTime)
				this.$set(m, 'scheduleAddr', q.scheduleAddr)
				this.$set(m, 'scheduleTitle', q.scheduleTitle)
				this.$set(m, 'scheduleType', q.scheduleType)
				this.$set(m, 'scheduleId', q.scheduleId)
				this.$set(m, 'index', k + 1)
			},
			handleClashTip(m, n) {
				if (m.clashIndex) {
					this.$set(m, 'clashIndex', 0)
				} else {
					this.$set(m, 'clashIndex', n + 1)
				}
			},
			timeFun(minute = 5, startTime = '08:30', endTime = '18:00') {
				var seconds = minute * 60;
				let len = (60 * 24 * 60) / seconds; //数组长度
				for (var i = 0, total = 0, newArr = []; i < len; i++) {
					var h = parseInt(total / 3600),
						min = parseInt(total % 3600 / 60);
					let t = this.tateFmt(h) + ':' + this.tateFmt(min)
					if (t >= startTime && t < endTime) {
						newArr.push({
							time: this.tateFmt(h) + ':' + this.tateFmt(min),
							value: i
						});
					}
					total += seconds;
				}
				this.timeArr = newArr
				this.timeNewArr = newArr
			},
			tateFmt(n) {
				return n < 10 ? '0' + n : n
			}
		}
	}
</script>

<style scoped lang="less">
	.daily-schedule {
		padding-top: 34rpx;
		background-color: #FDFDFD;
		overflow: hidden;
		border-bottom: 120rpx solid #FDFDFD;

		.timelineItem {
			.timeItem {
				display: flex;
				height: 22rpx;

				.leftTime {
					width: 100%;
					text-align: right;
					font-size: 24rpx;
					color: #999999;
					margin-top: -18rpx;
					margin-right: 10rpx;
					overflow: hidden;
					text-overflow: ellipsis;
					white-space: nowrap;
				}

				.scale {
					width: 20rpx;
					display: flex;
					justify-content: right;
					text-align: right;

					text {
						border-top: 2rpx solid #A6A6A6;
					}
				}

				.line {
					width: 1rpx;
					background: #A6A6A6;
					position: relative;
				}

				.rightContent {
					padding: 0 20rpx;
					flex: 1;
					height: 2rpx;

					.conflict-box {
						width: 100%;
						position: absolute;
						bottom: -20rpx;
						left: -8rpx;
						display: flex;
						justify-content: space-around;
						overflow-x: auto;
						border-left: 8rpx solid #FC4242;

						.btn-schedule {
							padding: 0 20rpx;
							text-align: left;
							width: 100%;
							height: 76rpx;
							line-height: 76rpx;
							color: #E33C64;
							background-color: #FFE3E5;
							font-size: 24rpx;
						}

						.active {
							background-color: #E33C64;
							color: #fff;
						}
					}

					.tripItem-box {
						position: relative;

						.tripItem,
						.tripItem-conflict {
							position: absolute;
							left: -8rpx;
							height: 128rpx;
							padding: 20rpx;
							box-sizing: border-box;
							background: #F5F5F5;
							border-radius: 0rpx 4rpx, 4rpx, 0rpx;
							width: 100%;
							color: #333333;
							font-size: 32rpx;
							font-weight: 500;

							.text {
								margin-right: 8rpx;
								width: 40rpx;
								height: 40rpx;
								line-height: 40rpx;
								text-align: center;
								border-radius: 50%;
								font-size: 24rpx;
							}

							.time-addr {
								display: flex;
								align-items: center;
								margin-top: 12rpx;
								color: #9B9B9B;
								font-size: 28rpx;
								font-weight: normal;
							}

							.tip {
								display: flex;
								font-size: 24rpx;
								font-weight: 500;
								color: #FC4242;
							}
						}

						.tripItem-conflict {
							position: relative;
							height: 220rpx;

							.clash-tip {
								position: absolute;
								top: 50%;
								right: 10rpx;
								transform: translateY(-50%);
							}

							.show-box {
								padding-left: 10rpx;
								width: 100%;
								position: absolute;
								top: 30rpx;
								left: -8rpx;
								bottom: 0;
								z-index: 1;
								background-color: #F5F5F5;
								border-left: 8rpx solid #FC4242;
							}

							.fadeInUp {
								-webkit-animation-name: move_up;
								animation-name: move_up;
								-webkit-animation-duration: 1s;
								animation-duration: 1s;
								-webkit-animation-iteration-count: 1;
								animation-iteration-count: 1;
								-webkit-animation-fill-mode: forwards;
								animation-fill-mode: forwards;
							}

							@-webkit-keyframes move_up {
								from {
									opacity: 0;
								}

								to {
									opacity: 1;
									-webkit-transform: translateY(50px);
									transform: translateY(50px);
								}
							}

							@keyframes move_up {
								from {
									opacity: 0;
								}

								to {
									opacity: 1;
									-webkit-transform: translateY(50px);
									transform: translateY(50px);
								}
							}
						}

						.title-ellipsis {
							overflow: hidden;
							text-overflow: ellipsis;
							display: -webkit-box;
							-webkit-box-orient: vertical;
							-webkit-line-clamp: 1;
						}
					}
				}
			}
		}

		.routine-work {
			padding: 20rpx;
			height: 40rpx;
			position: relative;
			left: -8rpx;
			background-color: #f9f9f9;
			color: #999999;
			font-size: 28rpx;
			border-left: 8rpx solid #999999;
		}
	}
</style>

 数据源可用:

				listInfo: [{
						"scheduleId": "366471527434162177",
						"leadUserId": 18375156497,
						"startTime": "09:10",
						"endTime": "09:40",
						"scheduleTitle": "省委常委会1",
						"scheduleAddr": "省委常委会议室",
						"scheduleType": 100,
						isClash: true,
						clashArr : [{
								"startTime": "09:10",
								"endTime": "09:40",
								"scheduleTitle": "省委常委会1",
								"scheduleAddr": "省委常委会议室1",
								scheduleType: 100,
								"scheduleId": "366471527434162177"
							},
							{
								"startTime": "09:30",
								"endTime": "09:50",
								"scheduleTitle": "省委常委会2",
								"scheduleAddr": "省委常委会议室2",
								scheduleType: 200,
								"scheduleId": "366471527434162177"
							}
						]
					},
					{
						"scheduleId": "367522536147259393",
						"leadUserId": 18375156497,
						"startScheduleDate": "2022-09-29 09:00",
						"endScheduleDate": "2022-09-29 12:00",
						"startTime": "11:00",
						"endTime": "11:20",
						"scheduleTitle": "临时会议2",
						"scheduleContent": "临时会议,工作安排",
						"scheduleAddr": "4楼2号会议室",
						"scheduleStatus": 100,
						"scheduleType": 200,
						"trainType": 0,
						"isUrgentDiscuss": false,
						"isClash": false,
						"clashNum": 0
					}
				]

 如果没有设计冲突,可把冲突的代码删掉就行(clashArr 判断的html代码删除),时间轴就正常显示

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: QGraphicsView是Qt中的视图类,它可以用于显示大量的图形元素。如果要实现时间轴,可以用QGraphicsView来实现。 首先,要创建一个QGraphicsView的实例,并设置一些属性,例如背景颜色、视图大小、滚动条等等。然后,创建一个QGraphicsScene对象,并将它与视图关联起来。QGraphicsScene是一个图形场景,可以用于管理和呈现图形项。 接下来,创建一些图形项来表示时间轴上的不同时间点。可以使用QGraphicsRectItem来创建矩形图形项,并将其放置在场景中的合适位置。可以使用QGraphicsTextItem来添加标签、文字等内容。 为了使时间轴可滚动,需要添加一个滚动条。可以使用QScrollBar或者QGraphicsView自带的滚动条。此外,还可以将时间轴上的不同时间点和滚动条进行联动,即当滚动条滑动时,时间轴上的时间点也会做出相应的改变。 最后,为了增强用户体验,可以考虑添加一些交互效果,例如鼠标悬停时的高亮效果、鼠标点击时的动画效果等等。这些效果可以通过重载QGraphicsItem中的鼠标事件来实现。 总的来说,实现时间轴需要我们借助QGraphicsView和QGraphicsScene这两个类来管理和呈现图形项,同时还需要实现滚动条和交互效果等功能。 ### 回答2: QGraphicsView是Qt中用于显示和编辑图形对象的控件,它的功能非常强大,可以实现很多复杂的图形界面效果,包括时间轴实现实现时间轴的关键是要先确定时间线的起点和终点,并在QGraphicsScene中创建对应的时间轴图形对象(如线段、文本标签等),然后将它们添加到QGraphicsView中显示出来。 具体实现步骤如下: 1. 创建QGraphicsScene,设置场景的大小和背景色。在场景中添加表示时间轴的图形对象,比如线段和文本标签。 2. 创建QGraphicsView,设置视图的大小和位置,并关联到QGraphicsScene上。设置滚动和缩放功能,以方便用户查看时间轴。 3. 在QGraphicsView中添加用于控制时间轴的用户界面元素,比如按钮和滑块等,实现调整时间轴的功能。 4. 在程序中添加逻辑代码,实现根据用户输入调整时间轴图形对象位置和文本标签内容的功能,以实现时间轴的动态调整和更新。 需要注意的是,在实现时间轴时要考虑到用户的操作体验和交互性,如何让用户方便操作和快速定位到所需的时间点,是实现时间轴的关键。因此,在设计时间轴界面时要根据实际需求和用户习惯做出合理的调整和优化。 ### 回答3: QGraphicsView是Qt框架中用于显示大型可交互的图像、绘图、模拟和数据的控件。利用QGraphicsView可以实现复杂的可视化界面,其中包括了时间轴实现时间轴是一种可视化的工具,用于展示时间序列数据。时间轴通常由一个线性的时间轴和一系列数据点组成,每个数据点都会根据其对应的时间戳被绘制在时间轴上。 使用QGraphicsView实现时间轴需要遵循以下步骤: 1. 创建QGraphicsView实例。 2. 创建QGraphicsScene实例,并将其关联到QGraphicsView。 3. 创建自定义的GraphicsItem类,用于绘制时间轴和数据点。 4. 将自定义的GraphicsItem类添加到QGraphicsScene中。 5. 根据数据生成对应的GraphicsItem,将其添加到QGraphicsScene中。 6. 根据需要,创建QGraphicsView的API接口,实现时间轴的交互功能。 实现时间轴最重要的一步是创建自定义的GraphicsItem类。这个类要负责根据数据绘制时间轴和数据点,同时必须实现诸如拖动、放大、缩小等交互功能。QGraphicsView提供了一些常用的交互动作,例如鼠标拖拽、鼠标滚轮缩放、键盘控制等,但是更高级的交互功能需要通过创建自定义的API接口来实现。 总之,使用QGraphicsView实现时间轴需要一定的Qt编程经验,但是只要按照上面提到的步骤进行操作,就能实现一个高效实用的时间轴

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值