Просмотр исходного кода

feat: 项目初始化, 完成首页

YuJing 1 месяц назад
Родитель
Сommit
8825ee381b
26 измененных файлов с 485 добавлено и 342 удалено
  1. 1 1
      commons/basic/src/main/resources/base/element/color.json
  2. 1 0
      commons/basic/src/main/resources/base/media/icon_Search.svg
  3. BIN
      commons/basic/src/main/resources/base/media/png_MonthRecommend.png
  4. BIN
      commons/basic/src/main/resources/base/media/png_TopRecommend.png
  5. BIN
      commons/basic/src/main/resources/base/media/png_bookProcedure.png
  6. BIN
      commons/basic/src/main/resources/base/media/png_bookstore.png
  7. BIN
      commons/basic/src/main/resources/base/media/png_newBook.png
  8. BIN
      commons/basic/src/main/resources/base/media/png_question.png
  9. 12 0
      features/feature/src/main/ets/components/BuilderIndex.ets
  10. 45 0
      features/feature/src/main/ets/components/DeerSearch.ets
  11. 0 40
      features/feature/src/main/ets/components/FloatingComp.ets
  12. 25 0
      features/feature/src/main/ets/style/RootColumnStyle.ets
  13. 24 0
      features/feature/src/main/ets/style/TextStyle.ets
  14. 177 82
      features/feature/src/main/ets/view/MainView.ets
  15. 141 190
      features/feature/src/main/ets/view/SecondView.ets
  16. 25 0
      features/feature/src/main/ets/viewModel/MainViewModel.ets
  17. 17 18
      products/entry/src/main/ets/pages/Index.ets
  18. 17 11
      products/entry/src/main/ets/pages/PrivacyPage.ets
  19. BIN
      products/entry/src/main/resources/base/media/icon_classify.png
  20. BIN
      products/entry/src/main/resources/base/media/icon_classify_.png
  21. BIN
      products/entry/src/main/resources/base/media/icon_home.png
  22. BIN
      products/entry/src/main/resources/base/media/icon_home_.png
  23. BIN
      products/entry/src/main/resources/base/media/icon_mine.png
  24. BIN
      products/entry/src/main/resources/base/media/icon_mine_.png
  25. BIN
      products/entry/src/main/resources/base/media/icon_schoolbag.png
  26. BIN
      products/entry/src/main/resources/base/media/icon_schoolbag_.png

+ 1 - 1
commons/basic/src/main/resources/base/element/color.json

@@ -6,7 +6,7 @@
     },
     {
       "name": "main_ac_color_dark",
-      "value": "#FFEA663E"
+      "value": "#FECF2F"
     },
     {
       "name": "main_na_color",

+ 1 - 0
commons/basic/src/main/resources/base/media/icon_Search.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1761705613403" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4920" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1005.276891 945.444571L885.030034 825.051429c77.312-88.722286 117.394286-203.337143 117.394286-323.584A499.858286 499.858286 0 0 0 501.322606 0.512a499.858286 499.858286 0 0 0-501.174857 501.028571c0 277.796571 226.230857 501.174857 501.174857 501.174858 120.246857 0 231.862857-43.008 323.584-117.467429l123.099428 123.172571a43.081143 43.081143 0 0 0 31.451429 11.410286c11.483429 0 22.966857-2.852571 31.524571-11.410286 11.483429-20.041143 11.483429-45.860571-5.705143-62.976zM86.090606 501.540571a415.451429 415.451429 0 0 1 415.232-415.158857 415.451429 415.451429 0 0 1 415.158857 415.158857 416.914286 416.914286 0 0 1-117.394286 289.206858c-2.852571 0-2.852571 2.925714-5.705143 2.925714 0 0-2.925714 2.852571-2.925714 5.705143a416.914286 416.914286 0 0 1-289.133714 117.394285 415.451429 415.451429 0 0 1-415.232-415.232z" fill="#b5b5b5" p-id="4921"></path></svg>

BIN
commons/basic/src/main/resources/base/media/png_MonthRecommend.png


BIN
commons/basic/src/main/resources/base/media/png_TopRecommend.png


BIN
commons/basic/src/main/resources/base/media/png_bookProcedure.png


BIN
commons/basic/src/main/resources/base/media/png_bookstore.png


BIN
commons/basic/src/main/resources/base/media/png_newBook.png


BIN
commons/basic/src/main/resources/base/media/png_question.png


+ 12 - 0
features/feature/src/main/ets/components/BuilderIndex.ets

@@ -0,0 +1,12 @@
+import { CustomTextStyle } from "../style/TextStyle"
+
+@Builder
+export function tagItemComp(text: string, fontColor: ResourceColor, bgColor: ResourceColor){
+  Row(){
+    Text(text)
+      .attributeModifier(new CustomTextStyle({size: 12, weight: 400 , color: fontColor}))
+  }
+  .padding(5)
+  .backgroundColor(bgColor)
+  .borderRadius({topLeft: 8.5, topRight: 8.5, bottomRight: 8.5, bottomLeft: 0})
+}

+ 45 - 0
features/feature/src/main/ets/components/DeerSearch.ets

@@ -0,0 +1,45 @@
+import { YTButton } from "basic"
+import { CustomTextStyle } from "../style/TextStyle"
+
+@ComponentV2
+export struct DeerSearch {
+  @Param enable: boolean = true
+
+  @Local text: string = ''
+
+  build() {
+    Row({space: 7}) {
+      Row({space: 12.5}){
+        Image($r('[basic].media.icon_Search'))
+          .width(16)
+          .aspectRatio(1)
+          .fillColor('#FECF2F')
+
+        TextInput({text: this.text, placeholder: '搜索图书/书单'})
+          .padding(0)
+          .fontSize(12)
+          // .maxLength(20)
+          .fontWeight(400)
+          .layoutWeight(1)
+          .borderRadius(0)
+          .border({ width: 0 })
+          .placeholderColor('#B5B8BC')
+          .backgroundColor(Color.Transparent)
+          .placeholderFont({size: 12, weight: 400})
+      }
+      .borderRadius(31)
+      .layoutWeight(1)
+      .backgroundColor(Color.White)
+      .border({width: 2, color: '#000000'})
+      .padding({left: 13, right: 13, top: 3, bottom: 3})
+
+      Text('搜索')
+        .borderRadius(31)
+        .backgroundColor('#FECF2F')
+        .border({ width: 2, color: '#000000' })
+        .padding({left: 18, right: 18, top: 9, bottom: 9})
+        .attributeModifier(new CustomTextStyle({size: 12, weight: 600}))
+    }
+    .width("100%")
+  }
+}

+ 0 - 40
features/feature/src/main/ets/components/FloatingComp.ets

@@ -1,40 +0,0 @@
-import { UserInfo, userInfo } from 'basic';
-
-@Component
-export struct FloatingComp {
-  @Prop src: ResourceStr = $r('[basic].media.app_icon')
-  initPosition: Position | Edges | LocalizedEdges = { right: '50%', bottom: 20 }
-  imageWidth: number = 48
-  @State private cumulativeX: number = 0;
-  @State private cumulativeY: number = 0;
-  @StorageProp(UserInfo.KEY) private userInfo: UserInfo = userInfo
-  private startX: number = 0;
-  private startY: number = 0;
-  click = () => {
-  }
-
-  build() {
-    if (this.userInfo.checkLogin()) {
-      Image(this.src)
-        .width(this.imageWidth)
-        .aspectRatio(1)
-        .borderRadius(9999)
-        .gesture(
-          PanGesture({ distance: 1 })
-            .onActionStart(() => {
-              this.startX = this.cumulativeX;
-              this.startY = this.cumulativeY;
-            })
-            .onActionUpdate(event => {
-              // 记录起始位置
-              this.cumulativeX = this.startX + event.offsetX;
-              this.cumulativeY = this.startY + event.offsetY;
-            })
-        )
-        .translate({ x: this.cumulativeX, y: this.cumulativeY })
-        .position(this.initPosition)
-        .markAnchor({ x: -this.imageWidth / 2 })
-        .onClick(this.click)
-    }
-  }
-}

+ 25 - 0
features/feature/src/main/ets/style/RootColumnStyle.ets

@@ -0,0 +1,25 @@
+import { YTAvoid } from 'basic/Index'
+
+// 页面根布局样式
+@ObservedV2
+export class RootColumnStyle implements AttributeModifier<ColumnAttribute> {
+  @Trace safeTop: number = AppStorage.get(YTAvoid.SAFE_TOP_KEY) as number
+  @Trace safeBottom: number = AppStorage.get(YTAvoid.SAFE_BOTTOM_KEY) as number
+
+  constructor(needSafeBottom: boolean = true) {
+    if (!needSafeBottom) {
+      this.safeBottom = 0
+    }
+  }
+
+  // 组件常态样式
+  applyNormalAttribute(instance: ColumnAttribute): void {
+    instance
+      .width('100%')
+      .height('100%')
+      .backgroundColor('#F7F8FA')
+      .justifyContent(FlexAlign.Start)
+      .alignItems(HorizontalAlign.Start)
+      .padding({ left: 16, right: 16, top: this.safeTop, bottom: this.safeBottom })
+  }
+}

+ 24 - 0
features/feature/src/main/ets/style/TextStyle.ets

@@ -0,0 +1,24 @@
+export class CustomTextStyle implements AttributeModifier<TextAttribute> {
+  fontSize: number | string | Resource = 16;
+  fontWeight: number | FontWeight | string = 400;
+  fontColor: ResourceColor = '#000000';
+
+  constructor(font: CustomFont) {
+    this.fontSize = font.size ?? this.fontSize
+    this.fontWeight = font.weight ?? this.fontWeight
+    this.fontColor = font.color ?? this.fontColor
+  }
+
+  applyNormalAttribute(instance: TextAttribute): void {
+    instance
+      .fontSize(this.fontSize)
+      .fontWeight(this.fontWeight)
+      .fontColor(this.fontColor)
+  }
+}
+
+interface CustomFont{
+  size?: number | string | Resource
+  weight?: number | FontWeight | string
+  color?: ResourceColor
+}

+ 177 - 82
features/feature/src/main/ets/view/MainView.ets

@@ -1,105 +1,200 @@
-import { UnitType } from 'basic/src/main/ets/datepicker/DatePickerEnums'
-import { promptAction } from '@kit.ArkUI'
-import { tkAdHelper } from 'basic/src/main/ets/ads/tkAd/utils/TkAdHelper'
-import { DateOption, TkBannerAdComp, YTAddressSelectorDialog, YTDateUtil, YtProgressComp, yTRouter } from 'basic'
+import { BasicType } from "basic"
+import { tagItemComp } from "../components/BuilderIndex"
+import { DeerSearch } from "../components/DeerSearch"
+import { CustomTextStyle } from "../style/TextStyle"
+import { MainViModel } from "../viewModel/MainViewModel"
 
-@Component
+@ComponentV2
 export struct MainView {
-  @State point: number = 40
+  vm: MainViModel = new MainViModel()
 
   build() {
     Column() {
-      Text('打开日历')
-        .onClick(() => {
-          //以下内容都可以不传 有默认值
-          const date: Date = new Date()
-          const yTDateDialog = new YTAddressSelectorDialog(this.getUIContext())
-          let dateOption = new DateOption() //选项配置类
-          dateOption.date = date //当前日期  默认今天
-          dateOption.minDate = new Date(2000, 0, 1) //最小选择的日期 默认10年前的今天
-          dateOption.maxDate = new Date(2048, 12, 30) //最大选择的日期 默认10年后的今天
-          dateOption.unitType = UnitType.YEAR_MONTH_DAY //日期单位 默认年月日 可选年月、月日等组合
-          dateOption.confirm = (date: Date) => { //确认选择回调函数
-            console.log('确认', YTDateUtil.formatDate(date))
-            promptAction.openToast({ message: YTDateUtil.formatDate(date) })
+      Stack({alignContent: Alignment.Top}){
+        List(){
+          // logo
+          ListItem(){
+            Text('京东快递合作伙伴')
+              .attributeModifier(new CustomTextStyle({size: 12, weight: 600}))
+              .padding({top: this.vm.safeTop})
           }
-          dateOption.headerLeftBuilder = wrapBuilder(headerLeftBuilder) //头部左侧按钮 默认返回按钮
-          dateOption.headerRightBuilder = wrapBuilder(headerRightBuilder) //头部右侧按钮 默认确认按钮
-          dateOption.highlightBackgroundColor = Color.Pink //选中高亮背景色
-          dateOption.highlightBorderColor = Color.Red //选中高亮边框色
-          dateOption.textStyle = {
-            //日期文字样式
-            font: { size: 20, weight: 400 },
-            color: Color.Gray
-          }
-          dateOption.selectedTextStyle = {
-            //选中日期文字样式
-            font: { size: 25, weight: 400 },
-            color: Color.Yellow
+          .padding({bottom: 13})
+
+          // 搜索框
+          ListItem(){
+            DeerSearch()
           }
-          yTDateDialog.show(dateOption) //设置好配置之后打开日历的函数
-        })
-      Button('跳转页面测试')
-        .onClick(() => {
-          yTRouter.pushPathByName('TestRouterPage', null)
-        })
 
-      Button('播放激励广告')
-        .onClick(() => {
-          tkAdHelper.showRewardAd()
-        })
 
 
-      Button('播放插屏广告')
-        .onClick(() => {
-          tkAdHelper.showInterstitialAd()
-        })
+          ListItem(){
+            Column(){
+              // 轮播
+              Swiper(){
+                Row()
+                  .height(150)
+                  .width('100%')
+                  .backgroundColor(Color.Orange)
+              }
+              .height(150)
+              .width("100%")
+              .enabled(false)
+              .indicator(false)
+              .borderRadius(30)
+
+
+              // 功能
+              Row(){
+                ForEach(this.vm.function1, (item: BasicType, index) => {
+                  Column({space: 5}){
+                    Image(item.src)
+                      .width(60)
+                      .aspectRatio(1)
+
+                    Text(item.text)
+                      .attributeModifier(new CustomTextStyle({size: 14, weight: 600}))
+                  }
+                  .onClick(item.click)
+                })
+              }
+              .width("100%")
+              .margin({top: 22})
+              .justifyContent(FlexAlign.SpaceAround)
+
+
+              // 榜单
+              Row({space: 7}){
+                ForEach(['畅销版单TOP', '月度推荐'], (item: string, index) => {
+                  Column({space: 5}){
+                    Text(item)
+                      .attributeModifier(new CustomTextStyle({size: 16, weight: 600, color: '#663815'}))
+
+                    Text('查看更多>>')
+                      .attributeModifier(new CustomTextStyle({size: 12, weight: 600, color: index == 0 ?'#B27500' : '#E45C0B'}))
+                  }
+                  .layoutWeight(1)
+                  .aspectRatio(1)
+                  .justifyContent(FlexAlign.Start)
+                  .alignItems(HorizontalAlign.Start)
+                  .padding({left: 15, top: 17, right: 15, bottom: 17})
+                  .backgroundImage( index == 0 ?
+                    $r('[basic].media.png_TopRecommend') :
+                    $r('[basic].media.png_MonthRecommend') )
+                  .backgroundImageSize({ width: '100%', height: '100%'})
+                  .onClick(() => {
+                    // todo 完成榜单的跳转
+                  })
+                })
+              }
+              .width("100%")
+              .margin({top: 18})
+
+
+              // 新书上架
+              Column({space: 18}){
+                Row({space: 8}){
+                  Text('新书上架')
+                    .attributeModifier(new CustomTextStyle({size: 16, weight: 600}))
 
-      TkBannerAdComp()
+                  Text('查看更多>>')
+                    .attributeModifier(new CustomTextStyle({size: 12, weight: 600, color: '#807A66'}))
+                }
+                .width("100%")
+                .justifyContent(FlexAlign.Start)
+                .alignItems(VerticalAlign.Bottom)
 
-      CalendarPicker()
+                Grid(){
+                  ForEach(new Array(4).fill(''), (item: string, index) => {
+                    GridItem(){
+                      Column(){
+                        Image('https://th.bing.com/th/id/R.8bbf769b39bb26eefb9b6de51c23851d?rik=crTnc5i8A%2b8p7A&riu=http%3a%2f%2fpicview.iituku.com%2fcontentm%2fzhuanji%2fimg%2f202207%2f09%2fe7196ac159f7cf2b.jpg%2fnu&ehk=DYPLVpoNAXLj5qzwgR5vHf9DladFh%2b34s4UcuP3Kn6E%3d&risl=&pid=ImgRaw&r=0')
+                          .width('100%')
+                          .aspectRatio(148/100)
 
-      YtProgressComp({
-        growPoint: this.point,
-        v1Point: {
-          point: 100,
-          position: 4
-        },
-        v2Point: {
-          point: 200,
-          position: 10,
-          topImage: $r('app.media.app_icon'),
+                        Column({space: 5}){
+                          Text('红楼梦幼儿美绘本 第四卷红楼梦幼儿美绘本 第四卷')
+                            .maxLines(2)
+                            .textOverflow({overflow: TextOverflow.Ellipsis})
+                            .attributeModifier(new CustomTextStyle({size: 14, weight: 400}))
+
+                          Row({space: 8}){
+                            tagItemComp('情绪价值', '#4EB1EF', '#EDF7FD')
+                            tagItemComp('3-8岁', '#FC9911', '#FFF5E7')
+                          }
+                          .width("100%")
+                          .justifyContent(FlexAlign.Start)
+                        }
+                        .width("100%")
+                        .padding({left: 8, right: 8, top: 8, bottom: 8})
+                      }
+                      .width('100%')
+                      .borderRadius(8)
+                      .aspectRatio(152/180)
+                      .backgroundColor(Color.White)
+                      .border({width: 2, color: '#000000'})
+                    }
+                  })
+                }
+                .rowsGap(16)
+                .maxCount(2)
+                .width("100%")
+                .columnsGap(10)
+                .layoutWeight(1)
+                .columnsTemplate('repeat(2, 1fr)')
+              }
+              .height(500)
+              .height(470)
+              .width("100%")
+              .margin({top: 25})
+              .padding({left: 18, right: 18, top: 20})
+              .backgroundImage($r('[basic].media.png_newBook'))
+              .backgroundImageSize({width: '100%', height: '100%'})
+            }
+            .width("100%")
+          }
+          .margin({top: 13})
+
+
+
+          ListItem(){}
+          .padding({ bottom: 16 })
+        }
+        .width('100%')
+        .height('100%')
+        .scrollBar(BarState.Off)
+        .padding({ left: 16, right: 16 })
+        .onScrollIndex((index: number) => {
+          this.vm.scrollIndex = index
+          console.log(`index = ${JSON.stringify(index)}`)
+        })
+
+        if(this.vm.scrollIndex > 0){
+          Row(){
+            this.deerTitleComp()
+          }
+          .transition(TransitionEffect.asymmetric(TransitionEffect.move(TransitionEdge.TOP), TransitionEffect.move(TransitionEdge.TOP)).animation({ duration: 100 }))
         }
-      })
-      Row() {
-        Button('+10')
-          .onClick(() => {
-            this.point += 10
-          })
-        Button('-10')
-          .onClick(() => {
-            this.point -= 10
-          })
       }
     }
     .width('100%')
-    .height('100%')
-
+    .linearGradient({ colors: [['#F9EDAE', 0], ['#FFFFFF', 0.4]] })
   }
 
-  // .attributeModifier(new BackgroundPageModifier(true))
-
+  @Builder
+  deerTitleComp(){
+    Column({space: 10}){
+      Row()
+        .width(55)
+        .height(30)
 
-}
+      DeerSearch()
+    }
+    .width('100%')
+    .backgroundColor(Color.White)
+    .alignItems(HorizontalAlign.Center)
+    .shadow({ offsetY: 13, radius: 16, color: '#0A000000' })
+    .padding({top: this.vm.safeTop, bottom: 10, left: 16, right: 16})
+  }
 
-@Builder
-function headerLeftBuilder() {
-  Image($r('app.media.app_icon'))
-    .width(24)
-}
 
-@Builder
-function headerRightBuilder() {
-  Image($r("app.media.app_icon"))
-    .width(24)
 }

+ 141 - 190
features/feature/src/main/ets/view/SecondView.ets

@@ -1,214 +1,165 @@
-import { textToSpeech } from '@kit.CoreSpeechKit';
-import { BusinessError } from '@kit.BasicServicesKit';
-
-let ttsEngine: textToSpeech.TextToSpeechEngine;
-
-
 @Component
 export struct SecondView {
-  @State createCount: number = 0;
-  @State voiceInfo: string = "";
-  @State originalText: string = "支付宝到账[n2]1000000元";
+  @State animate_scale: boolean = false; // 商品缩小动画
+  @State toggle: boolean = false; // 轨迹动画控制flag
+  @State imageScaleX: number = 1; // 商品缩小尺寸X
+  @State imageScaleY: number = 1; // 商品缩小尺寸Y
+  @State cartAngle: number = 0; // 购物车抖动幅度
 
   build() {
     Column() {
-      Scroll() {
-        Column() {
-          TextArea({ placeholder: 'Please enter tts original text', text: `${this.originalText}` })
-            .margin(20)
-            .border({
-              width: 5,
-              color: 0x317AE7,
-              radius: 10,
-              style: BorderStyle.Solid
-            })
-            .onChange((value: string) => {
-              this.originalText = value;
-              console.info(`original text: ${this.originalText}`);
-            })
-          Button() {
-            Text("CreateEngineByCallback")
-              .fontColor(Color.White)
-              .fontSize(20)
+      Row() {
+        // 用stack包两个image,实现商品缩小动效;这里需要注意的是,图片给大小,父组件不给大小,跟随image大小;
+        // 使得column包着图片做路径动画;
+        Stack() {
+          Image($r('app.media.app_icon'))
+            .objectFit(ImageFit.Contain)
+            .width(400)
+            .height(400)
+          if (this.animate_scale) {
+            Column() {
+              Image($r('app.media.app_icon'))
+                .objectFit(ImageFit.Contain)
+                .width(400)
+                .height(400)
+                .scale({ x: this.imageScaleX, y: this.imageScaleY })
+                .motionPath({
+                  path: 'Mstart.x start.y C -400 50, -150 200, -360 1480', // -360 1500是相对于原位置的终点位置
+                  from: 0.0,
+                  to: 1.0,
+                  rotatable: false
+                })
+            }
+            .zIndex(3)
+            .alignItems(this.toggle ? HorizontalAlign.Start : HorizontalAlign.Center)
           }
-          .type(ButtonType.Capsule)
-          .backgroundColor("#0x317AE7")
-          .width("80%")
-          .height(50)
-          .margin(10)
-          .onClick(() => {
-            this.createCount++;
-            console.info(`CreateTtsEngine:createCount:${this.createCount}`);
-            this.createByCallback();
-          })
+        }
+      }
+      .backgroundColor(Color.Blue)
 
-          Button() {
-            Text("speak")
-              .fontColor(Color.White)
-              .fontSize(20)
-          }
-          .type(ButtonType.Capsule)
-          .backgroundColor("#0x317AE7")
-          .width("80%")
-          .height(50)
-          .margin(10)
-          .onClick(() => {
-            this.createCount++;
-            this.speak();
-          })
+      Column() {
+        Text('XXX元')
+          .fontSize(20)
+        Text('收货地址:XXX')
+          .fontSize(18)
+      }
+      .width('100%')
+      .margin({ left: 20, top: 20, bottom: 20 })
+      .alignItems(HorizontalAlign.Start)
 
-          Button() {
-            Text("listVoicesCallback")
-              .fontColor(Color.White)
-              .fontSize(20)
-          }
-          .type(ButtonType.Capsule)
-          .backgroundColor("#0x317AE7")
-          .width("80%")
-          .height(50)
-          .margin(10)
-          .onClick(() => {
-            this.listVoicesCallback();
-          })
+      Row() {
+        Column() {
+          Image($r('app.media.app_icon'))
+            .width(25)
+            .height(25)
+            .margin(5)
+          Text('首页')
+            .fontSize(12)
+        }
 
-          Button() {
-            Text("stop")
-              .fontColor(Color.White)
-              .fontSize(20)
-          }
-          .type(ButtonType.Capsule)
-          .backgroundColor("#0x317AE7")
-          .width("80%")
-          .height(50)
-          .margin(10)
-          .onClick(() => {
-            // 停止播报
-            console.info("Stop button clicked.");
-            ttsEngine.stop();
-          })
+        Column() {
+          Image($r('app.media.app_icon'))
+            .width(25)
+            .height(25)
+            .margin(5)
+          Text('消息')
+            .fontSize(12)
+        }
 
-          Button() {
-            Text("isBusy")
-              .fontColor(Color.White)
-              .fontSize(20)
-          }
-          .type(ButtonType.Capsule)
-          .backgroundColor("#0x317AE7")
-          .width("80%")
-          .height(50)
-          .margin(10)
+        Column() {
+          Image($r('app.media.app_icon'))
+            .width(25)
+            .rotate({
+              angle: this.cartAngle
+            })
+            .height(25)
+            .margin(5)
+          Text('购物车')
+            .fontSize(12)
+        }
+
+        Button('加入购物车')
+          .zIndex(1)
+          .backgroundColor('#ffcdcdcd')
+          .fontColor(Color.Red)
+          .fontSize(15)
+          .width(120)
+          .margin({ left: 20, right: 10 })
           .onClick(() => {
-            // 查询播报状态
-            let isBusy = ttsEngine.isBusy();
-            console.info(`isBusy: ${isBusy}`);
+            this.animate_scale = true;
+            // 先做商品缩小动效
+            this.animationImageScale();
           })
-
-          Button() {
-            Text("shutdown")
-              .fontColor(Color.White)
-              .fontSize(20)
-          }
-          .type(ButtonType.Capsule)
-          .backgroundColor("#0x317AA7")
-          .width("80%")
-          .height(50)
-          .margin(10)
+        Button('购买')
+          .width(120)
+          .zIndex(1)
+          .backgroundColor(Color.Red)
+          .fontColor(Color.White)
+          .fontSize(15)
           .onClick(() => {
-            // 释放引擎
-            ttsEngine.shutdown();
+
           })
-        }
-        .layoutWeight(1)
       }
+      .zIndex(1)
+      .height('20%')
       .width('100%')
-      .height('100%')
     }
+    .justifyContent(FlexAlign.SpaceBetween)
+    .height('100%')
+    .width('100%')
   }
 
-  // 创建引擎,通过callback形式返回
-  private createByCallback() {
-    // 设置创建引擎参数
-    let extraParam: Record<string, Object> = { "style": 'interaction-broadcast', "locate": 'CN', "name": 'EngineName' };
-    let initParamsInfo: textToSpeech.CreateEngineParams = {
-      language: 'zh-CN',
-      person: 0,
-      online: 1,
-      extraParams: extraParam
-    };
-    // 调用createEngine方法
-    textToSpeech.createEngine(initParamsInfo,
-      (err: BusinessError, textToSpeechEngine: textToSpeech.TextToSpeechEngine) => {
-        if (!err) {
-          console.info('Succeeded in creating engine.');
-          // 接收创建引擎的实例
-          ttsEngine = textToSpeechEngine;
-        } else {
-          console.error(`Failed to create engine. Code: ${err.code}, message: ${err.message}.`);
-        }
-      });
-  };
+  animationImageShake() {
+    animateTo({
+      duration: 100,
+      curve: Curve.Linear,
+      onFinish: () => {
+        animateTo({
+          duration: 100,
+          curve: Curve.Linear,
+          onFinish: () => {
+            // 最终节点,恢复所有设置
+            this.cartAngle = 0;
+            this.animate_scale = false;
+            this.imageScaleX = 1;
+            this.imageScaleY = 1;
+          }
+        }, () => {
+          this.cartAngle = -30;
+        })
+      }
+    }, () => {
+      this.cartAngle = 30;
+    })
+  }
 
-  // 调用speak播报方法
-  private speak() {
-    let speakListener: textToSpeech.SpeakListener = {
-      // 开始播报回调
-      onStart(requestId: string, response: textToSpeech.StartResponse) {
-        console.info(`onStart, requestId: ${requestId} response: ${JSON.stringify(response)}`);
-      },
-      // 完成播报回调
-      onComplete(requestId: string, response: textToSpeech.CompleteResponse) {
-        console.info(`onComplete, requestId: ${requestId} response: ${JSON.stringify(response)}`);
-      },
-      // 停止播报完成回调,调用stop方法并完成时会触发此回调
-      onStop(requestId: string, response: textToSpeech.StopResponse) {
-        console.info(`onStop, requestId: ${requestId} response: ${JSON.stringify(response)}`);
-      },
-      // 返回音频流
-      onData(requestId: string, audio: ArrayBuffer, response: textToSpeech.SynthesisResponse) {
-        console.info(`onData, requestId: ${requestId} sequence: ${JSON.stringify(response)} audio: ${JSON.stringify(audio)}`);
-      },
-      // 错误回调,播报过程发生错误时触发此回调
-      onError(requestId: string, errorCode: number, errorMessage: string) {
-        console.error(`onError, requestId: ${requestId} errorCode: ${errorCode} errorMessage: ${errorMessage}`);
+  animationImageScale() {
+    animateTo({
+      duration: 100,
+      curve: Curve.EaseOut,
+      iterations: 1,
+      playMode: PlayMode.Normal,
+      onFinish: () => {
+        console.info('scale play end')
+        // 做路径动效
+        this.animationImageMove();
       }
-    };
-    // 设置回调
-    ttsEngine.setListener(speakListener);
-    // 设置播报相关参数
-    let extraParam: Record<string, Object> = {
-      "queueMode": 0,
-      "speed": 1,
-      "volume": 2,
-      "pitch": 1,
-      "languageContext": 'zh-CN',
-      "audioType": "pcm",
-      "soundChannel": 3,
-      "playType": 1
-    }
-    let speakParams: textToSpeech.SpeakParams = {
-      requestId: '123456-a', // requestId在同一实例内仅能用一次,请勿重复设置
-      extraParams: extraParam
-    };
-    // 调用speak播报方法
-    ttsEngine.speak(this.originalText, speakParams);
-  };
+    }, () => {
+      this.imageScaleX = 0.1
+      this.imageScaleY = 0.1
+    })
+  }
 
-  // 查询语种音色信息,以callback形式返回
-  private listVoicesCallback() {
-    // 设置查询相关参数
-    let voicesQuery: textToSpeech.VoiceQuery = {
-      requestId: '123456-b', // requestId在同一实例内仅能用一次,请勿重复设置
-      online: 1
-    };
-    // 调用listVoices方法,以callback返回语种音色查询结果
-    ttsEngine.listVoices(voicesQuery, (err: BusinessError, voiceInfo: textToSpeech.VoiceInfo[]) => {
-      if (!err) {
-        // 接收目前支持的语种音色等信息
-        this.voiceInfo = JSON.stringify(voiceInfo);
-        console.info(`Succeeded in listing voices, voiceInfo is ${voiceInfo}`);
-      } else {
-        console.error(`Failed to list voices. Code: ${err.code}, message: ${err.message}`);
+  animationImageMove() {
+    animateTo({
+      duration: 100, curve: Curve.Linear,
+      onFinish: () => {
+        console.info('move play end')
+        // 购物车图标抖动动效;
+        this.animationImageShake();
       }
-    });
-  };
+    }, () => {
+      this.toggle = !this.toggle // 通过this.toggle变化组件的位置
+    })
+  }
 }

+ 25 - 0
features/feature/src/main/ets/viewModel/MainViewModel.ets

@@ -0,0 +1,25 @@
+import { BasicType, YTAvoid } from "basic"
+
+@ObservedV2
+export class MainViModel{
+  @Trace safeTop: number = AppStorage.get(YTAvoid.SAFE_TOP_KEY) as number
+
+  @Trace scrollIndex: number = 0
+
+  // 功能栏
+  function1: Array<BasicType> = [
+    {
+      src: $r('[basic].media.png_question'),
+      text: '借阅问答',
+      click: () => {}
+    }, {
+      src: $r('[basic].media.png_bookProcedure'),
+      text: '借阅流程',
+      click: () => {}
+    }, {
+      src: $r('[basic].media.png_bookstore'),
+      text: '精选书单',
+      click: () => {}
+    },
+  ]
+}

+ 17 - 18
products/entry/src/main/ets/pages/Index.ets

@@ -12,24 +12,24 @@ struct Index {
   //tabs展示内容
   contentList: BasicType<undefined>[] = [
     {
-      text: '日历',
-      src: $r('app.media.app_icon'),
-      acSrc: $r('app.media.app_icon')
+      text: '首页',
+      src: $r('app.media.icon_home'),
+      acSrc: $r('app.media.icon_home_')
     },
     {
-      text: '黄历',
-      src: $r('app.media.app_icon'),
-      acSrc: $r('app.media.app_icon')
+      text: '分类',
+      src: $r('app.media.icon_classify'),
+      acSrc: $r('app.media.icon_classify_')
     },
     {
-      text: '卡片',
-      src: $r('app.media.app_icon'),
-      acSrc: $r('app.media.app_icon')
+      text: '书包',
+      src: $r('app.media.icon_schoolbag'),
+      acSrc: $r('app.media.icon_schoolbag_')
     },
     {
       text: '我的',
-      src: $r('app.media.app_icon'),
-      acSrc: $r('app.media.app_icon')
+      src: $r('app.media.icon_mine'),
+      acSrc: $r('app.media.icon_mine_')
     }
   ]
   tabsController: TabsController = new TabsController()
@@ -79,7 +79,8 @@ struct Index {
           .justifyContent(FlexAlign.SpaceAround)
           .width('100%')
           .padding({ bottom: this.bottom })
-          .shadow({ offsetY: -13, radius: 16, color: '#0A000000' })
+          // .shadow({ offsetY: -13, radius: 16, color: '#0A000000' })
+          .border({width: { top: 1 }, color: '#E2E2E2'})
         }
         .width('100%')
         .height('100%')
@@ -89,11 +90,9 @@ struct Index {
       .mode(NavigationMode.Stack)
       .hideToolBar(true)
 
-      TkStartAdComp() {
-        Text('占位组件')
-      }
-
-
+      // TkStartAdComp() {
+      //   Text('占位组件')
+      // }
     }
 
   }
@@ -109,7 +108,7 @@ struct Index {
         .fontColor(this.currentIndex == item.index ? $r('[basic].color.main_ac_color_dark') :
         $r('[basic].color.main_na_color'))
     }
-    .margin({ top: 5 })
+    .margin({ top: 18 })
     .onClick(() => {
       this.currentIndex = item.index!
       this.tabsController.changeIndex(this.currentIndex)

+ 17 - 11
products/entry/src/main/ets/pages/PrivacyPage.ets

@@ -8,7 +8,7 @@ import { webview } from '@kit.ArkWeb'
 struct PrivacyPage {
   @StorageProp(YTAvoid.SAFE_TOP_KEY) safeTop: number = 0
   // 倒计时
-  @State time: number = 5
+  @State time: number = 3
 
   private webviewController: WebviewController = new webview.WebviewController()
   private forEach: Array<BasicType> = [
@@ -60,9 +60,10 @@ struct PrivacyPage {
                 renderMode: RenderMode.ASYNC_RENDER // 设置渲染模式
               })
             }
+            .padding(8)
             .height(225)
             .width('100%')
-            .padding(8)
+            .borderRadius(14)
             .border({ width: 1 })
           }
           .alignItems(HorizontalAlign.Start)
@@ -71,19 +72,19 @@ struct PrivacyPage {
         Blank().height(10)
 
         Row(){
-          Text('我不同意返回')
+          Text('我不同意返回')
             .fontSize(16)
             .fontWeight(400)
             .fontColor('#676767')
             .onClick(() => { this._onBack() })
 
-          Text(`我已全部了解${this.time != 0 ? ' ('+this.time+')' : '' }`)
+          Text(`我已全部了解${this.time != 0 ? ' ('+this.time+')' : '' }`)
             .fontSize(18)
             .fontWeight(500)
             .borderRadius(20)
-            .fontColor('#FAFAFA')
+            .fontColor('#000000')
             .enabled(this.time == 0)
-            .backgroundColor(this.time == 0 ?'#7186F9' : '#ffacbaf3')
+            .backgroundColor(this.time == 0 ?'#FECF2F' : '#fffad669')
             .padding({ left: 20, top: 8, right: 20, bottom: 8 })
             .onClick(() => { this._onConfirm() })
         }
@@ -92,15 +93,20 @@ struct PrivacyPage {
         .alignItems(VerticalAlign.Center)
         .justifyContent(FlexAlign.SpaceBetween )
 
-        Row(){
-          Text('*请仔细阅读以上协议内容,点击同意表示您已充分理解并接受协议条款')
-            .fontSize(10)
+        Column(){
+          Text('请仔细阅读以上协议内容')
+            .fontSize(12)
             .fontWeight(400)
-            .fontColor('#F50000')
+            .fontColor('#111111')
+          Text('点击同意表示您已充分理解并接受协议条款')
+            .fontSize(12)
+            .fontWeight(400)
+            .fontColor('#111111')
         }
-        .padding({top: 5})
         .width("100%")
+        .padding({top: 5})
         .justifyContent(FlexAlign.Center)
+        .alignItems(HorizontalAlign.Center)
       }
       .width('100%')
       .layoutWeight(1)

BIN
products/entry/src/main/resources/base/media/icon_classify.png


BIN
products/entry/src/main/resources/base/media/icon_classify_.png


BIN
products/entry/src/main/resources/base/media/icon_home.png


BIN
products/entry/src/main/resources/base/media/icon_home_.png


BIN
products/entry/src/main/resources/base/media/icon_mine.png


BIN
products/entry/src/main/resources/base/media/icon_mine_.png


BIN
products/entry/src/main/resources/base/media/icon_schoolbag.png


BIN
products/entry/src/main/resources/base/media/icon_schoolbag_.png