設計理念?
昨天寫了個簡單美觀的日歷簽到組件,使用的是Vue3+TypeScript,大概邏輯是先找到本月份第一天是周幾,然后開始填充月份日期:weeksArray:[[]]:之后渲染到表格中,對于簽到事件觸發則先判斷是否是今天且還未沒有簽到,沒有就發送請求給后端的接口,然后簽到就完成了。
設計UI
代碼
詳情請看俺滴代碼:
<template><div class="calendar"><h1>{{ month }}月每日簽到</h1><p>您已經簽到了<em>{{ signedDates.length }}</em>天,<span v-show="!isTodaySigned">今天還沒簽到哦!</span><span v-show="isTodaySigned">今日已經簽到!</span></p><a-divider style="margin-top: 0" /><table><thead><tr><th v-for="weekday in weekdays" :key="weekday">{{ weekday }}</th></tr></thead><tbody><tr v-for="week in weeks" :key="week"><tdv-for="day in week":key="day":class="{ today: isToday(day), signed: isSigned(day) }"@click="sign(day)">{{ day }}</td></tr></tbody></table></div>
</template><script lang="ts" setup>
import { computed, onMounted, reactive, ref } from "vue";
import message from "@arco-design/web-vue/es/message";
import { SignAddRequest, SignControllerService } from "../../generated";const currentDate = ref<Date>(new Date()); // 今天
const signedDates = ref(["2023-12-01", "2023-12-05"]); // 已簽到的日期
const month = ref(new Date().getMonth() + 1); //本月
const weekdays = computed(() => {const weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];return weekdays.map((weekday) => weekday.slice(0, 2));
}); //表頭
//本月日期情況
const weeks = computed(() => {const year = currentDate.value.getFullYear();const month = currentDate.value.getMonth();const firstDayOfMonth = new Date(year, month, 1).getDay();const daysInMonth = new Date(year, month + 1, 0).getDate();const weeksArray: Array<Array<any>> = [[]];let currentWeek = 0;for (let i = 0; i < firstDayOfMonth; i++) {weeksArray[currentWeek].push("");}for (let day = 1; day <= daysInMonth; day++) {if (weeksArray[currentWeek].length === 7) {weeksArray.push([]);currentWeek++;}weeksArray[currentWeek].push(day);}return weeksArray;
});
// 當前表格是不是今天
const isToday = (day: number) => {const today = new Date();return (day === today.getDate() &¤tDate.value.getMonth() === today.getMonth() &¤tDate.value.getFullYear() === today.getFullYear());
};
// 當前表格是否已經被簽到了
const isSigned = (day: number) => {const year = currentDate.value.getFullYear();const month = currentDate.value.getMonth() + 1;const date = day.toString().padStart(2, "0");const dateString = `${year}-${month}-${date}`;return signedDates.value.includes(dateString);
};
// 今天是否已簽
const isTodaySigned = computed(() => {const today = new Date();const day = today.getDate();return isSigned(day);
});
// 簽到
const sign = (day: number) => {if (isToday(day) && !isSigned(day)) {const year = currentDate.value.getFullYear();const month = currentDate.value.getMonth() + 1;const date = day.toString().padStart(2, "0");const dateString = `${year}-${month}-${date}`;signedDates.value.push(dateString);message.success("簽到成功,業精于勤荒于嬉,請繼續堅持!!!");addSign(dateString);}
};
//發送簽到請求參數
// 發給后端請求當前登錄用戶本月的簽到情況
const addSign = async (date: string) => {SignControllerService.addSignUsingPost(date);
};
const init = async () => {console.log("簽到組件加載完成");const res = await SignControllerService.getSignedDateUsingGet();if (res.code === 0) {signedDates.value = res.data as string[];}
};
onMounted(() => {init();
});
</script><style scoped>
.calendar {display: flex;flex-direction: column;justify-content: center;
}.calendar h1 {font-family: 華文仿宋;text-align: center;margin-bottom: 0px;
}.calendar p {font-size: large;font-family: 華文仿宋;text-align: center;
}em {color: lightgreen;font-size: large;font-weight: bold;margin: 0 5px 0 1px;
}table {border-collapse: collapse;width: 95%;margin: 0 auto;
}th,
td {border: 1px solid #ccc;padding: 10px;text-align: center;
}th {background-color: #f0f0f0;
}td.today {background-color: #eaf6ff;cursor: pointer;
}td.signed {background-color: #b3e5fc;
}td.signed:hover {background-color: #80d4f7;
}
</style>
后端主要的SQL語言
主要的SQL語言是:用DATE_FORMAT(CURDATE(), '%Y%m)判斷年月是否一樣。
SELECT createTime
FROM sign
WHERE userId = 1727616588754034690and DATE_FORMAT(createTime, '%Y%m') = DATE_FORMAT(CURDATE(), '%Y%m')
###判斷本月內的簽到情況