浏览代码

feat:
1. 完成《记录》页面下, 日期切换和日期懒加载逻辑
2. 完成《记录》页面下, 日期选择弹窗的逻辑和跳转逻辑
3. 完成《记录》页面下, 对日历中日期的选中逻辑

YuJing 2 月之前
父节点
当前提交
307986ed11

+ 0 - 0
features/feature/src/main/ets/apis/ApiUrl.ets


+ 3 - 0
features/feature/src/main/ets/apis/DiaryApi.ets

@@ -0,0 +1,3 @@
+export class ApiUrl {
+
+}

+ 36 - 0
features/feature/src/main/ets/components/DiaryDatePicker.ets

@@ -0,0 +1,36 @@
+
+// 日期选择器
+@Component
+export struct DiaryDatePicker {
+  @State selectedDate: Date = new Date();
+
+  selectDateBack: (date: Date) => void = (date: Date) => {
+    console.log("选择的日期" + date.toLocaleString())
+  }
+
+  build() {
+    Column({space: 10}){
+      Row(){
+        Text("最新")
+          .onClick(() => {
+            this.selectedDate = new Date()
+          })
+        Text("ok")
+          .onClick(() => {
+            this.selectDateBack(this.selectedDate)
+          })
+      }
+      .width("100%")
+      .justifyContent(FlexAlign.SpaceBetween)
+      .padding({ left: 16, right: 16, top: 16, bottom: 16})
+
+      DatePicker({
+        end: new Date(),
+        selected: $$this.selectedDate,
+      })
+    }
+    .width("100%")
+    // .height("100%")
+    .backgroundColor('#EEEFF1')
+  }
+}

+ 16 - 3
features/feature/src/main/ets/models/BasicDataSource.ets

@@ -91,16 +91,29 @@ export class BasicDataSource<T> implements IDataSource {
     this.notifyDataAdd(this.dataArray.length - 1);
   }
 
+  // 往监听列表内部添加元素
+  public unshiftData(data: T): void {
+    this.dataArray.unshift(data);
+    this.notifyDataAdd(0);
+  }
+
   // 所有数据进行重新赋值
-  public reloadData(data: T[]) {
+  public init(data: T[]) {
     this.dataArray = data
     this.notifyDataReload()
   }
 
-  // 传入一个数组, 初始化监听列表
-  public init(datas: T[]) {
+  // 传入一个数组, 初始化监听列表 - 在数组尾部追加数据
+  public reloadDataPush(datas: T[]) {
     datas.forEach(i => {
       this.pushData(i)
     })
   }
+
+  // 传入一个数组, 初始化监听列表
+  public reloadDataUnshift(datas: T[]) {
+    datas.forEach(i => {
+      this.unshiftData(i)
+    })
+  }
 }

+ 1 - 0
features/feature/src/main/ets/models/DateInfo.ets

@@ -4,4 +4,5 @@ export interface DateInfo {
   month: number;  // 月份(1-12)
   day: number;    // 日期(1-31)
   week: string;   // 星期(中文)
+  id: Date ;    // 唯一标识
 }

+ 96 - 13
features/feature/src/main/ets/utils/weekUtil.ets

@@ -1,15 +1,35 @@
 import { DateInfo } from "../models/DateInfo";
 
 // 星期中文映射表
-const WEEK_MAP = ['日', '一', '二', '三', '四', '五', '六'];
+const WEEK_MAP = ['日', '一', '二', '三', '四', '五', '六'];
 
 /**
- * 生成从指定日期开始的连续日期数组
+ * 创建一个日期信息对象
+ * @param date 日期对象
+ * @returns DateInfo 对象
+ */
+function createDateInfo(date: Date): DateInfo {
+  const year = date.getFullYear();
+  const month = date.getMonth() + 1;
+  const day = date.getDate();
+  const week = WEEK_MAP[date.getDay()];
+
+  return {
+    year: year,
+    month: month,
+    day: day,
+    week: week,
+    id: new Date(date)
+  };
+}
+
+/**
+ * 生成从指定日期开始向前的连续日期数组
  * @param startDate 起始日期(默认当前日期)
  * @param count 生成的日期数量(默认7天)
  * @returns 日期对象数组
  */
-export function generateDateArray(
+export function generateForwardDateArray(
   startDate: Date = new Date(),
   count: number = 7
 ): DateInfo[] {
@@ -19,19 +39,82 @@ export function generateDateArray(
   const currentDate = new Date(startDate);
 
   for (let i = 0; i < count; i++) {
-    // 注意:月份从0开始,需要+1转为1-12
-    const month = currentDate.getMonth() + 1;
+    // 添加日期信息到数组
+    dateArray.push(createDateInfo(currentDate));
 
-    dateArray.push({
-      year: currentDate.getFullYear(),
-      month: month,
-      day: currentDate.getDate(),
-      week: WEEK_MAP[currentDate.getDay()]  // getDay()返回0-6(0=周日)
-    });
+    // 日期减1天(向前)
+    currentDate.setDate(currentDate.getDate() - 1);
+  }
 
-    // 日期加1天
+  return dateArray;
+}
+
+/**
+ * 生成从指定日期开始向后的连续日期数组,可以包含今天但不能超过今天
+ * @param startDate 起始日期(默认当前日期)
+ * @param count 生成的日期数量(默认7天)
+ * @returns 日期对象数组,包含今天但不包含超过今天的日期
+ */
+export function generateBackwardDateArray(
+  startDate: Date = new Date(),
+  count: number = 7
+): DateInfo[] {
+  const dateArray: DateInfo[] = [];
+
+  // 复制起始日期,避免修改原对象
+  const currentDate = new Date(startDate);
+
+  // 获取今天的日期
+  // 获取今天的日期并设置时间为23:59:59:999,便于比较
+  const today = new Date();
+  today.setHours(0, 0, 0, 0);
+  today.setDate(today.getDate() + 1);
+  today.setTime(today.getTime() - 1); // 设置为今天的最后一毫秒
+
+  for (let i = 0; i < count; i++) {
+    // 检查当前日期是否超过今天
+    if (currentDate > today) {
+      break;
+    }
+
+    // 添加日期信息到数组
+    dateArray.push(createDateInfo(currentDate));
+
+    // 日期加1天(向后)
     currentDate.setDate(currentDate.getDate() + 1);
   }
 
   return dateArray;
-}
+}
+
+
+
+/**
+ * 生成指定日期前后指定天数的完整日期数组
+ * @param centerDate 中心日期
+ * @param days 每侧天数(默认30天)
+ * @returns 包含前后日期的完整数组,按时间顺序排列
+ */
+export function generateCenteredDateArray(
+  centerDate: Date = new Date(),
+  days: number = 30
+): DateInfo[] {
+  // 创建前一天的日期作为前向数组的起始日期
+  const forwardStartDate = new Date(centerDate);
+  forwardStartDate.setDate(centerDate.getDate() - 1);
+
+  // 生成前days天的日期数组(需要反转以保证时间顺序)
+  const forwardArray = generateForwardDateArray(
+    forwardStartDate,
+    days
+  ).reverse();
+
+  // 生成后days天的日期数组(包括当天)
+  const backwardArray = generateBackwardDateArray(centerDate, days + 1);
+
+  // 删除backwardArray中的第一天(即centerDate),避免重复
+  backwardArray.shift();
+
+  // 合并数组
+  return [...forwardArray, ...backwardArray];
+}

+ 9 - 1
features/feature/src/main/ets/view/DiaryView.ets

@@ -1,6 +1,7 @@
 import { IBestToast, YTAvoid, yTRouter, yTToast } from "basic"
 import { ArrayList } from "@kit.ArkTS"
 import { yTDoubleConfirm } from "basic/src/main/ets/components/generalComp/YtDoubleConfirm";
+import { generateBackwardDateArray, generateCenteredDateArray, generateForwardDateArray } from "../utils/weekUtil";
 
 /**
  * 日记页面
@@ -13,7 +14,14 @@ export struct DiaryView {
    * 增加日记
    */
   increaseDiary() {
-    yTRouter.pushPathByName("IncreaseDiaryPage", null);
+    let res = generateForwardDateArray(new Date(), 20)
+    console.log("向前  " + JSON.stringify(res))
+    let res2 = generateBackwardDateArray(new Date(), 20)
+    console.log("向后  " + JSON.stringify(res2))
+    res2 = generateCenteredDateArray(new Date(), 20)
+    console.log("向后  " + JSON.stringify(res2))
+
+    // yTRouter.pushPathByName("IncreaseDiaryPage", null);
   }
 
   /**

+ 76 - 40
features/feature/src/main/ets/view/RecodView.ets

@@ -1,6 +1,7 @@
-import { YTAvoid } from "basic"
-import { BasicDataSource } from "../models/BasicDataSource"
-import { DateInfo } from "../models/DateInfo"
+import { YTAvoid } from 'basic'
+import { DateInfo } from '../models/DateInfo'
+import { RecodeViewModel } from '../viewModels/RecodeViewModel'
+import { DiaryDatePicker } from '../components/DiaryDatePicker'
 
 /**
  * 记录页面
@@ -9,24 +10,15 @@ import { DateInfo } from "../models/DateInfo"
 export struct RecodView {
   @StorageProp(YTAvoid.SAFE_BOTTOM_KEY) bottom: number = 0
   @StorageProp(YTAvoid.SAFE_TOP_KEY) safeTop: number = 0
-
-  @State weekLoop: BasicDataSource<DateInfo> = new BasicDataSource()
-
-  private swiperController: SwiperController = new SwiperController();
-
-  private weeks: ResourceStr[] = [
-    $r('app.string.hm_calendar_sunday'),
-    $r('app.string.hm_calendar_monday'),
-    $r('app.string.hm_calendar_tuesday'),
-    $r('app.string.hm_calendar_wednesday'),
-    $r('app.string.hm_calendar_thursday'),
-    $r('app.string.hm_calendar_friday'),
-    $r('app.string.hm_calendar_saturday'),
-  ]
-
+  // ViewModel
+  @State Vm: RecodeViewModel = new RecodeViewModel()
 
   aboutToAppear(): void {
-    // this.swiperController.changeIndex(19)
+    this.Vm.selectedDateChange = this.selectDateChange
+  }
+
+  selectDateChange = (index: number) => {
+    this.Vm.selectedDate = index
   }
 
   build() {
@@ -38,38 +30,82 @@ export struct RecodView {
         Image($r("app.media.calendar"))
           .width(30)
           .aspectRatio(1)
+          .onClick(() => {
+            animateToImmediately({
+              duration: 200
+            }, () => {
+              this.Vm.showTimePicker = !this.Vm.showTimePicker;
+            })
+          })
       }
       .width("100%")
       .justifyContent(FlexAlign.SpaceBetween)
 
-      /**
-       * 日历组件
-       * 1. 懒加载用上
-       * 2. 纵向list, 最右边(今天)作为列表头
-       * 3. 一次加载一个月数据(待定), 是否可以添加触底刷新机制(到已加载的第一天触发)
-       *
-       * question
-       * 1. 使用日历选择器选择的时间跨度 大于 30 天时,怎么加载?
-       *
-       */
-      Column(){
-        Swiper(this.swiperController){
-          ForEach(new Array(20).fill(0), (item: number, index: number) => {
-            Column() {
-              Text("星期")
-              Text("日期" + index.toString())
+      Stack({alignContent: Alignment.TopEnd}){
+        /**
+         * 日历组件
+         * 1. 懒加载用上
+         * 2. 纵向 swiper, 最右边(今天)作为头
+         *
+         * 加载方式
+         * 1. 通过监听 swiper index 的变化来触发相应逻辑
+         *
+         * * 未通过日历进行跳转日期
+         * 1. 向左滑动时, 如果日期剩余 < 10,则加载下一周 ( index == list.length - 10 )
+         *
+         * * 通过日历进行跳转日期
+         * * *
+         */
+
+        // 小 《 《 《 大
+        Column(){
+          Swiper(this.Vm.swiperController){
+            LazyForEach(this.Vm.weekLoop, (item: DateInfo, index: number) => {
+              Column() {
+                Text(item.week)
+                Text(`${item.month}-${item.day}`)
+              }
+              .border({
+                width: this.Vm.selectedDate === index ? 1 : 0
+              })
+              .onClick(() => {
+                this.Vm.selectedDate = index
+              })
+            }, (item: DateInfo, index: number) => { return item.id.toString() })
+          }
+          .loop(false)
+          .displayCount(7)
+          .indicator(false)
+          .direction(Direction.Rtl)
+          .onChange((index: number) => {
+            this.Vm.swiperOnChange(index)
+          })
+        }
+
+        if(this.Vm.showTimePicker) {
+          DiaryDatePicker({
+            selectedDate: this.Vm.weekLoop.getData(this.Vm.swiperCurrentIndex).id,
+            selectDateBack: (date: Date) => {
+              this.Vm.showTimePicker = false
+              this.Vm.jumpToDate(date)
             }
           })
+            .width("80%")
         }
-        .loop(false)
-        .displayCount(7)
-        .direction(Direction.Rtl)
-        .indicator(false)
       }
+      .width("100%")
+      .layoutWeight(1)
 
+      Button("check")
+        .onClick(() => {
+          for (let index = 0; index < this.Vm.weekLoop.totalCount(); index++) {
+            console.log(`${ this.Vm.swiperCurrentIndex == index ? 'ToDay' : '' } ${this.Vm.weekLoop.getData(index).month} 月 ${this.Vm.weekLoop.getData(index).day} 日 `)
+          }
+        })
     }
     .width("100%")
     .height("100%")
     .padding({ top: this.safeTop + 22, left: 16, right: 16 })
   }
-}
+}
+

+ 102 - 0
features/feature/src/main/ets/viewModels/RecodeViewModel.ets

@@ -0,0 +1,102 @@
+import { BasicDataSource } from '../models/BasicDataSource';
+import { DateInfo } from '../models/DateInfo';
+import { generateBackwardDateArray, generateForwardDateArray } from '../utils/weekUtil';
+
+export class RecodeViewModel{
+  // 懒加载数据源
+  weekLoop: BasicDataSource<DateInfo> = new BasicDataSource()
+  // swiper 控制器
+  swiperController: SwiperController = new SwiperController();
+  // 是否显示时间选择器
+  showTimePicker: boolean = false
+  // swiper 容器中当前选中的 index
+  swiperCurrentIndex: number = 0
+  // 日历中被选中的日期
+  selectedDate: number = 0
+
+  // 外部传入, 用于修改日历中选中的日期 ( 直接在本类中修改 UI 无法进行刷新WW )
+  selectedDateChange: (index: number) => void = (index: number) => {}
+
+  constructor() {
+    // 初始化列表数据
+    const dateList: DateInfo[] = generateForwardDateArray(new Date, 30);
+    console.log("初始化数据" + JSON.stringify(dateList))
+    this.weekLoop.init(dateList);
+  }
+
+  /**
+   * 加载更多数据 - 向左
+   * @param days 需要加载天数
+   */
+  loadForwardMoreData(days: number): void {
+    // 取得列表最后一条数据的 id
+    const dateInfo: Date = this.weekLoop.getData(this.weekLoop.totalCount() - 1).id;
+    // 向后加载 10 天的数据
+    const dateArray: DateInfo[] = generateForwardDateArray(dateInfo, days)
+    dateArray.splice(0, 1)
+    console.log("向左加载的数据" +  JSON.stringify(dateArray))
+
+    // 重新挂载到数据源中
+    this.weekLoop.reloadDataPush(dateArray)
+  }
+
+  /**
+   * 加载更多数据 - 向右
+   * @param days 加载的天数
+   * @param start 起始的日期, 未传则使用当前时间
+   * @returns 加载的天数
+   */
+  loadBackwardMoreData(days: number, start?: Date): number {
+    // 向后加载 10 天的数据
+    const dateArray: DateInfo[] = generateBackwardDateArray(start ?? new Date(), days)
+    console.log("向右加载的数据" + JSON.stringify(dateArray))
+    dateArray.splice(0, 1)
+
+    const count = dateArray.length
+    // 重新挂载到数据源中
+    this.weekLoop.reloadDataUnshift(dateArray)
+
+    return count;
+  }
+
+  /**
+   * swiper 改变时触发
+   * @param currentIndex 当前 swiper 选中的 index
+   * @param days 加载的天数
+   */
+  swiperOnChange(currentIndex: number, days: number = 10){
+    console.log('Swiper currentIndex', currentIndex)
+    this.swiperCurrentIndex = currentIndex
+    if (currentIndex >= this.weekLoop.totalCount() - 10) {
+      // 向左加载
+      console.log('Swiper loadMoreData')
+      this.loadForwardMoreData(days)
+    } else if (currentIndex <= 10) {
+      // 向右加载
+      let count = this.loadBackwardMoreData(days, this.weekLoop.getData(0).id)
+      this.swiperController.changeIndex(this.swiperCurrentIndex + count)
+      this.selectedDateChange(this.selectedDate + count)
+    }
+  }
+
+  /**
+   * 通过日期选择器跳转至指定日期时触发
+   * @param date 跳转到的指定日期
+   */
+  jumpToDate(date: Date) {
+    const backList: DateInfo[] = generateBackwardDateArray(date, 20).reverse()
+    const forwardList: DateInfo[] = generateForwardDateArray(date, 20)
+    console.log("向右加载的数据" + JSON.stringify(backList))
+    console.log("向左加载的数据" + JSON.stringify(forwardList))
+
+    backList.pop()
+    // 小 小 大 大
+    const dateList: DateInfo[] = [...backList, ...forwardList]
+    console.log("重新加载" + JSON.stringify(dateList))
+    this.weekLoop.init(dateList);
+
+    const targetIndex = dateList.findIndex(item => item.id.getTime() === date.getTime())
+    this.swiperController.changeIndex(targetIndex)
+    this.selectedDateChange(targetIndex)
+  }
+}

+ 0 - 156
features/feature/src/main/resources/base/element/string.json

@@ -3,162 +3,6 @@
     {
       "name": "shared_desc",
       "value": "description"
-    },
-    {
-      "name": "module_desc",
-      "value": "module description"
-    },
-    {
-      "name": "EntryAbility_desc",
-      "value": "description"
-    },
-    {
-      "name": "EntryAbility_label",
-      "value": "日历日程"
-    },
-    {
-      "name": "hm_calendar_monday",
-      "value": "一"
-    },
-    {
-      "name": "hm_calendar_tuesday",
-      "value": "二"
-    },
-    {
-      "name": "hm_calendar_wednesday",
-      "value": "三"
-    },
-    {
-      "name": "hm_calendar_thursday",
-      "value": "四"
-    },
-    {
-      "name": "hm_calendar_friday",
-      "value": "五"
-    },
-    {
-      "name": "hm_calendar_saturday",
-      "value": "六"
-    },
-    {
-      "name": "hm_calendar_sunday",
-      "value": "日"
-    },
-    {
-      "name": "hm_calendar_clocked",
-      "value": "已打卡"
-    },
-    {
-      "name": "hm_calendar_back",
-      "value": "回今天"
-    },
-    {
-      "name": "hm_calendar_month",
-      "value": "月"
-    },
-    {
-      "name": "hm_calendar_currentDay",
-      "value": "今天"
-    },
-    {
-      "name": "hm_calendar_measures",
-      "value": "措施"
-    },
-    {
-      "name": "hm_calendar_time",
-      "value": "时间"
-    },
-    {
-      "name": "hm_calendar_cancel",
-      "value": "取消"
-    },
-    {
-      "name": "hm_calendar_confirm",
-      "value": "确定"
-    },
-    {
-      "name": "reason_read_calendar",
-      "value": "读取日历"
-    },
-    {
-      "name": "reason_write_calendar",
-      "value": "写入日历"
-    },
-    {
-      "name": "message",
-      "value": "插入成功"
-    },
-    {
-      "name": "back",
-      "value": "回到首页"
-    },
-    {
-      "name": "showToast",
-      "value": "该功能尚在开发中"
-    },
-    {
-      "name": "title",
-      "value": "事项标题"
-    },
-    {
-      "name": "location",
-      "value": "地点"
-    },
-    {
-      "name": "priority",
-      "value": "优先级"
-    },
-    {
-      "name": "timePeriod",
-      "value": "事件时间段"
-    },
-    {
-      "name": "permission",
-      "value": "暂无权限,请申请后再次尝试"
-    },
-    {
-      "name": "success",
-      "value": "添加成功!"
-    },
-    {
-      "name": "calendar",
-      "value": "日历"
-    },
-    {
-      "name": "TIME",
-      "value": "开始时间须要早于结束时间!"
-    },
-    {
-      "name": "TITLE",
-      "value": "请输入标题!"
-    },
-    {
-      "name": "HEADING",
-      "value": "标题"
-    },
-    {
-      "name": "TITLE_ENTER",
-      "value": "请输入标题"
-    },
-    {
-      "name": "LOCATION_ENTER",
-      "value": "请输入地点"
-    },
-    {
-      "name": "DATE",
-      "value": "时间"
-    },
-    {
-      "name": "start",
-      "value": "开始"
-    },
-    {
-      "name": "end",
-      "value": "结束"
-    },
-    {
-      "name": "plan",
-      "value": "请输入日程说明或者计划"
     }
   ]
 }

+ 2 - 1
products/entry/src/main/ets/pages/Index.ets

@@ -37,7 +37,7 @@ struct Index {
   build() {
     Navigation(yTRouter) {
       Column() {
-        Tabs({ controller: this.tabsController, index: 1 }) {
+        Tabs({ controller: this.tabsController, index: 0 }) {
           ForEach(this.contentList, (_: BasicType<undefined>, index) => {
             TabContent() {
               if (index == 0) {
@@ -56,6 +56,7 @@ struct Index {
         })
         .barHeight(0)
         .layoutWeight(1)
+        .scrollable(false)
 
         Row() {
           ForEach(this.contentList, (item: BasicType<undefined>, index) => {