使用Vue3+Typescript手写一个日历签到组件

设计理念

昨天写了个简单美观的日历签到组件,使用的是Vue3+TypeScript,大概逻辑是先找到本月份第一天是周几,然后开始填充月份日期:weeksArray:[[]]:之后渲染到表格中,对于签到事件触发则先判断是否是今天且还未没有签到,没有就发送请求给后端的接口,然后签到就完成了。

设计UI

代码

详情请看俺滴代码:

html 复制代码
<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">
          <td
            v-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() &&
    currentDate.value.getMonth() === today.getMonth() &&
    currentDate.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)判断年月是否一样。

sql 复制代码
SELECT createTime
FROM sign
WHERE userId = 1727616588754034690
  and DATE_FORMAT(createTime, '%Y%m') = DATE_FORMAT(CURDATE(), '%Y%m')
###判断本月内的签到情况
相关推荐
GISer_Jing7 分钟前
前端面试通关:Cesium+Three+React优化+TypeScript实战+ECharts性能方案
前端·react.js·面试
落霞的思绪1 小时前
CSS复习
前端·css
咖啡の猫3 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲5 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5816 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路6 小时前
GeoTools 读取影像元数据
前端
ssshooter7 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友7 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry7 小时前
Jetpack Compose 中的状态
前端
dae bal8 小时前
关于RSA和AES加密
前端·vue.js