fix(calendar): 优化历史营期显示和交互体验
- 移除顶部状态指示器,改为通过事件点样式区分历史营期 - 添加鼠标悬停延迟显示和离开隐藏功能 - 实现历史营期数据映射到日历的功能 - 调整历史营期切换时的日期跳转逻辑 - 优化历史营期事件点的视觉样式
This commit is contained in:
@@ -5,8 +5,8 @@ import { useUserStore } from '@/stores/user'
|
|||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
// baseURL: 'https://mldash.nycjy.cn/' || '', // API基础路径,支持完整URL
|
baseURL: 'https://mldash.nycjy.cn/' || '', // API基础路径,支持完整URL
|
||||||
baseURL: 'http://192.168.15.121:8890' || '', // API基础路径,支持完整URL
|
// baseURL: 'http://192.168.15.121:8890' || '', // API基础路径,支持完整URL
|
||||||
timeout: 100000, // 请求超时时间
|
timeout: 100000, // 请求超时时间
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json;charset=UTF-8'
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
|
|||||||
@@ -41,22 +41,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 营期状态指示器 -->
|
|
||||||
<div class="period-indicator">
|
|
||||||
<div v-if="isViewingHistory" class="history-indicator">
|
|
||||||
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
||||||
<path fill="currentColor" d="M13,3A9,9 0 0,0 4,12H1L4.89,15.89L4.96,16.03L9,12H6A7,7 0 0,1 13,5A7,7 0 0,1 20,12A7,7 0 0,1 13,19C11.07,19 9.32,18.21 8.06,16.94L6.64,18.36C8.27,20 10.5,21 13,21A9,9 0 0,0 22,12A9,9 0 0,0 13,3Z"/>
|
|
||||||
</svg>
|
|
||||||
<span>正在查看:第{{ selectedHistoryPeriod.periodNum }}期历史营期</span>
|
|
||||||
</div>
|
|
||||||
<div v-else class="current-indicator">
|
|
||||||
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
||||||
<path fill="currentColor" d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M12,6A6,6 0 0,1 18,12A6,6 0 0,1 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6M12,8A4,4 0 0,0 8,12A4,4 0 0,0 12,16A4,4 0 0,0 16,12A4,4 0 0,0 12,8Z"/>
|
|
||||||
</svg>
|
|
||||||
<span>当前营期</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 星期标题 -->
|
<!-- 星期标题 -->
|
||||||
<div class="weekdays">
|
<div class="weekdays">
|
||||||
<div v-for="day in weekdays" :key="day" class="weekday">
|
<div v-for="day in weekdays" :key="day" class="weekday">
|
||||||
@@ -80,9 +64,10 @@
|
|||||||
}
|
}
|
||||||
]"
|
]"
|
||||||
@mouseenter="selectDate(date, $event)"
|
@mouseenter="selectDate(date, $event)"
|
||||||
|
@mouseleave="onMouseLeave"
|
||||||
>
|
>
|
||||||
<span class="date-number">{{ date.day }}</span>
|
<span class="date-number">{{ date.day }}</span>
|
||||||
<div v-if="date.hasEvent && !isRestDay(date.dateStr)" class="event-dot" :class="getEventTypeClass(date.dateStr)"></div>
|
<div v-if="date.hasEvent && !isRestDay(date.dateStr)" class="event-dot" :class="[getEventTypeClass(date.dateStr), { 'history-period': isViewingHistory }]"></div>
|
||||||
<span v-if="isRestDay(date.dateStr)" class="rest-text">休</span>
|
<span v-if="isRestDay(date.dateStr)" class="rest-text">休</span>
|
||||||
<span v-if="date.isHoliday" class="holiday-text">休</span>
|
<span v-if="date.isHoliday" class="holiday-text">休</span>
|
||||||
<div v-if="isHolidayStart(date.dateStr)" class="holiday-name">
|
<div v-if="isHolidayStart(date.dateStr)" class="holiday-name">
|
||||||
@@ -295,6 +280,7 @@ const selectedDate = ref(null);
|
|||||||
const today = new Date();
|
const today = new Date();
|
||||||
const showTooltip = ref(false);
|
const showTooltip = ref(false);
|
||||||
const tooltipPosition = ref({ x: 0, y: 0 });
|
const tooltipPosition = ref({ x: 0, y: 0 });
|
||||||
|
const hoverTimer = ref(null);
|
||||||
|
|
||||||
// 营期设置相关
|
// 营期设置相关
|
||||||
const showCampModal = ref(false);
|
const showCampModal = ref(false);
|
||||||
@@ -473,22 +459,31 @@ const nextMonth = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 方法:选择日期
|
// 方法:选择日期(鼠标悬停延迟触发)
|
||||||
const selectDate = (date, event) => {
|
const selectDate = (date, event) => {
|
||||||
selectedDate.value = date;
|
selectedDate.value = date;
|
||||||
|
|
||||||
|
// 清除之前的定时器
|
||||||
|
if (hoverTimer.value) {
|
||||||
|
clearTimeout(hoverTimer.value);
|
||||||
|
}
|
||||||
|
|
||||||
// 只有当日期有事件时才显示悬浮框
|
// 只有当日期有事件时才显示悬浮框
|
||||||
if (event && date.hasEvent) {
|
if (event && date.hasEvent) {
|
||||||
tooltipPosition.value = {
|
tooltipPosition.value = {
|
||||||
x: event.clientX + 10,
|
x: event.clientX + 10,
|
||||||
y: event.clientY - 10
|
y: event.clientY - 10
|
||||||
};
|
};
|
||||||
showTooltip.value = true;
|
|
||||||
|
|
||||||
// 3秒后自动隐藏
|
// 延迟500毫秒后显示悬浮框
|
||||||
setTimeout(() => {
|
hoverTimer.value = setTimeout(() => {
|
||||||
showTooltip.value = false;
|
showTooltip.value = true;
|
||||||
}, 3000);
|
|
||||||
|
// 3秒后自动隐藏
|
||||||
|
setTimeout(() => {
|
||||||
|
showTooltip.value = false;
|
||||||
|
}, 3000);
|
||||||
|
}, 500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -497,6 +492,15 @@ const hideTooltip = () => {
|
|||||||
showTooltip.value = false;
|
showTooltip.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 方法:鼠标离开日期单元格
|
||||||
|
const onMouseLeave = () => {
|
||||||
|
// 清除延迟显示的定时器
|
||||||
|
if (hoverTimer.value) {
|
||||||
|
clearTimeout(hoverTimer.value);
|
||||||
|
hoverTimer.value = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 方法:显示历史记录
|
// 方法:显示历史记录
|
||||||
const showHistory = async () => {
|
const showHistory = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -558,10 +562,14 @@ const switchToHistoryPeriod = async (period) => {
|
|||||||
// 关闭历史营期弹框
|
// 关闭历史营期弹框
|
||||||
showHistoryModal.value = false;
|
showHistoryModal.value = false;
|
||||||
|
|
||||||
// 重新获取营期数据以更新日历显示
|
// 使用历史营期数据构建日历显示
|
||||||
await CenterCampPeriodAdmin();
|
mapHistoryPeriodToCalendar(period);
|
||||||
|
|
||||||
|
// 切换日历到历史营期的时间段
|
||||||
|
const startDate = new Date(period.startDate);
|
||||||
|
currentYear.value = startDate.getFullYear();
|
||||||
|
currentMonth.value = startDate.getMonth();
|
||||||
|
|
||||||
alert(`已切换到第${period.periodNum}期历史营期`);
|
|
||||||
} else {
|
} else {
|
||||||
alert('切换历史营期失败,请重试');
|
alert('切换历史营期失败,请重试');
|
||||||
}
|
}
|
||||||
@@ -580,6 +588,11 @@ const returnToCurrentPeriod = async () => {
|
|||||||
// 重新获取当前营期数据
|
// 重新获取当前营期数据
|
||||||
await CenterCampPeriodAdmin();
|
await CenterCampPeriodAdmin();
|
||||||
|
|
||||||
|
// 切换日历回到当前时间
|
||||||
|
const now = new Date();
|
||||||
|
currentYear.value = now.getFullYear();
|
||||||
|
currentMonth.value = now.getMonth();
|
||||||
|
|
||||||
alert('已返回当前营期');
|
alert('已返回当前营期');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('返回当前营期失败:', error);
|
console.error('返回当前营期失败:', error);
|
||||||
@@ -671,6 +684,9 @@ const isRestDay = (dateStr) => {
|
|||||||
|
|
||||||
// 方法:检查营期是否应该结束
|
// 方法:检查营期是否应该结束
|
||||||
const shouldShowFinishCamp = () => {
|
const shouldShowFinishCamp = () => {
|
||||||
|
// 如果正在查看历史营期,不显示结束营期按钮
|
||||||
|
if (isViewingHistory.value) return false;
|
||||||
|
|
||||||
if (isCampFinished.value) return false;
|
if (isCampFinished.value) return false;
|
||||||
|
|
||||||
// 检查是否有营期相关的事件
|
// 检查是否有营期相关的事件
|
||||||
@@ -908,6 +924,71 @@ const parseDateRange = (dateRangeStr) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 方法:将历史营期数据映射到日历
|
||||||
|
const mapHistoryPeriodToCalendar = (historyPeriod) => {
|
||||||
|
// 清除之前的营期相关事件
|
||||||
|
events.value = events.value.filter(event => !event.isCampEvent);
|
||||||
|
|
||||||
|
let eventId = events.value.length + 1;
|
||||||
|
const startDate = new Date(historyPeriod.startDate);
|
||||||
|
const endDate = new Date(historyPeriod.endDate);
|
||||||
|
|
||||||
|
// 计算营期总天数
|
||||||
|
const totalDays = Math.ceil((endDate - startDate) / (1000 * 60 * 60 * 24)) + 1;
|
||||||
|
|
||||||
|
let currentDate = new Date(startDate);
|
||||||
|
|
||||||
|
// 1. 添加接数据事件
|
||||||
|
for (let i = 0; i < historyPeriod.dataDays; i++) {
|
||||||
|
const dateStr = formatDateToString(currentDate);
|
||||||
|
events.value.push({
|
||||||
|
id: eventId++,
|
||||||
|
date: dateStr,
|
||||||
|
title: '接数据',
|
||||||
|
description: `第${historyPeriod.periodNum}期历史营期 - 数据接收阶段 (第${i + 1}天)`,
|
||||||
|
isCampEvent: true,
|
||||||
|
type: 'data'
|
||||||
|
});
|
||||||
|
currentDate.setDate(currentDate.getDate() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 添加课程事件(课1-4,连续4天)
|
||||||
|
const courses = ['课1', '课2', '课3', '课4'];
|
||||||
|
courses.forEach((courseTitle, index) => {
|
||||||
|
if (currentDate <= endDate) {
|
||||||
|
const dateStr = formatDateToString(currentDate);
|
||||||
|
events.value.push({
|
||||||
|
id: eventId++,
|
||||||
|
date: dateStr,
|
||||||
|
title: courseTitle,
|
||||||
|
description: `第${historyPeriod.periodNum}期历史营期 - ${courseTitle}阶段`,
|
||||||
|
isCampEvent: true,
|
||||||
|
type: 'course'
|
||||||
|
});
|
||||||
|
currentDate.setDate(currentDate.getDate() + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. 添加休息日事件(在营期结束前的几天)
|
||||||
|
const restStartDate = new Date(endDate);
|
||||||
|
restStartDate.setDate(endDate.getDate() - historyPeriod.restDays + 1);
|
||||||
|
|
||||||
|
for (let i = 0; i < historyPeriod.restDays; i++) {
|
||||||
|
const restDate = new Date(restStartDate);
|
||||||
|
restDate.setDate(restStartDate.getDate() + i);
|
||||||
|
const dateStr = formatDateToString(restDate);
|
||||||
|
|
||||||
|
events.value.push({
|
||||||
|
id: eventId++,
|
||||||
|
date: dateStr,
|
||||||
|
title: '休息',
|
||||||
|
description: `第${historyPeriod.periodNum}期历史营期 - 休息日 (第${i + 1}天)`,
|
||||||
|
isCampEvent: true,
|
||||||
|
type: 'rest'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1376,6 +1457,28 @@ onMounted(async () => {
|
|||||||
box-shadow: 0 2px 4px rgba(40, 167, 69, 0.3);
|
box-shadow: 0 2px 4px rgba(40, 167, 69, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 历史营期事件点样式 */
|
||||||
|
.event-dot.history-period {
|
||||||
|
opacity: 0.6;
|
||||||
|
border: 2px solid #6c757d;
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-dot.history-period.event-data {
|
||||||
|
background: #6c757d;
|
||||||
|
box-shadow: 0 2px 4px rgba(108, 117, 125, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-dot.history-period.event-course {
|
||||||
|
background: #6c757d;
|
||||||
|
box-shadow: 0 2px 4px rgba(108, 117, 125, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-dot.history-period.event-rest {
|
||||||
|
background: #6c757d;
|
||||||
|
box-shadow: 0 2px 4px rgba(108, 117, 125, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
/* 休息日文字样式 */
|
/* 休息日文字样式 */
|
||||||
.rest-text {
|
.rest-text {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -1702,40 +1805,5 @@ onMounted(async () => {
|
|||||||
box-shadow: 0 2px 4px rgba(40, 167, 69, 0.2);
|
box-shadow: 0 2px 4px rgba(40, 167, 69, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 营期状态指示器样式 */
|
|
||||||
.period-indicator {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 8px 0;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
border-bottom: 1px solid #e9ecef;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-indicator,
|
|
||||||
.current-indicator {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 6px 12px;
|
|
||||||
border-radius: 20px;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-indicator {
|
|
||||||
background: linear-gradient(135deg, #ffc107, #fd7e14);
|
|
||||||
color: white;
|
|
||||||
box-shadow: 0 2px 4px rgba(255, 193, 7, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-indicator {
|
|
||||||
background: linear-gradient(135deg, #28a745, #20c997);
|
|
||||||
color: white;
|
|
||||||
box-shadow: 0 2px 4px rgba(40, 167, 69, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-indicator svg,
|
|
||||||
.current-indicator svg {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user