yangsunyue_wd

Merge branch 'main' of http://192.168.1.42/developOne/harmonyPool

# Conflicts:
#	PeopleDaily_Harmony/wdComponent/src/main/ets/components/PageComponent.ets
#	PeopleDaily_Harmony/wdComponent/src/main/resources/base/element/color.json
Showing 86 changed files with 2046 additions and 199 deletions
1 import UIAbility from '@ohos.app.ability.UIAbility'; 1 import UIAbility from '@ohos.app.ability.UIAbility';
2 import hilog from '@ohos.hilog'; 2 import hilog from '@ohos.hilog';
3 import window from '@ohos.window'; 3 import window from '@ohos.window';
4 - 4 +import { AppContext } from 'wdKit';
5 export default class EntryAbility extends UIAbility { 5 export default class EntryAbility extends UIAbility {
6 onCreate(want, launchParam) { 6 onCreate(want, launchParam) {
7 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 7 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  8 + AppContext.init(this.context)
8 } 9 }
9 10
10 onDestroy() { 11 onDestroy() {
  1 +import { ColumnPageComponent } from 'wdComponent';
  2 +
  3 +import { Logger } from 'wdKit';
  4 +
  5 +const TAG = 'ColumnPage';
  6 +
  7 +/**
  8 + * 二级栏目页面,显示展排数据(comp list)
  9 + */
  10 +@Entry
  11 +@Component
  12 +struct ColumnPage {
  13 + aboutToAppear() {
  14 + Logger.info(TAG, `aboutToAppear `);
  15 + }
  16 +
  17 + aboutToDisappear() {
  18 + Logger.info(TAG, 'aboutToDisappear');
  19 + }
  20 +
  21 + onPageShow() {
  22 + Logger.info(TAG, 'onPageShow');
  23 + }
  24 +
  25 + onPageHide() {
  26 + Logger.info(TAG, 'onPageHide');
  27 + }
  28 +
  29 + onBackPress() {
  30 + Logger.info(TAG, 'onBackPress');
  31 + }
  32 +
  33 + build() {
  34 + Column() {
  35 + // TODO 跳转获取id
  36 + ColumnPageComponent({ pageId: "20011", channelId: "2001"});
  37 + }
  38 + }
  39 +}
1 { 1 {
2 "src": [ 2 "src": [
3 "pages/Index", 3 "pages/Index",
4 - "pages/MainPage" 4 + "pages/MainPage",
  5 + "pages/ColumnPage"
5 ] 6 ]
6 } 7 }
1 -  
2 export { PageViewModel } from "./viewmodel/PageViewModel" 1 export { PageViewModel } from "./viewmodel/PageViewModel"
3 2
4 -export { EmptyComponent } from "./components/EmptyComponent" 3 +export { EmptyComponent } from "./components/view/EmptyComponent"
  4 +
  5 +export { DemoPreviewerComponent } from "./components/DemoPreviewerComponent"
  6 +
  7 +export { ErrorComponent } from "./components/view/ErrorComponent"
  8 +
  9 +export { LoadingComponent } from "./components/view/LoadingComponent"
  10 +
  11 +export { PageComponent } from "./components/page/PageComponent"
  12 +
  13 +export { BottomNavigationComponent } from "./components/page/BottomNavigationComponent"
5 14
6 -export { ErrorComponent } from "./components/ErrorComponent" 15 +export { TopNavigationComponent } from "./components/page/TopNavigationComponent"
7 16
8 -export { LoadingComponent } from "./components/LoadingComponent" 17 +export { LabelComponent } from "./components/view/LabelComponent"
9 18
10 -export { PageComponent } from "./components/PageComponent" 19 +export { SmallVideoCardComponent } from "./components/view/SmallVideoCardComponent"
11 20
12 -export { BottomNavigationComponent } from "./components/BottomNavigationComponent" 21 +export { BannerComponent } from "./components/view/BannerComponent"
13 22
14 -export { TopNavigationComponent } from "./components/TopNavigationComponent" 23 +export { ColumnPageComponent } from "./components/page/ColumnPageComponent"
15 24
16 -export { LabelComponent } from "./components/LabelComponent"  
  1 +import { CommonConstants, CompStyle } from 'wdConstant';
  2 +import { CompDTO } from '../repository/bean/CompDTO';
  3 +import { BannerComponent } from './view/BannerComponent';
  4 +import { LabelComponent } from './view/LabelComponent';
  5 +import { TitleAbbrComponent } from './view/TitleAbbrComponent';
  6 +import { TitleAllComponent } from './view/TitleAllComponent';
  7 +
  8 +/**
  9 + * comp适配器.
  10 + */
  11 +@Component
  12 +export struct CompParser {
  13 + compDTO: CompDTO = {} as CompDTO;
  14 + compIndex: number = 0;
  15 +
  16 + build() {
  17 + this.componentBuilder(this.compDTO, this.compIndex);
  18 + }
  19 +
  20 + @Builder
  21 + componentBuilder(compDTO: CompDTO, compIndex: number) {
  22 + if (compDTO.compStyle === CompStyle.Label_03) {
  23 + LabelComponent({ compDTO: compDTO })
  24 + } else if (compDTO.compStyle === CompStyle.Title_Abbr_01) {
  25 + TitleAbbrComponent({ compDTO: compDTO })
  26 + } else if (compDTO.compStyle === CompStyle.Title_All_01) {
  27 + TitleAllComponent({ compDTO: compDTO })
  28 + } else if (compDTO.compStyle === CompStyle.Carousel_Layout_01) {
  29 + BannerComponent({ compDTO: compDTO })
  30 + } else {
  31 + // todo:组件未实现 / Component Not Implemented
  32 + Text(compDTO.compStyle)
  33 + .width(CommonConstants.FULL_PARENT)
  34 + .padding(10)
  35 + // .backgroundColor(Color.Brown) // 展示本页未实现的compStyle
  36 + }
  37 + }
  38 +}
  1 +import { CompDTO } from '../repository/bean/CompDTO';
  2 +import { ContentDTO } from '../repository/bean/ContentDTO';
  3 +
  4 +const FULL_PARENT: string = '100%';
  5 +const COLUMNS_TEMPLATE_ONE: string = '1fr';
  6 +const COLUMNS_TEMPLATE_TWO: string = '1fr 1fr';
  7 +const COLUMNS_TEMPLATE_THREE: string = '1fr 1fr 1fr';
  8 +const COLUMNS_TEMPLATE_FOUR: string = '1fr 1fr 1fr 1fr';
  9 +const COLUMNS_TEMPLATE_SIX: string = '1fr 1fr 1fr 1fr 1fr 1fr';
  10 +
  11 +const TAG = 'DemoPreviewerComponent';
  12 +
  13 +/**
  14 + * xxxx 布局及功能说明
  15 + *
  16 + * 【查看ArkUI预览效果】在线参考文档:
  17 + * https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/previewer-0000001054328973-V3#section146052489820
  18 + */
  19 +@Entry
  20 +@Component
  21 +export struct DemoPreviewerComponent {
  22 + @State compDTO: CompDTO = {
  23 + compStyle: 'compStyle3',
  24 + operDataList: [
  25 + {
  26 + title: 'title0',
  27 + description: "description0",
  28 + coverUrl: 'https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231208/image/display/d4496925a1264a749975ae9b01a4ef46.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg'
  29 + } as ContentDTO,
  30 + {
  31 + title: 'title1 title1 title1 title1 title1 title1 title1 title1 title1',
  32 + description: "description1",
  33 + "coverUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20240104/image/display/c4a9b526e0994d1bbd3ac8450f5cfc6c.jpg?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
  34 + } as ContentDTO,
  35 + {
  36 + title: 'title2',
  37 + description: "description2",
  38 + "coverUrl": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231206/image/live/bbe6d821e92b48919d90c7dadfd1f05a.jpg?x-oss-process=image/resize,l_850/auto-orient,1/quality,q_95/format,jpg",
  39 + } as ContentDTO,
  40 + {
  41 + title: 'title3',
  42 + description: "description3",
  43 + coverUrl: 'https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231109/image/live/102e6eb9356b4ef19405b04c1f6ff875.png?x-oss-process=image/resize,l_850/auto-orient,1/quality,q_95/format,jpg'
  44 + } as ContentDTO,
  45 + {
  46 + title: 'title4',
  47 + description: "description4",
  48 + "coverUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231218/image/display/62bdbbb35dbd45689e00790c81f04c4b.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
  49 + } as ContentDTO,
  50 + {
  51 + title: 'title5',
  52 + description: "description5",
  53 + "coverUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231218/image/display/f79bbaa5a33b4bd88176071c4f797ff6.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
  54 + } as ContentDTO,
  55 + {
  56 + title: 'title6',
  57 + description: "description6",
  58 + "coverUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231218/image/display/2c1d917009584ce2bb4a35cbb3a860a0.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
  59 + } as ContentDTO,
  60 + {
  61 + title: 'title7',
  62 + description: "description7",
  63 + "coverUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231222/image/display/117dc516ca5c42d5843c0d32050c9fc6.jpeg?x-oss-process=image/resize,w_240/quality,q_90/format,jpg",
  64 + } as ContentDTO,
  65 + {
  66 + title: 'title8',
  67 + description: "description8",
  68 + "coverUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231228/image/display/90a2db4077d44a1f887f068fc659d977.jpeg?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
  69 + } as ContentDTO
  70 + ]
  71 + } as CompDTO
  72 +
  73 + aboutToAppear() {
  74 + // this.compDTO = {
  75 + // compStyle: 'compStyle3',
  76 + // operDataList: [
  77 + // {
  78 + // title: 'title0',
  79 + // description: "description0",
  80 + // coverUrl: 'https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231208/image/display/d4496925a1264a749975ae9b01a4ef46.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg'
  81 + // } as ContentDTO
  82 + // ]
  83 + // } as CompDTO
  84 +
  85 + this.compDTO.operDataList[0].title = 'title_first_0'
  86 + }
  87 +
  88 + build() {
  89 + Grid() {
  90 + ForEach(this.compDTO.operDataList, (item: ContentDTO, index: number) => {
  91 + GridItem() {
  92 + this.gridItemView(item, index)
  93 + }
  94 + }, (item: ContentDTO, index: number) => JSON.stringify(item))
  95 + }
  96 + .height(FULL_PARENT)
  97 + .margin({ top: 10, bottom: 10, left: $r('app.float.main_margin'), right: $r('app.float.main_margin') })
  98 + .columnsTemplate(COLUMNS_TEMPLATE_TWO)
  99 + .columnsGap(4)
  100 + .rowsGap(2)
  101 + }
  102 +
  103 + /**
  104 + * 布局描述
  105 + *
  106 + * @param ContentDTO item 组件项
  107 + * @param index
  108 + */
  109 + @Builder
  110 + gridItemView(item: ContentDTO, index: number) {
  111 + Column() {
  112 + Image(item.coverUrl)
  113 + .width(FULL_PARENT)// .aspectRatio(3 / 4) // 宽/高比:纵向
  114 + // .aspectRatio(1 / 1) // 宽/高比:正方形
  115 + .aspectRatio(16 / 9)// 宽/高比:横向
  116 + .margin({ top: 8 })
  117 + .borderRadius(10)
  118 +
  119 + Text(item.title)
  120 + .width(FULL_PARENT)
  121 + .margin({ top: 4, left: 2, right: 2, bottom: 4 })
  122 + .backgroundColor(Color.White)
  123 + .fontWeight(FontWeight.Bold)// .textAlign(TextAlign.Center)
  124 + .fontSize($r('app.float.font_size_12'))
  125 + .fontColor('#808080')
  126 + .maxLines(1)
  127 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  128 + }
  129 + .width(FULL_PARENT)
  130 + .backgroundColor(Color.Yellow)
  131 + .justifyContent(FlexAlign.Center)
  132 + .onClick(() => {
  133 + console.info(TAG, `gridItemView onClick, index: ${index}`);
  134 + // MGRouterRule.jumpWithAction(item.action)
  135 + })
  136 + }
  137 +}
1 -import { CommonConstants, CompStyle, ViewType } from 'wdConstant';  
2 -import { LazyDataSource, Logger } from 'wdKit';  
3 -import { CompDTO } from '../repository/bean/CompDTO';  
4 -import { PageViewModel } from '../viewmodel/PageViewModel';  
5 -import { EmptyComponent } from './EmptyComponent';  
6 -import { ErrorComponent } from './ErrorComponent';  
7 -import { LabelComponent } from './LabelComponent';  
8 -import { LoadingComponent } from './LoadingComponent';  
9 -import { TitleAbbrComponent } from './TitleAbbrComponent';  
10 -import { TitleAllComponent } from './TitleAllComponent';  
11 -import { HorizontalStrokeCardThreeTwoRadioForOneComponent } from './HorizontalStrokeCardThreeTwoRadioForOneComponent';  
12 -import { HorizontalStrokeCardThreeTwoRadioForTwoComponent } from './HorizontalStrokeCardThreeTwoRadioForTwoComponent';  
13 -import { HorizontalStrokeCardThreeTwoRadioForMoreComponent } from './HorizontalStrokeCardThreeTwoRadioForMoreComponent';  
14 -  
15 -  
16 -const TAG = 'PageComponent';  
17 -  
18 -@Component  
19 -export struct PageComponent {  
20 - @State viewType: number = ViewType.LOADED;  
21 - // Group数据及子组件数据  
22 - @State compList: LazyDataSource<CompDTO> = new LazyDataSource();  
23 - @State currentTopNavSelectedIndex: number = 0;  
24 -  
25 - build() {  
26 - if (this.viewType == ViewType.LOADING) {  
27 - LoadingComponent()  
28 - } else if (this.viewType == ViewType.ERROR) {  
29 - ErrorComponent()  
30 - } else if (this.viewType == ViewType.EMPTY) {  
31 - EmptyComponent()  
32 - } else {  
33 - List() {  
34 - LazyForEach(this.compList, (compDTO: CompDTO, compIndex: number) => {  
35 - ListItem() {  
36 - Column() {  
37 - this.componentBuilder(compDTO, compIndex)  
38 - }  
39 - }  
40 - })  
41 - }  
42 - .cachedCount(5)  
43 - .height(CommonConstants.FULL_PARENT)  
44 - }  
45 - }  
46 -  
47 - @Builder  
48 - componentBuilder(compDTO: CompDTO, compIndex: number) {  
49 - if (compDTO.compStyle === CompStyle.Label_03) {  
50 - LabelComponent({ compDTO: compDTO })  
51 - } else if (compDTO.compStyle === CompStyle.Title_Abbr_01) {  
52 - TitleAbbrComponent({ compDTO: compDTO })  
53 - } else if (compDTO.compStyle === CompStyle.Title_All_01) {  
54 - TitleAllComponent({ compDTO: compDTO })  
55 - } else {  
56 - // todo:组件未实现 / Component Not Implemented  
57 - Text(compDTO.compStyle)  
58 - .width(CommonConstants.FULL_PARENT)  
59 - .padding(10)  
60 - // .backgroundColor(Color.Brown) // 展示本页未实现的compStyle  
61 - }  
62 - }  
63 -  
64 - async aboutToAppear() {  
65 - Logger.info(TAG, `aboutToAppear, this.pageId: ${this.viewType} this.currentTopNavSelectedIndex: ${this.currentTopNavSelectedIndex}`);  
66 - if (this.currentTopNavSelectedIndex === 1) { // 顶导tab的第0个item是【热点】,第1个item是【推荐】  
67 - this.compList.replaceAll()  
68 - let pageDto = await PageViewModel.getPageData2(getContext(this))  
69 - if (pageDto && pageDto.compList) {  
70 - this.compList.push(...pageDto.compList)  
71 - }  
72 - } else {  
73 - let pageDto = await PageViewModel.getPageData1(getContext(this))  
74 - if (pageDto && pageDto.compList) {  
75 - this.compList.push(...pageDto.compList)  
76 - }  
77 - }  
78 - }  
79 -}  
80 -  
1 import { BottomNavi, CommonConstants } from 'wdConstant'; 1 import { BottomNavi, CommonConstants } from 'wdConstant';
2 -import { LazyDataSource, Logger } from 'wdKit'; 2 +import { Logger } from 'wdKit';
3 import { TopNavigationComponent } from './TopNavigationComponent'; 3 import { TopNavigationComponent } from './TopNavigationComponent';
4 -import { PageComponent } from './PageComponent';  
5 -import { BottomNavDTO } from '../repository/bean/BottomNavDTO';  
6 -import { PageViewModel } from '../Index'; 4 +import { BottomNavDTO } from '../../repository/bean/BottomNavDTO';
  5 +import { UIUtils } from '../../repository/UIUtils';
  6 +import { MinePageComponent } from './MinePageComponent';
  7 +import PageViewModel from '../../viewmodel/PageViewModel';
7 8
8 const TAG = 'BottomNavigationComponent'; 9 const TAG = 'BottomNavigationComponent';
9 10
@@ -28,13 +29,12 @@ export struct BottomNavigationComponent { @@ -28,13 +29,12 @@ export struct BottomNavigationComponent {
28 */ 29 */
29 readonly SIXTY_OPACITY: number = 0.6; 30 readonly SIXTY_OPACITY: number = 0.6;
30 31
31 -  
32 async aboutToAppear() { 32 async aboutToAppear() {
33 Logger.info(TAG, `aboutToAppear currentNavIndex: ${this.currentNavIndex}`); 33 Logger.info(TAG, `aboutToAppear currentNavIndex: ${this.currentNavIndex}`);
34 let bottomNav = await PageViewModel.getBottomNavData(getContext(this)) 34 let bottomNav = await PageViewModel.getBottomNavData(getContext(this))
35 - if (bottomNav) {  
36 - Logger.info(TAG, `aboutToAppear, bottomNav.length: ${bottomNav.length}`);  
37 - this.bottomNavList = bottomNav 35 + if (bottomNav && bottomNav.bottomNavList != null) {
  36 + Logger.info(TAG, `aboutToAppear, bottomNav.length: ${bottomNav.bottomNavList.length}`);
  37 + this.bottomNavList = bottomNav.bottomNavList
38 } 38 }
39 } 39 }
40 40
@@ -47,8 +47,9 @@ export struct BottomNavigationComponent { @@ -47,8 +47,9 @@ export struct BottomNavigationComponent {
47 ForEach(this.bottomNavList, (navItem: BottomNavDTO, index: number) => { 47 ForEach(this.bottomNavList, (navItem: BottomNavDTO, index: number) => {
48 TabContent() { 48 TabContent() {
49 Column() { 49 Column() {
50 - if (navItem.topNavChannelList && navItem.topNavChannelList.length == 0 && navItem.name == '我的') {  
51 - PageComponent({ compList: new LazyDataSource() }) // todo:我的页面组件数据列表 50 + if (UIUtils.isMine(navItem)) {
  51 + // 我的页面组件数据列表
  52 + MinePageComponent()
52 } else { 53 } else {
53 TopNavigationComponent({ topNavList: navItem.topNavChannelList }) 54 TopNavigationComponent({ topNavList: navItem.topNavChannelList })
54 } 55 }
  1 +import { PageComponent } from './PageComponent';
  2 +
  3 +const TAG = 'ColumnPageComponent';
  4 +
  5 +/**
  6 + * 二级栏目页面,展排数据
  7 + */
  8 +@Component
  9 +export struct ColumnPageComponent {
  10 + @State currentTopNavSelectedIndex: number = 0;
  11 + pageId: string = "";
  12 + channelId: string = "";
  13 +
  14 + build() {
  15 + PageComponent({
  16 + currentTopNavSelectedIndex: $currentTopNavSelectedIndex,
  17 + navIndex: this.currentTopNavSelectedIndex,
  18 + pageId: this.pageId,
  19 + channelId: this.channelId,
  20 + });
  21 +
  22 + }
  23 +}
  24 +
  1 +import { RefreshConstants } from '../../utils/RefreshConstants';
  2 +import { RefreshLayoutBean } from './RefreshLayoutBean';
  3 +
  4 +/**
  5 + * Custom layout to show refresh or load.
  6 + */
  7 +@Component
  8 +export default struct CustomLayout {
  9 + @ObjectLink refreshBean: RefreshLayoutBean;
  10 +
  11 + build() {
  12 + Row() {
  13 + Image(this.refreshBean.imageSrc)
  14 + .width(RefreshConstants.RefreshLayout_IMAGE_WIDTH)
  15 + .height(RefreshConstants.RefreshLayout_IMAGE_HEIGHT)
  16 +
  17 + Text(this.refreshBean.textValue)
  18 + .margin({
  19 + left: RefreshConstants.RefreshLayout_TEXT_MARGIN_LEFT,
  20 + bottom: RefreshConstants.RefreshLayout_TEXT_MARGIN_BOTTOM
  21 + })
  22 + .fontSize(RefreshConstants.RefreshLayout_TEXT_FONT_SIZE)
  23 + .textAlign(TextAlign.Center)
  24 + }
  25 + .clip(true)
  26 + .width(RefreshConstants.FULL_WIDTH)
  27 + .justifyContent(FlexAlign.Center)
  28 + .height(this.refreshBean.heightValue)
  29 + }
  30 +}
  1 +import CustomRefreshLoadLayout from './CustomRefreshLoadLayout';
  2 +import { RefreshLayoutBean } from './RefreshLayoutBean';
  3 +
  4 +/**
  5 + * The load more layout component.
  6 + */
  7 +@Component
  8 +export default struct LoadMoreLayout {
  9 + @ObjectLink refreshBean: RefreshLayoutBean;
  10 +
  11 + build() {
  12 + Column() {
  13 + if (this.refreshBean.isVisible) {
  14 + CustomRefreshLoadLayout({
  15 + refreshBean: new RefreshLayoutBean(this.refreshBean.isVisible,
  16 + this.refreshBean.imageSrc, this.refreshBean.textValue, this.refreshBean.heightValue)
  17 + })
  18 + } else {
  19 + CustomRefreshLoadLayout({
  20 + refreshBean: new RefreshLayoutBean(this.refreshBean.isVisible,
  21 + this.refreshBean.imageSrc, this.refreshBean.textValue, 0)
  22 + })
  23 + }
  24 + }
  25 + }
  26 +}
  1 +const TAG = 'PageComponent';
  2 +
  3 +/**
  4 + * 我的页面
  5 + */
  6 +@Component
  7 +export struct MinePageComponent {
  8 + // TODO 待完善
  9 + build() {
  10 + Text('我的页面')
  11 + }
  12 +}
  13 +
  1 +import { RefreshConstants } from '../../utils/RefreshConstants'
  2 +
  3 +/**
  4 + * The No more data layout component.
  5 + */
  6 +@Component
  7 +export default struct NoMoreLayout {
  8 + build() {
  9 + Row() {
  10 + Text($r('app.string.footer_text'))
  11 + .margin({ left: RefreshConstants.NoMoreLayoutConstant_NORMAL_PADDING })
  12 + .fontSize(RefreshConstants.NoMoreLayoutConstant_TITLE_FONT)
  13 + .textAlign(TextAlign.Center)
  14 + }
  15 + .width(RefreshConstants.FULL_WIDTH)
  16 + .justifyContent(FlexAlign.Center)
  17 + .height(RefreshConstants.CUSTOM_LAYOUT_HEIGHT)
  18 + }
  19 +}
  1 +import { CommonConstants, ViewType } from 'wdConstant';
  2 +import { Logger } from 'wdKit';
  3 +import { CompDTO } from '../../repository/bean/CompDTO';
  4 +import PageViewModel from '../../viewmodel/PageViewModel';
  5 +import { EmptyComponent } from '../view/EmptyComponent';
  6 +import { ErrorComponent } from '../view/ErrorComponent';
  7 +import PageModel from '../../viewmodel/PageModel';
  8 +import { listTouchEvent } from '../../utils/PullDownRefresh';
  9 +import RefreshLayout from './RefreshLayout';
  10 +import { RefreshLayoutBean } from './RefreshLayoutBean';
  11 +import NoMoreLayout from './NoMoreLayout';
  12 +import LoadMoreLayout from './LoadMoreLayout';
  13 +import CustomRefreshLoadLayout from './CustomRefreshLoadLayout';
  14 +import { CompParser } from '../CompParser';
  15 +
  16 +const TAG = 'PageComponent';
  17 +
  18 +@Component
  19 +export struct PageComponent {
  20 + @State private pageModel: PageModel = new PageModel();
  21 + navIndex: number = 0;
  22 + pageId: string = "";
  23 + channelId: string = "";
  24 + @Link @Watch('onChange') currentTopNavSelectedIndex: number
  25 +
  26 + build() {
  27 + Column() {
  28 + if (this.pageModel.viewType == ViewType.LOADING) {
  29 + // LoadingComponent()
  30 + this.LoadingLayout()
  31 + } else if (this.pageModel.viewType == ViewType.ERROR) {
  32 + ErrorComponent()
  33 + } else if (this.pageModel.viewType == ViewType.EMPTY) {
  34 + EmptyComponent()
  35 + } else {
  36 + this.ListLayout()
  37 + }
  38 + }
  39 + .width(CommonConstants.FULL_PARENT)
  40 + .height(CommonConstants.FULL_PARENT)
  41 + .onTouch((event: TouchEvent | undefined) => {
  42 + if (event) {
  43 + if (this.pageModel.viewType === ViewType.LOADED) {
  44 + listTouchEvent(this.pageModel, event);
  45 + }
  46 + }
  47 + })
  48 +
  49 + }
  50 +
  51 + @Builder ListLayout() {
  52 + List() {
  53 + // 下拉刷新
  54 + ListItem() {
  55 + RefreshLayout({
  56 + refreshBean: new RefreshLayoutBean(this.pageModel.isVisiblePullDown, this.pageModel.pullDownRefreshImage,
  57 + this.pageModel.pullDownRefreshText, this.pageModel.pullDownRefreshHeight)
  58 + })
  59 + }
  60 +
  61 + LazyForEach(this.pageModel.compList, (compDTO: CompDTO, compIndex: number) => {
  62 + ListItem() {
  63 + Column() {
  64 + CompParser({ compDTO: compDTO, compIndex: compIndex });
  65 + }
  66 + }
  67 + })
  68 +
  69 + // 加载更多
  70 + ListItem() {
  71 + if (this.pageModel.hasMore) {
  72 + LoadMoreLayout({
  73 + refreshBean: new RefreshLayoutBean(this.pageModel.isVisiblePullUpLoad, this.pageModel.pullUpLoadImage,
  74 + this.pageModel.pullUpLoadText, this.pageModel.pullUpLoadHeight)
  75 + })
  76 + } else {
  77 + NoMoreLayout()
  78 + }
  79 + }
  80 + }
  81 + .cachedCount(5)
  82 + .height(CommonConstants.FULL_PARENT)
  83 + .onScrollIndex((start: number, end: number) => {
  84 + // Listen to the first index of the current list.
  85 + this.pageModel.startIndex = start;
  86 + // 包含了 头尾item,判断时需要考虑+2
  87 + this.pageModel.endIndex = end;
  88 + })
  89 + }
  90 +
  91 + @Builder LoadingLayout() {
  92 + CustomRefreshLoadLayout({ refreshBean: new RefreshLayoutBean(true,
  93 + $r('app.media.ic_pull_up_load'), $r('app.string.pull_up_load_text'), this.pageModel.pullDownRefreshHeight) })
  94 + }
  95 +
  96 + async aboutToAppear() {
  97 + // 选中tab,才请求数据。拦截大量接口请求
  98 + if (this.navIndex === this.currentTopNavSelectedIndex) {
  99 + this.getData();
  100 + }
  101 + }
  102 +
  103 + onChange() {
  104 + if (this.navIndex === this.currentTopNavSelectedIndex) {
  105 + this.getData();
  106 + }
  107 + }
  108 +
  109 + async getData() {
  110 + Logger.info(TAG, `getData id: ${this.pageId} , ${this.channelId} , navIndex: ${this.currentTopNavSelectedIndex}`);
  111 + this.pageModel.pageId = this.pageId;
  112 + this.pageModel.groupId = this.pageId;
  113 + this.pageModel.channelId = this.channelId;
  114 + this.pageModel.currentPage = 1;
  115 + let pageDto = await PageViewModel.getPageData(this.pageModel.pageId, this.pageModel.pageId, this.pageModel.channelId
  116 + , this.pageModel.currentPage, this.pageModel.pageSize, getContext(this))
  117 + if (pageDto && pageDto.compList && pageDto.compList.length > 0) {
  118 + this.pageModel.viewType = ViewType.LOADED;
  119 + this.pageModel.compList.push(...pageDto.compList)
  120 + if (pageDto.compList.length === this.pageModel.pageSize) {
  121 + this.pageModel.currentPage++;
  122 + this.pageModel.hasMore = true;
  123 + } else {
  124 + this.pageModel.hasMore = false;
  125 + }
  126 + } else {
  127 + Logger.debug(TAG, 'aboutToAppear, data response page ' + this.pageId + ', comp list is empty.');
  128 + this.pageModel.viewType = ViewType.EMPTY;
  129 + }
  130 + }
  131 +}
  132 +
  1 +import CustomRefreshLoadLayout from './CustomRefreshLoadLayout';
  2 +import { RefreshLayoutBean } from './RefreshLayoutBean';
  3 +
  4 +/**
  5 + * The refresh layout component.
  6 + */
  7 +@Component
  8 +export default struct RefreshLayout {
  9 + @ObjectLink refreshBean: RefreshLayoutBean;
  10 +
  11 + build() {
  12 + Column() {
  13 + if (this.refreshBean.isVisible) {
  14 + CustomRefreshLoadLayout({ refreshBean: new RefreshLayoutBean
  15 + (this.refreshBean.isVisible, this.refreshBean.imageSrc, this.refreshBean.textValue,
  16 + this.refreshBean.heightValue) })
  17 + }
  18 + }
  19 + }
  20 +}
  1 +/**
  2 + * Custom refresh load layout data.
  3 + */
  4 +@Observed
  5 +export class RefreshLayoutBean {
  6 + /**
  7 + * Custom refresh load layout isVisible.
  8 + */
  9 + isVisible: boolean;
  10 +
  11 + /**
  12 + * Custom refresh load layout imageSrc.
  13 + */
  14 + imageSrc: Resource;
  15 +
  16 + /**
  17 + * Custom refresh load layout textValue.
  18 + */
  19 + textValue: Resource;
  20 +
  21 + /**
  22 + * Custom refresh load layout heightValue.
  23 + */
  24 + heightValue: number;
  25 +
  26 + constructor(isVisible: boolean, imageSrc: Resource, textValue: Resource, heightValue: number) {
  27 + this.isVisible = isVisible;
  28 + this.imageSrc = imageSrc;
  29 + this.textValue = textValue;
  30 + this.heightValue = heightValue;
  31 + }
  32 +}
1 import { LazyDataSource, Logger } from 'wdKit'; 1 import { LazyDataSource, Logger } from 'wdKit';
2 -import { CompDTO } from '../repository/bean/CompDTO';  
3 -import { TopNavDTO } from '../repository/bean/TopNavDTO'; 2 +import { CompDTO } from '../../repository/bean/CompDTO';
  3 +import { TopNavDTO } from '../../repository/bean/TopNavDTO';
4 import { PageComponent } from './PageComponent'; 4 import { PageComponent } from './PageComponent';
5 5
6 const TAG = 'TopNavigationComponent'; 6 const TAG = 'TopNavigationComponent';
@@ -21,7 +21,12 @@ export struct TopNavigationComponent { @@ -21,7 +21,12 @@ export struct TopNavigationComponent {
21 Tabs() { 21 Tabs() {
22 ForEach(this.topNavList, (navItem: TopNavDTO, index: number) => { 22 ForEach(this.topNavList, (navItem: TopNavDTO, index: number) => {
23 TabContent() { 23 TabContent() {
24 - PageComponent({ currentTopNavSelectedIndex: index }) 24 + PageComponent({
  25 + currentTopNavSelectedIndex: $currentTopNavSelectedIndex,
  26 + navIndex: index,
  27 + pageId: navItem.pageId,
  28 + channelId: navItem.channelId
  29 + })
25 } 30 }
26 .tabBar(this.tabBarBuilder(navItem, index)) 31 .tabBar(this.tabBarBuilder(navItem, index))
27 }, (navItem: TopNavDTO) => JSON.stringify(navItem)); 32 }, (navItem: TopNavDTO) => JSON.stringify(navItem));
  1 +/**
  2 + * BannerComponent
  3 + * 轮播图卡/单图
  4 + * 邢照杰
  5 + */
  6 +
  7 +import { CommonConstants } from 'wdConstant';
  8 +import colorSpaceManager from '@ohos.graphics.colorSpaceManager';
  9 +import { CompDTO } from '../../repository/bean/CompDTO';
  10 +import { CompUtils } from '../../utils/CompUtils';
  11 +import { ContentDTO } from '../../repository/bean/ContentDTO';
  12 +
  13 +
  14 +const TAG = 'BannerComponent';
  15 +let timerIds: number[] = [];
  16 +
  17 +
  18 +/**
  19 + * 轮播卡(暂时仅展示主标题,不展示子标题)
  20 + * comp类型
  21 + * 重磅推荐/精选/电视剧/电影/综艺/短剧/更多>/
  22 + */
  23 +@Entry
  24 +@Component
  25 +export struct BannerComponent {
  26 + @State compDTO: CompDTO = {} as CompDTO
  27 + @State index: number = 0;
  28 + private bannerContent:ContentDTO;
  29 + private swiperController: SwiperController = new SwiperController();
  30 +
  31 + aboutToAppear() {
  32 +
  33 + // Data Initialization.
  34 + this.bannerContent = this.compDTO.operDataList[0];
  35 + // Turn on scheduled task.
  36 + if (this.compDTO.operDataList.length > 1) {
  37 + startPlay(this.swiperController);
  38 + }
  39 + }
  40 +
  41 + aboutToDisappear() {
  42 + stopPlay();
  43 + }
  44 +
  45 + build() {
  46 + // 整体父视图
  47 + Column() {
  48 + // 判断数组元素个数
  49 + if (this.compDTO.operDataList.length > 1) {
  50 + // 滚动banner
  51 + Swiper(this.swiperController) {
  52 + ForEach(this.compDTO.operDataList, item => {
  53 + Stack() {
  54 + // 背景图
  55 + Image(item.coverUrl)
  56 + .objectFit(ImageFit.Fill)
  57 + .borderRadius(5)
  58 +
  59 + // 底部标题和时间
  60 + Column() {
  61 + Text(item.description)
  62 + .fontSize(18)
  63 + .margin({ bottom: 4 })
  64 + .fontColor(Color.White)
  65 + .fontWeight(600)
  66 + .maxLines(1)
  67 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  68 + .padding({ left: 10, right: 5 })
  69 + .width('100%')
  70 + .textAlign(TextAlign.Start)
  71 + if (item.lengthTime) {
  72 + Row() {
  73 + Image($r('app.media.videoTypeIcon'))
  74 + .height(20)
  75 + .width(20)
  76 + // .margin({right:3})
  77 + Text(item.lengthTime)
  78 + .padding({ left: 5, right: 5 })
  79 + .fontColor(Color.White)
  80 + }
  81 + .backgroundColor('#333333')
  82 + .height(20)
  83 + .margin({ right: 5, bottom: 3 })
  84 + .alignSelf(ItemAlign.End)
  85 + .borderRadius(2)
  86 + }
  87 + }
  88 + .height('50')
  89 + .width('100%')
  90 + }
  91 + .alignContent(Alignment.BottomStart)
  92 + }, item => JSON.stringify(item))
  93 + }
  94 + .width('100%')
  95 + .height('100%')
  96 + .index(this.index)
  97 + .indicatorStyle({
  98 + selectedColor: Color.White,
  99 + color: Color.Gray,
  100 + size: 18,
  101 + left: 15
  102 + })
  103 + .indicator(true)
  104 + .duration(500)
  105 + } else {
  106 + // 不滚动banner
  107 + Stack() {
  108 + // 背景图
  109 + Image(this.bannerContent.coverUrl.toString())
  110 + .objectFit(ImageFit.Fill)
  111 + .borderRadius(5)
  112 +
  113 + // 底部标题和时间
  114 + Row() {
  115 + // 标题
  116 + Text(this.bannerContent.description.toString())
  117 + .fontSize(18)
  118 + .fontColor(Color.White)
  119 + .fontWeight(600)
  120 + .maxLines(2)
  121 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  122 + .padding({ left: 10, right: 0 ,bottom: 5 })
  123 + .width('80%')
  124 + // 时间
  125 + if (this.bannerContent.lengthTime) {
  126 + Row() {
  127 + Image($r('app.media.videoTypeIcon'))
  128 + .height(20)
  129 + .width(20)
  130 + // .margin({right:3})
  131 + Text(this.bannerContent.lengthTime.toString())
  132 + .padding({ left: 5, right: 5 })
  133 + .fontColor(Color.White)
  134 + }
  135 + .backgroundColor('#333333')
  136 + .height(20)
  137 + .borderRadius(2)
  138 + .margin({ bottom: 6 })
  139 + }
  140 + }
  141 + .width('100%')
  142 + .height('100%')
  143 + .alignItems(VerticalAlign.Bottom)
  144 + }
  145 + .alignContent(Alignment.BottomStart)
  146 + .width('100%')
  147 + .height('100%')
  148 + }
  149 + }
  150 + .width('100%')
  151 + .aspectRatio(1.7)
  152 + .padding({left:10,right:15,top:10,bottom:10})
  153 + }
  154 +}
  155 +
  156 +/**
  157 + * start scheduled task.
  158 + *
  159 + * @param swiperController Controller.
  160 + */
  161 +export function startPlay(swiperController: SwiperController) {
  162 + let timerId = setInterval(() => {
  163 + swiperController.showNext();
  164 + }, 3000);
  165 + timerIds.push(timerId);
  166 +}
  167 +
  168 +/**
  169 + * stop scheduled task.
  170 + */
  171 +export function stopPlay() {
  172 + timerIds.forEach((item) => {
  173 + clearTimeout(item);
  174 + })
  175 +}
@@ -46,7 +46,7 @@ export struct EmptyComponent { @@ -46,7 +46,7 @@ export struct EmptyComponent {
46 46
47 Text(this.buildNoDataTip()) 47 Text(this.buildNoDataTip())
48 .fontSize($r('app.float.normal_text_size')) 48 .fontSize($r('app.float.normal_text_size'))
49 - .fontColor('#B2B2B2') 49 + .fontColor('#000000')
50 .fontWeight(FontWeight.Normal) 50 .fontWeight(FontWeight.Normal)
51 .opacity(this.TEXT_OPACITY) 51 .opacity(this.TEXT_OPACITY)
52 .margin({ top: this.EMPTY_TIP_TEXT_MARGIN_TOP }) 52 .margin({ top: this.EMPTY_TIP_TEXT_MARGIN_TOP })
1 import { CommonConstants } from 'wdConstant'; 1 import { CommonConstants } from 'wdConstant';
2 -import { CompDTO } from '../repository/bean/CompDTO';  
3 -import { CompUtils } from '../utils/CompUtils'; 2 +import { CompDTO } from '../../repository/bean/CompDTO';
  3 +import { CompUtils } from '../../utils/CompUtils';
4 4
5 const TAG = 'LabelComponent'; 5 const TAG = 'LabelComponent';
6 6
  1 +// import { CommonConstants } from 'wdConstant/src/main/ets/constants/CommonConstants'
  2 +
  3 +@Entry
  4 +@Component
  5 +export struct SmallVideoCardComponent {
  6 + build() {
  7 + Row() {
  8 + Column() {
  9 + Text('“畅享亚运”新模式活动打卡,看杭州打开“金角银边活动启动 跟着体育明星云打卡,看杭州打开“金角银边')
  10 + .fontWeight(400)
  11 + .fontSize($r('app.float.font_size_17'))
  12 + .maxLines(4)
  13 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  14 + .fontColor($r('app.color.color_222222'))
  15 + .lineHeight(25)
  16 + Row() {
  17 + Text('人民日报')
  18 + .labelTextStyle()
  19 + Image($r('app.media.point'))
  20 + .width(16)
  21 + .height(16)
  22 + Text('20分钟前')
  23 + .labelTextStyle()
  24 + .margin({
  25 + right: 6
  26 + })
  27 + Text('2000评')
  28 + .labelTextStyle()
  29 + }
  30 + }
  31 + .height(156)
  32 + .layoutWeight(1)
  33 + .justifyContent(FlexAlign.SpaceBetween)
  34 + .alignItems(HorizontalAlign.Start)
  35 + .margin({ right: 12 })
  36 +
  37 + Stack({ alignContent: Alignment.BottomEnd }) {
  38 + Image('https://www.harmonyos.com/resource/image/partner/harmonyos-connect/pic_shengtai_connect_qudao_xianxia.jpg')
  39 + .width(117)
  40 + .aspectRatio(117 / 156)
  41 + .border({ radius: 4 })
  42 + Row() {
  43 + Image($r('app.media.iv_card_play_yellow_flag'))
  44 + .width(22)
  45 + .height(18)
  46 + Text('10:00')
  47 + .fontSize($r('app.float.font_size_13'))
  48 + .fontWeight(400)
  49 + .fontColor($r('app.color.color_fff'))
  50 + }
  51 + .height(18)
  52 + .padding({ right: 4 })
  53 + .margin({
  54 + right: 4,
  55 + bottom: 4
  56 + })
  57 + .backgroundColor($r('app.color.color_4d000000'))
  58 + }
  59 + }
  60 + // .width(CommonConstants.FULL_WIDTH)
  61 + .width('100%')
  62 + .height(184)
  63 + .padding({
  64 + top: 14,
  65 + bottom: 14,
  66 + left: 16,
  67 + right: 16
  68 + })
  69 + }
  70 +}
  71 +
  72 +@Extend(Text) function labelTextStyle() {
  73 + .fontSize($r('app.float.font_size_12'))
  74 + .fontWeight(400)
  75 + .fontColor($r('app.color.color_B0B0B0'))
  76 +}
1 //缩略标题 1 //缩略标题
2 import { CommonConstants } from 'wdConstant' 2 import { CommonConstants } from 'wdConstant'
3 -import { CompDTO } from '../repository/bean/CompDTO' 3 +import { CompDTO } from '../../repository/bean/CompDTO'
4 4
5 @Component 5 @Component
6 export struct TitleAbbrComponent { 6 export struct TitleAbbrComponent {
1 //全标题 "compStyle":"3", 1 //全标题 "compStyle":"3",
2 import { CommonConstants } from 'wdConstant' 2 import { CommonConstants } from 'wdConstant'
3 -import { CompDTO } from '../repository/bean/CompDTO' 3 +import { CompDTO } from '../../repository/bean/CompDTO'
4 4
5 @Component 5 @Component
6 export struct TitleAllComponent { 6 export struct TitleAllComponent {
  1 +import HashMap from '@ohos.util.HashMap'
  2 +import { ConfigConstants } from 'wdConstant/src/main/ets/constants/ConfigConstants'
  3 +import { DateTimeUtils, Logger } from 'wdKit'
  4 +
  5 +/**
  6 + * 网络请求业务侧工具类
  7 + */
  8 +export class HttpUrlUtils {
  9 + /**
  10 + * 现网地址
  11 + */
  12 + static readonly HOST: string = "https://pd-apis-uat.pdnews.cn";
  13 + /**
  14 + * 启动接口(底导接口)
  15 + */
  16 + static readonly BOTTOM_NAV_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/bottomNavGroup";
  17 + /**
  18 + * 展现comp接口
  19 + */
  20 + static readonly COMP_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/compInfo";
  21 +
  22 + static getCommonHeaders(): HashMap<string, string> {
  23 + let headers: HashMap<string, string> = new HashMap<string, string>()
  24 + headers.set('User-Agent', 'Dalvik/2.1.0 (Linux; U; Android 13; 22101317C Build/TKQ1.221013.002)')
  25 + headers.set('channel', this.getChannel())
  26 + headers.set('appCode', ConfigConstants.appCode)
  27 + headers.set('plat', this.getPlat())
  28 + headers.set('Authorization', 'APPCODE 83092caa603a421aa0222308b3f6b27a')
  29 + headers.set('Content-Type', 'application/json; charset=utf-8')
  30 + headers.set('timestamp', this.getTimestamp())
  31 + headers.set('RMRB-X-TOKEN', this.getXToken())
  32 + headers.set('device_id', this.getDeviceId())
  33 + headers.set('cookie', 'RMRB-X-TOKEN=eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc')
  34 + headers.set('build_version', this.getVersion())
  35 + headers.set('adcode', this.getAdCode())
  36 + headers.set('os_version', this.getOsVersion())
  37 + headers.set('X-Ca-Stage', 'PRE')
  38 + headers.set('versionCode', this.getVersionCode())
  39 + headers.set('system', this.getTerminalId())
  40 + headers.set('version_name', 'debug')
  41 + headers.set('EagleEye-TraceID', '0B6DE03D2997435BA875FFBE05425ED2')
  42 + headers.set('imei', this.getImei())
  43 + headers.set('Accept-Language', 'zh')
  44 + headers.set('city', this.getCity())
  45 + headers.set('city_dode', this.getCityCode())
  46 + // TODO 判断是否登录
  47 + headers.set('userId', this.getUserId())
  48 + headers.set('userType', this.getUserType())
  49 +
  50 + // Logger.debug("TAG", '******************* commonHeaders headers start ******************************** ');
  51 + // headers.forEach((v,k)=>{
  52 + // Logger.debug("TAG", 'getCommonHeaders header: ' + k + ': ' + v);
  53 + // })
  54 + // Logger.debug("TAG", '******************* commonHeaders headers end ******************************** ');
  55 + return headers;
  56 + }
  57 +
  58 + static getBottomNavGroupUrl() {
  59 + // https: //pd-apis-uat.pdnews.cn/api/rmrb-bff-display-zh/display/zh/c/bottomNavGroup
  60 + return this.HOST + this.BOTTOM_NAV_PATH;
  61 + }
  62 +
  63 + static getCompInfoUrl(pageId: string, groupId: string, channelId: string, currentPage: number
  64 + , pageSize: number) {
  65 + let url = this.HOST + this.COMP_PATH;
  66 + // TODO 暂定只请求第一页,后续对接分页加载,参数再调整 first_load?
  67 + url = url + "?channelStrategy=2&loadStrategy=first_load"
  68 + + "&districtCode=" + this.getDistrictCode()
  69 + + "&provinceCode=" + this.getProvinceCode()
  70 + + "&cityCode=" + this.getCityCode()
  71 + + "&refreshTime=" + DateTimeUtils.getCurrentTimeMillis()
  72 + + "&pageId=" + pageId
  73 + + "&groupId=" + groupId
  74 + + "&channelId=" + channelId
  75 + + "&pageSize=" + pageSize
  76 + + "&pageNum=" + currentPage;
  77 + // Logger.debug("TAG", 'getCompInfoUrl url: '+url);
  78 + return url;
  79 + }
  80 +
  81 +
  82 + private static getCity() {
  83 + // TODO 对接定位
  84 + return '%E5%90%88%E8%82%A5%E5%B8%82';
  85 + }
  86 +
  87 + private static getChannel() {
  88 + // TODO 对接配置
  89 + return 'rmrb_china_0000';
  90 + }
  91 +
  92 + private static getPlat() {
  93 + return 'Phone';
  94 + }
  95 +
  96 + private static getTimestamp() {
  97 + // return DateTimeUtils.getCurrentTime() + '';
  98 + // TODO 暂时写死,有些page 真实时间戳 返回数据为空
  99 + return '155203523';
  100 + }
  101 +
  102 + private static getXToken() {
  103 + return 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc';
  104 + }
  105 +
  106 + private static getDeviceId() {
  107 + // TODO
  108 + return 'b5cf725d-193d-3215-8c77-e76fe15ce64d';
  109 + }
  110 +
  111 + private static getVersion() {
  112 + // TODO
  113 + return '202312251034';
  114 + }
  115 +
  116 + private static getVersionCode() {
  117 + // TODO
  118 + return '7301';
  119 + }
  120 +
  121 + private static getAdCode() {
  122 + return '340000';
  123 + }
  124 +
  125 + private static getOsVersion() {
  126 + // TODO
  127 + return '13';
  128 + }
  129 +
  130 + private static getCityCode() {
  131 + // TODO
  132 + return '340100';
  133 + }
  134 +
  135 + private static getProvinceCode() {
  136 + // TODO
  137 + return '340000';
  138 + }
  139 +
  140 + /**
  141 + * 地区code
  142 + */
  143 + private static getDistrictCode() {
  144 + // TODO
  145 + return '340103';
  146 + }
  147 +
  148 + private static getTerminalId() {
  149 + return 'Android';
  150 + }
  151 +
  152 + private static getImei() {
  153 + // TODO
  154 + return 'b5cf725d-193d-3215-8c77-e76fe15ce64d';
  155 + }
  156 +
  157 + private static getUserId() {
  158 + // TODO 对接登录
  159 + return '459776297474949';
  160 + }
  161 +
  162 + private static getUserType() {
  163 + return '2';
  164 + }
  165 +}
1 import { ResponseDTO, WDHttp } from 'wdNetwork'; 1 import { ResponseDTO, WDHttp } from 'wdNetwork';
2 import { NavigationBodyDTO } from './bean/NavigationBodyDTO'; 2 import { NavigationBodyDTO } from './bean/NavigationBodyDTO';
3 import { PageDTO } from './bean/PageDTO'; 3 import { PageDTO } from './bean/PageDTO';
  4 +import HashMap from '@ohos.util.HashMap';
  5 +import { HttpUrlUtils } from '../network/HttpUrlUtils';
4 6
5 export class PageRepository { 7 export class PageRepository {
6 -  
7 - static fetchNavigationDataApi(url: string) {  
8 - return WDHttp.get<ResponseDTO<NavigationBodyDTO>>(url) 8 + static fetchNavigationDataApi() {
  9 + let url = HttpUrlUtils.getBottomNavGroupUrl();
  10 + let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
  11 + return WDHttp.get<ResponseDTO<NavigationBodyDTO>>(url, headers)
9 }; 12 };
10 13
11 - static fetchPageData(url: string) {  
12 - return WDHttp.get<ResponseDTO<PageDTO>>(url) 14 + static fetchPageData(pageId: string, groupId: string, channelId: string, currentPage: number
  15 + , pageSize: number) {
  16 + let url = HttpUrlUtils.getCompInfoUrl(pageId, groupId, channelId, currentPage, pageSize)
  17 + let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
  18 + return WDHttp.get<ResponseDTO<PageDTO>>(url, headers)
13 }; 19 };
14 } 20 }
  1 +/**
  2 + * 网络请求业务侧工具类
  3 + */
  4 +import { BottomNavDTO } from './bean/BottomNavDTO';
  5 +
  6 +export class UIUtils {
  7 +
  8 + /**
  9 + * 判断是否为我的页面
  10 + */
  11 + static isMine(navItem: BottomNavDTO): boolean {
  12 + if (navItem == null) {
  13 + return false;
  14 + }
  15 + return navItem.type == '2';
  16 + }
  17 +}
@@ -36,5 +36,6 @@ export interface BottomNavDTO { @@ -36,5 +36,6 @@ export interface BottomNavDTO {
36 statusBarColor: number; 36 statusBarColor: number;
37 topNavChannelList: TopNavDTO[]; 37 topNavChannelList: TopNavDTO[];
38 topStyle: string; 38 topStyle: string;
  39 + // 1-普通页面,2-我的
39 type: string; 40 type: string;
40 } 41 }
@@ -10,7 +10,7 @@ export interface ContentDTO { @@ -10,7 +10,7 @@ export interface ContentDTO {
10 heatValue: string; 10 heatValue: string;
11 innerUrl: string; 11 innerUrl: string;
12 landscape: number; 12 landscape: number;
13 - // lengthTime?: any; 13 + lengthTime?: any;
14 linkUrl: string; 14 linkUrl: string;
15 openLikes: number; 15 openLikes: number;
16 openUrl: string; 16 openUrl: string;
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 * 顶导 2 * 顶导
3 */ 3 */
4 export interface TopNavDTO { 4 export interface TopNavDTO {
5 - channelId: number; 5 + channelId: string;
6 channelStyle: number; 6 channelStyle: number;
7 channelType: number; 7 channelType: number;
8 defaultPermitted: number; 8 defaultPermitted: number;
@@ -21,7 +21,7 @@ export interface TopNavDTO { @@ -21,7 +21,7 @@ export interface TopNavDTO {
21 myChannel: string; 21 myChannel: string;
22 name: string; 22 name: string;
23 num: number; 23 num: number;
24 - pageId: number; 24 + pageId: string;
25 pageType: string; 25 pageType: string;
26 underlineCColor: string; 26 underlineCColor: string;
27 } 27 }
  1 +import promptAction from '@ohos.promptAction';
  2 +import PageModel from '../viewmodel/PageModel';
  3 +import { RefreshConstants as Const, RefreshState } from './RefreshConstants';
  4 +import PageViewModel from '../viewmodel/PageViewModel';
  5 +import { PageDTO } from '../repository/bean/PageDTO';
  6 +import { touchMoveLoadMore, touchUpLoadMore } from './PullUpLoadMore';
  7 +
  8 +export function listTouchEvent(pageModel: PageModel, event: TouchEvent) {
  9 + switch (event.type) {
  10 + case TouchType.Down:
  11 + pageModel.downY = event.touches[0].y;
  12 + pageModel.lastMoveY = event.touches[0].y;
  13 + break;
  14 + case TouchType.Move:
  15 + if ((pageModel.isRefreshing === true) || (pageModel.isLoading === true)) {
  16 + return;
  17 + }
  18 + let isDownPull = event.touches[0].y - pageModel.lastMoveY > 0;
  19 + if (((isDownPull === true) || (pageModel.isPullRefreshOperation === true)) && (pageModel.isCanLoadMore === false)) {
  20 + // Finger movement, processing pull-down refresh.
  21 + touchMovePullRefresh(pageModel, event);
  22 + } else {
  23 + // Finger movement, processing load more.
  24 + touchMoveLoadMore(pageModel, event);
  25 + }
  26 + pageModel.lastMoveY = event.touches[0].y;
  27 + break;
  28 + case TouchType.Cancel:
  29 + break;
  30 + case TouchType.Up:
  31 + if ((pageModel.isRefreshing === true) || (pageModel.isLoading === true)) {
  32 + return;
  33 + }
  34 + if ((pageModel.isPullRefreshOperation === true)) {
  35 + // Lift your finger and pull down to refresh.
  36 + touchUpPullRefresh(pageModel);
  37 + } else {
  38 + // Fingers up, handle loading more.
  39 + touchUpLoadMore(pageModel);
  40 + }
  41 + break;
  42 + default:
  43 + break;
  44 + }
  45 +}
  46 +
  47 +export function touchMovePullRefresh(pageModel: PageModel, event: TouchEvent) {
  48 + if (pageModel.startIndex === 0) {
  49 + pageModel.isPullRefreshOperation = true;
  50 + let height = vp2px(pageModel.pullDownRefreshHeight);
  51 + pageModel.offsetY = event.touches[0].y - pageModel.downY;
  52 + // The sliding offset is greater than the pull-down refresh layout height, and the refresh condition is met.
  53 + if (pageModel.offsetY >= height) {
  54 + pullRefreshState(pageModel, RefreshState.Release);
  55 + pageModel.offsetY = height + pageModel.offsetY * Const.Y_OFF_SET_COEFFICIENT;
  56 + } else {
  57 + pullRefreshState(pageModel, RefreshState.DropDown);
  58 + }
  59 + if (pageModel.offsetY < 0) {
  60 + pageModel.offsetY = 0;
  61 + pageModel.isPullRefreshOperation = false;
  62 + }
  63 + }
  64 +}
  65 +
  66 +export function touchUpPullRefresh(pageModel: PageModel) {
  67 + if (pageModel.isCanRefresh === true) {
  68 + pageModel.offsetY = vp2px(pageModel.pullDownRefreshHeight);
  69 + pullRefreshState(pageModel, RefreshState.Refreshing);
  70 + pageModel.currentPage = 1;
  71 + setTimeout(() => {
  72 + let self: PageModel = pageModel;
  73 +
  74 + PageViewModel.getPageData(self.pageId, self.groupId, self.channelId, self.currentPage, self.pageSize)
  75 + .then((data: PageDTO) => {
  76 + if (data == null || data.compList == null || data.compList.length == 0) {
  77 + self.hasMore = false;
  78 + } else {
  79 + if (data.compList.length == self.pageSize) {
  80 + self.currentPage++;
  81 + self.hasMore = true;
  82 + } else {
  83 + self.hasMore = false;
  84 + }
  85 + // 刷新,替换所有数据
  86 + self.compList.replaceAll(...data.compList)
  87 + }
  88 + closeRefresh(self, true);
  89 + }).catch((err: string | Resource) => {
  90 + promptAction.showToast({ message: err });
  91 + closeRefresh(self, false);
  92 + });
  93 + }, Const.DELAY_TIME);
  94 + } else {
  95 + closeRefresh(pageModel, false);
  96 + }
  97 +}
  98 +
  99 +export function pullRefreshState(pageModel: PageModel, state: number) {
  100 + switch (state) {
  101 + case RefreshState.DropDown:
  102 + pageModel.pullDownRefreshText = $r('app.string.pull_down_refresh_text');
  103 + pageModel.pullDownRefreshImage = $r('app.media.ic_pull_down_refresh');
  104 + pageModel.isCanRefresh = false;
  105 + pageModel.isRefreshing = false;
  106 + pageModel.isVisiblePullDown = true;
  107 + break;
  108 + case RefreshState.Release:
  109 + pageModel.pullDownRefreshText = $r('app.string.release_refresh_text');
  110 + pageModel.pullDownRefreshImage = $r('app.media.ic_pull_up_refresh');
  111 + pageModel.isCanRefresh = true;
  112 + pageModel.isRefreshing = false;
  113 + break;
  114 + case RefreshState.Refreshing:
  115 + pageModel.offsetY = vp2px(pageModel.pullDownRefreshHeight);
  116 + pageModel.pullDownRefreshText = $r('app.string.refreshing_text');
  117 + pageModel.pullDownRefreshImage = $r('app.media.ic_pull_up_load');
  118 + pageModel.isCanRefresh = true;
  119 + pageModel.isRefreshing = true;
  120 + break;
  121 + case RefreshState.Success:
  122 + pageModel.pullDownRefreshText = $r('app.string.refresh_success_text');
  123 + pageModel.pullDownRefreshImage = $r('app.media.ic_succeed_refresh');
  124 + pageModel.isCanRefresh = true;
  125 + pageModel.isRefreshing = true;
  126 + break;
  127 + case RefreshState.Fail:
  128 + pageModel.pullDownRefreshText = $r('app.string.refresh_fail_text');
  129 + pageModel.pullDownRefreshImage = $r('app.media.ic_fail_refresh');
  130 + pageModel.isCanRefresh = true;
  131 + pageModel.isRefreshing = true;
  132 + break;
  133 + default:
  134 + break;
  135 + }
  136 +}
  137 +
  138 +export function closeRefresh(pageModel: PageModel, isRefreshSuccess: boolean) {
  139 + let self = pageModel;
  140 + setTimeout(() => {
  141 + let delay = Const.RefreshConstant_DELAY_PULL_DOWN_REFRESH;
  142 + if (self.isCanRefresh === true) {
  143 + pullRefreshState(pageModel, isRefreshSuccess ? RefreshState.Success : RefreshState.Fail);
  144 + delay = Const.RefreshConstant_DELAY_SHRINK_ANIMATION_TIME;
  145 + }
  146 + animateTo({
  147 + duration: Const.RefreshConstant_CLOSE_PULL_DOWN_REFRESH_TIME,
  148 + delay: delay,
  149 + onFinish: () => {
  150 + pullRefreshState(pageModel, RefreshState.DropDown);
  151 + self.isVisiblePullDown = false;
  152 + self.isPullRefreshOperation = false;
  153 + }
  154 + }, () => {
  155 + self.offsetY = 0;
  156 + })
  157 + }, self.isCanRefresh ? Const.DELAY_ANIMATION_DURATION : 0);
  158 +}
  1 +import promptAction from '@ohos.promptAction';
  2 +import PageModel from '../viewmodel/PageModel';
  3 +import { RefreshConstants as Const } from './RefreshConstants';
  4 +import PageViewModel from '../viewmodel/PageViewModel';
  5 +import { PageDTO } from '../repository/bean/PageDTO';
  6 +
  7 +export function touchMoveLoadMore(model: PageModel, event: TouchEvent) {
  8 + // list size +1
  9 + if (model.endIndex === model.compList.size() || model.endIndex === model.compList.size() + 1) {
  10 + model.offsetY = event.touches[0].y - model.downY;
  11 + if (Math.abs(model.offsetY) > vp2px(model.pullUpLoadHeight) / 2) {
  12 + model.isCanLoadMore = true;
  13 + model.isVisiblePullUpLoad = true;
  14 + model.offsetY = -vp2px(model.pullUpLoadHeight) + model.offsetY * Const.Y_OFF_SET_COEFFICIENT;
  15 + }
  16 + }
  17 +}
  18 +
  19 +export function touchUpLoadMore(model: PageModel) {
  20 + let self: PageModel = model;
  21 + animateTo({
  22 + duration: Const.ANIMATION_DURATION,
  23 + }, () => {
  24 + self.offsetY = 0;
  25 + })
  26 + if ((self.isCanLoadMore === true) && (self.hasMore === true)) {
  27 + self.isLoading = true;
  28 + setTimeout(() => {
  29 + closeLoadMore(model);
  30 + PageViewModel.getPageData(self.pageId, self.groupId, self.channelId, self.currentPage, self.pageSize)
  31 + .then((data: PageDTO) => {
  32 + if (data == null || data.compList == null || data.compList.length == 0) {
  33 + self.hasMore = false;
  34 + } else {
  35 + if (data.compList.length == self.pageSize) {
  36 + self.currentPage++;
  37 + self.hasMore = true;
  38 + } else {
  39 + self.hasMore = false;
  40 + }
  41 + self.compList.push(...data.compList)
  42 + }
  43 + }).catch((err: string | Resource) => {
  44 + promptAction.showToast({ message: err });
  45 + })
  46 + }, Const.DELAY_TIME);
  47 + } else {
  48 + closeLoadMore(self);
  49 + }
  50 +}
  51 +
  52 +export function closeLoadMore(model: PageModel) {
  53 + model.isCanLoadMore = false;
  54 + model.isLoading = false;
  55 + model.isVisiblePullUpLoad = false;
  56 +}
  1 +/**
  2 + * The constant of refresh.
  3 + */
  4 +export class RefreshConstants {
  5 + /**
  6 + * The off set coefficient.
  7 + */
  8 + static readonly Y_OFF_SET_COEFFICIENT: number = 0.1;
  9 + /**
  10 + * The animation delay time.
  11 + */
  12 + static readonly DELAY_ANIMATION_DURATION: number = 300;
  13 + /**
  14 + * The delay time.
  15 + */
  16 + static readonly DELAY_TIME: number = 1000;
  17 +
  18 + /**
  19 + * The animation duration.
  20 + */
  21 + static readonly ANIMATION_DURATION: number = 2000;
  22 + /**
  23 + * The RefreshConstant constants.
  24 + */
  25 + static readonly RefreshConstant_DELAY_PULL_DOWN_REFRESH: number = 50;
  26 + static readonly RefreshConstant_CLOSE_PULL_DOWN_REFRESH_TIME: number = 150;
  27 + static readonly RefreshConstant_DELAY_SHRINK_ANIMATION_TIME: number = 500;
  28 +
  29 + /**
  30 + * The page size.
  31 + */
  32 + static readonly PAGE_SIZE: number = 20;
  33 +
  34 + /**
  35 + * The refresh and load height.
  36 + */
  37 + static readonly CUSTOM_LAYOUT_HEIGHT: number = 70;
  38 + /**
  39 + * Full the width.
  40 + */
  41 + static readonly FULL_WIDTH: string = '100%';
  42 + /**
  43 + * The NoMoreLayout constants.
  44 + */
  45 + static readonly NoMoreLayoutConstant_NORMAL_PADDING: number = 8;
  46 + static readonly NoMoreLayoutConstant_TITLE_FONT: string = '16fp';
  47 +
  48 + /**
  49 + * The RefreshLayout constants.
  50 + */
  51 + static readonly RefreshLayout_MARGIN_LEFT: string = '40%';
  52 + static readonly RefreshLayout_TEXT_MARGIN_BOTTOM: number = 1;
  53 + static readonly RefreshLayout_TEXT_MARGIN_LEFT: number = 7;
  54 + static readonly RefreshLayout_TEXT_FONT_SIZE: number = 17;
  55 + static readonly RefreshLayout_IMAGE_WIDTH: number = 18;
  56 + static readonly RefreshLayout_IMAGE_HEIGHT: number = 18;
  57 +}
  58 +/**
  59 + * The refresh state enum.
  60 + */
  61 +export const enum RefreshState {
  62 + DropDown = 0,
  63 + Release = 1,
  64 + Refreshing = 2,
  65 + Success = 3,
  66 + Fail = 4
  67 +}
  1 +import { Logger } from 'wdKit';
  2 +import { ResponseDTO } from 'wdNetwork';
  3 +
  4 +/**
  5 + * 处理返回后的数据
  6 + */
  7 +export abstract class BaseViewModel {
  8 + abstract getLogTag(): string;
  9 +
  10 + public isRespondsInvalid(resDTO: ResponseDTO<any>, tag?: string): boolean {
  11 + if (resDTO == null) {
  12 + Logger.error(this.getLogTag(), `${tag == null ? '' : tag + ', '}resDTO is empty`);
  13 + return true;
  14 + }
  15 + // code = 0, success
  16 + if (resDTO.code != 0) {
  17 + Logger.error(this.getLogTag(), `${tag == null ? '' : tag + ', '}code error, code:${resDTO.code}, message:${resDTO.message}`);
  18 + return true;
  19 + }
  20 + if (!resDTO.data) {
  21 + Logger.error(this.getLogTag(), `${tag == null ? '' : tag + ', '}resDTO.data is null`);
  22 + return true;
  23 + }
  24 + return false;
  25 + }
  26 +}
  1 +import { ViewType } from 'wdConstant/src/main/ets/enum/ViewType';
  2 +import { LazyDataSource } from 'wdKit';
  3 +import { CompDTO } from '../repository/bean/CompDTO';
  4 +import { RefreshConstants as Const } from '../utils/RefreshConstants';
  5 +
  6 +export default class PageModel {
  7 + // 页面数据
  8 + pageId: string = "";
  9 + groupId: string = "";
  10 + channelId: string = "";
  11 + compList: LazyDataSource<CompDTO> = new LazyDataSource();
  12 + // 页面状态,刷新、加载更多等
  13 + currentPage: number = 1;
  14 + pageSize: number = Const.PAGE_SIZE;
  15 + pullDownRefreshText: Resource = $r('app.string.pull_down_refresh_text');
  16 + pullDownRefreshImage: Resource = $r('app.media.ic_pull_down_refresh');
  17 + pullDownRefreshHeight: number = Const.CUSTOM_LAYOUT_HEIGHT;
  18 + isVisiblePullDown: boolean = false;
  19 + pullUpLoadText: Resource = $r('app.string.pull_up_load_text');
  20 + pullUpLoadImage: Resource = $r('app.media.ic_pull_up_load');
  21 + pullUpLoadHeight: number = Const.CUSTOM_LAYOUT_HEIGHT;
  22 + isVisiblePullUpLoad: boolean = false;
  23 + offsetY: number = 0;
  24 + viewType: number = ViewType.LOADING;
  25 + hasMore: boolean = true;
  26 + startIndex = 0;
  27 + endIndex = 0;
  28 + downY = 0;
  29 + lastMoveY = 0;
  30 + isRefreshing: boolean = false;
  31 + isCanRefresh = false;
  32 + isPullRefreshOperation = false;
  33 + isLoading: boolean = false;
  34 + isCanLoadMore: boolean = false;
  35 +}
1 import { Logger, ResourcesUtils } from 'wdKit'; 1 import { Logger, ResourcesUtils } from 'wdKit';
2 import { ResponseDTO, } from 'wdNetwork'; 2 import { ResponseDTO, } from 'wdNetwork';
3 import { PageRepository } from '../repository/PageRepository'; 3 import { PageRepository } from '../repository/PageRepository';
4 -import http from '@ohos.net.http';  
5 import { NavigationBodyDTO } from '../repository/bean/NavigationBodyDTO'; 4 import { NavigationBodyDTO } from '../repository/bean/NavigationBodyDTO';
6 -import { BottomNavDTO } from '../repository/bean/BottomNavDTO';  
7 import { PageDTO } from '../repository/bean/PageDTO'; 5 import { PageDTO } from '../repository/bean/PageDTO';
  6 +import { BaseViewModel } from './BaseViewModel';
8 7
9 const TAG = 'PageViewModel'; 8 const TAG = 'PageViewModel';
  9 +/**
  10 + * mock数据开关,默认关。
  11 + * mock数据是本地json数据,可自行修改内容(‘entry\src\main\resources\rawfile\’目录)
  12 + */
  13 +const mock_switch = true;
10 14
11 /** 15 /**
12 * 处理返回后的数据 16 * 处理返回后的数据
13 */ 17 */
14 -export class PageViewModel { 18 +export class PageViewModel extends BaseViewModel {
  19 + getLogTag() {
  20 + return TAG;
  21 + }
  22 +
15 /** 23 /**
16 * get Nav Data from Resource . 24 * get Nav Data from Resource .
17 * 25 *
18 * @return BottomNavBean[] Nav Data List 26 * @return BottomNavBean[] Nav Data List
19 */ 27 */
20 - static async getBottomNavData(context: Context): Promise<BottomNavDTO[]> { 28 + async getBottomNavData(context?: Context): Promise<NavigationBodyDTO> {
21 Logger.info(TAG, `getBottomNavData start`); 29 Logger.info(TAG, `getBottomNavData start`);
22 - let compRes: ResponseDTO<NavigationBodyDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<NavigationBodyDTO>>(context, 'bottom_nav.json');  
23 - if (!compRes || !compRes.data || !compRes.data.bottomNavList) {  
24 - Logger.info(TAG, `getBottomNavData compRes bottomNavList is empty`);  
25 - return [] 30 + if (mock_switch) {
  31 + return this.getBottomNavDataMock(context);
26 } 32 }
27 - Logger.info(TAG, `getBottomNavData getResourcesJsonSync compRes : ${JSON.stringify(compRes)}`);  
28 - return compRes.data.bottomNavList 33 + return this.getNavData();
29 } 34 }
30 35
31 - static getNavData(url: string): Promise<NavigationBodyDTO> {  
32 - return new Promise<NavigationBodyDTO>((success, error) => {  
33 - Logger.info(TAG, `getNavData start`);  
34 - PageRepository.fetchNavigationDataApi(url).then((navResDTO: ResponseDTO<NavigationBodyDTO>) => {  
35 - if (!navResDTO) {  
36 - Logger.error(TAG, 'getNavData then navResDTO is empty');  
37 - error('navResDTO is empty');  
38 - return 36 + async getBottomNavDataMock(context?: Context): Promise<NavigationBodyDTO> {
  37 + Logger.info(TAG, `getBottomNavDataMock start`);
  38 + let compRes: ResponseDTO<NavigationBodyDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<NavigationBodyDTO>>('bottom_nav.json', context);
  39 + if (!compRes || !compRes.data) {
  40 + Logger.info(TAG, `getBottomNavDataMock compRes bottomNavList is empty`);
  41 + return null
39 } 42 }
40 - if (navResDTO.code != http.ResponseCode.OK) {  
41 - Logger.error(TAG, `getNavData then code:${navResDTO.code}, message:${navResDTO.message}`);  
42 - error('navResDTO Response Code is failure');  
43 - return 43 + Logger.info(TAG, `getBottomNavDataMock getResourcesJsonSync compRes : ${JSON.stringify(compRes)}`);
  44 + return compRes.data
44 } 45 }
45 - if (!navResDTO.data?.bottomNavList) {  
46 - error('navResDTO list is empty'); 46 +
  47 + private getNavData(): Promise<NavigationBodyDTO> {
  48 + return new Promise<NavigationBodyDTO>((success, error) => {
  49 + Logger.info(TAG, `getNavData start`);
  50 + PageRepository.fetchNavigationDataApi().then((navResDTO: ResponseDTO<NavigationBodyDTO>) => {
  51 + if (this.isRespondsInvalid(navResDTO, 'getNavData')) {
  52 + error("page data invalid");
47 return 53 return
48 } 54 }
49 - // let navResStr = JSON.stringify(navResDTO);  
50 Logger.info(TAG, "getNavData then,navResDTO.timeStamp:" + navResDTO.timestamp); 55 Logger.info(TAG, "getNavData then,navResDTO.timeStamp:" + navResDTO.timestamp);
51 let navigationBean = navResDTO.data 56 let navigationBean = navResDTO.data
52 success(navigationBean); 57 success(navigationBean);
@@ -62,8 +67,12 @@ export class PageViewModel { @@ -62,8 +67,12 @@ export class PageViewModel {
62 * 67 *
63 * @return {GroupDTO} compRes.data 68 * @return {GroupDTO} compRes.data
64 */ 69 */
65 - static async getPageData1(context: Context): Promise<PageDTO> {  
66 - let compRes: ResponseDTO<PageDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<PageDTO>>(context, 'comp_list0.json'); 70 + private async getPageData1(currentPage: number, context?: Context): Promise<PageDTO> {
  71 + if (currentPage > 1) {
  72 + // 加载更多,返回无数据
  73 + return {} as PageDTO
  74 + }
  75 + let compRes: ResponseDTO<PageDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<PageDTO>>('comp_list0.json', context);
67 if (!compRes || !compRes.data) { 76 if (!compRes || !compRes.data) {
68 Logger.info(TAG, `getCompList compRes is empty`); 77 Logger.info(TAG, `getCompList compRes is empty`);
69 return {} as PageDTO 78 return {} as PageDTO
@@ -76,34 +85,36 @@ export class PageViewModel { @@ -76,34 +85,36 @@ export class PageViewModel {
76 * Get Group data. 85 * Get Group data.
77 * 86 *
78 * @return {GroupDTO} compRes.data 87 * @return {GroupDTO} compRes.data
  88 + * @deprecated
79 */ 89 */
80 - static async getPageData2(context: Context): Promise<PageDTO> {  
81 - let compRes: ResponseDTO<PageDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<PageDTO>>(context, 'comp_list2.json'); 90 + private async getPageData2(context?: Context): Promise<PageDTO> {
  91 + let compRes: ResponseDTO<PageDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<PageDTO>>('comp_list2.json');
82 if (!compRes || !compRes.data) { 92 if (!compRes || !compRes.data) {
83 Logger.info(TAG, `getCompList compRes is empty`); 93 Logger.info(TAG, `getCompList compRes is empty`);
84 return {} as PageDTO 94 return {} as PageDTO
85 } 95 }
  96 + // router.push('')
86 Logger.info(TAG, `getCompList getResourcesJson compRes : ${JSON.stringify(compRes)}`); 97 Logger.info(TAG, `getCompList getResourcesJson compRes : ${JSON.stringify(compRes)}`);
87 return compRes.data 98 return compRes.data
88 } 99 }
89 100
90 -  
91 - static getPageData(url: string): Promise<PageDTO> {  
92 - return new Promise<PageDTO>((success, error) => {  
93 - PageRepository.fetchPageData(url).then((resDTO: ResponseDTO<PageDTO>) => {  
94 - if (!resDTO) {  
95 - Logger.error(TAG, 'getPageData then resDTO is empty');  
96 - error("page data is empty");  
97 - return 101 + async getPageData(pageId: string, groupId: string, channelId: string, currentPage: number
  102 + , pageSize: number, context?: Context): Promise<PageDTO> {
  103 + Logger.debug(TAG, 'getPageData pageId: ' + pageId);
  104 + if (mock_switch) {
  105 + return this.getPageData1(currentPage, context);
98 } 106 }
99 - if (resDTO.code != http.ResponseCode.OK || !resDTO.data) {  
100 - Logger.error(TAG, `getPageData then code:${resDTO.code}, message:${resDTO.message}`);  
101 - error(`get page data error code:${resDTO.code}, message:${resDTO.message}`); 107 + return new Promise<PageDTO>((success, error) => {
  108 + PageRepository.fetchPageData(pageId, groupId, channelId, currentPage, pageSize)
  109 + .then((resDTO: ResponseDTO<PageDTO>) => {
  110 + if (this.isRespondsInvalid(resDTO, 'getPageData')) {
  111 + error("page data invalid");
102 return 112 return
103 } 113 }
104 Logger.info(TAG, "getPageData then,resDTO.timeStamp:" + resDTO.timestamp); 114 Logger.info(TAG, "getPageData then,resDTO.timeStamp:" + resDTO.timestamp);
105 success(resDTO.data); 115 success(resDTO.data);
106 - }).catch((err: Error) => { 116 + })
  117 + .catch((err: Error) => {
107 Logger.error(TAG, `getPageData catch, error.name : ${err.name}, error.message:${err.message}`); 118 Logger.error(TAG, `getPageData catch, error.name : ${err.name}, error.message:${err.message}`);
108 error(err); 119 error(err);
109 }) 120 })
@@ -112,7 +123,6 @@ export class PageViewModel { @@ -112,7 +123,6 @@ export class PageViewModel {
112 } 123 }
113 124
114 125
115 -  
116 let pageViewModel = new PageViewModel(); 126 let pageViewModel = new PageViewModel();
117 127
118 export default pageViewModel as PageViewModel; 128 export default pageViewModel as PageViewModel;
@@ -36,6 +36,12 @@ @@ -36,6 +36,12 @@
36 "name": "color_212228", 36 "name": "color_212228",
37 "value": "#212228" 37 "value": "#212228"
38 }, 38 },
39 - 39 + "name": "color_fff",
  40 + "value": "#ffffff"
  41 + },
  42 + {
  43 + "name": "color_4d000000",
  44 + "value": "#4d000000"
  45 + }
40 ] 46 ]
41 } 47 }
@@ -10,7 +10,11 @@ @@ -10,7 +10,11 @@
10 }, 10 },
11 { 11 {
12 "name": "font_size_12", 12 "name": "font_size_12",
13 - "value": "11fp" 13 + "value": "12fp"
  14 + },
  15 + {
  16 + "name": "font_size_13",
  17 + "value": "13fp"
14 }, 18 },
15 { 19 {
16 "name": "font_size_14", 20 "name": "font_size_14",
@@ -7,6 +7,30 @@ @@ -7,6 +7,30 @@
7 { 7 {
8 "name": "footer_text", 8 "name": "footer_text",
9 "value": "已经到底了" 9 "value": "已经到底了"
  10 + },
  11 + {
  12 + "name": "pull_up_load_text",
  13 + "value": "加载中..."
  14 + },
  15 + {
  16 + "name": "pull_down_refresh_text",
  17 + "value": "下拉刷新"
  18 + },
  19 + {
  20 + "name": "release_refresh_text",
  21 + "value": "松开刷新"
  22 + },
  23 + {
  24 + "name": "refreshing_text",
  25 + "value": "正在刷新"
  26 + },
  27 + {
  28 + "name": "refresh_success_text",
  29 + "value": "刷新成功"
  30 + },
  31 + {
  32 + "name": "refresh_fail_text",
  33 + "value": "刷新失败"
10 } 34 }
11 ] 35 ]
12 } 36 }
  1 +{
  2 + "src": [
  3 + "components/DemoPreviewerComponent",
  4 + "components/view/SmallVideoCardComponent"
  5 + ]
  6 +}
@@ -28,7 +28,7 @@ export class ConfigConstants { @@ -28,7 +28,7 @@ export class ConfigConstants {
28 /** 28 /**
29 * 产品渠道应用对照关系: 29 * 产品渠道应用对照关系:
30 */ 30 */
31 - static readonly appCode: string = ""; 31 + static readonly appCode: string = "83092caa603a421aa0222308b3f6b27a";
32 /** 32 /**
33 * 基线代码和客户端应用版本号规范 33 * 基线代码和客户端应用版本号规范
34 */ 34 */
@@ -10,3 +10,7 @@ export { BasicDataSource } from './utils/BasicDataSource'; @@ -10,3 +10,7 @@ export { BasicDataSource } from './utils/BasicDataSource';
10 10
11 export { LazyDataSource } from './utils/LazyDataSource' 11 export { LazyDataSource } from './utils/LazyDataSource'
12 12
  13 +export { DateTimeUtils } from './utils/DateTimeUtils'
  14 +
  15 +export { AppContext } from './utils/AppContext'
  16 +
  1 +/**
  2 + * 应用ability上下文管理类
  3 + */
  4 +export class AppContext {
  5 + private static sContext: Context;
  6 +
  7 + public static init(abilityContext: Context) {
  8 + this.sContext = abilityContext;
  9 + }
  10 +
  11 + public static getAbilityContext() {
  12 + return this.sContext;
  13 + }
  14 +}
@@ -316,6 +316,21 @@ export class DateTimeUtils { @@ -316,6 +316,21 @@ export class DateTimeUtils {
316 static isTomorrow(date: number): boolean { 316 static isTomorrow(date: number): boolean {
317 return this.isSameDay(date, this.addDays(Date.now(), 1).getTime()); 317 return this.isSameDay(date, this.addDays(Date.now(), 1).getTime());
318 } 318 }
  319 +
  320 +
  321 + /**
  322 + * 获取当前时间戳,秒
  323 + * */
  324 + public static getCurrentTime(): number {
  325 + let time: number = new Date().getTime();
  326 + return Math.floor(time / 1000);
  327 + }
  328 + /**
  329 + * 获取当前时间戳,毫秒
  330 + * */
  331 + public static getCurrentTimeMillis(): number {
  332 + return new Date().getTime();
  333 + }
319 } 334 }
320 335
321 // const dateTimeUtils = new DateTimeUtils() 336 // const dateTimeUtils = new DateTimeUtils()
@@ -36,6 +36,10 @@ export class LazyDataSource<T> extends BasicDataSource<T> { @@ -36,6 +36,10 @@ export class LazyDataSource<T> extends BasicDataSource<T> {
36 return this.dataArray; 36 return this.dataArray;
37 } 37 }
38 38
  39 + public size(): number {
  40 + return this.dataArray.length
  41 + }
  42 +
39 // 增加/插入1个Item/数据,若index为undefined,则在数据尾部增加1个元素;否则,在指定索引(可为负/或大于数组长度)位置插入1个元素 43 // 增加/插入1个Item/数据,若index为undefined,则在数据尾部增加1个元素;否则,在指定索引(可为负/或大于数组长度)位置插入1个元素
40 public addItem(data: T, index?: number): void { 44 public addItem(data: T, index?: number): void {
41 if (index == undefined) { 45 if (index == undefined) {
1 import buffer from '@ohos.buffer'; 1 import buffer from '@ohos.buffer';
  2 +import { AppContext } from './AppContext';
2 import { Logger } from './Logger'; 3 import { Logger } from './Logger';
3 4
4 const TAG = "ResourcesUtils"; 5 const TAG = "ResourcesUtils";
@@ -13,10 +14,13 @@ export class ResourcesUtils { @@ -13,10 +14,13 @@ export class ResourcesUtils {
13 * @param filename 仅文件名(不包含路径,文件在src\main\resources\rawfile下),如:"agconnect-services.json",test.xml, 14 * @param filename 仅文件名(不包含路径,文件在src\main\resources\rawfile下),如:"agconnect-services.json",test.xml,
14 * @returns text 字符串 15 * @returns text 字符串
15 */ 16 */
16 - static getResourcesText(context: Context, filename: string): Promise<string> { 17 + static getResourcesText(filename: string, context?: Context): Promise<string> {
  18 + if (context == null) {
  19 + context = AppContext.getAbilityContext();
  20 + }
17 return new Promise((success, error) => { 21 return new Promise((success, error) => {
18 Logger.info(TAG, "ResourcesUtils getResourcesText filename:" + filename); 22 Logger.info(TAG, "ResourcesUtils getResourcesText filename:" + filename);
19 - context.resourceManager.getRawFileContent(filename).then((content: Uint8Array) => { 23 + context?.resourceManager.getRawFileContent(filename).then((content: Uint8Array) => {
20 if (!content) { 24 if (!content) {
21 Logger.warn(TAG, 'getResourcesText then content is empty'); 25 Logger.warn(TAG, 'getResourcesText then content is empty');
22 error("file is empty"); 26 error("file is empty");
@@ -53,14 +57,17 @@ export class ResourcesUtils { @@ -53,14 +57,17 @@ export class ResourcesUtils {
53 * 调用方式: 57 * 调用方式:
54 * let compRes: MGHttp.ResponseDTO<BodyComponent> = await ResourcesUtils.getResourcesJson<MGHttp.ResponseDTO<BodyComponent>>(context, 'model/componentList.json'); 58 * let compRes: MGHttp.ResponseDTO<BodyComponent> = await ResourcesUtils.getResourcesJson<MGHttp.ResponseDTO<BodyComponent>>(context, 'model/componentList.json');
55 */ 59 */
56 - static getResourcesJson<R>(context:Context, filename: string): Promise<R> { 60 + static getResourcesJson<R>(filename: string, context?: Context): Promise<R> {
57 Logger.info(TAG, `getResourcesJson filename: ${filename}`); 61 Logger.info(TAG, `getResourcesJson filename: ${filename}`);
  62 + if (context == null) {
  63 + context = AppContext.getAbilityContext();
  64 + }
58 return new Promise<R>((resolve, reject) => { 65 return new Promise<R>((resolve, reject) => {
59 - ResourcesUtils.getResourcesText(context, filename) 66 + ResourcesUtils.getResourcesText(filename, context)
60 .then((text: string) => { 67 .then((text: string) => {
61 try { 68 try {
62 // let config: R = JSON.parse(text) 69 // let config: R = JSON.parse(text)
63 - let config:R = JSON.parse(text) as R; 70 + let config: R = JSON.parse(text) as R;
64 if (config) { 71 if (config) {
65 Logger.info(TAG, "getResourcesJson parse JSON file success."); 72 Logger.info(TAG, "getResourcesJson parse JSON file success.");
66 // Logger.info(TAG, `getResourcesJson config : ${JSON.stringify(config)}`); 73 // Logger.info(TAG, `getResourcesJson config : ${JSON.stringify(config)}`);
@@ -74,7 +81,7 @@ export class ResourcesUtils { @@ -74,7 +81,7 @@ export class ResourcesUtils {
74 reject(err) 81 reject(err)
75 } 82 }
76 }) 83 })
77 - .catch((error:Error) => { 84 + .catch((error: Error) => {
78 reject(error) 85 reject(error)
79 }) 86 })
80 }) 87 })
1 -import type { AxiosError, AxiosRequestConfig} from '@ohos/axios'; 1 +import { AxiosError, AxiosHeaders, AxiosRequestConfig, RawAxiosRequestHeaders } from '@ohos/axios';
  2 +import HashMap from '@ohos.util.HashMap';
2 import service from './AxiosRequest'; 3 import service from './AxiosRequest';
3 4
4 export class HttpRequest { 5 export class HttpRequest {
@@ -6,17 +7,28 @@ export class HttpRequest { @@ -6,17 +7,28 @@ export class HttpRequest {
6 static request<T = any>(config: AxiosRequestConfig): Promise<T> { 7 static request<T = any>(config: AxiosRequestConfig): Promise<T> {
7 return new Promise<T>((resolve, reject) => { 8 return new Promise<T>((resolve, reject) => {
8 service.request<any, T>(config) 9 service.request<any, T>(config)
9 - .then((res:T) => { 10 + .then((res: T) => {
10 resolve(res) 11 resolve(res)
11 }) 12 })
12 - .catch((err:AxiosError) => { 13 + .catch((err: AxiosError) => {
13 reject(err) 14 reject(err)
14 }) 15 })
15 }) 16 })
16 // return service.request<any, T>(config) 17 // return service.request<any, T>(config)
17 } 18 }
18 19
19 - static get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> { 20 + private static get0<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
  21 + return service.get(url, config)
  22 + }
  23 +
  24 + static get<T = any>(url: string, headers?: HashMap<string, string>): Promise<T> {
  25 + let requestHeaders: AxiosHeaders = new AxiosHeaders()
  26 + headers?.forEach((v, k) => {
  27 + requestHeaders.set(k, v);
  28 + });
  29 + let config: AxiosRequestConfig = {
  30 + headers: requestHeaders as RawAxiosRequestHeaders
  31 + }
20 return service.get(url, config) 32 return service.get(url, config)
21 } 33 }
22 34
@@ -5,13 +5,13 @@ @@ -5,13 +5,13 @@
5 "name": "default", 5 "name": "default",
6 "type": "HarmonyOS", 6 "type": "HarmonyOS",
7 "material": { 7 "material": {
8 - "certpath": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000309521319.cer",  
9 - "storePassword": "0000001AB8EC943F2BE2E18A8AEFE1FCA450B66E91DFD2548DD09FD6AB15755699E084327B0CC2ED695B", 8 + "certpath": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.cer",
  9 + "storePassword": "0000001B4100D63EDF7155D2954BDDEC8F40FA74E710B0D1FF3C0782DE2745F90F1B83D1C1C110398F4559",
10 "keyAlias": "debugKey", 10 "keyAlias": "debugKey",
11 - "keyPassword": "0000001AAB9FF41A89BB2C32EA7122E2EE2E6C97447932FDC7E91010CC02128130B6040A09EBC04CD07E",  
12 - "profile": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000309521319.p7b", 11 + "keyPassword": "0000001B157D6824BE8F21F112459AD1B61654DE9396A50B0CE60898F02F4C95CBF127122F293DD6C80C62",
  12 + "profile": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.p7b",
13 "signAlg": "SHA256withECDSA", 13 "signAlg": "SHA256withECDSA",
14 - "storeFile": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000309521319.p12" 14 + "storeFile": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.p12"
15 } 15 }
16 } 16 }
17 ], 17 ],
@@ -134,17 +134,17 @@ @@ -134,17 +134,17 @@
134 } 134 }
135 ] 135 ]
136 } 136 }
137 -// {  
138 -// "name": "wdLayout",  
139 -// "srcPath": "./wdLayout",  
140 -// "targets": [  
141 -// {  
142 -// "name": "default",  
143 -// "applyToProducts": [  
144 -// "default"  
145 -// ]  
146 -// }  
147 -// ]  
148 -// } 137 + // {
  138 + // "name": "wdLayout",
  139 + // "srcPath": "./wdLayout",
  140 + // "targets": [
  141 + // {
  142 + // "name": "default",
  143 + // "applyToProducts": [
  144 + // "default"
  145 + // ]
  146 + // }
  147 + // ]
  148 + // }
149 ] 149 ]
150 } 150 }
  1 +import { ENewspaperPageComponent } from 'wdComponent';
  2 +import { Logger } from 'wdKit'
  3 +
  4 +const TAG = 'ENewspaper';
  5 +
  6 +@Entry
  7 +@Component
  8 +struct ENewspaper {
  9 +
  10 + build() {
  11 + Column() {
  12 + ENewspaperPageComponent()
  13 + }
  14 + }
  15 +
  16 + pageTransition(){
  17 + // 定义页面进入时的效果,从底侧滑入
  18 + PageTransitionEnter({ type: RouteType.None, duration: 300 })
  19 + .slide(SlideEffect.Bottom)
  20 + // 定义页面退出时的效果,向底侧滑出
  21 + PageTransitionExit({ type: RouteType.None, duration: 300 })
  22 + .slide(SlideEffect.Bottom)
  23 + }
  24 +
  25 + aboutToAppear() {
  26 + Logger.info(TAG, 'aboutToAppear');
  27 + }
  28 +
  29 + aboutToDisappear() {
  30 + Logger.info(TAG, 'aboutToDisappear');
  31 + }
  32 +
  33 + onPageShow() {
  34 + Logger.info(TAG, 'onPageShow');
  35 + }
  36 +
  37 + onPageHide() {
  38 + Logger.info(TAG, 'onPageHide');
  39 + }
  40 +
  41 + onBackPress() {
  42 + Logger.info(TAG, 'onBackPress');
  43 + }
  44 +}
1 { 1 {
2 "src": [ 2 "src": [
3 "pages/Index", 3 "pages/Index",
4 - "pages/web/DefaultWebPage" 4 + "pages/web/DefaultWebPage",
  5 + "pages/ENewspaper"
5 ] 6 ]
6 } 7 }
This diff could not be displayed because it is too large.
  1 +{
  2 + "code": "0",
  3 + "data": [{
  4 + "date": "49997-06-15",
  5 + "list": [{
  6 + "exist": 1,
  7 + "pageName": "",
  8 + "pageNum": "05",
  9 + "periodNum": "49997-06-15"
  10 + }]
  11 + }],
  12 + "message": "Success",
  13 + "meta": null,
  14 + "requestId": "",
  15 + "success": true,
  16 + "timestamp": 1706170629625
  17 +}
@@ -39,3 +39,15 @@ export { GroupDTO } from './src/main/ets/bean/component/GroupDTO'; @@ -39,3 +39,15 @@ export { GroupDTO } from './src/main/ets/bean/component/GroupDTO';
39 export { CompDTO } from './src/main/ets/bean/component/CompDTO'; 39 export { CompDTO } from './src/main/ets/bean/component/CompDTO';
40 40
41 export { ContentDTO } from './src/main/ets/bean/component/ContentDTO'; 41 export { ContentDTO } from './src/main/ets/bean/component/ContentDTO';
  42 +
  43 +export { NewspaperListBean } from './src/main/ets/bean/newspaper/NewspaperListBean';
  44 +
  45 +export { NewspaperListItemBean } from './src/main/ets/bean/newspaper/NewspaperListItemBean';
  46 +
  47 +export { NewspaperPositionItemBean } from './src/main/ets/bean/newspaper/NewspaperPositionItemBean';
  48 +
  49 +export { NewspaperShareBean } from './src/main/ets/bean/newspaper/NewspaperShareBean';
  50 +
  51 +export { NewspaperTimeInfoBean} from './src/main/ets/bean/newspaper/NewspaperTimeInfoBean';
  52 +
  53 +export { NewspaperTimeItemBean } from './src/main/ets/bean/newspaper/NewspaperTimeItemBean';
  1 +import { NewspaperListItemBean } from './NewspaperListItemBean';
  2 +
  3 +export interface NewspaperListBean {
  4 + list:NewspaperListItemBean[];
  5 +}
  1 +import { NewspaperPositionItemBean } from './NewspaperPositionItemBean';
  2 +import { NewspaperShareBean } from './NewspaperShareBean';
  3 +
  4 +export interface NewspaperListItemBean {
  5 + items:NewspaperPositionItemBean[];
  6 + pageName:string;
  7 + pageNum:string;
  8 + pagePic:string;
  9 + periodNum:string;
  10 + sharePagePic:NewspaperShareBean;
  11 +}
  1 +export interface NewspaperPositionItemBean {
  2 + image:string[];
  3 + downTitle:string;
  4 + imageHeight:number;
  5 + imageWidth:number;
  6 + newsId:number;
  7 + newsTxt:string;
  8 + newsType:number;
  9 + points:string;
  10 + relId:number;
  11 + relObjectId: string;
  12 + relType: string;
  13 + shortTitle: string;
  14 + title: string;
  15 +}
  1 +export interface NewspaperShareBean {
  2 + shareUrl:string;
  3 + sharePosterOpen:number;
  4 +}
  1 +import { NewspaperTimeItemBean } from './NewspaperTimeItemBean';
  2 +
  3 +export interface NewspaperTimeInfoBean {
  4 + date:string;
  5 + list:NewspaperTimeItemBean[];
  6 +}
  1 +export interface NewspaperTimeItemBean {
  2 + pageName:string;
  3 + pageNum:string;
  4 + periodNum:string;
  5 + exit:number;
  6 +}
@@ -25,3 +25,7 @@ export { SingleColumnComponent } from "./src/main/ets/components/SingleColumnCom @@ -25,3 +25,7 @@ export { SingleColumnComponent } from "./src/main/ets/components/SingleColumnCom
25 export { GridLayout01Component } from "./src/main/ets/components/GridLayout01Component" 25 export { GridLayout01Component } from "./src/main/ets/components/GridLayout01Component"
26 26
27 export { WaterFlowComponent } from "./src/main/ets/components/WaterFlowComponent" 27 export { WaterFlowComponent } from "./src/main/ets/components/WaterFlowComponent"
  28 +
  29 +export { NewspaperViewModel} from "./src/main/ets/viewmodel/NewspaperViewModel"
  30 +
  31 +export {ENewspaperPageComponent} from "./src/main/ets/components/ENewspaperPageComponent"
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 "wdConstant": "file:../wdConstant", 10 "wdConstant": "file:../wdConstant",
11 "wdKit": "file:../wdKit", 11 "wdKit": "file:../wdKit",
12 "wdBean": "file:../wdBean", 12 "wdBean": "file:../wdBean",
13 - "wdNetwork": "file:../wdNetwork",  
14 - "wdRouter": "file:../wdRouter" 13 + "wdRouter": "file:../wdRouter",
  14 + "wdNetwork": "file:../wdNetwork"
15 } 15 }
16 } 16 }
  1 +import { NewspaperListItemBean, NewspaperPositionItemBean } from 'wdBean';
  2 +import { StringUtils } from 'wdKit';
  3 +
  4 +@Component
  5 +export struct ENewspaperItemComponent {
  6 + private newspaperListItemBean: NewspaperListItemBean = {} as NewspaperListItemBean
  7 + private settings: RenderingContextSettings = new RenderingContextSettings(true);
  8 + private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
  9 + private startX: number = 0
  10 + private startY: number = 0
  11 + private itemBeanClicked: NewspaperPositionItemBean = {} as NewspaperPositionItemBean
  12 +
  13 + build() {
  14 + Stack() {
  15 + Image(this.newspaperListItemBean.pagePic)
  16 + .width('100%')
  17 + .aspectRatio(0.68688)
  18 + .objectFit(ImageFit.Contain)
  19 +
  20 + Canvas(this.context)
  21 + .width('100%')
  22 + .height('100%')
  23 + .backgroundColor(Color.Transparent)
  24 + .onReady(() => {
  25 +
  26 + })
  27 + }
  28 + .width('100%')
  29 + .aspectRatio(0.68688)
  30 + .onClick((event: ClickEvent) =>{
  31 + if (this.itemBeanClicked && this.itemBeanClicked.newsId){
  32 + // todo 跳转事件
  33 +
  34 +
  35 + this.itemBeanClicked = {} as NewspaperPositionItemBean
  36 + }
  37 + })
  38 + .onTouch((event: TouchEvent) => {
  39 + if (event.type === TouchType.Down) {
  40 + let x = event.touches[0].x;
  41 + let y = event.touches[0].y;
  42 + this.startX = x;
  43 + this.startY = y;
  44 + let points: number[][] = this.getArea(x, y, this.newspaperListItemBean.items);
  45 + if (points && points.length > 2){
  46 + let path = new Path2D();
  47 + path.moveTo(px2vp(points[0][0]), px2vp(points[0][1]));
  48 + for(let point of points.slice(1, points.length)){
  49 + path.lineTo(px2vp(point[0]), px2vp(point[1]));
  50 + }
  51 + path.closePath();
  52 + // 设定填充色为蓝色
  53 + this.context.fillStyle = '#33000000';
  54 + // 使用填充的方式,将Path2D描述的五边形绘制在canvas组件内部
  55 + this.context.fill(path);
  56 + }
  57 +
  58 + }
  59 + if (event.type === TouchType.Up) {
  60 + this.context.clearRect(0, 0, this.context.width, this.context.height)
  61 + }
  62 + if (event.type === TouchType.Move) {
  63 + let mx = event.touches[0].x;
  64 + let my = event.touches[0].y;
  65 + if (this.startX - mx > 5 || mx - this.startX > 5 || this.startY - my > 5 || my - this.startY > 5){
  66 + this.itemBeanClicked = {} as NewspaperPositionItemBean
  67 + this.context.clearRect(0, 0, this.context.width, this.context.height)
  68 + }
  69 +
  70 + }
  71 + })
  72 + }
  73 +
  74 + public getArea(x: number, y: number, itemBeans: NewspaperPositionItemBean[]): number[][] {
  75 + if (itemBeans && itemBeans.length > 0) {
  76 + for (let itemBean of itemBeans) {
  77 + if (itemBean.points) {
  78 + let area: string[] = itemBean.points.split(';')
  79 + if (area && area.length > 0) {
  80 + let xys: number[][] = []
  81 + let minX: number = -1;
  82 + let maxX: number = -1;
  83 + let minY: number = -1;
  84 + let maxY: number = -1;
  85 + for (let item of area) {
  86 + let pair: string[] = item.split(',');
  87 + if (pair && pair.length > 1) {
  88 + // todo 因为数据是根据安卓手机抓的,这里根据分辨率倍数做了数据放大处理,真实数据不用乘以放大倍数
  89 + let xy: number[] = [StringUtils.parseNumber(pair[0])*1.28, StringUtils.parseNumber(pair[1])*1.24]
  90 + if (minX < 0) {
  91 + minX = xy[0]
  92 + } else {
  93 + if (minX > xy[0]) {
  94 + minX = xy[0]
  95 + }
  96 + }
  97 + if (maxX < 0) {
  98 + maxX = xy[0]
  99 + } else {
  100 + if (maxX < xy[0]) {
  101 + maxX = xy[0]
  102 + }
  103 + }
  104 + if (minY < 0) {
  105 + minY = xy[1]
  106 + } else {
  107 + if (minY > xy[1]) {
  108 + minY = xy[1]
  109 + }
  110 + }
  111 + if (maxY < 0) {
  112 + maxY = xy[1]
  113 + } else {
  114 + if (maxY < xy[1]) {
  115 + maxY = xy[1]
  116 + }
  117 + }
  118 + xys.push(xy);
  119 + }
  120 +
  121 + }
  122 +
  123 + if (vp2px(x) > minX && vp2px(x) < maxX && vp2px(y) > minY && vp2px(y) < maxY) {
  124 + this.itemBeanClicked = itemBean;
  125 + return xys;
  126 + }
  127 + }
  128 + }
  129 +
  130 + }
  131 + }
  132 + return []
  133 + }
  134 +}
  1 +import { NewspaperListBean, NewspaperListItemBean } from 'wdBean'
  2 +import { NewspaperViewModel } from '../viewmodel/NewspaperViewModel'
  3 +import router from '@ohos.router'
  4 +import { Logger } from 'wdKit';
  5 +import { ENewspaperItemComponent } from './ENewspaperItemComponent'
  6 +
  7 +@Component
  8 +export struct ENewspaperPageComponent {
  9 + @State newspaperListBean: NewspaperListBean = {} as NewspaperListBean
  10 + @State currentPageNum: string = '01';
  11 + private swiperController: SwiperController = new SwiperController()
  12 +
  13 +
  14 + build() {
  15 + RelativeContainer() {
  16 + RelativeContainer() {
  17 + Image($r('app.media.icon_arrow_down'))
  18 + .height($r('app.float.top_arrow_size'))
  19 + .width($r('app.float.top_arrow_size'))
  20 + .alignRules({ left: { anchor: "__container__", align: HorizontalAlign.Start },
  21 + center: { anchor: "__container__", align: VerticalAlign.Center } })
  22 + .id('e_newspaper_back')
  23 + .onClick((event: ClickEvent) => {
  24 + Logger.info("sfsfsd", "" + vp2px(10))
  25 + router.back()
  26 + })
  27 +
  28 + Row() {
  29 + Text('2024.01.26')
  30 + .fontSize($r('app.float.font_size_20'))
  31 + .fontColor($r('app.color.white'))
  32 +
  33 + Image($r('app.media.icon_triangle'))
  34 + .width($r('app.float.border_radius_6'))
  35 + .height($r('app.float.border_radius_6'))
  36 + .margin({ left: 2, bottom: 5 })
  37 + }
  38 + .alignItems(VerticalAlign.Bottom)
  39 + .alignRules({ middle: { anchor: "__container__", align: HorizontalAlign.Center },
  40 + center: { anchor: "__container__", align: VerticalAlign.Center } })
  41 + .id('e_newspaper_date')
  42 +
  43 + Image($r('app.media.icon_share'))
  44 + .height($r('app.float.top_arrow_size'))
  45 + .width($r('app.float.top_arrow_size'))
  46 + .alignRules({ right: { anchor: "__container__", align: HorizontalAlign.End },
  47 + center: { anchor: "__container__", align: VerticalAlign.Center } })
  48 + .id('e_newspaper_share')
  49 + }
  50 + .margin({ left: $r('app.float.margin_16'), right: $r('app.float.margin_16') })
  51 + .height($r('app.float.top_bar_height'))
  52 + .alignRules({ top: { anchor: '__container__', align: VerticalAlign.Top },
  53 + left: { anchor: '__container__', align: HorizontalAlign.Start },
  54 + right: { anchor: '__container__', align: HorizontalAlign.End } })
  55 + .id('e_newspaper_top')
  56 +
  57 + if (this.newspaperListBean && this.newspaperListBean.list && this.newspaperListBean.list.length > 0) {
  58 + Swiper(this.swiperController) {
  59 + ForEach(this.newspaperListBean?.list, (item: NewspaperListItemBean, index: number) => {
  60 + ENewspaperItemComponent({newspaperListItemBean: item})
  61 + })
  62 + }
  63 + .width('100%')
  64 + .vertical(true)
  65 + .autoPlay(false)
  66 + .cachedCount(3)
  67 + .indicator(false)
  68 + .displayCount(1)
  69 + .aspectRatio(0.68688)
  70 + .margin({ top: $r('app.float.vp_55'), left: 10, right: 10 })
  71 + .id('e_newspaper_content')
  72 + .alignRules({ top: { anchor: "e_newspaper_top", align: VerticalAlign.Bottom },
  73 + middle: { anchor: "__container__", align: HorizontalAlign.Center } })
  74 + .onChange((index: number) => {
  75 + this.currentPageNum = this.newspaperListBean?.list[index]?.pageNum
  76 + })
  77 +
  78 + Image($r('app.media.newspaper_shadow'))
  79 + .height($r('app.float.vp_12'))
  80 + .margin({ left: 12, right: 12, top: -5 })
  81 + .objectFit(ImageFit.Contain)
  82 + .alignRules({ top: { anchor: "e_newspaper_content", align: VerticalAlign.Bottom },
  83 + left: { anchor: 'e_newspaper_content', align: HorizontalAlign.Start },
  84 + right: { anchor: 'e_newspaper_content', align: HorizontalAlign.End } })
  85 + .id('e_newspaper_shadow')
  86 +
  87 + Row() {
  88 + Text('滑动查看下一版')
  89 + .fontColor(Color.White)
  90 + .fontSize($r('app.float.font_size_14'))
  91 + Image($r('app.media.icon_next_page'))
  92 + .width($r('app.float.vp_16'))
  93 + .height($r('app.float.vp_16'))
  94 + }
  95 + .justifyContent(FlexAlign.Center)
  96 + .margin({ top: $r('app.float.margin_16') })
  97 + .alignRules({ top: { anchor: "e_newspaper_shadow", align: VerticalAlign.Bottom },
  98 + middle: { anchor: "__container__", align: HorizontalAlign.Center } })
  99 + .id('e_newspaper_next')
  100 + .onClick((event: ClickEvent) => {
  101 + this.swiperController.showNext()
  102 + })
  103 + }
  104 +
  105 + Row() {
  106 + Text(this.currentPageNum)
  107 + .fontSize($r('app.float.font_size_36'))
  108 + .fontColor($r('app.color.white'))
  109 + Text('版')
  110 + .fontSize($r('app.float.font_size_16'))
  111 + .fontColor($r('app.color.white'))
  112 + .margin({ bottom: 6 })
  113 +
  114 + Image($r('app.media.icon_triangle'))
  115 + .width($r('app.float.border_radius_6'))
  116 + .height($r('app.float.border_radius_6'))
  117 + .margin({ left: 2, bottom: 6 })
  118 + }
  119 + .alignItems(VerticalAlign.Bottom)
  120 + .margin({ left: $r('app.float.margin_16'), bottom: $r('app.float.top_tab_bar_height') })
  121 + .alignRules({ bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
  122 + left: { anchor: '__container__', align: HorizontalAlign.Start } })
  123 + .id('e_newspaper_page_num')
  124 +
  125 + Row() {
  126 + Image($r('app.media.icon_read_paper'))
  127 + .width($r('app.float.vp_20'))
  128 + .height($r('app.float.vp_20'))
  129 + .margin({ right: $r('app.float.vp_3') })
  130 + Text('读报纸')
  131 + .fontSize($r('app.float.font_size_14'))
  132 + .fontColor($r('app.color.white'))
  133 + }
  134 + .alignItems(VerticalAlign.Center)
  135 + .margin({ right: $r('app.float.margin_16'), bottom: $r('app.float.top_tab_bar_height') })
  136 + .alignRules({ bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
  137 + right: { anchor: '__container__', align: HorizontalAlign.End } })
  138 + .id('e_newspaper_read')
  139 + }
  140 + .width('100%')
  141 + .height('100%')
  142 + .backgroundColor($r('app.color.color_80000000'))
  143 + .id('e_newspaper_container')
  144 + }
  145 +
  146 + aboutToAppear() {
  147 + let listBean = NewspaperViewModel.getNewspaperListFromLocal(getContext(this));
  148 + this.newspaperListBean = listBean;
  149 +
  150 + }
  151 +
  152 + aboutToDisappear() {
  153 +
  154 + }
  155 +}
1 -import { GroupDTO, TopNavBean } from 'wdBean'; 1 +import { Action, GroupDTO, Params, TopNavBean } from 'wdBean';
2 import { LazyDataSource, Logger } from 'wdKit'; 2 import { LazyDataSource, Logger } from 'wdKit';
  3 +import { WDRouterRule } from 'wdRouter';
3 import { PageComponent } from './PageComponent'; 4 import { PageComponent } from './PageComponent';
4 5
5 const TAG = 'TopNavigationComponent'; 6 const TAG = 'TopNavigationComponent';
@@ -17,6 +18,19 @@ export struct TopNavigationComponent { @@ -17,6 +18,19 @@ export struct TopNavigationComponent {
17 readonly MAX_LINE: number = 1; 18 readonly MAX_LINE: number = 1;
18 19
19 build() { 20 build() {
  21 + Column(){
  22 + Image($r('app.media.icon_ren_min_ri_bao'))
  23 + .width(72)
  24 + .height(29)
  25 + .onClick((event: ClickEvent) => {
  26 + let taskAction: Action = {
  27 + type: 'JUMP_INNER_NEW_PAGE',
  28 + params: {
  29 + pageID: 'E_NEWSPAPER'
  30 + } as Params,
  31 + };
  32 + WDRouterRule.jumpWithAction(taskAction)
  33 + })
20 Tabs() { 34 Tabs() {
21 ForEach(this.topNavList, (navItem: TopNavBean, index: number) => { 35 ForEach(this.topNavList, (navItem: TopNavBean, index: number) => {
22 TabContent() { 36 TabContent() {
@@ -34,6 +48,8 @@ export struct TopNavigationComponent { @@ -34,6 +48,8 @@ export struct TopNavigationComponent {
34 }) 48 })
35 } 49 }
36 50
  51 + }
  52 +
37 @Builder 53 @Builder
38 tabBarBuilder(item: TopNavBean, index: number) { 54 tabBarBuilder(item: TopNavBean, index: number) {
39 Column() { 55 Column() {
  1 +import { BottomNavBean, GroupDTO, NavigationBody, NewspaperListBean, NewspaperTimeInfoBean } from 'wdBean';
  2 +import { Logger, ResourcesUtils } from 'wdKit';
  3 +import { ResponseDTO, WDHttp } from 'wdNetwork';
  4 +import { PageRepository } from '../repository/PageRepository';
  5 +import http from '@ohos.net.http';
  6 +import { BusinessError } from '@ohos.base';
  7 +
  8 +const TAG = 'NewspaperViewModel';
  9 +
  10 +export class NewspaperViewModel {
  11 +
  12 + static getNewspaperTimeFromLocal(context: Context): NewspaperTimeInfoBean[] {
  13 + Logger.info(TAG, `getNewspaperTimeFromLocal start`);
  14 + let newspaperTimeInfo: ResponseDTO<NewspaperTimeInfoBean[]> | null = ResourcesUtils.getResourcesJsonSync<ResponseDTO<NewspaperTimeInfoBean[]>>(context, 'newspaper_info.json');
  15 + if (!newspaperTimeInfo || !newspaperTimeInfo.data) {
  16 + Logger.info(TAG, `getNewspaperTimeFromLocal List is empty`);
  17 + return []
  18 + }
  19 + return newspaperTimeInfo.data
  20 + }
  21 +
  22 + static getNewspaperListFromLocal(context: Context): NewspaperListBean {
  23 + let newspaperListBean: ResponseDTO<NewspaperListBean> | null = ResourcesUtils.getResourcesJsonSync<ResponseDTO<NewspaperListBean>>(context, 'newspaper_datalist.json');
  24 + if (!newspaperListBean || !newspaperListBean.data) {
  25 + Logger.info(TAG, `getCompList compRes is empty`);
  26 + return {} as NewspaperListBean
  27 + }
  28 + return newspaperListBean.data
  29 + }
  30 +}
@@ -19,6 +19,14 @@ @@ -19,6 +19,14 @@
19 { 19 {
20 "name": "color_FE4B05", 20 "name": "color_FE4B05",
21 "value": "#FE4B05" 21 "value": "#FE4B05"
  22 + },
  23 + {
  24 + "name": "color_505050",
  25 + "value": "#505050"
  26 + },
  27 + {
  28 + "name": "color_80000000",
  29 + "value": "#80000000"
22 } 30 }
23 ] 31 ]
24 } 32 }
@@ -32,7 +32,14 @@ @@ -32,7 +32,14 @@
32 "name": "font_size_24", 32 "name": "font_size_24",
33 "value": "24fp" 33 "value": "24fp"
34 }, 34 },
35 - 35 + {
  36 + "name": "font_size_20",
  37 + "value": "20fp"
  38 + },
  39 + {
  40 + "name": "font_size_36",
  41 + "value": "36fp"
  42 + },
36 { 43 {
37 "name": "main_margin", 44 "name": "main_margin",
38 "value": "14vp" 45 "value": "14vp"
@@ -104,6 +111,42 @@ @@ -104,6 +111,42 @@
104 { 111 {
105 "name": "top_tab_item_padding_top", 112 "name": "top_tab_item_padding_top",
106 "value": "2vp" 113 "value": "2vp"
  114 + },
  115 + {
  116 + "name": "top_bar_height",
  117 + "value": "44vp"
  118 + },
  119 + {
  120 + "name": "top_arrow_size",
  121 + "value": "24vp"
  122 + },
  123 + {
  124 + "name": "margin_16",
  125 + "value": "16vp"
  126 + },
  127 + {
  128 + "name": "vp_20",
  129 + "value": "20vp"
  130 + },
  131 + {
  132 + "name": "vp_3",
  133 + "value": "3vp"
  134 + },
  135 + {
  136 + "name": "vp_55",
  137 + "value": "55vp"
  138 + },
  139 + {
  140 + "name": "vp_12",
  141 + "value": "12vp"
  142 + },
  143 + {
  144 + "name": "vp_8",
  145 + "value": "8vp"
  146 + },
  147 + {
  148 + "name": "vp_16",
  149 + "value": "16vp"
107 } 150 }
108 ] 151 ]
109 } 152 }
@@ -63,10 +63,10 @@ export function registerRouter() { @@ -63,10 +63,10 @@ export function registerRouter() {
63 return WDRouterPage.defaultWebPage 63 return WDRouterPage.defaultWebPage
64 }) 64 })
65 65
66 - // Action2Page.register("JUMP_INNER_NEW_PAGE", (action) => {  
67 - // if (action.params?.pageID == "WORLDCUP_DETAIL") {  
68 - // return WDRouterPage.livependantpage  
69 - // }  
70 - // return undefined  
71 - // }) 66 + Action2Page.register("JUMP_INNER_NEW_PAGE", (action) => {
  67 + if (action.params?.pageID == "E_NEWSPAPER") {
  68 + return WDRouterPage.eNewspaper
  69 + }
  70 + return undefined
  71 + })
72 } 72 }
@@ -20,4 +20,6 @@ export class WDRouterPage { @@ -20,4 +20,6 @@ export class WDRouterPage {
20 // static aboutPage = new WDRouterPage("entry", "ets/pages/about/AboutPage"); 20 // static aboutPage = new WDRouterPage("entry", "ets/pages/about/AboutPage");
21 // web默认页面 21 // web默认页面
22 static defaultWebPage = new WDRouterPage("entry", "ets/pages/web/DefaultWebPage"); 22 static defaultWebPage = new WDRouterPage("entry", "ets/pages/web/DefaultWebPage");
  23 + // 电子报页面
  24 + static eNewspaper = new WDRouterPage("entry", "ets/pages/ENewspaper")
23 } 25 }