|
@@ -0,0 +1,219 @@
|
|
|
+<!--
|
|
|
+* @FileDescription: 日历
|
|
|
+* @Author: 黄琪勇
|
|
|
+* @Date:2024-03-28 19:43:30
|
|
|
+-->
|
|
|
+<template>
|
|
|
+ <el-calendar ref="calendarDom" :class="{ isNowMonth: isNowMonth }" class="h-calendar" v-model="dateData" v-bind="$attrs">
|
|
|
+ <template #header="{ date }">
|
|
|
+ <div class="calendarHead">
|
|
|
+ <div class="tit">{{ date }}</div>
|
|
|
+ <div class="operate">
|
|
|
+ <div class="left" @click="selectDate('prev-month')"></div>
|
|
|
+ <div class="mid" @click="selectDate('today')"></div>
|
|
|
+ <div class="right" @click="selectDate('next-month')"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #date-cell="{ data }">
|
|
|
+ <div class="dayCon" @click.stop>
|
|
|
+ <div v-if="data.type === 'current-month'" class="dayBox" @click.stop="handleClickDate(data)">
|
|
|
+ <div class="daytit">
|
|
|
+ {{ format() === data.day ? "今" : format(data.day, "d") }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-else class="nobg"></div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-calendar>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { format } from "@/libs/tools"
|
|
|
+import { ref, computed } from "vue"
|
|
|
+import type { CalendarDateType, CalendarInstance } from "element-plus"
|
|
|
+import { useLocale } from "element-plus"
|
|
|
+import dayjs from "dayjs"
|
|
|
+
|
|
|
+const props = defineProps<{
|
|
|
+ modelValue: Date
|
|
|
+}>()
|
|
|
+const emits = defineEmits<{
|
|
|
+ (e: "update:modelValue", value: Date): void
|
|
|
+}>()
|
|
|
+
|
|
|
+const isNowMonth = computed(() => {
|
|
|
+ return dateData.value.getMonth() === props.modelValue.getMonth() && dateData.value.getFullYear() === props.modelValue.getFullYear()
|
|
|
+})
|
|
|
+
|
|
|
+const { lang } = useLocale()
|
|
|
+const dateData = ref(props.modelValue)
|
|
|
+
|
|
|
+const calendarDom = ref<CalendarInstance>()
|
|
|
+const selectDate = (val: CalendarDateType) => {
|
|
|
+ calendarDom.value?.selectDate(val)
|
|
|
+ if (val == "today") {
|
|
|
+ emits("update:modelValue", dateData.value)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function handleClickDate(data: { type: "prev-month" | "current-month" | "next-month"; isSelected: boolean; day: string; date: Date }) {
|
|
|
+ calendarDom.value?.pickDay(dayjs(data.date).locale(lang.value))
|
|
|
+ emits("update:modelValue", dateData.value)
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.h-calendar.el-calendar {
|
|
|
+ --el-calendar-cell-width: 70px;
|
|
|
+ background-color: #fff;
|
|
|
+ .el-calendar__body {
|
|
|
+ padding: 0;
|
|
|
+ }
|
|
|
+ /* 头部 */
|
|
|
+ .el-calendar__header {
|
|
|
+ padding: initial;
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+ .el-calendar-table thead th {
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 24px;
|
|
|
+ color: #777777;
|
|
|
+ padding: 32px 0 18px 0;
|
|
|
+ }
|
|
|
+ .calendarHead {
|
|
|
+ width: 100%;
|
|
|
+ height: 42px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ .tit {
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 30px;
|
|
|
+ color: #333333;
|
|
|
+ }
|
|
|
+ .operate {
|
|
|
+ display: flex;
|
|
|
+ & > div {
|
|
|
+ cursor: pointer;
|
|
|
+ width: 38px;
|
|
|
+ height: 38px;
|
|
|
+ }
|
|
|
+ .left {
|
|
|
+ background: url("./img//left1.png") no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ &:hover {
|
|
|
+ background-image: url("./img//left.png");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .mid {
|
|
|
+ margin: 0 28px;
|
|
|
+ background: url("./img//mid.png") no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ &:hover {
|
|
|
+ opacity: $opacity-hover;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .right {
|
|
|
+ background: url("./img//right1.png") no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ &:hover {
|
|
|
+ background-image: url("./img//right.png");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 内容 */
|
|
|
+ .el-calendar-table td {
|
|
|
+ border: none;
|
|
|
+ &.is-today {
|
|
|
+ color: initial;
|
|
|
+ }
|
|
|
+ &.is-selected {
|
|
|
+ background-color: initial;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .el-calendar-table .el-calendar-day {
|
|
|
+ height: initial;
|
|
|
+ padding: 0;
|
|
|
+ &:hover {
|
|
|
+ cursor: initial;
|
|
|
+ background-color: initial;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .el-calendar-table tr td:first-child .el-calendar-day .dayCon {
|
|
|
+ padding-left: 6px;
|
|
|
+ }
|
|
|
+ .el-calendar-table tr td:last-child .el-calendar-day .dayCon {
|
|
|
+ padding-right: 6px;
|
|
|
+ }
|
|
|
+ .el-calendar-table tr:last-child td .el-calendar-day .dayCon {
|
|
|
+ padding-bottom: 0px;
|
|
|
+ }
|
|
|
+ .el-calendar-table td {
|
|
|
+ .el-calendar-day .dayCon {
|
|
|
+ padding: 0 12px 12px 0;
|
|
|
+ .dayBox {
|
|
|
+ cursor: pointer;
|
|
|
+ background: #f8f8f8;
|
|
|
+ border-radius: 7px;
|
|
|
+ height: var(--el-calendar-cell-width);
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ color: #333333;
|
|
|
+ font-family: DINAlternate, DINAlternate;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 32px;
|
|
|
+ &:hover {
|
|
|
+ background: #fff7ed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .nobg {
|
|
|
+ height: var(--el-calendar-cell-width);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.is-today .el-calendar-day .dayCon .dayBox {
|
|
|
+ background-image: url("./img//jiao.png");
|
|
|
+ background-size: 100% 100%;
|
|
|
+ background-color: #fff7ed;
|
|
|
+ .daytit {
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 28px;
|
|
|
+ position: relative;
|
|
|
+ &::after {
|
|
|
+ content: "";
|
|
|
+ position: absolute;
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ border-radius: 50%;
|
|
|
+ bottom: -14px;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ background-color: #ff8057;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.isNowMonth .el-calendar-table td.is-selected .el-calendar-day .dayCon .dayBox {
|
|
|
+ background: linear-gradient(45deg, #ffa357 0%, #ff6736 100%), #fff7ed;
|
|
|
+ color: #ffffff;
|
|
|
+ .daytit {
|
|
|
+ font-weight: 600;
|
|
|
+ font-size: 28px;
|
|
|
+ position: relative;
|
|
|
+ &::after {
|
|
|
+ content: "";
|
|
|
+ position: absolute;
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ border-radius: 50%;
|
|
|
+ bottom: -14px;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
+ background-color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|