Prechádzať zdrojové kódy

feat: 时间显示磁贴功能完善

kindring 10 mesiacov pred
rodič
commit
2c35fbae03

+ 30 - 10
src/components/magnetView.vue

@@ -1,9 +1,10 @@
 <script setup lang="ts">
-import { ref} from "vue";
-import {Magnet, MagnetSize} from "@/types/magnetType.ts";
+import {ref, shallowRef} from "vue";
+import {Magnet, MagnetEmit, MagnetSize} from "@/types/magnetType.ts";
 import {computeMagnetStyle, initTimeMagnetInfo} from "@/components/magnets/magnetInfo.ts";
 
 import TimeMagnet from "@/components/magnets/timeMagnet.vue";
+import {Calendar} from "@/util/time.ts";
 
 const timeMagnetInfo = initTimeMagnetInfo(TimeMagnet)
 
@@ -26,11 +27,11 @@ const magnetItemInfos: vueMagnet[] = [
   {
     id: `233`,
     type: timeMagnetInfo.type,
-    x: 6,
-    y: 6,
-    width: timeMagnetInfo.sizes.medium?.width??0,
-    height: timeMagnetInfo.sizes.medium?.height??0,
-    size: MagnetSize.medium,
+    x: 7,
+    y: 0,
+    width: timeMagnetInfo.sizes.small?.width??0,
+    height: timeMagnetInfo.sizes.small?.height??0,
+    size: MagnetSize.small,
     editMode: false,
     selected: false,
     component: timeMagnetInfo.component
@@ -39,9 +40,23 @@ const magnetItemInfos: vueMagnet[] = [
 
 
 
-const magnetItems = ref(magnetItemInfos)
-
+const magnetItems = shallowRef(magnetItemInfos)
 
+function daySelect(calendar: Calendar){
+  console.log(`选择日期 ${calendar.year}年 ${calendar.month}月 ${calendar.day}日`)
+}
+function eventHandler(magnetEmit: MagnetEmit<any>){
+  // 事件处理
+  switch (magnetEmit.event){
+    case timeMagnetInfo.event:
+      daySelect(magnetEmit.data)
+    break;
+      default:
+        console.log('no match event')
+        console.log(magnetEmit)
+        break;
+  }
+}
 
 
 
@@ -57,7 +72,11 @@ const magnetItems = ref(magnetItemInfos)
        :key="magnet.id"
        :style="computeMagnetStyle(magnet)"
   >
-    <component :is="magnet.component" v-bind:size="magnet.size"></component>
+    <component
+        :is="magnet.component"
+        :size="magnet.size"
+        @magnet="eventHandler"
+    ></component>
   </div>
 
 </div>
@@ -77,4 +96,5 @@ const magnetItems = ref(magnetItemInfos)
   box-shadow: 0px 1px 2px #ccc;
 }
 
+
 </style>

+ 10 - 3
src/components/magnets/magnetInfo.ts

@@ -7,15 +7,22 @@ import {Magnet, MagnetInfo, MagnetSize} from "@/types/magnetType.ts";
 const cellWidth = 50;
 const cellMargin = 10;
 
-const timeMagnetInfo: MagnetInfo =
+export const MagnetEvent = "magnet"
+
+export const timeMagnetInfo: MagnetInfo =
 {
     type: 'TimeMagnet',
+    event: 'daySelect',
     defaultSize: MagnetSize.medium,
     sizes: {
-        medium: {
-            width: 5,
+        small: {
+            width: 7,
             height: 3,
         },
+        medium: {
+            width: 7,
+            height: 6,
+        },
     },
     component: null
 }

+ 138 - 10
src/components/magnets/timeMagnet.vue

@@ -1,25 +1,31 @@
 <script setup lang="ts">
 import {defineComponent, ref} from "vue";
 // import {MagnetSize} from "@/types/magnetType.ts";
-import {timeFormat} from "@/util/time.ts";
-import magnetInfos, { computeStyle} from "@/components/magnets/magnetInfo.ts";
+import {Calendar, getCalendar, getCalendarByWeek, LUNAR_INFO, timeFormat} from "@/util/time.ts";
+import {computeStyle, timeMagnetInfo} from "@/components/magnets/magnetInfo.ts";
+import {MagnetEmit, MagnetSize} from "@/types/magnetType.ts";
 
 defineComponent({
   name: "timeMagnet"
 })
+
+const emit = defineEmits<{
+  (e: 'magnet', magnetEmit: MagnetEmit<Calendar>): void
+}>()
+
 let props = defineProps({
   size: {
-    default: magnetInfos.timeMagnetInfo.defaultSize
+    default: timeMagnetInfo.defaultSize
   }
 })
 
 let _size = props.size;
-let sizeItem = magnetInfos.timeMagnetInfo.sizes[_size];
+let sizeItem = timeMagnetInfo.sizes[_size];
 // 监听 size 值的变化
 if (!sizeItem){
   // size 属性值不存在,则使用默认值
-  _size = magnetInfos.timeMagnetInfo.defaultSize;
-  sizeItem = magnetInfos.timeMagnetInfo.sizes[_size];
+  _size = timeMagnetInfo.defaultSize;
+  sizeItem = timeMagnetInfo.sizes[_size];
   // 获取默认值
   if(!sizeItem){
     throw new Error('size 属性值不存在');
@@ -36,6 +42,19 @@ const hourStr = ref(timeFormat(new Date(), hourFormat));
 // 获取 年月日 2021-08-31
 const yearStr = ref(timeFormat(new Date(), yearFormat));
 
+const weekDays = LUNAR_INFO.WEEK_DAY_SHORT;
+
+
+const calendar = ref(getCalendar(new Date()))
+const calendarIndex = ref(-1);
+// 生成日历
+if (props.size === MagnetSize.small){
+  // 获取 7 天的日历
+  calendar.value = getCalendarByWeek(new Date())
+}
+
+
+
 // 定时器
 function updateTime(){
   setTimeout(()=>{
@@ -46,6 +65,16 @@ function updateTime(){
   }, 500)
 }
 updateTime()
+
+
+function selectDay(calendarItem:  Calendar, index: number){
+  calendarIndex.value = index;
+  const magnetEmit = {
+    event: timeMagnetInfo.event,
+    data: calendarItem,
+  }
+  emit('magnet', magnetEmit)
+}
 </script>
 
 <template>
@@ -61,7 +90,33 @@ updateTime()
       </div>
     </div>
 <!--    当前日程 -->
-
+    <div class="date-box">
+<!--      星期 -->
+      <div class="week">
+        <div class="week-item"
+             v-for="week in weekDays"
+             :key="week"
+        >
+          <span>{{ week }}</span>
+        </div>
+      </div>
+      <div class="calendar">
+        <div
+             v-for="(item, i) in calendar"
+             :key="item.year + item.month + item.day"
+             :class="`calendar-item
+             ${item.isToday?'today':''}
+             ${item.isLast||item.isNext?'last':''}
+             ${calendarIndex === i?'selected':''}
+             `"
+             @click="selectDay(item, i)"
+        >
+          <span class="calendar-day">{{ item.day }}</span>
+<!--          最大四字 -->
+<!--          <span class="calendar-info">节日|节气|农历日</span>-->
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
@@ -74,16 +129,89 @@ updateTime()
 .now-info {
   border-bottom: 1px solid #eee;
 }
-.sty-medium .now-info {
+.now-info {
   width: 100%;
   height: 80px;
 }
-.sty-medium .now-info .hour {
+.now-info .hour {
   font-size: 30px;
 }
-.sty-medium .now-info .year {
+.now-info .year {
   margin-top: 5px;
   font-size: 16px;
 }
 
+.week{
+  width: 100%;
+  height: 40px;
+  display: grid;
+  grid-template-columns: repeat(7, 1fr);
+  justify-content: space-around;
+  align-items: center;
+}
+.week-item{
+  width: 50px;
+  height: 40px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  cursor: default;
+}
+.calendar{
+  display: grid;
+  grid-template-columns: repeat(7, 1fr);
+  grid-template-rows: repeat(5, 1fr);
+  width: 100%;
+  height: 150px;
+}
+.calendar-item{
+  width: 50px;
+  height: 40px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+  cursor: default;
+  border-radius: 5px;
+  font-size: 16px;
+  transition: all .3s;
+  box-sizing: border-box;
+  user-select: none;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  -webkit-touch-callout: none;
+  -webkit-tap-highlight-color: transparent;
+
+}
+.calendar-item:hover{
+  border: 2px solid #42a4f1;
+}
+.selected{
+  border: 2px solid #5cb7fd;
+}
+.today{
+  background: #5cb7fd;
+  color: #ff3a3a;
+}
+.last{
+  color: #545454;
+  font-weight: normal;
+  font-size: 14px;
+}
+.calendar-day{
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 50px;
+  height: 20px;
+}
+.calendar-info{
+  display: flex;
+  justify-content: center;
+  width: 50px;
+  height: 20px;
+  font-size: 12px;
+}
+
 </style>

+ 8 - 0
src/types/magnetType.ts

@@ -43,11 +43,13 @@ interface size {
     height: number,
 }
 
+
 /**
  * 磁贴大小定义
  */
 export interface MagnetInfo  {
     type: string,
+    event: string,
     // 磁贴可以有多个可选尺寸, 不同尺寸, 对应不同宽高
     sizes:
         { [key in MagnetSize]?: size}
@@ -56,3 +58,9 @@ export interface MagnetInfo  {
     // 磁贴内容, 确定磁贴中的具体内容
     component: any
 }
+
+
+export interface MagnetEmit<T>{
+    event: string,
+    data: T,
+}

+ 250 - 23
src/util/time.ts

@@ -1,3 +1,15 @@
+export interface Calendar {
+    year: number;
+    month: number;
+    day: number;
+    week: number;
+    isToday: boolean;
+    isLast: boolean;
+    isNext: boolean;
+    // todo 农历
+}
+
+
 /**
  * 时间戳转时间字符串
  * @param timestamp - 时间戳
@@ -44,29 +56,18 @@ export function timeFormat(t: Date, format: string): string {
     let tf = function(i: number) {
         return (i < 10 ? '0' : '') + i;
     };
-
-    return format.replace(/yyyy|MM|M|dd|HH|mm|m|ss/g, function(a) {
-        switch (a) {
-            case 'yyyy':
-                return tf(t.getFullYear());
-            case 'MM':
-                return tf(t.getMonth() + 1);
-            case 'M':
-                return t.getMonth() + 1;
-            case 'mm':
-                return tf(t.getMinutes());
-            case 'm':
-                return t.getMinutes();
-            case 'dd':
-                return tf(t.getDate());
-            case 'HH':
-                return tf(t.getHours());
-            case 'ss':
-                return tf(t.getSeconds());
-            default:
-                return '';
-        }
-    });
+    format.replace(/yyyy/, tf(t.getFullYear()))
+        .replace(/MM/, tf(t.getMonth() + 1))
+        .replace(/M/, String(t.getMonth() + 1))
+        .replace(/dd/, tf(t.getDate()))
+        .replace(/d/, String(t.getDate()))
+        .replace(/HH/, tf(t.getHours()))
+        .replace(/H/, String(t.getHours()))
+        .replace(/mm/, tf(t.getMinutes()))
+        .replace(/m/, String(t.getMinutes()))
+        .replace(/ss/, tf(t.getSeconds()))
+        .replace(/s/, String(t.getSeconds()));
+    return format
 }
 
 /**
@@ -86,3 +87,229 @@ export function timestampFormat(timestamp: number, format: string): string {
 export function getUnixTimeStamp(): number {
     return Math.round(new Date().getTime() / 1000);
 }
+
+
+export const LUNAR_INFO = {
+    MIN_YEAR: 1901, // YEAR_INFO 的最小年份,和数组下标配合可知每个项的年份
+    MAX_YEAR: 2100, // YEAR_INFO 的最大年份
+    YEAR_INFO: [
+        "4e4ae0", "22a570", "7554d5", "42d260", "12d950", "e56554", "3656a0", "a9ad0", "5955d2", "2a4ae0",
+        "79a5b6", "4aa4d0", "1ad250", "e9d255", "3ab540", "ed6a0", "5dada2", "2e95b0", "864977", "524970",
+        "22a4b0", "71b4b5", "426a50", "166d40", "e1ab54", "362b60", "a9570", "5d52f2", "2a4970", "796566",
+        "46d4a0", "1aea50", "e96a95", "3a5ad0", "122b60", "e186e3", "2e92e0", "fd48d7", "4ec950", "22d4a0",
+        "edd8a6", "3eb550", "1656a0", "e5a5b4", "3625d0", "a92d0", "59d2b2", "2aa950", "75b557", "466ca0",
+        "1ab550", "ed5355", "3a4da0", "ea5b0", "e14573", "3252b0", "7da9a8", "4ae930", "226aa0", "71aea6",
+        "3eab50", "164b60", "65aae4", "36a570", "a5260", "55f263", "26d950", "795b57", "4656a0", "1a96d0",
+        "6d4dd5", "3e4ad0", "ea4d0", "5dd4d4", "2ed250", "7dd558", "4ab540", "1eb6a0", "f195a6", "4295b0",
+        "1649b0", "65a974", "36a4b0", "ab27a", "526a50", "266d40", "75af46", "46ab60", "1a9570", "6d4af5",
+        "3e4970", "1264b0", "5d74a3", "2aea50", "7d6b58", "4e5ac0", "1eab60", "7196d5", "4292e0", "16c960",
+        "61d954", "32d4a0", "6da50", "597552", "2656a0", "75abb7", "4a25d0", "1e92d0", "69cab5", "3aa950",
+        "eb4a0", "5dbaa4", "2aad50", "7d55d9", "4e4ba0", "22a5b0", "f15176", "4252b0", "16a930", "657954",
+        "326aa0", "6ad50", "595b52", "2a4b60", "75a6e6", "46a4e0", "1ad260", "69ea65", "36d530", "e5aa0",
+        "5d76a3", "2e96d0", "7d4afb", "4e4ad0", "22a4d0", "f1d0b6", "3ed250", "12d520", "61dd45", "32b5a0",
+        "656d0", "5955b2", "2a49b0", "79a577", "46a4b0", "1aaa50", "e9b255", "3a6d20", "aada0", "dd4b63",
+        "2e9370", "649f8", "4e4970", "2264b0", "f168a6", "3eea50", "126aa0", "e1a6c4", "32aae0", "a92e0",
+        "55d2e3", "26c960", "75d557", "46d4a0", "16da50", "695d55", "3a56a0", "ea6d0", "5d55d4", "2e52d0",
+        "7da9b8", "4ea950", "1eb4a0", "6db6a6", "3ead50", "1655a0", "61aba4", "32a5b0", "a52b0", "59b273",
+        "266930", "757337", "466aa0", "1aad50", "e94b55", "3a4b60", "ea570", "6154e4", "2ad160", "79e968",
+        "4ad520", "1edaa0", "ed6aa6", "3e56d0", "164ae0", "65a9d4", "32a2d0", "6d150", "55f252", "26d520"
+    ],
+    HEAVENLY_STEMS: ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'],
+    EARTHLY_BRANCHES: ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'],
+    ZODIAC: ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'],
+    CHINESE_MONTH: ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '冬', '腊'],
+    CHINESE_DATE: ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '初', '廿', '卅', '年', '月', '日', '闰'], // 廿: nian; 卅: sa; 都读四声
+    CHINESE_SOLAR_TERMS: ['立春', '雨水', '惊蛰', '春分', '清明', '谷雨', '立夏', '小满', '芒种', '夏至', '小暑', '大暑', '立秋', '处暑', '白露', '秋分', '寒露', '霜降', '立冬', '小雪', '大雪', '冬至', '小寒', '大寒'],
+    WEEK_DAY: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
+    WEEK_DAY_SHORT: ['一', '二', '三', '四', '五', '六', '日'],
+    MONTH_DAY: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], // 闰年2月29天
+}
+
+
+
+
+/**
+ * 获取日期的中文星期 星期一 至 星期日
+ * @param date
+ * @returns
+ */
+function getChineseWeek(date: Date): number {
+    const dayOfWeek = date.getDay()
+    return dayOfWeek === 0 ? 7 : dayOfWeek;
+}
+
+/**
+ * 获取指定月份的天数 该函数无需考虑闰年
+ * @param date
+ */
+function getMonthDays(date: Date): number {
+    const days = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
+    return days;
+}
+
+
+/**
+ * 获取指定月份的日期信息
+ * @param year
+ * @param month
+ */
+function getMonthDaysInfo(year: number, month: number): Calendar[] {
+    let calendar: Calendar[] = [];
+    let time = new Date(`${year}-${month}-01`)
+    let nowDate = new Date();
+    let nowDay = nowDate.getDate();
+    let isDay = nowDate.getMonth() + 1 === month && nowDate.getFullYear() === year;
+    // 计算当前月有多少天
+    let daysInMonth = getMonthDays(time);
+    for (let i = 1; i <= daysInMonth; i++) {
+        let date = new Date(`${year}-${month}-${i}`);
+        calendar.push({
+            year: date.getFullYear(),
+            month: date.getMonth() + 1,
+            day: i,
+            week: getChineseWeek(date),
+            isToday: isDay ? nowDay === date.getDate() : false,
+            isLast: false,
+            isNext: false,
+        });
+    }
+    return calendar;
+}
+
+function calendarGetNextMonth(calendar: Calendar): Calendar
+{
+
+    let nextMonth = calendar.month + 1;
+    let nextYear = calendar.year;
+    if (nextMonth > 12) {
+        nextMonth = 1;
+        nextYear++;
+    }
+    let newCalendar: Calendar = {
+        ...calendar,
+        month: nextMonth,
+        year: nextYear
+    }
+    return newCalendar;
+}
+
+function calendarGetPrevMonth(calendar: Calendar): Calendar
+{
+
+    let prevMonth = calendar.month - 1;
+    let prevYear = calendar.year;
+    if (prevMonth < 1) {
+        prevMonth = 12;
+        prevYear--;
+    }
+    let newCalendar: Calendar = {
+        ...calendar,
+        month: prevMonth,
+        year: prevYear
+    }
+    return newCalendar;
+}
+
+/**
+ * 获取指定日期的日历列表
+ * @param time
+ * @param isWeek
+ */
+export function getCalendar(time: Date): Calendar[] {
+    const calendar: Calendar = dateToCalendar(time);
+    console.log(calendar)
+    let calendars: Calendar[] = getMonthDaysInfo(calendar.year, calendar.month);
+
+    // 判断第一天是星期几
+    let firstDayWeek = calendars[0].week;
+    if (firstDayWeek !== 1)
+    {
+        // 计算前一个月的天数
+        let lastCalendar = calendarGetPrevMonth(calendar);
+        let daysInLastMonth = getMonthDaysInfo(lastCalendar.year, lastCalendar.month);
+        // 获取前一个月的后几天
+        for(let i = 1; i < firstDayWeek; i++)
+        {
+            // 获取上一个月的最后几天
+            let lastDay = daysInLastMonth[daysInLastMonth.length - i];
+            lastDay.isLast = true;
+            calendars.unshift(lastDay);
+        }
+    }
+    // 判断最后一天是星期几
+    let lastDayWeek = calendars[calendars.length - 1].week;
+    if (lastDayWeek !== 7) {
+        // 计算下一个月的天数
+        let nextCalendar = calendarGetNextMonth(calendar);
+        let daysInNextMonth = getMonthDaysInfo(nextCalendar.year, nextCalendar.month);
+        for (let i = 0; i + lastDayWeek < 7; i++) {
+            let nextDay = daysInNextMonth[i];
+            nextDay.isNext = true;
+            calendars.push(nextDay);
+        }
+    }
+    return calendars;
+}
+
+function dateToCalendar(date: Date): Calendar {
+    let nowDate = new Date();
+    let isToday = date.getFullYear() === nowDate.getFullYear() && date.getMonth() === nowDate.getMonth() && date.getDate() === nowDate.getDate();
+    let calendar:Calendar = {
+        year: date.getFullYear(),
+        month: date.getMonth() + 1,
+        day: date.getDate(),
+        week: getChineseWeek(date),
+        isToday: isToday,
+        isLast: false,
+        isNext: false,
+    };
+    return calendar;
+}
+
+export function getCalendarByWeek(time: Date, expand: boolean = false): Calendar[] {
+    const calendar: Calendar = dateToCalendar(time);
+    let calendars: Calendar[] = getMonthDaysInfo(calendar.year, calendar.month);
+    // 如果当前日期小于第7天, 则获取上一个月的日期
+    if (calendar.day < 7){
+        // 获取前一个月的天数
+        let lastCalendar = calendarGetPrevMonth(calendar);
+        let daysInLastMonth = getMonthDaysInfo(lastCalendar.year, lastCalendar.month);
+        let len = expand ? daysInLastMonth.length : calendar.day - 1 ;
+        for (let i = 0; i < len; i++) {
+            daysInLastMonth[daysInLastMonth.length - i].isLast = true;
+            calendars.unshift(daysInLastMonth[daysInLastMonth.length - i]);
+        }
+    }
+    if (calendar.day >= 22) {
+        // 获取下一个月的天数
+        let nextCalendar = calendarGetNextMonth(calendar);
+        let daysInNextMonth = getMonthDaysInfo(nextCalendar.year, nextCalendar.month);
+        let len = expand ? daysInNextMonth.length : 7 ;
+        for (let i = 0; i < len; i++) {
+            daysInNextMonth[i].isNext = true;
+            calendars.push(daysInNextMonth[i]);
+        }
+    }
+
+    // 获取指定周
+    let targetIndex = calendars.findIndex(item => item.year === calendar.year && item.month === calendar.month && item.day === calendar.day);
+    if(targetIndex === -1) {
+        return calendars.slice(0, 7);
+    }
+    let targetDay = calendars[targetIndex];
+    // 获取指定日期所在周的信息
+    let startIndex = targetIndex - (targetDay.week - 1);
+    let endIndex = targetIndex + (7 - targetDay.week);
+    // 如果不进行扩展,则只返回指定日期所在周
+    if (!expand) {
+        return calendars.slice(startIndex, endIndex + 1);
+    }
+    // 扩展的话则获取前后一周
+    let start = Math.max(0, startIndex - 7);
+    let end = Math.min(calendars.length - 1, endIndex + 7);
+    calendars = calendars.slice(start, end + 1);
+    return calendars;
+}
+
+
+