【VUE】某时间某空间占用情况效果展示,vue2+element ui实现。场景:会议室占用、教室占用等。

某时间某空间占用情况效果展示,vue2+element ui实现。场景:会议室占用、教室占用等。

场景说明:

现在需要基于vue2和el-table实现每日会议室个时间点占用情况。
已知数据:
1、会议室数据(名称,id)
2、会议计划数据(id,名称,会议室id,开始时间,结束时间)
表格展示内容:
表头构成:日期,会议室,00-07,08,09,10…19-23(小时格子对应24小时)。
1、日期列:代表从今天开始到未来7天的日期,因此一天对应多个会议室,需要合并相同日期。
2、格子占用规则:会议室时间开始时间向下取整,结束时间向上取整,跨时间合并小时格子。
3、格子显示内容:展示对应会议数据的数据量,鼠标悬浮上去需要弹出显示会议数据列表。
具体如:2025-05-21 8:23-9:00 就占08的格子,8:23-9:30就占08和09的格子并合并,
特殊情况如有3个会议数据对应时间 18-19:30,20-20:30,21-23,就需要合并18和19-23的格子并显示数量3,鼠标悬浮展示这三条。

实现效果:

具体展示效果可以根据代码调整。
在这里插入图片描述

代码实现:

<template><div class="meeting-room-table"><el-table :data="tableData" :span-method="objectSpanMethod" border tooltip-effect="light" style="width: 100%"><el-table-column prop="date" label="时间" width="120"></el-table-column><el-table-column prop="roomName" label="会议室" width="120"></el-table-column><el-table-column prop="time0007" label="00-07"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time0007 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time0007Meetings.length" v-for="(meeting, index) in scope.row.time0007Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time0007 > 0 }"@mouseenter="showTooltip(scope.$index, 'time0007')"><i v-if="scope.row.time0007" class="el-icon-user"/> {{ scope.row.time0007 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time08" label="08"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time08 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time08Meetings.length" v-for="(meeting, index) in scope.row.time08Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time08 > 0 }"@mouseenter="showTooltip(scope.$index, 'time08')"><i v-if="scope.row.time08" class="el-icon-user"/> {{ scope.row.time08 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time09" label="09"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time09 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time09Meetings.length" v-for="(meeting, index) in scope.row.time09Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time09 > 0 }"@mouseenter="showTooltip(scope.$index, 'time09')"><i v-if="scope.row.time09" class="el-icon-user"/> {{ scope.row.time09 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time10" label="10"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time10 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time10Meetings.length" v-for="(meeting, index) in scope.row.time10Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time10 > 0 }"@mouseenter="showTooltip(scope.$index, 'time10')"><i v-if="scope.row.time10" class="el-icon-user"/> {{ scope.row.time10 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time11" label="11"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time11 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time11Meetings.length" v-for="(meeting, index) in scope.row.time11Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time11 > 0 }"@mouseenter="showTooltip(scope.$index, 'time11')"><i v-if="scope.row.time11" class="el-icon-user"/> {{ scope.row.time11 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time12" label="12"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time12 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time12Meetings.length" v-for="(meeting, index) in scope.row.time12Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time12 > 0 }"@mouseenter="showTooltip(scope.$index, 'time12')"><i v-if="scope.row.time12" class="el-icon-user"/> {{ scope.row.time12 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time13" label="13"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time13 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time13Meetings.length" v-for="(meeting, index) in scope.row.time13Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time13 > 0 }"@mouseenter="showTooltip(scope.$index, 'time13')"><i v-if="scope.row.time13" class="el-icon-user"/> {{ scope.row.time13 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time14" label="14"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time14 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time14Meetings.length" v-for="(meeting, index) in scope.row.time14Meetings":key="index" class="tooltip-item"><span>主持人:</span><span>主题:</span><span>会议时间:</span><span>会议状态:</span><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time14 > 0 }"@mouseenter="showTooltip(scope.$index, 'time14')"><i v-if="scope.row.time14" class="el-icon-user"/> {{ scope.row.time14 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time15" label="15"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time15 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time15Meetings.length" v-for="(meeting, index) in scope.row.time15Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time15 > 0 }"@mouseenter="showTooltip(scope.$index, 'time15')"><i v-if="scope.row.time15" class="el-icon-user"/> {{ scope.row.time15 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time16" label="16"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time16 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time16Meetings.length" v-for="(meeting, index) in scope.row.time16Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time16 > 0 }"@mouseenter="showTooltip(scope.$index, 'time16')"><i v-if="scope.row.time16" class="el-icon-user"/> {{ scope.row.time16 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time17" label="17"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time17 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time17Meetings.length" v-for="(meeting, index) in scope.row.time17Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time17 > 0 }"@mouseenter="showTooltip(scope.$index, 'time17')"><i v-if="scope.row.time17" class="el-icon-user"/> {{ scope.row.time17 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time18" label="18"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time18 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time18Meetings.length" v-for="(meeting, index) in scope.row.time18Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time18 > 0 }"@mouseenter="showTooltip(scope.$index, 'time18')"><i v-if="scope.row.time18" class="el-icon-user"/> {{ scope.row.time18 || '' }}</div></el-tooltip></template></el-table-column><el-table-column prop="time1923" label="19-23"><template slot-scope="scope"><el-tooltip content="" :disabled="scope.row.time1923 === 0" effect="light" placement="top"><div slot="content"><div v-if="scope.row.time1923Meetings.length" v-for="(meeting, index) in scope.row.time1923Meetings":key="index" class="tooltip-item"><span>主持人:{{ meeting.userName }}</span><span>主题: {{ meeting.theme }}</span><span>会议时间:{{ formatTime(meeting.beginSta) }}-{{ formatTime(meeting.beginEnd) }}</span><span>会议状态:{{meeting.state|statefitler}}</span></div></div><div class="time-cell" :class="{ 'occupied': scope.row.time1923 > 0 }"@mouseenter="showTooltip(scope.$index, 'time1923')"><i v-if="scope.row.time1923" class="el-icon-user"/> {{ scope.row.time1923 || '' }}</div></el-tooltip></template></el-table-column></el-table></div>
</template><script>//按需引入接口// import {listMeeting,listMeetingRoom } from "@/api/meeting";export default {name: 'MeetingRoomTable',data() {return {rooms: [],meetings: [],tableData: [],dateSpanArr: [],roomSpanArr: [],meetingSpanMap: new Map() // 存储会议合并信息}},//可作为组件接收外部入参props: {roomList: {type: Array,default: null},meetingList: {type: Array,default: null}},filters: {statefitler(value) {if (value == '1') {return '召开中';}if (value == '2') {return '已结束';}if (value == '3') {return '待召开';}if (value == '4') {return '已取消';}}},watch: {roomList: {handler(newVal) {if(newVal){this.rooms = newVal;this.generateTableData();}},deep: true,immediate: true},meetingList: {handler(newVal) {if(newVal){this.meetings = newVal;this.generateTableData();}},deep: true,immediate: true}},created() {// 如果没有传入数据,使用默认数据if (this.roomList == null) {// this.getRealeRooms()this.rooms = this.getDefaultRooms();}if (this.meetingList == null) {// this.getRealeMeetings()this.meetings = this.getDefaultMeetings();}setTimeout(()=>{this.generateTableData()},500)},methods: {generateTableData() {// 初始化会议合并信息this.meetingSpanMap.clear();// 生成未来7天日期const dates = [];for (let i = 0; i < 7; i++) {const date = new Date();date.setDate(date.getDate() + i);dates.push(this.formatDate(date));}// 时间段映射const timeSlotMap = {0: 'time0007',1: 'time0007',2: 'time0007',3: 'time0007',4: 'time0007',5: 'time0007',6: 'time0007',7: 'time0007',8: 'time08',9: 'time09',10: 'time10',11: 'time11',12: 'time12',13: 'time13',14: 'time14',15: 'time15',16: 'time16',17: 'time17',18: 'time18',19: 'time1923',20: 'time1923',21: 'time1923',22: 'time1923',23: 'time1923'};// 初始化表格数据this.tableData = [];dates.forEach(date => {this.rooms.forEach(room => {this.tableData.push({date,meetingRoom: room.id,roomName: room.name,time0007: 0,time08: 0,time09: 0,time10: 0,time11: 0,time12: 0,time13: 0,time14: 0,time15: 0,time16: 0,time17: 0,time18: 0,time1923: 0,time0007Meetings: [],time08Meetings: [],time09Meetings: [],time10Meetings: [],time11Meetings: [],time12Meetings: [],time13Meetings: [],time14Meetings: [],time15Meetings: [],time16Meetings: [],time17Meetings: [],time18Meetings: [],time1923Meetings: []});});});// 处理会议数据this.meetings.forEach(meeting => {// 查找对应的表格行const rowIndex = this.tableData.findIndex(item => {return item.date === this.formatDate(new Date(meeting.beginSta)) && item.meetingRoom == meeting.meetingRoom;});if (rowIndex !== -1) {// 计算会议占用的时间段const startHour = new Date(meeting.beginSta).getHours();const endHour = new Date(meeting.beginEnd).getHours();const startMinute = new Date(meeting.beginSta).getMinutes();const endMinute = new Date(meeting.beginEnd).getMinutes();// 开始时间:如果分钟数大于0,占用下一个完整小时// 结束时间:如果分钟数大于0,占用当前小时;否则占用前一小时let startTimeSlot = startHour;let endTimeSlot = endHour + (endMinute > 0 ? 0 : -1);// 记录该会议占用的时间段const timeSlots = new Set();// 生成所有被占用的时间段for (let hour = startTimeSlot; hour <= endTimeSlot; hour++) {if (hour in timeSlotMap) {timeSlots.add(timeSlotMap[hour]);}}// 更新表格数据和合并信息if (timeSlots.size > 0) {// 转换为有序数组const orderedTimeSlots = Array.from(timeSlots);// 记录时间段与会议的映射关系orderedTimeSlots.forEach(slot => {// 更新占用计数this.tableData[rowIndex][slot]++; // 这里是关键:对每个时间段的占用计数+1// 添加会议信息this.tableData[rowIndex][`${slot}Meetings`].push(meeting);console.log(slot, this.tableData[rowIndex][slot])});// 记录会议合并信息if (orderedTimeSlots.length > 1) {this.meetingSpanMap.set(`${rowIndex}-${meeting.meetingId}`, orderedTimeSlots);}}}});// 处理合并单元格this.handleSpan();console.log("tableData", this.tableData)},handleSpan() {// 重置合并数组this.dateSpanArr = [];this.roomSpanArr = [];let datePos = 0;let roomPos = 0;// 处理日期列合并this.tableData.forEach((item, index) => {if (index === 0) {this.dateSpanArr.push(1);datePos = 0;} else {// 如果当前行日期和上一行日期相同,则合并if (item.date === this.tableData[index - 1].date) {this.dateSpanArr[datePos] += 1;this.dateSpanArr.push(0);} else {this.dateSpanArr.push(1);datePos = index;}}});// 处理会议室列合并this.tableData.forEach((item, index) => {if (index === 0) {this.roomSpanArr.push(1);roomPos = 0;} else {// 如果当前行日期和上一行日期相同,且会议室也相同,则合并if (item.date === this.tableData[index - 1].date && item.meetingRoom === this.tableData[index - 1].meetingRoom) {this.roomSpanArr[roomPos] += 1;this.roomSpanArr.push(0);} else {this.roomSpanArr.push(1);roomPos = index;}}});//===========================合并格子进行会议数据合并去重共享============================================// 时间段列const timeProps = ['time0007', 'time08', 'time09', 'time10', 'time11','time12', 'time13', 'time14', 'time15', 'time16','time17', 'time18', 'time1923'];// 处理时间段列的会议数据合并this.tableData.forEach((row, rowIndex) => {// 检查是否有需要合并的会议const meetingsToMerge = [];// 遍历所有时间段,收集需要合并的会议timeProps.forEach(timeProp => {const meetings = row[`${timeProp}Meetings`] || [];meetings.forEach(meeting => {// 如果会议已经在列表中,跳过if (meetingsToMerge.some(m => m.meetingId === meeting.meetingId)) {return;}// 计算会议覆盖的时间段const startHour = new Date(meeting.beginSta).getHours();const endHour = new Date(meeting.beginEnd).getHours();const endMinute = new Date(meeting.beginEnd).getMinutes();// 确定会议覆盖的时间段索引范围const startTimeSlot = this.getTimeSlotIndex(startHour);const endTimeSlot = this.getTimeSlotIndex(endHour + (endMinute > 0 ? 0 : -1));// 如果会议跨多个时间段,添加到合并列表if (endTimeSlot > startTimeSlot) {meetingsToMerge.push({...meeting,startTimeSlot,endTimeSlot});}});});// 处理需要合并的会议meetingsToMerge.forEach(meeting => {// 收集会议覆盖的所有时间段的会议数据const allMeetings = [];const meetingIds = new Set();for (let i = meeting.startTimeSlot; i <= meeting.endTimeSlot; i++) {const timeProp = timeProps[i];const slotMeetings = row[`${timeProp}Meetings`] || [];slotMeetings.forEach(m => {if (!meetingIds.has(m.meetingId)) {meetingIds.add(m.meetingId);allMeetings.push(m);}});}// 更新所有相关时间段的会议数据for (let i = meeting.startTimeSlot; i <= meeting.endTimeSlot; i++) {const timeProp = timeProps[i];row[timeProp] = allMeetings.length;row[`${timeProp}Meetings`] = allMeetings;}});});//===========================合并格子进行会议数据合并去重共享============================================},// 根据小时获取时间段索引getTimeSlotIndex(hour) {const timeSlotMap = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, // time00078: 1, 9: 2, 10: 3, 11: 4, // time08, time09, time10, time1112: 5, 13: 6, 14: 7, 15: 8, 16: 9, 17: 10, 18: 11, // time12-time1819: 12, 20: 12, 21: 12, 22: 12, 23: 12 // time1923};return timeSlotMap[hour] || 0;},//el-table表格合并方法objectSpanMethod({row,column,rowIndex,columnIndex}) {// 处理日期列和会议室列的合并if (columnIndex === 0) {return {rowspan: this.dateSpanArr[rowIndex],colspan: 1};} else if (columnIndex === 1) {return {rowspan: this.roomSpanArr[rowIndex],colspan: 1};}// 处理时间段列的会议合并const timePropIndex = columnIndex - 2; // 时间段列从第3列开始if (timePropIndex < 0) return {rowspan: 1,colspan: 1};const timeProps = ['time0007', 'time08', 'time09', 'time10', 'time11','time12', 'time13', 'time14', 'time15', 'time16','time17', 'time18', 'time1923'];const timeProp = timeProps[timePropIndex];if (!timeProp) return {rowspan: 1,colspan: 1};// 检查当前单元格是否属于某个需要合并的会议for (const [key, timeSlots] of this.meetingSpanMap.entries()) {const [rowIdx, meetingId] = key.split('-');if (parseInt(rowIdx) === rowIndex && timeSlots.includes(timeProp)) {const firstSlot = timeSlots[0];const lastSlot = timeSlots[timeSlots.length - 1];// 如果是会议的第一个时间段,设置合并if (timeProp === firstSlot) {// 找出合并范围内数量最多的时间段const timePropIdx = timeProps.indexOf(timeProp);const lastSlotIdx = timeProps.indexOf(lastSlot);return {rowspan: 1,colspan: lastSlotIdx - timePropIdx + 1};} else {// 否则不显示return {rowspan: 0,colspan: 0};}}}// 默认不合并return {rowspan: 1,colspan: 1};},formatDate(date) {const year = date.getFullYear();const month = String(date.getMonth() + 1).padStart(2, '0');const day = String(date.getDate()).padStart(2, '0');return `${year}-${month}-${day}`;},formatTime(dateTime) {const date = new Date(dateTime);const hour = String(date.getHours()).padStart(2, '0');const minute = String(date.getMinutes()).padStart(2, '0');return `${hour}:${minute}`;},showTooltip(rowIndex, timeKey) {// 处理鼠标悬停事件},//会议室数据getRealeRooms() {//获取真实数据接口listMeetingRoom().then(response => {this.rooms = response.rows;this.generateTableData();});},//会议数据getRealeMeetings() {//获取今天及今天之后的数据const today = new Date();listMeeting().then(response => {this.meetings = response.rows;this.generateTableData();});},getDefaultRooms() {return [{id: 1,name: '会议室A'},{id: 2,name: '会议室B'},{id: 3,name: '会议室C'}];},getDefaultMeetings() {const today = new Date();return [{meetingId: 1,theme: '周会',userName: '张三',meetingRoom: 1,state:1,beginSta: new Date(today.setHours(4, 30, 0)).toISOString(),beginEnd: new Date(today.setHours(5, 0, 0)).toISOString()},{meetingId: 2,theme: '技审',userName: '张三',meetingRoom: 1,state:1,beginSta: new Date(today.setHours(6, 0, 0)).toISOString(),beginEnd: new Date(today.setHours(9, 30, 0)).toISOString()},{meetingId: 3,theme: '技审3',userName: '张三',meetingRoom: 1,state:2,beginSta: new Date(today.setHours(8, 0, 0)).toISOString(),beginEnd: new Date(today.setHours(9, 30, 0)).toISOString()},{meetingId: 6,theme: '跨时1',userName: '张三',meetingRoom: 3,state:2,beginSta: new Date(today.setHours(18, 0, 0)).toISOString(),beginEnd: new Date(today.setHours(20, 30, 0)).toISOString()},{meetingId: 7,theme: '跨时2',userName: '张三',meetingRoom: 3,state:1,beginSta: new Date(today.setHours(20, 0, 0)).toISOString(),beginEnd: new Date(today.setHours(21, 30, 0)).toISOString()},{meetingId: 9,theme: '跨19-23',userName: '张三',meetingRoom: 3,state:3,beginSta: new Date(today.setHours(20, 30, 0)).toISOString(),beginEnd: new Date(today.setHours(22, 30, 0)).toISOString()},{meetingId: 10,theme: '跨列测试1',userName: '张三',meetingRoom: 3,state:4,beginSta: new Date(today.setHours(18, 0, 0)).toISOString(),beginEnd: new Date(today.setHours(19, 30, 0)).toISOString()},{meetingId: 11,theme: '跨列测试2',userName: '张三',meetingRoom: 2,state:1,beginSta: new Date(today.setHours(20, 0, 0)).toISOString(),beginEnd: new Date(today.setHours(21, 0, 0)).toISOString()},{meetingId: 12,theme: '重叠测试1',userName: '张三',meetingRoom: 3,state:1,beginSta: new Date(today.setHours(19, 0, 0)).toISOString(),beginEnd: new Date(today.setHours(20, 30, 0)).toISOString()},{meetingId: 13,theme: '重叠测试2',userName: '张三',meetingRoom: 3,state:1,beginSta: new Date(today.setHours(20, 0, 0)).toISOString(),beginEnd: new Date(today.setHours(21, 30, 0)).toISOString()}];}}}
</script><style scoped>.meeting-room-table {margin: 20px;}.time-cell {text-align: center;padding: 5px;height: 100%;border-radius: 4px;cursor: pointer;}.time-cell.occupied {background-color: #55aaff;color: white;}.tooltip-item {padding: 5px 0;display: flex;align-content: flex-start;flex-direction: column;font-size: 14px;border-bottom: 1px solid #eee;}.tooltip-item:last-child {border-bottom: none;}
</style>

参考DeepSeek和豆包AI。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/bicheng/86173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git更换源方式记录

本文首发地址&#xff1a;https://www.dawnsite.cn/archives/198.html 该方式前提是本地项目已关联远程仓库&#xff0c;由于业务变更git地址改变 1. 移除本地已有远程仓库 git remote remove origin2. 添加新的远程仓库源 git remote add origin "clone地址"3.一步…

前端面试专栏-主流框架:12. Vue3响应式原理与API

&#x1f525; 欢迎来到前端面试通关指南专栏&#xff01;从js精讲到框架到实战&#xff0c;渐进系统化学习&#xff0c;坚持解锁新技能&#xff0c;祝你轻松拿下心仪offer。 前端面试通关指南专栏主页 前端面试专栏规划详情 Vue3响应式原理与API详解 一、引言 Vue3作为Vue.j…

DAY 37 早停策略和模型权重的保存

早停策略 import torch.nn as nn import torch.optim as optim import time import matplotlib.pyplot as plt from tqdm import tqdm# Define the MLP model class MLP(nn.Module):def __init__(self):super(MLP, self).__init__()self.fc1 nn.Linear(X_train.shape[1], 10)s…

零基础搭建Spring AI本地开发环境指南

Spring AI 是一个 Spring 官方团队主导的开源项目&#xff0c;旨在将生成式人工智能&#xff08;Generative AI&#xff09;能力无缝集成到 Spring 应用程序中。它提供了一个统一的、Spring 风格的抽象层&#xff0c;简化了与各种大型语言模型&#xff08;LLMs&#xff09;、嵌…

windows登录系统配置双因子认证的解决方案

在数字化浪潮席卷全球的今天&#xff0c;安全如同氧气般不可或缺。Verizon《2023年数据泄露调查报告》指出&#xff0c;80%的黑客攻击与登录凭证失窃直接相关。当传统密码防护变得千疮百孔&#xff0c;企业如何在身份验证的战场上赢得主动权&#xff1f;答案就藏在"双保险…

Java数据结构——线性表Ⅱ

一、链式存储结构概述 1. 基本概念&#xff08;逻辑分析&#xff09; 核心思想&#xff1a;用指针将离散的存储单元串联成逻辑上连续的线性表 设计动机&#xff1a;解决顺序表 "预先分配空间" 与 "动态扩展" 的矛盾 关键特性&#xff1a; 结点空间动态…

技术基石:SpreadJS 引擎赋能极致体验

在能源行业数字化转型的浪潮中&#xff0c;青岛国瑞信息技术有限公司始终以技术创新为核心驱动力&#xff0c;不断探索前沿技术在能源领域的深度应用。其推出的 RCV 行列视生产数据应用系统之所以能够在行业内脱颖而出&#xff0c;离不开背后强大的技术基石 ——SpreadJS 引擎。…

Typora - Typora 打字机模式

Typora 打字机模式 1、基本介绍 Typora 打字机模式&#xff08;Typewriter Mode&#xff09;是一种专注于当前写作行的功能 打字机模式会自动将正在编辑的行保持在屏幕中央&#xff0c;让用户更集中注意力&#xff0c;类似于传统打字机的体验 2、开启方式 点击 【视图】 -…

3.0 compose学习:MVVM框架+Hilt注解调用登录接口

文章目录 前言&#xff1a;1、添加依赖1.1 在settings.gradle.kts中添加1.2 在应用级的build.gradle.kts添加插件依赖1.3 在module级的build.gradle.kts添加依赖 2、实体类2.1 request2.2 reponse 3、网络请求3.1 ApiService3.2 NetworkModule3.3 拦截器 添加token3.4 Hilt 的 …

git学习资源

动画演示&#xff1a;Learn Git Branching 终极目标&#xff08;能看懂即入门&#xff09;&#xff1a;git 简明指南 Git 教程 | 菜鸟教程

C++ 第二阶段:模板编程 - 第一节:函数模板与类模板

目录 一、模板编程的核心概念 1.1 什么是模板编程&#xff1f; 二、函数模板详解 2.1 函数模板的定义与使用 2.1.1 基本语法 2.1.2 示例&#xff1a;通用交换函数 2.1.3 类型推导规则 2.2 函数模板的注意事项 2.2.1 普通函数与函数模板的调用规则 2.2.2 隐式类型转换…

Docker 报错“x509: certificate signed by unknown authority”的排查与解决实录

目录 &#x1f527;Docker 报错“x509: certificate signed by unknown authority”的排查与解决实录 &#x1f4cc; 问题背景 &#x1f9ea; 排查过程 步骤 1&#xff1a;确认加速器地址是否可访问 步骤 2&#xff1a;检查 Docker 是否真的使用了镜像加速器 步骤 3&…

达梦以及其他图形化安装没反应或者报错No more handles [gtk_init_check() failed]

本人安装问题和解决步骤如下&#xff0c;仅供参考 执行 DMInstall.bin 报错 按照网上大部分解决方案 export DISPLAY:0.0 xhost 重新执行 DMInstall.bin&#xff0c;无报错也无反应 安装xclock测试也是同样效果&#xff0c;无报错也无反应 最开始猜测可能是连接工具问题&a…

项目节奏不一致时,如何保持全局平衡

项目节奏不一致时&#xff0c;如何保持全局平衡的关键在于&#xff1a;构建跨项目协调机制、合理配置资源、建立共享节奏看板、优先明确战略驱动、引入缓冲与预警机制。其中&#xff0c;构建跨项目协调机制尤为关键&#xff0c;它能将各项目的排期、优先级和风险实时联动&#…

macOS - 安装微软雅黑字体

文章目录 1、下载资源2、安装3、查看字体 app4、卸载字体 macOS 中打开 Windows 传输过来的文件的时候&#xff0c;经常会提示 xxx 字体缺失。下面以安装 微软雅黑字体为例。 1、下载资源 https://github.com/BronyaCat/Win-Fonts-For-Mac 2、安装 双击 Fonts 文件夹下的 msy…

ArkUI-X资源分类与访问

应用开发过程中&#xff0c;经常需要用到颜色、字体、间距、图片等资源&#xff0c;在不同的设备或配置中&#xff0c;这些资源的值可能不同。 应用资源&#xff1a;借助资源文件能力&#xff0c;开发者在应用中自定义资源&#xff0c;自行管理这些资源在不同的设备或配置中的…

11-StarRocks故障诊断FAQ

StarRocks故障诊断FAQ 概述 本文档整理了StarRocks故障诊断过程中常见的问题和解决方案,涵盖了故障排查、日志分析、性能诊断、问题定位等各个方面,帮助用户快速定位和解决StarRocks相关问题。 故障排查FAQ Q1: 如何排查连接故障? A: 连接故障排查方法: 1. 网络连通性…

敏捷项目管理怎么做?4大主流方法论对比及工具适配方案

在传统瀑布式项目管理中&#xff0c;需求定义、设计、开发、测试等环节如同工业流水线般严格线性推进&#xff0c;展现出强大的流程控制能力。不过今天的软件迭代周期已压缩至周级乃至日级&#xff0c;瀑布式管理难以应对需求的快速变化&#xff0c;敏捷式项目管理则以“小步快…

解决YOLO模型从Python迁移到C++时目标漏检问题——跨语言部署中的关键陷阱与解决方案

问题背景 当我们将Python训练的YOLO模型部署到C环境时&#xff0c;常遇到部分目标漏检问题。这通常源于预处理/后处理差异、数据类型隐式转换或模型转换误差。本文通过完整案例解析核心问题并提供可落地的解决方案。 一、常见原因分析 预处理不一致 Python常用OpenCV&#xff…

【2025CCF中国开源大会】开放注册与会议通知(第二轮)

点击蓝字 关注我们 CCF Opensource Development Committee 2025 CCF中国开源大会 由中国计算机学会主办的 2025 CCF中国开源大会&#xff08;CCF ChinaOSC&#xff09;拟于 2025年8月2日-3日 在上海召开。本届大会以“蓄势引领、众行致远”为主题&#xff0c;由上海交通大学校长…