fanmingyou3_wd

把DevEco3.1的PeopleDaily_Harmony中的代码合并到DevEco4.0的sight_harmony中

Showing 103 changed files with 3266 additions and 1057 deletions
... ... @@ -4,12 +4,15 @@ import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';
import { registerRouter } from 'wdRouter';
import { WindowModel } from 'wdKit';
import { SPHelper, WindowModel } from 'wdKit';
import { WDHttp } from 'wdNetwork'
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
SPHelper.init(this.context);
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
registerRouter();
WDHttp.initHttpHeader()
}
onDestroy(): void {
... ... @@ -29,7 +32,7 @@ export default class EntryAbility extends UIAbility {
.catch((err: Error) => {
hilog.error(0x0000, 'testTag', `setPreferredOrientation catch, error error.name : ${err.name}, error.message:${err.message}`);
})
windowStage.loadContent('pages/Index', (err, data) => {
windowStage.loadContent('pages/MainPage', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
... ...
import { BottomNavBean } from 'wdBean';
import { BottomNavigationComponent, PageViewModel } from 'wdComponent';
import { BottomNavigationComponent} from 'wdComponent';
import { BreakpointConstants } from 'wdConstant';
import { BreakpointSystem, Logger } from 'wdKit';
const TAG = 'Index';
const TAG = 'MainPage';
@Entry
@Component
struct Index {
struct MainPage {
private breakpointSystem: BreakpointSystem = new BreakpointSystem()
@StorageLink('currentBreakpoint') @Watch('watchCurrentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_XS;
@State bottomNavList: BottomNavBean[] = []
watchCurrentBreakpoint() {
Logger.info(TAG, `watchCurrentBreakpoint, this.currentBreakpoint: ${this.currentBreakpoint}`);
}
build() {
Column() {
BottomNavigationComponent({ bottomNavList: this.bottomNavList })
}
}
aboutToAppear() {
this.breakpointSystem.register()
let bottomNav = PageViewModel.getBottomNavData(getContext(this))
if (bottomNav) {
Logger.info(TAG, `aboutToAppear, bottomNav.length: ${bottomNav.length}`);
this.bottomNavList = bottomNav
}
Logger.info(TAG, `aboutToAppear `);
}
aboutToDisappear() {
... ... @@ -47,4 +36,10 @@ struct Index {
onBackPress() {
Logger.info(TAG, 'onBackPress');
}
build() {
Column() {
BottomNavigationComponent()
}
}
}
\ No newline at end of file
... ...
{
"src": [
"pages/Index",
"pages/MainPage",
"pages/web/DefaultWebPage",
"pages/ENewspaper"
]
... ...
... ... @@ -4,39 +4,40 @@
"backgroundColor": "#FFFFFF",
"bottomNavList": [
{
"backgroundUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231214/image/display/2e1d5f235d1a44cfb9fc120e8596c56b.png",
"channelChooseActionUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231227/vod/display/7c92f5b2a08b4a65aa9da13e66d5ad4a.pag",
"channelChooseCColor": "#666666",
"channelChooseColor": "#222222",
"channelMoreColor": "#666666",
"backgroundUrl": "",
"channelChooseActionUrl": "",
"channelChooseCColor": "",
"channelChooseColor": "",
"channelMoreColor": "",
"extraData": "{\"haveSearch\":\"1\",\"haveTopNav\":\"1\",\"leftIconurl\":\"\",\"rightIconUrl\":\"\"}",
"homePageColor": "#FFFFF",
"icon": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231220/image/display/0dc20f38da09405ea0ab675d700bc2ce.png",
"iconC": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231220/image/display/e162a5d3401045f298c237f1c795c015.gif",
"homePageColor": "",
"icon": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/a59ee3978357490bb58cbc378d70b557.png",
"iconC": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/213ab95c788d41f2838771e1eaaba62d.png",
"id": 201,
"immersiveIconCUrl": "",
"immersiveIconUrl": "",
"immersiveNameCColor": "#FFFFFF",
"immersiveNameColor": "#FFFFFF",
"logoUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231229/image/display/51d568f9af05421f9754a2c08906dc42.png",
"morningAndEveningUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231214/image/display/0f37cc0c86194c969d2143f85c056c9c.png",
"immersiveNameCColor": "",
"immersiveNameColor": "",
"logoUrl": "",
"morningAndEveningUrl": "",
"name": "新闻",
"nameCColor": "#ED2800",
"nameCColor": "#CB0000",
"nameColor": "#999999",
"nightIconCUrl": "",
"nightIconUrl": "",
"nightNameCColor": "",
"nightNameColor": "",
"noticeColor": "#FFFFFF",
"noticeColor": "",
"pageId": null,
"pageType": null,
"searchBothColor": "#666666",
"searchUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231214/image/display/2f2a9b3af5334eac8d7c3b6007240b83.png",
"searchBothColor": "",
"searchUrl": "",
"sortValue": 1,
"statusBarColor": 1,
"statusBarColor": null,
"topNavChannelList": [
{
"channelId": 2002,
"channelId": 2001,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 1,
... ... @@ -53,21 +54,22 @@
"moreChannel": "0",
"movePermitted": 0,
"myChannel": "0",
"name": "热点",
"name": "推荐",
"num": 1,
"pageId": 20012,
"pageId": 20011,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2001,
"channelId": 2002,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 1,
"delPermitted": 0,
"fontCColor": "#FFFFFF",
"fontColor": "#F9AB99",
"headlinesOn": 0,
"headlinesOn": 1,
"homeChannel": "0",
"iconCUrl": "",
"iconCUrlSize": "",
... ... @@ -77,15 +79,16 @@
"moreChannel": "0",
"movePermitted": 0,
"myChannel": "0",
"name": "推荐",
"name": "热点",
"num": 2,
"pageId": 20011,
"pageId": 20012,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2009,
"channelStyle": 2,
"channelId": 2066,
"channelStrategy": 2,
"channelStyle": 3,
"channelType": 1,
"defaultPermitted": 0,
"delPermitted": 1,
... ... @@ -101,14 +104,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "社会",
"name": "播报",
"num": 3,
"pageId": 20019,
"pageId": 21003,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2066,
"channelId": 2006,
"channelStrategy": 2,
"channelStyle": 3,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -125,14 +129,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "播报",
"name": "版面",
"num": 4,
"pageId": 21003,
"pageId": 20016,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2012,
"channelId": 2065,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -147,16 +152,17 @@
"iconUrlSize": "",
"localChannel": "0",
"moreChannel": "0",
"movePermitted": 0,
"movePermitted": 1,
"myChannel": "0",
"name": "文化",
"name": "三农",
"num": 5,
"pageId": 20022,
"pageId": 21002,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2007,
"channelId": 2063,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -173,38 +179,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "镜头",
"name": "两会",
"num": 6,
"pageId": 20017,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2006,
"channelStyle": 3,
"channelType": 1,
"defaultPermitted": 0,
"delPermitted": 1,
"fontCColor": "#FFFFFF",
"fontColor": "#F9AB99",
"headlinesOn": 0,
"homeChannel": "0",
"iconCUrl": "",
"iconCUrlSize": "",
"iconUrl": "",
"iconUrlSize": "",
"localChannel": "0",
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "版面",
"num": 7,
"pageId": 20016,
"pageId": 21000,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2015,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -214,9 +197,9 @@
"headlinesOn": 0,
"homeChannel": "0",
"iconCUrl": "",
"iconCUrlSize": "210*60",
"iconCUrlSize": "",
"iconUrl": "",
"iconUrlSize": "210*60",
"iconUrlSize": "",
"localChannel": "0",
"moreChannel": "0",
"movePermitted": 1,
... ... @@ -228,11 +211,12 @@
"underlineCColor": ""
},
{
"channelId": 2063,
"channelId": 2003,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
"delPermitted": 0,
"delPermitted": 1,
"fontCColor": "#FFFFFF",
"fontColor": "#F9AB99",
"headlinesOn": 0,
... ... @@ -245,14 +229,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "两会",
"name": "锐评",
"num": 9,
"pageId": 21000,
"pageId": 20013,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2064,
"channelId": 2011,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -269,14 +254,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "二十大",
"name": "体育",
"num": 10,
"pageId": 21001,
"pageId": 20021,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2003,
"channelId": 2005,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -293,14 +279,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "锐评",
"num": 11,
"pageId": 20013,
"name": "文件",
"num": 12,
"pageId": 20015,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2011,
"channelId": 2016,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -317,14 +304,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "体育",
"num": 12,
"pageId": 20021,
"name": "乡村振兴",
"num": 13,
"pageId": 20026,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2005,
"channelId": 2007,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -341,14 +329,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "文件",
"name": "镜头",
"num": 14,
"pageId": 20015,
"pageId": 20017,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2065,
"channelId": 2009,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -365,14 +354,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "三农",
"num": 15,
"pageId": 21002,
"name": "社会",
"num": 16,
"pageId": 20019,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2016,
"channelId": 2010,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -389,14 +379,15 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "乡村振兴",
"num": 16,
"pageId": 20026,
"name": "财经",
"num": 17,
"pageId": 20020,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2010,
"channelId": 2012,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -411,16 +402,17 @@
"iconUrlSize": "",
"localChannel": "0",
"moreChannel": "0",
"movePermitted": 1,
"movePermitted": 0,
"myChannel": "0",
"name": "财经",
"name": "文化",
"num": 18,
"pageId": 20020,
"pageId": 20022,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2013,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -445,6 +437,7 @@
},
{
"channelId": 2017,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -469,6 +462,7 @@
},
{
"channelId": 2014,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -493,6 +487,7 @@
},
{
"channelId": 2018,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -517,6 +512,7 @@
},
{
"channelId": 2019,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -541,6 +537,7 @@
},
{
"channelId": 2027,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -565,6 +562,7 @@
},
{
"channelId": 2029,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -589,6 +587,7 @@
},
{
"channelId": 2030,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -613,6 +612,7 @@
},
{
"channelId": 2031,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -637,6 +637,7 @@
},
{
"channelId": 2032,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -661,6 +662,7 @@
},
{
"channelId": 2033,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -685,6 +687,7 @@
},
{
"channelId": 2034,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -709,6 +712,7 @@
},
{
"channelId": 2035,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -733,6 +737,7 @@
},
{
"channelId": 2028,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -757,6 +762,7 @@
},
{
"channelId": 2036,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -781,6 +787,7 @@
},
{
"channelId": 2037,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -805,6 +812,7 @@
},
{
"channelId": 2038,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -829,6 +837,7 @@
},
{
"channelId": 2039,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -853,6 +862,7 @@
},
{
"channelId": 2040,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -877,6 +887,7 @@
},
{
"channelId": 2041,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -901,6 +912,7 @@
},
{
"channelId": 2042,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -925,6 +937,7 @@
},
{
"channelId": 2043,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -949,6 +962,7 @@
},
{
"channelId": 2044,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -973,6 +987,7 @@
},
{
"channelId": 2045,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -997,6 +1012,7 @@
},
{
"channelId": 2046,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1021,6 +1037,7 @@
},
{
"channelId": 2047,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1045,6 +1062,7 @@
},
{
"channelId": 2048,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1069,6 +1087,7 @@
},
{
"channelId": 2049,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1093,6 +1112,7 @@
},
{
"channelId": 2050,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1117,6 +1137,7 @@
},
{
"channelId": 2051,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1141,6 +1162,7 @@
},
{
"channelId": 2052,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1165,6 +1187,7 @@
},
{
"channelId": 2053,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1189,6 +1212,7 @@
},
{
"channelId": 2054,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1213,6 +1237,7 @@
},
{
"channelId": 2055,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1237,6 +1262,7 @@
},
{
"channelId": 2056,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1261,6 +1287,7 @@
},
{
"channelId": 2057,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 2,
"defaultPermitted": 0,
... ... @@ -1285,6 +1312,7 @@
},
{
"channelId": 2020,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -1309,6 +1337,7 @@
},
{
"channelId": 2021,
"channelStrategy": 1,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -1332,7 +1361,8 @@
"underlineCColor": ""
},
{
"channelId": 2022,
"channelId": 2069,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -1349,18 +1379,19 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "生活",
"num": 59,
"pageId": 20032,
"name": "冬奥",
"num": 66,
"pageId": 21006,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2092,
"channelId": 2070,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
"delPermitted": 0,
"delPermitted": 1,
"fontCColor": "#FFFFFF",
"fontColor": "#F9AB99",
"headlinesOn": 0,
... ... @@ -1373,18 +1404,19 @@
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "设计",
"num": 68,
"pageId": 21063,
"name": "旅游",
"num": 67,
"pageId": 21007,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2098,
"channelId": 2077,
"channelStrategy": 2,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
"delPermitted": 0,
"delPermitted": 1,
"fontCColor": "#FFFFFF",
"fontColor": "#F9AB99",
"headlinesOn": 0,
... ... @@ -1395,35 +1427,11 @@
"iconUrlSize": "",
"localChannel": "0",
"moreChannel": "0",
"movePermitted": 0,
"myChannel": "0",
"name": "设计组件",
"num": 72,
"pageId": 21299,
"pageType": "",
"underlineCColor": ""
},
{
"channelId": 2099,
"channelStyle": 2,
"channelType": 1,
"defaultPermitted": 0,
"delPermitted": 0,
"fontCColor": "",
"fontColor": "",
"headlinesOn": 0,
"homeChannel": "0",
"iconCUrl": "",
"iconCUrlSize": "",
"iconUrl": "",
"iconUrlSize": "",
"localChannel": "0",
"moreChannel": "0",
"movePermitted": 1,
"myChannel": "0",
"name": "设计号",
"num": 73,
"pageId": 21736,
"name": "设计",
"num": 69,
"pageId": 21528,
"pageType": "",
"underlineCColor": ""
}
... ... @@ -1432,39 +1440,40 @@
"type": "1"
},
{
"backgroundUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231214/image/display/2e1d5f235d1a44cfb9fc120e8596c56b.png",
"channelChooseActionUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231227/vod/display/3835f09a973443cb824af179e30e87ed.pag",
"channelChooseCColor": "#666666",
"channelChooseColor": "#222222",
"backgroundUrl": "",
"channelChooseActionUrl": "",
"channelChooseCColor": "",
"channelChooseColor": "",
"channelMoreColor": "",
"extraData": "{\"haveSearch\":\"0\",\"haveTopNav\":\"1\",\"leftIconurl\":\"\",\"rightIconUrl\":\"\"}",
"homePageColor": "#FFFFFF",
"icon": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231220/image/display/460f61a48c6a4993af442d54aedb682b.png",
"iconC": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231220/image/display/9aa759f72ccb4848b3ded2dee9502c25.gif",
"homePageColor": "",
"icon": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/e54cb55897604f099940d0a8526680c0.png",
"iconC": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/29e827defea748e295fa4397022b6cc9.png",
"id": 202,
"immersiveIconCUrl": "",
"immersiveIconUrl": "",
"immersiveNameCColor": "#FFFFFF",
"immersiveNameColor": "#FFFFFF",
"immersiveNameCColor": "",
"immersiveNameColor": "",
"logoUrl": "",
"morningAndEveningUrl": "",
"name": "人民号",
"nameCColor": "#ED2800",
"nameCColor": "#CB0000",
"nameColor": "#999999",
"nightIconCUrl": "",
"nightIconUrl": "",
"nightNameCColor": "",
"nightNameColor": "",
"noticeColor": "#FFFFFF",
"noticeColor": "",
"pageId": null,
"pageType": null,
"searchBothColor": "#222222",
"searchBothColor": "",
"searchUrl": "",
"sortValue": 2,
"statusBarColor": 1,
"statusBarColor": null,
"topNavChannelList": [
{
"channelId": 2058,
"channelStrategy": 1,
"channelStyle": 3,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -1489,6 +1498,7 @@
},
{
"channelId": 2059,
"channelStrategy": 2,
"channelStyle": 3,
"channelType": 3,
"defaultPermitted": 0,
... ... @@ -1513,6 +1523,7 @@
},
{
"channelId": 2073,
"channelStrategy": 2,
"channelStyle": 3,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -1540,39 +1551,40 @@
"type": "1"
},
{
"backgroundUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231214/image/display/2e1d5f235d1a44cfb9fc120e8596c56b.png",
"channelChooseActionUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231221/vod/display/65c6eb2ca91849c582d057adc9e76d46.pag",
"channelChooseCColor": "#666666",
"channelChooseColor": "#222222",
"backgroundUrl": "",
"channelChooseActionUrl": "",
"channelChooseCColor": "",
"channelChooseColor": "",
"channelMoreColor": "",
"extraData": "{\"haveSearch\":\"1\",\"haveTopNav\":\"1\",\"leftIconurl\":\"\",\"rightIconUrl\":\"\"}",
"homePageColor": "#FFFFFF",
"icon": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231221/image/display/bf77561966654001a538857ebef8a15c.png",
"iconC": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231224/image/display/1a42d5b8183a4eb1a044ddd64223c687.png",
"homePageColor": "",
"icon": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/551a687fccdc44ce916a391cc10eabdd.png",
"iconC": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/8ebb3bfe44534b059d5af53aafba8919.png",
"id": 203,
"immersiveIconCUrl": "",
"immersiveIconUrl": "",
"immersiveNameCColor": "#FFFFFF",
"immersiveNameColor": "#FFFFFF",
"immersiveNameCColor": "",
"immersiveNameColor": "",
"logoUrl": "",
"morningAndEveningUrl": "",
"name": "视频",
"nameCColor": "#ED2800",
"nameCColor": "#CB0000",
"nameColor": "#999999",
"nightIconCUrl": "",
"nightIconUrl": "",
"nightNameCColor": "",
"nightNameColor": "",
"noticeColor": "#FFFFFF",
"noticeColor": "",
"pageId": null,
"pageType": null,
"searchBothColor": "#222222",
"searchBothColor": "",
"searchUrl": "",
"sortValue": 3,
"statusBarColor": 1,
"statusBarColor": null,
"topNavChannelList": [
{
"channelId": 2060,
"channelStrategy": 1,
"channelStyle": 1,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -1597,6 +1609,7 @@
},
{
"channelId": 2061,
"channelStrategy": 2,
"channelStyle": 3,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -1624,39 +1637,40 @@
"type": "1"
},
{
"backgroundUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231214/image/display/2e1d5f235d1a44cfb9fc120e8596c56b.png",
"channelChooseActionUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231221/vod/display/65c6eb2ca91849c582d057adc9e76d46.pag",
"channelChooseCColor": "#666666",
"channelChooseColor": "#222222",
"backgroundUrl": "",
"channelChooseActionUrl": "",
"channelChooseCColor": "",
"channelChooseColor": "",
"channelMoreColor": "",
"extraData": "{\"haveSearch\":\"1\",\"haveTopNav\":\"1\",\"leftIconurl\":\"\",\"rightIconUrl\":\"\"}",
"homePageColor": "#FFFFFF",
"icon": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231220/image/display/5a6cf95f7b9e489390ec73faf458b58a.png",
"iconC": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231220/image/display/1b075ed30a6b43d2ae319e5d892c66e4.gif",
"homePageColor": "",
"icon": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/a35a51ac415343bb8122b48f84b5ca70.png",
"iconC": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/972642ec160b4fc2a5dad2de3488d903.png",
"id": 204,
"immersiveIconCUrl": "",
"immersiveIconUrl": "",
"immersiveNameCColor": "#FFFFFF",
"immersiveNameColor": "#FFFFFF",
"immersiveNameCColor": "",
"immersiveNameColor": "",
"logoUrl": "",
"morningAndEveningUrl": "",
"name": "服务",
"nameCColor": "#ED2800",
"nameCColor": "#CB0000",
"nameColor": "#999999",
"nightIconCUrl": "",
"nightIconUrl": "",
"nightNameCColor": "",
"nightNameColor": "",
"noticeColor": "#FFFFFF",
"noticeColor": "",
"pageId": null,
"pageType": null,
"searchBothColor": "#222222",
"searchBothColor": "",
"searchUrl": "",
"sortValue": 4,
"statusBarColor": 1,
"statusBarColor": null,
"topNavChannelList": [
{
"channelId": 2062,
"channelStrategy": 2,
"channelStyle": 3,
"channelType": 1,
"defaultPermitted": 0,
... ... @@ -1684,36 +1698,36 @@
"type": "1"
},
{
"backgroundUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231214/image/display/3e1f4fe85b0445b6a0be24f3759d0ff6.png",
"backgroundUrl": "",
"channelChooseActionUrl": "",
"channelChooseCColor": "#FFFFFF",
"channelChooseColor": "#FFFFFF",
"channelChooseCColor": "",
"channelChooseColor": "",
"channelMoreColor": "",
"extraData": "{\"haveSearch\":\"0\",\"haveTopNav\":\"0\"}",
"homePageColor": "#222222",
"icon": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231220/image/display/f55f0ac25b764809bc8285c284adb147.png",
"iconC": "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231220/image/display/3b5cff54d2a546f5b523a8aa8c33352e.gif",
"homePageColor": "",
"icon": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/3fa1832f3fbf49e6ad6765e64d27e60e.png",
"iconC": "https://cdnjdphoto.aikan.pdnews.cn/sjbj-20231015/image/display/39a357a0f0954b86b993a18988d29f96.png",
"id": 205,
"immersiveIconCUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/inen-20230403/image/display/9f22b579db15497797e8204b1ec12d14.png",
"immersiveIconUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/inen-20230403/image/display/5be23055a4dc4d869be2139e9deb7a55.png",
"immersiveIconCUrl": "https://cdnjdphoto.aikan.pdnews.cn/inen-20230403/image/display/9f22b579db15497797e8204b1ec12d14.png",
"immersiveIconUrl": "https://cdnjdphoto.aikan.pdnews.cn/inen-20230403/image/display/5be23055a4dc4d869be2139e9deb7a55.png",
"immersiveNameCColor": "#FFFFFF",
"immersiveNameColor": "#FFFFFF",
"immersiveNameColor": "#6A6B75",
"logoUrl": "",
"morningAndEveningUrl": "",
"name": "我的",
"nameCColor": "#ED2800",
"nameCColor": "#CB0000",
"nameColor": "#999999",
"nightIconCUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/inen-20230403/image/display/9d584ddcfdf74e3ea8e445d102127b97.png",
"nightIconUrl": "https://uatjdcdnphoto.aikan.pdnews.cn/inen-20230403/image/display/1f79063b6ecb493c95703e45529d3a5f.png",
"nightIconCUrl": "https://cdnjdphoto.aikan.pdnews.cn/inen-20230403/image/display/9d584ddcfdf74e3ea8e445d102127b97.png",
"nightIconUrl": "https://cdnjdphoto.aikan.pdnews.cn/inen-20230403/image/display/1f79063b6ecb493c95703e45529d3a5f.png",
"nightNameCColor": "#DA1C1C",
"nightNameColor": "#6A6B75",
"noticeColor": "#ED2800",
"noticeColor": "",
"pageId": null,
"pageType": null,
"searchBothColor": "#FFFFFF",
"searchBothColor": "",
"searchUrl": "",
"sortValue": 5,
"statusBarColor": 1,
"statusBarColor": null,
"topNavChannelList": [],
"topStyle": "",
"type": "2"
... ... @@ -1728,9 +1742,9 @@
},
"message": "Success",
"meta": {
"md5": "e2942dbcd76710d1bac0d98f9a0a9d0a"
"md5": "bab17ef603000513258f3ff7c4add868"
},
"requestId": "",
"success": true,
"timestamp": 1704765430031
"timestamp": 1706625315509
}
\ No newline at end of file
... ...
// enum
export { BottomNavi } from './src/main/ets/enum/BottomNavi';
export { CompStyle } from './src/main/ets/enum/CompStyle';
export { CompType } from './src/main/ets/enum/CompType';
export { NetDataStatusType } from './src/main/ets/enum/NetDataStatusType';
export { ViewType } from './src/main/ets/enum/ViewType';
export { DelayTimeEnum } from './src/main/ets/enum/DelayTimeEnum';
export { ScreenType } from './src/main/ets/enum/ScreenType';
// navigation
export { NavigationBody } from './src/main/ets/bean/navigation/NavigationBody';
export { NavigationBodyDTO } from './src/main/ets/bean/navigation/NavigationBodyDTO';
export { BottomNavBean } from './src/main/ets/bean/navigation/BottomNavBean';
export { BottomNavDTO } from './src/main/ets/bean/navigation/BottomNavDTO';
export { TopNavBean } from './src/main/ets/bean/navigation/TopNavBean';
export { TopNavDTO } from './src/main/ets/bean/navigation/TopNavDTO';
// entity
export { ItemDTO } from './src/main/ets/bean/ItemDTO';
... ... @@ -36,6 +21,8 @@ export { LabelBean } from './src/main/ets/bean/component/extra/LabelBean';
export { LabelDTO } from './src/main/ets/bean/component/extra/LabelDTO';
export { PageDTO } from './src/main/ets/bean/component/PageDTO';
export { GroupDTO } from './src/main/ets/bean/component/GroupDTO';
export { CompDTO } from './src/main/ets/bean/component/CompDTO';
... ...
... ... @@ -6,14 +6,9 @@ import { Pic } from './programme/Pic';
* 绑定到组件comp/view的数据Bean
*/
@Observed
// export abstract class ItemBean<DTO> implements Mapper<DTO> {
export abstract class ItemBean extends ItemDTO {
landscapeCover?: string; // 横向低分辨封面图片
portraitCover?: string; // 竖向低分辨封面图片
highLandscapeCover?: string; // 横向高分辨封面图片
highPortraitCover?: string; // 竖向高分辨封面图片
lowResolutionV34?: string; // 低清竖图(3:4比例), 取图逻辑 3:4低清竖图-->3:4高清竖图-->低分辨率竖图-->高分辨率竖图
highResolutionV34?: string; // 高清竖图(3:4比例), 取图逻辑 3:4高清竖图-->3:4低清竖图-->高分辨率竖图-->低分辨率竖图
export abstract class ItemBean {
action?: Action; // 事件行为
pics?: Pic
/**
* 是否被曝光
*/
... ... @@ -23,18 +18,20 @@ export abstract class ItemBean extends ItemDTO {
*/
position: string;
constructor(dto: ItemDTO) {
super(dto.action, dto.actionId, dto.pics, dto.h5pics)
this.landscapeCover = !dto.pics ? "" : !dto.pics.lowResolutionH ? dto.pics.highResolutionH : dto.pics.lowResolutionH;
this.portraitCover = !dto.pics ? "" : !dto.pics.lowResolutionV ? dto.pics.highResolutionV : dto.pics.lowResolutionV;
this.highLandscapeCover = !dto.pics ? "" : !dto.pics.highResolutionH ? dto.pics.lowResolutionH : dto.pics.highResolutionH;
this.highPortraitCover = !dto.pics ? "" : !dto.pics.highResolutionV ? dto.pics.lowResolutionV : dto.pics.highResolutionV;
this.lowResolutionV34 = !dto.pics ? "" : (!dto.pics.lowResolutionV34 ? dto.pics.lowResolutionV34 : (!dto.pics.highResolutionV34 ? dto.pics.highResolutionV34 : this.portraitCover));
this.highResolutionV34 = !dto.pics ? "" : (!dto.pics.highResolutionV34 ? dto.pics.highResolutionV34 : (!dto.pics.lowResolutionV34 ? dto.pics.lowResolutionV34 : this.highPortraitCover));
constructor(dto?: ItemDTO) {
if (dto) {
this.action = dto.action
this.pics = dto.pics
}
this.exposed = false
this.position = "0"
}
public setAction(action: Action): void {
this.action = action
}
public getAction(): Action {
return this.action ?? {} as Action
}
}
... ...
... ... @@ -5,16 +5,7 @@ import { Pic } from './programme/Pic';
* 组件comp/view对应的服务端数据
* DTO 数据传输实体类接口,所有数据传输层数据结构体需实现该接口
*/
export abstract class ItemDTO {
export interface ItemDTO {
action?: Action; // 事件对象
actionId?: string; // 点击事件id
pics?: Pic // 图片
h5pics?: Pic; // h5图片
constructor(action?: Action, actionId?: string, pics?: Pic, h5pics?: Pic) {
this.action = action;
this.actionId = actionId;
this.pics = pics;
this.h5pics = h5pics;
}
}
... ...
... ... @@ -10,7 +10,7 @@ export interface ContentDTO {
heatValue: string;
innerUrl: string;
landscape: number;
// lengthTime?: any;
lengthTime?: object;
linkUrl: string;
openLikes: number;
openUrl: string;
... ... @@ -33,4 +33,11 @@ export interface ContentDTO {
title: string;
vImageUrl: string;
screenType: string;
source: string;
objectId: string;
objectType: string;
channelId: string;
relId: string;
relType: string;
}
\ No newline at end of file
... ...
import { GroupDTO } from './GroupDTO';
import { CompDTO } from './CompDTO';
/**
* Page数据DTO
*/
export interface PageDTO {
id: number; // 页面id
name: string; // 页面名称
description: string; // 描述
groups: GroupDTO[]; // page下的group列表
pageId: string; // 页面id
id: number; // 楼层id
name: string; // 名称
branchMark: boolean;
compList: CompDTO[]; // Components集合的布局信息
}
\ No newline at end of file
... ...
import { TopNavBean } from './TopNavBean';
import { TopNavDTO } from './TopNavDTO';
/**
* 底导(包含顶导列表)数据
*/
export interface BottomNavBean {
export interface BottomNavDTO {
backgroundUrl: string;
channelChooseActionUrl: string;
channelChooseCColor: string;
... ... @@ -34,7 +34,7 @@ export interface BottomNavBean {
searchUrl: string;
sortValue: number;
statusBarColor: number;
topNavChannelList: TopNavBean[];
topNavChannelList: TopNavDTO[];
topStyle: string;
type: string;
}
\ No newline at end of file
... ...
import { BottomNavBean } from './BottomNavBean';
import { BottomNavDTO } from './BottomNavDTO';
/**
* 导航Body数据
*/
export interface NavigationBody {
export interface NavigationBodyDTO {
backgroundColor: string;
bottomNavList: BottomNavBean[];
bottomNavList: BottomNavDTO[];
// greyBottomNav: GreyBottomNav;
immersiveBackgroundColor: string;
nightBackgroundColor: string;
... ...
/**
* 顶导
*/
export interface TopNavBean {
export interface TopNavDTO {
channelId: number;
channelStyle: number;
channelType: number;
... ...
... ... @@ -3,6 +3,5 @@ import { Params } from './Params';
// 事件对象
export interface Action {
type: string;
name?: string; // 行为的名称,目前值与type相同,暂不启用
params?: Params; // 参数集合
}
\ No newline at end of file
... ...
/**
* 延时枚举常量值
*/
export const enum DelayTimeEnum {
DURATION_50 = 50, // 50毫秒
DURATION_100 = 100, // 50毫秒
DURATION_1000 = 1000, // 1秒/1000ms
DURATION_2000 = 2000, // 2秒/2000ms
LAUNCHER_DELAY_TIME = 1500, // 1.5秒
INTERVAL_4000 = 4000, //4秒
}
... ... @@ -2,34 +2,34 @@ export { PageViewModel } from "./src/main/ets/viewmodel/PageViewModel"
export { CompUtils } from "./src/main/ets/utils/CompUtils"
export { EmptyComponent } from "./src/main/ets/components/EmptyComponent"
export { EmptyComponent } from "./src/main/ets/components/view/EmptyComponent"
export { ErrorComponent } from "./src/main/ets/components/ErrorComponent"
export { ErrorComponent } from "./src/main/ets/components/view/ErrorComponent"
export { LoadingComponent } from "./src/main/ets/components/LoadingComponent"
export { LoadingComponent } from "./src/main/ets/components/view/LoadingComponent"
export { PageComponent } from "./src/main/ets/components/PageComponent"
export { PageComponent } from "./src/main/ets/components/page/PageComponent"
export { BottomNavigationComponent } from "./src/main/ets/components/BottomNavigationComponent"
export { BottomNavigationComponent } from "./src/main/ets/components/page/BottomNavigationComponent"
export { TopNavigationComponent } from "./src/main/ets/components/TopNavigationComponent"
export { TopNavigationComponent } from "./src/main/ets/components/page/TopNavigationComponent"
export { LabelComponent } from "./src/main/ets/components/LabelComponent"
export { LabelComponent } from "./src/main/ets/components/view/LabelComponent"
export { BannerComponent } from "./src/main/ets/components/BannerComponent"
export { BannerComponent } from "./src/main/ets/components/view/BannerComponent"
export { SingleRow03Component } from "./src/main/ets/components/SingleRow03Component"
export { SingleRow03Component } from "./src/main/ets/components/page/SingleRow03Component"
export { SingleColumnComponent } from "./src/main/ets/components/SingleColumnComponent"
export { SingleColumnComponent } from "./src/main/ets/components/page/SingleColumnComponent"
export { GridLayout01Component } from "./src/main/ets/components/GridLayout01Component"
export { GridLayout01Component } from "./src/main/ets/components/page/GridLayout01Component"
export { WaterFlowComponent } from "./src/main/ets/components/WaterFlowComponent"
export { WaterFlowComponent } from "./src/main/ets/components/page/WaterFlowComponent"
export { NewspaperViewModel} from "./src/main/ets/viewmodel/NewspaperViewModel"
export { NewspaperViewModel } from "./src/main/ets/viewmodel/NewspaperViewModel"
export {ENewspaperPageComponent} from "./src/main/ets/components/ENewspaperPageComponent"
export { ENewspaperPageComponent } from "./src/main/ets/components/ENewspaperPageComponent"
export {ENewspaperItemComponent} from "./src/main/ets/components/ENewspaperItemComponent"
export { ENewspaperItemComponent } from "./src/main/ets/components/ENewspaperItemComponent"
export {ENewspaperListDialog} from "./src/main/ets/dialog/ENewspaperListDialog"
export { ENewspaperListDialog } from "./src/main/ets/dialog/ENewspaperListDialog"
... ...
import { CompDTO, ContentDTO, DelayTimeEnum } from 'wdBean';
import { BreakpointConstants } from 'wdConstant';
import { BreakPointType, Logger } from 'wdKit';
import { CarouselLayout01CardView } from './CardView';
import { EmptyComponent } from './EmptyComponent';
const TAG = 'BannerComponent';
/**
* 轮播组件,即Banner/轮播大图/焦点图/自动滑动
* 样式:
* 'Carousel_Layout-01', // 通用轮播卡:视频、直播、活动、专题、榜单、外链
*/
@Component
export struct BannerComponent {
@StorageLink('currentBreakpoint') @Watch('watchCurrentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_XS;
@State compDTO: CompDTO = {} as CompDTO
watchCurrentBreakpoint() {
Logger.info(TAG, `watchCurrentBreakpoint, this.currentBreakpoint: ${this.currentBreakpoint}`);
}
aboutToAppear() {
Logger.info(TAG, `aboutToAppear, beanList:${this.compDTO?.operDataList?.length}, currentBreakpoint:${this.currentBreakpoint}`);
}
aboutToDisappear() {
Logger.info(TAG, 'aboutToDisappear');
}
onPageShow() {
Logger.info(TAG, 'onPageShow');
}
onPageHide() {
Logger.info(TAG, 'onPageHide');
}
onBackPress() {
Logger.info(TAG, 'onBackPress');
}
build() {
if (this.compDTO && this.compDTO?.operDataList?.length > 0) {
Swiper() {
ForEach(this.compDTO?.operDataList, (item: ContentDTO, index: number) => {
this.buildItemBanner01(item, index)
})
}
.margin({ left: $r('app.float.main_margin'), right: $r('app.float.main_margin') })
.padding({ bottom: 14 })
.displayCount(this.buildDisplayCount()) // 仅展示1个图片
.cachedCount(2)
.index(1) // The default index of Swiper.
.autoPlay(true)
.interval(DelayTimeEnum.INTERVAL_4000)
.indicator(Indicator.dot()
.right(5)
.itemWidth(4)
.itemHeight(4)
.selectedItemWidth(10)
.selectedItemHeight(6))
.loop(true)
.duration(DelayTimeEnum.DURATION_1000)
.vertical(false)
.curve(Curve.Linear)
.onChange((index: number) => {
Logger.info(TAG, `Swiper onChange index : ${index}`);
})
} else {
EmptyComponent({ emptyHeight: 200 })
}
}
public buildDisplayCount(): number {
return new BreakPointType({ xs: 1, sm: 1, md: 2, lg: 3 }).getValue(this.currentBreakpoint)
}
/**
* 组件项
*
* @param programmeBean item 组件项
*/
@Builder
buildItemBanner01(item: ContentDTO, index: number) {
CarouselLayout01CardView({
item: item,
index: index
})
}
}
\ No newline at end of file
import { CommonConstants, CompStyle } from 'wdConstant';
import { BannerComponent } from './view/BannerComponent';
import { LabelComponent } from './view/LabelComponent';
import { TitleAbbrComponent } from './view/TitleAbbrComponent';
import { TitleAllComponent } from './view/TitleAllComponent';
import { HorizontalStrokeCardThreeTwoRadioForOneComponent } from './view/HorizontalStrokeCardThreeTwoRadioForOneComponent';
import { HorizontalStrokeCardThreeTwoRadioForTwoComponent } from './view/HorizontalStrokeCardThreeTwoRadioForTwoComponent';
import { HorizontalStrokeCardThreeTwoRadioForMoreComponent } from './view/HorizontalStrokeCardThreeTwoRadioForMoreComponent';
import { CompDTO } from 'wdBean';
/**
* comp适配器.
*/
@Component
export struct CompParser {
compDTO: CompDTO = {} as CompDTO;
compIndex: number = 0;
build() {
this.componentBuilder(this.compDTO, this.compIndex);
}
@Builder
componentBuilder(compDTO: CompDTO, compIndex: number) {
if (compDTO.compStyle === CompStyle.Label_03) {
LabelComponent({ compDTO: compDTO })
} else if (compDTO.compStyle === CompStyle.Title_Abbr_01) {
TitleAbbrComponent({ compDTO: compDTO })
} else if (compDTO.compStyle === CompStyle.Title_All_01) {
TitleAllComponent({ compDTO: compDTO })
} else if (compDTO.compStyle === CompStyle.Carousel_Layout_01) {
BannerComponent({ compDTO: compDTO })
} else {
// todo:组件未实现 / Component Not Implemented
Text(compDTO.compStyle)
.width(CommonConstants.FULL_PARENT)
.padding(10)
// .backgroundColor(Color.Brown) // 展示本页未实现的compStyle
}
}
}
\ No newline at end of file
... ...
import { CompDTO } from '../repository/bean/CompDTO';
import { ContentDTO } from '../repository/bean/ContentDTO';
const FULL_PARENT: string = '100%';
const COLUMNS_TEMPLATE_ONE: string = '1fr';
const COLUMNS_TEMPLATE_TWO: string = '1fr 1fr';
const COLUMNS_TEMPLATE_THREE: string = '1fr 1fr 1fr';
const COLUMNS_TEMPLATE_FOUR: string = '1fr 1fr 1fr 1fr';
const COLUMNS_TEMPLATE_SIX: string = '1fr 1fr 1fr 1fr 1fr 1fr';
const TAG = 'DemoPreviewerComponent';
/**
* xxxx 布局及功能说明
*
* 【查看ArkUI预览效果】在线参考文档:
* https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/previewer-0000001054328973-V3#section146052489820
*/
@Entry
@Component
export struct DemoPreviewerComponent {
@State compDTO: CompDTO = {
compStyle: 'compStyle3',
operDataList: [
{
title: 'title0',
description: "description0",
coverUrl: 'https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231208/image/display/d4496925a1264a749975ae9b01a4ef46.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg'
} as ContentDTO,
{
title: 'title1 title1 title1 title1 title1 title1 title1 title1 title1',
description: "description1",
coverUrl: "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20240104/image/display/c4a9b526e0994d1bbd3ac8450f5cfc6c.jpg?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
} as ContentDTO,
{
title: 'title2',
description: "description2",
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",
} as ContentDTO,
{
title: 'title3',
description: "description3",
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'
} as ContentDTO,
{
title: 'title4',
description: "description4",
coverUrl: "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231218/image/display/62bdbbb35dbd45689e00790c81f04c4b.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
} as ContentDTO,
{
title: 'title5',
description: "description5",
coverUrl: "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231218/image/display/f79bbaa5a33b4bd88176071c4f797ff6.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
} as ContentDTO,
{
title: 'title6',
description: "description6",
coverUrl: "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231218/image/display/2c1d917009584ce2bb4a35cbb3a860a0.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
} as ContentDTO,
{
title: 'title7',
description: "description7",
coverUrl: "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231222/image/display/117dc516ca5c42d5843c0d32050c9fc6.jpeg?x-oss-process=image/resize,w_240/quality,q_90/format,jpg",
} as ContentDTO,
{
title: 'title8',
description: "description8",
coverUrl: "https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231228/image/display/90a2db4077d44a1f887f068fc659d977.jpeg?x-oss-process=image/resize,w_550/quality,q_90/format,jpg",
} as ContentDTO
]
} as CompDTO
aboutToAppear() {
// this.compDTO = {
// compStyle: 'compStyle3',
// operDataList: [
// {
// title: 'title0',
// description: "description0",
// coverUrl: 'https://uatjdcdnphoto.aikan.pdnews.cn/sjbj-20231208/image/display/d4496925a1264a749975ae9b01a4ef46.png?x-oss-process=image/resize,w_550/quality,q_90/format,jpg'
// } as ContentDTO
// ]
// } as CompDTO
this.compDTO.operDataList[0].title = 'title_first_0'
}
build() {
Grid() {
ForEach(this.compDTO.operDataList, (item: ContentDTO, index: number) => {
GridItem() {
this.gridItemView(item, index)
}
}, (item: ContentDTO, index: number) => JSON.stringify(item))
}
.height(FULL_PARENT)
.margin({ top: 10, bottom: 10, left: $r('app.float.main_margin'), right: $r('app.float.main_margin') })
.columnsTemplate(COLUMNS_TEMPLATE_TWO)
.columnsGap(4)
.rowsGap(2)
}
/**
* 布局描述
*
* @param ContentDTO item 组件项
* @param index
*/
@Builder
gridItemView(item: ContentDTO, index: number) {
Column() {
Image(item.coverUrl)
.width(FULL_PARENT)// .aspectRatio(3 / 4) // 宽/高比:纵向
// .aspectRatio(1 / 1) // 宽/高比:正方形
.aspectRatio(16 / 9)// 宽/高比:横向
.margin({ top: 8 })
.borderRadius(10)
Text(item.title)
.width(FULL_PARENT)
.margin({ top: 4, left: 2, right: 2, bottom: 4 })
.backgroundColor(Color.White)
.fontWeight(FontWeight.Bold)// .textAlign(TextAlign.Center)
.fontSize($r('app.float.font_size_12'))
.fontColor('#808080')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width(FULL_PARENT)
.backgroundColor(Color.Yellow)
.justifyContent(FlexAlign.Center)
.onClick(() => {
console.info(TAG, `gridItemView onClick, index: ${index}`);
// MGRouterRule.jumpWithAction(item.action)
})
}
}
\ No newline at end of file
... ...
import { CommonConstants } from 'wdConstant';
import { CompDTO } from '../repository/bean/CompDTO';
import { CompUtils } from '../utils/CompUtils';
@Component
export struct HeadPictureCardComponent {
@State compDTO: CompDTO = {} as CompDTO
build() {
Stack() {
Image(this.compDTO.backgroundImgUrl)
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
Row()
.width(CommonConstants.FULL_WIDTH)
.height(59)
.linearGradient({
colors:[
['rgba(0, 0, 0, 0.0)', 0.0], ['rgba(0, 0, 0, 0.3)', 1.0]
]
})
Row() {
Text(CompUtils.getLabelTitle(this.compDTO.extraData))
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
.fontColor(Color.White)
.fontSize($r('app.float.normal_text_size'))
.fontWeight(FontWeight.Bold)
}
.height(25)
.margin({left: 12, bottom: 10, right: 12})
}
.alignContent(Alignment.Bottom)
}
}
... ...
import { CompDTO, CompStyle, GroupDTO, ViewType } from 'wdBean';
import { CommonConstants } from 'wdConstant';
import { LazyDataSource, Logger } from 'wdKit';
import { PageViewModel } from '../viewmodel/PageViewModel';
import { BannerComponent } from './BannerComponent';
import { EmptyComponent } from './EmptyComponent';
import { ErrorComponent } from './ErrorComponent';
import { GridLayout01Component } from './GridLayout01Component';
import { LabelComponent } from './LabelComponent';
import { LoadingComponent } from './LoadingComponent';
import { SingleColumnComponent } from './SingleColumnComponent';
import { SingleRow03Component } from './SingleRow03Component';
import { WaterFlowComponent } from './WaterFlowComponent';
const TAG = 'PageComponent';
@Component
export struct PageComponent {
@Prop viewType: number = ViewType.LOADED;
// Group数据及子组件数据
@State groupList: LazyDataSource<GroupDTO> = new LazyDataSource();
@State currentTopNavSelectedIndex: number = 0;
build() {
if (this.viewType == ViewType.LOADING) {
LoadingComponent()
} else if (this.viewType == ViewType.ERROR) {
ErrorComponent()
} else if (this.viewType == ViewType.EMPTY) {
EmptyComponent()
} else {
List() {
LazyForEach(this.groupList, (groupDTO: GroupDTO, groupIndex: number) => {
ListItem() {
Column() {
ForEach(groupDTO.compList, (compDTO: CompDTO, compIndex: number) => {
this.componentBuilder(compDTO, groupIndex, compIndex)
})
}
}
})
}
.cachedCount(5)
.height(CommonConstants.FULL_PARENT)
}
}
@Builder
componentBuilder(compDTO: CompDTO, groupIndex: number, compIndex: number) {
if (compDTO.compStyle === CompStyle.Label_03) {
LabelComponent({ compDTO: compDTO })
} else if (compDTO.compStyle === CompStyle.Carousel_Layout_01) {
BannerComponent({ compDTO: compDTO })
} else if (compDTO.compStyle === CompStyle.Single_Row_03) {
SingleRow03Component({ dataList: compDTO.operDataList })
} else if (compDTO.compStyle === CompStyle.Single_Column_01 || compDTO.compStyle === CompStyle.Single_Column_02) {
SingleColumnComponent({ compDTO: compDTO })
} else if (compDTO.compStyle === CompStyle.Grid_Layout_01) {
GridLayout01Component({ dataList: compDTO.operDataList })
} else if (compDTO.compStyle === CompStyle.Masonry_Layout_01) {
WaterFlowComponent({ compDTO: compDTO })
} else {
// todo:组件未实现 / Component Not Implemented
Text(compDTO.compStyle)
.width(CommonConstants.FULL_PARENT)
.padding(10)
// .backgroundColor(Color.Brown) // 展示本页未实现的compStyle
}
}
aboutToAppear() {
Logger.info(TAG, `aboutToAppear, this.pageId: ${this.viewType} this.currentTopNavSelectedIndex: ${this.currentTopNavSelectedIndex}`);
if (this.currentTopNavSelectedIndex === 1) { // 顶导tab的第0个item是【热点】,第1个item是【推荐】
this.groupList.replaceAll()
let groupDto = PageViewModel.getGroup2DTO(getContext(this))
if (groupDto) {
this.groupList.push(groupDto)
}
} else {
let groupDto = PageViewModel.getGroupDTO(getContext(this))
if (groupDto) {
this.groupList.push(groupDto)
}
}
}
}
import { BottomNavBean, BottomNavi } from 'wdBean';
import { CommonConstants } from 'wdConstant';
import { LazyDataSource, Logger } from 'wdKit';
import { BottomNavi, CommonConstants } from 'wdConstant';
import { BottomNavDTO } from 'wdBean';
import { Logger } from 'wdKit';
import { TopNavigationComponent } from './TopNavigationComponent';
import { PageComponent } from './PageComponent';
import { MinePageComponent } from './MinePageComponent';
import { CompUtils } from '../../utils/CompUtils';
import PageViewModel from '../../viewmodel/PageViewModel';
const TAG = 'BottomNavigationComponent';
... ... @@ -12,7 +14,7 @@ const TAG = 'BottomNavigationComponent';
@Component
export struct BottomNavigationComponent {
// 底导/顶导全部数据
@Prop @Watch('onBottomNavigationDataUpdated') bottomNavList: BottomNavBean[] = []
@State @Watch('onBottomNavigationDataUpdated') bottomNavList: BottomNavDTO[] = []
// 底导当前选中/焦点下标
@Provide currentNavIndex: number = BottomNavi.NEWS;
// 底导TabsController
... ... @@ -27,8 +29,13 @@ export struct BottomNavigationComponent {
*/
readonly SIXTY_OPACITY: number = 0.6;
aboutToAppear() {
async aboutToAppear() {
Logger.info(TAG, `aboutToAppear currentNavIndex: ${this.currentNavIndex}`);
let bottomNav = await PageViewModel.getBottomNavData(getContext(this))
if (bottomNav && bottomNav.bottomNavList != null) {
Logger.info(TAG, `aboutToAppear, bottomNav.length: ${bottomNav.bottomNavList.length}`);
this.bottomNavList = bottomNav.bottomNavList
}
}
aboutToDisappear() {
... ... @@ -37,11 +44,12 @@ export struct BottomNavigationComponent {
build() {
Tabs({ barPosition: BarPosition.End, index: this.currentNavIndex, controller: this.navController }) {
ForEach(this.bottomNavList, (navItem: BottomNavBean, index: number) => {
ForEach(this.bottomNavList, (navItem: BottomNavDTO, index: number) => {
TabContent() {
Column() {
if (navItem.topNavChannelList && navItem.topNavChannelList.length == 0 && navItem.name == '我的') {
PageComponent({ groupList: new LazyDataSource() }) // todo:我的页面组件数据列表
if (CompUtils.isMine(navItem)) {
// 我的页面组件数据列表
MinePageComponent()
} else {
TopNavigationComponent({ topNavList: navItem.topNavChannelList })
}
... ... @@ -60,7 +68,7 @@ export struct BottomNavigationComponent {
}
@Builder
tabBarBuilder(navItem: BottomNavBean, index: number) {
tabBarBuilder(navItem: BottomNavDTO, index: number) {
Stack({ alignContent: Alignment.Bottom }) {
Image(this.currentNavIndex === index ? navItem.iconC : navItem.icon)
.height(CommonConstants.FULL_PARENT)
... ...
import { Action, ContentDTO, Params, ScreenType } from 'wdBean';
import { CommonConstants, ConfigConstants } from 'wdConstant';
import { Action, ContentDTO, Params } from 'wdBean';
import { CommonConstants, ConfigConstants, ScreenType } from 'wdConstant';
import { Logger } from 'wdKit';
import { CompUtils } from '../utils/CompUtils';
import { CompUtils } from '../../utils/CompUtils';
import { WDRouterRule } from 'wdRouter';
const TAG: string = 'CardView';
... ...
import { PageComponent } from './PageComponent';
const TAG = 'ColumnPageComponent';
/**
* 二级栏目页面,展排数据
*/
@Component
export struct ColumnPageComponent {
@State currentTopNavSelectedIndex: number = 0;
pageId: string = "";
channelId: string = "";
build() {
PageComponent({
currentTopNavSelectedIndex: $currentTopNavSelectedIndex,
navIndex: this.currentTopNavSelectedIndex,
pageId: this.pageId,
channelId: this.channelId,
});
}
}
... ...
import { RefreshConstants } from '../../utils/RefreshConstants';
import { RefreshLayoutBean } from './RefreshLayoutBean';
/**
* Custom layout to show refresh or load.
*/
@Component
export default struct CustomLayout {
@ObjectLink refreshBean: RefreshLayoutBean;
build() {
Row() {
Image(this.refreshBean.imageSrc)
.width(RefreshConstants.RefreshLayout_IMAGE_WIDTH)
.height(RefreshConstants.RefreshLayout_IMAGE_HEIGHT)
Text(this.refreshBean.textValue)
.margin({
left: RefreshConstants.RefreshLayout_TEXT_MARGIN_LEFT,
bottom: RefreshConstants.RefreshLayout_TEXT_MARGIN_BOTTOM
})
.fontSize(RefreshConstants.RefreshLayout_TEXT_FONT_SIZE)
.textAlign(TextAlign.Center)
}
.clip(true)
.width(RefreshConstants.FULL_WIDTH)
.justifyContent(FlexAlign.Center)
.height(this.refreshBean.heightValue)
}
}
\ No newline at end of file
... ...
import CustomRefreshLoadLayout from './CustomRefreshLoadLayout';
import { RefreshLayoutBean } from './RefreshLayoutBean';
/**
* The load more layout component.
*/
@Component
export default struct LoadMoreLayout {
@ObjectLink refreshBean: RefreshLayoutBean;
build() {
Column() {
if (this.refreshBean.isVisible) {
CustomRefreshLoadLayout({
refreshBean: new RefreshLayoutBean(this.refreshBean.isVisible,
this.refreshBean.imageSrc, this.refreshBean.textValue, this.refreshBean.heightValue)
})
} else {
CustomRefreshLoadLayout({
refreshBean: new RefreshLayoutBean(this.refreshBean.isVisible,
this.refreshBean.imageSrc, this.refreshBean.textValue, 0)
})
}
}
}
}
\ No newline at end of file
... ...
const TAG = 'PageComponent';
/**
* 我的页面
*/
@Component
export struct MinePageComponent {
// TODO 待完善
build() {
Text('我的页面')
}
}
... ...
import { RefreshConstants } from '../../utils/RefreshConstants'
/**
* The No more data layout component.
*/
@Component
export default struct NoMoreLayout {
build() {
Row() {
Text($r('app.string.footer_text'))
.margin({ left: RefreshConstants.NoMoreLayoutConstant_NORMAL_PADDING })
.fontSize(RefreshConstants.NoMoreLayoutConstant_TITLE_FONT)
.textAlign(TextAlign.Center)
}
.width(RefreshConstants.FULL_WIDTH)
.justifyContent(FlexAlign.Center)
.height(RefreshConstants.CUSTOM_LAYOUT_HEIGHT)
}
}
\ No newline at end of file
... ...
import { CommonConstants, ViewType } from 'wdConstant';
import { Logger } from 'wdKit';
import PageViewModel from '../../viewmodel/PageViewModel';
import { EmptyComponent } from '../view/EmptyComponent';
import { ErrorComponent } from '../view/ErrorComponent';
import PageModel from '../../viewmodel/PageModel';
import { listTouchEvent } from '../../utils/PullDownRefresh';
import RefreshLayout from './RefreshLayout';
import { RefreshLayoutBean } from './RefreshLayoutBean';
import NoMoreLayout from './NoMoreLayout';
import LoadMoreLayout from './LoadMoreLayout';
import CustomRefreshLoadLayout from './CustomRefreshLoadLayout';
import { CompParser } from '../CompParser';
import { CompDTO } from 'wdBean';
const TAG = 'PageComponent';
@Component
export struct PageComponent {
@State private pageModel: PageModel = new PageModel();
navIndex: number = 0;
pageId: string = "";
channelId: string = "";
@Link @Watch('onChange') currentTopNavSelectedIndex: number
build() {
Column() {
if (this.pageModel.viewType == ViewType.LOADING) {
// LoadingComponent()
this.LoadingLayout()
} else if (this.pageModel.viewType == ViewType.ERROR) {
ErrorComponent()
} else if (this.pageModel.viewType == ViewType.EMPTY) {
EmptyComponent()
} else {
this.ListLayout()
}
}
.width(CommonConstants.FULL_PARENT)
.height(CommonConstants.FULL_PARENT)
.onTouch((event: TouchEvent | undefined) => {
if (event) {
if (this.pageModel.viewType === ViewType.LOADED) {
listTouchEvent(this.pageModel, event);
}
}
})
}
@Builder ListLayout() {
List() {
// 下拉刷新
ListItem() {
RefreshLayout({
refreshBean: new RefreshLayoutBean(this.pageModel.isVisiblePullDown, this.pageModel.pullDownRefreshImage,
this.pageModel.pullDownRefreshText, this.pageModel.pullDownRefreshHeight)
})
}
LazyForEach(this.pageModel.compList, (compDTO: CompDTO, compIndex: number) => {
ListItem() {
Column() {
CompParser({ compDTO: compDTO, compIndex: compIndex });
}
}
})
// 加载更多
ListItem() {
if (this.pageModel.hasMore) {
LoadMoreLayout({
refreshBean: new RefreshLayoutBean(this.pageModel.isVisiblePullUpLoad, this.pageModel.pullUpLoadImage,
this.pageModel.pullUpLoadText, this.pageModel.pullUpLoadHeight)
})
} else {
NoMoreLayout()
}
}
}
.cachedCount(5)
.height(CommonConstants.FULL_PARENT)
.onScrollIndex((start: number, end: number) => {
// Listen to the first index of the current list.
this.pageModel.startIndex = start;
// 包含了 头尾item,判断时需要考虑+2
this.pageModel.endIndex = end;
})
}
@Builder LoadingLayout() {
CustomRefreshLoadLayout({ refreshBean: new RefreshLayoutBean(true,
$r('app.media.ic_pull_up_load'), $r('app.string.pull_up_load_text'), this.pageModel.pullDownRefreshHeight) })
}
async aboutToAppear() {
// 选中tab,才请求数据。拦截大量接口请求
if (this.navIndex === this.currentTopNavSelectedIndex) {
this.getData();
}
}
onChange() {
if (this.navIndex === this.currentTopNavSelectedIndex) {
this.getData();
}
}
async getData() {
Logger.info(TAG, `getData id: ${this.pageId} , ${this.channelId} , navIndex: ${this.currentTopNavSelectedIndex}`);
this.pageModel.pageId = this.pageId;
this.pageModel.groupId = this.pageId;
this.pageModel.channelId = this.channelId;
this.pageModel.currentPage = 1;
let pageDto = await PageViewModel.getPageData(this.pageModel.pageId, this.pageModel.pageId, this.pageModel.channelId
, this.pageModel.currentPage, this.pageModel.pageSize, getContext(this))
if (pageDto && pageDto.compList && pageDto.compList.length > 0) {
this.pageModel.viewType = ViewType.LOADED;
this.pageModel.compList.push(...pageDto.compList)
if (pageDto.compList.length === this.pageModel.pageSize) {
this.pageModel.currentPage++;
this.pageModel.hasMore = true;
} else {
this.pageModel.hasMore = false;
}
} else {
Logger.debug(TAG, 'aboutToAppear, data response page ' + this.pageId + ', comp list is empty.');
this.pageModel.viewType = ViewType.EMPTY;
}
}
}
... ...
import CustomRefreshLoadLayout from './CustomRefreshLoadLayout';
import { RefreshLayoutBean } from './RefreshLayoutBean';
/**
* The refresh layout component.
*/
@Component
export default struct RefreshLayout {
@ObjectLink refreshBean: RefreshLayoutBean;
build() {
Column() {
if (this.refreshBean.isVisible) {
CustomRefreshLoadLayout({ refreshBean: new RefreshLayoutBean
(this.refreshBean.isVisible, this.refreshBean.imageSrc, this.refreshBean.textValue,
this.refreshBean.heightValue) })
}
}
}
}
\ No newline at end of file
... ...
/**
* Custom refresh load layout data.
*/
@Observed
export class RefreshLayoutBean {
/**
* Custom refresh load layout isVisible.
*/
isVisible: boolean;
/**
* Custom refresh load layout imageSrc.
*/
imageSrc: Resource;
/**
* Custom refresh load layout textValue.
*/
textValue: Resource;
/**
* Custom refresh load layout heightValue.
*/
heightValue: number;
constructor(isVisible: boolean, imageSrc: Resource, textValue: Resource, heightValue: number) {
this.isVisible = isVisible;
this.imageSrc = imageSrc;
this.textValue = textValue;
this.heightValue = heightValue;
}
}
\ No newline at end of file
... ...
import { CompDTO, CompStyle, ContentDTO } from 'wdBean';
import { BreakpointConstants } from 'wdConstant';
import { CompDTO, ContentDTO } from 'wdBean';
import { BreakpointConstants, CompStyle } from 'wdConstant';
import { BreakPointType, Logger } from 'wdKit';
import { EmptyComponent } from '../view/EmptyComponent';
import { SingleColumn01CardView, SingleColumn02CardView } from './CardView';
import { EmptyComponent } from './EmptyComponent';
const TAG = 'SingleColumn01Component';
... ...
import { Action, GroupDTO, Params, TopNavBean } from 'wdBean';
import { CompDTO, TopNavDTO } from 'wdBean';
import { LazyDataSource, Logger } from 'wdKit';
import { WDRouterRule } from 'wdRouter';
import { PageComponent } from './PageComponent';
const TAG = 'TopNavigationComponent';
... ... @@ -13,31 +12,23 @@ export struct TopNavigationComponent {
// 顶导当前选中/焦点下标
@State currentTopNavSelectedIndex: number = 0;
// 顶导数据
@State @Watch('onTopNavigationDataUpdated') topNavList: TopNavBean[] = []
@State groupList: LazyDataSource<GroupDTO> = new LazyDataSource();
@State @Watch('onTopNavigationDataUpdated') topNavList: TopNavDTO[] = []
@State compList: LazyDataSource<CompDTO> = new LazyDataSource();
readonly MAX_LINE: number = 1;
build() {
Column(){
Image($r('app.media.icon_ren_min_ri_bao'))
.width(72)
.height(29)
.onClick((event: ClickEvent) => {
let taskAction: Action = {
type: 'JUMP_INNER_NEW_PAGE',
params: {
pageID: 'E_NEWSPAPER'
} as Params,
};
WDRouterRule.jumpWithAction(taskAction)
})
Tabs() {
ForEach(this.topNavList, (navItem: TopNavBean, index: number) => {
ForEach(this.topNavList, (navItem: TopNavDTO, index: number) => {
TabContent() {
PageComponent({ groupList: this.groupList, currentTopNavSelectedIndex:index})
PageComponent({
currentTopNavSelectedIndex: $currentTopNavSelectedIndex,
navIndex: index,
pageId: navItem.pageId + '',
channelId: navItem.channelId + ''
})
}
.tabBar(this.tabBarBuilder(navItem, index))
}, (navItem: TopNavBean) => JSON.stringify(navItem));
}, (navItem: TopNavDTO) => JSON.stringify(navItem));
}
.barHeight($r('app.float.top_tab_bar_height'))
.barMode(BarMode.Scrollable)
... ... @@ -48,10 +39,8 @@ export struct TopNavigationComponent {
})
}
}
@Builder
tabBarBuilder(item: TopNavBean, index: number) {
tabBarBuilder(item: TopNavDTO, index: number) {
Column() {
Text(item.name)
.fontSize(this.currentTopNavSelectedIndex === index ? $r('app.float.selected_text_size') : $r('app.float.normal_text_size'))
... ... @@ -62,7 +51,7 @@ export struct TopNavigationComponent {
Divider()
.width(16)
.strokeWidth(2) // 分割线粗细度。
.padding({top:2})
.padding({ top: 2 })
.color(Color.Red)
.opacity(this.currentTopNavSelectedIndex === index ? 1 : 0)
}
... ...
import { CompDTO, ContentDTO } from 'wdBean';
import { BreakPointType, Logger } from 'wdKit';
import { EmptyComponent } from '../view/EmptyComponent';
import { MasonryLayout01CardView } from './CardView';
import { EmptyComponent } from './EmptyComponent';
const TAG = 'WaterFlowComponent';
... ...
/**
* BannerComponent
* 轮播图卡/单图
* 邢照杰
*/
import { CommonConstants } from 'wdConstant';
import colorSpaceManager from '@ohos.graphics.colorSpaceManager';
import { CompUtils } from '../../utils/CompUtils';
import { Action, CompDTO, ContentDTO, Params } from 'wdBean';
import { Logger } from 'wdKit';
import { WDRouterRule } from 'wdRouter';
const TAG = 'BannerComponent';
let timerIds: number[] = [];
/**
* 轮播卡(暂时仅展示主标题,不展示子标题)
* comp类型
* 重磅推荐/精选/电视剧/电影/综艺/短剧/更多>/
*/
@Entry
@Component
export struct BannerComponent {
@State compDTO: CompDTO = {} as CompDTO
@State index: number = 0;
private bannerContent: ContentDTO = {} as ContentDTO;
private swiperController: SwiperController = new SwiperController();
aboutToAppear() {
// Data Initialization.
this.bannerContent = this.compDTO.operDataList[0];
// Turn on scheduled task.
if (this.compDTO.operDataList.length > 1) {
startPlay(this.swiperController);
}
}
aboutToDisappear() {
stopPlay();
}
build() {
// 整体父视图
Column() {
// 判断数组元素个数
if (this.compDTO.operDataList.length > 1) {
// 滚动banner
Swiper(this.swiperController) {
ForEach(this.compDTO.operDataList, (item: ContentDTO, index: number) => {
Stack() {
// 背景图
Image(item.coverUrl)
.objectFit(ImageFit.Fill)
.borderRadius(5)
// 底部标题和时间
Column() {
Text(item.description)
.fontSize(18)
.margin({ bottom: 4 })
.fontColor(Color.White)
.fontWeight(600)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.padding({ left: 10, right: 5 })
.width('100%')
.textAlign(TextAlign.Start)
if (item.lengthTime) {
Row() {
Image($r('app.media.videoTypeIcon'))
.height(20)
.width(20)
// .margin({right:3})
Text(item.lengthTime + '')
.padding({ left: 5, right: 5 })
.fontColor(Color.White)
}
.backgroundColor('#333333')
.height(20)
.margin({ right: 5, bottom: 3 })
.alignSelf(ItemAlign.End)
.borderRadius(2)
}
}
.height('50')
.width('100%')
}
.alignContent(Alignment.BottomStart)
.onClick((event: ClickEvent) => {
Logger.info(TAG, `BannerComponent onClick event index: ${this.index}`);
// let taskAction: Action = {
// type: 'JUMP_H5_BY_WEB_VIEW',
// params: {
// url: ConfigConstants.DETAIL_URL
// } as Params,
// };
// WDRouterRule.jumpWithAction(taskAction)
let taskAction: Action = {
type: 'JUMP_DETAIL_PAGE',
params: {
detailPageType: 7, // 沉浸式竖屏详情页
contentID: '863556812'
} as Params,
};
WDRouterRule.jumpWithAction(taskAction)
})
}, (item: ContentDTO, index: number) => JSON.stringify(item))
}
.width('100%')
.height('100%')
.index(this.index)
.indicatorStyle({
selectedColor: Color.White,
color: Color.Gray,
size: 18,
left: 15
})
.indicator(true)
.duration(500)
} else {
// 不滚动banner
Stack() {
// 背景图
Image(this.bannerContent.coverUrl.toString())
.objectFit(ImageFit.Fill)
.borderRadius(5)
// 底部标题和时间
Row() {
// 标题
Text(this.bannerContent.description.toString())
.fontSize(18)
.fontColor(Color.White)
.fontWeight(600)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.padding({ left: 10, right: 0, bottom: 5 })
.width('80%')
// 时间
if (this.bannerContent.lengthTime) {
Row() {
Image($r('app.media.videoTypeIcon'))
.height(20)
.width(20)
// .margin({right:3})
Text(this.bannerContent.lengthTime.toString())
.padding({ left: 5, right: 5 })
.fontColor(Color.White)
}
.backgroundColor('#333333')
.height(20)
.borderRadius(2)
.margin({ bottom: 6 })
}
}
.width('100%')
.height('100%')
.alignItems(VerticalAlign.Bottom)
}
.alignContent(Alignment.BottomStart)
.width('100%')
.height('100%')
}
}
.width('100%')
.aspectRatio(1.7)
.padding({ left: 10, right: 15, top: 10, bottom: 10 })
}
}
/**
* start scheduled task.
*
* @param swiperController Controller.
*/
export function startPlay(swiperController: SwiperController) {
let timerId = setInterval(() => {
swiperController.showNext();
}, 3000);
timerIds.push(timerId);
}
/**
* stop scheduled task.
*/
export function stopPlay() {
timerIds.forEach((item) => {
clearTimeout(item);
})
}
\ No newline at end of file
... ...
... ... @@ -46,7 +46,7 @@ export struct EmptyComponent {
Text(this.buildNoDataTip())
.fontSize($r('app.float.normal_text_size'))
.fontColor('#B2B2B2')
.fontColor('#000000')
.fontWeight(FontWeight.Normal)
.opacity(this.TEXT_OPACITY)
.margin({ top: this.EMPTY_TIP_TEXT_MARGIN_TOP })
... ...
import { CompDTO } from 'wdBean'
import { CommonConstants } from 'wdConstant'
@Component
export struct HorizontalStrokeCardThreeTwoRadioForMoreComponent {
@State compDTO: CompDTO = {} as CompDTO
private arr: number[] = [0, 1, 2]
build() {
Column() {
Row() {
Row() {
Image($r("app.media.redLine"))
.width(3)
.height(16)
.margin({ right: 4 })
Text("大标题")
.fontSize($r("app.float.font_size_17"))
.fontColor($r("app.color.color_222222"))
.fontWeight(600)
}
Row() {
Text("更多")
.fontSize($r("app.float.font_size_14"))
.fontColor($r("app.color.color_999999"))
.margin({ right: 1 })
Image($r("app.media.more"))
.width(14)
.height(14)
}
}.justifyContent(FlexAlign.SpaceBetween)
.padding({left:16,right:16})
.margin({top:8 ,bottom:8})
.width('100%')
// .backgroundColor($r("app.color.white"))
List({ space: 12 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Column() {
Image($r("app.media.setting"))
.aspectRatio(1.5)
.width(150)
.borderRadius(4)
.objectFit(ImageFit.Cover)
Text("大发大法师法师打发大水发生发大水发大水发大发大法师法师打发大水发生发大水发大水发大发大法师法师打发大水发生发大水发大水发")
.fontSize($r("app.float.font_size_14"))
.fontColor($r("app.color.color_212228"))
.fontWeight(400)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis }) // 超出的部分显示省略号。
.textAlign(TextAlign.Start)
.margin({ top: 8 })
.width(150)
}
}
.padding({left:(item == 0)? 16:0, right:(item == this.arr.length - 1) ? 16:0})
// .offset({x:16})
}, (item: number) => JSON.stringify(item))
}.listDirection(Axis.Horizontal)
.width('100%')
// .backgroundColor($r("app.color.color_FE4B05"))
// .padding({left:16,right:16})
// .margin({left:16,right:16})
}
.width("100%")
.padding({
top: 14,
left: 0,
right: 0,
bottom: 14
})
.backgroundColor($r("app.color.white"))
// .backgroundColor($r("app.color.color_FE4B05"))
.margin({ bottom: 8 })
}
}
... ...
import { CompDTO } from 'wdBean'
import { CommonConstants } from 'wdConstant'
@Component
export struct HorizontalStrokeCardThreeTwoRadioForOneComponent {
@State compDTO: CompDTO = {} as CompDTO
build() {
Column() {
Row() {
Row() {
Image($r("app.media.redLine"))
.width(3)
.height(16)
.margin({ right: 4 })
Text("大标题")
.fontSize($r("app.float.font_size_17"))
.fontColor($r("app.color.color_222222"))
.fontWeight(600)
}
Row() {
Text("更多")
.fontSize($r("app.float.font_size_14"))
.fontColor($r("app.color.color_999999"))
.margin({ right: 1 })
Image($r("app.media.more"))
.width(14)
.height(14)
}
}.justifyContent(FlexAlign.SpaceBetween)
.margin({ top: 8 ,bottom: 8})
.width('100%')
Image($r("app.media.setting"))
.aspectRatio(1.5)
.width('100%')
.borderRadius(4)
.objectFit(ImageFit.Cover)
Text("大发大法师法师打发大水发生发大水发大水发大发大法师法师打发大水发生发大水发大水发大发大法师法师打发大水发生发大水发大水发")
.fontSize($r("app.float.font_size_14"))
.fontColor($r("app.color.color_212228"))
.fontWeight(400)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis }) // 超出的部分显示省略号。
.textAlign(TextAlign.Start)
.margin({ top: 8 })
.width('100%')
}.width("100%")
.padding({
top: 14,
left: 16,
right: 16,
bottom: 14
})
.backgroundColor($r("app.color.white"))
.margin({ bottom: 8 })
}
}
\ No newline at end of file
... ...
import { CompDTO } from 'wdBean'
import { CommonConstants } from 'wdConstant'
@Component
export struct HorizontalStrokeCardThreeTwoRadioForTwoComponent {
@State compDTO: CompDTO = {} as CompDTO
private arr: number[] = [0, 1, 2]
build() {
Column() {
Row() {
Row() {
Image($r("app.media.redLine"))
.width(3)
.height(16)
.margin({ right: 4 })
Text("大标题")
.fontSize($r("app.float.font_size_17"))
.fontColor($r("app.color.color_222222"))
.fontWeight(600)
}
Row() {
Text("更多")
.fontSize($r("app.float.font_size_14"))
.fontColor($r("app.color.color_999999"))
.margin({ right: 1 })
Image($r("app.media.more"))
.width(14)
.height(14)
}
}.justifyContent(FlexAlign.SpaceBetween)
.padding({left:16,right:16})
.margin({top:8 ,bottom:8})
.width('100%')
// .backgroundColor($r("app.color.white"))
List({ space: 12 }) {
ForEach(this.arr, (item: number) => {
ListItem() {
Column() {
Image($r("app.media.setting"))
.aspectRatio(1.5)
.width(210)
.borderRadius(4)
.objectFit(ImageFit.Cover)
Text("大发大法师法师打发大水发生发大水发大水发大发大法师法师打发大水发生发大水发大水发大发大法师法师打发大水发生发大水发大水发")
.fontSize($r("app.float.font_size_14"))
.fontColor($r("app.color.color_212228"))
.fontWeight(400)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis }) // 超出的部分显示省略号。
.textAlign(TextAlign.Start)
.margin({ top: 8 })
.width(210)
}
}
.padding({left:(item == 0)? 16:0, right:(item == this.arr.length - 1) ? 16:0})
// .offset({x:16})
}, (item: number) => JSON.stringify(item))
}.listDirection(Axis.Horizontal)
.width('100%')
// .backgroundColor($r("app.color.color_FE4B05"))
// .padding({left:16,right:16})
// .margin({left:16,right:16})
}
.width("100%")
.padding({
top: 14,
left: 0,
right: 0,
bottom: 14
})
.backgroundColor($r("app.color.white"))
// .backgroundColor($r("app.color.color_FE4B05"))
.margin({ bottom: 8 })
}
}
... ...
import { CompDTO } from 'wdBean';
import { CommonConstants } from 'wdConstant';
import { CompUtils } from '../utils/CompUtils';
import { CompUtils } from '../../utils/CompUtils';
const TAG = 'LabelComponent';
... ...
// import { CommonConstants } from 'wdConstant/src/main/ets/constants/CommonConstants'
@Entry
@Component
export struct SmallVideoCardComponent {
build() {
Row() {
Column() {
Text('“畅享亚运”新模式活动打卡,看杭州打开“金角银边活动启动 跟着体育明星云打卡,看杭州打开“金角银边')
.fontWeight(400)
.fontSize($r('app.float.font_size_17'))
.maxLines(4)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontColor($r('app.color.color_222222'))
.lineHeight(25)
Row() {
Text('人民日报')
.labelTextStyle()
Image($r('app.media.point'))
.width(16)
.height(16)
Text('20分钟前')
.labelTextStyle()
.margin({
right: 6
})
Text('2000评')
.labelTextStyle()
}
}
.height(156)
.layoutWeight(1)
.justifyContent(FlexAlign.SpaceBetween)
.alignItems(HorizontalAlign.Start)
.margin({ right: 12 })
Stack({ alignContent: Alignment.BottomEnd }) {
Image('https://www.harmonyos.com/resource/image/partner/harmonyos-connect/pic_shengtai_connect_qudao_xianxia.jpg')
.width(117)
.aspectRatio(117 / 156)
.border({ radius: 4 })
Row() {
Image($r('app.media.iv_card_play_yellow_flag'))
.width(22)
.height(18)
Text('10:00')
.fontSize($r('app.float.font_size_13'))
.fontWeight(400)
.fontColor($r('app.color.color_fff'))
}
.height(18)
.padding({ right: 4 })
.margin({
right: 4,
bottom: 4
})
.backgroundColor($r('app.color.color_4d000000'))
}
}
// .width(CommonConstants.FULL_WIDTH)
.width('100%')
.height(184)
.padding({
top: 14,
bottom: 14,
left: 16,
right: 16
})
}
}
@Extend(Text) function labelTextStyle() {
.fontSize($r('app.float.font_size_12'))
.fontWeight(400)
.fontColor($r('app.color.color_B0B0B0'))
}
\ No newline at end of file
... ...
//缩略标题
import { CompDTO } from 'wdBean'
import { CommonConstants } from 'wdConstant'
@Component
export struct TitleAbbrComponent {
@State compDTO: CompDTO = {} as CompDTO
build() {
Column() {
Text(this.compDTO.operDataList[0].title)
.fontSize($r("app.float.font_size_16"))
.fontColor($r("app.color.color_222222"))
.maxLines(3)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.width(CommonConstants.FULL_WIDTH)
Row() {
Text("锐评")
.fontSize($r("app.float.font_size_12"))
.fontColor($r("app.color.color_ED2800"))
Text(this.compDTO.operDataList[0].source)
.fontSize($r("app.float.font_size_12"))
.fontColor($r("app.color.color_B0B0B0"))
.margin({ left: 6 })
Image($r("app.media.point"))
.width(16)
.height(16)
Text("46分钟前")
.fontSize($r("app.float.font_size_12"))
.fontColor($r("app.color.color_B0B0B0"))
}.width(CommonConstants.FULL_WIDTH)
.justifyContent(FlexAlign.Start)
.margin({ top: 8 })
}.width(CommonConstants.FULL_WIDTH)
.padding({
top: 14,
left: 16,
right: 16,
bottom: 14
})
.backgroundColor($r("app.color.white"))
.margin({ bottom: 8 })
}
}
\ No newline at end of file
... ...
//全标题 "compStyle":"3",
import { CompDTO } from 'wdBean'
import { CommonConstants } from 'wdConstant'
@Component
export struct TitleAllComponent {
@State compDTO: CompDTO = {} as CompDTO
build() {
Column() {
Text(this.compDTO.operDataList[0].title)
.fontSize($r("app.float.font_size_16"))
.fontColor($r("app.color.color_222222"))
.width(CommonConstants.FULL_WIDTH)
Row() {
Text("锐评")
.fontSize($r("app.float.font_size_12"))
.fontColor($r("app.color.color_ED2800"))
Text(this.compDTO.operDataList[0].source)
.fontSize($r("app.float.font_size_12"))
.fontColor($r("app.color.color_B0B0B0"))
.margin({ left: 6 })
Image($r("app.media.point"))
.width(16)
.height(16)
Text("46分钟前")
.fontSize($r("app.float.font_size_12"))
.fontColor($r("app.color.color_B0B0B0"))
}.width(CommonConstants.FULL_WIDTH)
.justifyContent(FlexAlign.Start)
.margin({ top: 8 })
}.width("100%")
.padding({
top: 14,
left: 16,
right: 16,
bottom: 14
})
.backgroundColor($r("app.color.white"))
.margin({ bottom: 8 })
}
}
\ No newline at end of file
... ...
export class ContentConstants {
/* content#objectType,跳转类型:0:不跳转 1:点播,2:直播,3:活动,4:广告,5:专题,6:链接,7:榜单,8:图文,9:组图,10:H5新闻,11:频道,12:组件,13:音频,14动态图文,15动态视频 */
/**
* 0:不跳转
*/
static readonly TYPE_NONE: string = "0";
/**
* 1:点播
*/
static readonly TYPE_VOD: string = "1";
/**
* 8:图文详情,这里是h5页面
*/
static readonly TYPE_TELETEXT: string = "8";
}
\ No newline at end of file
... ...
import { GroupDTO, NavigationBody } from 'wdBean';
import { WDHttp } from 'wdNetwork';
import HashMap from '@ohos.util.HashMap';
import { HttpUrlUtils, ResponseDTO, WDHttp } from 'wdNetwork';
import { DateTimeUtils } from 'wdKit';
import { NavigationBodyDTO, PageDTO } from 'wdBean';
export class PageRepository {
static getBottomNavGroupUrl() {
// https: //pd-apis-uat.pdnews.cn/api/rmrb-bff-display-zh/display/zh/c/bottomNavGroup
return HttpUrlUtils.HOST + HttpUrlUtils.BOTTOM_NAV_PATH;
}
static fetchNavigationDataApi(url: string) {
return WDHttp.Request.get<WDHttp.ResponseDTO<NavigationBody>>(url)
};
static getCompInfoUrl(pageId: string, groupId: string, channelId: string, currentPage: number, pageSize: number) {
let url = HttpUrlUtils.HOST + HttpUrlUtils.COMP_PATH;
// TODO 暂定只请求第一页,后续对接分页加载,参数再调整 first_load?
url = url + "?channelStrategy=2&loadStrategy=first_load"
+ "&districtCode=" + HttpUrlUtils.getDistrictCode()
+ "&provinceCode=" + HttpUrlUtils.getProvinceCode()
+ "&cityCode=" + HttpUrlUtils.getCityCode()
+ "&refreshTime=" + DateTimeUtils.getTimeStamp()
+ "&pageId=" + pageId
+ "&groupId=" + groupId
+ "&channelId=" + channelId
+ "&pageSize=" + pageSize
+ "&pageNum=" + currentPage;
// Logger.debug("TAG", 'getCompInfoUrl url: '+url);
return url;
}
static fetchPageData(url: string) {
return WDHttp.Request.get<WDHttp.ResponseDTO<GroupDTO>>(url)
static fetchNavigationDataApi() {
let url = PageRepository.getBottomNavGroupUrl();
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return WDHttp.get<ResponseDTO<NavigationBodyDTO>>(url, headers)
};
static fetchPageData(pageId: string, groupId: string, channelId: string, currentPage: number, pageSize: number) {
let url = PageRepository.getCompInfoUrl(pageId, groupId, channelId, currentPage, pageSize)
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return WDHttp.get<ResponseDTO<PageDTO>>(url, headers)
};
}
\ No newline at end of file
... ...
import { LabelDTO } from 'wdBean';
import { BottomNavDTO, LabelDTO } from 'wdBean';
import { Logger } from 'wdKit';
const TAG: string = 'CompCornerUtil';
... ... @@ -20,6 +20,17 @@ export class CompUtils {
public static readonly MAX_LINES_2: number = 2;
public static readonly MAX_LINES_3: number = 3;
/**
* 判断是否为我的页面
*/
static isMine(navItem: BottomNavDTO): boolean {
if (navItem == null) {
return false;
}
return navItem.type === '2';
}
/**
* 获取Label标题
*
... ... @@ -39,4 +50,5 @@ export class CompUtils {
return labelDTO.title ?? "";
}
}
... ...
import { Logger } from 'wdKit';
import { StringUtils } from 'wdKit/src/main/ets/utils/StringUtils';
import { ContentConstants } from '../constants/ContentConstants';
import { ContentDTO } from '../repository/bean/ContentDTO';
const TAG = 'ProcessUtils';
/**
* 页面跳转业务封装
*/
export class ProcessUtils {
/**
* 页面跳转
*/
static processPage(content: ContentDTO) {
if (content == null) {
Logger.error(TAG, "processPage, content is null");
return;
}
if (StringUtils.isEmpty(content.objectType)) {
Logger.error(TAG, "processPage, objectType is empty");
return;
}
let type = content.objectType;
switch (type) {
case ContentConstants.TYPE_NONE:
Logger.debug(TAG, "processPage, do nothing");
break;
case ContentConstants.TYPE_VOD:
Logger.debug(TAG, "processPage, nonsupport!!!");
// TODO 待对接更多页面
break;
case ContentConstants.TYPE_TELETEXT:
// 图文详情,跳转h5
ProcessUtils.gotoWeb(content);
break;
default:
break;
}
}
private static gotoWeb(content: ContentDTO) {
// // topicId
// content.channelId;
// content.linkUrl;
// content.objectId;
// // CompId
// content.relId;
// content.relType;
// // ScrollToBottom
// // FromPage
// TODO 对接路由
Logger.debug(TAG, `gotoWeb, ${content.objectId}`);
}
}
\ No newline at end of file
... ...
import promptAction from '@ohos.promptAction';
import { RefreshConstants as Const, RefreshState } from './RefreshConstants';
import { touchMoveLoadMore, touchUpLoadMore } from './PullUpLoadMore';
import { PageDTO } from 'wdBean';
import PageModel from '../viewmodel/PageModel';
import PageViewModel from '../viewmodel/PageViewModel';
export function listTouchEvent(pageModel: PageModel, event: TouchEvent) {
switch (event.type) {
case TouchType.Down:
pageModel.downY = event.touches[0].y;
pageModel.lastMoveY = event.touches[0].y;
break;
case TouchType.Move:
if ((pageModel.isRefreshing === true) || (pageModel.isLoading === true)) {
return;
}
let isDownPull = event.touches[0].y - pageModel.lastMoveY > 0;
if (((isDownPull === true) || (pageModel.isPullRefreshOperation === true)) && (pageModel.isCanLoadMore === false)) {
// Finger movement, processing pull-down refresh.
touchMovePullRefresh(pageModel, event);
} else {
// Finger movement, processing load more.
touchMoveLoadMore(pageModel, event);
}
pageModel.lastMoveY = event.touches[0].y;
break;
case TouchType.Cancel:
break;
case TouchType.Up:
if ((pageModel.isRefreshing === true) || (pageModel.isLoading === true)) {
return;
}
if ((pageModel.isPullRefreshOperation === true)) {
// Lift your finger and pull down to refresh.
touchUpPullRefresh(pageModel);
} else {
// Fingers up, handle loading more.
touchUpLoadMore(pageModel);
}
break;
default:
break;
}
}
export function touchMovePullRefresh(pageModel: PageModel, event: TouchEvent) {
if (pageModel.startIndex === 0) {
pageModel.isPullRefreshOperation = true;
let height = vp2px(pageModel.pullDownRefreshHeight);
pageModel.offsetY = event.touches[0].y - pageModel.downY;
// The sliding offset is greater than the pull-down refresh layout height, and the refresh condition is met.
if (pageModel.offsetY >= height) {
pullRefreshState(pageModel, RefreshState.Release);
pageModel.offsetY = height + pageModel.offsetY * Const.Y_OFF_SET_COEFFICIENT;
} else {
pullRefreshState(pageModel, RefreshState.DropDown);
}
if (pageModel.offsetY < 0) {
pageModel.offsetY = 0;
pageModel.isPullRefreshOperation = false;
}
}
}
export function touchUpPullRefresh(pageModel: PageModel) {
if (pageModel.isCanRefresh === true) {
pageModel.offsetY = vp2px(pageModel.pullDownRefreshHeight);
pullRefreshState(pageModel, RefreshState.Refreshing);
pageModel.currentPage = 1;
setTimeout(() => {
let self: PageModel = pageModel;
PageViewModel.getPageData(self.pageId, self.groupId, self.channelId, self.currentPage, self.pageSize, getContext())
.then((data: PageDTO) => {
if (data == null || data.compList == null || data.compList.length == 0) {
self.hasMore = false;
} else {
if (data.compList.length == self.pageSize) {
self.currentPage++;
self.hasMore = true;
} else {
self.hasMore = false;
}
// 刷新,替换所有数据
self.compList.replaceAll(...data.compList)
}
closeRefresh(self, true);
}).catch((err: string | Resource) => {
promptAction.showToast({ message: err });
closeRefresh(self, false);
});
}, Const.DELAY_TIME);
} else {
closeRefresh(pageModel, false);
}
}
export function pullRefreshState(pageModel: PageModel, state: number) {
switch (state) {
case RefreshState.DropDown:
pageModel.pullDownRefreshText = $r('app.string.pull_down_refresh_text');
pageModel.pullDownRefreshImage = $r('app.media.ic_pull_down_refresh');
pageModel.isCanRefresh = false;
pageModel.isRefreshing = false;
pageModel.isVisiblePullDown = true;
break;
case RefreshState.Release:
pageModel.pullDownRefreshText = $r('app.string.release_refresh_text');
pageModel.pullDownRefreshImage = $r('app.media.ic_pull_up_refresh');
pageModel.isCanRefresh = true;
pageModel.isRefreshing = false;
break;
case RefreshState.Refreshing:
pageModel.offsetY = vp2px(pageModel.pullDownRefreshHeight);
pageModel.pullDownRefreshText = $r('app.string.refreshing_text');
pageModel.pullDownRefreshImage = $r('app.media.ic_pull_up_load');
pageModel.isCanRefresh = true;
pageModel.isRefreshing = true;
break;
case RefreshState.Success:
pageModel.pullDownRefreshText = $r('app.string.refresh_success_text');
pageModel.pullDownRefreshImage = $r('app.media.ic_succeed_refresh');
pageModel.isCanRefresh = true;
pageModel.isRefreshing = true;
break;
case RefreshState.Fail:
pageModel.pullDownRefreshText = $r('app.string.refresh_fail_text');
pageModel.pullDownRefreshImage = $r('app.media.ic_fail_refresh');
pageModel.isCanRefresh = true;
pageModel.isRefreshing = true;
break;
default:
break;
}
}
export function closeRefresh(pageModel: PageModel, isRefreshSuccess: boolean) {
let self = pageModel;
setTimeout(() => {
let delay = Const.RefreshConstant_DELAY_PULL_DOWN_REFRESH;
if (self.isCanRefresh === true) {
pullRefreshState(pageModel, isRefreshSuccess ? RefreshState.Success : RefreshState.Fail);
delay = Const.RefreshConstant_DELAY_SHRINK_ANIMATION_TIME;
}
animateTo({
duration: Const.RefreshConstant_CLOSE_PULL_DOWN_REFRESH_TIME,
delay: delay,
onFinish: () => {
pullRefreshState(pageModel, RefreshState.DropDown);
self.isVisiblePullDown = false;
self.isPullRefreshOperation = false;
}
}, () => {
self.offsetY = 0;
})
}, self.isCanRefresh ? Const.DELAY_ANIMATION_DURATION : 0);
}
\ No newline at end of file
... ...
import promptAction from '@ohos.promptAction';
import PageModel from '../viewmodel/PageModel';
import { RefreshConstants as Const } from './RefreshConstants';
import PageViewModel from '../viewmodel/PageViewModel';
import { PageDTO } from 'wdBean';
export function touchMoveLoadMore(model: PageModel, event: TouchEvent) {
// list size +1
if (model.endIndex === model.compList.totalCount() || model.endIndex === model.compList.totalCount() + 1) {
model.offsetY = event.touches[0].y - model.downY;
if (Math.abs(model.offsetY) > vp2px(model.pullUpLoadHeight) / 2) {
model.isCanLoadMore = true;
model.isVisiblePullUpLoad = true;
model.offsetY = -vp2px(model.pullUpLoadHeight) + model.offsetY * Const.Y_OFF_SET_COEFFICIENT;
}
}
}
export function touchUpLoadMore(model: PageModel) {
let self: PageModel = model;
animateTo({
duration: Const.ANIMATION_DURATION,
}, () => {
self.offsetY = 0;
})
if ((self.isCanLoadMore === true) && (self.hasMore === true)) {
self.isLoading = true;
setTimeout(() => {
closeLoadMore(model);
PageViewModel.getPageData(self.pageId, self.groupId, self.channelId, self.currentPage, self.pageSize, getContext())
.then((data: PageDTO) => {
if (data == null || data.compList == null || data.compList.length == 0) {
self.hasMore = false;
} else {
if (data.compList.length == self.pageSize) {
self.currentPage++;
self.hasMore = true;
} else {
self.hasMore = false;
}
self.compList.push(...data.compList)
}
}).catch((err: string | Resource) => {
promptAction.showToast({ message: err });
})
}, Const.DELAY_TIME);
} else {
closeLoadMore(self);
}
}
export function closeLoadMore(model: PageModel) {
model.isCanLoadMore = false;
model.isLoading = false;
model.isVisiblePullUpLoad = false;
}
\ No newline at end of file
... ...
/**
* The constant of refresh.
*/
export class RefreshConstants {
/**
* The off set coefficient.
*/
static readonly Y_OFF_SET_COEFFICIENT: number = 0.1;
/**
* The animation delay time.
*/
static readonly DELAY_ANIMATION_DURATION: number = 300;
/**
* The delay time.
*/
static readonly DELAY_TIME: number = 1000;
/**
* The animation duration.
*/
static readonly ANIMATION_DURATION: number = 2000;
/**
* The RefreshConstant constants.
*/
static readonly RefreshConstant_DELAY_PULL_DOWN_REFRESH: number = 50;
static readonly RefreshConstant_CLOSE_PULL_DOWN_REFRESH_TIME: number = 150;
static readonly RefreshConstant_DELAY_SHRINK_ANIMATION_TIME: number = 500;
/**
* The page size.
*/
static readonly PAGE_SIZE: number = 20;
/**
* The refresh and load height.
*/
static readonly CUSTOM_LAYOUT_HEIGHT: number = 70;
/**
* Full the width.
*/
static readonly FULL_WIDTH: string = '100%';
/**
* The NoMoreLayout constants.
*/
static readonly NoMoreLayoutConstant_NORMAL_PADDING: number = 8;
static readonly NoMoreLayoutConstant_TITLE_FONT: string = '16fp';
/**
* The RefreshLayout constants.
*/
static readonly RefreshLayout_MARGIN_LEFT: string = '40%';
static readonly RefreshLayout_TEXT_MARGIN_BOTTOM: number = 1;
static readonly RefreshLayout_TEXT_MARGIN_LEFT: number = 7;
static readonly RefreshLayout_TEXT_FONT_SIZE: number = 17;
static readonly RefreshLayout_IMAGE_WIDTH: number = 18;
static readonly RefreshLayout_IMAGE_HEIGHT: number = 18;
}
/**
* The refresh state enum.
*/
export const enum RefreshState {
DropDown = 0,
Release = 1,
Refreshing = 2,
Success = 3,
Fail = 4
}
\ No newline at end of file
... ...
import { Logger } from 'wdKit';
import { ResponseDTO } from 'wdNetwork';
/**
* 处理返回后的数据
*/
export abstract class BaseViewModel {
abstract getLogTag(): string;
public isRespondsInvalid(resDTO: ResponseDTO<object>, tag?: string): boolean {
if (resDTO == null) {
Logger.error(this.getLogTag(), `${tag == null ? '' : tag + ', '}resDTO is empty`);
return true;
}
// code = 0, success
if (resDTO.code != 0) {
Logger.error(this.getLogTag(), `${tag == null ? '' : tag + ', '}code error, code:${resDTO.code}, message:${resDTO.message}`);
return true;
}
if (!resDTO.data) {
Logger.error(this.getLogTag(), `${tag == null ? '' : tag + ', '}resDTO.data is null`);
return true;
}
return false;
}
}
\ No newline at end of file
... ...
import { BottomNavBean, GroupDTO, NavigationBody, NewspaperListBean, NewspaperTimeInfoBean } from 'wdBean';
import { Logger, ResourcesUtils } from 'wdKit';
import { ResponseDTO, WDHttp } from 'wdNetwork';
import { PageRepository } from '../repository/PageRepository';
import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
import { ResponseDTO } from 'wdNetwork';
import { NewspaperListBean, NewspaperTimeInfoBean } from 'wdBean';
const TAG = 'NewspaperViewModel';
export class NewspaperViewModel {
static getNewspaperTimeFromLocal(context: Context): NewspaperTimeInfoBean[] {
Logger.info(TAG, `getNewspaperTimeFromLocal start`);
let newspaperTimeInfo: ResponseDTO<NewspaperTimeInfoBean[]> | null = ResourcesUtils.getResourcesJsonSync<ResponseDTO<NewspaperTimeInfoBean[]>>(context, 'newspaper_info.json');
... ...
import { CompDTO } from 'wdBean';
import { LazyDataSource } from 'wdKit';
import { ViewType } from 'wdConstant/src/main/ets/enum/ViewType';
import { RefreshConstants as Const } from '../utils/RefreshConstants';
export default class PageModel {
// 页面数据
pageId: string = "";
groupId: string = "";
channelId: string = "";
compList: LazyDataSource<CompDTO> = new LazyDataSource();
// 页面状态,刷新、加载更多等
currentPage: number = 1;
pageSize: number = Const.PAGE_SIZE;
pullDownRefreshText: Resource = $r('app.string.pull_down_refresh_text');
pullDownRefreshImage: Resource = $r('app.media.ic_pull_down_refresh');
pullDownRefreshHeight: number = Const.CUSTOM_LAYOUT_HEIGHT;
isVisiblePullDown: boolean = false;
pullUpLoadText: Resource = $r('app.string.pull_up_load_text');
pullUpLoadImage: Resource = $r('app.media.ic_pull_up_load');
pullUpLoadHeight: number = Const.CUSTOM_LAYOUT_HEIGHT;
isVisiblePullUpLoad: boolean = false;
offsetY: number = 0;
viewType: number = ViewType.LOADING;
hasMore: boolean = true;
startIndex = 0;
endIndex = 0;
downY = 0;
lastMoveY = 0;
isRefreshing: boolean = false;
isCanRefresh = false;
isPullRefreshOperation = false;
isLoading: boolean = false;
isCanLoadMore: boolean = false;
}
\ No newline at end of file
... ...
import { BottomNavBean, GroupDTO, NavigationBody } from 'wdBean';
import { NavigationBodyDTO, PageDTO } from 'wdBean';
import { Logger, ResourcesUtils } from 'wdKit';
import { ResponseDTO, WDHttp } from 'wdNetwork';
import { ResponseDTO, } from 'wdNetwork';
import { PageRepository } from '../repository/PageRepository';
import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
import { BaseViewModel } from './BaseViewModel';
const TAG = 'PageViewModel';
/**
* mock数据开关,默认关。
* mock数据是本地json数据,可自行修改内容(‘entry\src\main\resources\rawfile\’目录)
*/
const mock_switch = true;
/**
* 处理返回后的数据
*/
export class PageViewModel {
export class PageViewModel extends BaseViewModel {
getLogTag() {
return TAG;
}
/**
* get Nav Data from Resource .
*
* @return BottomNavBean[] Nav Data List
*/
static getBottomNavData(context: Context): BottomNavBean[] {
async getBottomNavData(context: Context): Promise<NavigationBodyDTO> {
Logger.info(TAG, `getBottomNavData start`);
let compRes: ResponseDTO<NavigationBody> | null = ResourcesUtils.getResourcesJsonSync<ResponseDTO<NavigationBody>>(context, 'bottom_nav.json');
if (!compRes || !compRes.data || !compRes.data.bottomNavList) {
Logger.info(TAG, `getBottomNavData compRes bottomNavList is empty`);
return []
if (mock_switch) {
return this.getBottomNavDataMock(context);
}
return this.getNavData();
}
Logger.info(TAG, `getBottomNavData getResourcesJsonSync compRes : ${JSON.stringify(compRes)}`);
return compRes.data.bottomNavList
async getBottomNavDataMock(context: Context): Promise<NavigationBodyDTO> {
Logger.info(TAG, `getBottomNavDataMock start`);
let compRes: ResponseDTO<NavigationBodyDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<NavigationBodyDTO>>(context, 'bottom_nav.json');
if (!compRes || !compRes.data) {
Logger.info(TAG, `getBottomNavDataMock compRes bottomNavList is empty`);
return {} as NavigationBodyDTO
}
Logger.info(TAG, `getBottomNavDataMock getResourcesJsonSync compRes : ${JSON.stringify(compRes)}`);
return compRes.data
}
static getNavData(url: string): Promise<NavigationBody> {
return new Promise<NavigationBody>((success, error) => {
private getNavData(): Promise<NavigationBodyDTO> {
return new Promise<NavigationBodyDTO>((success, error) => {
Logger.info(TAG, `getNavData start`);
PageRepository.fetchNavigationDataApi(url).then((navResDTO: WDHttp.ResponseDTO<NavigationBody>) => {
if (!navResDTO) {
PageRepository.fetchNavigationDataApi().then((navResDTO: ResponseDTO<NavigationBodyDTO>) => {
if (!navResDTO || !navResDTO.data) {
Logger.error(TAG, 'getNavData then navResDTO is empty');
error('navResDTO is empty');
return
}
if (navResDTO.code != http.ResponseCode.OK) {
if (navResDTO.code != 0) {
Logger.error(TAG, `getNavData then code:${navResDTO.code}, message:${navResDTO.message}`);
error('navResDTO Response Code is failure');
return
}
if (!navResDTO.body?.bottomNavList) {
error('navResDTO list is empty');
return
}
// let navResStr = JSON.stringify(navResDTO);
Logger.info(TAG, "getNavData then,navResDTO.timeStamp:" + navResDTO.timeStamp);
let navigationBean = navResDTO.body
success(navigationBean);
}).catch((err: BusinessError) => {
Logger.error(TAG, `fetchNavigationDataApi catch, error.code : ${err.code}, error.message:${err.message}`);
Logger.info(TAG, "getNavData then,navResDTO.timestamp:" + navResDTO.timestamp);
success(navResDTO.data);
}).catch((err: Error) => {
Logger.error(TAG, `fetchNavigationDataApi catch, error.name : ${err.name}, error.message:${err.message}`);
error(err);
})
})
}
/**
* Get Group data.
* Get PageDTO data.
*
* @return {GroupDTO} compRes.data
*/
static getGroupDTO(context: Context): GroupDTO {
let compRes: ResponseDTO<GroupDTO> | null = ResourcesUtils.getResourcesJsonSync<ResponseDTO<GroupDTO>>(context, 'comp_list0.json');
private async getPageData1(currentPage: number, context: Context): Promise<PageDTO> {
if (currentPage > 1) {
// 加载更多,返回无数据
return {} as PageDTO
}
let compRes: ResponseDTO<PageDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<PageDTO>>(context, 'comp_list0.json');
if (!compRes || !compRes.data) {
Logger.info(TAG, `getCompList compRes is empty`);
return {} as GroupDTO
return {} as PageDTO
}
Logger.info(TAG, `getCompList getResourcesJson compRes : ${JSON.stringify(compRes)}`);
return compRes.data
... ... @@ -75,35 +90,43 @@ export class PageViewModel {
* Get Group data.
*
* @return {GroupDTO} compRes.data
* @deprecated
*/
static getGroup2DTO(context: Context): GroupDTO {
let compRes: ResponseDTO<GroupDTO> | null = ResourcesUtils.getResourcesJsonSync<ResponseDTO<GroupDTO>>(context, 'comp_list2.json');
private async getPageData2(context: Context): Promise<PageDTO> {
let compRes: ResponseDTO<PageDTO> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<PageDTO>>(context, 'comp_list2.json');
if (!compRes || !compRes.data) {
Logger.info(TAG, `getCompList compRes is empty`);
return {} as GroupDTO
return {} as PageDTO
}
// router.push('')
Logger.info(TAG, `getCompList getResourcesJson compRes : ${JSON.stringify(compRes)}`);
return compRes.data
}
static getPageData(url: string): Promise<GroupDTO> {
return new Promise<GroupDTO>((success, error) => {
PageRepository.fetchPageData(url).then((resDTO: WDHttp.ResponseDTO<GroupDTO>) => {
if (!resDTO) {
Logger.error(TAG, 'getPageData then resDTO is empty');
error("page data is empty");
async getPageData(pageId: string, groupId: string, channelId: string, currentPage: number
, pageSize: number, context: Context): Promise<PageDTO> {
Logger.debug(TAG, 'getPageData pageId: ' + pageId);
if (mock_switch) {
return this.getPageData1(currentPage, context);
}
return new Promise<PageDTO>((success, error) => {
PageRepository.fetchPageData(pageId, groupId, channelId, currentPage, pageSize)
.then((resDTO: ResponseDTO<PageDTO>) => {
if (!resDTO || !resDTO.data) {
Logger.error(TAG, 'getNavData then resDTO is empty');
error('resDTO is empty');
return
}
if (resDTO.code != http.ResponseCode.OK || !resDTO.body) {
Logger.error(TAG, `getPageData then code:${resDTO.code}, message:${resDTO.message}`);
error(`get page data error code:${resDTO.code}, message:${resDTO.message}`);
if (resDTO.code != 0) {
Logger.error(TAG, `getNavData then code:${resDTO.code}, message:${resDTO.message}`);
error('resDTO Response Code is failure');
return
}
Logger.info(TAG, "getPageData then,resDTO.timeStamp:" + resDTO.timeStamp);
success(resDTO.body);
}).catch((err: BusinessError) => {
Logger.error(TAG, `getPageData catch, error.code : ${err.code}, error.message:${err.message}`);
Logger.info(TAG, "getNavData then,resDTO.timestamp:" + resDTO.timestamp);
success(resDTO.data);
})
.catch((err: Error) => {
Logger.error(TAG, `getPageData catch, error.name : ${err.name}, error.message:${err.message}`);
error(err);
})
})
... ... @@ -111,7 +134,6 @@ export class PageViewModel {
}
let pageViewModel = new PageViewModel();
export default pageViewModel as PageViewModel;
\ No newline at end of file
... ...
... ... @@ -35,6 +35,22 @@
{
"name": "color_ED2800",
"value": "#ED2800"
},
{
"name": "color_B0B0B0",
"value": "#B0B0B0"
},
{
"name": "color_212228",
"value": "#212228"
},
{
"name": "color_fff",
"value": "#ffffff"
},
{
"name": "color_4d000000",
"value": "#4d000000"
}
]
}
\ No newline at end of file
... ...
... ... @@ -7,6 +7,30 @@
{
"name": "footer_text",
"value": "已经到底了"
},
{
"name": "pull_up_load_text",
"value": "加载中..."
},
{
"name": "pull_down_refresh_text",
"value": "下拉刷新"
},
{
"name": "release_refresh_text",
"value": "松开刷新"
},
{
"name": "refreshing_text",
"value": "正在刷新"
},
{
"name": "refresh_success_text",
"value": "刷新成功"
},
{
"name": "refresh_fail_text",
"value": "刷新失败"
}
]
}
\ No newline at end of file
... ...
... ... @@ -3,3 +3,18 @@ export { CommonConstants } from './src/main/ets/constants/CommonConstants';
export { BreakpointConstants } from './src/main/ets/constants/BreakpointConstants';
export { ConfigConstants } from './src/main/ets/constants/ConfigConstants';
// enum
export { BottomNavi } from './src/main/ets/enum/BottomNavi';
export { CompStyle } from './src/main/ets/enum/CompStyle';
export { CompType } from './src/main/ets/enum/CompType';
export { NetDataStatusType } from './src/main/ets/enum/NetDataStatusType';
export { ViewType } from './src/main/ets/enum/ViewType';
export { DurationEnum } from './src/main/ets/enum/DurationEnum';
export { ScreenType } from '../wdConstant/src/main/ets/enum/ScreenType';
\ No newline at end of file
... ...
... ... @@ -28,7 +28,7 @@ export class ConfigConstants {
/**
* 产品渠道应用对照关系:
*/
static readonly appCode: string = "";
static readonly appCode: string = "83092caa603a421aa0222308b3f6b27a";
/**
* 基线代码和客户端应用版本号规范
*/
... ...
/**
* 常见图片宽/高比
*/
export const enum AspectRatioEnum {
// 常见纵向比例
ASPECT_RATIO_2_3 = 2 / 3,
ASPECT_RATIO_3_4 = 3 / 4,
ASPECT_RATIO_4_5 = 4 / 5,
ASPECT_RATIO_5_7 = 5 / 7,
ASPECT_RATIO_9_16 = 9 / 16,
ASPECT_RATIO_10_16 = 10 / 16,
ASPECT_RATIO_9_21 = 9 / 21,
// 正方形
ASPECT_RATIO_1_1 = 1 / 1,
// 常见横向比例
ASPECT_RATIO_7_5 = 7 / 5,
ASPECT_RATIO_5_4 = 5 / 4,
ASPECT_RATIO_4_3 = 4 / 3,
ASPECT_RATIO_3_2 = 3 / 2,
ASPECT_RATIO_16_10 = 16 / 10,
ASPECT_RATIO_16_9 = 16 / 9,
ASPECT_RATIO_21_9 = 21 / 9,
// 其他常见比例
ASPECT_RATIO_2_1 = 2 / 1, // banner图宽高比
ASPECT_RATIO_1_2 = 1 / 2,
ASPECT_RATIO_75_45 = 75 / 45, // 角标宽高比
}
... ...
... ... @@ -19,4 +19,6 @@ export const enum CompStyle {
Grid_Layout_01 = 'Grid_Layout-01', // 横屏宫格卡:视频、直播
Grid_Layout_02 = 'Grid_Layout-02', // 竖屏宫格卡:视频、直播、榜单
Masonry_Layout_01 = 'Masonry_Layout-01', // 双列瀑布流/瀑布流卡:视频、直播、专题、活动
Title_Abbr_01 = 'Title_Abbr_01', // 标题缩略
Title_All_01 = 'Title_All_01', // 全标题
}
... ...
/**
* 时间跨度/延时枚举常量值
* duration/delay/interval
*/
export const enum DurationEnum {
DURATION_MS_50 = 50, // 50毫秒
DURATION_MS_100 = 100, // 50毫秒
DURATION_MS_1000 = 1000, // 1秒/1000ms
DURATION_MS_1500 = 1500, // 1.5秒
DURATION_1 = 1000, // 1秒
DURATION_2 = 2000, // 2秒
DURATION_3 = 3000, // 3秒
DURATION_4 = 4000, // 4秒
}
... ...
/**
* 屏幕类型。1: 竖屏; 2: 横屏;
*/
export const enum ScreenType {
PORTRAIT = "1", // 竖屏
LANDSCAPE = "2", // 横屏;
}
... ...
... ... @@ -7,4 +7,7 @@ export { PlayError } from './src/main/ets/view/PlayError'
export { devicePLSensorManager } from './src/main/ets/utils/devicePortLandSensor'
export { ContentDetailDTO } from './src/main/ets/bean/ContentDetailDTO'
... ...
import { Logger, ResourcesUtils } from 'wdKit';
import { WDHttp } from 'wdNetwork'
import { ResponseDTO, WDHttp } from 'wdNetwork'
import { ContentDetailDTO } from '../bean/ContentDetailDTO'
const TAG = 'ContentDetailRequest';
... ... @@ -13,9 +13,9 @@ export interface ContentDetailRequestParams {
}
export class ContentDetailRequest {
static getContentDetailDataMock(context: Context): Promise<WDHttp.ResponseDTO<ContentDetailDTO[]>> {
static getContentDetailDataMock(context: Context): Promise<ResponseDTO<ContentDetailDTO[]>> {
Logger.info(TAG, `getContentDetailDataMock start`);
return ResourcesUtils.getResourcesJson<WDHttp.ResponseDTO<ContentDetailDTO[]>>(context, 'content_detail.json')
return ResourcesUtils.getResourcesJson<ResponseDTO<ContentDetailDTO[]>>(context, 'content_detail.json')
}
/**
... ... @@ -35,13 +35,11 @@ export class ContentDetailRequest {
return url;
}
static getContentDetail(params: ContentDetailRequestParams): Promise<WDHttp.ResponseDTO<ContentDetailDTO[]>> {
static getContentDetail(params: ContentDetailRequestParams): Promise<ResponseDTO<ContentDetailDTO[]>> {
if (mock_switch) {
return ContentDetailRequest.getContentDetailDataMock(getContext());
}
let headers: Record<string, string> = {};
let url = ContentDetailRequest.getContentDetailUrl(params.contentId, params.relId, params.relType)
// let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return WDHttp.Request.get<WDHttp.ResponseDTO<ContentDetailDTO[]>>(url, headers)
return WDHttp.get<ResponseDTO<ContentDetailDTO[]>>(url)
}
}
\ No newline at end of file
... ...
import { BusinessError } from '@ohos.base'
import { Logger } from 'wdKit'
import { WDHttp } from 'wdNetwork'
import { ContentDetailRequest } from 'wdDetailPlayApi'
import { ContentDetailDTO } from 'wdDetailPlayApi/src/main/ets/bean/ContentDetailDTO'
import { ResponseDTO} from 'wdNetwork'
import { ContentDetailDTO, ContentDetailRequest } from 'wdDetailPlayApi'
const TAG = 'PlayViewModel';
... ... @@ -36,7 +35,7 @@ export class PlayViewModel {
contentId: this.contentId,
relId: this.relId,
relType: this.relType
}).then((resDTO: WDHttp.ResponseDTO<ContentDetailDTO[]>) => {
}).then((resDTO: ResponseDTO<ContentDetailDTO[]>) => {
if (!resDTO) {
Logger.error(TAG, 'getContentDetailData then resDTO is empty');
return
... ...
... ... @@ -4,8 +4,6 @@ export { ResourcesUtils } from './src/main/ets/utils/ResourcesUtils'
export { StringUtils } from './src/main/ets/utils/StringUtils'
export { ArrayUtils } from './src/main/ets/utils/ArrayUtils';
export { AppUtils } from './src/main/ets/utils/AppUtils';
export { BasicDataSource } from './src/main/ets/utils/BasicDataSource';
... ... @@ -19,3 +17,15 @@ export { ToastUtils } from './src/main/ets/utils/ToastUtils';
export { WindowModel } from './src/main/ets/utils/WindowModel'
export { SPHelper } from './src/main/ets/utils/SPHelper'
export { AccountManagerUtils } from './src/main/ets/utils/AccountManagerUtils'
export { CollectionUtils } from './src/main/ets/utils/CollectionUtils'
export { DateTimeUtils } from './src/main/ets/utils/DateTimeUtils'
export { DeviceUtil } from './src/main/ets/utils/DeviceUtil'
export { DisplayUtils } from './src/main/ets/utils/DisplayUtils'
export { SystemUtils } from './src/main/ets/utils/SystemUtils'
... ...
import { StringUtils } from './StringUtils';
import { SPHelper } from './SPHelper';
import { Logger } from './Logger';
const KEY_USER_TOKEN = 'userToken';
const TAG: string = 'AccountManagerUtils';
// 是否已登录hadLogin
let hasLogin: boolean = false;
export class AccountManagerUtils {
// 是否已登录hadLogin
// private static hasLogin: boolean = undefined;
constructor() {
}
static async getUserToken(): Promise<string> {
let userToken = await SPHelper.default.get(KEY_USER_TOKEN, '') as string;
// Logger.info(TAG, 'getUserToken UserToken.' + userToken);
return userToken;
}
static getUserTokenSync(): string {
let userToken = SPHelper.default.getSync(KEY_USER_TOKEN, '') as string;
// Logger.info(TAG, 'getUserToken UserToken.' + userToken);
return userToken;
}
static async putUserToken(value: string) {
await SPHelper.default.save(KEY_USER_TOKEN, value);
}
static putUserTokenSync(value: string) {
SPHelper.default.saveSync(KEY_USER_TOKEN, value);
}
static async deleteUserToken() {
await SPHelper.default.delete(KEY_USER_TOKEN);
}
static deleteUserTokenSync() {
SPHelper.default.deleteSync(KEY_USER_TOKEN);
}
/**
* 是否已登录
* @param folder
* @param files
*/
static async isLogin() {
Logger.info(TAG, 'isLogin hasLogin1:' + hasLogin);
let lastUserToken = await AccountManagerUtils.getUserToken()
Logger.info(TAG, 'isLogin lastUserToken:' + lastUserToken);
if (StringUtils.isEmpty(lastUserToken)) {
hasLogin = false;
Logger.info(TAG, "isLogin lastUserToken is empty");
} else {
hasLogin = true;
Logger.info(TAG, "isLogin lastUserToken is not empty,lastUserToken:" + lastUserToken);
}
// hasLogin = true;
Logger.info(TAG, 'isLogin hasLogin2:' + hasLogin);
return hasLogin;
}
/**
* 是否已登录
* @param folder
* @param files
*/
static isLoginSync() {
Logger.info(TAG, 'isLogin hasLogin1:' + hasLogin);
let lastUserToken = AccountManagerUtils.getUserTokenSync()
Logger.info(TAG, 'isLogin lastUserToken:' + lastUserToken);
if (StringUtils.isEmpty(lastUserToken)) {
hasLogin = false;
Logger.info(TAG, "isLogin lastUserToken is empty");
} else {
hasLogin = true;
Logger.info(TAG, "isLogin lastUserToken is not empty,lastUserToken:" + lastUserToken);
}
// hasLogin = true;
Logger.info(TAG, 'isLogin hasLogin2:' + hasLogin);
return hasLogin;
}
}
// export const accountManagerUtils = new AccountManagerUtils();
\ No newline at end of file
... ...
import LinkList from '@ohos.util.List';
import HashMap from '@ohos.util.HashMap';
export class ArrayUtils {
/**
* ArrayUtils class.
*/
export class CollectionUtils {
/**
* The Array utils tag.
*/
... ... @@ -20,7 +25,32 @@ export class ArrayUtils {
* @returns {boolean} true(empty)
*/
static isEmpty(collection?: any[]): boolean {
return!collection || collection.length === 0;
return !collection || collection.length === 0;
}
static isEmptyList<T>(list1?: LinkList<T>): boolean {
return !list1 || list1.length === 0;
}
static isEmptyHashMap(obj?: HashMap<any, any>): boolean {
if (!obj) {
return true;
}
return obj.isEmpty();
}
static isEmptyMap(obj?: Map<any, any>): boolean {
if (!obj) {
return true;
}
return Object.keys(obj).length === 0 && obj.constructor === Object;
}
static isEmptyRecord(obj?: Record<string, string>): boolean {
if (!obj) {
return true;
}
return Object.keys(obj).length === 0 && obj.constructor === Object;
}
/**
... ... @@ -36,18 +66,18 @@ export class ArrayUtils {
}
static getListSize(collection?: any[]): number {
return ArrayUtils.isEmpty(collection) ? 0 : collection.length;
return CollectionUtils.isEmpty(collection) ? 0 : collection.length;
}
static getListElement(collection?: any[], index?: number): any {
if (ArrayUtils.isEmpty(collection) || index === undefined) {
if (CollectionUtils.isEmpty(collection) || index === undefined) {
return null;
}
return index >= 0 && index < collection.length ? collection[index] : null;
}
static convertArray<T>(objectList: T[] | T): T[] {
if (ArrayUtils.isArray(objectList)) {
if (CollectionUtils.isArray(objectList)) {
return objectList as T[];
} else {
return [objectList as T];
... ... @@ -131,3 +161,4 @@ export class ArrayUtils {
return new Uint8Array(arr);
}
}
... ...
import { StringUtils } from './StringUtils';
/**
* 日期/时间工具
*/
// let myDate = new Date();
// myDate.getTime() // 获取以毫秒为单位的时间值。
// myDate.getFullYear(); // 获取完整的年份(4位,1970-????)
// myDate.getMonth(); // 获取myDate月份(0-11,0代表1月)
// myDate.getDate(); // 获取myDate日期(1-31)
// myDate.getDay(); // 获取myDate星期X(0-6,0代表星期天)
// myDate.getTime(); // 获取myDate时间(从1970.1.1开始的毫秒数)
// myDate.getHours(); // 获取myDate小时数(0-23)
// myDate.getMinutes(); // 获取myDate分钟数(0-59)
// myDate.getSeconds(); // 获取myDate秒数(0-59)
// myDate.getMilliseconds(); // 获取myDate毫秒数(0-999)
// myDate.toLocaleDateString(); // 获取当前日期:使用当前或指定的区域设置将日期转换为字符串。
// myDate.toLocaleTimeString(); // 获取当前时间:使用当前或指定的区域设置将时间转换为字符串。
// myDate.toLocaleString(); // 获取日期与时间:使用当前或指定的区域设置将日期和时间转换为字符串
// 日期时间的年月日时分秒以及毫秒的各个字段
// export class DateOpt {
// year: string = ''; // 年 小写y
// month: string = ''; // 月 大写M
// day: string = ''; // 日 小写d
// hour: string = ''; // 时 大写H(24小时制)
// // hh: string = ''; // 时 小写H(12小时制)
// minute: string = ''; // 分 小写m
// second: string = ''; // 秒 小写s
// millisecond: string = ''; // 毫秒 大写S
// }
export class DateTimeUtils {
static readonly MAX_TIME = Math.pow(10, 8) * 24 * 60 * 60 * 1000; // 8640000000000000 毫秒
static readonly MIN_TIME = -DateTimeUtils.MAX_TIME; // -8640000000000000 毫秒
// 日期+时间格式
static readonly PATTERN_DATE_TIME_DEFAULT: string = 'yyyyMMddHHmmss'; // 年月日时分秒
static readonly PATTERN_DATE_TIME_HYPHEN: string = 'yyyy-MM-dd HH:mm:ss'; // 日期中包含连字符/中划线(HYPHEN),时间是以冒号(Colon)分割
static readonly PATTERN_DATE_TIME_HYPHEN_MS: string = 'yyyy-MM-dd HH:mm:ss.SSS'; // 日期中包含连字符/中划线(HYPHEN),时间是以冒号(Colon)分割
static readonly PATTERN_DATE_TIME_SLASH: string = 'yyyy/MM/dd HH:mm:ss'; // 日期中包含正斜杠(forward slash '/')
static readonly PATTERN_DATE_TIME_BACK_SLASH: string = 'yyyy\\MM\\dd HH:mm:ss'; // 日期中包含反斜杠(back slash '\')
static readonly PATTERN_DATE_TIME_DOT: string = 'yyyy.MM.dd HH:mm:ss'; // 日期中包含英文小圆点(DOT '.')
static readonly PATTERN_DATE_TIME_CN: string = 'yyyy年MM月dd日 HH:mm:ss'; // 日期中包含包含中文年月日
static readonly PATTERN_DATE_TIME_MS: string = 'yyyyMMddHHmmssSSS'; // 时间中包含毫秒
static readonly PATTERN_DATE_TIME_WITHOUT_SECOND: string = 'yyyyMMddHHmm'; // 时间中不包含秒
static readonly PATTERN_DATE_TIME_SIMPLIFY: string = 'MM/dd HH:mm'; // 精简的日期+时间(不包含年份和秒), 月/日 时:分
// 仅日期格式(不包含时间)
static readonly PATTERN_DATE_DEFAULT: string = 'yyyyMMdd'; // 年月日
static readonly PATTERN_DATE_HYPHEN: string = 'yyyy-MM-dd'; // 日期中包含连字符/中划线(HYPHEN)
static readonly PATTERN_DATE_SLASH: string = 'yyyy/MM/dd'; // 日期中包含正斜杠(forward slash '/')
static readonly PATTERN_DATE_BACK_SLASH: string = 'yyyy\\MM\\dd'; // 日期中包含反斜杠(back slash '\')
static readonly PATTERN_DATE_DOT: string = 'yyyy.MM.dd'; // 日期中包含英文小圆点(DOT '.')
static readonly PATTERN_DATE_CN: string = 'yyyy年MM月dd日'; // 日期中包含包含中文年月日
static readonly PATTERN_DATE_SLASH_WITHOUT_YEAR: string = 'MM/dd'; // 日期中不包含年份
static readonly PATTERN_DATE_CN_WITHOUT_YEAR: string = 'MM月dd日'; // 日期中不包含年份,且month与day是中文
// 仅时间格式(不包含日期)
static readonly PATTERN_TIME_DEFAULT: string = 'HHmmss'; // 时分秒
static readonly PATTERN_TIME_COLON: string = 'HH:mm:ss'; // 时间是以冒号(Colon)分割
static readonly PATTERN_TIME_MS: string = 'HHmmssSSS'; // 时间中包含毫秒
static readonly PATTERN_TIME_COLON_DOT_MS: string = 'HH:mm:ss.SSS'; // 时间是以冒号(Colon)与点号(DOT)分割,且包含毫秒
static readonly PATTERN_TIME_WITHOUT_SECOND: string = 'HHmm'; // 时间中不包含秒
static readonly PATTERN_TIME_COLON_WITHOUT_SECOND: string = 'HH:mm'; // 时间是以冒号(Colon)分割,且不包含秒
static readonly PATTERN_TIME_COLON_WITHOUT_HOUR: string = 'mm:ss'; // 时间是以冒号(Colon)分割,且不包含小时(分钟长度至少2位,可能是3位)
static readonly PATTERN_WEEK: string = 'E'; // 周几/星期几
static readonly MONTHS_IN_YEAR: number = 12; // 1年12个月
static readonly QUARTERS_IN_YEAR: number = 4; // 1年4个季度
static readonly MONTHS_IN_QUARTER: number = 3; // 1季度3个月
static readonly DAYS_MONTH: number[] = [31, 30, 29, 28]; // 每月多少天:大月(1/3/5/7/8/10/12月);小月(4/6/9/11月);2月(闰年29天/非闰月28天)
static readonly DAYS_IN_WEEK: number = 7; // 1周7天
static readonly HOURS_IN_DAY = 24; // 1天24小时
// 分钟
static readonly MINUTES_IN_HOUR = 60; // 1小时60分(时分秒之间的进制RADIX)
static readonly MINUTES_IN_DAY = 1440 // 60 * 24 // 1天1440分钟
// 秒
static readonly SECONDS_IN_MINUTE = 60; // 1分60秒(时分秒之间的进制RADIX)
static readonly SECONDS_IN_HOUR = 3600 // 60 * 60 // 1小时3600秒
static readonly SECONDS_IN_DAY = 86400 // 60 * 60 * 24 // 1天86400秒
// 毫秒
static readonly MILLISECONDS_IN_SECOND: number = 1000; // 1秒是1000毫秒,秒与毫秒之间的转换进制RADIX
static readonly MILLISECONDS_IN_MINUTE: number = 60000; // 1000 * 60 // 1分钟是60000毫秒
static readonly MILLISECONDS_IN_HOUR: number = 3600000; // 1000 * 60 * 60 // 1小时是3600000毫秒
static readonly MILLISECONDS_IN_DAY: number = 86400000; // 1000 * 60 * 60 * 24 // 1天是86400000毫秒
static readonly CHINESE_YEAR: string = '年';
static readonly CHINESE_MONTH: string = '月';
static readonly CHINESE_DAY: string = '日';
static readonly CHINESE_LAST_WEEK: string = '上周';
static readonly CHINESE_YESTERDAY: string = '昨天';
static readonly CHINESE_TODAY: string = '今天';
static readonly CHINESE_TOMORROW: string = '明天';
static readonly CHINESE_NEXT_WEEK: string = '下周';
// 周x/星期X
static readonly CHINESE_WEEK1: string[] = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
static readonly CHINESE_WEEK2: string[] = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
static readonly ENGLISH_WEEK1 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
static readonly ENGLISH_WEEK2 = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
static readonly ENGLISH_MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
/**
* 获取当前日期:年月日
* 返回格式,默认如:yyyyMMdd,20230926
*/
static getCurDate(format = DateTimeUtils.PATTERN_DATE_DEFAULT): string {
const DATETIME = new Date()
return DateTimeUtils.formatDate(DATETIME.getTime(), format)
}
/**
* 获取当前时间:时分秒
* 返回格式,默认如:HHmmss,230559
*/
static getCurTime(format = DateTimeUtils.PATTERN_TIME_DEFAULT): string {
const DATETIME = new Date()
return DateTimeUtils.formatDate(DATETIME.getTime(), format)
}
/**
* 获取当前时间戳,毫秒
* */
public static getTimeStamp(): number {
return new Date().getTime();
}
/**
* 当数字转字符串不足maxLength位时,用前导0补足maxLength位
* @param value-数据值
* @returns
* 年份是4位
* 月/日/时/分/秒,都是2位
* 毫秒是3位
*/
static fill(num: number, maxLength: number = 2): string {
let value: string = '' + num
return value.padStart(maxLength, '0')
}
/**
* 获取两个时间点的时间差
* @param milliseconds1
* @param milliseconds2
* @returns Duration
*/
static getDuration(milliseconds1: number, milliseconds2: number): number {
let date1 = new Date(milliseconds1)
let date2 = new Date(milliseconds2)
let timeDiff = Math.abs(date2.getTime() - date1.getTime());
return timeDiff;
}
/**
* 格式化Duration时间
* @param duration 毫秒
* @returns 返回格式化后的Duration时间
*/
static getFormattedDuration(duration: number): string {
// 也可以直接先除以1000转换为秒后再计算 // duration = duration/1000
// Math.floor 用于向下取整
let hour = Math.floor(duration / (DateTimeUtils.MILLISECONDS_IN_HOUR))
// 用总毫秒数duration减去hour所对应的毫秒数差,再除以每分钟所占用的毫秒数
let minute = Math.floor((duration - hour * (DateTimeUtils.MILLISECONDS_IN_HOUR)) / (DateTimeUtils.MILLISECONDS_IN_MINUTE));
let second = Math.floor(duration / DateTimeUtils.MILLISECONDS_IN_SECOND) % DateTimeUtils.SECONDS_IN_MINUTE; // 先除以1000,转换为秒;再对整分钟取余
if (hour > 0) {
return `${DateTimeUtils.fill(hour)}:${DateTimeUtils.fill(minute)}:${DateTimeUtils.fill(second)}`
}
return `${DateTimeUtils.fill(minute)}:${DateTimeUtils.fill(second)}`
}
/**
* 格式化显示倒计时
* @param milliseconds 时间戳 毫秒
* @returns 返回格式化后的Duration时间
*/
static getDurationToNow(milliseconds: number): string {
let nowDateTime = new Date();
let duration = milliseconds - nowDateTime.getTime();
if (duration < 0) {
duration = 0;
}
return DateTimeUtils.getFormattedDuration(duration)
}
/**
* 根据日期/时间字符串反序列化对应的时间戳
* @param dateTimeString string 日期+时间字符串
* 列举字符串格式,如:
* 20231129,yyyyMMdd
* 20231126230559 yyyyMMddHHmmss
* 20231126230559729 yyyyMMddHHmmssSSS
* 2023-11-26 23:05:59.729, yyyy-MM-dd HH:mm:ss.SSS(先移除所有中划线和冒号及空格等非数字字符)
* 日期/时间字符串中包含连字符/中划线(Hyphen/Strike)/移除冒号(Colon)/移除空白字符(包括空格、制表符、换行符等)/移除正斜杠(forward slash '/')/移除反斜杠(back slash '\')
* @param format:string 日期+时间的格式,默认格式:yyyy-MM-dd
* @param referenceDate:Date 参考日期+时间
* @returns 转换后的时间戳:milliseconds 毫秒
* let dateTimeStr:string = "(预告) 2024年12月24日 02:50 开播"
* let formatPattern:string = "(预告) yyyy年MM月dd日 HH:mm 开播"
* let parsedDate = DateTimeUtils.parseDate(dateTimeStr, formatPattern)
*/
static parseDate(dateTimeString: string, format: string = DateTimeUtils.PATTERN_DATE_HYPHEN, referenceDate?: Date): number {
if (!dateTimeString) {
return 0
}
if (!referenceDate) {
referenceDate = new Date(); // 参考当前时间
}
const optPatternList: string[] = ['y+', 'M+', 'd+', 'H+', 'm+', 's+', 'S+'];
let targetYear: number = 0 // 年
let targetMonth: number = 0 // 月, monthIndex
let targetDay: number = 0 // 日
let targetHour: number = 0 // 时
let targetMinute: number = 0 // 分
let targetSecond: number = 0 // 秒
let targetMillisecond: number = 0 // 毫秒
for (let i = 0; i < optPatternList.length; i++) {
const optPattern = optPatternList[i];
const regExp = new RegExp(optPattern, 'g');
// console.log(optPattern);
let matches = regExp.exec(format);
if (!matches) {
continue
}
// console.dir(matches)
// console.dir(matches?.[0])
// console.dir(matches?.index)
let pick: number = StringUtils.parseNumber(dateTimeString.substring(matches.index, matches.index + matches?.[0].length))
// console.dir(pick)
switch (optPattern) {
case 'y+':
if (pick >= -271821 && pick <= 275760) { // 根据最大日期/时间与根据最小日期/时间计算出的年份范围
targetYear = pick
} else {
targetYear = referenceDate.getFullYear() // 当解析不到年份时,则设置为今年
}
break;
case 'M+': // monthIndex between 0 and 11
if (pick >= 1 && pick <= 12) {
targetMonth = pick - 1
} else {
targetMonth = referenceDate.getMonth() // 当解析不到月份时,则设置为本月
}
break;
case 'd+': // between 1 and 31.
if (pick >= 1 && pick <= 31) {
targetDay = pick
} else {
targetDay = referenceDate.getDate()
}
break;
case 'H+': // from 0 to 23
if (pick >= 0 && pick <= 23) {
targetHour = pick
} else {
targetDay = referenceDate.getDate()
}
break;
case 'm+': // from 0 to 59
if (pick >= 0 && pick <= 59) {
targetMinute = pick
} else {
targetDay = referenceDate.getMinutes()
}
break;
case 's+': // from 0 to 59
if (pick >= 0 && pick <= 59) {
targetSecond = pick
} else {
targetSecond = referenceDate.getSeconds()
}
break;
case 'S+': // from 0 to 999
if (pick >= 0 && pick <= 999) {
targetMillisecond = pick
} else {
targetMillisecond = referenceDate.getMilliseconds()
}
break;
default:
break;
}
}
let targetDate: Date = new Date(targetYear, targetMonth, targetDay, targetHour, targetMinute, targetSecond, targetMillisecond)
return targetDate.getTime()
}
/**
* 把整数时间戳格式化为指定格式的日期+时间字符串
* @param timestamp:毫秒
* @param format 指定要格式化的pattern,默认格式:yyyy-MM-dd
* @returns 格式化后的字符串
* 举例:
* let date_fmt = DateTimeUtils.formatDate(dateTime, "预告 (E) MM月dd日 HH:mm 开播")
*/
static formatDate(timestamp: number, format: string = DateTimeUtils.PATTERN_DATE_HYPHEN): string {
try {
const date = new Date(timestamp);
let targetYear: string = date.getFullYear().toString();
let targetMonth: string = DateTimeUtils.fill(date.getMonth() + 1);
let targetDay: string = DateTimeUtils.fill(date.getDate());
let targetHours: string = DateTimeUtils.fill(date.getHours());
let targetMinutes: string = DateTimeUtils.fill(date.getMinutes());
let targetSeconds: string = DateTimeUtils.fill(date.getSeconds());
let targetMilliseconds: string = DateTimeUtils.fill(date.getMilliseconds(), 3);
let targetDayOfWeek: number = date.getDay();
const dateOptionPatternList: string[] = ['y+', 'M+', 'd+', 'H+', 'm+', 's+', 'S+', 'E'];
for (let i = 0; i < dateOptionPatternList.length; i++) {
const dateOptionPattern = dateOptionPatternList[i];
const dateOptionRegExp = new RegExp(dateOptionPattern);
let match = dateOptionRegExp.exec(format); // 使用 RegExp 的exec 方法在目标字符串中查找匹配项
if (!match) {
continue
}
switch (dateOptionPattern) {
case 'y+':
format = format.replace(dateOptionRegExp, targetYear);
break;
case 'M+':
format = format.replace(dateOptionRegExp, targetMonth);
break;
case 'd+':
format = format.replace(dateOptionRegExp, targetDay);
break;
case 'H+':
format = format.replace(dateOptionRegExp, targetHours);
break;
case 'm+':
format = format.replace(dateOptionRegExp, targetMinutes);
break;
case 's+':
format = format.replace(dateOptionRegExp, targetSeconds);
break;
case 'S+':
format = format.replace(dateOptionRegExp, targetMilliseconds);
break;
case 'E': // from 0 to 6; the day of the week
format = format.replace(dateOptionRegExp, DateTimeUtils.CHINESE_WEEK1[targetDayOfWeek]);
break;
default:
break;
}
}
return format;
} catch (error) {
console.error(`ERROR formatDate error: ${error}.`);
return "";
}
}
/**
* 构造一周中的哪一天/构造星期X/周X
* @param timestamp
* @returns
*/
static buildDayOfWeek(timestamp: number, weeks: string[] = DateTimeUtils.CHINESE_WEEK1): string {
try {
const date = new Date(timestamp);
let day = date.getDay()
let week = weeks[day];
return week ?? ''
} catch (error) {
console.error(`ERROR formatDate error: ${error}.`);
return ''
}
}
static startOfDay(argument: number): Date {
const _date = new Date(argument);
_date.setHours(0, 0, 0, 0);
return _date;
}
static isSameDay(dateLeft: number, dateRight: number): boolean {
const dateLeftStartOfDay = DateTimeUtils.startOfDay(dateLeft);
const dateRightStartOfDay = DateTimeUtils.startOfDay(dateRight);
return dateLeftStartOfDay.getTime() === dateRightStartOfDay.getTime();
}
static addDays(argument: number, amount: number): Date {
const _date = new Date(argument);
if (amount == 0) {
return _date;
}
_date.setDate(_date.getDate() + amount);
return _date;
}
static subDays(date: number, amount: number): Date {
return DateTimeUtils.addDays(date, -amount);
}
static isToday(date: number,): boolean {
return DateTimeUtils.isSameDay(date, Date.now());
}
static isYesterday(date: number): boolean {
return DateTimeUtils.isSameDay(date, DateTimeUtils.subDays(Date.now(), 1).getTime());
}
static isTomorrow(date: number): boolean {
return DateTimeUtils.isSameDay(date, DateTimeUtils.addDays(Date.now(), 1).getTime());
}
// 检查指定的日期是过去的吗?
static isPast(_date: Date): boolean {
return _date.getTime() < Date.now();
}
// 检查指定的日期在未来/将来吗?
static isFuture(_date: Date): boolean {
return _date.getTime() > Date.now();
}
// 检查_date是在dateToCompare之后吗?,如
// const result = isAfter(new Date(1989, 6, 10), new Date(1987, 1, 11))
// => true
static isAfter(_date: Date, dateToCompare: Date): boolean {
return _date.getTime() > dateToCompare.getTime();
}
// 检查_date是在dateToCompare之前吗?,如
// const result = isBefore(new Date(1989, 6, 10), new Date(1987, 1, 11))
// => false
static isBefore(_date: Date, dateToCompare: Date): boolean {
return _date.getTime() < dateToCompare.getTime();
}
}
// const dateTimeUtils = new DateTimeUtils()
\ No newline at end of file
... ...
import util from '@ohos.util';
import deviceInfo from '@ohos.deviceInfo';
import { SPHelper } from './SPHelper';
const TAG = 'DeviceUtil';
/**
* 与(硬件)设备相关(不可改变或不可升级)属性或操作
*/
export class DeviceUtil {
static clientId() {
let uuid = SPHelper.default.getSync("clientId", '');
if (uuid == '') {
uuid = util.generateRandomUUID();
SPHelper.default.saveSync("clientId", uuid);
}
return uuid.toString();
}
/**
* 返回设备厂家名称
* HUAWEI
* @returns
*/
static getManufacture(): string {
return deviceInfo.manufacture;
}
/**
* 返回设备品牌名称
* HUAWEI MATE 40 PRO
* @returns
*/
static getBrand(): string {
return deviceInfo.brand;
}
/**
* 返回认证型号
* LIO-AL00
* @returns
*/
static getProductModel(): string {
return deviceInfo.productModel;
}
/**
* 返回产品版本
* OpenHarmony-3.2.6.5(Beta2)
* @returns
*/
static getDisplayVersion(): string {
return deviceInfo.productModel;
}
}
\ No newline at end of file
... ...
import display from '@ohos.display';
import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
import {Logger} from './Logger';
const TAG = 'DisplayUtils';
/**
* 设备显示器/Display属性:
*
手机(HUAWEI Mate 40 Pro & NOH-AN00)-竖屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 0,
"width": 1344, // 屏幕显示的实际宽度/(像素个数/以像素px为单位)
"height": 2772, // 屏幕显示的实际高度/(像素个数/以像素px为单位)
"densityDPI": 560, // 实际像素密度(每英寸像素:120/160/240/320/560)PPI,是一个具体的数值
"orientation": 0,
"densityPixels": 3.5, // 屏幕密度(当像素密度为160时屏幕密度为1.0, 像素比例0.75/1.0/1.5/2.0/3.5) | 缩放因子density = 屏幕像素密度/160, 可用于vp和px转化
"scaledDensity": 3.5, // 可用于fp和px转化
"xDPI": 461.3188781738281,
"yDPI": 457.1999816894531
}
手机(HUAWEI Mate 40 Pro & NOH-AN00)-横屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 1,
"width": 2772,
"height": 1344,
"densityDPI": 560,
"orientation": 1,
"densityPixels": 3.5,
"scaledDensity": 3.5,
"xDPI": 951.47021484375,
"yDPI": 221.67271423339844
}
Fold手机(HUAWEI Mate X5 & ALT-AL10)-折叠状态-竖屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 0,
"width": 1080,
"height": 2504,
"densityDPI": 500,
"orientation": 1,
"densityPixels": 3.125,
"scaledDensity": 3.125,
"xDPI": 173.62025451660156,
"yDPI": 451.0751647949219
}
Fold手机(HUAWEI Mate X5 & ALT-AL10)-折叠状态-横屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 3,
"width": 2504,
"height": 1080,
"densityDPI": 500,
"orientation": 2,
"densityPixels": 3.125,
"scaledDensity": 3.125,
"xDPI": 402.541748046875,
"yDPI": 194.55319213867188
}
Fold手机(HUAWEI Mate X5 & ALT-AL10)-完全展开状态-竖屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 90,
"rotation": 0,
"width": 2224,
"height": 2496,
"densityDPI": 500,
"orientation": 1,
"densityPixels": 3.125,
"scaledDensity": 3.125,
"xDPI": 357.52911376953125,
"yDPI": 449.634033203125
}
平板电脑(HUAWEI MatePad Pro & WGR-W09)(2in1设备)-横屏:
{
"id": 0,
"name": "UNKNOW",
"alive": true,
"state": 0,
"refreshRate": 60,
"rotation": 0,
"width": 2560,
"height": 1600,
"densityDPI": 240,
"orientation": 1,
"densityPixels": 1.5,
"scaledDensity": 1.5,
"xDPI": 239.05882263183594,
"yDPI": 239.05882263183594
}
*/
/**
* 与显示器/display/screen(硬件)设备相关(不可改变或不可升级)属性或操作(应该读取窗口Window的宽高,而不是显示器display的宽高,因为电脑设备的窗口可以动态调整Window窗口大小)
* 屏幕密度是160时,1vp=1px
*/
export class DisplayUtils {
/**
* Get 屏幕显示/display/screen Width(单位vp)
* 手机(HUAWEI Mate 40 Pro & NOH-AN00)-竖屏:width为1344*3.5=384vp
* 手机(HUAWEI Mate 40 Pro & NOH-AN00)-横屏:width为2772*3.5=792vp
* @returns screen width.
*/
public static getDeviceWidth(): number {
let displayObject: display.Display = display.getDefaultDisplaySync();
// Logger.info(TAG, `getDeviceWidth, displayObject: ${JSON.stringify(displayObject)}`);
let screenWidth = displayObject.width;
let screenDensityDPI = displayObject.densityDPI;
// 像素密度(Pixel Density)
let densityPixels = screenDensityDPI / ConfigurationConstant.ScreenDensity.SCREEN_DENSITY_MDPI
// let densityPixels = displayObject.densityPixels
let deviceWidth = screenWidth / densityPixels;
// Logger.info(TAG, `getDeviceWidth, deviceWidth: ${deviceWidth}`);
return deviceWidth
}
/**
* Get the 显示/display/screen height(单位vp).
*
* @returns screen height.
*/
public static getDeviceHeight(): number {
let displayObject: display.Display = display.getDefaultDisplaySync();
let screenHeight = displayObject.height;
let screenDensityDPI = displayObject.densityDPI;
// 像素密度(Pixel Density)
let densityPixels = screenDensityDPI / ConfigurationConstant.ScreenDensity.SCREEN_DENSITY_MDPI
// let densityPixels = displayObject.densityPixels
let deviceHeight = screenHeight / densityPixels
// Logger.info(TAG, `getDeviceHeight, deviceHeight: ${deviceHeight}`); // 345.6 // 711.68
return deviceHeight
}
}
... ...
... ... @@ -26,56 +26,97 @@ export class LazyDataSource<T> extends BasicDataSource<T> {
return this.dataArray[index];
}
// 获取索引对应的Item数据
public get(index: number): T {
return this.getData(index);
}
public getFirst(): T {
return this.getData(0);
}
public getLast(): T {
return this.getData(this.totalCount() - 1);
}
// 获取所有数据
public getDataArray(): T[] {
return this.dataArray;
}
// 增加/插入1个Item/数据,若index为undefined,则在数据尾部增加1个元素;否则,在指定索引(可为负/或大于数组长度)位置插入1个元素
public addItem(data: T, index?: number): void {
if (index == undefined) {
public addItem(item: T, startPosition?: number): void {
if (startPosition == undefined) {
// 将新元素添加到数组的末尾
this.dataArray.push(data);
// this.dataArray.splice(this.dataArray.length, 0, data)
this.dataArray.push(item);
// this.dataArray.splice(this.dataArray.length, 0, item)
this.notifyDataAdd(this.dataArray.length - 1);
} else {
// 从数组中的index位置开始删除0个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。
// 当index大于等于数组长度时,不删除任何数据,且data加在数组末尾
// 当index大于等于数组长度时,不删除任何数据,且item加在数组末尾
// 当index为负数时,其代表从数组后向前的索引位置
this.dataArray.splice(index, 0, data);
this.dataArray.splice(startPosition, 0, item);
this.notifyDataAdd(startPosition);
}
}
public addItems(arr: T[], startPosition?: number): void {
if (startPosition == undefined) {
// 将新元素添加到数组的末尾
this.dataArray.push(...arr)
for (let index = this.dataArray.length - arr.length; index < this.dataArray.length; index++) {
this.notifyDataAdd(index);
}
} else {
// 从数组中的position位置开始删除0个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。
// 当index大于等于数组长度时,不删除任何数据,且arr加在数组末尾
// 当index为负数时,其代表从数组后向前的索引位置
this.dataArray.splice(startPosition, 0, ...arr);
for (let index = startPosition; index < arr.length; index++) {
this.notifyDataAdd(index);
}
}
}
// 在数据尾部增加1到多个元素
public push(...data: T[]): void {
this.dataArray.push(...data)
for (let index = this.dataArray.length - data.length; index < this.dataArray.length; index++) {
public push(...items: T[]): void {
this.dataArray.push(...items)
for (let index = this.dataArray.length - items.length; index < this.dataArray.length; index++) {
this.notifyDataAdd(index);
}
}
// 在数据尾部增加一个同类型的LazyDataSource
public pushDataSource(dataSource: LazyDataSource<T>): void {
this.push(...dataSource.dataArray)
}
// 在数据尾部增加1个元素
public addLastItem(data: T): void {
this.addItem(data)
public addLastItem(item: T): void {
this.addItem(item)
}
// 在数据开头插入1个元素
public addFirstItem(data: T): void {
public addFirstItem(item: T): void {
// 在数组的开头插入(1个或多个)新元素
// this.dataArray.unshift(data)
// this.dataArray.unshift(item)
// this.notifyDataAdd(0);
this.addItem(data, 0)
this.addItem(item, 0)
}
// 在第2个元素位置,插入1个元素
public add2ndItem(data: T): void {
this.addItem(data, 1)
public add2ndItem(item: T): void {
this.addItem(item, 1)
}
// 在第3个元素位置,插入1个元素
public add3rdItem(data: T): void {
this.addItem(data, 2)
public add3rdItem(item: T): void {
this.addItem(item, 2)
}
// 在第4个元素位置,插入1个元素
public add4thItem(data: T): void {
this.addItem(data, 3)
public add4thItem(item: T): void {
this.addItem(item, 3)
}
// 把from位置的item移动到to位置(暂不支持from/to为负数或大于等于数组长度)
... ... @@ -159,53 +200,80 @@ export class LazyDataSource<T> extends BasicDataSource<T> {
}
// 修改/更新index指定索引位置的元素
public updateItem(data: T, index?: number): void {
public updateItem(item: T, index?: number): void {
if (index == undefined || index >= this.dataArray.length) {
// 当不传index或index大于等于数组长度时,修改/更新数组的最后1个元素
this.dataArray.splice(this.dataArray.length - 1, 1, data);
this.dataArray.splice(this.dataArray.length - 1, 1, item);
this.notifyDataChange(this.dataArray.length);
} else {
// 从数组中的index位置开始,删除1个元素
// 当index为负数时,其代表从数组后向前的索引位置
this.dataArray.splice(index, 1, data);
this.dataArray.splice(index, 1, item);
this.notifyDataChange(index);
}
}
// 修改/更新最后1个元素
public updateLastItem(data: T): void {
this.updateItem(data)
public updateLastItem(item: T): void {
this.updateItem(item)
}
// 修改/更新第1个元素
public updateFirstItem(data: T): void {
this.updateItem(data, 0)
public updateFirstItem(item: T): void {
this.updateItem(item, 0)
}
// 修改/更新第1个元素
public update2ndItem(data: T): void {
this.updateItem(data, 0)
public update2ndItem(item: T): void {
this.updateItem(item, 0)
}
// 修改/更新第2个元素
public update1stItem(data: T): void {
this.updateItem(data, 1)
public update1stItem(item: T): void {
this.updateItem(item, 1)
}
// 修改/更新第3个元素
public update3rdItem(data: T): void {
this.updateItem(data, 2)
public update3rdItem(item: T): void {
this.updateItem(item, 2)
}
// 修改/更新第4个元素
public update4thItem(data: T): void {
this.updateItem(data, 3)
public update4thItem(item: T): void {
this.updateItem(item, 3)
}
// 清空数组
public clear(): void {
this.replaceAll()
}
// 把数据全部删除,再添加全部新元素
public replaceAll(...data: T[]): void {
public replaceAll(...items: T[]): void {
// 从数组中的0位置开始删除dataArray.length个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。
this.dataArray.splice(0, this.dataArray.length, ...data);
this.dataArray.splice(0, this.dataArray.length, ...items);
this.notifyDataReload()
}
// 获取指定元素的下标
public getIndexOf(element: T): number {
for (let index = 0; index < this.dataArray.length; index++) {
if (this.dataArray[index] == element) {
return index
}
}
return -1
}
public isEmpty(): boolean {
return this.dataArray.length == 0
}
public isNotEmpty(): boolean {
return this.dataArray.length > 0
}
public sort(comparator: (firstValue: T, secondValue: T) => number): void {
this.dataArray.sort(comparator)
}
}
\ No newline at end of file
... ...
... ... @@ -79,16 +79,17 @@ export class ResourcesUtils {
* SubscribeListData.json
* @returns JSON Object
*
* 调用方式:todo:
* 调用方式:
* let compRes: MGHttp.ResponseDTO<BodyComponent> = await ResourcesUtils.getResourcesJson<MGHttp.ResponseDTO<BodyComponent>>(context, 'model/componentList.json');
*/
static getResourcesJson<R>(context:Context, filename: string): Promise<R> {
static getResourcesJson<R>(context: Context, filename: string): Promise<R> {
Logger.info(TAG, `getResourcesJson filename: ${filename}`);
return new Promise<R>((resolve, reject) => {
ResourcesUtils.getResourcesText(context, filename)
.then((text: string) => {
try {
// let config: R = JSON.parse(text)
let config:R = JSON.parse(text) as R;
let config: R = JSON.parse(text) as R;
if (config) {
Logger.info(TAG, "getResourcesJson parse JSON file success.");
// Logger.info(TAG, `getResourcesJson config : ${JSON.stringify(config)}`);
... ... @@ -117,7 +118,7 @@ export class ResourcesUtils {
}
try {
// let config: R = JSON.parse(text)
let config:R = JSON.parse(text) as R;
let config: R = JSON.parse(text) as R;
return config
} catch (err) {
// json解析异常
... ...
import deviceInfo from '@ohos.deviceInfo';
/**
* 与鸿蒙系统(软件)设备相关(可改变或可升级)属性或操作
*/
export class SystemUtils {
/**
* 返回AGC格式的系统名称
* OpenHarmony 3.2.6.5(Beta2)
*/
static getOsFullName(): string {
// OpenHarmony-3.2.6.5(Beta2)
let fullName = deviceInfo.osFullName.split('-');
if (fullName && fullName.length >= 1) {
return fullName[0] + ' ' + fullName[1];
}
return '';
}
/**
* 返回系统空闲存储空间,TODO:
* @returns number
*/
static getFreeBytes(): number {
return 0;
}
}
... ...
export { ResponseDTO } from './src/main/ets/bean/ResponseDTO'
export { ResponseDTO } from "./src/main/ets/bean/ResponseDTO"
export { ResponseVO } from './src/main/ets/bean/ResponseVO'
export { HttpRequest as WDHttp } from "./src/main/ets/http/HttpRequest"
export { ResultCode } from './src/main/ets/bean/ResultCode'
export { HttpUrlUtils } from "./src/main/ets/http/HttpUrlUtils"
export { WDHttp } from './src/main/ets/http/WDHttp'
\ No newline at end of file
... ...
... ... @@ -8,6 +8,7 @@
"version": "1.0.0",
"dependencies": {
"wdKit": "file:../wdKit",
"wdConstant": "file:../wdConstant",
"@ohos/axios": "^2.1.1"
}
}
... ...
/**
* ResponseVO
*/
export interface ResponseVO<T = string> {
// 返回代码,参考附录ResultCode 即(ACCEPTED/SUCCESS/FAILED/REJECTED等)
resultCode: string;
// 返回描述
resultDesc: string;
// 错误码,参考附录和接口中ErrorCode(当resultCode=FAILED才有),如:"ERR_USER_NOTFOUND"
errorCode?: string;
// 业务数据
data?: T;
}
\ No newline at end of file
/**
* The Response ResultCode enum.
*/
export const enum ResultCode {
// 请求执行(查询)成功
SUCCESS = 'SUCCESS',
// 请求执行(查询)失败
FAILED = 'FAILED',
// 该请求被拒绝处理,例如参数错误或非法等
REJECTED = 'REJECTED',
// 该请求已经被接收,但是本次同步返回无法知道执行结果
ACCEPTED = 'ACCEPTED',
// 参数错误
// ERR_NOT_VALID_PARAMETERS = 'ERR_NOT_VALID_PARAMETERS'
}
import type { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from '@ohos/axios';
import axios, { HttpStatusCode } from '@ohos/axios';
import axios, {
AxiosError,
AxiosInstance,
AxiosResponse,
HttpStatusCode,
InternalAxiosRequestConfig
} from '@ohos/axios';
// import type ResponseDTO from '../models/ResponseDTO';
... ... @@ -57,8 +62,7 @@ instance.interceptors.request.use(
// }
// 添加响应拦截器
instance.interceptors.response.use(
// 响应拦截器response类型就是Axios.request<T = any, R = AxiosResponse<T>, D = any>中的泛型R
instance.interceptors.response.use(// 响应拦截器response类型就是Axios.request<T = any, R = AxiosResponse<T>, D = any>中的泛型R
// 泛型 T 就是服务器返回数据的类型
// 泛型 R 就是这个泛型 T 数据经过 axios 包装一层得到的 response 对象的类型,而 request 方法的返回值是一个 Promise,其值就是成功态的 R,也就是 response对象。
(response: AxiosResponse) => {
... ... @@ -83,7 +87,9 @@ instance.interceptors.response.use(
// 改造返回的数据,即将AxiosResponse的data返回,服务端返回的数据
return response.data;
} else {
return Promise.reject(response);
console.log(`httpStatus:${response.status}-${response.status}!`)
// return Promise.reject(error);
return response.data;
}
},
(error: AxiosError) => {
... ... @@ -101,7 +107,7 @@ instance.interceptors.response.use(
export default instance;
function buildErrorMsg(httpStatus: number):string {
function buildErrorMsg(httpStatus: number): string {
let message = "";
switch (httpStatus) {
case HttpStatusCode.BadRequest:
... ...
import ArrayList from '@ohos.util.ArrayList';
import service from './AxiosRequest';
import { HttpUtils } from '../utils/HttpUtils';
import { AxiosError, AxiosHeaders, AxiosRequestConfig, RawAxiosRequestHeaders } from '@ohos/axios';
import { ResponseDTO } from '../bean/ResponseDTO';
import HashMap from '@ohos.util.HashMap';
export class HttpRequest {
private static globalHeaderProviders: ArrayList<() => Record<string, string>> = new ArrayList();
static addGlobalHeaderProvider(provider: () => Record<string, string>) {
HttpRequest.globalHeaderProviders.add(provider)
}
static initHttpHeader() {
HttpRequest.addGlobalHeaderProvider(() => {
return HttpUtils.buildHeaders();
})
}
// 加入泛型限定,返回数据类型为T,
static request<T = ResponseDTO<string>>(config: AxiosRequestConfig): Promise<T> {
return new Promise<T>((resolve, reject) => {
service.request<ResponseDTO<string>, T>(config)
.then((res: T) => {
resolve(res)
})
.catch((err: AxiosError) => {
reject(err)
})
})
// return service.request<any, T>(config)
}
static buildHeaderWithGlobalHeader(headers?: HashMap<string, string>): AxiosHeaders {
let commonHeader: AxiosHeaders = new AxiosHeaders()
headers?.forEach((v, k) => {
commonHeader.set(k, v);
});
HttpRequest.globalHeaderProviders.forEach((func) => {
let headers = func();
for (const obj of Object.entries(headers)) {
commonHeader.set(obj[0], obj[1]);
}
})
if (!commonHeader.get('Content-Type')) {
commonHeader.set('Content-Type', 'application/json;charset=utf-8');
}
return commonHeader
}
static get<T = ResponseDTO<string>>(url: string, headers?: HashMap<string, string>): Promise<T> {
let config: AxiosRequestConfig = {
headers: HttpRequest.buildHeaderWithGlobalHeader(headers)
}
return service.get(url, config)
}
static post<T = ResponseDTO<string>>(url: string, data?: object, headers?: HashMap<string, string>): Promise<T> {
let config: AxiosRequestConfig = {
headers: HttpRequest.buildHeaderWithGlobalHeader(headers)
}
return service.post(url, data, config)
}
static put<T = ResponseDTO<string>>(url: string, data?: object, headers?: HashMap<string, string>): Promise<T> {
let config: AxiosRequestConfig = {
headers: HttpRequest.buildHeaderWithGlobalHeader(headers)
}
return service.put(url, data, config)
}
static delete<T = ResponseDTO<string>>(url: string, headers?: HashMap<string, string>): Promise<T> {
let config: AxiosRequestConfig = {
headers: HttpRequest.buildHeaderWithGlobalHeader(headers)
}
return service.delete(url, config)
}
}
... ...
import type { AxiosError, AxiosRequestConfig} from '@ohos/axios';
import service from './AxiosRequest';
export default class HttpRequest {
// 加入泛型限定,返回数据类型为T,
static request<T = any>(config: AxiosRequestConfig): Promise<T> {
return new Promise<T>((resolve, reject) => {
service.request<any, T>(config)
.then((res:T) => {
resolve(res)
})
.catch((err:AxiosError) => {
reject(err)
})
})
// return service.request<any, T>(config)
}
static get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
return service.get(url, config)
}
static delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
return service.delete(url, config)
}
static post<T = any>(url: string, data?: object, config?: AxiosRequestConfig): Promise<T> {
return service.post(url, data, config)
}
static put<T = any>(url: string, data?: object, config?: AxiosRequestConfig): Promise<T> {
return service.put(url, data, config)
}
}
import HashMap from '@ohos.util.HashMap'
import { ConfigConstants } from 'wdConstant'
import { DateTimeUtils, Logger } from 'wdKit'
/**
* 网络请求业务侧工具类
*/
export class HttpUrlUtils {
/**
* 现网地址
*/
static readonly HOST: string = "https://pd-apis-uat.pdnews.cn";
/**
* 启动接口(底导接口)
*/
static readonly BOTTOM_NAV_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/bottomNavGroup";
/**
* 展现comp接口
*/
static readonly COMP_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/compInfo";
static getCommonHeaders(): HashMap<string, string> {
let headers: HashMap<string, string> = new HashMap<string, string>()
headers.set('User-Agent', 'Dalvik/2.1.0 (Linux; U; Android 13; 22101317C Build/TKQ1.221013.002)')
headers.set('channel', HttpUrlUtils.getChannel())
headers.set('appCode', ConfigConstants.appCode)
headers.set('plat', HttpUrlUtils.getPlat())
headers.set('Authorization', 'APPCODE 83092caa603a421aa0222308b3f6b27a')
headers.set('Content-Type', 'application/json; charset=utf-8')
headers.set('timestamp', HttpUrlUtils.getTimestamp())
headers.set('RMRB-X-TOKEN', HttpUrlUtils.getXToken())
headers.set('device_id', HttpUrlUtils.getDeviceId())
headers.set('cookie', 'RMRB-X-TOKEN=eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc')
headers.set('build_version', HttpUrlUtils.getVersion())
headers.set('adcode', HttpUrlUtils.getAdCode())
headers.set('os_version', HttpUrlUtils.getOsVersion())
headers.set('X-Ca-Stage', 'PRE')
headers.set('versionCode', HttpUrlUtils.getVersionCode())
headers.set('system', HttpUrlUtils.getTerminalId())
headers.set('version_name', 'debug')
headers.set('EagleEye-TraceID', '0B6DE03D2997435BA875FFBE05425ED2')
headers.set('imei', HttpUrlUtils.getImei())
headers.set('Accept-Language', 'zh')
headers.set('city', HttpUrlUtils.getCity())
headers.set('city_dode', HttpUrlUtils.getCityCode())
// TODO 判断是否登录
headers.set('userId', HttpUrlUtils.getUserId())
headers.set('userType', HttpUrlUtils.getUserType())
// Logger.debug("TAG", '******************* commonHeaders headers start ******************************** ');
// headers.forEach((v,k)=>{
// Logger.debug("TAG", 'getCommonHeaders header: ' + k + ': ' + v);
// })
// Logger.debug("TAG", '******************* commonHeaders headers end ******************************** ');
return headers;
}
private static getCity() {
// TODO 对接定位
return '%E5%90%88%E8%82%A5%E5%B8%82';
}
private static getChannel() {
// TODO 对接配置
return 'rmrb_china_0000';
}
private static getPlat() {
return 'Phone';
}
private static getTimestamp() {
// return DateTimeUtils.getCurrentTime() + '';
// TODO 暂时写死,有些page 真实时间戳 返回数据为空
return '155203523';
}
private static getXToken() {
return 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc';
}
private static getDeviceId() {
// TODO
return 'b5cf725d-193d-3215-8c77-e76fe15ce64d';
}
private static getVersion() {
// TODO
return '202312251034';
}
private static getVersionCode() {
// TODO
return '7301';
}
private static getAdCode() {
return '340000';
}
private static getOsVersion() {
// TODO
return '13';
}
public static getCityCode() {
// TODO
return '340100';
}
public static getProvinceCode() {
// TODO
return '340000';
}
/**
* 地区code
*/
public static getDistrictCode() {
// TODO
return '340103';
}
private static getTerminalId() {
return 'Android';
}
private static getImei() {
// TODO
return 'b5cf725d-193d-3215-8c77-e76fe15ce64d';
}
private static getUserId() {
// TODO 对接登录
return '459776297474949';
}
private static getUserType() {
return '2';
}
}
\ No newline at end of file
... ...
import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
import ArrayList from '@ohos.util.ArrayList';
import { Logger } from 'wdKit';
import { HttpUtils } from '../utils/HttpUtils';
const TAG = 'WDHttp';
export namespace WDHttp {
export enum RequestMethod {
OPTIONS = http.RequestMethod.OPTIONS,
GET = http.RequestMethod.GET,
HEAD = http.RequestMethod.HEAD,
POST = http.RequestMethod.POST,
PUT = http.RequestMethod.PUT,
DELETE = http.RequestMethod.DELETE,
TRACE = http.RequestMethod.TRACE,
CONNECT = http.RequestMethod.CONNECT,
}
export enum HttpParamsType {
STRING,
OBJECT,
ARRAY_BUFFER
}
export interface RequestOptions {
// 请求方法
method?: RequestMethod;
// 请求头
header?: object;
// 读超时时间 单位s 默认60
readTimeout?: number;
// 连接超时时间 单位s 默认60
connectTimeout?: number;
// 请求参数 当请求为get请求时 该参数会自动拼接在url后面
params?: object;
// 请求参数类型 当请求为post时有效
paramsType?: HttpParamsType;
}
export const enum ErrorCode {
// 请求执行(查询)失败
FAILED = -1,
// 请求执行(查询)成功
SUCCESS = http.ResponseCode.OK,
// 业务错误码。。。
}
/**
* ResponseDTO
* 微服务通用返回结构
* http://confluence.cmvideo.cn/confluence/pages/viewpage.action?pageId=4232418
*/
export interface ResponseDTO<T = string> {
// 服务请求响应值/微服务响应状态码”
code: number;
// 服务请求响应说明
message: string;
// 响应结果
body?: T;
data?: T;
// 请求响应时间戳(unix格式)
timeStamp?: number;
// timestamp?: number;
// 返回当前时间戳,格式:yyyyMMddHHmmss,如20230918102124
dataVersion?: string;
}
/**
* ResponseVO
* 基础服务通用返回结构
* 如PUGC错误码:http://confluence.cmvideo.cn/confluence/pages/viewpage.action?pageId=168081524
*/
export interface ResponseVO<T = string> {
// 返回代码,参考附录ResultCode 即(ACCEPTED/SUCCESS/FAILED/REJECTED等)
resultCode: string;
// 返回描述
resultDesc: string;
// 错误码,参考附录和接口中ErrorCode(当resultCode=FAILED才有),如:"ERR_USER_NOTFOUND"
errorCode?: string;
// 业务数据
data?: T;
}
/**
* The Response ResultCode enum.
*/
export const enum ResultCode {
// 请求执行(查询)成功
SUCCESS = 'SUCCESS',
// 请求执行(查询)失败
FAILED = 'FAILED',
// 该请求被拒绝处理,例如参数错误或非法等
REJECTED = 'REJECTED',
// 该请求已经被接收,但是本次同步返回无法知道执行结果
ACCEPTED = 'ACCEPTED',
// 参数错误
// ERR_NOT_VALID_PARAMETERS = 'ERR_NOT_VALID_PARAMETERS'
}
export class Request {
private static globalHeaderProviders: ArrayList<() => Record<string, string>> = new ArrayList();
static addGlobalHeaderProvider(provider: () => Record<string, string>) {
Request.globalHeaderProviders.add(provider)
}
static initHttpHeader() {
Request.addGlobalHeaderProvider(() => {
return HttpUtils.buildHeaders();
})
}
private static makeRequestOptions(options?: RequestOptions): http.HttpRequestOptions {
if (options) {
let op: http.HttpRequestOptions = {};
op.method = options.method!.toString() as http.RequestMethod;
op.header = options.header
op.readTimeout = (options.readTimeout ?? 60) * 1000
op.connectTimeout = (options.connectTimeout ?? 60) * 1000
if (options.method == RequestMethod.POST) {
op.extraData = options.params;
if (options.paramsType == HttpParamsType.STRING) {
op.expectDataType = http.HttpDataType.STRING;
} else if (options.paramsType == HttpParamsType.OBJECT) {
op.expectDataType = http.HttpDataType.OBJECT;
} else if (options.paramsType == HttpParamsType.ARRAY_BUFFER) {
op.expectDataType = http.HttpDataType.ARRAY_BUFFER;
}
} else if (options.method == RequestMethod.PUT) {
// todo
} else if (options.method == RequestMethod.DELETE) {
// todo
}
return op;
}
return {}
}
private static makeUrl(url: string, options?: RequestOptions): string {
if (!options || (options.method && options.method != RequestMethod.GET)) {
return url;
}
if (!options.params) {
return url;
}
let paramStr = "";
if (typeof options.params == "string") {
paramStr = options.params;
} else if (typeof options.params == "object") {
let arr: string[] = [];
Object.entries(options.params).forEach((entry: object) => {
arr.push(`${entry[0]}=${entry[1]}`)
})
if (arr.length == 0) {
return url;
}
paramStr = arr.join("&")
}
if (url.indexOf("?") == -1) {
return url + "?" + paramStr;
} else {
if (url.endsWith("?")) {
return url + paramStr;
} else {
return url + "&" + paramStr;
}
}
}
// 加入泛型限定,返回数据类型为T,
// static request<T = any>(url: string, options: RequestOptions, callback?: AsyncCallback<ResponseDTO<T>>) {
// let httpRequest = http.createHttp();
// if (!options) {
// options = {};
// }
// if (!options.method) {
// options.method = RequestMethod.GET;
// }
// if (!options.header) {
// let header: Record<string, string> = {
// // 'Content-Type': 'text/plain'
// 'Content-Type': 'application/json;charset=utf-8'
// };
// options.header = header
// } else if (!options.header['Content-Type']) {
// options.header['Content-Type'] = 'application/json;charset=utf-8';
// }
//
// Request.globalHeaders.forEach((value, key) => {
// options!.header![key] = value;
// })
// let realUrl = Request.makeUrl(url, options);
// httpRequest.request(realUrl, Request.makeRequestOptions(options), (error, responseData: http.HttpResponse) => {
// if (callback) {
// if (error) {
// callback(error, undefined)
// } else {
// try {
// let response: ResponseDTO<T> = JSON.parse(`${responseData.result}`)
// callback(error, response)
// } catch (err) {
// callback(error, { code: responseData?.responseCode, message: responseData?.result?.toString() })
// }
// }
// }
// })
// }
//
// static get<T = any>(url: string, options: RequestOptions, callback?: AsyncCallback<ResponseDTO<T>>) {
// let op = options ?? {}
// op.method = RequestMethod.GET;
// Request.request<T>(url, op, callback)
// }
//
// static post<T = any>(url: string, options: RequestOptions, callback?: AsyncCallback<ResponseDTO<T>>) {
// let op = options ?? {}
// op.method = RequestMethod.POST;
// Request.request<T>(url, op, callback)
// }
//
// static put<T = any>(url: string, options: RequestOptions, callback?: AsyncCallback<ResponseDTO<T>>) {
// let op = options ?? {}
// op.method = RequestMethod.PUT;
// Request.request<T>(url, op, callback)
// }
//
// static delete<T = any>(url: string, options: RequestOptions, callback?: AsyncCallback<ResponseDTO<T>>) {
// let op = options ?? {}
// op.method = RequestMethod.DELETE;
// Request.request<T>(url, op, callback)
// }
////
static request<T = string>(url: string, options?: RequestOptions): Promise<T> {
let httpRequest = http.createHttp();
if (!options) {
options = {};
}
if (!options.method) {
options.method = RequestMethod.GET;
}
if (!options.header) {
let header: Record<string, string> = {
// 'Content-Type': 'text/plain'
'Content-Type': 'application/json;charset=utf-8'
};
options.header = header
} else if (!options.header['Content-Type']) {
options.header['Content-Type'] = 'application/json;charset=utf-8';
}
let commonHeader: Record<string, string | number> = {};
Request.globalHeaderProviders.forEach((func) => {
let headers = func();
for (const obj of Object.entries(headers)) {
commonHeader[obj[0]] = obj[1];
}
})
let userHeader = options.header as Record<string, string | number>
for (const obj1 of Object.entries(userHeader)) {
commonHeader[obj1[0]] = obj1[1];
}
options.header = commonHeader
let realUrl = Request.makeUrl(url, options);
Logger.info(TAG, `request realUrl: ${realUrl}`);
Logger.info(TAG, `header: ${realUrl}`);
return new Promise<T>((resolve, reject) => {
httpRequest.request(realUrl, Request.makeRequestOptions(options))
.then((responseData: http.HttpResponse) => {
try {
if (responseData.responseCode == http.ResponseCode.OK) {
// todo:待处理JSON.parse只解析目标class中指定的字段
// let response = JSON.parse(`${data}`) as ResponseDTO<T>
let response: T = JSON.parse(`${responseData.result}`)
resolve(response)
} else {
// 返回码不是ok
let responseError: BusinessError = {
code: responseData?.responseCode,
message: responseData?.result?.toString(),
name: '业务错误',
}
reject(responseError)
}
} catch (err) {
// json解析异常
let responseParseError: BusinessError = {
code: responseData?.responseCode,
message: responseData?.result?.toString(),
name: '解析异常',
}
reject(responseParseError)
}
})
.catch((error: BusinessError) => {
reject(error)
})
})
}
static get<T = ResponseDTO<string>>(url: string, options?: RequestOptions): Promise<T> {
let op = options ?? {}
op.method = RequestMethod.GET;
return Request.request<T>(url, op)
}
static post<T = ResponseDTO<string>>(url: string, options?: RequestOptions): Promise<T> {
let op = options ?? {}
op.method = RequestMethod.POST;
return Request.request<T>(url, op)
}
static put<T = ResponseDTO<string>>(url: string, options?: RequestOptions): Promise<T> {
let op = options ?? {}
op.method = RequestMethod.PUT;
return Request.request<T>(url, op)
}
static delete<T = ResponseDTO<string>>(url: string, options?: RequestOptions): Promise<T> {
let op = options ?? {}
op.method = RequestMethod.DELETE;
return Request.request<T>(url, op)
}
}
}
// import { ResponseLogin } from '../bean/account/ResponseLogin';
import { Logger } from 'wdKit';
// import { UserInfo } from '../bean/account/UserInfo';
// import { ConfigConstants } from '../constants/ConfigConstants';
// import { AccountManagerUtils } from './AccountManagerUtils';
// import { AppUtils } from './AppUtils';
// import { DeviceUtil } from './DeviceUtil';
// import { Logger } from './Logger';
// import { StringUtils } from './StringUtils';
const TAG: string = '[HttpUtils]'
export class HttpUtils {
static buildHeaders(): Record<string, string> {
let timestamp: number = new Date().getTime(); // 单位毫秒
// let clientId = DeviceUtil.clientId()
let headers: Record<string, string> = {};
// 通用请求头
headers["version"] = 'V3';
// headers["appId"] = ConfigConstants.appId; // 应用id
// headers["terminalId"] = ConfigConstants.terminalId; // 终端ID
// headers["sourceId"] = ConfigConstants.sourceId; // 咪咕视频
// headers["appType"] = ConfigConstants.appType; // 手机客户端App(安卓)
// headers["clientType"] = ConfigConstants.clientType; // 客户端类型
// headers["appVersion"] = AppUtils.getAppVersionCode() + ''; // 客户端版本号:2600010500
// headers["APP-VERSION-CODE"] = AppUtils.getAppVersionCode() + ''; // APP版本号:250006577
// headers["appVersionName"] = AppUtils.getAppVersionName() // app对外显示版本: '6.1.5.00'
// headers["appCode"] = ConfigConstants.appCode; // 应用编码:产品_渠道_应用的拼接串,用下划线_ 拼接而成
// headers["ptvCode"] = ConfigConstants.ptvCode; // 基线版本号_应用版本号 todo:
// headers["clientProvinceCode"] = ''; // 客户端分省号 // 02
// headers["provinceCode"] = ''; // 客户端分省号 // 02
// headers["clientCityId"] = ''; // 客户端城市ID // 0210
// headers["carrierCode"] = ''; // 运营商信息
// 设备信息请求头
// headers["User-Agent"] = ''; // 终端UA,自动获取
headers["Content-Type"] = 'application/json;charset=UTF-8'; // 返回/响应的HTTP内容类型
headers["os"] = 'harmony'; // 操作系统类型:鸿蒙、安卓或iOS
// 用户信息/登录信息请求头:登录完成之后二级接口返回,带入头信息;未登录情况下,头信息不传这些字段
headers["os"] = 'android'; // 操作系统类型:鸿蒙、安卓或iOS
// headers["osInfo"] = 'AD'; // 操作系统信息
headers["Phone-Info"] = 'HUAWEI'; // 手机信息: todo
// headers["oaid"] = ''; // 开放匿名设备ID,是中国移动安全联盟(MSA)发起并制定标准用户识别ID
headers["networkInfo"] = 'WIFI'; // 网络类型: todo
headers["cache-control"] = 'no-cache'; // 请求和响应遵循的缓存机制
// headers["clientId"] = clientId; // 客户端编号:客户端初始化时生成的客户端ID,保证唯一性
headers["imei"] = 'd1de6d3ae0db44bea1b3f0e20a14d90a'; // 终端手机序列号: todo
headers["X-UP-CLIENT-CHANNEL-ID"] = '2600010500-99000-101700010130012'; // 客户端渠道ID: todo
headers["channelCode"] = 'VIDEO_APPMAIL'; // 渠道编码
// headers["l_c"] = clientId; // 客户端id,同clientId
// headers["l_t"] = timestamp + ''; // 本机时间戳
// headers["l_s"] = ''; // l_c和l_t拼接后的MD5校验
// 签名相关请求头
headers["timeStamp"] = timestamp + ''; // 服务端时间戳(毫秒):1701667763664
headers["signType"] = 'RSA'; // 签名类型,固定RSA
// 业务请求头
// headers["promotionID"] = '54b0f421-a6df-41d3-9be2-92820b2c5d8c'; // 促销Id todo
// headers["tenantId"] = ''; // 租户Id
// 添加其他header
// Logger.info(TAG, "buildHeader headers:" + JSON.stringify(headers));
// headers["sdkCeId"] = '27fb3129-5a54-45bc-8af1-7dc8f1155501'; // 用户中台老接口定义的ID,保持不变,现网:咪咕视频Android版,27fb3129-5a54-45bc-8af1-7dc8f1155501 todo
headers["support-pendant"] = '1'; // 挂件标识, "1":客户端支持挂件节目结构;非"1":不支持挂件节目结构-展示通用对象
Logger.info(TAG, "buildHeader headers:" + JSON.stringify(headers));
return headers;
}
}
... ...