|
@@ -0,0 +1,299 @@
|
|
|
+<template>
|
|
|
+ <div class="calendar">
|
|
|
+ <div class="header-wrap">
|
|
|
+ <div class="header-l">
|
|
|
+ <el-icon class="icon" color="#999999" size="11" @click="prevPeriod"><ArrowLeftBold /></el-icon>
|
|
|
+ <span class="header-text"
|
|
|
+ >{{ dateRange.start }} <span class="center-line">-</span> {{ dateRange.end }}</span
|
|
|
+ >
|
|
|
+ <el-icon class="icon" color="#999999" size="11" @click="nextPeriod"><ArrowRightBold /></el-icon>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="header-r">
|
|
|
+ <span class="line"></span>
|
|
|
+ 高温预警
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ <div class="days">
|
|
|
+ <div
|
|
|
+ class="days-item"
|
|
|
+ v-for="(day, index) in calendarDays"
|
|
|
+ :key="index"
|
|
|
+ :class="[{ activeDay: activeDay === day.date, today: day.isToday && !day.solarTerm }]"
|
|
|
+ @click="selectDate(day.date, day)"
|
|
|
+ >
|
|
|
+ <div class="day-box">
|
|
|
+ <span class="days-week">{{ day.isToday ? "今天" : `周${day.dayOfWeek}` }}</span>
|
|
|
+ <span class="days-one">{{ day.day }}</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="day.solarTerm" class="solar-term">{{ day.solarTerm }}</div>
|
|
|
+ <div v-if="day.typeName" class="type-num">{{ day.typeName.farmWorkName.length }}</div>
|
|
|
+ <!-- <div v-if="day.isHeatWarning" class="heat-warning"></div>
|
|
|
+ <div v-if="day.typeName" class="type-name">
|
|
|
+ <div class="type-text">{{ day.typeName.farmWorkName }}</div>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, computed, onDeactivated, onMounted } from "vue";
|
|
|
+// const props = defineProps({
|
|
|
+// calendarWorkList: {
|
|
|
+// type: Array,
|
|
|
+// required: true,
|
|
|
+// },
|
|
|
+// });
|
|
|
+
|
|
|
+const today = new Date();
|
|
|
+// const startDate = ref(getAlignedStartDate(today));
|
|
|
+const startDate = ref(new Date(today));
|
|
|
+console.log('startDate', startDate);
|
|
|
+// 定义星期几的名称
|
|
|
+const weekdays = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
|
|
|
+const weekdaysShort = ["一", "二", "三", "四", "五", "六", "日"];
|
|
|
+
|
|
|
+const days = computed(() => {
|
|
|
+ return Array.from({ length: 7 }, (_, i) => {
|
|
|
+ const date = new Date(startDate.value);
|
|
|
+ date.setDate(startDate.value.getDate() + i);
|
|
|
+ return date;
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+const calendarDays = computed(() => {
|
|
|
+ const daysList = [];
|
|
|
+ for (let i = 0; i < days.value.length; i++) {
|
|
|
+ const date = days.value[i];
|
|
|
+ const dayOfWeek = date.getDay(); // 0是周日,1是周一,...,6是周六
|
|
|
+ // 调整显示:周一显示为"一",周二显示为"二",...,周日显示为"日"
|
|
|
+ const displayDayOfWeek = dayOfWeek === 0 ? "日" : weekdaysShort[dayOfWeek - 1];
|
|
|
+
|
|
|
+ daysList.push({
|
|
|
+ day: date.getDate(),
|
|
|
+ date: formatDate(date),
|
|
|
+ isToday: formatDate(date) === formatDate(today),
|
|
|
+ dayOfWeek: displayDayOfWeek,
|
|
|
+ // 模拟数据 - 在实际应用中可以从props中获取
|
|
|
+ solarTerm: i === 3 ? "白露" : null,
|
|
|
+ isHeatWarning: i === 5,
|
|
|
+ typeName:
|
|
|
+ i === 2
|
|
|
+ ? { farmWorkType: 2, farmWorkName: "播种" }
|
|
|
+ : i === 4
|
|
|
+ ? { farmWorkType: 1, farmWorkName: "施肥" }
|
|
|
+ : i === 6
|
|
|
+ ? { farmWorkType: 3, farmWorkName: "收割" }
|
|
|
+ : null,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return daysList;
|
|
|
+});
|
|
|
+
|
|
|
+const dateRange = computed(() => {
|
|
|
+ let start = calendarDays.value[0].date;
|
|
|
+ start = start.replace(/-/g, ".");
|
|
|
+ let end = calendarDays.value[6].date;
|
|
|
+ end = end.replace(/^\d{4}-(\d{2})-(\d{2})$/, "$1.$2");
|
|
|
+ return { start, end };
|
|
|
+});
|
|
|
+
|
|
|
+function getAlignedStartDate(referenceDate) {
|
|
|
+ const start = new Date(referenceDate);
|
|
|
+ const dayOfWeek = start.getDay();
|
|
|
+ start.setDate(start.getDate() - dayOfWeek + (dayOfWeek === 0 ? -13 : 1)); // 对齐至周一,确保21天周期合理
|
|
|
+ return start;
|
|
|
+}
|
|
|
+
|
|
|
+function formatDate(date) {
|
|
|
+ // String(currentMonth.value).padStart(2, "0")
|
|
|
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(
|
|
|
+ 2,
|
|
|
+ "0"
|
|
|
+ )}`;
|
|
|
+}
|
|
|
+
|
|
|
+function prevPeriod() {
|
|
|
+ startDate.value.setDate(startDate.value.getDate() - 7);
|
|
|
+ startDate.value = new Date(startDate.value);
|
|
|
+}
|
|
|
+
|
|
|
+function nextPeriod() {
|
|
|
+ startDate.value.setDate(startDate.value.getDate() + 7);
|
|
|
+ startDate.value = new Date(startDate.value);
|
|
|
+}
|
|
|
+
|
|
|
+const activeDay = ref(null);
|
|
|
+const selectDate = (date, day) => {
|
|
|
+ activeDay.value = date;
|
|
|
+ selectedDate.value = `${date} (${day.dayOfWeek})`;
|
|
|
+};
|
|
|
+
|
|
|
+// 初始化时选择今天
|
|
|
+onMounted(() => {
|
|
|
+ selectDate(formatDate(today), {
|
|
|
+ day: today.getDate(),
|
|
|
+ dayOfWeek: weekdaysShort[today.getDay() === 0 ? 6 : today.getDay() - 1],
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+function closeDialog() {
|
|
|
+ activeDay.value = null;
|
|
|
+}
|
|
|
+const selectedDate = ref(null);
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.calendar {
|
|
|
+ width: 100%;
|
|
|
+ text-align: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ .header-wrap {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ .header-l {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ width: 100%;
|
|
|
+ .header-text {
|
|
|
+ color: #000;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ .center-line {
|
|
|
+ position: relative;
|
|
|
+ top: -3px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .icon {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ background: #F2F3F5;
|
|
|
+ border-radius: 50%;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 20px;
|
|
|
+ margin-left: 6px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .header-r {
|
|
|
+ background: rgba(252, 138, 44, 0.12);
|
|
|
+ padding: 6px 10px;
|
|
|
+ border-radius: 28px;
|
|
|
+ color: #fc8a2c;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 10px;
|
|
|
+ .line {
|
|
|
+ width: 12px;
|
|
|
+ height: 1px;
|
|
|
+ margin-right: 5px;
|
|
|
+ background: #fc8a2c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.weekdays {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(7, 1fr);
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+.days {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(7, 1fr);
|
|
|
+ // gap: 5px;
|
|
|
+ font-size: 12px;
|
|
|
+ .days-item + .days-item {
|
|
|
+ margin-left: 6px;
|
|
|
+ }
|
|
|
+ .days-item {
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+ &.today {
|
|
|
+ .day-box {
|
|
|
+ color: #2199f8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &.activeDay {
|
|
|
+ .day-box {
|
|
|
+ color: #fff;
|
|
|
+ background: linear-gradient(136deg, #9fd5ff, #2199f8);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .day-box {
|
|
|
+ background: #ffffff;
|
|
|
+ color: #000;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 7px 0;
|
|
|
+ position: relative;
|
|
|
+ .days-week {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .solar-term {
|
|
|
+ padding-top: 3px;
|
|
|
+ color: #8D8D8D;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+ .type-num {
|
|
|
+ position: absolute;
|
|
|
+ top: -5px;
|
|
|
+ right: -5px;
|
|
|
+ color: #fff;
|
|
|
+ font-size: 10px;
|
|
|
+ background: #2199F8;
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+ .days-one {
|
|
|
+ text-align: center;
|
|
|
+ display: block;
|
|
|
+ margin: 0 auto;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ padding-top: 2px;
|
|
|
+ // width: 32px;
|
|
|
+ // height: 32px;
|
|
|
+ // line-height: 32px;
|
|
|
+ // border-radius: 50%;
|
|
|
+ }
|
|
|
+ .type-name {
|
|
|
+ font-size: 10px;
|
|
|
+ position: relative;
|
|
|
+ top: -4px;
|
|
|
+ border-radius: 12px;
|
|
|
+ position: relative;
|
|
|
+ background: #fff;
|
|
|
+ padding-top: 2px;
|
|
|
+ .type-text {
|
|
|
+ border-radius: 12px;
|
|
|
+ padding: 2px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.today {
|
|
|
+ position: relative;
|
|
|
+ &::after {
|
|
|
+ content: "";
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ margin: 0 auto;
|
|
|
+ width: 10px;
|
|
|
+ height: 10px;
|
|
|
+ background: url("@/assets/img/home/today.png") no-repeat center center / 100% 100%;
|
|
|
+ }
|
|
|
+ &.no-type {
|
|
|
+ &::after {
|
|
|
+ bottom: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|