还差删除

This commit is contained in:
2026-04-04 16:59:08 +08:00
parent 37443d3b68
commit 293ba9df3c
2 changed files with 172 additions and 188 deletions
@@ -51,6 +51,11 @@ const props = defineProps({
required: false, required: false,
default: "", default: "",
}, },
isEditable:{
type:Boolean,
required: false,
default: true,
}
}); });
const eventData = ref({ const eventData = ref({
@@ -83,8 +88,9 @@ function passing_date_characters(startDate, endDate) {
} }
function passing_date_characters_Select(startDate, endDate) { function passing_date_characters_Select(startDate, endDate) {
//滑动选择日期的参数来自FullCalendar,不需要加一天也不需要判断大小,而且直接就是字符串类型 //滑动选择日期的参数来自FullCalendar,不需要加一天也不需要判断大小,而且直接就是字符串类型
eventData.value.start = startDate; eventData.value.start = startDate;
eventData.value.end = endDate; eventData.value.end = endDate===""?startDate:endDate;
} }
// 监听props变化,更新本地eventData // 监听props变化,更新本地eventData
@@ -296,11 +302,14 @@ const calendarOptions = ref({
}); });
function switchShow() { function switchShow() {
if (isShow.value) { if(props.isEditable){
isShow.value = false; if (isShow.value) {
} else { isShow.value = false;
isShow.value = true; } else {
isShow.value = true;
}
} }
} }
function splicingDataWeek(data) { function splicingDataWeek(data) {
+158 -183
View File
@@ -1,6 +1,6 @@
<script setup> <script setup>
// Vue 核心响应式 API // Vue 核心响应式 API
import { ref, watch, onMounted, onBeforeUnmount,reactive } from "vue"; import { ref, watch, onMounted, onBeforeUnmount, reactive } from "vue";
// FullCalendar Vue 3 组件 // FullCalendar Vue 3 组件
import FullCalendar from "@fullcalendar/vue3"; import FullCalendar from "@fullcalendar/vue3";
// FullCalendar 插件:月视图 // FullCalendar 插件:月视图
@@ -52,10 +52,13 @@ const calendarNowShow = ref();
// 模态框相关状态 // 模态框相关状态
const showModal = ref(false); const showModal = ref(false);
const eventData = ref({ const eventData = ref({
id: 0,
title: "", title: "",
startDate: "", startDate: "",
endDate: "", endDate: "",
color: "#066FD1", // 默认蓝色工作事件 color: "#066FD1", // 默认蓝色工作事件
isEditing: false, //是否处于编辑模式,false就是添加模式
isEditable: false,//是否有权限编辑,无权限就让按钮灰掉
}); });
// 颜色选项 // 颜色选项
@@ -80,50 +83,46 @@ const colorOptions = ref([
}, },
]); ]);
const pageData =reactive({//本页全局变量 const pageData = reactive({//本页全局变量
seleEventID:0,//上次点击的eventid seleEventID: 0,//上次点击的eventid
lastClickTime:0,// 用于跟踪上次点击时间的响应式变量 lastClickTime: 0,// 用于跟踪上次点击时间的响应式变量
lastClickTimeStr:"", lastClickTimeStr: "",
lastEventClickTime:0,// 用于跟踪上次点击event时间的响应式变量 lastEventClickTime: 0,// 用于跟踪上次点击event时间的响应式变量
lastEventClickID:0, lastEventClickID: 0,
submitChecked:false, submitChecked: false,
editMode:false, editMode: false,
}) })
function unseleEvent(eventID) function unseleEvent(eventID) {
{
//寻找哪个event被单击了并修改边框 //寻找哪个event被单击了并修改边框
const target = calendarOptions.value.events.find(item => item.id === eventID) const target = calendarOptions.value.events.find(item => item.id === eventID)
if(target){ if (target) {
target.borderColor=target.backgroundColor; target.borderColor = target.backgroundColor;
} }
} }
function unseleEventAll() function unseleEventAll() {
{
unseleEvent(pageData.seleEventID) unseleEvent(pageData.seleEventID)
pageData.seleEventID=0; pageData.seleEventID = 0;
} }
function seleEvent(eventID) function seleEvent(eventID) {
{
//单击了event //单击了event
//取消上次选中 //取消上次选中
if(pageData.seleEventID!=0) if (pageData.seleEventID != 0) {
{
unseleEvent(pageData.seleEventID); unseleEvent(pageData.seleEventID);
} }
//寻找哪个event被单击了并修改边框 //寻找哪个event被单击了并修改边框
const target = calendarOptions.value.events.find(item => item.id === eventID) const target = calendarOptions.value.events.find(item => item.id === eventID)
if(target){ if (target) {
target.borderColor="#000000"; target.borderColor = "#000000";
} }
pageData.seleEventID=eventID; pageData.seleEventID = eventID;
} }
@@ -258,15 +257,22 @@ const calendarOptions = ref({
unseleEventAll();//点击了日期就取消event的选择 unseleEventAll();//点击了日期就取消event的选择
//判断和上次点击的是不是同一天 //判断和上次点击的是不是同一天
if(info.dateStr===pageData.lastClickTimeStr){ if (info.dateStr === pageData.lastClickTimeStr) {
// 判断是否为双击(400ms 内连续点击) // 判断是否为双击(400ms 内连续点击)
if (timeDifference < 400 && timeDifference > 0) { if (timeDifference < 400 && timeDifference > 0) {
// 双击功能:快速添加事件 // 双击功能:快速添加事件
handleDoubleClick(info);
//先判断是否登录
if (userStore.isLoggedIn) {
openEventModal(info.dateStr, info.dateStr);
} else {
toast.warning(t("message.login_to_your_account"));
router.replace("/login?redirect=/schedule");
}
} }
} }
pageData.lastClickTimeStr=info.dateStr; pageData.lastClickTimeStr = info.dateStr;
// 更新上次点击时间 // 更新上次点击时间
pageData.lastClickTime = nowTime; pageData.lastClickTime = nowTime;
@@ -284,34 +290,35 @@ const calendarOptions = ref({
} }
}, },
//事件event点击处理函数 //事件event点击处理函数
eventClick(info) { eventClick(info) {
const nowTime = new Date().getTime(); const nowTime = new Date().getTime();
const timeDifference = nowTime - pageData.lastEventClickTime; const timeDifference = nowTime - pageData.lastEventClickTime;
//判断event的title是否过长,如果是被截断的 就toast.info弹窗显示 //判断event的title是否过长,如果是被截断的 就toast.info弹窗显示
const titleEl = info.el.querySelector('.fc-event-title'); // const titleEl = info.el.querySelector('.fc-event-title');
if (titleEl && titleEl.scrollWidth > titleEl.clientWidth) { // if (titleEl && titleEl.scrollWidth > titleEl.clientWidth) {
//title过长 得换一种方式显示 // //title过长 得换一种方式显示
//toast.info(info.event.title); // //toast.info(info.event.title);
} // }
// 单击功能: // 单击功能:
var eventid=parseInt(info.event.id) var eventid = parseInt(info.event.id)
seleEvent(eventid); seleEvent(eventid);
//判断和上次点击的是不是同一个event //判断和上次点击的是不是同一个event
if(eventid===pageData.lastEventClickID){ if (eventid === pageData.lastEventClickID) {
// 判断是否为双击(400ms 内连续点击) // 判断是否为双击(400ms 内连续点击)
if (timeDifference < 400 && timeDifference > 0) { if (timeDifference < 400 && timeDifference > 0) {
//console.log("双击事件:", info); //console.log("双击事件:", info);
openEventModal(info.event.startStr, info.event.end ? info.event.endStr : info.event.startStr, parseInt(info.event.id), info.event.title, info.event.backgroundColor, true, info.event.durationEditable);
// 双击功能: // 双击功能:
unseleEventAll() unseleEventAll()
} }
} }
pageData.lastEventClickID=eventid; pageData.lastEventClickID = eventid;
// 更新上次点击时间 // 更新上次点击时间
pageData.lastEventClickTime = nowTime; pageData.lastEventClickTime = nowTime;
@@ -319,44 +326,59 @@ const calendarOptions = ref({
//event拖动处理 //event拖动处理
eventDrop(info) { eventDrop(info) {
//需要发送到后端修改event updateEditData(parseInt(info.event.id),info.event.title,info.event.startStr,info.event.end === null ? info.event.startStr : DateUtils.toRealEnd(info.event.end),info.event.backgroundColor);
//console.log(info.event)
scheduleApi
.editEvent({
id:parseInt(info.event.id),
title: info.event.title,
start: info.event.startStr,
end: info.event.end===null?info.event.startStr:DateUtils.toRealEnd(info.event.end),
color: info.event.backgroundColor,
})
.then((r) => {
//console.log(r);
if (r.errCode == 0) {
//前端提交是否错误
switch (
r.raw.err_code //后端返回是否错误
) {
case 0:
getEvents();//从新从后端获取最新数据
break;
default:
toast.danger(t("message.server_error"));
break;
}
}
});
}, },
}); });
function editSaveEvent(){
//console.log(eventData)
updateEditData(eventData.value.id,eventData.value.title,eventData.value.startDate,eventData.value.startDate===eventData.value.endDate?eventData.value.startDate:DateUtils.toRealEnd(eventData.value.endDate),eventData.value.color);
}
function updateEditData(id,title,start,end,color){
//需要发送到后端修改event
//console.log(info.event)
scheduleApi
.editEvent({
id: id,
title: title,
start: start,
end: end,
color: color,
})
.then((r) => {
//console.log(r);
if (r.errCode == 0) {
//前端提交是否错误
switch (
r.raw.err_code //后端返回是否错误
) {
case 0:
closeEventModal();
getEvents();//从新从后端获取最新数据
break;
default:
toast.danger(t("message.server_error"));
break;
}
}
});
}
// 打开模态框 // 打开模态框
const openEventModal = (dateStr, dataEnd,title="",color="#066FD1",editMode=false) => { const openEventModal = (dateStr, dataEnd, id = 0, title = "", color = "#066FD1", isEditing = false, isEditable = true) => {
eventData.value = { eventData.value = {
id: id,
title: title, title: title,
startDate: dateStr, startDate: dateStr,
endDate: dataEnd, endDate: dataEnd,
color: color, color: color,
isEditing: isEditing,
isEditable: isEditable,
}; };
pageData.editMode=editMode;
//console.log(eventData.value);
showModal.value = true; showModal.value = true;
}; };
@@ -365,28 +387,16 @@ const closeEventModal = () => {
showModal.value = false; showModal.value = false;
}; };
// 处理双击事件:打开模态框添加事件
const handleDoubleClick = (info) => {
//先判断是否登录
if (userStore.isLoggedIn) {
openEventModal(info.dateStr, info.dateStr);
} else {
toast.warning(t("message.login_to_your_account"));
router.replace("/login?redirect=/schedule");
}
};
// 保存日程事件 // 保存日程事件
const saveEvent = () => { const saveEvent = () => {
if (!eventData.value.title.trim()) { if (!eventData.value.title.trim()) {
//alert("请输入日程内容"); //alert("请输入日程内容");
pageData.submitChecked=true; pageData.submitChecked = true;
toast.warning(t("schedule.event_title_required")); toast.warning(t("schedule.event_title_required"));
return; return;
} }
pageData.submitChecked=false; pageData.submitChecked = false;
if (!eventData.value.startDate || !eventData.value.endDate) { if (!eventData.value.startDate || !eventData.value.endDate) {
//alert("请选择日期"); //alert("请选择日期");
@@ -422,7 +432,7 @@ const saveEvent = () => {
.addEvent({ .addEvent({
title: newEvent.title, title: newEvent.title,
start: newEvent.start, start: newEvent.start,
end: newEvent.end===newEvent.start?newEvent.end:DateUtils.toRealEnd(newEvent.end), end: newEvent.end === newEvent.start ? newEvent.end : DateUtils.toRealEnd(newEvent.end),
color: newEvent.backgroundColor, color: newEvent.backgroundColor,
}) })
.then((r) => { .then((r) => {
@@ -430,7 +440,7 @@ const saveEvent = () => {
if (r.errCode == 0) { if (r.errCode == 0) {
//前端提交是否错误 //前端提交是否错误
switch ( switch (
r.raw.err_code //后端返回是否错误 r.raw.err_code //后端返回是否错误
) { ) {
case 0: case 0:
//calendarOptions.value.events.push(newEvent); //calendarOptions.value.events.push(newEvent);
@@ -443,6 +453,8 @@ const saveEvent = () => {
toast.danger(t("message.server_error")); toast.danger(t("message.server_error"));
break; break;
} }
} else {
toast.danger(t("message.server_error"));
} }
}); });
}; };
@@ -460,24 +472,24 @@ const getEvents = () => {
if (r.errCode == 0) { if (r.errCode == 0) {
//前端提交是否错误 //前端提交是否错误
switch ( switch (
r.raw.err_code //后端返回是否错误 r.raw.err_code //后端返回是否错误
) { ) {
case 0: case 0:
calendarOptions.value.events=[]; calendarOptions.value.events = [];
var events = r.raw.return.list; var events = r.raw.return.list;
//console.log(events); //console.log(events);
var eventstemp = []; var eventstemp = [];
events?.forEach((item) => { events?.forEach((item) => {
calendarOptions.value.events.push({ calendarOptions.value.events.push({
id: item.ID, // 后端 ID id: item.ID, // 后端 ID
title: item.Title, // 标题 title: item.Title, // 标题
start: item.StartDate, // 开始日期 start: item.StartDate, // 开始日期
end: item.StartDate===item.EndDate?item.EndDate:DateUtils.toCalendarEnd(item.EndDate), // 结束日期 end: item.StartDate === item.EndDate ? item.EndDate : DateUtils.toCalendarEnd(item.EndDate), // 结束日期
backgroundColor: item.BgColor, // 背景色 backgroundColor: item.BgColor, // 背景色
borderColor: item.BgColor, // 边框色(一般和背景一样) borderColor: item.BgColor, // 边框色(一般和背景一样)
allDay: true, // 全天事件 allDay: true, // 全天事件
editable:item.edit, editable: item.edit,
}); });
}); });
@@ -489,15 +501,14 @@ const getEvents = () => {
} }
}); });
}; };
// 清除日期选择
const clearDates = () => {
eventData.value.startDate = "";
eventData.value.endDate = "";
};
// 颜色选择处理 // 颜色选择处理
const selectColor = (colorValue) => { const selectColor = (colorValue) => {
eventData.value.color = colorValue; if (eventData.value.isEditable) {
eventData.value.color = colorValue;
}
}; };
// 监听语言变化,更新日历的本地化和按钮文字 // 监听语言变化,更新日历的本地化和按钮文字
@@ -565,37 +576,23 @@ onMounted(() => {
<!-- 日历容器占满视口高度减去顶部导航高度 --> <!-- 日历容器占满视口高度减去顶部导航高度 -->
<div class="flex w-full flex-col relative"> <div class="flex w-full flex-col relative">
<!-- 事件编辑模态框 --> <!-- 事件编辑模态框 -->
<div <div v-if="showModal" class="fixed inset-0 z-50 flex items-center justify-center bg-gray-800/20">
v-if="showModal"
class="fixed inset-0 z-50 flex items-center justify-center bg-gray-800/20"
>
<!-- 👇 最关键给外层加最大高度 + 溢出隐藏 --> <!-- 👇 最关键给外层加最大高度 + 溢出隐藏 -->
<div <div class="modal-content bg-white rounded-lg shadow-lg w-full max-w-2xl max-h-[95vh] flex flex-col">
class="modal-content bg-white rounded-lg shadow-lg w-full max-w-2xl max-h-[95vh] flex flex-col"
>
<!-- 模态框头部 --> <!-- 模态框头部 -->
<div <div class="modal-header border-b p-4 flex justify-between items-center flex-shrink-0">
class="modal-header border-b p-4 flex justify-between items-center flex-shrink-0"
>
<h5 class="modal-title text-lg font-semibold"> <h5 class="modal-title text-lg font-semibold">
{{ t("schedule.add_event") }} {{ userStore.isLoggedIn ? eventData.isEditing ? "修改日程" : t("schedule.add_event") : "查看日程" }}
</h5> </h5>
<button <h5 class="modal-title text-lg font-semibold absolute left-1/2 -translate-x-1/2">
@click="closeEventModal" {{userStore.isLoggedIn ? eventData.isEditing ?"xxx的日程":"":""}}
class="btn-close text-gray-500 hover:text-gray-700"
> </h5>
<svg <button @click="closeEventModal" class="btn-close text-gray-500 hover:text-gray-700">
xmlns="http://www.w3.org/2000/svg" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
width="24" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
height="24" class="icon icon-tabler icons-tabler-outline icon-tabler-x">
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="icon icon-tabler icons-tabler-outline icon-tabler-x"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M18 6l-12 12"></path> <path d="M18 6l-12 12"></path>
<path d="M6 6l12 12"></path> <path d="M6 6l12 12"></path>
@@ -606,31 +603,21 @@ onMounted(() => {
<!-- 👇 主体区域允许内部滚动 --> <!-- 👇 主体区域允许内部滚动 -->
<div class="modal-body p-4 flex-1 overflow-y-auto"> <div class="modal-body p-4 flex-1 overflow-y-auto">
<!-- 日期选择区域 --> <!-- 日期选择区域 -->
<DatatimePickerForFullCalendar <DatatimePickerForFullCalendar v-model:startDate="eventData.startDate" v-model:endDate="eventData.endDate"
v-model:startDate="eventData.startDate" :color="eventData.color" :title="eventData.title" :isEditable="eventData.isEditable" />
v-model:endDate="eventData.endDate"
:color="eventData.color"
:title="eventData.title"
/>
<!-- 内容输入区域 --> <!-- 内容输入区域 -->
<div class="mb-4"> <div class="mb-4">
<div class="uni-easyinput input relative"> <div class="uni-easyinput input relative">
<div <div class="uni-easyinput__content is-input-border border border-gray-300 rounded-md bg-white relative"
class="uni-easyinput__content is-input-border border border-gray-300 rounded-md bg-white relative"
:class="{ :class="{
'border-gray-300': eventData.title ||!pageData.submitChecked, 'border-gray-300': eventData.title || !pageData.submitChecked,
'border-red-500': !eventData.title && pageData.submitChecked 'border-red-500': !eventData.title && pageData.submitChecked
}" }">
> <input v-model="eventData.title" type="text" maxlength="140"
<input
v-model="eventData.title"
type="text"
maxlength="140"
class="uni-easyinput__content-input w-full px-3 py-2 outline-none" class="uni-easyinput__content-input w-full px-3 py-2 outline-none"
:placeholder="t('schedule.event_title_placeholder')" :placeholder="t('schedule.event_title_placeholder')" @keyup.enter="saveEvent"
@keyup.enter="saveEvent" :disabled="!eventData.isEditable" />
/>
</div> </div>
</div> </div>
</div> </div>
@@ -638,33 +625,19 @@ onMounted(() => {
<!-- 颜色选择区域 --> <!-- 颜色选择区域 -->
<div class="mb-4"> <div class="mb-4">
<div class="color_box grid grid-cols-3 gap-2"> <div class="color_box grid grid-cols-3 gap-2">
<div <div v-for="color in colorOptions" :key="color.value" class="color_box_item">
v-for="color in colorOptions" <label class="uni-label-pointer form-colorinput flex items-center gap-2 cursor-pointer"
:key="color.value" @click="selectColor(color.value)">
class="color_box_item"
>
<label
class="uni-label-pointer form-colorinput flex items-center gap-2 cursor-pointer"
@click="selectColor(color.value)"
>
<div class="uni-radio-wrapper"> <div class="uni-radio-wrapper">
<div <div class="uni-radio-input flex items-center justify-center w-6 h-6 rounded-full transition-all"
class="uni-radio-input flex items-center justify-center w-6 h-6 rounded-full transition-all"
:style="{ :style="{
backgroundColor: color.value, backgroundColor: color.value,
borderColor: color.value, borderColor: color.value,
}" }">
> <svg v-if="eventData.color === color.value" width="18" height="18" viewBox="0 0 32 32">
<svg
v-if="eventData.color === color.value"
width="18"
height="18"
viewBox="0 0 32 32"
>
<path <path
d="M1.952 18.080q-0.32-0.352-0.416-0.88t0.128-0.976l0.16-0.352q0.224-0.416 0.64-0.528t0.8 0.176l6.496 4.704q0.384 0.288 0.912 0.272t0.88-0.336l17.312-14.272q0.352-0.288 0.848-0.256t0.848 0.352l-0.416-0.416q0.32 0.352 0.32 0.816t-0.32 0.816l-18.656 18.912q-0.32 0.352-0.8 0.352t-0.8-0.32l-7.936-8.064z" d="M1.952 18.080q-0.32-0.352-0.416-0.88t0.128-0.976l0.16-0.352q0.224-0.416 0.64-0.528t0.8 0.176l6.496 4.704q0.384 0.288 0.912 0.272t0.88-0.336l17.312-14.272q0.352-0.288 0.848-0.256t0.848 0.352l-0.416-0.416q0.32 0.352 0.32 0.816t-0.32 0.816l-18.656 18.912q-0.32 0.352-0.8 0.352t-0.8-0.32l-7.936-8.064z"
fill="#ffffff" fill="#ffffff"></path>
></path>
</svg> </svg>
</div> </div>
</div> </div>
@@ -676,33 +649,36 @@ onMounted(() => {
</div> </div>
<!-- 👇 底部固定不被滚动不压缩 --> <!-- 👇 底部固定不被滚动不压缩 -->
<div <!-- 如果没登录直接不显示 -->
class="modal-footer border-t p-4 flex justify-between items-center flex-shrink-0" <div v-if="userStore.isLoggedIn"
> class="modal-footer border-t p-4 flex justify-between items-center flex-shrink-0">
<button
@click="closeEventModal"
class="btn px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md"
>
{{ t("schedule.close") }}
</button>
<div class="flex gap-2"> <div class="flex gap-2">
<button <button v-if="eventData.isEditing" @click="closeEventModal" class="btn px-4 py-2 text-white bg-red-500 hover:bg-red-600 rounded-md
class="btn px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md" disabled:bg-gray-400 disabled:cursor-not-allowed" :disabled="!eventData.isEditable">
disabled 删除
> </button>
</div>
<div class="flex gap-2">
<button class="btn px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md" disabled>
{{ t("schedule.copy") }} {{ t("schedule.copy") }}
</button> </button>
<button <button class="btn px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md" disabled>
class="btn px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md"
disabled
>
{{ t("schedule.paste") }} {{ t("schedule.paste") }}
</button> </button>
<button <button
v-if="!eventData.isEditing"
@click="saveEvent" @click="saveEvent"
class="btn btn-primary px-4 py-2 bg-blue-600 text-white hover:bg-blue-700 rounded-md" class="btn btn-primary px-4 py-2 bg-cyan-600 text-white hover:bg-cyan-700 rounded-md disabled:bg-gray-400 disabled:cursor-not-allowed"
> :disabled="!eventData.isEditable">
{{ t("schedule.add_event_button") }} {{t("schedule.add_event_button") }}
</button>
<button
v-if="eventData.isEditing"
@click="editSaveEvent"
class="btn btn-primary px-4 py-2 bg-teal-600 text-white hover:bg-teal-700 rounded-md disabled:bg-gray-400 disabled:cursor-not-allowed"
:disabled="!eventData.isEditable">
修改日程
</button> </button>
</div> </div>
</div> </div>
@@ -710,9 +686,7 @@ onMounted(() => {
</div> </div>
<!-- 日历主体区域带边框和阴影 --> <!-- 日历主体区域带边框和阴影 -->
<div <div class="flex-1 rounded-lg border border-gray-200 bg-white p-0.5 shadow dark:border-dk-muted dark:bg-dk-card">
class="flex-1 rounded-lg border border-gray-200 bg-white p-0.5 shadow dark:border-dk-muted dark:bg-dk-card"
>
<!-- 内层容器隐藏溢出内容 --> <!-- 内层容器隐藏溢出内容 -->
<div class="h-full w-full overflow-hidden rounded-md"> <div class="h-full w-full overflow-hidden rounded-md">
<!-- FullCalendar 日历组件 --> <!-- FullCalendar 日历组件 -->
@@ -747,6 +721,7 @@ onMounted(() => {
0% { 0% {
transform: translateX(0%); transform: translateX(0%);
} }
100% { 100% {
transform: translateX(-100%); transform: translateX(-100%);
} }