效果图:
image.png版本与依赖:注意这里引入了webpack-merge
image.png
大概思路如下
1.修改日历周一至周五的文本:
解决办法:使用Config Provider
2.自定义日历头部:
首先element-plus官网提供了demo,但是我未使用这种方式,经测试发现这样不能通过顶部的日期组件选择日期
解决办法:使用dayjs自己实现日期快捷切换,这里把这部分逻辑抽离到myCalendar.ts中
注意Element-plus (opens new window)组件库默认支持 dayjs 进行日期时间处理,所以可以直接导入使用。
3.使用date-cell 的 scoped-slot 来自定义日历单元格,从而接入拖拽事件
4.使用 data.type === 'current-month'
实现只显示当月日期
5.若你的element-plus
版本使用#date-cell
不能实现自定义日历单元格,可改为#dateCell
试下
完整代码如下:
index.vue
<template>
<div class="panel-content">
<ELPlusLanguageConfig :local="local">
<el-calendar :model-value="new Date(currentMonth)">
<template #header="{ date }">
<div class="button-box">
<div class="control-list">
<el-button round size="small" @click="selectDate('prev-year')">上一年</el-button>
<el-button round size="small" @click="selectDate('prev-month')">上一月</el-button>
<el-date-picker class="date-picker" v-model="currentMonth" :value-format="valueFormat" type="month"
placeholder="选择月份" />
<el-button round size="small" @click="selectDate('next-month')">下一月</el-button>
<el-button round size="small" @click="selectDate('next-year')">下一年</el-button>
<el-button round size="small" @click="selectDate('today')">今天</el-button>
</div>
<div>
<!-- <el-button type="primary" size="small">导入</el-button> -->
</div>
</div>
</template>
<template #dateCell="{ data }">
<div :class="{ 'dayBox': true }">
<div v-if="isCurrentMonth(data)" :class="{ 'dargIn': retData.dragIn === data.day }"
@click.stop="handleClick(data)" @drop="onDrop" @dragover="$event => onDragover($event, data)">
<h1>{{ formatDay(data) }}</h1>
<!-- 删除 -->
<el-icon class="del" @click.stop="del(data)">
<Delete />
</el-icon>
</div>
</div>
</template>
</el-calendar>
</ELPlusLanguageConfig>
<div class="right-box">
<div class="d-title">选择值班人员</div>
<div class="content-box">
<div class="t-one" v-for="(item, index) in retData.people" :key="index">
<!-- 组 -->
<div class="draggable" v-if="item.type" :draggable="true" @dragstart="onDragStart(item)">
{{ item.name }}
<p><span v-for="(sub, subIndex) in item.children" :key="subIndex">{{ sub.name }}</span></p>
</div>
<!-- 未分组 -->
<div v-else>
{{ item.name }}
<p>
<span class="draggable" v-for="(sub, subIndex) in item.children" :key="subIndex" :draggable="true"
@dragstart="onDragStart(sub)">{{ sub.name }}</span>
</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import ELPlusLanguageConfig from '../components/ELPlusLanguageConfig.vue'
import { useCalendar } from '../components/myCalendar'
type calendarDateCell = { type: 'prev-month' | 'current-month' | 'next-month', isSelected: boolean, day: string, date: Date }
// 日历相关 start --------
let valueFormat = 'YYYY-MM'
const { currentMonth, selectDate, local } = useCalendar(valueFormat)
// 日期格式化显示
const formatDay = ({ day }:calendarDateCell) => {
return Number(day.split('-')[2])
}
// 判断是否是当前月
const isCurrentMonth = (data:calendarDateCell) => {
return data.type === 'current-month'
}
const handleClick = (data:calendarDateCell) => {
console.log(data, 'click')
}
// 删除
const del = (data:calendarDateCell) => {
console.log(data, 'del')
}
// 日历相关 end --------
// 拖拽相关 start -------
const retData = reactive({
people: [
{
type: 'group',
name: '组1',
children: [
{
name: '李xx'
},
{
name: '李bbb'
}
]
},
{
type: 'group',
name: '组2',
children: [
{
name: '李xx2'
},
{
name: '李xxx3'
}
]
},
{
name: '未分配人员',
children: [
{
name: '张三'
},
{
name: '李四'
}
]
}
],
dragIn: null, // 拖入的盒子,设置样式使用
dragData: {} // 拖入的数据
})
const onDragStart = (data:any) => {
console.log('onDragStart', data)
retData.dragData = data
}
const onDragover = (e:DragEvent, data:any) => {
// console.log('onDragover', e)
e.preventDefault();
retData.dragIn = data.day
}
const onDrop = (ev:DragEvent) => {
// console.log('onDrop', ev)
console.log('onDrop', retData.dragIn, retData.dragData)
retData.dragIn = null
}
// 拖拽相关 end -------
</script>
<style lang="less" scoped>
.panel-content {
background-color: #122645;
display: flex;
justify-content: space-between;
align-items: stretch;
height: 100%;
color: #ffffff;
.button-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.control-list {
display: flex;
justify-content: flex-start;
align-items: center;
button {
height: 34px;
width: 88px;
font-size: 16px;
border: none;
transition: all .3s;
}
:deep(.date-picker) {
width: 188px;
height: 40px;
margin: 0 15px;
}
}
}
.dayBox {
position: relative;
height: 100%;
width: 100%;
font-size: 30px;
font-family: MicrosoftYaHei-Bold-, MicrosoftYaHei-Bold;
cursor: default;
>div {
height: 100%;
}
h1 {
padding: 10px 16px 0 16px;
font-size: 30px;
margin: 0;
}
.del {
cursor: pointer;
position: absolute;
bottom: 9px;
right: 9px;
font-size: 16px;
&:hover {
color: #0d84ff;
}
}
}
.right-box {
width: 729px;
flex: none;
background-color: rgba(45, 103, 254, 0.12);
margin-top: 64px;
.d-title {
background-color: #1C4294;
font-size: 18px;
padding: 16px 38px;
}
@PADDING: 15px;
.content-box {
padding: 0 (38px - @PADDING);
overflow-y: auto;
box-sizing: border-box;
max-height: calc(100vh - 300px);
;
}
.t-one {
margin-top: 44px - 2*@PADDING;
&:first-child {
margin-top: 44px - @PADDING;
}
>div {
padding: @PADDING;
}
p {
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
flex-direction: row;
margin: 0;
}
span {
background-color: #122645;
width: 138px;
height: 40px;
line-height: 40px;
padding: 0 16px;
border: 1px solid #196BD1;
margin-right: 13px;
margin-top: 17px;
}
}
}
}
.draggable {
cursor: move;
&:hover {
outline: 1px dashed #196BD1;
box-shadow: 0px 0px 20px 1px rgb(25, 107, 209,0.5);
}
}
.dargIn {
outline: 1px dashed #196BD1;
}
</style>
<!-- 全局样式 -->
<style lang="less">
@themeColor:#ffffff;
.el-calendar {
background-color: transparent;
.el-calendar__header {
margin-bottom: 0;
padding-bottom: 0;
}
.el-calendar__body {
padding-top: 5px;
padding-bottom: 0;
}
.el-calendar-day {
padding: 0;
// border: 1px solid #b4bbc5;
border-radius: 4px;
height: 126px;
background-color: #081827;
}
// 其他月隐藏
// .el-calendar-table:not(.is-range) td.prev,
// .el-calendar-table:not(.is-range) td.next {
// color: transparent;
// }
// 顶部周一、周日
.el-calendar-table thead {
background-color: #061529;
th {
font-weight: normal;
color: @themeColor;
font-size: 18px;
padding: 10px 0;
}
}
.el-calendar-table tr td:first-child {
border-left: none;
}
.el-calendar-table tr td:last-child {
border-right: none;
}
.el-calendar-table td.is-today {
color: @themeColor;
.el-calendar-day {
background-color: rgba(45, 103, 254, 0.35);
}
}
.el-calendar-table__row:last-child {
td {
border-bottom: none;
}
}
// hover
.el-calendar-table .el-calendar-day:hover {
// .dayBox{
// background-color: rgba(102, 177, 255,0.5);
// }
}
// 选中项设置
.el-calendar-table td.is-selected {
background-color: transparent;
.el-calendar-day {
border-color: #0d84ff;
}
}
}
</style>
ELPlusLanguageConfig.vue
<!-- 给elementplus 单独设置国际化内容 -->
<template>
<el-config-provider :locale="locale">
<slot></slot>
</el-config-provider>
</template>
<script setup lang="ts">
// import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
// import en from 'element-plus/dist/locale/en.mjs'
import zhCn from 'element-plus/lib/locale/lang/zh-cn';
// import en from 'element-plus/lib/locale/lang/en';
import { merge } from 'webpack-merge';
import {reactive,watch,ref} from 'vue'
const props = defineProps({
local: { // 国际化
type: Object,
default() {
return {}
}
}
})
const locale = ref({})
watch(()=>props.local,(newVal,oldVal)=>{
locale.value = merge({}, zhCn, newVal)
},{
immediate:true
})
</script>
<style scoped></style>
myCalendar.ts
import { ref, reactive } from 'vue'
import {dayjs} from "element-plus"
/**
* 日历切换,快捷时间切换改为结合dayjs实现
* @param {*} valueFormat
* @returns
*/
export function useCalendar(valueFormat = 'YYYY-MM') {
// 修改element-plus日历文案
const local = {
el: {
datepicker: {
weeks: {
fri: "周五",
mon: "周一",
sat: "周六",
sun: "周日",
thu: "周四",
tue: "周二",
wed: "周三",
}
}
}
}
// 日期
const currentMonth = ref(dayjs(new Date()).format(valueFormat))
// 这里没有使用element-plus案例中的方式【因为没有同时生效】,这里改为自己实现快捷切换
const selectDate = (val:'prev-year'|'prev-month'|'next-month'|'next-year'|'today') => {
let ploy = {
// 上一年
'prev-year': () => {
currentMonth.value = dayjs(currentMonth.value).add(-1, 'year').format(valueFormat)
},
// 上一月
'prev-month': () => {
currentMonth.value = dayjs(currentMonth.value).add(-1, 'month').format(valueFormat)
},
// 下一月
'next-month': () => {
currentMonth.value = dayjs(currentMonth.value).add(1, 'month').format(valueFormat)
},
// 下一年
'next-year': () => {
currentMonth.value = dayjs(currentMonth.value).add(1, 'year').format(valueFormat)
},
// 今天
'today': () => {
currentMonth.value = dayjs(new Date()).format(valueFormat)
},
}
ploy[val]()
}
return {
local,
currentMonth, // 日历组件上的modelValue值,也是日期组件的-model值
selectDate // 快捷切换时间的事件
}
}
若对你有帮助,请点个赞吧,若能打赏不胜感激,谢谢支持!
本文地址:https://www.jianshu.com/p/ac88cabc0af5?v=1680746028292,转载请注明出处,谢谢。
参考:
element-plus日历组件
网友评论