文章目录
需求
使用 ElementPlus中的 Calendar 组件完成自定义渲染
分析
1. 英文改为中文
转为中文的方式:用 ElementPlus的日历组件如何改为中文
2. 修改样式
- 附源码
javascript
<template>
<el-calendar>
<template #date-cell="{ data }">
<el-row :class="data.isSelected ? 'is-selected' : 'sds'">
{{ data.day.split('-').slice(1).join('-') }}
{{ data.isSelected ? '✔️' : '' }}
</el-row>
<div v-for="(item, index) in textContent(data.day)" :key="index">
<e-row>
<el-col class="center">
<el-tag type="warning" class="tag">
<el-row v-if="item.xianyue == 0">
<el-col :span="17" class="tag">
<span>当日限约</span>
</el-col>
<el-col :span="1"></el-col>
<el-col :span="6" class="tag2">
<span>0</span>
</el-col>
</el-row>
<el-row v-else>
<el-col :span="17" class="tag">
<span>当日限约</span>
</el-col>
<el-col :span="1"></el-col>
<el-col :span="6" class="tag2">
<span>{{ item.xianyue }}</span>
</el-col>
</el-row>
</el-tag>
</el-col>
</e-row>
<el-row
style="margin-top: 10px"
class="yuyue"
v-if="item.yiyue && item.sy == 0"
>
<el-col :span="11" class="center">
<span>已约</span
><span class="center2" style="">0</span></el-col
>
<el-col :span="2" class="center">|</el-col>
<el-col :span="11" class="center">
<span>剩余</span><span class="center2">0</span></el-col
>
</el-row>
<el-row style="margin-top: 10px" class="yuyue" v-else>
<el-col :span="11" class="center">
<span>已约</span
><span class="center2" style="">{{
item.yiyue
}}</span></el-col
>
<el-col :span="2" class="center">|</el-col>
<el-col :span="11" class="center">
<span>剩余</span
><span class="center2">{{ item.sy }}</span></el-col
>
</el-row>
</div>
</template>
</el-calendar>
</template>
<style>
.is-selected {
color: #1989fa;
}
</style>
<style scoped >
:deep .el-calendar__body {
padding: 4px 20px 35px;
}
:deep .el-calendar-table thead th {
color: #ffab11;
font-weight: bold;
font-size: 25px;
}
.tag {
display: flex;
align-items: center;
height: 2.5vh;
justify-content: center;
}
.tag2 {
display: flex;
align-items: center;
height: 2.5vh;
justify-content: center;
font-size: 18px;
}
.aaa .is-selected .yuyue {
color: #ffab11;
}
.aaa .datastyle {
display: flex;
justify-content: center;
align-items: center;
font-size: 3rem;
color: #353636;
font-weight: 600;
}
:deep .el-calendar-table .el-calendar-day:hover {
background-color: #faecd8;
}
:deep .el-calendar {
--el-calendar-selected-bg-color: #faecd8;
}
.aaa .is-selected .datastyle {
color: #ffab11;
}
.aaa .prev .datastyle {
color: #c4c5c8;
}
.aaa .next .datastyle {
color: #c4c5c8;
}
:deep .el-calendar {
--el-calendar-cell-width: 130px;
}
.center {
display: flex;
justify-content: center;
align-items: center;
}
.center2 {
display: flex;
justify-content: center;
align-items: center;
color: #ffab11;
margin-left: 5px;
font-size: 20px;
}
:deep .el-calendar__header {
justify-content: center;
}
</style>
<script setup lang="ts">
import { ref, reactive, toRefs, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
const state = reactive({
tableData: [],
//测试数据
calendarData: [
{
day: "2022-11-04",
xianyue: 400,
yiyue: 5,
sy: 1,
},
{
day: "2022-11-05",
xianyue: 500,
yiyue: 5,
sy: 1,
},
{
day: "2022-11-06",
xianyue: 200,
yiyue: 5,
sy: 1,
},
{
day: "2022-11-07",
xianyue: 0,
yiyue: 0,
sy: 0,
},
],
});
//处理日期获取后台数据动态渲染上去
const textContent = (date) => {
//当前date是拿到上面日历组件当前的日期值 根据该值去筛选测试数据找到对应各个日期下对应的数据return出去
console.log(date, 1111);
return state.calendarData.filter((item) => {
return date === item.day;
});
};
</script>
3. 自定义头部
javascript
<el-calendar v-model="value" ref="calendar">
<template #header="{ date }">
<el-button-group>
<el-button size="small" @click="selectDate('prev-year')">
上一年
</el-button>
<el-button size="small" @click="selectDate('prev-month')">
上个月
</el-button>
</el-button-group>
<span>{{ date }}</span>
<el-button-group>
<el-button size="small" @click="selectDate('today')">今天</el-button>
<el-button size="small" @click="selectDate('next-month')">
下个月
</el-button>
<el-button size="small" @click="selectDate('next-year')">
下一年
</el-button>
</el-button-group>
</template>
<el-calendar/>
const value = ref(new Date());
const dateList = ref([])
const calendar = ref();
const selectDate = (val) => {
dateList.value.length = 0
calendar.value.selectDate(val);
};
function handleMonthChange(date) {
dateList.value.push(date)
// date 是切换后的日期,根据这个日期来计算开始日期和结束日期
// const year = date.getFullYear();
// const month = date.getMonth();
// const startDate = new Date(year, month, 1); // 开始日期
// const endDate = new Date(year, month + 1, 1); // 结束日期
//根据开始日期和结束日期来查询数据,然后更新视图
// ...
}
4. 增删改功能接入
javascript
<template>
<div class="container my-container">
<a-card :bordered="false" :style="{ width: '100%' }">
<el-calendar v-model="value" ref="calendar">
<template #header="{ date }">
<el-button-group>
<el-button size="small" @click="selectDate('prev-year')">
上一年
</el-button>
<el-button size="small" @click="selectDate('prev-month')">
上个月
</el-button>
</el-button-group>
<span>{{ date }}</span>
<el-button-group>
<el-button size="small" @click="selectDate('today')">今天</el-button>
<el-button size="small" @click="selectDate('next-month')">
下个月
</el-button>
<el-button size="small" @click="selectDate('next-year')">
下一年
</el-button>
</el-button-group>
</template>
<template #date-cell="{ data }">
<div class="calendar-day">
<div :class="data.isSelected ? 'is-selected' : ''">
{{ data.day.split('-').slice(1).join('-') }}
</div>
{{ handleMonthChange(data.day) }}
<p class="duty-text">
值班人员:
<span v-for="item in tableData" :key="item.id">
<span v-if="item.dutyDate == data.day">
{{ item.dutyUser }}
</span>
</span>
<div>
<a-button size="mini" type="text" @click="handleEdit(data)"
style="color: #58a7fe;">编辑</a-button>
<a-popconfirm content="确定要删除" @ok="handleDelete(data)">
<a-button size="mini" type="text" style="color: #58a7fe;">删除</a-button>
</a-popconfirm>
</div>
</p>
</div>
</template>
</el-calendar>
</a-card>
<a-modal v-model:visible="visible" :title="title" draggable :on-before-ok="handleOk" :mask-closable="false">
<a-form ref="formRef" :model="editForm" :label-col-props="{ span: 5 }" :wrapper-col-props="{ span: 16 }">
<a-form-item field="deptId" label="部门:">
<el-cascader v-model="editForm.deptId" style="min-width: 350px;" ref="cas"
:options="typeList.deptList" :props="props" clearable collapse-tags @change="cascaderChange"
placeholder="请选择">
</el-cascader>
</a-form-item>
<a-form-item field="userId" label="值班人:" :rules="[
{
required: true,
message: '请选择',
},
]">
<el-select style="min-width: 350px;" v-model="editForm.userId" placeholder="请选择">
<el-option v-for="(item, index) in typeList.userList" :key="index" :label="item.userName"
:value="item.userId" />
</el-select>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, watch, watchEffect, defineComponent, computed } from 'vue';
import { Message } from '@arco-design/web-vue';
import {
getDutyPlanData as getInfo,
getdept,
getUser,
getUserData,
addDutyPlanData as addData,
editDutyPlaneData as editData,
deleteDutyPlanData as deleteData,
} from '@/api/common-management'
import { handleTree } from "@/utils/common-tools";
function findItemUser(data) {
const currentObj = typeList.value.userLists.find(item => {
return item.user_id == data
})
if (currentObj) {
return currentObj.user_name
}
}
const value = ref(new Date());
// 编辑
const resetEditForm = () => {
return {
deptId: null,
userId: null
}
}
const editForm = ref(resetEditForm())
const visible = ref(false)
const title = ref('')
// 编辑
function handleEdit(val) {
editForm.value = resetEditForm()
getInfo({ dutyDate: val.day }).then(res => {
if (res.rows.length) {
editForm.value = res.rows[0]
title.value = '编辑'
} else {
editForm.value.dutyDate = val.day
title.value = '添加'
}
})
visible.value = true
}
const formRef = ref()
const handleOk = async () => {
const res = await formRef.value?.validate();
if (!res) {
if (title.value == '编辑') {
const tempData = {
dutyDate: editForm.value.dutyDate,
dutyUserId: editForm.value.userId,
id: editForm.value.id,
dutyUser: findItemUser(editForm.value.userId)
}
editData(tempData).then(res => {
Message.success('编辑成功')
visible.value = false
})
} else {
const tempData = {
dutyDate: editForm.value.dutyDate,
dutyUserId: editForm.value.userId,
// id: editForm.value.id,
dutyUser: findItemUser(editForm.value.userId)
}
addData(tempData).then(res => {
visible.value = false
Message.success('添加成功')
})
}
getTableData({
pageNum: 1,
pageSize: dateList.value.length,
'params.beginTime': dateList.value[0],
'params.endTime': dateList.value[dateList.value.length - 1],
})
} else {
Message.error('请完整填写表单信息')
return false
}
};
// 删除
function handleDelete(val) {
getInfo({ dutyDate: val.day }).then(res => {
if (res?.rows[0]?.id) {
deleteData(res.rows[0].id).then(res => {
Message.success('删除成功')
getTableData({
pageNum: 1,
pageSize: dateList.value.length,
'params.beginTime': dateList.value[0],
'params.endTime': dateList.value[dateList.value.length - 1],
})
})
}
})
}
const dateList = ref([])// 存放当前页所获取的所有日期
const calendar = ref();
const selectDate = (val) => {
dateList.value.length = 0
calendar.value.selectDate(val);
};
function handleMonthChange(date) {
dateList.value.push(date)
}
const watchObj = computed(() => {
return dateList.value[0]
})
watch(watchObj, (val) => {
if (val) {
const tempData = {
pageNum: 1,
pageSize: dateList.value.length,
'params.beginTime': dateList.value[0],
'params.endTime': dateList.value[dateList.value.length - 1],
}
getTableData(tempData)
}
})
// 获取页面信息
const tableData = ref([])
const getTableData = (tempData) => {
getInfo(tempData).then(res => {
tableData.value = res.rows
})
}
// 获取类型信息
const typeList = ref({
deptList: [],
userList: [],
userLists: []
})
// 树选择器
const props = {
expandTrigger: 'hover',
label: "deptName",
checkStrictly: true,
value: "deptId",
}
function getTypeList() {
getdept().then(res => {
const temp = JSON.parse(JSON.stringify(res.data))
typeList.value.deptList = handleTree(res.data, "deptId")
})
getUserData().then(res => {
typeList.value.userLists = res.data
})
}
const cas = ref()
function cascaderChange(data, id) {
let nodes = cas.value.getCheckedNodes()
getUser({ deptId: nodes[0].value }).then(res => {
typeList.value.userList = res.rows
})
}
const fetchData = () => {
getTypeList()
}
onMounted(() => {
fetchData()
});
</script>
<style scoped lang="less">
.wrapper {
padding-top: 10px;
}
.duty-text {
text-align: center;
color: #939fb6;
font-size: large;
}
.is-selected {
color: #1989fa;
}
</style>