vue3+FullCalendar+Element-plus修改的日程安排表

news2024/11/24 19:12:41

实现效果

在这里插入图片描述

安装Fullcalendar相关插件

npm install @fullcalendar/core @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/list @fullcalendar/interaction --save
  • 代码中使用到了时间转换和element-plus,安装dayjs和element-plus
npm install element-plus @element-plus/icons-vue dayjs
  • 样式sass
npm install sass sass-loader

实现代码

注意:月份中想要横向拖拽几天日期,配置项属性中必须allDaySlot为true,默认为true。同时,周页面中这个日期是全天才可以横向拖拽几天日期

<template>
  <div class="calender-container">
    <el-card>
      <!-- 自定义头部,切换视图类型和切换日期 -->
      <div class="calender-header mb2">
        <div class="header-left">
          <span class="time-title">{{ currentDate }}</span>
          <el-button
            :icon="ArrowLeftBold"
            circle
            @click="
              Tcalendar.prev();
              dayTime();
            "
          />
          <el-button
            :icon="ArrowRightBold"
            circle
            @click="
              Tcalendar.next();
              dayTime();
            "
          />
        </div>
        <div class="header-right">
          <el-button
            class="btn-m2"
            type="primary"
            @click="
              Tcalendar.today();
              dayTime();
            "
            plain
            round
            >今天</el-button
          >
          <el-select
            v-model="type"
            placeholder="视图类型"
            style="width: 80px"
            @change="changeType"
          >
            <el-option label="月" value="dayGridMonth" />
            <el-option label="周" value="timeGridWeek" />
            <el-option label="天" value="timeGridDay" />
            <el-option label="列" value="listWeek" />
          </el-select>
          <!-- 选择月份的日期框 -->
          <el-date-picker
            v-if="type === 'dayGridMonth'"
            v-model="showMonth"
            type="month"
            :clearable="false"
            placeholder="请选择日期"
            style="margin-left: 10px; vertical-align: middle"
            @change="changeDate"
          />
          <el-button class="ml2" type="primary" :icon="Plus" plain
            >新增排班</el-button
          >
        </div>
      </div>
      <div ref="fullcalendar" class="card"></div>
    </el-card>

    <!-- 查看任务详情弹窗 -->
    <calendarDetailDialog
      v-model:dialogVisible="calendarDialogVisible"
      :detailInfo="detailInfo"
    />
    <!-- 新增任务弹窗 -->
    <drawerAddPlan v-model:drawerVisile="drawerVisile" />
  </div>
</template>

<script setup lang="ts">
import { ref, nextTick, onMounted } from "vue";
import { Calendar } from "@fullcalendar/core";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import listPlugin from "@fullcalendar/list";
import interactionPlugin from "@fullcalendar/interaction";
import dayjs from "dayjs";
import { ArrowLeftBold, ArrowRightBold, Plus } from "@element-plus/icons-vue";
import calendarDetailDialog from "./components/calendarDetailDialog.vue";
import drawerAddPlan from "./components/drawerAddPlan.vue";

const state = {
  infoList: [
    {
      id: "1",
      title: "老化实验",
      name: "张三",
      start: "2024-10-08",
      end: "2024-10-08",
      class: "tag_1",
      job: "产线员工",
      description: "XXXXXXXXX实验XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    },
    {
      id: "2",
      title: "第一个任务12312312312312312",
      name: "李四",
      start: "2024-10-10 13:30:00",
      end: "2024-10-10 14:30:00",
      class: "tag_2",
      job: "负责人",
      description: "测试XXXXXXX",
    },
    {
      id: "3",
      title: "第一个任务12312312312312312",
      name: "员工1",
      start: "2024-10-11 08:00:00",
      end: "2024-10-11 12:30:00",
      class: "tag_2",
      job: "员工",
      description: "测试XXXXXXXeqee",
    },
    {
      id: "4",
      title: "第一个任务12312312312312312",
      name: "员工",
      start: "2024-10-09 09:30:00",
      end: "2024-10-09 11:00:00",
      class: "tag_3",
      job: "生产员工3",
      description: "测试XXXXXXXeqee",
    },
    {
      id: "5",
      title: "第一个任务12312312312312312",
      name: "员工3",
      start: "2024-10-09 16:00:00",
      end: "2024-10-09 18:30:00",
      class: "tag_1",
      job: "生产员工2",
      description: "测试XXXXXXXeqee",
    },
    {
      id: "6",
      title: "第一个任务12312312312312312",
      name: "员工4",
      start: "2024-10-09 13:30:00",
      end: "2024-10-09 14:00:00",
      class: "tag_2",
      job: "生产员工1",
      description: "测试XXXXXXXeqee",
    },
  ],
  Tcalendar: ref(),
};
const fullcalendar = ref();
const Tcalendar = ref();
const type = ref("dayGridMonth"); // 默认月视图
const currentDate = ref(); // 当前时间
const showMonth = ref(dayjs().format("YYYY-MM")); // 默认当前月份
const calendarDialogVisible = ref(false); // 是否显示详情弹窗
const detailInfo = ref(); // 详情数据
const drawerVisile = ref(false); // 是否显示新增排班的抽屉

const initCalendar = () => {
  Tcalendar.value = new Calendar(fullcalendar.value, {
    plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
    initialView: type.value,
    aspectRatio: 2.2, // 宽度比
    locale: "zh-cn",
    handleWindowResize: true,
    //   loading: loading //控制表格加载
    editable: true, // 允许编辑表格
    droppable: true, //允许从外部拖拽进入日历
    eventDurationEditable: true, //控制时间段是否可以拖动
    eventResizableFromStart: true, //控制事件是否可以拖动
    selectable: true, // 允许用户通过单击和拖动来突出显示多个日期或时间段
    firstDay: 1, // 设置一周中显示的第一天是哪天,周日是0,周一是1,类推。
    unselectAuto: true, // 当点击页面日历以外的位置时,是否自动取消当前的选中状态
    dayMaxEvents: true, //在dayGrid视图中,给定日期内的最大事件数
    headerToolbar: false, // 关闭默认日历头部,采取自定义的方式切换日历视图
    // allDaySlot: false, // 关闭全天选项
    allDayText: "全天",
    nowIndicator: true,
    eventMaxStack: 2,
    events: state.infoList, //主要数据
    eventClassNames: function (arg) {
      // 添加自定义class
      return [arg.event.extendedProps.class];
    },
    eventContent: function (arg) {
      // 日历上event显示的样式
      const italicEl = document.createElement("div");
      // 列表才显示
      if (type.value === "listWeek") {
        // 标题
        const nameEl = document.createElement("h4");
        nameEl.setAttribute("class", `h4`);
        nameEl.innerHTML = arg.event.extendedProps.name;
        italicEl.append(nameEl);
        // 岗位
        const text1El = document.createElement("p");
        text1El.innerHTML = arg.event.extendedProps.job;
        italicEl.append(text1El);
        // 面试官
        const text2El = document.createElement("p");
        text2El.innerHTML = "描述:" + arg.event.extendedProps.job;
        italicEl.append(text2El);
      } else {
        // 标题
        const titleEl = document.createElement("div");
        titleEl.setAttribute("class", `calendar-title`);
        const nameEl = document.createElement("span");
        nameEl.innerHTML = arg.event.extendedProps.name;
        titleEl.append(nameEl);
        // 时间
        const timeEl = document.createElement("span");
        if (arg.event.start && arg.event.end) {
          timeEl.innerHTML =
            dayjs(arg.event.start).format("HH:mm") +
            "-" +
            dayjs(arg.event.end).format("HH:mm");
          if (timeEl.innerHTML !== "00:00-00:00") {
            titleEl.append(timeEl);
          }
        }
        italicEl.append(titleEl);
      }
      italicEl.setAttribute("class", `calendar-card`);
      return { domNodes: [italicEl] };
    },
    noEventsContent: function () {
      const noEl = document.createElement("div");
      noEl.innerHTML = "暂无日程安排,请安排相关日程";
      return { domNodes: [noEl] };
    },
    // 点击查看时触发
    eventClick: function (info) {
      handleClick(info);
    },
    // 视图选择日期触发
    select: function (info) {
      handleSelectDate(info);
    },
    // 拖拽event大小时触发
    eventResize: function (info) {
      handleEventResize(info);
    },
    // 拖拽停止时触发
    eventDrop: function (info) {
      handleDrap(info);
    },
  });
  Tcalendar.value.render();
};

//   切换类型
const changeType = (type: any) => {
  Tcalendar.value.changeView(type);
  dayTime();
};

/**
 * 获取当前时间
 */
const dayTime = () => {
  if (type.value === "dayGridMonth") {
    currentDate.value = dayjs(Tcalendar.value.getDate()).format("YYYY年MM月");
    // showMonth.value = dayjs(Tcalendar.value.getDate()).format('YYYY-MM');
  } else if (type.value === "timeGridWeek" || type.value === "listWeek") {
    currentDate.value =
      dayjs(Tcalendar.value.getDate()).format("YYYY年MM月DD日") +
      " - " +
      dayjs(Tcalendar.value.getDate()).add(6, "day").format("DD日");
  } else if (type.value === "timeGridDay") {
    currentDate.value = dayjs(Tcalendar.value.getDate()).format(
      "YYYY年MM月DD日"
    );
  }
};

/**
 * 修改月份
 * @param date 跳转日期
 */
const changeDate = (date: any) => {
  Tcalendar.value.gotoDate(dayjs(date).format("YYYY-MM"));
  currentDate.value = dayjs(date).format("YYYY年MM月");
};

/**
 * 拖拽调整大小
 */
const handleDrap = (info: any) => {
  console.log("info1--", info);
};
/**
 * 拖拽调整大小时触发
 */
const handleEventResize = (info: any) => {
  console.log("info2--", info);
};

/**
 * 点击事件,查看任务详情
 */
const handleClick = (info: any) => {
  console.log("info-3-", info.event);
  detailInfo.value = info.event;
  calendarDialogVisible.value = true;
};

const handleSelectDate = (info: any) => {
  console.log("info4--", info);
  drawerVisile.value = true;
};
const handleOk = () => {};
onMounted(() => {
  nextTick(() => {
    initCalendar();
    dayTime();
  });
});
</script>

<style lang="scss" scoped>
.calender-container {
  width: 1525px;
  position: relative;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.calender-header {
  display: flex;
  justify-content: space-between;
  .header-left,
  .header-right {
    display: flex;
    align-items: center;
    .time-title {
      font-weight: bold;
      margin-right: 20px;
    }
  }
  .header-left {
    h1 {
      margin-right: 20px;
    }
  }
}

.btn-m2 {
  margin-right: 20px;
}
.ml2 {
  margin-left: 20px !important;
}
.mb2 {
  margin-bottom: 20px !important;
}
</style>
<style lang="scss">
.fc-col-header {
  background-color: #fafafa;
}
.calendar-card {
  display: block;
  padding: 2px 4px;
}
.calendar-title {
  display: flex;
  align-items: center;
  margin-left: 10px;
  font-size: 13px;
  span {
    margin-right: 5px;
  }
}
.fc .fc-daygrid-day.fc-day-today {
  background-color: rgba(101, 180, 230, 0.2);
  .fc-daygrid-day-number {
    background-color: #00b578;
    color: #fff;
    border-radius: 4px;
  }
}
.fc .fc-highlight {
  background: rgba(101, 180, 230, 0.2);
}
.fc .fc-timegrid-col.fc-day-today {
  background-color: rgba(101, 180, 230, 0.2);
}

.tag_1,
.tag_2,
.tag_3 {
  border-radius: 20px;
}
.tag_1 {
  background-color: #fab6b6;
}
.tag_2 {
  background-color: #a0cfff;
}
.tag_3 {
  background-color: #c8c9cc;
}
</style>

  • 弹窗组件calendarDetailDialog.vue代码如下:
<template>
	<div class="container">
		<el-dialog :model-value="dialogVisible" width="25%" :before-close="handleClose">
			<template #header>
				<h3>{{ '任务详情' }}</h3>
			</template>
			<!-- 具体内容 -->
			<el-descriptions :column="1" border>
				<template #title>
					<div class="task-title">{{ taskTitle }}</div>
				</template>
				<el-descriptions-item label="执行人" min-width="90">{{ taskContent.name }}</el-descriptions-item>
				<el-descriptions-item label="岗位">{{ taskContent.job }}</el-descriptions-item>
				<el-descriptions-item label="执行时间">{{ taskStartTime }} - {{ taskEndTime }}</el-descriptions-item>
				<el-descriptions-item label="描述"> {{ taskContent.description }} </el-descriptions-item>
				<el-descriptions-item label="创建时间"> </el-descriptions-item>
				<el-descriptions-item label="创建人"> </el-descriptions-item>
			</el-descriptions>
		</el-dialog>
	</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import dayjs from 'dayjs';

// 接收父组件传值
const props = defineProps(['dialogVisible', 'detailInfo']);
const emits = defineEmits(['update:dialogVisible']);

const taskTitle = ref(''); // 任务标题
const taskContent = ref<any>('');
const taskStartTime = ref(''); // 任务开始时间
const taskEndTime = ref(''); // 任务结束时间

watch(
	() => props.detailInfo,
	(newValue) => {
		console.log(newValue);
		taskTitle.value = newValue.title;
		taskContent.value = newValue.extendedProps;
		taskStartTime.value = dayjs(newValue.start).format('YYYY-MM-DD HH:mm:ss');
		taskEndTime.value = dayjs(newValue.end).format('YYYY-MM-DD HH:mm:ss');
	}
);
/**
 * 弹窗关闭时操作
 */
const handleClose = () => {
	emits('update:dialogVisible', false);
};
</script>
<style lang="scss" scoped>
.task-title::before{
  content: '';
  width: 6px;
  height: 22px;
  display: inline-block;
  vertical-align: middle;
  background: #409eff;
  margin-right: 8px;
  border-radius: 10px;
}
.task-title{
  vertical-align: middle;
}
:deep(.el-overlay .el-overlay-dialog .el-dialog .el-dialog__body) {
	padding: 0 !important;
}
:deep(.el-overlay) {
	z-index: 9999 !important;
}
</style>

源码链接

日程安排表源码

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

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

相关文章

03 django管理系统 - 部门管理 - 部门列表

部门管理 首先我们需要在models里定义Dept类 # 创建部门表 class Dept(models.Model):name models.CharField(max_length100)head models.CharField(max_length100)phone models.CharField(max_length15)email models.EmailField()address models.CharField(max_length2…

MySql的binlog与数据的恢复

目录 什么是binlogbinlog的作用binlog的三种模式binlog的开启数据的恢复与回滚binlog日志的删除 什么是binlog binlog我们一般叫做归档日志&#xff0c;他是mysql服务器层的日志&#xff0c;跟存储引擎无关&#xff0c;他记录的是所有DDL和DML的语句&#xff0c;不包含查询语句…

文本语义检索系统的搭建过程,涵盖了召回、排序以及Milvus召回系统、短视频推荐等相关内容

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下本文详细介绍了文本语义检索系统的搭建过程&#xff0c;涵盖了召回、排序以及Milvus召回系统的相关内容。通过使用PyTorch框架&#xff0c;我们提供了样例代码&#xff0c;以帮助读者更好地理解和实践。该系统具有广…

基于STM32的车牌识别系统

基于STM32的车牌识别系统硬件设计 在智能交通系统中&#xff0c;车牌识别技术扮演着至关重要的角色。它不仅用于道路交通监控&#xff0c;还广泛应用于小区和停车场管理、收费站管理系统、车流统计以及移动车载系统等领域。本文将详细介绍基于STM32单片机的车牌识别系统的硬件…

Vue3 + TypeScript + Vite + Echarts

Vue3 TypeScript Vite Echarts 1、创建工程 npm create vitelatestcd echarts npm install npm run dev2、安装项目依赖模块 npm install types/node --save-devnpm install vue-router4npm install animate.css --save npm install gsap --savenpm install fetch --save …

2024年源代码加密软件推荐,十款超好用的源代码加密软件推荐

在当今数字化时代&#xff0c;源代码的安全性对于企业和开发者来说至关重要。无论是为了保护知识产权&#xff0c;还是为了防止恶意攻击&#xff0c;选择一款可靠的源代码加密软件都是必不可少的。本文将为您推荐2024年十款超好用的源代码加密软件&#xff0c;帮助您在保护代码…

10款超好用的电脑加密软件推荐|2024年常用电脑加密软件排行榜

随着数字化办公的普及&#xff0c;企业的数据安全面临前所未有的挑战。文件的泄露、窃取和丢失不仅会影响企业的商业利益&#xff0c;还可能导致客户隐私泄露&#xff0c;进而影响企业声誉。因此&#xff0c;选择一款合适的加密软件来保护公司机密文件变得尤为重要。2024年&…

AI产品经理怎么准备面试啊?

最近有些小伙伴&#xff0c;想要求职AI领域的产品经理&#xff0c;特别是AIGC的产品经理&#xff0c;但是不知道面试官会问哪些问题&#xff0c;也就不知道如何开始准备&#xff1f;该准备哪些东西&#xff1f;要准备到什么程度&#xff1f;最终导致迟迟不敢开始。 下面总共5家…

多级代理与提权维权

目录 代理构建FRP介绍下载配置⽂件&#xff1a; sock5代理Venom介绍下载配置 icmpsh介绍下载配置 pingtunnel介绍下载配置 EarthWorm介绍下载使用 权限提升win权限提升常⻅利⽤⼯具 Linux权限提升SUID提权 权限维持win权限维持系统服务后⻔⾃启动⽬录注册表后⻔其他类似隐藏⽤户…

西安国际数字影像产业园:文化创意产业的加速器

西安国际数字影像产业园作为文化创意产业的加速器&#xff0c;正为西安乃至全国的文化创意产业发展注入强大动力&#xff1a; 优越的基础条件&#xff1a;西安作为历史文化名城&#xff0c;文化底蕴深厚&#xff0c;为数字影像产业提供了丰富的创作素材和灵感源泉。西安国际数…

magic-html : 通用HTML数据提取器!DocAI:从非结构化文档中提取结构化数据!强大、快速、开源的微信机器人底层框架:wcf.js!

magic-html : 通用HTML数据提取器&#xff01;DocAI&#xff1a;从非结构化文档中提取结构化数据&#xff01;强大、快速、开源的微信机器人底层框架&#xff1a;wcf.js&#xff01; magic-html : 通用HTML数据提取器 magic-html提供了一套工具&#xff0c;能够轻松地从HTML中…

闪电麦昆 语音控制齿轮行进轨迹,ESP32搭配语音控制板,串口通信,附视频演示地址

演示地址 https://www.bilibili.com/video/BV1cW421d79L/?vd_sourceb8515e53f6d4c564b541d98dcc9df990 语音控制板的配置 web展示页面 esp32 程序 #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <LittleFS.h> #include <WebSo…

最全方案解决Android Studio中使用lombok插件错误: 找不到符号的问题

直接原因 先直接说原因&#xff0c;小部分是因为配置错误导致的&#xff0c;注意查看下面的步骤即可&#xff0c;另一大部分是因为Java和Kotlin混编的问题&#xff0c;lombok和kapt冲突&#xff0c;其实你用了kotlin基本不需要用lombok&#xff0c;多此一举&#xff01;所以可…

最新版 Global Mapper 26 发布

我们在《工作中常用的软件&#xff0c;可直接下载0.3m卫星影像、DEM和土地覆盖数据》一文中&#xff0c;为你分享了GlobalMapper25版本。 现在&#xff0c;该神器的最新版GlobalMapper26已发布&#xff0c;如果这两个版本的软件你都需要&#xff0c;请在文末查看它们的下载方法…

Spring源码分析:bean加载流程

背景 在Spring中&#xff0c;Bean的加载和管理是其核心功能之一&#xff0c;包括配置元数据解析、Bean定义注册、实例化、属性填充、初始化、后置处理器处理、完成创建和销毁等步骤。 源码入口 AbstractBeanFactory#doGetBean 具体源码流程如下&#xff1a; bean加载流程&#…

怎么利用商品详情API接口实现数据获取与应用?

在当今数字化的商业时代&#xff0c;高效获取和利用商品数据对于企业和开发者来说至关重要。商品详情 API 接口为我们提供了一种便捷的方式来获取丰富的商品信息&#xff0c;从而实现各种有价值的应用。本文将深入探讨如何利用商品详情 API 接口实现数据获取与应用。 一、商品…

信号转导的风暴中心:ERK1/2

前 言 ERK1/2是RAF-MEK-ERK信号通路的关键组成部分&#xff0c;在Thr202、Tyr204位点被磷酸化从而激活&#xff0c;进而激活多种与细胞增殖、分化、迁移和血管生成相关的底物&#xff08;超过160种&#xff09;。因此ERK1/2的(Thr202, Tyr204)/(Thr185, Tyr187)磷酸化是ERK激…

从SQL Server过渡到PostgreSQL:理解模式的差异

前言 随着越来越多的企业转向开源技术&#xff0c;商业数据库管理员和开发者也逐渐面临向PostgreSQL迁移的需求。 虽然SQL Server和PostgreSQL共享许多数据库管理系统&#xff08;RDBMS&#xff09;的基本概念&#xff0c;但它们在处理某些结构上的差异可能会让人感到困惑&…

利用Spring Boot实现医疗病历的B2B平台集成

第5章 系统实现 5.1 管理员角色 5.1.1 医院管理 管理员可以在医院管理界面对医院信息进行添加&#xff0c;修改&#xff0c;删除&#xff0c;查询操作。医院管理页面的运行结果如图5-1所示&#xff1a; 图5-1医院管理界面 5.1.2 医院注册 管理员可以在医院注册界面对医院信息…

【LeetCode】动态规划—1312. 让字符串成为回文串的最少插入次数(附完整Python/C++代码)

动态规划—1312. 让字符串成为回文串的最少插入次数 题目描述前言基本思路1. 问题定义目标&#xff1a;举例&#xff1a; 2. 理解问题和递推关系动态规划思路&#xff1a; 3. 解决方法动态规划方法伪代码&#xff1a; 4. 进一步优化5. 小总结 Python代码Python代码解释&#xf…