封装日期选择组件
This commit is contained in:
parent
2cbcc62ec2
commit
ddd5ab1ed5
|
@ -0,0 +1,661 @@
|
|||
<template>
|
||||
<div class="diy-calendar-wrapper">
|
||||
<div class="calendar-header">
|
||||
<!-- 左箭头 -->
|
||||
<div class="left-arrow" @click="jumpMonth(-1)">
|
||||
<svg width="30" height="30">
|
||||
<path d="M 19,9 L 11,15 18,21" stroke="rgba(95,147,238,0.9)" fill="none" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
<!-- 年月标题 -->
|
||||
<div class="center-title">{{ targetDateFormat }}</div>
|
||||
<!-- 右箭头 -->
|
||||
<div class="right-arrow" @click="jumpMonth(1)">
|
||||
<svg width="30" height="30">
|
||||
<path d="M 11,9 L 18,15 11,21" stroke="rgba(95,147,238,0.9)" fill="none" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 日历主体 -->
|
||||
<table class="diy-calendar-table">
|
||||
<!-- 星期栏 -->
|
||||
<thead>
|
||||
<tr class="table-header-row">
|
||||
<th v-for="day in dayNameList" :key="day.chineseShortName" class="table-header">
|
||||
{{ day.chineseFullName }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!-- 日期部分 -->
|
||||
<tbody>
|
||||
<tr class="table-body-row" v-for="(row, index) in calendarData" :key="index">
|
||||
<td v-for="col in row" class="table-data" :data-date="col.dateNumber"
|
||||
:key="`${col.dateObj.getMonth()}-${col.dateNumber}`">
|
||||
<div class="td-content-box">
|
||||
<div class="content-border" :class="{ selected: isSelectedDate(col) }"
|
||||
@click="checkoutTargetDate(col)">
|
||||
<div class="date-number" :class="{ current: isCurrentMonth(col) }">
|
||||
{{ col.dateNumber }}
|
||||
</div>
|
||||
<!--<div class="the-tradition-chinese-calendar">
|
||||
{{ col.dateObj }}
|
||||
</div>-->
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, computed, watch } from "vue";
|
||||
import dayjs from "dayjs"
|
||||
const props = defineProps({
|
||||
modelValue: Date,
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
|
||||
/**
|
||||
* 最小年份
|
||||
*/
|
||||
const MIN_YEAR = 1900;
|
||||
/**
|
||||
* 最大年份
|
||||
*/
|
||||
const MAX_YEAR = 9999;
|
||||
|
||||
/**
|
||||
* 目标日期
|
||||
* @type {Ref<Date>}
|
||||
*/
|
||||
const targetDate = ref(props.modelValue);
|
||||
|
||||
/**
|
||||
* 有关月度的名称列表
|
||||
*/
|
||||
const monthNameList = {
|
||||
chineseFullName: [
|
||||
"一月",
|
||||
"二月",
|
||||
"三月",
|
||||
"四月",
|
||||
"五月",
|
||||
"六月",
|
||||
"七月",
|
||||
"八月",
|
||||
"九月",
|
||||
"十月",
|
||||
"十一月",
|
||||
"十二月",
|
||||
],
|
||||
fullName: [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
],
|
||||
mmm: [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
],
|
||||
};
|
||||
/**
|
||||
* 有关周几的名称列表
|
||||
*/
|
||||
const dayNameList = [
|
||||
{
|
||||
chineseFullName: "周日",
|
||||
chineseShortName: "日",
|
||||
fullName: "Sunday",
|
||||
shortName: "Sun",
|
||||
dayNumber: 0,
|
||||
},
|
||||
{
|
||||
chineseFullName: "周一",
|
||||
chineseShortName: "一",
|
||||
fullName: "Monday",
|
||||
shortName: "Mon",
|
||||
dayNumber: 1,
|
||||
},
|
||||
{
|
||||
chineseFullName: "周二",
|
||||
chineseShortName: "二",
|
||||
fullName: "Tuesday",
|
||||
shortName: "Tue",
|
||||
dayNumber: 2,
|
||||
},
|
||||
{
|
||||
chineseFullName: "周三",
|
||||
chineseShortName: "三",
|
||||
fullName: "Wednesday",
|
||||
shortName: "Wed",
|
||||
dayNumber: 3,
|
||||
},
|
||||
{
|
||||
chineseFullName: "周四",
|
||||
chineseShortName: "四",
|
||||
fullName: "Thursday",
|
||||
shortName: "Thu",
|
||||
dayNumber: 4,
|
||||
},
|
||||
{
|
||||
chineseFullName: "周五",
|
||||
chineseShortName: "五",
|
||||
fullName: "Friday",
|
||||
shortName: "Fri",
|
||||
dayNumber: 5,
|
||||
},
|
||||
{
|
||||
chineseFullName: "周六",
|
||||
chineseShortName: "六",
|
||||
fullName: "Saturday",
|
||||
shortName: "Sat",
|
||||
dayNumber: 6,
|
||||
},
|
||||
];
|
||||
/**
|
||||
* 今日
|
||||
*/
|
||||
const today = new Date();
|
||||
|
||||
/**
|
||||
* 日历的各项属性
|
||||
*/
|
||||
const calendarProps = reactive({
|
||||
target: {
|
||||
year: null,
|
||||
month: null,
|
||||
date: null,
|
||||
day: null,
|
||||
monthShortName: null,
|
||||
monthFullName: null,
|
||||
monthChineseFullName: null,
|
||||
firstDay: null,
|
||||
firstDayIndex: null,
|
||||
totalDays: null,
|
||||
},
|
||||
previous: {
|
||||
totalDays: null,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 用于展现的日历数据
|
||||
*/
|
||||
const calendarData = ref([]);
|
||||
|
||||
initCalendar();
|
||||
|
||||
/**
|
||||
* 初始化日历数据
|
||||
*/
|
||||
function initCalendar() {
|
||||
setCalendarProps();
|
||||
setCalendarData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置日历的各个属性,比如当前年月日,本月一共多少天,上个月一共多少天等等
|
||||
*/
|
||||
function setCalendarProps() {
|
||||
if (!targetDate.value) {
|
||||
targetDate.value = today;
|
||||
}
|
||||
// 获取目标日期的年月日星期几数据
|
||||
calendarProps.target.year = targetDate.value.getFullYear();
|
||||
calendarProps.target.month = targetDate.value.getMonth();
|
||||
calendarProps.target.date = targetDate.value.getDate();
|
||||
calendarProps.target.day = targetDate.value.getDay();
|
||||
|
||||
if (
|
||||
calendarProps.target.year < MIN_YEAR ||
|
||||
calendarProps.target.year > MAX_YEAR
|
||||
) {
|
||||
console.error("无效的年份,请检查传入的数据是否是正常");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取到目标日期的月份【中文】名称
|
||||
let dateString;
|
||||
dateString = targetDate.value.toString().split(" ");
|
||||
calendarProps.target.monthShortName = dateString[1];
|
||||
calendarProps.target.monthFullName =
|
||||
monthNameList.fullName[calendarProps.target.month];
|
||||
calendarProps.target.monthChineseFullName =
|
||||
monthNameList.chineseFullName[calendarProps.target.month];
|
||||
// 获取目标月份的第一天是星期几,和在星期几中的索引值
|
||||
const targetMonthFirstDay = new Date(
|
||||
calendarProps.target.year,
|
||||
calendarProps.target.month,
|
||||
1
|
||||
);
|
||||
calendarProps.target.firstDay = targetMonthFirstDay.getDay();
|
||||
calendarProps.target.firstDayIndex = dayNameList.findIndex(
|
||||
(day) => day.dayNumber === calendarProps.target.firstDay
|
||||
);
|
||||
|
||||
// 获取目标月份总共多少天
|
||||
const targetMonthLastDay = new Date(
|
||||
calendarProps.target.year,
|
||||
calendarProps.target.month + 1,
|
||||
0
|
||||
);
|
||||
calendarProps.target.totalDays = targetMonthLastDay.getDate();
|
||||
|
||||
// 获取目标月份的上个月总共多少天
|
||||
const previousMonth = new Date(
|
||||
calendarProps.target.year,
|
||||
calendarProps.target.month,
|
||||
0
|
||||
);
|
||||
calendarProps.previous.totalDays = previousMonth.getDate();
|
||||
|
||||
console.log('calendarProps:', calendarProps);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成日历的数据
|
||||
*/
|
||||
function setCalendarData() {
|
||||
let i;
|
||||
let date = 1;
|
||||
const originData = [];
|
||||
const firstRow = [];
|
||||
// 设置第一行数据
|
||||
for (i = 0; i <= 6; i++) {
|
||||
// 设置目标月份之前月份的日期数据
|
||||
if (i < calendarProps.target.firstDayIndex) {
|
||||
const previousDate =
|
||||
calendarProps.previous.totalDays -
|
||||
calendarProps.target.firstDayIndex +
|
||||
(i + 1);
|
||||
firstRow.push({
|
||||
dateObj: new Date(
|
||||
calendarProps.target.year,
|
||||
calendarProps.target.month - 1,
|
||||
previousDate
|
||||
),
|
||||
dateNumber: previousDate,
|
||||
dateType: "previous",
|
||||
});
|
||||
} else {
|
||||
// 设置目标月份当月的日期数据
|
||||
firstRow.push({
|
||||
dateObj: new Date(
|
||||
calendarProps.target.year,
|
||||
calendarProps.target.month,
|
||||
date
|
||||
),
|
||||
dateNumber: date,
|
||||
dateType: "current",
|
||||
});
|
||||
date++;
|
||||
}
|
||||
}
|
||||
originData.push(firstRow);
|
||||
// 设置后面五行的数据
|
||||
for (let j = 0; j <= 4; j++) {
|
||||
const rowData = [];
|
||||
for (let k = 0; k <= 6; k++) {
|
||||
// 设置目标月份剩下的日期数据
|
||||
if (date <= calendarProps.target.totalDays) {
|
||||
rowData.push({
|
||||
dateObj: new Date(
|
||||
calendarProps.target.year,
|
||||
calendarProps.target.month,
|
||||
date
|
||||
),
|
||||
dateNumber: date,
|
||||
dateType: "current",
|
||||
});
|
||||
} else {
|
||||
// 设置目标月份下个月的日期数据
|
||||
const nextDate = date - calendarProps.target.totalDays;
|
||||
rowData.push({
|
||||
dateObj: new Date(
|
||||
calendarProps.target.year,
|
||||
calendarProps.target.month + 1,
|
||||
nextDate
|
||||
),
|
||||
dateNumber: nextDate,
|
||||
dateType: "next",
|
||||
});
|
||||
}
|
||||
date++;
|
||||
}
|
||||
originData.push(rowData);
|
||||
}
|
||||
calendarData.value = originData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是被选中的日期
|
||||
* @param col 日期数据
|
||||
*/
|
||||
function isSelectedDate(col) {
|
||||
const colDateObj = col.dateObj;
|
||||
const colYear = colDateObj.getFullYear();
|
||||
const colMonth = colDateObj.getMonth();
|
||||
const colDate = colDateObj.getDate();
|
||||
|
||||
const targetDateYear = targetDate.value.getFullYear();
|
||||
const targetDateMonth = targetDate.value.getMonth();
|
||||
const targetDateDate = targetDate.value.getDate();
|
||||
|
||||
if (
|
||||
colYear === targetDateYear &&
|
||||
colMonth === targetDateMonth &&
|
||||
colDate === targetDateDate
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是当前月份
|
||||
* @param col 日期数据
|
||||
*/
|
||||
function isCurrentMonth(col) {
|
||||
if (col.dateType !== "current") {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换目标日期
|
||||
* @param col 日期数据
|
||||
*/
|
||||
function checkoutTargetDate(col) {
|
||||
const currentDate = col.dateObj;
|
||||
const oldDate = targetDate.value;
|
||||
// 如果本次点击的日期是当前选中的日期,则停止执行
|
||||
if (currentDate.getTime() === oldDate.getTime()) {
|
||||
return;
|
||||
}
|
||||
if (col.dateType === "current") {
|
||||
targetDate.value = col.dateObj;
|
||||
setCalendarProps();
|
||||
} else {
|
||||
targetDate.value = col.dateObj;
|
||||
initCalendar();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转月份
|
||||
* @param flag 跳转数字标识,+1,就是增加一个月,-1就是减少一个月
|
||||
*/
|
||||
function jumpMonth(flag) {
|
||||
let targetMonthNumber = calendarProps.target.month;
|
||||
let targetYear = calendarProps.target.year;
|
||||
targetDate.value = calendarProps.target.date;
|
||||
targetMonthNumber += flag;
|
||||
console.log('targetMonthNumber', calendarProps.target.month, targetMonthNumber);
|
||||
if (targetMonthNumber > 11) {
|
||||
targetYear += 1;
|
||||
targetMonthNumber = 0;
|
||||
} else if (targetMonthNumber < 0) {
|
||||
targetYear -= 1;
|
||||
targetMonthNumber = 11;
|
||||
}
|
||||
targetDate.value = new Date(targetYear, targetMonthNumber, targetDate.value);
|
||||
initCalendar();
|
||||
}
|
||||
|
||||
const targetDateFormat = computed(() => {
|
||||
const monthNumber = targetDate.value.getMonth() + 1
|
||||
let monthString = "";
|
||||
|
||||
if (monthNumber > 9) {
|
||||
monthString = monthNumber + '';
|
||||
} else {
|
||||
monthString = '0' + monthNumber;
|
||||
}
|
||||
return `${targetDate.value.getFullYear()}.${monthString}`;
|
||||
});
|
||||
|
||||
watch(targetDate, (newVal) => {
|
||||
emits("update:modelValue", newVal);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.diy-calendar-wrapper {
|
||||
width: auto;
|
||||
height: 100%;
|
||||
|
||||
.calendar-header {
|
||||
height: 54px;
|
||||
padding: 13px 20px;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
user-select: none;
|
||||
|
||||
.left-arrow,
|
||||
.right-arrow {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(215, 221, 228, 0.2);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid rgba(95, 147, 238, 0.5);
|
||||
transition: all 0.2s;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid rgba(8, 94, 243, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.center-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: Magneto;
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.diy-calendar-table {
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
border-collapse: collapse;
|
||||
|
||||
.table-header-row {
|
||||
height: 32px;
|
||||
background-color: rgba(95, 147, 238, 0.06);
|
||||
|
||||
.table-header {
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
font-family: "Lucida Handwriting";
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body-row {
|
||||
height: 75px;
|
||||
|
||||
.table-data {
|
||||
text-align: center;
|
||||
|
||||
.td-content-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.content-border {
|
||||
position: relative;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
.table-badge {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 3px;
|
||||
background-color: rgba(20, 167, 59, 0.5);
|
||||
color: #ffffff;
|
||||
font-size: 10px;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&.current {
|
||||
background-color: #14a73b;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.date-number {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
top: 20px;
|
||||
font-size: 18px;
|
||||
line-height: 20px;
|
||||
transition: all ease 0.3s;
|
||||
font-family: Magneto;
|
||||
font-weight: normal;
|
||||
// color: rgba(42, 63, 103, 0.48);
|
||||
color: #666;
|
||||
|
||||
&.current {
|
||||
// color: #435069;
|
||||
color: #cdd2d8;
|
||||
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.the-tradition-chinese-calendar {
|
||||
width: 40px;
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 34px;
|
||||
font-size: 10px;
|
||||
transition: all ease 0.2s;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
//background: #023f99;
|
||||
background: radial-gradient(#2B6CFF , #0062fb );
|
||||
border-radius: 50%;
|
||||
|
||||
.table-badge {
|
||||
background: #ffffff;
|
||||
color: #023f99;
|
||||
}
|
||||
|
||||
.date-number {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.the-tradition-chinese-calendar {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* &::before,
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 3px solid rgba(2, 63, 153, 0.5);
|
||||
border-radius: 50%;
|
||||
inset: -10px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
// animation: pathRotate1 4s linear infinite;
|
||||
}
|
||||
|
||||
&::after {
|
||||
animation: pathRotate2 4s linear infinite;
|
||||
} */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pathRotate1 {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
clip-path: inset(0 0 95% 0);
|
||||
}
|
||||
|
||||
25% {
|
||||
clip-path: inset(0 0 0 95%);
|
||||
}
|
||||
|
||||
50% {
|
||||
clip-path: inset(95% 0 0 0);
|
||||
}
|
||||
|
||||
75% {
|
||||
clip-path: inset(0 95% 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pathRotate2 {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
clip-path: inset(95% 0 0 0);
|
||||
}
|
||||
|
||||
25% {
|
||||
clip-path: inset(0 95% 0 0);
|
||||
}
|
||||
|
||||
50% {
|
||||
clip-path: inset(0 0 95% 0);
|
||||
}
|
||||
|
||||
75% {
|
||||
clip-path: inset(0 0 0 95%);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,187 @@
|
|||
<!--
|
||||
* @Author: 张宁 18339727226@163.com
|
||||
* @Date: 2024-05-27 14:46:17
|
||||
* @LastEditors: 张宁 18339727226@163.com
|
||||
* @LastEditTime: 2024-05-29 15:37:58
|
||||
* @FilePath: \welcome-system-screen\src\components\datePicker\datePicker.vue
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
-->
|
||||
<template>
|
||||
<div ref="datePickerRef" class="datePicker">
|
||||
<el-config-provider :locale="zhCn">
|
||||
<!-- Dropdown button -->
|
||||
<button @click="toggleDropdown" style="width: 100%;">
|
||||
切换日期
|
||||
</button>
|
||||
<!-- Dropdown menu -->
|
||||
<div v-if="isOpen" class="datePicker-menu">
|
||||
<div class="picker-title">
|
||||
<div class="tabs">
|
||||
<div class="title-item" v-for="(tab, index) in tabs" :key="index"
|
||||
:class="{ active: activeTab === index }" @click="changeTab(index)">
|
||||
{{ tab.content?tab.content:'' }}{{ tab.title }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="confirm-box" @click="confirmDate">确定</div>
|
||||
</div>
|
||||
<div class="picker-content" v-show="activeTab === 0">
|
||||
<yearPane v-model:curYear="myYear" />
|
||||
</div>
|
||||
<div class="picker-content" v-show="activeTab === 1">
|
||||
<monthPane v-model:curMonth="myMonth" />
|
||||
|
||||
</div>
|
||||
<div class="picker-content" v-show="activeTab === 2">
|
||||
<DayPane :curYear="myYear" :curMonth="myMonth" v-model:curDay="myDay" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-config-provider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="datePicker">
|
||||
import { ref, onMounted, onUnmounted, nextTick } from "vue";
|
||||
import { ElConfigProvider } from 'element-plus'
|
||||
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
|
||||
// Reactive variables
|
||||
const isOpen = ref(false); // Dropdown open/close state
|
||||
const datePickerRef = ref(null); // Reference to datePicker element
|
||||
const { proxy } = getCurrentInstance();
|
||||
// Toggle datePicker open/close state
|
||||
const toggleDropdown = () => {
|
||||
isOpen.value = !isOpen.value;
|
||||
};
|
||||
const myYear = ref();
|
||||
const myMonth = ref();
|
||||
const myDay = ref();
|
||||
|
||||
// tabs 切换
|
||||
const activeTab = ref(0);
|
||||
const tabs = computed(()=>{
|
||||
return [
|
||||
{ title: '年', content: myYear.value },
|
||||
{ title: '月', content: myMonth.value },
|
||||
{ title: '日', content: myDay.value },
|
||||
];
|
||||
})
|
||||
const changeTab = (index: number) => {
|
||||
activeTab.value = index;
|
||||
};
|
||||
|
||||
|
||||
// Select an option from the datePicker
|
||||
const confirmDate = () => {
|
||||
isOpen.value = false; // Close the datePicker
|
||||
// 将选择的值传递给父组件
|
||||
let dates = `${myYear.value}-${myMonth.value}-${myDay.value}`
|
||||
console.log(dates);
|
||||
proxy.$emit("getOption",dates);
|
||||
};
|
||||
|
||||
// Close datePicker when clicking outside
|
||||
const closeDropdown = (event: any) => {
|
||||
// 单独针对dataPane中的组件进行处理
|
||||
if (event.target.className === 'content-border' || event.target.className === 'date-number') {
|
||||
return
|
||||
}
|
||||
if (!datePickerRef.value.contains(event.target)) {
|
||||
isOpen.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Lifecycle hook: mounted
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
document.addEventListener("click", closeDropdown); // Listen for click events outside datePicker
|
||||
});
|
||||
});
|
||||
|
||||
// Lifecycle hook: unmounted
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener("click", closeDropdown); // Remove event listener when component is unmounted
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.datePicker {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.datePicker button {
|
||||
background: none;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
border: none;
|
||||
// cursor: pointer;
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
.datePicker-menu {
|
||||
width: 580px;
|
||||
height: 660px;
|
||||
position: absolute;
|
||||
// left: -50%;
|
||||
transform: translate(-530px, 20px);
|
||||
// background-color: #f9f9f9;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
min-width: 580px;
|
||||
max-height: 660px;
|
||||
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
|
||||
z-index: 1;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
border: 5px double #34354a;
|
||||
border-radius: 20px;
|
||||
cursor: default;
|
||||
|
||||
// padding: 10px;
|
||||
.picker-title {
|
||||
line-height: 70px;
|
||||
height: 70px;
|
||||
border-bottom: 3px solid #272b40;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
// width: 580px;
|
||||
.tabs {
|
||||
display: flex;
|
||||
|
||||
div {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.active {
|
||||
border-bottom: 3px solid #0254eb;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-box {
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background: #0254eb;
|
||||
border-radius: 20px;
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 设置滚动条的宽度 */
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,232 @@
|
|||
<!--
|
||||
* @Author: 张宁 18339727226@163.com
|
||||
* @Date: 2024-05-28 11:55:39
|
||||
* @LastEditors: 张宁 18339727226@163.com
|
||||
* @LastEditTime: 2024-05-29 15:38:56
|
||||
* @FilePath: \welcome-system-screen\src\components\datePicker\dayPane.vue
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
-->
|
||||
<template>
|
||||
<div class="box">
|
||||
<!-- 日历主体 -->
|
||||
<table class="diy-calendar-table">
|
||||
<!-- 星期栏 -->
|
||||
<thead>
|
||||
<tr class="table-header-row">
|
||||
<th v-for="day in dayNameList" class="table-header">
|
||||
{{ day }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!-- 日期部分 -->
|
||||
<tbody>
|
||||
<tr class="table-body-row" v-for="(row, index) in dayList" :key="index">
|
||||
<td v-for="col in row" class="table-data" :data-date="col">
|
||||
<div class="td-content-box">
|
||||
<div class="content-border" :class="{ selected: isSelectedDate(col) }"
|
||||
@click="selectDay(col)">
|
||||
<div :class="['date-number', {'current':col !==''}]">
|
||||
{{ col }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
curYear: Number,
|
||||
curMonth: Number,
|
||||
curDay: Number,
|
||||
});
|
||||
const selectDays:Ref<any> = ref(props.curDay);
|
||||
/**
|
||||
* @description: 获取某年某月的天数
|
||||
* @param {*} year
|
||||
* @param {*} month
|
||||
* @return {*}
|
||||
*/
|
||||
function getDaysInMonth(year: number, month: number) {
|
||||
const daysInMonth = new Date(year, month, 0).getDate();
|
||||
const firstDay = new Date(year, month - 1, 1).getDay(); // 获取本月第一天是星期几
|
||||
const weeks = Math.ceil((firstDay + daysInMonth) / 7); // 计算本月有几周
|
||||
|
||||
let date = 1;
|
||||
const result = [];
|
||||
for (let i = 0; i < weeks; i++) {
|
||||
const week = [];
|
||||
for (let j = 0; j < 7; j++) {
|
||||
if ((i === 0 && j < firstDay) || date > daysInMonth) {
|
||||
week.push('');
|
||||
} else {
|
||||
week.push(date);
|
||||
date++;
|
||||
}
|
||||
}
|
||||
result.push(week);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 用于展现的日历数据 -- 当前月
|
||||
*/
|
||||
const dayList = computed(() => {
|
||||
if (props.curYear && props.curMonth) {
|
||||
return getDaysInMonth(props.curYear, props.curMonth)
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
})
|
||||
// 选择当前时间
|
||||
const selectDay = (day: any) => {
|
||||
if (!day) {
|
||||
return
|
||||
}
|
||||
if (selectDays.value == day) {
|
||||
selectDays.value = 0
|
||||
} else {
|
||||
selectDays.value = day;
|
||||
}
|
||||
}
|
||||
const emits = defineEmits(["update:curDay"]);
|
||||
watch(selectDays, (newVal) => {
|
||||
emits("update:curDay", newVal);
|
||||
});
|
||||
/**
|
||||
* @description: 判断是否被选择
|
||||
* @param {*} day
|
||||
* @return {*}
|
||||
*/
|
||||
const isSelectedDate = (day: any) => {
|
||||
if (!day) {
|
||||
return false
|
||||
}
|
||||
return day === selectDays.value
|
||||
}
|
||||
/**
|
||||
* 有关周几的名称列表
|
||||
*/
|
||||
const dayNameList = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
</script>
|
||||
|
||||
<style scoped lang='scss'>
|
||||
.box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
.diy-calendar-table {
|
||||
width: 100%;
|
||||
user-select: none;
|
||||
border-collapse: collapse;
|
||||
|
||||
.table-header-row {
|
||||
height: 32px;
|
||||
background-color: rgba(95, 147, 238, 0.06);
|
||||
|
||||
.table-header {
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
font-family: "Lucida Handwriting";
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body-row {
|
||||
height: 75px;
|
||||
|
||||
.table-data {
|
||||
text-align: center;
|
||||
|
||||
.td-content-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.content-border {
|
||||
position: relative;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
.table-badge {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 3px;
|
||||
background-color: rgba(20, 167, 59, 0.5);
|
||||
color: #ffffff;
|
||||
font-size: 10px;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&.current {
|
||||
background-color: #14a73b;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.date-number {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
top: 20px;
|
||||
font-size: 18px;
|
||||
line-height: 20px;
|
||||
transition: all ease 0.3s;
|
||||
font-family: Magneto;
|
||||
font-weight: normal;
|
||||
// color: rgba(42, 63, 103, 0.48);
|
||||
color: #666;
|
||||
|
||||
&.current {
|
||||
// color: #435069;
|
||||
color: #cdd2d8;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.the-tradition-chinese-calendar {
|
||||
width: 40px;
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 34px;
|
||||
font-size: 10px;
|
||||
transition: all ease 0.2s;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
//background: #023f99;
|
||||
background: radial-gradient(#2B6CFF, #0062fb);
|
||||
border-radius: 50%;
|
||||
|
||||
.table-badge {
|
||||
background: #ffffff;
|
||||
color: #023f99;
|
||||
}
|
||||
|
||||
.date-number {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.the-tradition-chinese-calendar {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,81 @@
|
|||
<!--
|
||||
* @Author: 张宁 18339727226@163.com
|
||||
* @Date: 2024-05-28 11:56:59
|
||||
* @LastEditors: 张宁 18339727226@163.com
|
||||
* @LastEditTime: 2024-05-29 15:23:57
|
||||
* @FilePath: \welcome-system-screen\src\components\datePicker\monthPane.vue
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
-->
|
||||
<template>
|
||||
<div class="box">
|
||||
<div class='box-item' v-for="item, index in MonthList">
|
||||
<div class="item-num" :class="{ selected: isSelectedDate(item) }" @click="selectMonth(item)">{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
curMonth: Number,
|
||||
});
|
||||
const selectMonths:Ref<any> = ref(props.curMonth)
|
||||
const MonthList = computed(() => {
|
||||
let Months = []
|
||||
for (let i = 0; i < 12; i++) {
|
||||
Months.unshift(12 - i);
|
||||
}
|
||||
return Months;
|
||||
})
|
||||
const selectMonth = (Month: number) => {
|
||||
if(selectMonths.value === Month){
|
||||
selectMonths.value = 0
|
||||
}else{
|
||||
selectMonths.value = Month;
|
||||
}
|
||||
}
|
||||
// 更新外面的值
|
||||
const emits = defineEmits(["update:curMonth"]);
|
||||
watch(selectMonths, (newVal) => {
|
||||
emits("update:curMonth", newVal);
|
||||
});
|
||||
const isSelectedDate = (Month: any) => {
|
||||
if (Month == selectMonths.value) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang='scss'>
|
||||
.box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.box-item {
|
||||
margin-right: 10px;
|
||||
margin-top: 20px;
|
||||
width: 120px;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.item-num {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,83 @@
|
|||
<!--
|
||||
* @Author: 张宁 18339727226@163.com
|
||||
* @Date: 2024-05-28 11:55:39
|
||||
* @LastEditors: 张宁 18339727226@163.com
|
||||
* @LastEditTime: 2024-05-29 15:28:27
|
||||
* @FilePath: \welcome-system-screen\src\components\datePicker\yearPane.vue
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
-->
|
||||
<template>
|
||||
<div class="box">
|
||||
<div class='box-item' v-for="item, index in yearList" @click="selectYear(item)">
|
||||
<div :class="{ selected: isSelectedDate(item) }" class="item-num">{{ item }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
curYear: Number,
|
||||
});
|
||||
const currentYear = ref(new Date().getFullYear());
|
||||
const selectYears:Ref<any> = ref(props.curYear)
|
||||
// 获取到近六年的年份
|
||||
const yearList = computed(() => {
|
||||
let years = []
|
||||
for (let i = 0; i < 6; i++) {
|
||||
years.unshift(currentYear.value - i);
|
||||
}
|
||||
return years;
|
||||
})
|
||||
// 选择年的处理 如果点击的是当前的 就赋值为空
|
||||
const selectYear = (year: number) => {
|
||||
if (selectYears.value == year) {
|
||||
selectYears.value = 0
|
||||
} else {
|
||||
selectYears.value = year;
|
||||
}
|
||||
}
|
||||
const emits = defineEmits(["update:curYear"]);
|
||||
watch(selectYears, (newVal) => {
|
||||
emits("update:curYear", newVal);
|
||||
});
|
||||
const isSelectedDate = (year: any) => {
|
||||
if (year == selectYears.value) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang='scss'>
|
||||
.box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.box-item {
|
||||
margin-right: 10px;
|
||||
margin-top: 20px;
|
||||
width: 120px;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.item-num {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -11,7 +11,8 @@ const test = () => {
|
|||
// const returnHome = () => {
|
||||
// history.go(-1)
|
||||
// };
|
||||
const yearOptions = ref([{ label: '2024年', value: 2024 }, { label: '2023年', value: 2023 }, { label: '2022年', value: 2022 }, { label: '2021年', value: 2021 }, { label: '2020年', value: 2020 }])
|
||||
|
||||
/* const yearOptions = ref([{ label: '2024年', value: 2024 }, { label: '2023年', value: 2023 }, { label: '2022年', value: 2022 }, { label: '2021年', value: 2021 }, { label: '2020年', value: 2020 }])
|
||||
const monthOptions = ref([
|
||||
{ label: '/', value: null },
|
||||
{ label: '1月', value: 1 },
|
||||
|
@ -31,7 +32,7 @@ const monthOptions = ref([
|
|||
const getYear = (val: any) => {
|
||||
console.log(val)
|
||||
timeStore.setYears(val)
|
||||
}
|
||||
}
|
||||
// 获取选择的月
|
||||
const getMonth = (val: any) => {
|
||||
console.log(val)
|
||||
|
@ -47,6 +48,11 @@ const selectNowdays = () => {
|
|||
selectMonth.value.clearOption()
|
||||
}
|
||||
timeStore.setNowDays()
|
||||
}*/
|
||||
// 获取选择的日期(年 || 月 ||日)
|
||||
const getDate = (val:any)=>{
|
||||
console.log('获取选择的日期',val);
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -65,13 +71,15 @@ const selectNowdays = () => {
|
|||
|
||||
<div class="change-time">
|
||||
<div class="change-year">
|
||||
<DatePicker @getOption="getDate" ref="selectYear"></DatePicker>
|
||||
</div>
|
||||
<!-- <div class="change-year">
|
||||
<Dropdown :options="yearOptions" title="切换年份" @getOption="getYear" ref="selectYear"></Dropdown>
|
||||
</div>
|
||||
|
||||
<div class="change-year">
|
||||
<Dropdown :options="monthOptions" title="切换月份" @getOption="getMonth" ref="selectMonth"></Dropdown>
|
||||
</div>
|
||||
<div class="change-year" @click="selectNowdays">选择今日</div>
|
||||
<div class="change-year" @click="selectNowdays">选择今日</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -135,7 +143,8 @@ const selectNowdays = () => {
|
|||
width: 400px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
// justify-content: space-between;
|
||||
flex-direction: row-reverse;
|
||||
font-family: 'YouSheBiaoTiHei';
|
||||
font-size: 16px;
|
||||
|
||||
|
|
Loading…
Reference in New Issue