Prechádzať zdrojové kódy

feat: 完成模范事迹下的UI和逻辑交互、网络请求

YuJing 2 týždňov pred
rodič
commit
974cd3bf81

+ 6 - 0
features/feature/src/main/ets/Apis/ApiUrl.ets

@@ -28,4 +28,10 @@ export class ApiUrl {
    * @method POST
    */
   static getAllHeroicModel = '/api/military/heroicModel/list';
+
+  /**
+   * @description 获取模范事迹分类
+   * @method GET
+   */
+  static getHeroicModelCategory = 'api/military/heroicModel/typeList';
 }

+ 9 - 4
features/feature/src/main/ets/Apis/HistoryApis.ets

@@ -1,5 +1,5 @@
 import { YTRequest } from "basic";
-import { HeroDeedItem, HistoryEventDetail, HistoryTimelineItem, NesResponse, Query } from "../model/Index";
+import { HeroDeedItem, HistoryEventDetail, HistoryTimelineItem, NesResponse, Query, Response } from "../model/Index";
 import { ApiUrl } from "./ApiUrl";
 
 export class HistoryApis {
@@ -19,12 +19,17 @@ export class HistoryApis {
   }
 
   // 献花
-  static giveFlowers(contentId: number): Promise<HeroDeedItem>{
+  static giveFlowers(contentId: string): Promise<HeroDeedItem>{
     return YTRequest.get<HeroDeedItem>(ApiUrl.giveFlowers, { contentId })
   }
 
   // 获取英雄事迹列表
-  static getHeroDeedList(query: Query): Promise<NesResponse>{
-    return YTRequest.post<NesResponse, Query>(ApiUrl.getAllHeroicModel, query)
+  static getHeroDeedList(query: Query): Promise<Response<HeroDeedItem[]>>{
+    return YTRequest.post<Response<HeroDeedItem[]>, Query>(ApiUrl.getAllHeroicModel, query)
+  }
+
+  // 获取模范事迹分类
+  static getHeroicModelCategory(): Promise<string[]>{
+    return YTRequest.get<string[]>(ApiUrl.getHeroicModelCategory)
   }
 }

+ 10 - 0
features/feature/src/main/ets/model/AnimationModel.ets

@@ -0,0 +1,10 @@
+@ObservedV2
+export class Location{
+  @Trace x: number
+  @Trace y: number
+
+  constructor(x: number, y: number){
+    this.x = x
+    this.y = y
+  }
+}

+ 2 - 1
features/feature/src/main/ets/model/Index.ets

@@ -4,7 +4,8 @@ export interface Query{
   page?: number
   type?: number
   pageSizes?: number,
-  total?: number
+  total?: number,
+  times?: string
 }
 
 // 军事咨询列表项

+ 309 - 79
features/feature/src/main/ets/view/ThirdView.ets

@@ -1,96 +1,326 @@
-import { Pet, RDBMapper, RelationalStoreUtils, Test } from 'basic';
+import { HeroDeedItem } from '../model/Index'
+import { ThirdViewModel } from '../viewModel/ThirdViewModel'
+import { Location } from '../model/AnimationModel'
+import { IBestToast } from 'basic'
+import { HistoryApis } from '../Apis/HistoryApis'
 
-@Component
+@ComponentV2
 export struct ThirdView {
-  @State list: Test[] = []
-  @State list2: Pet[] = []
-  id1: number = 0
-  id2: number = 0
-  petMapper: RDBMapper<Pet> = new RDBMapper(Pet)
-  petMapper2: RDBMapper<Test> = new RDBMapper(Test)
+  vm: ThirdViewModel = new ThirdViewModel()
 
   build() {
     Column() {
-      Row() {
-        Button('测试新增')
-          .onClick(() => {
-            RelationalStoreUtils.insert(Test, { name: 'test1', age: 18 }, (id) => {
-              console.log('insert success');
-              this.id1 = id
-              let list = RelationalStoreUtils.getListSync(Test)
-              this.list = list
-              console.log('list:', JSON.stringify(list))
-            })
-          })
+      Row(){
+        Text('英雄人物模范事迹')
+          .fontSize(18)
+          .fontWeight(500)
+          .fontColor('#FF333333')
+      }
+      .width("100%")
+      .padding({top: 28, bottom: 15})
+      .justifyContent(FlexAlign.Center)
 
-        Button('测试修改')
-          .onClick(() => {
-            RelationalStoreUtils.updateItemById(Test, { id: this.id1, name: '测试1修改', age: 20 }, () => {
-              console.log('insert success');
-              let list = RelationalStoreUtils.getListSync(Test)
-              this.list = list
-              console.log('list:', JSON.stringify(list))
-            })
-          })
-        Button('测试删除')
-          .onClick(() => {
-            RelationalStoreUtils.deleteItemById(Test, this.id1)
-            console.log('insert success');
-            let list = RelationalStoreUtils.getListSync(Test)
-            this.list = list
-            console.log('list:', JSON.stringify(list))
+      List({space: 10}){
+        Repeat(this.vm.heroicModelCategory)
+          .each((item) => {
+            ListItem(){
+              Text(item.item)
+                .fontSize(14)
+                .borderRadius(44)
+                .padding({left: 16, top: 6, right: 16, bottom: 6})
+                .fontWeight(this.vm.currentCategory == item.index ? 700 : 400)
+                .fontColor(this.vm.currentCategory == item.index ? '#FFFFFFFF' : '#FF787878')
+                .backgroundColor(this.vm.currentCategory == item.index ? '#FF45E595' : '#FFFFFFFF')
+                .shadow(this.vm.currentCategory == item.index ? null : { color: '#1A000000', radius: 4 })
+            }
+            .onClick(() => { this.vm.changeCategory(item.index) })
           })
+          .key((item) => item)
       }
-      .width('100%')
-      .justifyContent(FlexAlign.SpaceAround)
-      .margin({ bottom: 30 })
-
-      Text(JSON.stringify(this.list))
-        .font({ size: 20 })
-        .margin({ bottom: 20 })
-
-      Row() {
-        Button('测试新增2')
-          .onClick(() => {
-            this.petMapper.insert({ name: 'test1', tag: '标签' }, (id: number) => {
-              console.log('insert success');
-              this.id2 = id
-              let list = this.petMapper.getListSync()
-              this.list2 = list
-              console.log('list:', JSON.stringify(list))
-            })
-          })
+      .height(32)
+      .width("100%")
+      .scrollBar(BarState.Off)
+      .listDirection(Axis.Horizontal)
 
-        Button('测试修改2')
-          .onClick(() => {
-            this.petMapper.updateItemById({ id: this.id2, name: '测试1修改', tag: '标签2' }, () => {
-              console.log('insert success');
-              let list = this.petMapper.getListSync()
-              this.list2 = list
-              console.log('list:', JSON.stringify(list))
+      Column(){
+        List({space: 20}){
+          Repeat(this.vm.dataSource)
+            .each((item) => {
+              ListItem(){
+                HeroItem({data: item.item, flowerEvent: (i: HeroDeedItem) =>{ this.vm.onFlower(i, item.index) }})
+              }
             })
-          })
-        Button('测试删除2')
-          .onClick(() => {
-            this.petMapper.deleteItemByIdSync(this.id2)
-            console.log('insert success');
-            let list = this.petMapper.getListSync()
-            this.list2 = list
-            console.log('list:', JSON.stringify(list))
-          })
+            .key((item) => JSON.stringify(item))
+        }
+        .width("100%")
+        .height('100%')
+        .scrollBar(BarState.Off)
+        .onReachEnd(() => { if(this.vm.dataSource.length != 0) this.vm.getHeroDeedList(false)  })
       }
-      .width('100%')
-      .justifyContent(FlexAlign.SpaceAround)
-      .margin({ bottom: 30 })
+      .width("100%")
+      .layoutWeight(1)
+    }
+    .width('100%')
+    .height('100%')
+    .padding({left: 17, right: 17, top: this.vm.safeTop})
+    .linearGradient({colors: [['#FFF4FFF1', 0], ['#FFFFFFFF', 0.8]]})
+  }
+}
 
-      Text(JSON.stringify(this.list2))
-        .font({ size: 20 })
-        .margin({ bottom: 20 })
 
+// 英雄人物事迹 Item
+@ComponentV2
+struct HeroItem{
+  @Param @Require data: HeroDeedItem
+
+  @Event flowerEvent: (data: HeroDeedItem) => void
+
+  // 详情是否展开 - 默认收起
+  @Local isOpen: boolean = false
+  @Local height_: number = 207
+  // 开始撒花动画
+  @Local flowerAnimation: boolean = false
+
+  // 花瓣的坐标数组
+  @Local flowerCoordinates: Array<Location> = []
+
+  // 打开、关闭 详情
+  changeDetail(){
+    this.getUIContext().animateTo({ duration: 300 }, () =>{
+      this.isOpen = !this.isOpen
+    })
+  }
+
+  // 献花
+  async onFlower(){
+    try {
+      let ans = await HistoryApis.giveFlowers(this.data.contentId!)
+      console.log(`ans = ${JSON.stringify(ans)}`)
+      this.flowerEvent(ans)
+      this.startFlowerAnimation()
+    } catch (e) {
+      // IBestToast.show('献花失败')
+    }
+  }
+
+  // 开启献花动画
+  startFlowerAnimation(){
+    IBestToast.show(`感谢您为${this.data?.heroName}英雄献花`)
+    this.generateFlowerCoordinates(true)
+    setTimeout(() => {
+      this.generateFlowerCoordinates(false)
+    }, 100)
+  }
+
+  // 生成花瓣坐标
+  generateFlowerCoordinates(isStart: boolean = true){
+    if(isStart){
+      this.flowerCoordinates = []
+      let len = this.isOpen ? 10 : 7
+      for(let i = 0; i < len; i++){
+        let x = 10 + Math.random() * 70
+        let y = 10 + Math.random() * (this.height_ - 40)
+        let location: Location = new Location(x, y)
+        this.flowerCoordinates.push(location)
+      }
+      this.flowerAnimation = true
+    } else {
+      for (let i = 0; i < this.flowerCoordinates.length; i++) {
+        let f = new Location(this.flowerCoordinates[i].x, this.flowerCoordinates[i].y)
+        f.x -= 5
+        f.y += 20
+        this.getUIContext().animateTo({ duration: 600 }, () => {
+          this.flowerCoordinates.splice(i, 1, f)
+        })
+      }
+      setTimeout(() => {
+        this.flowerAnimation = false
+      }, 800)
+    }
+  }
+
+  build() {
+    Stack(){
+      Column(){
+        Column(){
+          Row(){
+            Text(this.data?.heroName)
+              .fontSize(22)
+              .fontWeight(800)
+              .fontColor('#FF333333')
+
+            Text(this.data?.period)
+              .fontSize(14)
+              .fontWeight(400)
+              .fontColor('#FF333333')
+          }
+          .width("100%")
+          .justifyContent(FlexAlign.SpaceBetween)
+
+          Row(){
+            Text(this.data?.description)
+              .fontSize(14)
+              .width("100%")
+              .fontWeight(400)
+              .fontColor('#FF333333')
+          }
+          .width("100%")
+          .padding({top: 29})
+
+          Row(){
+            Row({space: 8}){
+              Image($r('app.media.icon_flower'))
+                .width(38)
+                .aspectRatio(1)
+
+              Text(){
+                Span(this.data?.flowersNum ?? '0')
+                  .fontSize(20)
+                  .fontWeight(400)
+                  .fontColor('#FFFF7B00')
+
+                Span('朵鲜花')
+                  .fontSize(12)
+                  .fontWeight(400)
+                  .fontColor('#FF333333')
+              }
+            }
+
+            Row(){
+              Text('献花')
+                .fontSize(14)
+                .fontWeight(400)
+                .fontColor('#FFFFFFFF')
+            }
+            .width(85)
+            .height(30)
+            .borderRadius(8)
+            .alignItems(VerticalAlign.Center)
+            .justifyContent(FlexAlign.Center)
+            .linearGradient({colors: [['#FFFFCA00', 0], ['#FFFF9D01', 0.5]], angle: 90})
+            .onClick(() => { this.onFlower() })
+          }
+          .width("100%")
+          .padding({top: 13, bottom: 30})
+          .justifyContent(FlexAlign.SpaceBetween)
+        }
+        .background(this.bgc(), {align: Alignment.Top})
+        .padding({left: 13, right: 13, top: 5})
+
+        Column(){
+          Column({space: 6}){
+            Column(){
+              Text('英雄事迹')
+                .fontSize(14)
+                .fontWeight(500)
+                .fontColor('#333333')
+                .zIndex(999)
+              Image($r('app.media.icon_unLine'))
+                .width(56)
+                .height(13)
+                .offset({ y: -5})
+                .zIndex(0)
+                .visibility(this.isOpen ? Visibility.Visible : Visibility.Hidden)
+            }
+            .width("100%")
+            .justifyContent(FlexAlign.Center)
+            .alignItems(HorizontalAlign.Start)
+
+            Text(this.data.heroicDeeds)
+              .width("100%")
+              .fontSize(12)
+              .fontWeight(400)
+              .lineHeight(20)
+
+            Column(){
+              Text('精神内涵')
+                .fontSize(14)
+                .fontWeight(500)
+                .fontColor('#333333')
+                .zIndex(999)
+              Image($r('app.media.icon_unLine'))
+                .width(56)
+                .height(13)
+                .offset({ y: -5})
+                .zIndex(0)
+                .visibility(this.isOpen ? Visibility.Visible : Visibility.Hidden)
+            }
+            .width("100%")
+            .justifyContent(FlexAlign.Center)
+            .alignItems(HorizontalAlign.Start)
+
+            Row({space: 12}){
+              ForEach(this.data.type?.split('、'), (item: string, index) => {
+                Text(item)
+                  .fontSize(12)
+                  .fontWeight(400)
+                  .borderRadius(5)
+                  .fontColor('#52886F')
+                  .backgroundColor('#F2F2F2')
+                  .padding({left: 13, top: 6, right: 13, bottom: 6})
+              })
+            }
+            .width("100%")
+            .justifyContent(FlexAlign.Start)
+            .padding({bottom: 37})
+          }
+          .height(this.isOpen ? '' : 0)
+          // .backgroundColor(Color.Black)
+
+          Row({space: 7}){
+            Text(this.isOpen ? '收起详情' : '展开详情')
+              .fontSize(10)
+              .fontWeight(400)
+              .fontColor('#FF52886F')
+
+            Image($r('app.media.icon_heroOpen'))
+              .width(12)
+              .aspectRatio(1)
+              .rotate({angle: this.isOpen ? 180 : 0})
+          }
+          .onClick(() => { this.changeDetail() })
+        }
+        .padding({left: 13, right: 13})
+      }
+      .width("100%")
+      .justifyContent(FlexAlign.Start)
+      .alignItems(HorizontalAlign.Center)
+      .onAreaChange((o, n) => {
+        if(this.isOpen){
+          this.height_ = Math.max(this.height_, n.height as number)
+        } else {
+          this.height_ = Math.min(this.height_, n.height as number)
+        }
+        console.log(`this.height_ = ${JSON.stringify(this.height_)}`)
+      })
+
+
+      if(this.flowerAnimation) {
+        Column(){
+          Repeat(this.flowerCoordinates)
+            .each((item) => {
+              Image($r('app.media.icon_hero_flower'))
+                .width(36)
+                .aspectRatio(1)
+                .position({ x: `${item.item.x}%`, y: item.item.y })
+            })
+            .key((item) => JSON.stringify(item))
+        }
+        .width("100%")
+        .height(this.height_)
+      }
     }
-    .justifyContent(FlexAlign.Center)
-    .alignItems(HorizontalAlign.Center)
-    .height('100%')
     .width('100%')
+    .borderRadius(8)
+    .padding({bottom: 8})
+    .backgroundColor(Color.White)
+    .shadow({ color: '#1A000000', radius: 4 })
+  }
+
+  @Builder
+  bgc(){
+    Image($r('app.media.img_heroBgImg'))
+      .width("100%")
+      .height(207)
   }
 }

+ 69 - 0
features/feature/src/main/ets/viewModel/ThirdViewModel.ets

@@ -0,0 +1,69 @@
+import { YTAvoid } from 'basic'
+import { HistoryApis } from '../Apis/HistoryApis'
+import { HeroDeedItem, Query } from '../model/Index'
+
+@ObservedV2
+export class ThirdViewModel{
+  @Trace safeTop: number = 0
+
+  @Trace dataSource: Array<HeroDeedItem> = []
+  @Trace heroicModelCategory: Array<string> = ['全部']
+  @Trace currentCategory: number = 0
+
+  query: Query = {
+    page: 1,
+    pageSizes: 30
+  }
+
+  constructor() {
+    this.safeTop = AppStorage.get(YTAvoid.SAFE_TOP_KEY) as number
+
+    this.getHeroicModelCategory()
+    this.getHeroDeedList()
+  }
+
+  // 修改选中的类型
+  changeCategory(index: number){
+    this.currentCategory = index
+
+    if(index == 0){
+      this.query.times = undefined
+    } else {
+      this.query.times = this.heroicModelCategory[this.currentCategory]
+    }
+
+    this.getHeroDeedList()
+  }
+
+  onFlower(i:HeroDeedItem, index: number){
+    this.dataSource.splice(index, 1, i)
+  }
+
+  // 获取英雄事迹列表
+  async getHeroDeedList(isReload: boolean = true){
+    if(isReload) {
+      this.query.page = 1
+    } else {
+      if(this.dataSource.length >= this.query.total!) return
+      this.query.page!++
+    }
+
+
+    let ans = await HistoryApis.getHeroDeedList(this.query)
+
+    if(isReload){
+      this.dataSource = ans.records ?? []
+    } else {
+      this.dataSource.push(...ans.records ?? [])
+    }
+
+    this.query.total = Number.parseInt(ans.total ?? '0')
+  }
+
+
+  // 获取模范事迹分类
+  async getHeroicModelCategory(){
+    let ans = await HistoryApis.getHeroicModelCategory()
+    this.heroicModelCategory.push(...ans)
+  }
+}

BIN
features/feature/src/main/resources/base/media/icon_flower.png


BIN
features/feature/src/main/resources/base/media/icon_heroOpen.png


BIN
features/feature/src/main/resources/base/media/icon_hero_flower.png


BIN
features/feature/src/main/resources/base/media/icon_unLine.png


BIN
features/feature/src/main/resources/base/media/img_heroBgImg.png