Showing
100 changed files
with
4082 additions
and
34 deletions
Too many changes to show.
To preserve performance only 100 of 100+ files are displayed.
| @@ -5,13 +5,13 @@ | @@ -5,13 +5,13 @@ | ||
| 5 | "name": "default", | 5 | "name": "default", |
| 6 | "type": "HarmonyOS", | 6 | "type": "HarmonyOS", |
| 7 | "material": { | 7 | "material": { |
| 8 | - "certpath": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.cer", | ||
| 9 | - "storePassword": "0000001A76406594DCD45689E6888037F1FA52EA0D15317DD495835E1F8D18BEF743FCEB51D881F01BA2", | 8 | + "certpath": "C:\\Users\\PC\\.ohos\\config\\default_sight_harmony_vDjosN2opayZneQDLiBs3Lc0sT1uPzRAYaDxxv2LWEQ=.cer", |
| 9 | + "storePassword": "0000001A87430EDC6C0D1CD6A6473A6D385177DBFF70325BBD48C7E491A0D9B37F91920FD46D82B2436B", | ||
| 10 | "keyAlias": "debugKey", | 10 | "keyAlias": "debugKey", |
| 11 | - "keyPassword": "0000001ACD3163BEAB09744DEA803A35F7B90073531926D60C13C3BA4F277C41CDB92A46819ED663CD31", | ||
| 12 | - "profile": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.p7b", | 11 | + "keyPassword": "0000001A8E615E1CB276AA122C291AFBCDFF792FEE8AA618B186EE7C99220C7F549B8C2ED6A209703D75", |
| 12 | + "profile": "C:\\Users\\PC\\.ohos\\config\\default_sight_harmony_vDjosN2opayZneQDLiBs3Lc0sT1uPzRAYaDxxv2LWEQ=.p7b", | ||
| 13 | "signAlg": "SHA256withECDSA", | 13 | "signAlg": "SHA256withECDSA", |
| 14 | - "storeFile": "C:\\Users\\PC\\.ohos\\config\\auto_debug_sight_harmony_com.wondertek.sight_70086000327424393.p12" | 14 | + "storeFile": "C:\\Users\\PC\\.ohos\\config\\default_sight_harmony_vDjosN2opayZneQDLiBs3Lc0sT1uPzRAYaDxxv2LWEQ=.p12" |
| 15 | } | 15 | } |
| 16 | } | 16 | } |
| 17 | ], | 17 | ], |
| @@ -35,8 +35,8 @@ | @@ -35,8 +35,8 @@ | ||
| 35 | }, | 35 | }, |
| 36 | "modules": [ | 36 | "modules": [ |
| 37 | { | 37 | { |
| 38 | - "name": "entry", | ||
| 39 | - "srcPath": "./entry", | 38 | + "name": "phone", |
| 39 | + "srcPath": "./products/phone", | ||
| 40 | "targets": [ | 40 | "targets": [ |
| 41 | { | 41 | { |
| 42 | "name": "default", | 42 | "name": "default", |
| @@ -48,7 +48,7 @@ | @@ -48,7 +48,7 @@ | ||
| 48 | }, | 48 | }, |
| 49 | { | 49 | { |
| 50 | "name": "wdConstant", | 50 | "name": "wdConstant", |
| 51 | - "srcPath": "./wdConstant", | 51 | + "srcPath": "./commons/wdConstant", |
| 52 | "targets": [ | 52 | "targets": [ |
| 53 | { | 53 | { |
| 54 | "name": "default", | 54 | "name": "default", |
| @@ -60,7 +60,7 @@ | @@ -60,7 +60,7 @@ | ||
| 60 | }, | 60 | }, |
| 61 | { | 61 | { |
| 62 | "name": "wdKit", | 62 | "name": "wdKit", |
| 63 | - "srcPath": "./wdKit", | 63 | + "srcPath": "./commons/wdKit", |
| 64 | "targets": [ | 64 | "targets": [ |
| 65 | { | 65 | { |
| 66 | "name": "default", | 66 | "name": "default", |
| @@ -72,7 +72,7 @@ | @@ -72,7 +72,7 @@ | ||
| 72 | }, | 72 | }, |
| 73 | { | 73 | { |
| 74 | "name": "wdBean", | 74 | "name": "wdBean", |
| 75 | - "srcPath": "./wdBean", | 75 | + "srcPath": "./features/wdBean", |
| 76 | "targets": [ | 76 | "targets": [ |
| 77 | { | 77 | { |
| 78 | "name": "default", | 78 | "name": "default", |
| @@ -84,7 +84,7 @@ | @@ -84,7 +84,7 @@ | ||
| 84 | }, | 84 | }, |
| 85 | { | 85 | { |
| 86 | "name": "wdComponent", | 86 | "name": "wdComponent", |
| 87 | - "srcPath": "./wdComponent", | 87 | + "srcPath": "./features/wdComponent", |
| 88 | "targets": [ | 88 | "targets": [ |
| 89 | { | 89 | { |
| 90 | "name": "default", | 90 | "name": "default", |
| @@ -96,7 +96,7 @@ | @@ -96,7 +96,7 @@ | ||
| 96 | }, | 96 | }, |
| 97 | { | 97 | { |
| 98 | "name": "wdNetwork", | 98 | "name": "wdNetwork", |
| 99 | - "srcPath": "./wdNetwork", | 99 | + "srcPath": "./commons/wdNetwork", |
| 100 | "targets": [ | 100 | "targets": [ |
| 101 | { | 101 | { |
| 102 | "name": "default", | 102 | "name": "default", |
| @@ -108,7 +108,7 @@ | @@ -108,7 +108,7 @@ | ||
| 108 | }, | 108 | }, |
| 109 | { | 109 | { |
| 110 | "name": "wdRouter", | 110 | "name": "wdRouter", |
| 111 | - "srcPath": "./wdRouter", | 111 | + "srcPath": "./commons/wdRouter", |
| 112 | "targets": [ | 112 | "targets": [ |
| 113 | { | 113 | { |
| 114 | "name": "default", | 114 | "name": "default", |
| @@ -120,11 +120,11 @@ | @@ -120,11 +120,11 @@ | ||
| 120 | }, | 120 | }, |
| 121 | { | 121 | { |
| 122 | "name": "wdJsBridge", | 122 | "name": "wdJsBridge", |
| 123 | - "srcPath": "./wdJsBridge" | 123 | + "srcPath": "./commons/wdJsBridge" |
| 124 | }, | 124 | }, |
| 125 | { | 125 | { |
| 126 | "name": "wdWebComponent", | 126 | "name": "wdWebComponent", |
| 127 | - "srcPath": "./wdWebComponent", | 127 | + "srcPath": "./commons/wdWebComponent", |
| 128 | "targets": [ | 128 | "targets": [ |
| 129 | { | 129 | { |
| 130 | "name": "default", | 130 | "name": "default", |
| @@ -148,7 +148,7 @@ | @@ -148,7 +148,7 @@ | ||
| 148 | // }, | 148 | // }, |
| 149 | { | 149 | { |
| 150 | "name": "wdPlayer", | 150 | "name": "wdPlayer", |
| 151 | - "srcPath": "./wdPlayer", | 151 | + "srcPath": "./features/wdPlayer", |
| 152 | "targets": [ | 152 | "targets": [ |
| 153 | { | 153 | { |
| 154 | "name": "default", | 154 | "name": "default", |
| @@ -160,7 +160,7 @@ | @@ -160,7 +160,7 @@ | ||
| 160 | }, | 160 | }, |
| 161 | { | 161 | { |
| 162 | "name": "wdDetailPlayApi", | 162 | "name": "wdDetailPlayApi", |
| 163 | - "srcPath": "./wdDetailPlayApi", | 163 | + "srcPath": "./features/wdDetailPlayApi", |
| 164 | "targets": [ | 164 | "targets": [ |
| 165 | { | 165 | { |
| 166 | "name": "default", | 166 | "name": "default", |
| @@ -172,7 +172,7 @@ | @@ -172,7 +172,7 @@ | ||
| 172 | }, | 172 | }, |
| 173 | { | 173 | { |
| 174 | "name": "wdDetailPlayShortVideo", | 174 | "name": "wdDetailPlayShortVideo", |
| 175 | - "srcPath": "./wdDetailPlayShortVideo", | 175 | + "srcPath": "./features/wdDetailPlayShortVideo", |
| 176 | "targets": [ | 176 | "targets": [ |
| 177 | { | 177 | { |
| 178 | "name": "default", | 178 | "name": "default", |
| @@ -184,7 +184,7 @@ | @@ -184,7 +184,7 @@ | ||
| 184 | }, | 184 | }, |
| 185 | { | 185 | { |
| 186 | "name": "wdDetailPlayVod", | 186 | "name": "wdDetailPlayVod", |
| 187 | - "srcPath": "./wdDetailPlayVod", | 187 | + "srcPath": "./features/wdDetailPlayVod", |
| 188 | "targets": [ | 188 | "targets": [ |
| 189 | { | 189 | { |
| 190 | "name": "default", | 190 | "name": "default", |
| @@ -196,7 +196,7 @@ | @@ -196,7 +196,7 @@ | ||
| 196 | }, | 196 | }, |
| 197 | { | 197 | { |
| 198 | "name": "wdDetailPlayLive", | 198 | "name": "wdDetailPlayLive", |
| 199 | - "srcPath": "./wdDetailPlayLive", | 199 | + "srcPath": "./features/wdDetailPlayLive", |
| 200 | "targets": [ | 200 | "targets": [ |
| 201 | { | 201 | { |
| 202 | "name": "default", | 202 | "name": "default", |
sight_harmony/commons/wdConstant/Index.ets
0 → 100644
| 1 | +export { CommonConstants } from './src/main/ets/constants/CommonConstants'; | ||
| 2 | + | ||
| 3 | +export { BreakpointConstants } from './src/main/ets/constants/BreakpointConstants'; | ||
| 4 | + | ||
| 5 | +export { ConfigConstants } from './src/main/ets/constants/ConfigConstants'; | ||
| 6 | + | ||
| 7 | +// enum | ||
| 8 | +export { BottomNavi } from './src/main/ets/enum/BottomNavi'; | ||
| 9 | + | ||
| 10 | +export { CompStyle } from './src/main/ets/enum/CompStyle'; | ||
| 11 | + | ||
| 12 | +export { CompType } from './src/main/ets/enum/CompType'; | ||
| 13 | + | ||
| 14 | +export { NetDataStatusType } from './src/main/ets/enum/NetDataStatusType'; | ||
| 15 | + | ||
| 16 | +export { ViewType } from './src/main/ets/enum/ViewType'; | ||
| 17 | + | ||
| 18 | +export { DurationEnum } from './src/main/ets/enum/DurationEnum'; | ||
| 19 | + | ||
| 20 | +export { ScreenType } from './src/main/ets/enum/ScreenType'; |
| 1 | +/** | ||
| 2 | + * Constants for breakpoint. | ||
| 3 | + */ | ||
| 4 | +export class BreakpointConstants { | ||
| 5 | + /** | ||
| 6 | + * Breakpoints that represent smaller device types. | ||
| 7 | + * 最小宽度 | ||
| 8 | + */ | ||
| 9 | + static readonly BREAKPOINT_XS: string = 'xs'; | ||
| 10 | + /** | ||
| 11 | + * Breakpoints that represent small device types. | ||
| 12 | + * 小宽度 | ||
| 13 | + */ | ||
| 14 | + static readonly BREAKPOINT_SM: string = 'sm'; | ||
| 15 | + /** | ||
| 16 | + * Breakpoints that represent middle device types. | ||
| 17 | + * 中等宽度 | ||
| 18 | + */ | ||
| 19 | + static readonly BREAKPOINT_MD: string = 'md'; | ||
| 20 | + /** | ||
| 21 | + * Breakpoints that represent large device types. | ||
| 22 | + * 大宽度 | ||
| 23 | + */ | ||
| 24 | + static readonly BREAKPOINT_LG: string = 'lg'; | ||
| 25 | + /** | ||
| 26 | + * Breakpoints that represent extra-large device types. | ||
| 27 | + * 特大宽度 | ||
| 28 | + */ | ||
| 29 | + // static readonly BREAKPOINT_XL: string = 'xl'; | ||
| 30 | + /** | ||
| 31 | + * Breakpoints that represent extra-extra-large device types. | ||
| 32 | + * 超大宽度 | ||
| 33 | + */ | ||
| 34 | + // static readonly BREAKPOINT_XXL: string = 'xxl'; | ||
| 35 | +} |
| 1 | +/** | ||
| 2 | + * The constant of Common. | ||
| 3 | + */ | ||
| 4 | +export class CommonConstants { | ||
| 5 | + // offset | ||
| 6 | + static readonly ZERO: number = 0; | ||
| 7 | + static readonly NO_INDEX: number = -1; | ||
| 8 | + static readonly NO_LENGTH: number = 0; | ||
| 9 | + | ||
| 10 | + /** | ||
| 11 | + * 布局相关. | ||
| 12 | + */ | ||
| 13 | + static readonly FULL_PARENT: string = '100%'; | ||
| 14 | + static readonly FULL_WIDTH: string = '100%'; | ||
| 15 | + static readonly FULL_HEIGHT: string = '100%'; | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * Component opacity value: 1. | ||
| 19 | + */ | ||
| 20 | + static readonly FULL_OPACITY: number = 1; | ||
| 21 | +} | ||
| 22 | +; | ||
| 23 | + |
| 1 | +/** | ||
| 2 | + * Config Constants. | ||
| 3 | + */ | ||
| 4 | +export class ConfigConstants { | ||
| 5 | + /** | ||
| 6 | + * 应用id/appId | ||
| 7 | + * | ||
| 8 | + */ | ||
| 9 | + static readonly appId: string = ""; | ||
| 10 | + /** | ||
| 11 | + * 终端id/terminalId | ||
| 12 | + * | ||
| 13 | + */ | ||
| 14 | + static readonly terminalId: string = "android"; | ||
| 15 | + /** | ||
| 16 | + * 36_渠道编码(sappType) | ||
| 17 | + * | ||
| 18 | + */ | ||
| 19 | + // static readonly appType: string = "2"; // wap | ||
| 20 | + static readonly appType: string = "3"; // 手机客户端App(安卓) | ||
| 21 | + | ||
| 22 | + static readonly clientType: string = ""; | ||
| 23 | + /** | ||
| 24 | + * SourceID | ||
| 25 | + * | ||
| 26 | + */ | ||
| 27 | + static readonly sourceId: string = ""; | ||
| 28 | + /** | ||
| 29 | + * 产品渠道应用对照关系: | ||
| 30 | + */ | ||
| 31 | + static readonly appCode: string = "83092caa603a421aa0222308b3f6b27a"; | ||
| 32 | + /** | ||
| 33 | + * 基线代码和客户端应用版本号规范 | ||
| 34 | + */ | ||
| 35 | + static readonly ptvCode: string = ""; | ||
| 36 | + /** | ||
| 37 | + * 省份code/province(02->上海) | ||
| 38 | + */ | ||
| 39 | + static readonly province: string = "02"; | ||
| 40 | + /** | ||
| 41 | + * 正在播放的节目ID | ||
| 42 | + */ | ||
| 43 | + static playingContentId?: string = undefined | ||
| 44 | + /** | ||
| 45 | + * 设备Id/deviceId | ||
| 46 | + * 设备Id或者能标识请求端的唯一标识 | ||
| 47 | + */ | ||
| 48 | + static readonly DEVICE_ID: string = "5bfed7be-0497-487f-990b-991e5b828a6e"; | ||
| 49 | + /** | ||
| 50 | + * base url VOD | ||
| 51 | + */ | ||
| 52 | + static readonly BASE_URL_VOD: string = ""; | ||
| 53 | + /** | ||
| 54 | + * base url Live | ||
| 55 | + */ | ||
| 56 | + static readonly BASE_URL_LIVE: string = ""; | ||
| 57 | + /** | ||
| 58 | + * 获取用户信息的服务器 | ||
| 59 | + */ | ||
| 60 | + static readonly BASE_URL: string = ""; | ||
| 61 | + /** | ||
| 62 | + * 内容列表路径 | ||
| 63 | + */ | ||
| 64 | + static readonly CONTENT_LIST_PATH: string = "/display/v4/static"; | ||
| 65 | + /** | ||
| 66 | + * 电视台(直播)列表路径 | ||
| 67 | + */ | ||
| 68 | + static readonly LIVE_TV_PATH: string = "/live/v2/tv-data"; | ||
| 69 | + /** | ||
| 70 | + * 临时的详情URL | ||
| 71 | + */ | ||
| 72 | + static readonly DETAIL_URL = "https://pd-people-uat.pdnews.cn/h/contentTop/110?hiddenTopNavigation=true" | ||
| 73 | +} |
| 1 | +/** | ||
| 2 | + * 常见图片宽/高比 | ||
| 3 | + */ | ||
| 4 | +export const enum AspectRatioEnum { | ||
| 5 | + // 常见纵向比例 | ||
| 6 | + ASPECT_RATIO_2_3 = 2 / 3, | ||
| 7 | + ASPECT_RATIO_3_4 = 3 / 4, | ||
| 8 | + ASPECT_RATIO_4_5 = 4 / 5, | ||
| 9 | + ASPECT_RATIO_5_7 = 5 / 7, | ||
| 10 | + ASPECT_RATIO_9_16 = 9 / 16, | ||
| 11 | + ASPECT_RATIO_10_16 = 10 / 16, | ||
| 12 | + ASPECT_RATIO_9_21 = 9 / 21, | ||
| 13 | + | ||
| 14 | + // 正方形 | ||
| 15 | + ASPECT_RATIO_1_1 = 1 / 1, | ||
| 16 | + | ||
| 17 | + // 常见横向比例 | ||
| 18 | + ASPECT_RATIO_7_5 = 7 / 5, | ||
| 19 | + ASPECT_RATIO_5_4 = 5 / 4, | ||
| 20 | + ASPECT_RATIO_4_3 = 4 / 3, | ||
| 21 | + ASPECT_RATIO_3_2 = 3 / 2, | ||
| 22 | + ASPECT_RATIO_16_10 = 16 / 10, | ||
| 23 | + ASPECT_RATIO_16_9 = 16 / 9, | ||
| 24 | + ASPECT_RATIO_21_9 = 21 / 9, | ||
| 25 | + | ||
| 26 | + // 其他常见比例 | ||
| 27 | + ASPECT_RATIO_2_1 = 2 / 1, // banner图宽高比 | ||
| 28 | + ASPECT_RATIO_1_2 = 1 / 2, | ||
| 29 | + ASPECT_RATIO_75_45 = 75 / 45, // 角标宽高比 | ||
| 30 | +} |
| 1 | +/** | ||
| 2 | + * 组件Style/展示样式 | ||
| 3 | + */ | ||
| 4 | +export const enum CompStyle { | ||
| 5 | + Label_03 = 'Label-03', // 标题卡:icon+文字 | ||
| 6 | + Carousel_Layout_01 = 'Zh_Carousel_Layout-01', // 通用轮播卡:视频、直播、活动、专题、榜单、外链 | ||
| 7 | + Carousel_Layout_02 = 'Carousel_Layout-02', // 直播轮播卡:直播 | ||
| 8 | + Single_Row_01 = 'Zh_Single_Row-01', // 三格方形小卡(排名):专题、活动 | ||
| 9 | + Zh_Single_Row_01 = 'Zh_Single_Row-01', // 横划卡 | ||
| 10 | + Single_Row_02 = 'Zh_Single_Row-02', // 通用横划卡:视频、直播、专题 | ||
| 11 | + Single_Row_03 = 'Single_Row-03', // 直播横划卡:直播 | ||
| 12 | + Single_Row_04 = 'Single_Row-04', // 三格方形小卡:专题、活动 | ||
| 13 | + Single_Row_05 = 'Single_Row-05', // 专题横划卡:视频、直播、专题、活动、榜单、外链 | ||
| 14 | + Single_Column_01 = 'Single_Column-01', // 大卡横屏视频:视频、直播 | ||
| 15 | + Single_Column_02 = 'Single_Column-02', // 活动卡:活动 | ||
| 16 | + Single_Column_03 = 'Single_Column-03', // 地域榜单:榜单 | ||
| 17 | + Single_Column_04 = 'Single_Column-04', // 大卡横屏(带背景):视频、直播 | ||
| 18 | + Single_Column_05 = 'Single_Column-05', // 海报图卡:/ | ||
| 19 | + Single_Column_06 = 'Single_Column-06', // 留言板卡:/ | ||
| 20 | + Zh_Single_Column_02 = 'Zh_Single_Column-02', // 头图卡 | ||
| 21 | + Grid_Layout_01 = 'Grid_Layout-01', // 横屏宫格卡:视频、直播 | ||
| 22 | + Grid_Layout_02 = 'Grid_Layout-02', // 竖屏宫格卡:视频、直播、榜单 | ||
| 23 | + Masonry_Layout_01 = 'Masonry_Layout-01', // 双列瀑布流/瀑布流卡:视频、直播、专题、活动 | ||
| 24 | + Title_Abbr_01 = '11', // 标题缩略 | ||
| 25 | + Title_All_01 = '3', // 全标题 | ||
| 26 | + Single_ImageCard_03 = '13',//单图卡:3行标题 | ||
| 27 | + Single_ImageCard_01 = '6',//单图卡,竖图 | ||
| 28 | + ZhGrid_Layout_03 = 'Zh_Grid_Layout-03', //金刚位卡 | ||
| 29 | + Album_Card_01 = '17' //图卡集 | ||
| 30 | +} |
| 1 | +/** | ||
| 2 | + * 组件Type/展示类型 | ||
| 3 | + */ | ||
| 4 | +export const enum CompType { | ||
| 5 | + LABEL = 'LABEL', // 标题组件 | ||
| 6 | + CAROUSEL_LAYOUT = 'CAROUSEL_LAYOUT', // 轮播组件,即Banner/焦点图 | ||
| 7 | + SINGLE_ROW = 'SINGLE_ROW', // 单行组件 | ||
| 8 | + SINGLE_COLUMN = 'SINGLE_COLUMN', // 单列组件 | ||
| 9 | + GRID_LAYOUT = 'GRID_LAYOUT', // 网格组件 | ||
| 10 | + MASONRY_LAYOUT = 'MASONRY_LAYOUT', // 瀑布流组件 | ||
| 11 | +} |
| 1 | +/** | ||
| 2 | + * 时间跨度/延时枚举常量值 | ||
| 3 | + * duration/delay/interval | ||
| 4 | + */ | ||
| 5 | +export const enum DurationEnum { | ||
| 6 | + DURATION_MS_50 = 50, // 50毫秒 | ||
| 7 | + DURATION_MS_100 = 100, // 50毫秒 | ||
| 8 | + DURATION_MS_1000 = 1000, // 1秒/1000ms | ||
| 9 | + DURATION_MS_1500 = 1500, // 1.5秒 | ||
| 10 | + DURATION_1 = 1000, // 1秒 | ||
| 11 | + DURATION_2 = 2000, // 2秒 | ||
| 12 | + DURATION_3 = 3000, // 3秒 | ||
| 13 | + DURATION_4 = 4000, // 4秒 | ||
| 14 | +} |
| 1 | +/** | ||
| 2 | + * view展示种类 | ||
| 3 | + */ | ||
| 4 | +export const enum ViewType { | ||
| 5 | + // 已初始化,但尚未发出请求 | ||
| 6 | + INITIAL = 0, | ||
| 7 | + // 加载中:已发出请求,但请求尚未返回; | ||
| 8 | + LOADING, | ||
| 9 | + // 数据加载失败(重试)/failure | ||
| 10 | + ERROR, | ||
| 11 | + // 结果为空/无数据/空view | ||
| 12 | + EMPTY, | ||
| 13 | + // 已加载结束/非失败/非空/可以是仅一页数据,即楼层数据列表PAGE_GROUP_LIST/ | ||
| 14 | + LOADED, | ||
| 15 | + // 已加载的是tab导航数据(可嵌套page的楼层列表) | ||
| 16 | + NAV_BAR | ||
| 17 | +} |
sight_harmony/entry/src/test/List.test.ets
→
sight_harmony/commons/wdConstant/src/test/List.test.ets
sight_harmony/commons/wdJsBridge/Index.ets
0 → 100644
sight_harmony/wdComponent/build-profile.json5
→
sight_harmony/commons/wdJsBridge/build-profile.json5
| 1 | +import { StringUtils } from '../utils/StringUtils'; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 消息Message | ||
| 5 | + */ | ||
| 6 | +export class CallBackMessage { | ||
| 7 | + callbackId: string = ""; //callbackId | ||
| 8 | + responseId: string = ""; //responseId | ||
| 9 | + responseData: string = ""; //responseData | ||
| 10 | + data?: string; //data of message | ||
| 11 | + handlerName: string = ""; //name of handler | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * TODO 待验证 | ||
| 15 | + * @returns | ||
| 16 | + */ | ||
| 17 | + toJson(): string { | ||
| 18 | + let cloneObject:object = JSON.parse(JSON.stringify(this)) | ||
| 19 | + return StringUtils.escapeDoubleQuotes(JSON.stringify(cloneObject)) | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * TODO 待验证 | ||
| 24 | + * @param jsonStr | ||
| 25 | + * @returns | ||
| 26 | + */ | ||
| 27 | + toList(jsonStr: string): Array<CallBackMessage> { | ||
| 28 | + return JSON.parse(jsonStr) | ||
| 29 | + } | ||
| 30 | +} |
| 1 | +import { Action } from './Action'; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 消息Message | ||
| 5 | + */ | ||
| 6 | +export class Message { | ||
| 7 | + callbackId: string = ""; //callbackId | ||
| 8 | + responseId: string = ""; //responseId | ||
| 9 | + responseData: string = ""; //responseData | ||
| 10 | + data?: Action; //data of message | ||
| 11 | + handlerName: string = ""; //name of handler | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * TODO 待验证 | ||
| 15 | + * @returns | ||
| 16 | + */ | ||
| 17 | + toJson(): string { | ||
| 18 | + let jsonString: string = JSON.stringify(this) | ||
| 19 | + return jsonString | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * TODO 待验证 | ||
| 24 | + * @param jsonStr | ||
| 25 | + * @returns | ||
| 26 | + */ | ||
| 27 | + toList(jsonStr: string): Array<Message> { | ||
| 28 | + return JSON.parse(jsonStr) | ||
| 29 | + } | ||
| 30 | +} |
| 1 | +import { Action } from '../bean/Action' | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 注册回调接口 | ||
| 5 | + */ | ||
| 6 | +export type Callback = (data: string) => void | ||
| 7 | + | ||
| 8 | +export interface BridgeHandler { | ||
| 9 | + handle: (data: Action, f: Callback) => void | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +export class DefaultBridgeHandler implements BridgeHandler { | ||
| 13 | + handle(data: Action, f: Callback) { | ||
| 14 | + //1,2.3 | ||
| 15 | + f("DefaultHandler response data") | ||
| 16 | + } | ||
| 17 | +} |
| 1 | +import webview from '@ohos.web.webview'; | ||
| 2 | +import HashMap from '@ohos.util.HashMap'; | ||
| 3 | +import { BridgeHandler, DefaultBridgeHandler, Callback } from './BridgeHandler'; | ||
| 4 | +import { BridgeUtil } from '../utils/BridgeUtil'; | ||
| 5 | +import { Message } from '../bean/Message'; | ||
| 6 | +import { CallBackMessage } from '../bean/CallBackMessage'; | ||
| 7 | +import { StringUtils } from '../utils/StringUtils'; | ||
| 8 | + | ||
| 9 | +const TAG = 'BridgeWebViewControl'; | ||
| 10 | + | ||
| 11 | +export class BridgeWebViewControl extends webview.WebviewController { | ||
| 12 | + /** | ||
| 13 | + * | ||
| 14 | + */ | ||
| 15 | + private responseCallbacks: HashMap<string, Callback> = new HashMap<string, Callback>() | ||
| 16 | + /** | ||
| 17 | + * | ||
| 18 | + */ | ||
| 19 | + private messageHandlers: HashMap<string, BridgeHandler> = new HashMap() | ||
| 20 | + /** | ||
| 21 | + * 页面加载前,不能处理消息 | ||
| 22 | + */ | ||
| 23 | + private uniqueId = 0; | ||
| 24 | + | ||
| 25 | + registerHandler(handlerName: string, handler: BridgeHandler) { | ||
| 26 | + if (handler != null) { | ||
| 27 | + this.messageHandlers.set(handlerName, handler) | ||
| 28 | + } | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + unregisterHandler(handlerName: string) { | ||
| 32 | + if (handlerName != null) { | ||
| 33 | + this.messageHandlers.remove(handlerName); | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * @param url | ||
| 39 | + * @param returnCallback | ||
| 40 | + */ | ||
| 41 | + loadUrlCustom(url: string, returnCallback: Callback) { | ||
| 42 | + this.loadUrl(url) | ||
| 43 | + this.responseCallbacks.set(BridgeUtil.parseFunctionName(url), returnCallback); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 刷新消息 | ||
| 48 | + */ | ||
| 49 | + flushMessageQueue() { | ||
| 50 | + this.loadUrlCustom(BridgeUtil.JS_FETCH_QUEUE_FROM_JAVA, (data: string) => { | ||
| 51 | + let list: Array<Message> = JSON.parse(data) | ||
| 52 | + if (list == null || list.length == 0) { | ||
| 53 | + return | ||
| 54 | + } | ||
| 55 | + list.forEach(value => { | ||
| 56 | + let responseId: string = value.responseId | ||
| 57 | + // 是否是response CallBackFunction,收到消息, | ||
| 58 | + if (StringUtils.isNotEmpty(responseId)) { | ||
| 59 | + let call: Callback = this.responseCallbacks.get(responseId) | ||
| 60 | + let responseData: string = value.responseData; | ||
| 61 | + if (StringUtils.isEmpty(responseData) || call === undefined) { | ||
| 62 | + return | ||
| 63 | + } | ||
| 64 | + call(responseData) | ||
| 65 | + this.responseCallbacks.remove(responseId) | ||
| 66 | + } else { | ||
| 67 | + let responseFunction: Callback; | ||
| 68 | + let callbackId: string = value.callbackId | ||
| 69 | + if (StringUtils.isNotEmpty(callbackId)) { | ||
| 70 | + responseFunction = (data: string) => { | ||
| 71 | + let msg: CallBackMessage = new CallBackMessage() | ||
| 72 | + msg.responseId = callbackId | ||
| 73 | + msg.responseData = data | ||
| 74 | + this.queueMessage(msg) | ||
| 75 | + } | ||
| 76 | + } else { | ||
| 77 | + responseFunction = (data: string) => { | ||
| 78 | + //TODO 更换log输出方式 | ||
| 79 | + // Logger.info(TAG, `default response:: ${data}`); | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | + let handle: BridgeHandler | ||
| 83 | + if (StringUtils.isNotEmpty(value.handlerName)) { | ||
| 84 | + handle = this.messageHandlers.get(value.handlerName) | ||
| 85 | + } else { | ||
| 86 | + handle = new DefaultBridgeHandler() | ||
| 87 | + } | ||
| 88 | + if (handle != undefined && value.data != undefined) { | ||
| 89 | + handle.handle(value.data, responseFunction) | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + }) | ||
| 93 | + | ||
| 94 | + }) | ||
| 95 | + | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + private queueMessage(msg: CallBackMessage) { | ||
| 99 | + // //TODO | ||
| 100 | + this.dispatchMessage(msg); | ||
| 101 | + // } | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + /** | ||
| 105 | + * 消息分发,最终执行js方法 | ||
| 106 | + * @param msg | ||
| 107 | + */ | ||
| 108 | + private dispatchMessage(msg: CallBackMessage) { | ||
| 109 | + let messageJson: string = msg.toJson() | ||
| 110 | + // messageJson = messageJson.replace("%7B", encodeURIComponent("%7B")); | ||
| 111 | + // messageJson = messageJson.replace("%7D", encodeURIComponent("%7D")); | ||
| 112 | + // messageJson = messageJson.replace("%22", encodeURIComponent("%22")); | ||
| 113 | + | ||
| 114 | + let javascriptCommand: string = StringUtils.formatStringForJS(BridgeUtil.JS_HANDLE_MESSAGE_FROM_JAVA, messageJson); | ||
| 115 | + this.runJavaScript(javascriptCommand) | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + /** | ||
| 119 | + * native 主动调用JSBridge方法 | ||
| 120 | + * @param msg | ||
| 121 | + */ | ||
| 122 | + callHandle(handlerName: string, data: string, callBack: Callback) { | ||
| 123 | + this.doSend(handlerName, data, callBack) | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + private doSend(handlerName: string, data: string, callBack: Callback) { | ||
| 127 | + let msg: CallBackMessage = new CallBackMessage() | ||
| 128 | + if (StringUtils.isNotEmpty(data)) { | ||
| 129 | + msg.data = data | ||
| 130 | + } | ||
| 131 | + if (StringUtils.isNotEmpty(handlerName)) { | ||
| 132 | + msg.handlerName = handlerName | ||
| 133 | + } | ||
| 134 | + if (callBack != undefined) { | ||
| 135 | + let callbackId: string = StringUtils.formatStringForJS(BridgeUtil.CALLBACK_ID_FORMAT, ++this.uniqueId + (BridgeUtil.UNDERLINE_STR + new Date().getTime())); | ||
| 136 | + this.responseCallbacks.set(callbackId, callBack) | ||
| 137 | + msg.callbackId = callbackId | ||
| 138 | + } | ||
| 139 | + this.queueMessage(msg); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + handlerReturnData(url: string) { | ||
| 143 | + let functionName: string = BridgeUtil.getFunctionFromReturnUrl(url); | ||
| 144 | + let callback = this.responseCallbacks.get(functionName); | ||
| 145 | + let data: string = BridgeUtil.getDataFromReturnUrl(url); | ||
| 146 | + if (callback != undefined) { | ||
| 147 | + callback(data) | ||
| 148 | + this.responseCallbacks.remove(functionName) | ||
| 149 | + } | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + //TODO | ||
| 153 | + clean() { | ||
| 154 | + this.responseCallbacks.clear() | ||
| 155 | + this.messageHandlers.clear() | ||
| 156 | + this.uniqueId = 0 | ||
| 157 | + } | ||
| 158 | +} | ||
| 159 | + | ||
| 160 | + | ||
| 161 | + |
| 1 | +import webview from '@ohos.web.webview'; | ||
| 2 | +import { ResourceManager } from './ResourceManager'; | ||
| 3 | + | ||
| 4 | +export class BridgeUtil { | ||
| 5 | + static readonly YY_OVERRIDE_SCHEMA = "yy://"; | ||
| 6 | + static readonly YY_RETURN_DATA = BridgeUtil.YY_OVERRIDE_SCHEMA + "return/"; | ||
| 7 | + static readonly YY_FETCH_QUEUE = BridgeUtil.YY_RETURN_DATA + "_fetchQueue/"; | ||
| 8 | + static readonly EMPTY_STR = ""; | ||
| 9 | + static readonly UNDERLINE_STR = "_"; | ||
| 10 | + static readonly SPLIT_MARK = "/"; | ||
| 11 | + static readonly CALLBACK_ID_FORMAT = "JAVA_CB_%s"; | ||
| 12 | + static readonly JS_HANDLE_MESSAGE_FROM_JAVA = "javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');"; | ||
| 13 | + static readonly JS_FETCH_QUEUE_FROM_JAVA = "javascript:WebViewJavascriptBridge._fetchQueue();"; | ||
| 14 | + static readonly JAVASCRIPT_STR = "javascript:"; | ||
| 15 | + | ||
| 16 | + // 例子 javascript:WebViewJavascriptBridge._fetchQueue(); --> _fetchQueue | ||
| 17 | + static parseFunctionName(jsUrl: string): string { | ||
| 18 | + return jsUrl.replace("javascript:WebViewJavascriptBridge.", "").replace("();", ""); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + static getDataFromReturnUrl(url: string): string { | ||
| 22 | + if (url.startsWith(BridgeUtil.YY_FETCH_QUEUE)) { | ||
| 23 | + // return = [{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] | ||
| 24 | + return url.replace(BridgeUtil.YY_FETCH_QUEUE, BridgeUtil.EMPTY_STR); | ||
| 25 | + } | ||
| 26 | + // temp = _fetchQueue/[{"responseId":"JAVA_CB_2_3957","responseData":"Javascript Says Right back aka!"}] | ||
| 27 | + let temp = url.replace(BridgeUtil.YY_RETURN_DATA, BridgeUtil.EMPTY_STR); | ||
| 28 | + let functionAndData = temp.split(BridgeUtil.SPLIT_MARK); | ||
| 29 | + if (functionAndData.length < 2) { | ||
| 30 | + return "" | ||
| 31 | + } | ||
| 32 | + let result = "" | ||
| 33 | + functionAndData.forEach((value) => { | ||
| 34 | + result = result + value | ||
| 35 | + }); | ||
| 36 | + return result | ||
| 37 | + | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * TODO | ||
| 42 | + */ | ||
| 43 | + static releaseWebView() { | ||
| 44 | + | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + // 获取到传递信息的方法 | ||
| 48 | + // url = yy://return/_fetchQueue/[{"responseId":"JAVA_CB_1_360","responseData":"Javascript Says Right back aka!"}] | ||
| 49 | + static getFunctionFromReturnUrl(url: string): string { | ||
| 50 | + let temp = url.replace(BridgeUtil.YY_RETURN_DATA, BridgeUtil.EMPTY_STR); | ||
| 51 | + let functionAndData = temp.split(BridgeUtil.SPLIT_MARK); | ||
| 52 | + if (functionAndData.length >= 1) { | ||
| 53 | + // functionAndData[0] = _fetchQueue | ||
| 54 | + return functionAndData[0]; | ||
| 55 | + } | ||
| 56 | + return "" | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * 这里只是加载lib包中assets中的 WebViewJavascriptBridge.js | ||
| 61 | + * @param controller | ||
| 62 | + * @param path 路径 | ||
| 63 | + */ | ||
| 64 | + static webViewLoadLocalJs(context: Context, controller: webview.WebviewController) { | ||
| 65 | + ResourceManager.getResourcesText(context, "WebViewJavascriptBridge.js").then((str) => { | ||
| 66 | + //执行js注入 | ||
| 67 | + controller.runJavaScriptExt('javascript:' + str).then((msg) => { | ||
| 68 | + console.log("Js注入结果:" + msg.getString()); | ||
| 69 | + }) | ||
| 70 | + }) | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | +} |
| 1 | +import buffer from '@ohos.buffer'; | ||
| 2 | + | ||
| 3 | +export class ResourceManager { | ||
| 4 | + /** | ||
| 5 | + * 获取资源字符串内容 | ||
| 6 | + * @param context | ||
| 7 | + * @param filename | ||
| 8 | + * @returns | ||
| 9 | + */ | ||
| 10 | + static getResourcesText(context: Context, filename: string): Promise<string> { | ||
| 11 | + return new Promise<string>((success, error) => { | ||
| 12 | + context.resourceManager.getRawFileContent(filename).then((content: Uint8Array) => { | ||
| 13 | + if (!content) { | ||
| 14 | + error("file is empty"); | ||
| 15 | + return | ||
| 16 | + } | ||
| 17 | + let result = buffer.from(content).toString("utf8"); | ||
| 18 | + if (result) { | ||
| 19 | + success(result); | ||
| 20 | + } else { | ||
| 21 | + error("parse resources file result is empty"); | ||
| 22 | + } | ||
| 23 | + }).catch((err: Error) => { | ||
| 24 | + error(err); | ||
| 25 | + }) | ||
| 26 | + }) | ||
| 27 | + } | ||
| 28 | +} |
| 1 | +/** | ||
| 2 | + * StringUtils class. | ||
| 3 | + */ | ||
| 4 | +export class StringUtils { | ||
| 5 | + | ||
| 6 | + /** | ||
| 7 | + * Check obj is not empty. | ||
| 8 | + * | ||
| 9 | + * @param {object} obj | ||
| 10 | + * @return {boolean} true(not empty) | ||
| 11 | + */ | ||
| 12 | + static isNotEmpty(obj: any): boolean { | ||
| 13 | + // return (obj && obj !== ''); | ||
| 14 | + // 或 | ||
| 15 | + return (obj !== undefined && obj !== null && obj !== ''); | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + static isEmpty(...params: any): boolean { | ||
| 20 | + if (params.length === 0) { | ||
| 21 | + return true; | ||
| 22 | + } | ||
| 23 | + for (const param of params) { | ||
| 24 | + if (!param) { // param === undefined || param === null || param === ''; | ||
| 25 | + return true; | ||
| 26 | + } | ||
| 27 | + } | ||
| 28 | + return false; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + static formatStringForJS(template: string, ...args: any[]): string { | ||
| 33 | + let formattedString = template; | ||
| 34 | + for (const arg of args) { | ||
| 35 | + formattedString = formattedString.replace(/%s/, arg.toString()); | ||
| 36 | + } | ||
| 37 | + return formattedString; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + static escapeDoubleQuotes(obj:any): any { | ||
| 42 | + if (typeof obj === 'string') { | ||
| 43 | + return obj.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); | ||
| 44 | + } else if (typeof obj === 'object') { | ||
| 45 | + for (let key in obj) { | ||
| 46 | + if (obj.hasOwnProperty(key)) { | ||
| 47 | + obj[key] = StringUtils.escapeDoubleQuotes(obj[key]); | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | + } | ||
| 51 | + return obj; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | +} | ||
| 55 | +// export default new StringUtils(); |
sight_harmony/commons/wdJsBridge/src/main/resources/rawfile/rawfile/WebViewJavascriptBridge.js
0 → 100644
| 1 | +//notation: js file can only use this kind of comments | ||
| 2 | +//since comments will cause error when use in webview.loadurl, | ||
| 3 | +//comments will be remove by java use regexp | ||
| 4 | +(function() { | ||
| 5 | + if (window.WebViewJavascriptBridge) { | ||
| 6 | + return; | ||
| 7 | + } | ||
| 8 | + | ||
| 9 | + var messagingIframe; | ||
| 10 | + var bizMessagingIframe; | ||
| 11 | + var sendMessageQueue = []; | ||
| 12 | + var receiveMessageQueue = []; | ||
| 13 | + var messageHandlers = {}; | ||
| 14 | + | ||
| 15 | + var CUSTOM_PROTOCOL_SCHEME = 'yy'; | ||
| 16 | + var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/'; | ||
| 17 | + | ||
| 18 | + var responseCallbacks = {}; | ||
| 19 | + var uniqueId = 1; | ||
| 20 | + | ||
| 21 | + // 创建消息index队列iframe | ||
| 22 | + function _createQueueReadyIframe(doc) { | ||
| 23 | + messagingIframe = doc.createElement('iframe'); | ||
| 24 | + messagingIframe.style.display = 'none'; | ||
| 25 | + doc.documentElement.appendChild(messagingIframe); | ||
| 26 | + } | ||
| 27 | + //创建消息体队列iframe | ||
| 28 | + function _createQueueReadyIframe4biz(doc) { | ||
| 29 | + bizMessagingIframe = doc.createElement('iframe'); | ||
| 30 | + bizMessagingIframe.style.display = 'none'; | ||
| 31 | + doc.documentElement.appendChild(bizMessagingIframe); | ||
| 32 | + } | ||
| 33 | + //set default messageHandler 初始化默认的消息线程 | ||
| 34 | + function init(messageHandler) { | ||
| 35 | + if (WebViewJavascriptBridge._messageHandler) { | ||
| 36 | + throw new Error('WebViewJavascriptBridge.init called twice'); | ||
| 37 | + } | ||
| 38 | + WebViewJavascriptBridge._messageHandler = messageHandler; | ||
| 39 | + var receivedMessages = receiveMessageQueue; | ||
| 40 | + receiveMessageQueue = null; | ||
| 41 | + for (var i = 0; i < receivedMessages.length; i++) { | ||
| 42 | + _dispatchMessageFromNative(receivedMessages[i]); | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + // 发送 | ||
| 47 | + function send(data, responseCallback) { | ||
| 48 | + _doSend({ | ||
| 49 | + data: data | ||
| 50 | + }, responseCallback); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + // 注册线程 往数组里面添加值 | ||
| 54 | + function registerHandler(handlerName, handler) { | ||
| 55 | + messageHandlers[handlerName] = handler; | ||
| 56 | + } | ||
| 57 | + // 调用线程 | ||
| 58 | + function callHandler(handlerName, data, responseCallback) { | ||
| 59 | + _doSend({ | ||
| 60 | + handlerName: handlerName, | ||
| 61 | + data: data | ||
| 62 | + }, responseCallback); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + //sendMessage add message, 触发native处理 sendMessage | ||
| 66 | + function _doSend(message, responseCallback) { | ||
| 67 | + if (responseCallback) { | ||
| 68 | + var callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime(); | ||
| 69 | + responseCallbacks[callbackId] = responseCallback; | ||
| 70 | + message.callbackId = callbackId; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + sendMessageQueue.push(message); | ||
| 74 | + messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + // 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容 | ||
| 78 | + function _fetchQueue() { | ||
| 79 | + var messageQueueString = JSON.stringify(sendMessageQueue); | ||
| 80 | + sendMessageQueue = []; | ||
| 81 | + //android can't read directly the return data, so we can reload iframe src to communicate with java | ||
| 82 | + if (messageQueueString !== '[]') { | ||
| 83 | + bizMessagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString); | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + //提供给native使用, | ||
| 88 | + function _dispatchMessageFromNative(messageJSON) { | ||
| 89 | + setTimeout(function() { | ||
| 90 | + var message = JSON.parse(messageJSON); | ||
| 91 | + var responseCallback; | ||
| 92 | + //java call finished, now need to call js callback function | ||
| 93 | + if (message.responseId) { | ||
| 94 | + responseCallback = responseCallbacks[message.responseId]; | ||
| 95 | + if (!responseCallback) { | ||
| 96 | + return; | ||
| 97 | + } | ||
| 98 | + responseCallback(message.responseData); | ||
| 99 | + delete responseCallbacks[message.responseId]; | ||
| 100 | + } else { | ||
| 101 | + //直接发送 | ||
| 102 | + if (message.callbackId) { | ||
| 103 | + var callbackResponseId = message.callbackId; | ||
| 104 | + responseCallback = function(responseData) { | ||
| 105 | + _doSend({ | ||
| 106 | + responseId: callbackResponseId, | ||
| 107 | + responseData: responseData | ||
| 108 | + }); | ||
| 109 | + }; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + var handler = WebViewJavascriptBridge._messageHandler; | ||
| 113 | + if (message.handlerName) { | ||
| 114 | + handler = messageHandlers[message.handlerName]; | ||
| 115 | + } | ||
| 116 | + //查找指定handler | ||
| 117 | + try { | ||
| 118 | + handler(message.data, responseCallback); | ||
| 119 | + } catch (exception) { | ||
| 120 | + if (typeof console != 'undefined') { | ||
| 121 | + console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception); | ||
| 122 | + } | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | + }); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + //提供给native调用,receiveMessageQueue 在会在页面加载完后赋值为null,所以 | ||
| 129 | + function _handleMessageFromNative(messageJSON) { | ||
| 130 | + //console.log(messageJSON); | ||
| 131 | + if (receiveMessageQueue) { | ||
| 132 | + receiveMessageQueue.push(messageJSON); | ||
| 133 | + } | ||
| 134 | + _dispatchMessageFromNative(messageJSON); | ||
| 135 | + | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + var WebViewJavascriptBridge = window.WebViewJavascriptBridge = { | ||
| 139 | + init: init, | ||
| 140 | + send: send, | ||
| 141 | + registerHandler: registerHandler, | ||
| 142 | + callHandler: callHandler, | ||
| 143 | + _fetchQueue: _fetchQueue, | ||
| 144 | + _handleMessageFromNative: _handleMessageFromNative | ||
| 145 | + }; | ||
| 146 | + | ||
| 147 | + var doc = document; | ||
| 148 | + _createQueueReadyIframe(doc); | ||
| 149 | + _createQueueReadyIframe4biz(doc); | ||
| 150 | + var readyEvent = doc.createEvent('Events'); | ||
| 151 | + readyEvent.initEvent('WebViewJavascriptBridgeReady'); | ||
| 152 | + readyEvent.bridge = WebViewJavascriptBridge; | ||
| 153 | + doc.dispatchEvent(readyEvent); | ||
| 154 | +})(); |
sight_harmony/commons/wdKit/.gitignore
0 → 100644
sight_harmony/commons/wdKit/Index.ets
0 → 100644
| 1 | +export { Logger } from './src/main/ets/utils/Logger' | ||
| 2 | + | ||
| 3 | +export { ResourcesUtils } from './src/main/ets/utils/ResourcesUtils' | ||
| 4 | + | ||
| 5 | +export { StringUtils } from './src/main/ets/utils/StringUtils' | ||
| 6 | + | ||
| 7 | +export { AppUtils } from './src/main/ets/utils/AppUtils'; | ||
| 8 | + | ||
| 9 | +export { BasicDataSource } from './src/main/ets/utils/BasicDataSource'; | ||
| 10 | + | ||
| 11 | +export { LazyDataSource } from './src/main/ets/utils/LazyDataSource' | ||
| 12 | + | ||
| 13 | +export { BreakpointSystem, BreakPointType } from './src/main/ets/utils/BreakPointSystem'; | ||
| 14 | + | ||
| 15 | +export { ToastUtils } from './src/main/ets/utils/ToastUtils'; | ||
| 16 | + | ||
| 17 | +export { WindowModel } from './src/main/ets/utils/WindowModel' | ||
| 18 | + | ||
| 19 | +export { SPHelper } from './src/main/ets/utils/SPHelper' | ||
| 20 | + | ||
| 21 | +export { AccountManagerUtils } from './src/main/ets/utils/AccountManagerUtils' | ||
| 22 | + | ||
| 23 | +export { CollectionUtils } from './src/main/ets/utils/CollectionUtils' | ||
| 24 | + | ||
| 25 | +export { DateTimeUtils } from './src/main/ets/utils/DateTimeUtils' | ||
| 26 | + | ||
| 27 | +export { DeviceUtil } from './src/main/ets/utils/DeviceUtil' | ||
| 28 | + | ||
| 29 | +export { DisplayUtils } from './src/main/ets/utils/DisplayUtils' | ||
| 30 | + | ||
| 31 | +export { SystemUtils } from './src/main/ets/utils/SystemUtils' |
| 1 | +{ | ||
| 2 | + "apiType": "stageMode", | ||
| 3 | + "buildOption": { | ||
| 4 | + "arkOptions": { | ||
| 5 | + // "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */ | ||
| 6 | + } | ||
| 7 | + }, | ||
| 8 | + "buildOptionSet": [ | ||
| 9 | + { | ||
| 10 | + "name": "release", | ||
| 11 | + "arkOptions": { | ||
| 12 | + "obfuscation": { | ||
| 13 | + "ruleOptions": { | ||
| 14 | + "enable": true, | ||
| 15 | + "files": [ | ||
| 16 | + "./obfuscation-rules.txt" | ||
| 17 | + ] | ||
| 18 | + } | ||
| 19 | + } | ||
| 20 | + } | ||
| 21 | + }, | ||
| 22 | + ], | ||
| 23 | + "targets": [ | ||
| 24 | + { | ||
| 25 | + "name": "default" | ||
| 26 | + } | ||
| 27 | + ] | ||
| 28 | +} |
sight_harmony/commons/wdKit/oh-package.json5
0 → 100644
| 1 | +import { StringUtils } from './StringUtils'; | ||
| 2 | +import { SPHelper } from './SPHelper'; | ||
| 3 | +import { Logger } from './Logger'; | ||
| 4 | + | ||
| 5 | +const KEY_USER_TOKEN = 'userToken'; | ||
| 6 | + | ||
| 7 | +const TAG: string = 'AccountManagerUtils'; | ||
| 8 | + | ||
| 9 | +// 是否已登录hadLogin | ||
| 10 | +let hasLogin: boolean = false; | ||
| 11 | + | ||
| 12 | +export class AccountManagerUtils { | ||
| 13 | + // 是否已登录hadLogin | ||
| 14 | + // private static hasLogin: boolean = undefined; | ||
| 15 | + | ||
| 16 | + constructor() { | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + static async getUserToken(): Promise<string> { | ||
| 20 | + let userToken = await SPHelper.default.get(KEY_USER_TOKEN, '') as string; | ||
| 21 | + // Logger.info(TAG, 'getUserToken UserToken.' + userToken); | ||
| 22 | + return userToken; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + static getUserTokenSync(): string { | ||
| 26 | + let userToken = SPHelper.default.getSync(KEY_USER_TOKEN, '') as string; | ||
| 27 | + // Logger.info(TAG, 'getUserToken UserToken.' + userToken); | ||
| 28 | + return userToken; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + static async putUserToken(value: string) { | ||
| 32 | + await SPHelper.default.save(KEY_USER_TOKEN, value); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + static putUserTokenSync(value: string) { | ||
| 36 | + SPHelper.default.saveSync(KEY_USER_TOKEN, value); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + static async deleteUserToken() { | ||
| 40 | + await SPHelper.default.delete(KEY_USER_TOKEN); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + static deleteUserTokenSync() { | ||
| 44 | + SPHelper.default.deleteSync(KEY_USER_TOKEN); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * 是否已登录 | ||
| 49 | + * @param folder | ||
| 50 | + * @param files | ||
| 51 | + */ | ||
| 52 | + static async isLogin() { | ||
| 53 | + Logger.info(TAG, 'isLogin hasLogin1:' + hasLogin); | ||
| 54 | + let lastUserToken = await AccountManagerUtils.getUserToken() | ||
| 55 | + Logger.info(TAG, 'isLogin lastUserToken:' + lastUserToken); | ||
| 56 | + if (StringUtils.isEmpty(lastUserToken)) { | ||
| 57 | + hasLogin = false; | ||
| 58 | + Logger.info(TAG, "isLogin lastUserToken is empty"); | ||
| 59 | + } else { | ||
| 60 | + hasLogin = true; | ||
| 61 | + Logger.info(TAG, "isLogin lastUserToken is not empty,lastUserToken:" + lastUserToken); | ||
| 62 | + } | ||
| 63 | + // hasLogin = true; | ||
| 64 | + Logger.info(TAG, 'isLogin hasLogin2:' + hasLogin); | ||
| 65 | + return hasLogin; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 是否已登录 | ||
| 70 | + * @param folder | ||
| 71 | + * @param files | ||
| 72 | + */ | ||
| 73 | + static isLoginSync() { | ||
| 74 | + Logger.info(TAG, 'isLogin hasLogin1:' + hasLogin); | ||
| 75 | + let lastUserToken = AccountManagerUtils.getUserTokenSync() | ||
| 76 | + Logger.info(TAG, 'isLogin lastUserToken:' + lastUserToken); | ||
| 77 | + if (StringUtils.isEmpty(lastUserToken)) { | ||
| 78 | + hasLogin = false; | ||
| 79 | + Logger.info(TAG, "isLogin lastUserToken is empty"); | ||
| 80 | + } else { | ||
| 81 | + hasLogin = true; | ||
| 82 | + Logger.info(TAG, "isLogin lastUserToken is not empty,lastUserToken:" + lastUserToken); | ||
| 83 | + } | ||
| 84 | + // hasLogin = true; | ||
| 85 | + Logger.info(TAG, 'isLogin hasLogin2:' + hasLogin); | ||
| 86 | + return hasLogin; | ||
| 87 | + } | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +// export const accountManagerUtils = new AccountManagerUtils(); |
| 1 | +import bundleManager from '@ohos.bundle.bundleManager'; | ||
| 2 | +import common from '@ohos.app.ability.common'; | ||
| 3 | +import { Logger } from './Logger'; | ||
| 4 | + | ||
| 5 | +const TAG: string = 'AppUtils'; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 与应用相关属性或操作 | ||
| 9 | + */ | ||
| 10 | +export class AppUtils { | ||
| 11 | + /** | ||
| 12 | + * 获取应用名称 | ||
| 13 | + * 即:咪咕视频 | ||
| 14 | + */ | ||
| 15 | + static getAppName(context: common.Context): string { | ||
| 16 | + // todo:获取到的是 $string:app_name | ||
| 17 | + // return context.applicationInfo?.label; | ||
| 18 | + return context.resourceManager.getStringByNameSync("app_name"); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 获取应用的包名 | ||
| 23 | + * 即:com.cmcc.myapplication | ||
| 24 | + */ | ||
| 25 | + static getPackageName(context: common.Context): string { | ||
| 26 | + return context.applicationInfo?.name; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 获取应用版本号,如:1.0.0.0 | ||
| 31 | + * @returns 版本号字符串 | ||
| 32 | + */ | ||
| 33 | + static getAppVersionName(): string { | ||
| 34 | + try { | ||
| 35 | + let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT) | ||
| 36 | + return bundleInfo?.versionName | ||
| 37 | + } catch (e) { | ||
| 38 | + Logger.warn(TAG, 'get app version error:' + e?.message); | ||
| 39 | + } | ||
| 40 | + return ""; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 获取应用版本编码,如:1000000 | ||
| 45 | + * @returns 应用版本编码 | ||
| 46 | + */ | ||
| 47 | + static getAppVersionCode(): string { | ||
| 48 | + try { | ||
| 49 | + let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT) | ||
| 50 | + return bundleInfo?.versionCode + "" | ||
| 51 | + } catch (e) { | ||
| 52 | + Logger.warn(TAG, 'get app version error:' + e?.message); | ||
| 53 | + } | ||
| 54 | + return ''; | ||
| 55 | + } | ||
| 56 | +} | ||
| 57 | + |
| 1 | +/** | ||
| 2 | + * IDataSource处理数据侦听器的基本实现 | ||
| 3 | + */ | ||
| 4 | +export abstract class BasicDataSource<T> implements IDataSource { | ||
| 5 | + private listeners: DataChangeListener[] = []; | ||
| 6 | + | ||
| 7 | + constructor() { | ||
| 8 | + } | ||
| 9 | + | ||
| 10 | + // 获取数据总个数 | ||
| 11 | + public abstract totalCount(): number; | ||
| 12 | + | ||
| 13 | + // 获取索引对应的Item数据 | ||
| 14 | + public abstract getData(index: number): T | undefined; | ||
| 15 | + | ||
| 16 | + // 注册改变数据的控制器 | ||
| 17 | + public registerDataChangeListener(listener: DataChangeListener): void { | ||
| 18 | + if (this.listeners.indexOf(listener) < 0) { | ||
| 19 | + console.info('add DataChangeListener'); | ||
| 20 | + this.listeners.push(listener); | ||
| 21 | + } | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + // 注销改变数据的控制器 | ||
| 25 | + public unregisterDataChangeListener(listener: DataChangeListener): void { | ||
| 26 | + const pos = this.listeners.indexOf(listener); | ||
| 27 | + if (pos >= 0) { | ||
| 28 | + console.info('remove DataChangeListener'); | ||
| 29 | + this.listeners.splice(pos, 1); | ||
| 30 | + } | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + // 通知控制器数据重新加载数据 | ||
| 34 | + public notifyDataReload(): void { | ||
| 35 | + this.listeners.forEach(listener => { | ||
| 36 | + listener.onDataReloaded(); | ||
| 37 | + }) | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + // 通知控制器数据增加 | ||
| 41 | + public notifyDataAdd(index: number): void { | ||
| 42 | + this.listeners.forEach(listener => { | ||
| 43 | + listener.onDataAdd(index); | ||
| 44 | + }) | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + // 通知控制器数据位置变化 | ||
| 48 | + public notifyDataMove(from: number, to: number): void { | ||
| 49 | + this.listeners.forEach(listener => { | ||
| 50 | + listener.onDataMove(from, to); | ||
| 51 | + }) | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + // 通知控制器数据删除 | ||
| 55 | + public notifyDataDelete(index: number): void { | ||
| 56 | + this.listeners.forEach(listener => { | ||
| 57 | + listener.onDataDelete(index); | ||
| 58 | + }) | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + // 通知控制器数据变化 | ||
| 62 | + public notifyDataChange(index: number): void { | ||
| 63 | + this.listeners.forEach(listener => { | ||
| 64 | + listener.onDataChange(index); | ||
| 65 | + }) | ||
| 66 | + } | ||
| 67 | +} |
| 1 | +import mediaQuery from '@ohos.mediaquery'; | ||
| 2 | +import { Logger } from './Logger'; | ||
| 3 | + | ||
| 4 | +const TAG = 'BreakPointSystem'; | ||
| 5 | + | ||
| 6 | +interface Breakpoint { | ||
| 7 | + name: string | ||
| 8 | + size: number | ||
| 9 | + mediaQueryListener?: mediaQuery.MediaQueryListener | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +// 响应式布局:"phone","tablet","2in1" | ||
| 13 | +// https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout.md/ | ||
| 14 | +declare interface BreakPointTypeOption<T> { | ||
| 15 | + xs: T; // [0, 320) (最小宽度-类型设备) // Wearable/可穿戴设备 | ||
| 16 | + sm: T; // [320,600) (小宽度-类型设备) // Phone/折叠设备当前折叠状态为折叠FOLDED/手机(HUAWEI Mate 40 Pro & NOH-AN00)/折叠后345.6vp | ||
| 17 | + md: T; // [600,840) (中等宽度-类型设备) // Fold/折叠设备当前折叠状态为完全展开EXPANDED/折叠手机(HUAWEI Mate X5 & ALT-AL10)/展开后711.68vp | ||
| 18 | + lg: T; // [840,1080) (大宽度-类型设备) // Tablet/2in1(PC与Tablet二合一产品)/TV/Car/PC/laptop | ||
| 19 | + // xl?: T; // [1080,1440) (特大宽度-类型设备) // TV/如4K电视 | ||
| 20 | + // xxl?:T; //[1440,+8) (超大宽度-类型设备) // TV/如8K以上(8K/16K)电视 | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +export class BreakpointSystem { | ||
| 24 | + // 上次通知的断点 | ||
| 25 | + private lastBreakpoint: string = '' | ||
| 26 | + private breakpoints: Breakpoint[] = [ | ||
| 27 | + { name: 'xs', size: 0 }, | ||
| 28 | + { name: 'sm', size: 320 }, | ||
| 29 | + { name: 'md', size: 600 }, // 520vp | ||
| 30 | + { name: 'lg', size: 840 } | ||
| 31 | + ] | ||
| 32 | + | ||
| 33 | + private updateCurrentBreakpoint(breakpoint: string): void { | ||
| 34 | + Logger.info(TAG, 'updateCurrentBreakpoint lastBreakpoint: ' + this.lastBreakpoint + ", breakpoint:" + breakpoint) | ||
| 35 | + if (this.lastBreakpoint !== breakpoint) { | ||
| 36 | + this.lastBreakpoint = breakpoint | ||
| 37 | + AppStorage.setOrCreate<string>('currentBreakpoint', breakpoint) | ||
| 38 | + // AppStorage.setOrCreate<string>(BreakpointConstants.CURRENT_BREAKPOINT, this.currentBreakpoint); | ||
| 39 | + Logger.info(TAG, 'on current Breakpoint: ' + this.lastBreakpoint) | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public register() { | ||
| 44 | + this.breakpoints.forEach((breakpoint: Breakpoint, index) => { | ||
| 45 | + let condition: string | ||
| 46 | + if (index === this.breakpoints.length - 1) { | ||
| 47 | + condition = '(' + breakpoint.size + 'vp<=width' + ')' | ||
| 48 | + } else { | ||
| 49 | + condition = '(' + breakpoint.size + 'vp<=width<' + this.breakpoints[index + 1].size + 'vp)' | ||
| 50 | + } | ||
| 51 | + Logger.info(TAG, "register matchMediaSync condition:" + condition); | ||
| 52 | + breakpoint.mediaQueryListener = mediaQuery.matchMediaSync(condition) | ||
| 53 | + breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => { | ||
| 54 | + // Logger.info(TAG, "register change mediaQueryResult:" + JSON.stringify(mediaQueryResult)); | ||
| 55 | + if (mediaQueryResult.matches) { | ||
| 56 | + // Logger.info(TAG, "register breakpoint.name:" + JSON.stringify(breakpoint.name)); | ||
| 57 | + this.updateCurrentBreakpoint(breakpoint.name) | ||
| 58 | + } | ||
| 59 | + }) | ||
| 60 | + }) | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public unregister() { | ||
| 64 | + this.breakpoints.forEach((breakpoint: Breakpoint) => { | ||
| 65 | + if (breakpoint.mediaQueryListener) { | ||
| 66 | + breakpoint.mediaQueryListener.off('change') | ||
| 67 | + } | ||
| 68 | + }) | ||
| 69 | + } | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +export class BreakPointType<T> { | ||
| 73 | + options: BreakPointTypeOption<T> | ||
| 74 | + | ||
| 75 | + constructor(option: BreakPointTypeOption<T>) { | ||
| 76 | + this.options = option | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + getValue(currentBreakPoint: string): T { | ||
| 80 | + // return this.options[currentBreakPoint] as T; | ||
| 81 | + // Logger.info(TAG, "getValue this.options:" + JSON.stringify(this.options)); | ||
| 82 | + if (currentBreakPoint === 'xs') { | ||
| 83 | + return this.options.xs | ||
| 84 | + } else if (currentBreakPoint === 'sm') { | ||
| 85 | + return this.options.sm | ||
| 86 | + } else if (currentBreakPoint === 'md') { | ||
| 87 | + return this.options.md | ||
| 88 | + } else if (currentBreakPoint === 'lg') { | ||
| 89 | + return this.options.lg | ||
| 90 | + // } else if (currentBreakPoint === 'xl') { | ||
| 91 | + // return this.options.xl | ||
| 92 | + // } else if (currentBreakPoint === 'xxl') { | ||
| 93 | + // return this.options.xxl | ||
| 94 | + } else { | ||
| 95 | + // return undefined | ||
| 96 | + return this.options.sm | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | +} | ||
| 100 | + |
| 1 | +import LinkList from '@ohos.util.List'; | ||
| 2 | +import HashMap from '@ohos.util.HashMap'; | ||
| 3 | + | ||
| 4 | +/** | ||
| 5 | + * ArrayUtils class. | ||
| 6 | + */ | ||
| 7 | + | ||
| 8 | +export class CollectionUtils { | ||
| 9 | + /** | ||
| 10 | + * The Array utils tag. | ||
| 11 | + */ | ||
| 12 | + private static readonly TAG: string = 'ArrayUtils'; | ||
| 13 | + | ||
| 14 | + static isArray(value: any): boolean { | ||
| 15 | + if (typeof Array.isArray === 'function') { | ||
| 16 | + return Array.isArray(value); | ||
| 17 | + } else { | ||
| 18 | + return Object.prototype.toString.call(value) === '[object Array]'; | ||
| 19 | + } | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * Check collection is empty or not. | ||
| 24 | + * @param collection any[] | ||
| 25 | + * @returns {boolean} true(empty) | ||
| 26 | + */ | ||
| 27 | + static isEmpty(collection?: any[]): boolean { | ||
| 28 | + return !collection || collection.length === 0; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + static isEmptyList<T>(list1?: LinkList<T>): boolean { | ||
| 32 | + return !list1 || list1.length === 0; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + static isEmptyHashMap(obj?: HashMap<any, any>): boolean { | ||
| 36 | + if (!obj) { | ||
| 37 | + return true; | ||
| 38 | + } | ||
| 39 | + return obj.isEmpty(); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + static isEmptyMap(obj?: Map<any, any>): boolean { | ||
| 43 | + if (!obj) { | ||
| 44 | + return true; | ||
| 45 | + } | ||
| 46 | + return Object.keys(obj).length === 0 && obj.constructor === Object; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + static isEmptyRecord(obj?: Record<string, string>): boolean { | ||
| 50 | + if (!obj) { | ||
| 51 | + return true; | ||
| 52 | + } | ||
| 53 | + return Object.keys(obj).length === 0 && obj.constructor === Object; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Check collection is empty or not. | ||
| 58 | + * @param collection any[] | ||
| 59 | + * @returns {boolean} true(not empty) | ||
| 60 | + */ | ||
| 61 | + static isNotEmpty(collection?: any[]): boolean { | ||
| 62 | + if (!collection) { | ||
| 63 | + return false | ||
| 64 | + } | ||
| 65 | + return collection.length > 0; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + static getListSize(collection?: any[]): number { | ||
| 69 | + return CollectionUtils.isEmpty(collection) ? 0 : collection.length; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + static getListElement(collection?: any[], index?: number): any { | ||
| 73 | + if (CollectionUtils.isEmpty(collection) || index === undefined) { | ||
| 74 | + return null; | ||
| 75 | + } | ||
| 76 | + return index >= 0 && index < collection.length ? collection[index] : null; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + static convertArray<T>(objectList: T[] | T): T[] { | ||
| 80 | + if (CollectionUtils.isArray(objectList)) { | ||
| 81 | + return objectList as T[]; | ||
| 82 | + } else { | ||
| 83 | + return [objectList as T]; | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 88 | + * 把list2合入list1后 | ||
| 89 | + * @param list1 | ||
| 90 | + * @param list2 | ||
| 91 | + * @returns | ||
| 92 | + */ | ||
| 93 | + static addAll<T>(list1: LinkList<T>, list2: LinkList<T>): LinkList<T> { | ||
| 94 | + if (!list1) { | ||
| 95 | + list1 = new LinkList<T>(); | ||
| 96 | + } | ||
| 97 | + if (!list2) { | ||
| 98 | + return list1; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + for (let index = 0; index < list2.length; index++) { | ||
| 102 | + list1.add(list2[index]) | ||
| 103 | + } | ||
| 104 | + return list1 | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + static deepCopy(objectList: any[]): any[] { | ||
| 108 | + const list: any[] = []; | ||
| 109 | + for (const objectItem of objectList) { | ||
| 110 | + if (typeof objectItem !== 'object') { | ||
| 111 | + list.push(objectItem); | ||
| 112 | + continue; | ||
| 113 | + } | ||
| 114 | + if (objectItem.constructor === Date) { | ||
| 115 | + list.push(new Date(objectItem)); | ||
| 116 | + continue; | ||
| 117 | + } | ||
| 118 | + if (objectItem.constructor === RegExp) { | ||
| 119 | + list.push(new RegExp(objectItem)); | ||
| 120 | + continue; | ||
| 121 | + } | ||
| 122 | + if (objectItem.clone) { | ||
| 123 | + list.push(objectItem.clone()); | ||
| 124 | + continue; | ||
| 125 | + } | ||
| 126 | + const newObj = new objectItem.constructor(); | ||
| 127 | + for (const key in objectItem) { | ||
| 128 | + if (Object.hasOwnProperty.call(objectItem, key)) { | ||
| 129 | + const val = objectItem[key]; | ||
| 130 | + newObj[key] = val; | ||
| 131 | + } | ||
| 132 | + } | ||
| 133 | + list.push(newObj); | ||
| 134 | + } | ||
| 135 | + return list; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + static deepCopyNumber(values: Set<number>): Set<number> { | ||
| 139 | + const newSet: Set<number> = new Set(); | ||
| 140 | + values.forEach((value => { | ||
| 141 | + newSet.add(value); | ||
| 142 | + })); | ||
| 143 | + return newSet; | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + /** | ||
| 147 | + * Uint8Array to string | ||
| 148 | + * @param fileData Uint8Array | ||
| 149 | + */ | ||
| 150 | + static uint8ArrayToString(fileData: Uint8Array): string { | ||
| 151 | + return decodeURIComponent(escape(String.fromCharCode(...fileData))); | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + /** | ||
| 155 | + * string to Uint8Array | ||
| 156 | + * @param str string | ||
| 157 | + */ | ||
| 158 | + static stringToUint8Array(str: string): Uint8Array { | ||
| 159 | + // spilt('') Each character is divided between them | ||
| 160 | + const arr = unescape(encodeURIComponent(str)).split('').map(val => val.charCodeAt(0)); | ||
| 161 | + return new Uint8Array(arr); | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + /** | ||
| 165 | + * 截取集合部分数据。 | ||
| 166 | + * start:0 - end:20 截取0-19,共20个数据 | ||
| 167 | + */ | ||
| 168 | + static getSubElements(collection?: any[], start?: number, end?: number): any[] { | ||
| 169 | + if (CollectionUtils.isEmpty(collection) || start === undefined || end === undefined) { | ||
| 170 | + return null; | ||
| 171 | + } | ||
| 172 | + if (start < 0 || end < start) { | ||
| 173 | + return null; | ||
| 174 | + } | ||
| 175 | + if (end > collection.length) { | ||
| 176 | + return null; | ||
| 177 | + } | ||
| 178 | + let ss = collection.slice(start, end); | ||
| 179 | + ss; | ||
| 180 | + return collection.slice(start, end); | ||
| 181 | + } | ||
| 182 | +} | ||
| 183 | + |
| 1 | +import { StringUtils } from './StringUtils'; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 日期/时间工具 | ||
| 5 | + */ | ||
| 6 | +// let myDate = new Date(); | ||
| 7 | +// myDate.getTime() // 获取以毫秒为单位的时间值。 | ||
| 8 | +// myDate.getFullYear(); // 获取完整的年份(4位,1970-????) | ||
| 9 | +// myDate.getMonth(); // 获取myDate月份(0-11,0代表1月) | ||
| 10 | +// myDate.getDate(); // 获取myDate日期(1-31) | ||
| 11 | +// myDate.getDay(); // 获取myDate星期X(0-6,0代表星期天) | ||
| 12 | +// myDate.getTime(); // 获取myDate时间(从1970.1.1开始的毫秒数) | ||
| 13 | +// myDate.getHours(); // 获取myDate小时数(0-23) | ||
| 14 | +// myDate.getMinutes(); // 获取myDate分钟数(0-59) | ||
| 15 | +// myDate.getSeconds(); // 获取myDate秒数(0-59) | ||
| 16 | +// myDate.getMilliseconds(); // 获取myDate毫秒数(0-999) | ||
| 17 | +// myDate.toLocaleDateString(); // 获取当前日期:使用当前或指定的区域设置将日期转换为字符串。 | ||
| 18 | +// myDate.toLocaleTimeString(); // 获取当前时间:使用当前或指定的区域设置将时间转换为字符串。 | ||
| 19 | +// myDate.toLocaleString(); // 获取日期与时间:使用当前或指定的区域设置将日期和时间转换为字符串 | ||
| 20 | + | ||
| 21 | +// 日期时间的年月日时分秒以及毫秒的各个字段 | ||
| 22 | +// export class DateOpt { | ||
| 23 | +// year: string = ''; // 年 小写y | ||
| 24 | +// month: string = ''; // 月 大写M | ||
| 25 | +// day: string = ''; // 日 小写d | ||
| 26 | +// hour: string = ''; // 时 大写H(24小时制) | ||
| 27 | +// // hh: string = ''; // 时 小写H(12小时制) | ||
| 28 | +// minute: string = ''; // 分 小写m | ||
| 29 | +// second: string = ''; // 秒 小写s | ||
| 30 | +// millisecond: string = ''; // 毫秒 大写S | ||
| 31 | +// } | ||
| 32 | + | ||
| 33 | +export class DateTimeUtils { | ||
| 34 | + static readonly MAX_TIME = Math.pow(10, 8) * 24 * 60 * 60 * 1000; // 8640000000000000 毫秒 | ||
| 35 | + static readonly MIN_TIME = -DateTimeUtils.MAX_TIME; // -8640000000000000 毫秒 | ||
| 36 | + | ||
| 37 | + // 日期+时间格式 | ||
| 38 | + static readonly PATTERN_DATE_TIME_DEFAULT: string = 'yyyyMMddHHmmss'; // 年月日时分秒 | ||
| 39 | + static readonly PATTERN_DATE_TIME_HYPHEN: string = 'yyyy-MM-dd HH:mm:ss'; // 日期中包含连字符/中划线(HYPHEN),时间是以冒号(Colon)分割 | ||
| 40 | + static readonly PATTERN_DATE_TIME_HYPHEN_MS: string = 'yyyy-MM-dd HH:mm:ss.SSS'; // 日期中包含连字符/中划线(HYPHEN),时间是以冒号(Colon)分割 | ||
| 41 | + static readonly PATTERN_DATE_TIME_SLASH: string = 'yyyy/MM/dd HH:mm:ss'; // 日期中包含正斜杠(forward slash '/') | ||
| 42 | + static readonly PATTERN_DATE_TIME_BACK_SLASH: string = 'yyyy\\MM\\dd HH:mm:ss'; // 日期中包含反斜杠(back slash '\') | ||
| 43 | + static readonly PATTERN_DATE_TIME_DOT: string = 'yyyy.MM.dd HH:mm:ss'; // 日期中包含英文小圆点(DOT '.') | ||
| 44 | + static readonly PATTERN_DATE_TIME_CN: string = 'yyyy年MM月dd日 HH:mm:ss'; // 日期中包含包含中文年月日 | ||
| 45 | + static readonly PATTERN_DATE_TIME_MS: string = 'yyyyMMddHHmmssSSS'; // 时间中包含毫秒 | ||
| 46 | + static readonly PATTERN_DATE_TIME_WITHOUT_SECOND: string = 'yyyyMMddHHmm'; // 时间中不包含秒 | ||
| 47 | + static readonly PATTERN_DATE_TIME_SIMPLIFY: string = 'MM/dd HH:mm'; // 精简的日期+时间(不包含年份和秒), 月/日 时:分 | ||
| 48 | + static readonly PATTERN_DATE_SLASH_WITHOUT_YEAR2: string = 'MM-dd'; // 日期中不包含年份 | ||
| 49 | + | ||
| 50 | + // 仅日期格式(不包含时间) | ||
| 51 | + static readonly PATTERN_DATE_DEFAULT: string = 'yyyyMMdd'; // 年月日 | ||
| 52 | + static readonly PATTERN_DATE_HYPHEN: string = 'yyyy-MM-dd'; // 日期中包含连字符/中划线(HYPHEN) | ||
| 53 | + static readonly PATTERN_DATE_SLASH: string = 'yyyy/MM/dd'; // 日期中包含正斜杠(forward slash '/') | ||
| 54 | + static readonly PATTERN_DATE_BACK_SLASH: string = 'yyyy\\MM\\dd'; // 日期中包含反斜杠(back slash '\') | ||
| 55 | + static readonly PATTERN_DATE_DOT: string = 'yyyy.MM.dd'; // 日期中包含英文小圆点(DOT '.') | ||
| 56 | + static readonly PATTERN_DATE_CN: string = 'yyyy年MM月dd日'; // 日期中包含包含中文年月日 | ||
| 57 | + static readonly PATTERN_DATE_SLASH_WITHOUT_YEAR: string = 'MM/dd'; // 日期中不包含年份 | ||
| 58 | + static readonly PATTERN_DATE_CN_WITHOUT_YEAR: string = 'MM月dd日'; // 日期中不包含年份,且month与day是中文 | ||
| 59 | + | ||
| 60 | + // 仅时间格式(不包含日期) | ||
| 61 | + static readonly PATTERN_TIME_DEFAULT: string = 'HHmmss'; // 时分秒 | ||
| 62 | + static readonly PATTERN_TIME_COLON: string = 'HH:mm:ss'; // 时间是以冒号(Colon)分割 | ||
| 63 | + static readonly PATTERN_TIME_MS: string = 'HHmmssSSS'; // 时间中包含毫秒 | ||
| 64 | + static readonly PATTERN_TIME_COLON_DOT_MS: string = 'HH:mm:ss.SSS'; // 时间是以冒号(Colon)与点号(DOT)分割,且包含毫秒 | ||
| 65 | + static readonly PATTERN_TIME_WITHOUT_SECOND: string = 'HHmm'; // 时间中不包含秒 | ||
| 66 | + static readonly PATTERN_TIME_COLON_WITHOUT_SECOND: string = 'HH:mm'; // 时间是以冒号(Colon)分割,且不包含秒 | ||
| 67 | + static readonly PATTERN_TIME_COLON_WITHOUT_HOUR: string = 'mm:ss'; // 时间是以冒号(Colon)分割,且不包含小时(分钟长度至少2位,可能是3位) | ||
| 68 | + | ||
| 69 | + static readonly PATTERN_WEEK: string = 'E'; // 周几/星期几 | ||
| 70 | + | ||
| 71 | + static readonly MONTHS_IN_YEAR: number = 12; // 1年12个月 | ||
| 72 | + static readonly QUARTERS_IN_YEAR: number = 4; // 1年4个季度 | ||
| 73 | + static readonly MONTHS_IN_QUARTER: number = 3; // 1季度3个月 | ||
| 74 | + static readonly DAYS_MONTH: number[] = [31, 30, 29, 28]; // 每月多少天:大月(1/3/5/7/8/10/12月);小月(4/6/9/11月);2月(闰年29天/非闰月28天) | ||
| 75 | + static readonly DAYS_IN_WEEK: number = 7; // 1周7天 | ||
| 76 | + static readonly HOURS_IN_DAY = 24; // 1天24小时 | ||
| 77 | + // 分钟 | ||
| 78 | + static readonly MINUTES_IN_HOUR = 60; // 1小时60分(时分秒之间的进制RADIX) | ||
| 79 | + static readonly MINUTES_IN_DAY = 1440 // 60 * 24 // 1天1440分钟 | ||
| 80 | + // 秒 | ||
| 81 | + static readonly SECONDS_IN_MINUTE = 60; // 1分60秒(时分秒之间的进制RADIX) | ||
| 82 | + static readonly SECONDS_IN_HOUR = 3600 // 60 * 60 // 1小时3600秒 | ||
| 83 | + static readonly SECONDS_IN_DAY = 86400 // 60 * 60 * 24 // 1天86400秒 | ||
| 84 | + // 毫秒 | ||
| 85 | + static readonly MILLISECONDS_IN_SECOND: number = 1000; // 1秒是1000毫秒,秒与毫秒之间的转换进制RADIX | ||
| 86 | + static readonly MILLISECONDS_IN_MINUTE: number = 60000; // 1000 * 60 // 1分钟是60000毫秒 | ||
| 87 | + static readonly MILLISECONDS_IN_HOUR: number = 3600000; // 1000 * 60 * 60 // 1小时是3600000毫秒 | ||
| 88 | + static readonly MILLISECONDS_IN_DAY: number = 86400000; // 1000 * 60 * 60 * 24 // 1天是86400000毫秒 | ||
| 89 | + | ||
| 90 | + static readonly CHINESE_YEAR: string = '年'; | ||
| 91 | + static readonly CHINESE_MONTH: string = '月'; | ||
| 92 | + static readonly CHINESE_DAY: string = '日'; | ||
| 93 | + static readonly CHINESE_LAST_WEEK: string = '上周'; | ||
| 94 | + static readonly CHINESE_YESTERDAY: string = '昨天'; | ||
| 95 | + static readonly CHINESE_TODAY: string = '今天'; | ||
| 96 | + static readonly CHINESE_TOMORROW: string = '明天'; | ||
| 97 | + static readonly CHINESE_NEXT_WEEK: string = '下周'; | ||
| 98 | + // 周x/星期X | ||
| 99 | + static readonly CHINESE_WEEK1: string[] = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; | ||
| 100 | + static readonly CHINESE_WEEK2: string[] = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; | ||
| 101 | + static readonly ENGLISH_WEEK1 = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; | ||
| 102 | + static readonly ENGLISH_WEEK2 = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; | ||
| 103 | + static readonly ENGLISH_MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; | ||
| 104 | + | ||
| 105 | + /** | ||
| 106 | + * 获取当前日期:年月日 | ||
| 107 | + * 返回格式,默认如:yyyyMMdd,20230926 | ||
| 108 | + */ | ||
| 109 | + static getCurDate(format = DateTimeUtils.PATTERN_DATE_DEFAULT): string { | ||
| 110 | + const DATETIME = new Date() | ||
| 111 | + return DateTimeUtils.formatDate(DATETIME.getTime(), format) | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * 获取当前时间:时分秒 | ||
| 116 | + * 返回格式,默认如:HHmmss,230559 | ||
| 117 | + */ | ||
| 118 | + static getCurTime(format = DateTimeUtils.PATTERN_TIME_DEFAULT): string { | ||
| 119 | + const DATETIME = new Date() | ||
| 120 | + return DateTimeUtils.formatDate(DATETIME.getTime(), format) | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + /** | ||
| 124 | + * 获取当前时间戳,毫秒 | ||
| 125 | + * */ | ||
| 126 | + public static getTimeStamp(): number { | ||
| 127 | + return new Date().getTime(); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * 当数字转字符串不足maxLength位时,用前导0补足maxLength位 | ||
| 132 | + * @param value-数据值 | ||
| 133 | + * @returns | ||
| 134 | + * 年份是4位 | ||
| 135 | + * 月/日/时/分/秒,都是2位 | ||
| 136 | + * 毫秒是3位 | ||
| 137 | + */ | ||
| 138 | + static fill(num: number, maxLength: number = 2): string { | ||
| 139 | + let value: string = '' + num | ||
| 140 | + return value.padStart(maxLength, '0') | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + /** | ||
| 144 | + * 获取两个时间点的时间差 | ||
| 145 | + * @param milliseconds1 | ||
| 146 | + * @param milliseconds2 | ||
| 147 | + * @returns Duration | ||
| 148 | + */ | ||
| 149 | + static getDuration(milliseconds1: number, milliseconds2: number): number { | ||
| 150 | + let date1 = new Date(milliseconds1) | ||
| 151 | + let date2 = new Date(milliseconds2) | ||
| 152 | + let timeDiff = Math.abs(date2.getTime() - date1.getTime()); | ||
| 153 | + return timeDiff; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + /** | ||
| 157 | + * 格式化Duration时间 | ||
| 158 | + * @param duration 毫秒 | ||
| 159 | + * @returns 返回格式化后的Duration时间 | ||
| 160 | + */ | ||
| 161 | + static getFormattedDuration(duration: number): string { | ||
| 162 | + // 也可以直接先除以1000转换为秒后再计算 // duration = duration/1000 | ||
| 163 | + // Math.floor 用于向下取整 | ||
| 164 | + let hour = Math.floor(duration / (DateTimeUtils.MILLISECONDS_IN_HOUR)) | ||
| 165 | + // 用总毫秒数duration减去hour所对应的毫秒数差,再除以每分钟所占用的毫秒数 | ||
| 166 | + let minute = Math.floor((duration - hour * (DateTimeUtils.MILLISECONDS_IN_HOUR)) / (DateTimeUtils.MILLISECONDS_IN_MINUTE)); | ||
| 167 | + let second = Math.floor(duration / DateTimeUtils.MILLISECONDS_IN_SECOND) % DateTimeUtils.SECONDS_IN_MINUTE; // 先除以1000,转换为秒;再对整分钟取余 | ||
| 168 | + if (hour > 0) { | ||
| 169 | + return `${DateTimeUtils.fill(hour)}:${DateTimeUtils.fill(minute)}:${DateTimeUtils.fill(second)}` | ||
| 170 | + } | ||
| 171 | + return `${DateTimeUtils.fill(minute)}:${DateTimeUtils.fill(second)}` | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + /** | ||
| 175 | + * 格式化显示倒计时 | ||
| 176 | + * @param milliseconds 时间戳 毫秒 | ||
| 177 | + * @returns 返回格式化后的Duration时间 | ||
| 178 | + */ | ||
| 179 | + static getDurationToNow(milliseconds: number): string { | ||
| 180 | + let nowDateTime = new Date(); | ||
| 181 | + let duration = milliseconds - nowDateTime.getTime(); | ||
| 182 | + if (duration < 0) { | ||
| 183 | + duration = 0; | ||
| 184 | + } | ||
| 185 | + return DateTimeUtils.getFormattedDuration(duration) | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + /** | ||
| 189 | + * 根据日期/时间字符串反序列化对应的时间戳 | ||
| 190 | + * @param dateTimeString string 日期+时间字符串 | ||
| 191 | + * 列举字符串格式,如: | ||
| 192 | + * 20231129,yyyyMMdd | ||
| 193 | + * 20231126230559 yyyyMMddHHmmss | ||
| 194 | + * 20231126230559729 yyyyMMddHHmmssSSS | ||
| 195 | + * 2023-11-26 23:05:59.729, yyyy-MM-dd HH:mm:ss.SSS(先移除所有中划线和冒号及空格等非数字字符) | ||
| 196 | + * 日期/时间字符串中包含连字符/中划线(Hyphen/Strike)/移除冒号(Colon)/移除空白字符(包括空格、制表符、换行符等)/移除正斜杠(forward slash '/')/移除反斜杠(back slash '\') | ||
| 197 | + * @param format:string 日期+时间的格式,默认格式:yyyy-MM-dd | ||
| 198 | + * @param referenceDate:Date 参考日期+时间 | ||
| 199 | + * @returns 转换后的时间戳:milliseconds 毫秒 | ||
| 200 | + * let dateTimeStr:string = "(预告) 2024年12月24日 02:50 开播" | ||
| 201 | + * let formatPattern:string = "(预告) yyyy年MM月dd日 HH:mm 开播" | ||
| 202 | + * let parsedDate = DateTimeUtils.parseDate(dateTimeStr, formatPattern) | ||
| 203 | + */ | ||
| 204 | + static parseDate(dateTimeString: string, format: string = DateTimeUtils.PATTERN_DATE_HYPHEN, referenceDate?: Date): number { | ||
| 205 | + if (!dateTimeString) { | ||
| 206 | + return 0 | ||
| 207 | + } | ||
| 208 | + if (!referenceDate) { | ||
| 209 | + referenceDate = new Date(); // 参考当前时间 | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + const optPatternList: string[] = ['y+', 'M+', 'd+', 'H+', 'm+', 's+', 'S+']; | ||
| 213 | + let targetYear: number = 0 // 年 | ||
| 214 | + let targetMonth: number = 0 // 月, monthIndex | ||
| 215 | + let targetDay: number = 0 // 日 | ||
| 216 | + let targetHour: number = 0 // 时 | ||
| 217 | + let targetMinute: number = 0 // 分 | ||
| 218 | + let targetSecond: number = 0 // 秒 | ||
| 219 | + let targetMillisecond: number = 0 // 毫秒 | ||
| 220 | + for (let i = 0; i < optPatternList.length; i++) { | ||
| 221 | + const optPattern = optPatternList[i]; | ||
| 222 | + const regExp = new RegExp(optPattern, 'g'); | ||
| 223 | + // console.log(optPattern); | ||
| 224 | + let matches = regExp.exec(format); | ||
| 225 | + if (!matches) { | ||
| 226 | + continue | ||
| 227 | + } | ||
| 228 | + // console.dir(matches) | ||
| 229 | + // console.dir(matches?.[0]) | ||
| 230 | + // console.dir(matches?.index) | ||
| 231 | + let pick: number = StringUtils.parseNumber(dateTimeString.substring(matches.index, matches.index + matches?.[0].length)) | ||
| 232 | + // console.dir(pick) | ||
| 233 | + switch (optPattern) { | ||
| 234 | + case 'y+': | ||
| 235 | + if (pick >= -271821 && pick <= 275760) { // 根据最大日期/时间与根据最小日期/时间计算出的年份范围 | ||
| 236 | + targetYear = pick | ||
| 237 | + } else { | ||
| 238 | + targetYear = referenceDate.getFullYear() // 当解析不到年份时,则设置为今年 | ||
| 239 | + } | ||
| 240 | + break; | ||
| 241 | + case 'M+': // monthIndex between 0 and 11 | ||
| 242 | + if (pick >= 1 && pick <= 12) { | ||
| 243 | + targetMonth = pick - 1 | ||
| 244 | + } else { | ||
| 245 | + targetMonth = referenceDate.getMonth() // 当解析不到月份时,则设置为本月 | ||
| 246 | + } | ||
| 247 | + break; | ||
| 248 | + case 'd+': // between 1 and 31. | ||
| 249 | + if (pick >= 1 && pick <= 31) { | ||
| 250 | + targetDay = pick | ||
| 251 | + } else { | ||
| 252 | + targetDay = referenceDate.getDate() | ||
| 253 | + } | ||
| 254 | + break; | ||
| 255 | + case 'H+': // from 0 to 23 | ||
| 256 | + if (pick >= 0 && pick <= 23) { | ||
| 257 | + targetHour = pick | ||
| 258 | + } else { | ||
| 259 | + targetDay = referenceDate.getDate() | ||
| 260 | + } | ||
| 261 | + break; | ||
| 262 | + case 'm+': // from 0 to 59 | ||
| 263 | + if (pick >= 0 && pick <= 59) { | ||
| 264 | + targetMinute = pick | ||
| 265 | + } else { | ||
| 266 | + targetDay = referenceDate.getMinutes() | ||
| 267 | + } | ||
| 268 | + break; | ||
| 269 | + case 's+': // from 0 to 59 | ||
| 270 | + if (pick >= 0 && pick <= 59) { | ||
| 271 | + targetSecond = pick | ||
| 272 | + } else { | ||
| 273 | + targetSecond = referenceDate.getSeconds() | ||
| 274 | + } | ||
| 275 | + break; | ||
| 276 | + case 'S+': // from 0 to 999 | ||
| 277 | + if (pick >= 0 && pick <= 999) { | ||
| 278 | + targetMillisecond = pick | ||
| 279 | + } else { | ||
| 280 | + targetMillisecond = referenceDate.getMilliseconds() | ||
| 281 | + } | ||
| 282 | + break; | ||
| 283 | + default: | ||
| 284 | + break; | ||
| 285 | + } | ||
| 286 | + } | ||
| 287 | + let targetDate: Date = new Date(targetYear, targetMonth, targetDay, targetHour, targetMinute, targetSecond, targetMillisecond) | ||
| 288 | + return targetDate.getTime() | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + /** | ||
| 292 | + * 把整数时间戳格式化为指定格式的日期+时间字符串 | ||
| 293 | + * @param timestamp:毫秒 | ||
| 294 | + * @param format 指定要格式化的pattern,默认格式:yyyy-MM-dd | ||
| 295 | + * @returns 格式化后的字符串 | ||
| 296 | + * 举例: | ||
| 297 | + * let date_fmt = DateTimeUtils.formatDate(dateTime, "预告 (E) MM月dd日 HH:mm 开播") | ||
| 298 | + */ | ||
| 299 | + static formatDate(timestamp: number, format: string = DateTimeUtils.PATTERN_DATE_HYPHEN): string { | ||
| 300 | + try { | ||
| 301 | + const date = new Date(timestamp); | ||
| 302 | + let targetYear: string = date.getFullYear().toString(); | ||
| 303 | + let targetMonth: string = DateTimeUtils.fill(date.getMonth() + 1); | ||
| 304 | + let targetDay: string = DateTimeUtils.fill(date.getDate()); | ||
| 305 | + let targetHours: string = DateTimeUtils.fill(date.getHours()); | ||
| 306 | + let targetMinutes: string = DateTimeUtils.fill(date.getMinutes()); | ||
| 307 | + let targetSeconds: string = DateTimeUtils.fill(date.getSeconds()); | ||
| 308 | + let targetMilliseconds: string = DateTimeUtils.fill(date.getMilliseconds(), 3); | ||
| 309 | + let targetDayOfWeek: number = date.getDay(); | ||
| 310 | + | ||
| 311 | + const dateOptionPatternList: string[] = ['y+', 'M+', 'd+', 'H+', 'm+', 's+', 'S+', 'E']; | ||
| 312 | + for (let i = 0; i < dateOptionPatternList.length; i++) { | ||
| 313 | + const dateOptionPattern = dateOptionPatternList[i]; | ||
| 314 | + const dateOptionRegExp = new RegExp(dateOptionPattern); | ||
| 315 | + let match = dateOptionRegExp.exec(format); // 使用 RegExp 的exec 方法在目标字符串中查找匹配项 | ||
| 316 | + if (!match) { | ||
| 317 | + continue | ||
| 318 | + } | ||
| 319 | + switch (dateOptionPattern) { | ||
| 320 | + case 'y+': | ||
| 321 | + format = format.replace(dateOptionRegExp, targetYear); | ||
| 322 | + break; | ||
| 323 | + case 'M+': | ||
| 324 | + format = format.replace(dateOptionRegExp, targetMonth); | ||
| 325 | + break; | ||
| 326 | + case 'd+': | ||
| 327 | + format = format.replace(dateOptionRegExp, targetDay); | ||
| 328 | + break; | ||
| 329 | + case 'H+': | ||
| 330 | + format = format.replace(dateOptionRegExp, targetHours); | ||
| 331 | + break; | ||
| 332 | + case 'm+': | ||
| 333 | + format = format.replace(dateOptionRegExp, targetMinutes); | ||
| 334 | + break; | ||
| 335 | + case 's+': | ||
| 336 | + format = format.replace(dateOptionRegExp, targetSeconds); | ||
| 337 | + break; | ||
| 338 | + case 'S+': | ||
| 339 | + format = format.replace(dateOptionRegExp, targetMilliseconds); | ||
| 340 | + break; | ||
| 341 | + case 'E': // from 0 to 6; the day of the week | ||
| 342 | + format = format.replace(dateOptionRegExp, DateTimeUtils.CHINESE_WEEK1[targetDayOfWeek]); | ||
| 343 | + break; | ||
| 344 | + default: | ||
| 345 | + break; | ||
| 346 | + } | ||
| 347 | + } | ||
| 348 | + return format; | ||
| 349 | + } catch (error) { | ||
| 350 | + console.error(`ERROR formatDate error: ${error}.`); | ||
| 351 | + return ""; | ||
| 352 | + } | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + /** | ||
| 356 | + * 构造一周中的哪一天/构造星期X/周X | ||
| 357 | + * @param timestamp | ||
| 358 | + * @returns | ||
| 359 | + */ | ||
| 360 | + static buildDayOfWeek(timestamp: number, weeks: string[] = DateTimeUtils.CHINESE_WEEK1): string { | ||
| 361 | + try { | ||
| 362 | + const date = new Date(timestamp); | ||
| 363 | + let day = date.getDay() | ||
| 364 | + let week = weeks[day]; | ||
| 365 | + return week ?? '' | ||
| 366 | + } catch (error) { | ||
| 367 | + console.error(`ERROR formatDate error: ${error}.`); | ||
| 368 | + return '' | ||
| 369 | + } | ||
| 370 | + } | ||
| 371 | + | ||
| 372 | + static startOfDay(argument: number): Date { | ||
| 373 | + const _date = new Date(argument); | ||
| 374 | + _date.setHours(0, 0, 0, 0); | ||
| 375 | + return _date; | ||
| 376 | + } | ||
| 377 | + | ||
| 378 | + static isSameDay(dateLeft: number, dateRight: number): boolean { | ||
| 379 | + const dateLeftStartOfDay = DateTimeUtils.startOfDay(dateLeft); | ||
| 380 | + const dateRightStartOfDay = DateTimeUtils.startOfDay(dateRight); | ||
| 381 | + return dateLeftStartOfDay.getTime() === dateRightStartOfDay.getTime(); | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + static addDays(argument: number, amount: number): Date { | ||
| 385 | + const _date = new Date(argument); | ||
| 386 | + if (amount == 0) { | ||
| 387 | + return _date; | ||
| 388 | + } | ||
| 389 | + _date.setDate(_date.getDate() + amount); | ||
| 390 | + return _date; | ||
| 391 | + } | ||
| 392 | + | ||
| 393 | + static subDays(date: number, amount: number): Date { | ||
| 394 | + return DateTimeUtils.addDays(date, -amount); | ||
| 395 | + } | ||
| 396 | + | ||
| 397 | + static isToday(date: number,): boolean { | ||
| 398 | + return DateTimeUtils.isSameDay(date, Date.now()); | ||
| 399 | + } | ||
| 400 | + | ||
| 401 | + static isYesterday(date: number): boolean { | ||
| 402 | + return DateTimeUtils.isSameDay(date, DateTimeUtils.subDays(Date.now(), 1).getTime()); | ||
| 403 | + } | ||
| 404 | + | ||
| 405 | + static isTomorrow(date: number): boolean { | ||
| 406 | + return DateTimeUtils.isSameDay(date, DateTimeUtils.addDays(Date.now(), 1).getTime()); | ||
| 407 | + } | ||
| 408 | + | ||
| 409 | + // 检查指定的日期是过去的吗? | ||
| 410 | + static isPast(_date: Date): boolean { | ||
| 411 | + return _date.getTime() < Date.now(); | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + // 检查指定的日期在未来/将来吗? | ||
| 415 | + static isFuture(_date: Date): boolean { | ||
| 416 | + return _date.getTime() > Date.now(); | ||
| 417 | + } | ||
| 418 | + | ||
| 419 | + // 检查_date是在dateToCompare之后吗?,如 | ||
| 420 | + // const result = isAfter(new Date(1989, 6, 10), new Date(1987, 1, 11)) | ||
| 421 | + // => true | ||
| 422 | + static isAfter(_date: Date, dateToCompare: Date): boolean { | ||
| 423 | + return _date.getTime() > dateToCompare.getTime(); | ||
| 424 | + } | ||
| 425 | + | ||
| 426 | + // 检查_date是在dateToCompare之前吗?,如 | ||
| 427 | + // const result = isBefore(new Date(1989, 6, 10), new Date(1987, 1, 11)) | ||
| 428 | + // => false | ||
| 429 | + static isBefore(_date: Date, dateToCompare: Date): boolean { | ||
| 430 | + return _date.getTime() < dateToCompare.getTime(); | ||
| 431 | + } | ||
| 432 | + | ||
| 433 | + /** | ||
| 434 | + * 获取文章发布时间 | ||
| 435 | + * */ | ||
| 436 | + public static getCommentTime(publishTime: number): string { | ||
| 437 | + let currentTime: number = new Date().getTime(); | ||
| 438 | + let timeGap = currentTime - publishTime; | ||
| 439 | + let timeStr = "" | ||
| 440 | + if (timeGap >= 60 * 60 * 1000 * 48) { | ||
| 441 | + let publishYear = new Date(publishTime).getFullYear(); | ||
| 442 | + let currentYear = new Date(currentTime).getFullYear(); | ||
| 443 | + if (publishYear == currentYear) { | ||
| 444 | + timeStr = this.formatDate(publishTime, DateTimeUtils.PATTERN_DATE_SLASH_WITHOUT_YEAR2) | ||
| 445 | + } else { | ||
| 446 | + timeStr = this.formatDate(publishTime) | ||
| 447 | + } | ||
| 448 | + } else if (timeGap > 60 * 60 * 1000 * 24) { | ||
| 449 | + timeStr = Math.floor(timeGap / (60 * 60 * 1000 * 24)) + "天前"; | ||
| 450 | + } else if (timeGap > 60 * 60 * 1000) { // 1小时-24小时 | ||
| 451 | + timeStr = Math.floor(timeGap / (60 * 60 * 1000)) + "小时前"; | ||
| 452 | + } else if (timeGap > 60 * 1000) { // 1分钟-59分钟 | ||
| 453 | + timeStr = Math.floor(timeGap / (60 * 1000)) + "分钟前"; | ||
| 454 | + } else { // 1秒钟-59秒钟 | ||
| 455 | + timeStr = "刚刚"; | ||
| 456 | + } | ||
| 457 | + return timeStr; | ||
| 458 | + } | ||
| 459 | + | ||
| 460 | +} | ||
| 461 | + | ||
| 462 | +// const dateTimeUtils = new DateTimeUtils() |
| 1 | +import util from '@ohos.util'; | ||
| 2 | +import deviceInfo from '@ohos.deviceInfo'; | ||
| 3 | +import { SPHelper } from './SPHelper'; | ||
| 4 | + | ||
| 5 | +const TAG = 'DeviceUtil'; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 与(硬件)设备相关(不可改变或不可升级)属性或操作 | ||
| 9 | + */ | ||
| 10 | +export class DeviceUtil { | ||
| 11 | + static clientId() { | ||
| 12 | + let uuid = SPHelper.default.getSync("clientId", ''); | ||
| 13 | + if (uuid == '') { | ||
| 14 | + uuid = util.generateRandomUUID(); | ||
| 15 | + SPHelper.default.saveSync("clientId", uuid); | ||
| 16 | + } | ||
| 17 | + return uuid.toString(); | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 返回设备厂家名称 | ||
| 22 | + * HUAWEI | ||
| 23 | + * @returns | ||
| 24 | + */ | ||
| 25 | + static getManufacture(): string { | ||
| 26 | + return deviceInfo.manufacture; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 返回设备品牌名称 | ||
| 31 | + * HUAWEI MATE 40 PRO | ||
| 32 | + * @returns | ||
| 33 | + */ | ||
| 34 | + static getBrand(): string { | ||
| 35 | + return deviceInfo.brand; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 返回认证型号 | ||
| 40 | + * LIO-AL00 | ||
| 41 | + * @returns | ||
| 42 | + */ | ||
| 43 | + static getProductModel(): string { | ||
| 44 | + return deviceInfo.productModel; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * 返回产品版本 | ||
| 49 | + * OpenHarmony-3.2.6.5(Beta2) | ||
| 50 | + * @returns | ||
| 51 | + */ | ||
| 52 | + static getDisplayVersion(): string { | ||
| 53 | + return deviceInfo.productModel; | ||
| 54 | + } | ||
| 55 | +} |
| 1 | +import display from '@ohos.display'; | ||
| 2 | +import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant'; | ||
| 3 | +import {Logger} from './Logger'; | ||
| 4 | + | ||
| 5 | +const TAG = 'DisplayUtils'; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 设备显示器/Display属性: | ||
| 9 | + * | ||
| 10 | + 手机(HUAWEI Mate 40 Pro & NOH-AN00)-竖屏: | ||
| 11 | + { | ||
| 12 | + "id": 0, | ||
| 13 | + "name": "UNKNOW", | ||
| 14 | + "alive": true, | ||
| 15 | + "state": 0, | ||
| 16 | + "refreshRate": 90, | ||
| 17 | + "rotation": 0, | ||
| 18 | + "width": 1344, // 屏幕显示的实际宽度/(像素个数/以像素px为单位) | ||
| 19 | + "height": 2772, // 屏幕显示的实际高度/(像素个数/以像素px为单位) | ||
| 20 | + "densityDPI": 560, // 实际像素密度(每英寸像素:120/160/240/320/560)PPI,是一个具体的数值 | ||
| 21 | + "orientation": 0, | ||
| 22 | + "densityPixels": 3.5, // 屏幕密度(当像素密度为160时屏幕密度为1.0, 像素比例0.75/1.0/1.5/2.0/3.5) | 缩放因子density = 屏幕像素密度/160, 可用于vp和px转化 | ||
| 23 | + "scaledDensity": 3.5, // 可用于fp和px转化 | ||
| 24 | + "xDPI": 461.3188781738281, | ||
| 25 | + "yDPI": 457.1999816894531 | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + 手机(HUAWEI Mate 40 Pro & NOH-AN00)-横屏: | ||
| 29 | + { | ||
| 30 | + "id": 0, | ||
| 31 | + "name": "UNKNOW", | ||
| 32 | + "alive": true, | ||
| 33 | + "state": 0, | ||
| 34 | + "refreshRate": 90, | ||
| 35 | + "rotation": 1, | ||
| 36 | + "width": 2772, | ||
| 37 | + "height": 1344, | ||
| 38 | + "densityDPI": 560, | ||
| 39 | + "orientation": 1, | ||
| 40 | + "densityPixels": 3.5, | ||
| 41 | + "scaledDensity": 3.5, | ||
| 42 | + "xDPI": 951.47021484375, | ||
| 43 | + "yDPI": 221.67271423339844 | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + Fold手机(HUAWEI Mate X5 & ALT-AL10)-折叠状态-竖屏: | ||
| 47 | + { | ||
| 48 | + "id": 0, | ||
| 49 | + "name": "UNKNOW", | ||
| 50 | + "alive": true, | ||
| 51 | + "state": 0, | ||
| 52 | + "refreshRate": 90, | ||
| 53 | + "rotation": 0, | ||
| 54 | + "width": 1080, | ||
| 55 | + "height": 2504, | ||
| 56 | + "densityDPI": 500, | ||
| 57 | + "orientation": 1, | ||
| 58 | + "densityPixels": 3.125, | ||
| 59 | + "scaledDensity": 3.125, | ||
| 60 | + "xDPI": 173.62025451660156, | ||
| 61 | + "yDPI": 451.0751647949219 | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + Fold手机(HUAWEI Mate X5 & ALT-AL10)-折叠状态-横屏: | ||
| 65 | + { | ||
| 66 | + "id": 0, | ||
| 67 | + "name": "UNKNOW", | ||
| 68 | + "alive": true, | ||
| 69 | + "state": 0, | ||
| 70 | + "refreshRate": 90, | ||
| 71 | + "rotation": 3, | ||
| 72 | + "width": 2504, | ||
| 73 | + "height": 1080, | ||
| 74 | + "densityDPI": 500, | ||
| 75 | + "orientation": 2, | ||
| 76 | + "densityPixels": 3.125, | ||
| 77 | + "scaledDensity": 3.125, | ||
| 78 | + "xDPI": 402.541748046875, | ||
| 79 | + "yDPI": 194.55319213867188 | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + Fold手机(HUAWEI Mate X5 & ALT-AL10)-完全展开状态-竖屏: | ||
| 83 | + { | ||
| 84 | + "id": 0, | ||
| 85 | + "name": "UNKNOW", | ||
| 86 | + "alive": true, | ||
| 87 | + "state": 0, | ||
| 88 | + "refreshRate": 90, | ||
| 89 | + "rotation": 0, | ||
| 90 | + "width": 2224, | ||
| 91 | + "height": 2496, | ||
| 92 | + "densityDPI": 500, | ||
| 93 | + "orientation": 1, | ||
| 94 | + "densityPixels": 3.125, | ||
| 95 | + "scaledDensity": 3.125, | ||
| 96 | + "xDPI": 357.52911376953125, | ||
| 97 | + "yDPI": 449.634033203125 | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + 平板电脑(HUAWEI MatePad Pro & WGR-W09)(2in1设备)-横屏: | ||
| 101 | + { | ||
| 102 | + "id": 0, | ||
| 103 | + "name": "UNKNOW", | ||
| 104 | + "alive": true, | ||
| 105 | + "state": 0, | ||
| 106 | + "refreshRate": 60, | ||
| 107 | + "rotation": 0, | ||
| 108 | + "width": 2560, | ||
| 109 | + "height": 1600, | ||
| 110 | + "densityDPI": 240, | ||
| 111 | + "orientation": 1, | ||
| 112 | + "densityPixels": 1.5, | ||
| 113 | + "scaledDensity": 1.5, | ||
| 114 | + "xDPI": 239.05882263183594, | ||
| 115 | + "yDPI": 239.05882263183594 | ||
| 116 | + } | ||
| 117 | + */ | ||
| 118 | +/** | ||
| 119 | + * 与显示器/display/screen(硬件)设备相关(不可改变或不可升级)属性或操作(应该读取窗口Window的宽高,而不是显示器display的宽高,因为电脑设备的窗口可以动态调整Window窗口大小) | ||
| 120 | + * 屏幕密度是160时,1vp=1px | ||
| 121 | + */ | ||
| 122 | +export class DisplayUtils { | ||
| 123 | + /** | ||
| 124 | + * Get 屏幕显示/display/screen Width(单位vp) | ||
| 125 | + * 手机(HUAWEI Mate 40 Pro & NOH-AN00)-竖屏:width为1344*3.5=384vp | ||
| 126 | + * 手机(HUAWEI Mate 40 Pro & NOH-AN00)-横屏:width为2772*3.5=792vp | ||
| 127 | + * @returns screen width. | ||
| 128 | + */ | ||
| 129 | + public static getDeviceWidth(): number { | ||
| 130 | + let displayObject: display.Display = display.getDefaultDisplaySync(); | ||
| 131 | + // Logger.info(TAG, `getDeviceWidth, displayObject: ${JSON.stringify(displayObject)}`); | ||
| 132 | + let screenWidth = displayObject.width; | ||
| 133 | + let screenDensityDPI = displayObject.densityDPI; | ||
| 134 | + // 像素密度(Pixel Density) | ||
| 135 | + let densityPixels = screenDensityDPI / ConfigurationConstant.ScreenDensity.SCREEN_DENSITY_MDPI | ||
| 136 | + // let densityPixels = displayObject.densityPixels | ||
| 137 | + let deviceWidth = screenWidth / densityPixels; | ||
| 138 | + // Logger.info(TAG, `getDeviceWidth, deviceWidth: ${deviceWidth}`); | ||
| 139 | + return deviceWidth | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + /** | ||
| 143 | + * Get the 显示/display/screen height(单位vp). | ||
| 144 | + * | ||
| 145 | + * @returns screen height. | ||
| 146 | + */ | ||
| 147 | + public static getDeviceHeight(): number { | ||
| 148 | + let displayObject: display.Display = display.getDefaultDisplaySync(); | ||
| 149 | + let screenHeight = displayObject.height; | ||
| 150 | + let screenDensityDPI = displayObject.densityDPI; | ||
| 151 | + // 像素密度(Pixel Density) | ||
| 152 | + let densityPixels = screenDensityDPI / ConfigurationConstant.ScreenDensity.SCREEN_DENSITY_MDPI | ||
| 153 | + // let densityPixels = displayObject.densityPixels | ||
| 154 | + let deviceHeight = screenHeight / densityPixels | ||
| 155 | + // Logger.info(TAG, `getDeviceHeight, deviceHeight: ${deviceHeight}`); // 345.6 // 711.68 | ||
| 156 | + return deviceHeight | ||
| 157 | + } | ||
| 158 | +} |
| 1 | +import { BasicDataSource } from './BasicDataSource'; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 实现/BasicDataSource抽象类,用于懒数据加载 | ||
| 5 | + */ | ||
| 6 | +export class LazyDataSource<T> extends BasicDataSource<T> { | ||
| 7 | + // private dataArray: Array<T> = new Array(); | ||
| 8 | + // private dataArray: Array<string> = new Array("0", "1", "2"); | ||
| 9 | + // private dataArray: string[] = ["0", "1", "2"]; | ||
| 10 | + private dataArray: T[] = []; | ||
| 11 | + | ||
| 12 | + constructor() { | ||
| 13 | + super(); | ||
| 14 | + // for (let i = 0; i < 100; i++) { | ||
| 15 | + // this.dataArray.push(i) | ||
| 16 | + // } | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + // 获取数据总个数 | ||
| 20 | + public totalCount(): number { | ||
| 21 | + return this.dataArray.length; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + // 获取索引对应的Item数据 | ||
| 25 | + public getData(index: number): T { | ||
| 26 | + return this.dataArray[index]; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + // 获取索引对应的Item数据 | ||
| 30 | + public get(index: number): T { | ||
| 31 | + return this.getData(index); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + public getFirst(): T { | ||
| 35 | + return this.getData(0); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public getLast(): T { | ||
| 39 | + return this.getData(this.totalCount() - 1); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + // 获取所有数据 | ||
| 43 | + public getDataArray(): T[] { | ||
| 44 | + return this.dataArray; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + // 增加/插入1个Item/数据,若index为undefined,则在数据尾部增加1个元素;否则,在指定索引(可为负/或大于数组长度)位置插入1个元素 | ||
| 48 | + public addItem(item: T, startPosition?: number): void { | ||
| 49 | + if (startPosition == undefined) { | ||
| 50 | + // 将新元素添加到数组的末尾 | ||
| 51 | + this.dataArray.push(item); | ||
| 52 | + // this.dataArray.splice(this.dataArray.length, 0, item) | ||
| 53 | + this.notifyDataAdd(this.dataArray.length - 1); | ||
| 54 | + } else { | ||
| 55 | + // 从数组中的index位置开始删除0个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。 | ||
| 56 | + // 当index大于等于数组长度时,不删除任何数据,且item加在数组末尾 | ||
| 57 | + // 当index为负数时,其代表从数组后向前的索引位置 | ||
| 58 | + this.dataArray.splice(startPosition, 0, item); | ||
| 59 | + this.notifyDataAdd(startPosition); | ||
| 60 | + } | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public addItems(arr: T[], startPosition?: number): void { | ||
| 64 | + if (startPosition == undefined) { | ||
| 65 | + // 将新元素添加到数组的末尾 | ||
| 66 | + this.dataArray.push(...arr) | ||
| 67 | + for (let index = this.dataArray.length - arr.length; index < this.dataArray.length; index++) { | ||
| 68 | + this.notifyDataAdd(index); | ||
| 69 | + } | ||
| 70 | + } else { | ||
| 71 | + // 从数组中的position位置开始删除0个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。 | ||
| 72 | + // 当index大于等于数组长度时,不删除任何数据,且arr加在数组末尾 | ||
| 73 | + // 当index为负数时,其代表从数组后向前的索引位置 | ||
| 74 | + this.dataArray.splice(startPosition, 0, ...arr); | ||
| 75 | + for (let index = startPosition; index < arr.length; index++) { | ||
| 76 | + this.notifyDataAdd(index); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + // 在数据尾部增加1到多个元素 | ||
| 82 | + public push(...items: T[]): void { | ||
| 83 | + this.dataArray.push(...items) | ||
| 84 | + for (let index = this.dataArray.length - items.length; index < this.dataArray.length; index++) { | ||
| 85 | + this.notifyDataAdd(index); | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + // 在数据尾部增加一个同类型的LazyDataSource | ||
| 90 | + public pushDataSource(dataSource: LazyDataSource<T>): void { | ||
| 91 | + this.push(...dataSource.dataArray) | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + // 在数据尾部增加1个元素 | ||
| 95 | + public addLastItem(item: T): void { | ||
| 96 | + this.addItem(item) | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + // 在数据开头插入1个元素 | ||
| 100 | + public addFirstItem(item: T): void { | ||
| 101 | + // 在数组的开头插入(1个或多个)新元素 | ||
| 102 | + // this.dataArray.unshift(item) | ||
| 103 | + // this.notifyDataAdd(0); | ||
| 104 | + this.addItem(item, 0) | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + // 在第2个元素位置,插入1个元素 | ||
| 108 | + public add2ndItem(item: T): void { | ||
| 109 | + this.addItem(item, 1) | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + // 在第3个元素位置,插入1个元素 | ||
| 113 | + public add3rdItem(item: T): void { | ||
| 114 | + this.addItem(item, 2) | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + // 在第4个元素位置,插入1个元素 | ||
| 118 | + public add4thItem(item: T): void { | ||
| 119 | + this.addItem(item, 3) | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + // 把from位置的item移动到to位置(暂不支持from/to为负数或大于等于数组长度) | ||
| 123 | + public moveItem(from: number, to: number): void { | ||
| 124 | + // 当from/to大于/等于数组长度时; | ||
| 125 | + if (from >= this.dataArray.length) { | ||
| 126 | + from = this.dataArray.length - 1; | ||
| 127 | + } | ||
| 128 | + if (to >= this.dataArray.length) { | ||
| 129 | + to = this.dataArray.length - 1; | ||
| 130 | + } | ||
| 131 | + // 当from/to为负时; | ||
| 132 | + let remainderFrom = from % this.dataArray.length | ||
| 133 | + if (remainderFrom < 0) { | ||
| 134 | + from = remainderFrom + this.dataArray.length | ||
| 135 | + } | ||
| 136 | + let remainderTo = to % this.dataArray.length | ||
| 137 | + if (remainderTo < 0) { | ||
| 138 | + to = remainderTo + this.dataArray.length | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + // 1.把from位置元素提出暂存 | ||
| 142 | + let tempFrom: T = this.dataArray[from]; | ||
| 143 | + // 2.把to位置元素覆盖from位置元素, | ||
| 144 | + let tempTo: T = this.dataArray[to]; | ||
| 145 | + this.updateItem(tempTo, from) | ||
| 146 | + // 3.把暂存的from位置元素覆盖to位置元素 | ||
| 147 | + this.updateItem(tempFrom, to) | ||
| 148 | + this.notifyDataMove(from, to); | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + // 删除index指定索引位置的元素 | ||
| 152 | + public deleteItem(index?: number): void { | ||
| 153 | + if (index == undefined) { | ||
| 154 | + // 删除数组的最后1个元素(倒数第1个元素) | ||
| 155 | + // this.dataArray.pop() | ||
| 156 | + this.dataArray.splice(-1, 1) | ||
| 157 | + this.notifyDataDelete(this.dataArray.length); | ||
| 158 | + } else { | ||
| 159 | + // 从数组中的index位置开始,删除1个元素 | ||
| 160 | + // 当index大于等于数组长度时,不删除任何数据 | ||
| 161 | + // 当index为负数时,其代表从数组后向前的索引位置 | ||
| 162 | + this.dataArray.splice(index, 1); | ||
| 163 | + this.notifyDataDelete(index); | ||
| 164 | + } | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + // 删除最后1个元素 | ||
| 168 | + public pop(): void { | ||
| 169 | + this.deleteItem() | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + // 删除最后1个元素 | ||
| 173 | + public deleteLastItem(): void { | ||
| 174 | + this.deleteItem() | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + // 删除第1个元素 | ||
| 178 | + public deleteFirstItem(): void { | ||
| 179 | + this.deleteItem(0) | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + // 删除第1个元素 | ||
| 183 | + public delete1stItem(): void { | ||
| 184 | + this.deleteItem(0) | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + // 删除第2个元素 | ||
| 188 | + public delete2ndItem(): void { | ||
| 189 | + this.deleteItem(1) | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + // 删除第3个元素 | ||
| 193 | + public delete3rdItem(): void { | ||
| 194 | + this.deleteItem(2) | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + // 删除第4个元素 | ||
| 198 | + public delete4thItem(): void { | ||
| 199 | + this.deleteItem(3) | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + // 修改/更新index指定索引位置的元素 | ||
| 203 | + public updateItem(item: T, index?: number): void { | ||
| 204 | + if (index == undefined || index >= this.dataArray.length) { | ||
| 205 | + // 当不传index或index大于等于数组长度时,修改/更新数组的最后1个元素 | ||
| 206 | + this.dataArray.splice(this.dataArray.length - 1, 1, item); | ||
| 207 | + this.notifyDataChange(this.dataArray.length); | ||
| 208 | + } else { | ||
| 209 | + // 从数组中的index位置开始,删除1个元素 | ||
| 210 | + // 当index为负数时,其代表从数组后向前的索引位置 | ||
| 211 | + this.dataArray.splice(index, 1, item); | ||
| 212 | + this.notifyDataChange(index); | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + // 修改/更新最后1个元素 | ||
| 217 | + public updateLastItem(item: T): void { | ||
| 218 | + this.updateItem(item) | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + // 修改/更新第1个元素 | ||
| 222 | + public updateFirstItem(item: T): void { | ||
| 223 | + this.updateItem(item, 0) | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + // 修改/更新第1个元素 | ||
| 227 | + public update2ndItem(item: T): void { | ||
| 228 | + this.updateItem(item, 0) | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + // 修改/更新第2个元素 | ||
| 232 | + public update1stItem(item: T): void { | ||
| 233 | + this.updateItem(item, 1) | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + // 修改/更新第3个元素 | ||
| 237 | + public update3rdItem(item: T): void { | ||
| 238 | + this.updateItem(item, 2) | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + // 修改/更新第4个元素 | ||
| 242 | + public update4thItem(item: T): void { | ||
| 243 | + this.updateItem(item, 3) | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + // 清空数组 | ||
| 247 | + public clear(): void { | ||
| 248 | + this.replaceAll() | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + // 把数据全部删除,再添加全部新元素 | ||
| 252 | + public replaceAll(...items: T[]): void { | ||
| 253 | + // 从数组中的0位置开始删除dataArray.length个元素,并在同一位置插入((1个或多个))新元素,返回已删除的元素。 | ||
| 254 | + this.dataArray.splice(0, this.dataArray.length, ...items); | ||
| 255 | + this.notifyDataReload() | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + // 获取指定元素的下标 | ||
| 259 | + public getIndexOf(element: T): number { | ||
| 260 | + for (let index = 0; index < this.dataArray.length; index++) { | ||
| 261 | + if (this.dataArray[index] == element) { | ||
| 262 | + return index | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + return -1 | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + public isEmpty(): boolean { | ||
| 269 | + return this.dataArray.length == 0 | ||
| 270 | + } | ||
| 271 | + | ||
| 272 | + public isNotEmpty(): boolean { | ||
| 273 | + return this.dataArray.length > 0 | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + public sort(comparator: (firstValue: T, secondValue: T) => number): void { | ||
| 277 | + this.dataArray.sort(comparator) | ||
| 278 | + } | ||
| 279 | +} |
| 1 | +import hilog from '@ohos.hilog'; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * Log level define | ||
| 5 | + * | ||
| 6 | + * @syscap SystemCapability.HiviewDFX.HiLog | ||
| 7 | + */ | ||
| 8 | +enum LogLevel { | ||
| 9 | + DEBUG = 3, | ||
| 10 | + INFO = 4, | ||
| 11 | + WARN = 5, | ||
| 12 | + ERROR = 6, | ||
| 13 | + FATAL = 7 | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * Common log for all features. | ||
| 18 | + * | ||
| 19 | + * @param {string} prefix Identifies the log tag. | ||
| 20 | + */ | ||
| 21 | +export class Logger { | ||
| 22 | + private static domain: number = 0xFF00; | ||
| 23 | + private static prefix: string = 'SightApp'; | ||
| 24 | + private static format: string = `%{public}s, %{public}s`; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * constructor. | ||
| 28 | + * | ||
| 29 | + * @param Prefix Identifies the log tag. | ||
| 30 | + * @param domain Domain Indicates the service domain, which is a hexadecimal integer ranging from 0x0 to 0xFFFFF. | ||
| 31 | + */ | ||
| 32 | + constructor(prefix: string = 'SightApp', domain: number = 0xFF00) { | ||
| 33 | + Logger.prefix = prefix; | ||
| 34 | + Logger.domain = domain; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + static debug(...args: string[]) { | ||
| 38 | + hilog.debug(Logger.domain, Logger.prefix, Logger.format, args); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + static info(...args: string[]) { | ||
| 42 | + hilog.info(Logger.domain, Logger.prefix, Logger.format, args); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + static warn(...args: string[]) { | ||
| 46 | + hilog.warn(Logger.domain, Logger.prefix, Logger.format, args); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + static error(...args: string[]) { | ||
| 50 | + hilog.error(Logger.domain, Logger.prefix, Logger.format, args); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + static fatal(...args: string[]) { | ||
| 54 | + hilog.fatal(Logger.domain, Logger.prefix, Logger.format, args); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + static isLoggable(level: LogLevel) { | ||
| 58 | + hilog.isLoggable(Logger.domain, Logger.prefix, level); | ||
| 59 | + } | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +export default new Logger('SightApp', 0xFF00) |
| 1 | +import buffer from '@ohos.buffer'; | ||
| 2 | +import { BusinessError } from '@ohos.base'; | ||
| 3 | +import { Logger } from './Logger'; | ||
| 4 | + | ||
| 5 | +const TAG = "ResourcesUtils"; | ||
| 6 | + | ||
| 7 | +// 默认针对entry/src/main/resources/rawfile目录下的文件: | ||
| 8 | +const JSON_FILE_NAME = "agconnect-services.json"; | ||
| 9 | + | ||
| 10 | +export class ResourcesUtils { | ||
| 11 | + /** | ||
| 12 | + * 获取资源字符串内容 | ||
| 13 | + * @param context | ||
| 14 | + * @param filename 仅文件名(不包含路径,文件在src\main\resources\rawfile下),如:"agconnect-services.json",test.xml, | ||
| 15 | + * @returns text 字符串 | ||
| 16 | + */ | ||
| 17 | + static getResourcesText(context: Context, filename: string): Promise<string> { | ||
| 18 | + return new Promise((success, error) => { | ||
| 19 | + Logger.info(TAG, "ResourcesUtils getResourcesText filename:" + filename); | ||
| 20 | + context.resourceManager.getRawFileContent(filename).then((content: Uint8Array) => { | ||
| 21 | + if (!content) { | ||
| 22 | + Logger.warn(TAG, 'getResourcesText then content is empty'); | ||
| 23 | + error("file is empty"); | ||
| 24 | + return | ||
| 25 | + } | ||
| 26 | + try { | ||
| 27 | + let text = buffer.from(content).toString("utf8"); | ||
| 28 | + if (text) { | ||
| 29 | + Logger.info(TAG, "getResourcesText then text:" + text); | ||
| 30 | + success(text); | ||
| 31 | + } else { | ||
| 32 | + Logger.warn(TAG, "getResourcesText then text is empty"); | ||
| 33 | + error("resources file text is empty"); | ||
| 34 | + } | ||
| 35 | + } catch (err) { | ||
| 36 | + // 转换异常 | ||
| 37 | + Logger.error(TAG, `getResourcesText catch err.: ${err}`); | ||
| 38 | + } | ||
| 39 | + }).catch((err: Error) => { | ||
| 40 | + Logger.error(TAG, `getResourcesText getRawFileContent catch, error.name : ${err.name}, error.message:${err.message}`); | ||
| 41 | + error(err); | ||
| 42 | + }) | ||
| 43 | + }) | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 获取资源字符串内容 | ||
| 48 | + * @param context | ||
| 49 | + * @param filename 仅文件名(不包含路径,文件在src\main\resources\rawfile下),如:"agconnect-services.json",test.xml, | ||
| 50 | + * @returns text 字符串 | ||
| 51 | + */ | ||
| 52 | + static getResourcesTextSync(context: Context, filename: string): string | null { | ||
| 53 | + Logger.info(TAG, `getResourcesTextSync filename: ${filename}`); | ||
| 54 | + try { | ||
| 55 | + let content: Uint8Array = context.resourceManager.getRawFileContentSync(filename) | ||
| 56 | + if (!content) { | ||
| 57 | + Logger.warn(TAG, 'getResourcesTextSync content is empty'); | ||
| 58 | + return null | ||
| 59 | + } | ||
| 60 | + let text = buffer.from(content).toString("utf8"); | ||
| 61 | + if (text) { | ||
| 62 | + // Logger.info(TAG, "getRawFileContentSync text:" + text); | ||
| 63 | + } else { | ||
| 64 | + Logger.warn(TAG, "getRawFileContentSync text is empty"); | ||
| 65 | + } | ||
| 66 | + return text; | ||
| 67 | + } catch (err) { | ||
| 68 | + // 转换异常 | ||
| 69 | + Logger.error(TAG, `getResourcesText catch err.: ${err}`); | ||
| 70 | + return null; | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * 获取资源文件并转为JSON | ||
| 76 | + * | ||
| 77 | + * @param appContext 上下文 | ||
| 78 | + * @param filename 仅文件名(不包含路径,文件在src\main\resources\rawfile下),如:"agconnect-services.json" | ||
| 79 | + * SubscribeListData.json | ||
| 80 | + * @returns JSON Object | ||
| 81 | + * | ||
| 82 | + * 调用方式: | ||
| 83 | + * let compRes: MGHttp.ResponseDTO<BodyComponent> = await ResourcesUtils.getResourcesJson<MGHttp.ResponseDTO<BodyComponent>>(context, 'model/componentList.json'); | ||
| 84 | + */ | ||
| 85 | + static getResourcesJson<R>(context: Context, filename: string): Promise<R> { | ||
| 86 | + Logger.info(TAG, `getResourcesJson filename: ${filename}`); | ||
| 87 | + return new Promise<R>((resolve, reject) => { | ||
| 88 | + ResourcesUtils.getResourcesText(context, filename) | ||
| 89 | + .then((text: string) => { | ||
| 90 | + try { | ||
| 91 | + // let config: R = JSON.parse(text) | ||
| 92 | + let config: R = JSON.parse(text) as R; | ||
| 93 | + if (config) { | ||
| 94 | + Logger.info(TAG, "getResourcesJson parse JSON file success."); | ||
| 95 | + // Logger.info(TAG, `getResourcesJson config : ${JSON.stringify(config)}`); | ||
| 96 | + resolve(config); | ||
| 97 | + } else { | ||
| 98 | + reject("getResourcesJson parse JSON file result is empty"); | ||
| 99 | + } | ||
| 100 | + } catch (err) { | ||
| 101 | + // json解析异常 | ||
| 102 | + Logger.error(TAG, `getResourcesJson catch parse failed.: ${err}`); | ||
| 103 | + reject(err) | ||
| 104 | + } | ||
| 105 | + }) | ||
| 106 | + .catch((error: BusinessError) => { | ||
| 107 | + reject(error) | ||
| 108 | + }) | ||
| 109 | + }) | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + static getResourcesJsonSync<R>(context: Context, filename: string): R | null { | ||
| 113 | + Logger.info(TAG, `getResourcesJsonSync filename: ${filename}`); | ||
| 114 | + let text = ResourcesUtils.getResourcesTextSync(context, filename) | ||
| 115 | + if (!text) { | ||
| 116 | + Logger.warn(TAG, `getResourcesJsonSync file result is empty`); | ||
| 117 | + return null | ||
| 118 | + } | ||
| 119 | + try { | ||
| 120 | + // let config: R = JSON.parse(text) | ||
| 121 | + let config: R = JSON.parse(text) as R; | ||
| 122 | + return config | ||
| 123 | + } catch (err) { | ||
| 124 | + // json解析异常 | ||
| 125 | + Logger.error(TAG, `getResourcesJsonSync catch parse failed.: ${err}`); | ||
| 126 | + return null | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | +} |
| 1 | +import data_preferences from '@ohos.data.preferences'; | ||
| 2 | + | ||
| 3 | +/* | ||
| 4 | +// SPHelper.default.get("key1", "defValue1").then((value1) => { | ||
| 5 | +// this.message = value1.toString(); | ||
| 6 | +// }) | ||
| 7 | + | ||
| 8 | +// let value2: string = await SPHelper.default.get("key2", "defValue2"); | ||
| 9 | +// this.message = result; | ||
| 10 | +* | ||
| 11 | +* 单例模式 | ||
| 12 | + */ | ||
| 13 | +export class SPHelper { | ||
| 14 | + private static context: Context; | ||
| 15 | + private static spFilename: string = '__SPHelper'; | ||
| 16 | + | ||
| 17 | + static init(context: Context) { | ||
| 18 | + SPHelper.context = context; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + static setSpFilename(spFilename: string) { | ||
| 22 | + SPHelper.spFilename = spFilename; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + // 静态属性 | ||
| 26 | + static default: SPHelper = new SPHelper(); | ||
| 27 | + | ||
| 28 | + // 私有构造函数 | ||
| 29 | + private constructor() { | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + private async getVideoPreferences(): Promise<data_preferences.Preferences> { | ||
| 33 | + let preferences: data_preferences.Preferences = await data_preferences.getPreferences(SPHelper.context, SPHelper.spFilename); | ||
| 34 | + return preferences; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + private getVideoPreferencesSync(): data_preferences.Preferences { | ||
| 38 | + let options: data_preferences.Options = { name: SPHelper.spFilename }; | ||
| 39 | + let preferences: data_preferences.Preferences = data_preferences.getPreferencesSync(SPHelper.context, options); | ||
| 40 | + return preferences; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + async save(key: string, value: data_preferences.ValueType) { | ||
| 44 | + const preferences: data_preferences.Preferences = await this.getVideoPreferences(); | ||
| 45 | + await preferences.put(key, value) | ||
| 46 | + await preferences.flush() | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + saveSync(key: string, value: data_preferences.ValueType) { | ||
| 50 | + const preferences: data_preferences.Preferences = this.getVideoPreferencesSync(); | ||
| 51 | + preferences.putSync(key, value) | ||
| 52 | + preferences.flush() // todo:Asynchronously | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + async get(key: string, defValue: data_preferences.ValueType): Promise<data_preferences.ValueType> { | ||
| 56 | + const preferences: data_preferences.Preferences = await this.getVideoPreferences(); | ||
| 57 | + return await preferences.get(key, defValue); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + getSync(key: string, defValue: data_preferences.ValueType): data_preferences.ValueType { | ||
| 61 | + const preferences: data_preferences.Preferences = this.getVideoPreferencesSync(); | ||
| 62 | + return preferences.getSync(key, defValue); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + async has(key: string): Promise<boolean> { | ||
| 66 | + const preferences: data_preferences.Preferences = await this.getVideoPreferences(); | ||
| 67 | + return await preferences.has(key); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + hasSync(key: string): boolean { | ||
| 71 | + const preferences: data_preferences.Preferences = this.getVideoPreferencesSync(); | ||
| 72 | + return preferences.hasSync(key); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + async delete(key: string) { | ||
| 76 | + const preferences: data_preferences.Preferences = await this.getVideoPreferences(); | ||
| 77 | + preferences.delete(key).then(async () => { | ||
| 78 | + await preferences.flush(); | ||
| 79 | + }).catch((err: Error) => { | ||
| 80 | + // Logger.error(TAG, 'Failed to delete the key. Cause: ' + err); | ||
| 81 | + }); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + deleteSync(key: string) { | ||
| 85 | + const preferences: data_preferences.Preferences = this.getVideoPreferencesSync(); | ||
| 86 | + preferences.deleteSync(key) | ||
| 87 | + preferences.flush(); // todo:Asynchronously | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + async clearSync() { | ||
| 91 | + this.getVideoPreferences().then(async (preferences: data_preferences.Preferences) => { | ||
| 92 | + preferences.clearSync() | ||
| 93 | + await preferences.flush() | ||
| 94 | + }).catch((err: Error) => { | ||
| 95 | + // Logger.error(TAG, 'get the preferences failed, Cause: ' + err); | ||
| 96 | + }); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + // clearSync() { | ||
| 100 | + // let preferences: data_preferences.Preferences = this.getVideoPreferencesSync() | ||
| 101 | + // preferences.clearSync() | ||
| 102 | + // preferences.flush() | ||
| 103 | + // } | ||
| 104 | +} |
| 1 | +const SLEEP_TIME: number = 10; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * StringUtils class. | ||
| 5 | + */ | ||
| 6 | +export class StringUtils { | ||
| 7 | + /** | ||
| 8 | + * The String utils tag. | ||
| 9 | + */ | ||
| 10 | + private static readonly TAG: string = 'StringUtils'; | ||
| 11 | + // 评分-整数或浮点数 | ||
| 12 | + private static readonly SCORE_REG_EXP = RegExp(/^(\d+)(\.\d+)?$/); | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * Check string is empty. | ||
| 16 | + * | ||
| 17 | + * @param {object} any | ||
| 18 | + * @return {boolean} true(empty) | ||
| 19 | + */ | ||
| 20 | + static isEmpty(...params: any): boolean { | ||
| 21 | + if (params.length === 0) { | ||
| 22 | + return true; | ||
| 23 | + } | ||
| 24 | + for (const param of params) { | ||
| 25 | + if (!param) { // param === undefined || param === null || param === ''; | ||
| 26 | + return true; | ||
| 27 | + } | ||
| 28 | + } | ||
| 29 | + return false; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Check obj is not empty. | ||
| 34 | + * | ||
| 35 | + * @param {object} obj | ||
| 36 | + * @return {boolean} true(not empty) | ||
| 37 | + */ | ||
| 38 | + static isNotEmpty(obj: any): boolean { | ||
| 39 | + // return (obj && obj !== ''); | ||
| 40 | + // 或 | ||
| 41 | + return (obj !== undefined && obj !== null && obj !== ''); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + static isObject(value: any): boolean { | ||
| 45 | + return Object.prototype.toString.call(value) === '[object Object]'; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + static isNotNullObject(value: unknown): boolean { | ||
| 49 | + return value !== null ? typeof value === 'object' : false; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + static isNullOrUndefined(value: any): boolean { | ||
| 53 | + return value === undefined || value === null; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + static isFunction(object: any): boolean { | ||
| 57 | + return typeof object === 'function'; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + static isValidObject(objectList: any): boolean { | ||
| 61 | + if (!objectList || typeof objectList !== 'object' | ||
| 62 | + || objectList.constructor.name === 'Object') { | ||
| 63 | + return false; | ||
| 64 | + } | ||
| 65 | + return true; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + static isClass(object: any): boolean { | ||
| 69 | + if (StringUtils.isFunction(object)) { | ||
| 70 | + const prototype = object.prototype; | ||
| 71 | + if (!StringUtils.isNotNullObject(prototype)) { | ||
| 72 | + return false; | ||
| 73 | + } | ||
| 74 | + const constructor = prototype.constructor; | ||
| 75 | + if (StringUtils.isFunction(constructor)) { | ||
| 76 | + return true; | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + return false; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + static getClassName(clz: any): string { | ||
| 83 | + if (StringUtils.isNullOrUndefined(clz)) { | ||
| 84 | + return clz; | ||
| 85 | + } | ||
| 86 | + let input = clz; | ||
| 87 | + if (!StringUtils.isClass(input)) { | ||
| 88 | + input = clz.constructor; | ||
| 89 | + } | ||
| 90 | + return input.className ? input.className : input.name; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + static hash(value: string | number): string { | ||
| 94 | + const str = '' + value; | ||
| 95 | + let hash = 5381; | ||
| 96 | + let index = str.length; | ||
| 97 | + while (index) { | ||
| 98 | + hash = (hash * 33) ^ str.charCodeAt(--index); | ||
| 99 | + } | ||
| 100 | + return '' + (hash >>> 0); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + static parseNumber(input: string): number { | ||
| 104 | + // let input: string = '135' // 135 | ||
| 105 | + // let input: string = '135T' // NaN | ||
| 106 | + // let input: string = 'ytr' // NaN | ||
| 107 | + // let input: string = '' // 0 | ||
| 108 | + // let input: string = null // 0 | ||
| 109 | + // let input: string = undefined // NaN | ||
| 110 | + const parsedInt = Number(input) | ||
| 111 | + if (!isNaN(parsedInt)) { | ||
| 112 | + return parsedInt | ||
| 113 | + } else { | ||
| 114 | + return 0 | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + static async sleep(times: number): Promise<void> { | ||
| 119 | + if (!times) { | ||
| 120 | + times = SLEEP_TIME; | ||
| 121 | + } | ||
| 122 | + await new Promise((res) => setTimeout(res, times)) // .then().catch().finally(); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + static isScore(text: string): boolean { | ||
| 126 | + return StringUtils.SCORE_REG_EXP.test(text); | ||
| 127 | + } | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +// export default new StringUtils(); |
| 1 | +import deviceInfo from '@ohos.deviceInfo'; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 与鸿蒙系统(软件)设备相关(可改变或可升级)属性或操作 | ||
| 5 | + */ | ||
| 6 | +export class SystemUtils { | ||
| 7 | + /** | ||
| 8 | + * 返回AGC格式的系统名称 | ||
| 9 | + * OpenHarmony 3.2.6.5(Beta2) | ||
| 10 | + */ | ||
| 11 | + static getOsFullName(): string { | ||
| 12 | + // OpenHarmony-3.2.6.5(Beta2) | ||
| 13 | + let fullName = deviceInfo.osFullName.split('-'); | ||
| 14 | + if (fullName && fullName.length >= 1) { | ||
| 15 | + return fullName[0] + ' ' + fullName[1]; | ||
| 16 | + } | ||
| 17 | + return ''; | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 返回系统空闲存储空间,TODO: | ||
| 22 | + * @returns number | ||
| 23 | + */ | ||
| 24 | + static getFreeBytes(): number { | ||
| 25 | + return 0; | ||
| 26 | + } | ||
| 27 | +} |
| 1 | +import prompt from '@ohos.promptAction' | ||
| 2 | + | ||
| 3 | +export class ToastUtils { | ||
| 4 | + private static longToastTime: number = 3000 | ||
| 5 | + private static shortToastTime: number = 1000 | ||
| 6 | + | ||
| 7 | + static showToast(message: ResourceStr, duration: number) { | ||
| 8 | + prompt.showToast({ message: message, duration: duration }) | ||
| 9 | + } | ||
| 10 | + | ||
| 11 | + static shortToast(message: ResourceStr) { | ||
| 12 | + ToastUtils.showToast(message, ToastUtils.shortToastTime) | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + static longToast(message: ResourceStr) { | ||
| 16 | + ToastUtils.showToast(message, ToastUtils.longToastTime) | ||
| 17 | + } | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +// export default new ToastUtils() |
| 1 | +import window from '@ohos.window'; | ||
| 2 | +import { BusinessError } from '@ohos.base'; | ||
| 3 | +import deviceInfo from '@ohos.deviceInfo' | ||
| 4 | +import display from '@ohos.display'; | ||
| 5 | + | ||
| 6 | +export class Size { | ||
| 7 | + width: number = 0 | ||
| 8 | + height: number = 0 | ||
| 9 | + | ||
| 10 | + constructor(width: number, height: number) { | ||
| 11 | + this.width = width; | ||
| 12 | + this.height = height; | ||
| 13 | + } | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +export class WindowModel { | ||
| 17 | + private windowStage?: window.WindowStage; | ||
| 18 | + | ||
| 19 | + static shared: WindowModel = new WindowModel() | ||
| 20 | + | ||
| 21 | + static TAG = "WindowModel"; | ||
| 22 | + | ||
| 23 | + setWindowStage(windowStage: window.WindowStage) { | ||
| 24 | + this.windowStage = windowStage; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + setMainWindowFullScreen(fullScreen: boolean) { | ||
| 28 | + if (deviceInfo.deviceType != "phone") { | ||
| 29 | + return | ||
| 30 | + } | ||
| 31 | + if (this.windowStage === undefined) { | ||
| 32 | + return; | ||
| 33 | + } | ||
| 34 | + this.windowStage.getMainWindow((err, windowClass: window.Window) => { | ||
| 35 | + if (err.code) { | ||
| 36 | + return; | ||
| 37 | + } | ||
| 38 | + windowClass.setWindowLayoutFullScreen(fullScreen, (err) => { | ||
| 39 | + if (err.code) { | ||
| 40 | + return; | ||
| 41 | + } | ||
| 42 | + }); | ||
| 43 | + windowClass.setWindowSystemBarEnable(fullScreen ? [] : ['status', 'navigation'], (err) => { | ||
| 44 | + if (err.code) { | ||
| 45 | + return; | ||
| 46 | + } | ||
| 47 | + }); | ||
| 48 | + }); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + getWindowSize(): Promise<Size> { | ||
| 52 | + return new Promise((resolve, reject) => { | ||
| 53 | + if (!this.windowStage) { | ||
| 54 | + let dis = display.getDefaultDisplaySync(); | ||
| 55 | + reject(new Size(dis.width, dis.height)) | ||
| 56 | + return; | ||
| 57 | + } | ||
| 58 | + let rect = this.windowStage.getMainWindowSync().getWindowProperties().windowRect; | ||
| 59 | + resolve(new Size(rect.width, rect.height)); | ||
| 60 | + }); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + setWindowKeepScreenOn(isKeepScreenOn: boolean) { | ||
| 64 | + this.windowStage?.getMainWindow((err, windowClass: window.Window) => { | ||
| 65 | + windowClass.setWindowKeepScreenOn(isKeepScreenOn, (err: BusinessError) => { | ||
| 66 | + const errCode: number = err.code; | ||
| 67 | + if (errCode) { | ||
| 68 | + console.error(WindowModel.TAG +'设置屏幕常亮:' + isKeepScreenOn + ',失败: ' + JSON.stringify(err)); | ||
| 69 | + return; | ||
| 70 | + } | ||
| 71 | + console.info(WindowModel.TAG +'设置屏幕常亮:' + isKeepScreenOn + ",成功"); | ||
| 72 | + }) | ||
| 73 | + }) | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * 设置窗口的显示方向属性 | ||
| 78 | + * @param orientation | ||
| 79 | + */ | ||
| 80 | + setPreferredOrientation(orientation: window.Orientation): Promise<void> { | ||
| 81 | + return new Promise((resolve, reject) => { | ||
| 82 | + if (!this.windowStage) { | ||
| 83 | + console.error('Failed, the main window is empty'); | ||
| 84 | + reject("Failed, the main window is empty") | ||
| 85 | + return; | ||
| 86 | + } | ||
| 87 | + this.windowStage.getMainWindow((err: BusinessError, windowClass: window.Window) => { | ||
| 88 | + if (err.code) { | ||
| 89 | + console.error('Failed to obtain the main window. Cause: ' + err.message); | ||
| 90 | + reject(err) | ||
| 91 | + return; | ||
| 92 | + } | ||
| 93 | + // 2.设置窗口的显示方向属性,使用Promise异步回调。 | ||
| 94 | + windowClass.setPreferredOrientation(orientation).then(() => { | ||
| 95 | + console.info('Succeeded in setting the window orientation.'); | ||
| 96 | + resolve() | ||
| 97 | + }).catch((err: BusinessError) => { | ||
| 98 | + console.error('Failed to set the window orientation. Cause: ' + err.message); | ||
| 99 | + reject(err) | ||
| 100 | + }); | ||
| 101 | + }); | ||
| 102 | + }) | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + |
| 1 | +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; | ||
| 2 | + | ||
| 3 | +export default function localUnitTest() { | ||
| 4 | + describe('localUnitTest',() => { | ||
| 5 | + // Defines a test suite. Two parameters are supported: test suite name and test suite function. | ||
| 6 | + beforeAll(() => { | ||
| 7 | + // Presets an action, which is performed only once before all test cases of the test suite start. | ||
| 8 | + // This API supports only one parameter: preset action function. | ||
| 9 | + }); | ||
| 10 | + beforeEach(() => { | ||
| 11 | + // Presets an action, which is performed before each unit test case starts. | ||
| 12 | + // The number of execution times is the same as the number of test cases defined by **it**. | ||
| 13 | + // This API supports only one parameter: preset action function. | ||
| 14 | + }); | ||
| 15 | + afterEach(() => { | ||
| 16 | + // Presets a clear action, which is performed after each unit test case ends. | ||
| 17 | + // The number of execution times is the same as the number of test cases defined by **it**. | ||
| 18 | + // This API supports only one parameter: clear action function. | ||
| 19 | + }); | ||
| 20 | + afterAll(() => { | ||
| 21 | + // Presets a clear action, which is performed after all test cases of the test suite end. | ||
| 22 | + // This API supports only one parameter: clear action function. | ||
| 23 | + }); | ||
| 24 | + it('assertContain', 0, () => { | ||
| 25 | + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. | ||
| 26 | + let a = 'abc'; | ||
| 27 | + let b = 'b'; | ||
| 28 | + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. | ||
| 29 | + expect(a).assertContain(b); | ||
| 30 | + expect(a).assertEqual(a); | ||
| 31 | + }); | ||
| 32 | + }); | ||
| 33 | +} |
sight_harmony/commons/wdNetwork/.gitignore
0 → 100644
sight_harmony/commons/wdNetwork/Index.ets
0 → 100644
| 1 | +{ | ||
| 2 | + "apiType": "stageMode", | ||
| 3 | + "buildOption": { | ||
| 4 | + "arkOptions": { | ||
| 5 | + // "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */ | ||
| 6 | + } | ||
| 7 | + }, | ||
| 8 | + "buildOptionSet": [ | ||
| 9 | + { | ||
| 10 | + "name": "release", | ||
| 11 | + "arkOptions": { | ||
| 12 | + "obfuscation": { | ||
| 13 | + "ruleOptions": { | ||
| 14 | + "enable": true, | ||
| 15 | + "files": [ | ||
| 16 | + "./obfuscation-rules.txt" | ||
| 17 | + ] | ||
| 18 | + } | ||
| 19 | + } | ||
| 20 | + } | ||
| 21 | + }, | ||
| 22 | + ], | ||
| 23 | + "targets": [ | ||
| 24 | + { | ||
| 25 | + "name": "default" | ||
| 26 | + } | ||
| 27 | + ] | ||
| 28 | +} |
| 1 | +# Define project specific obfuscation rules here. | ||
| 2 | +# You can include the obfuscation configuration files in the current module's build-profile.json5. | ||
| 3 | +# | ||
| 4 | +# For more details, see | ||
| 5 | +# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md | ||
| 6 | + | ||
| 7 | +# Obfuscation options: | ||
| 8 | +# -disable-obfuscation: disable all obfuscations | ||
| 9 | +# -enable-property-obfuscation: obfuscate the property names | ||
| 10 | +# -enable-toplevel-obfuscation: obfuscate the names in the global scope | ||
| 11 | +# -compact: remove unnecessary blank spaces and all line feeds | ||
| 12 | +# -remove-log: remove all console.* statements | ||
| 13 | +# -print-namecache: print the name cache that contains the mapping from the old names to new names | ||
| 14 | +# -apply-namecache: reuse the given cache file | ||
| 15 | + | ||
| 16 | +# Keep options: | ||
| 17 | +# -keep-property-name: specifies property names that you want to keep | ||
| 18 | +# -keep-global-name: specifies names that you want to keep in the global scope |
| 1 | +{ | ||
| 2 | + "meta": { | ||
| 3 | + "stableOrder": true | ||
| 4 | + }, | ||
| 5 | + "lockfileVersion": 3, | ||
| 6 | + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", | ||
| 7 | + "specifiers": { | ||
| 8 | + "@ohos/axios@^2.1.1": "@ohos/axios@2.1.1", | ||
| 9 | + "wdConstant@../../../../commons/wdConstant": "wdConstant@../wdConstant", | ||
| 10 | + "wdKit@../../../../commons/wdKit": "wdKit@../wdKit" | ||
| 11 | + }, | ||
| 12 | + "packages": { | ||
| 13 | + "@ohos/axios@2.1.1": { | ||
| 14 | + "name": "@ohos/axios", | ||
| 15 | + "integrity": "sha512-EQax257+eKKT0Rx7h6N6xvmKbDRWDjCCWOP2vyyktySFwvjtypXuXmQKEvRjmAalR6cqf8mbfhWmpg0bD9OQ3w==", | ||
| 16 | + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/axios/-/axios-2.1.1.har", | ||
| 17 | + "registryType": "ohpm" | ||
| 18 | + }, | ||
| 19 | + "wdConstant@../wdConstant": { | ||
| 20 | + "name": "wdconstant", | ||
| 21 | + "resolved": "../wdConstant", | ||
| 22 | + "registryType": "local" | ||
| 23 | + }, | ||
| 24 | + "wdKit@../wdKit": { | ||
| 25 | + "name": "wdkit", | ||
| 26 | + "resolved": "../wdKit", | ||
| 27 | + "registryType": "local" | ||
| 28 | + } | ||
| 29 | + } | ||
| 30 | +} |
| @@ -2,16 +2,13 @@ | @@ -2,16 +2,13 @@ | ||
| 2 | "license": "Apache-2.0", | 2 | "license": "Apache-2.0", |
| 3 | "devDependencies": {}, | 3 | "devDependencies": {}, |
| 4 | "author": "", | 4 | "author": "", |
| 5 | - "name": "wdcomponent", | 5 | + "name": "wdnetwork", |
| 6 | "description": "Please describe the basic information.", | 6 | "description": "Please describe the basic information.", |
| 7 | "main": "Index.ets", | 7 | "main": "Index.ets", |
| 8 | "version": "1.0.0", | 8 | "version": "1.0.0", |
| 9 | "dependencies": { | 9 | "dependencies": { |
| 10 | "wdConstant": "file:../wdConstant", | 10 | "wdConstant": "file:../wdConstant", |
| 11 | "wdKit": "file:../wdKit", | 11 | "wdKit": "file:../wdKit", |
| 12 | - "wdWebComponent": "file:../wdWebComponent", | ||
| 13 | - "wdBean": "file:../wdBean", | ||
| 14 | - "wdRouter": "file:../wdRouter", | ||
| 15 | - "wdNetwork": "file:../wdNetwork" | 12 | + "@ohos/axios": "^2.1.1" |
| 16 | } | 13 | } |
| 17 | } | 14 | } |
| 1 | +import axios, { | ||
| 2 | + AxiosError, | ||
| 3 | + AxiosInstance, | ||
| 4 | + AxiosResponse, | ||
| 5 | + HttpStatusCode, | ||
| 6 | + InternalAxiosRequestConfig | ||
| 7 | +} from '@ohos/axios'; | ||
| 8 | + | ||
| 9 | +// import type ResponseDTO from '../models/ResponseDTO'; | ||
| 10 | + | ||
| 11 | +// const key = 'xxxxyyyyzzz' | ||
| 12 | + | ||
| 13 | +// const apiBaseUrl = 'http://127.0.0.1:5566' | ||
| 14 | +// const apiBaseUrl = "https://display-sc.miguvideo.com/display/v3/static"; | ||
| 15 | +// console.log("apiBaseUrl:" + apiBaseUrl); | ||
| 16 | +// axios.defaults.baseURL = apiBaseUrl | ||
| 17 | + | ||
| 18 | +// 使跨域请求带上cookie等用户认证凭据 | ||
| 19 | +// axios.defaults.withCredentials = true; | ||
| 20 | + | ||
| 21 | +// 实例化axios | ||
| 22 | +const instance: AxiosInstance = axios.create({ | ||
| 23 | + // axios请求基础URL(包括端口号) | ||
| 24 | + // baseURL: apiBaseUrl, | ||
| 25 | + // 单位毫秒 | ||
| 26 | + timeout: 15000, | ||
| 27 | + // 跨域请求时,携带cookie等用户认证凭据 | ||
| 28 | + // withCredentials: true | ||
| 29 | +}); | ||
| 30 | + | ||
| 31 | +// 添加请求拦截器 | ||
| 32 | +instance.interceptors.request.use( | ||
| 33 | + (config: InternalAxiosRequestConfig) => { | ||
| 34 | + // 在发送请求之前 | ||
| 35 | + if (!config.headers["Content-Type"]) { | ||
| 36 | + config.headers["Content-Type"] = "application/json;charset=utf-8"; | ||
| 37 | + } | ||
| 38 | + // 公共请求参数 | ||
| 39 | + // config.params.key = key | ||
| 40 | + return config; | ||
| 41 | + }, | ||
| 42 | + (error: AxiosError) => { | ||
| 43 | + // 请求错误 | ||
| 44 | + console.log(`全局请求失败拦截,message:${error.message}`) | ||
| 45 | + return Promise.reject(error); | ||
| 46 | + } | ||
| 47 | +); | ||
| 48 | + | ||
| 49 | +// // GET /api/success | ||
| 50 | +// { | ||
| 51 | +// "code": 0, | ||
| 52 | +// "message": "请求成功", | ||
| 53 | +// "data": { | ||
| 54 | +// "name": "管理员" | ||
| 55 | +// } | ||
| 56 | +// } | ||
| 57 | +// // GET /api/fail | ||
| 58 | +// { | ||
| 59 | +// "code": -1, | ||
| 60 | +// "message": "请求失败:XXX错误!", | ||
| 61 | +// "data": null | ||
| 62 | +// } | ||
| 63 | + | ||
| 64 | +// 添加响应拦截器 | ||
| 65 | +instance.interceptors.response.use(// 响应拦截器response类型就是Axios.request<T = any, R = AxiosResponse<T>, D = any>中的泛型R | ||
| 66 | + // 泛型 T 就是服务器返回数据的类型 | ||
| 67 | + // 泛型 R 就是这个泛型 T 数据经过 axios 包装一层得到的 response 对象的类型,而 request 方法的返回值是一个 Promise,其值就是成功态的 R,也就是 response对象。 | ||
| 68 | + (response: AxiosResponse) => { | ||
| 69 | + // response为AxiosResponse类型,含有config\data\headers\request\status\statusText属 | ||
| 70 | + // console.dir(response) | ||
| 71 | + // 正常响应,可对响应数据做通用处理 | ||
| 72 | + // 2xx 范围内的状态码都会触发该函数。 | ||
| 73 | + if (response.status === HttpStatusCode.Ok) { | ||
| 74 | + // 直接返回response,当然你也可以只返回response.data | ||
| 75 | + // return response; | ||
| 76 | + // 也可以先解析服务器返回的状态码,可判断code处理通用逻辑 | ||
| 77 | + // const { code, message, data } = response.data | ||
| 78 | + // if (code === 0) { | ||
| 79 | + // // 将组件用的数据返回 | ||
| 80 | + // return data | ||
| 81 | + // } else { | ||
| 82 | + // // 处理业务错误。 | ||
| 83 | + // console.log(`处理业务,message:${message}`) | ||
| 84 | + // return Promise.reject(new Error(message)) | ||
| 85 | + // } | ||
| 86 | + // const data: ResponseBean<any> = response.data | ||
| 87 | + // 改造返回的数据,即将AxiosResponse的data返回,服务端返回的数据 | ||
| 88 | + return response.data; | ||
| 89 | + } else { | ||
| 90 | + console.log(`httpStatus:${response.status}-${response.status}!`) | ||
| 91 | + // return Promise.reject(error); | ||
| 92 | + return response.data; | ||
| 93 | + } | ||
| 94 | + }, | ||
| 95 | + (error: AxiosError) => { | ||
| 96 | + // 异常响应 | ||
| 97 | + // console.log('全局响应失败拦截') | ||
| 98 | + // console.log(error.request) | ||
| 99 | + // console.log(error.response) | ||
| 100 | + // 这里用来处理http常见错误,进行全局提示 | ||
| 101 | + let message = buildErrorMsg(error.response?.status); | ||
| 102 | + // 错误消息可以使用全局弹框展示出来 | ||
| 103 | + console.log(`httpStatus:${error.response?.status}-${message},请检查网络或联系管理员!`) | ||
| 104 | + return Promise.reject(error); | ||
| 105 | + } | ||
| 106 | +); | ||
| 107 | + | ||
| 108 | +export default instance; | ||
| 109 | + | ||
| 110 | +function buildErrorMsg(httpStatus: number): string { | ||
| 111 | + let message = ""; | ||
| 112 | + switch (httpStatus) { | ||
| 113 | + case HttpStatusCode.BadRequest: | ||
| 114 | + message = "请求错误(400)"; | ||
| 115 | + break; | ||
| 116 | + case HttpStatusCode.Unauthorized: | ||
| 117 | + message = "未授权(或token 失效),请重新登录(401)"; | ||
| 118 | + // 可以触发退出的 action | ||
| 119 | + // 可以做清空storage并跳转到登录页的操作 | ||
| 120 | + break; | ||
| 121 | + case HttpStatusCode.Forbidden: | ||
| 122 | + message = "拒绝访问(403)"; | ||
| 123 | + break; | ||
| 124 | + case HttpStatusCode.NotFound: | ||
| 125 | + message = "请求出错(404)"; | ||
| 126 | + // 请求地址错误 | ||
| 127 | + break; | ||
| 128 | + case HttpStatusCode.RequestTimeout: | ||
| 129 | + message = "请求超时(408)"; | ||
| 130 | + break; | ||
| 131 | + case HttpStatusCode.InternalServerError: | ||
| 132 | + message = "服务器错误(500)"; | ||
| 133 | + // 服务器故障 | ||
| 134 | + break; | ||
| 135 | + case HttpStatusCode.NotImplemented: | ||
| 136 | + message = "服务未实现(501)"; | ||
| 137 | + break; | ||
| 138 | + case HttpStatusCode.BadGateway: | ||
| 139 | + message = "网络错误(502)"; | ||
| 140 | + break; | ||
| 141 | + case HttpStatusCode.ServiceUnavailable: | ||
| 142 | + message = "服务不可用(503)"; | ||
| 143 | + break; | ||
| 144 | + case HttpStatusCode.GatewayTimeout: | ||
| 145 | + message = "网络超时(504)"; | ||
| 146 | + break; | ||
| 147 | + case HttpStatusCode.HttpVersionNotSupported: | ||
| 148 | + message = "HTTP版本不受支持(505)"; | ||
| 149 | + break; | ||
| 150 | + default: | ||
| 151 | + // 网络连接故障 | ||
| 152 | + message = `连接出错(${httpStatus})!`; | ||
| 153 | + } | ||
| 154 | + return message; | ||
| 155 | +} |
| 1 | +import ArrayList from '@ohos.util.ArrayList'; | ||
| 2 | +import service from './AxiosRequest'; | ||
| 3 | +import { HttpUtils } from '../utils/HttpUtils'; | ||
| 4 | +import { AxiosError, AxiosHeaders, AxiosRequestConfig, RawAxiosRequestHeaders } from '@ohos/axios'; | ||
| 5 | +import { ResponseDTO } from '../bean/ResponseDTO'; | ||
| 6 | +import HashMap from '@ohos.util.HashMap'; | ||
| 7 | + | ||
| 8 | +export class HttpRequest { | ||
| 9 | + private static globalHeaderProviders: ArrayList<() => Record<string, string>> = new ArrayList(); | ||
| 10 | + | ||
| 11 | + static addGlobalHeaderProvider(provider: () => Record<string, string>) { | ||
| 12 | + HttpRequest.globalHeaderProviders.add(provider) | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + static initHttpHeader() { | ||
| 16 | + HttpRequest.addGlobalHeaderProvider(() => { | ||
| 17 | + return HttpUtils.buildHeaders(); | ||
| 18 | + }) | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + // 加入泛型限定,返回数据类型为T, | ||
| 22 | + static request<T = ResponseDTO<string>>(config: AxiosRequestConfig): Promise<T> { | ||
| 23 | + return new Promise<T>((resolve, reject) => { | ||
| 24 | + service.request<ResponseDTO<string>, T>(config) | ||
| 25 | + .then((res: T) => { | ||
| 26 | + resolve(res) | ||
| 27 | + }) | ||
| 28 | + .catch((err: AxiosError) => { | ||
| 29 | + reject(err) | ||
| 30 | + }) | ||
| 31 | + }) | ||
| 32 | + // return service.request<any, T>(config) | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + static buildHeaderWithGlobalHeader(headers?: HashMap<string, string>): AxiosHeaders { | ||
| 36 | + let commonHeader: AxiosHeaders = new AxiosHeaders() | ||
| 37 | + headers?.forEach((v, k) => { | ||
| 38 | + commonHeader.set(k, v); | ||
| 39 | + }); | ||
| 40 | + HttpRequest.globalHeaderProviders.forEach((func) => { | ||
| 41 | + let headers = func(); | ||
| 42 | + for (const obj of Object.entries(headers)) { | ||
| 43 | + commonHeader.set(obj[0], obj[1]); | ||
| 44 | + } | ||
| 45 | + }) | ||
| 46 | + if (!commonHeader.get('Content-Type')) { | ||
| 47 | + commonHeader.set('Content-Type', 'application/json;charset=utf-8'); | ||
| 48 | + } | ||
| 49 | + return commonHeader | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + static get<T = ResponseDTO<string>>(url: string, headers?: HashMap<string, string>): Promise<T> { | ||
| 53 | + let config: AxiosRequestConfig = { | ||
| 54 | + headers: HttpRequest.buildHeaderWithGlobalHeader(headers) | ||
| 55 | + } | ||
| 56 | + return service.get(url, config) | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + static post0<T = ResponseDTO<string>>(url: string, data?: object, headers?: HashMap<string, string>): Promise<T> { | ||
| 60 | + let config: AxiosRequestConfig = { | ||
| 61 | + headers: HttpRequest.buildHeaderWithGlobalHeader(headers) | ||
| 62 | + } | ||
| 63 | + return service.post(url, data, config) | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + static post<T = object>(url: string, data1?: object, headers?: HashMap<string, string>): Promise<T> { | ||
| 67 | + let requestHeaders: AxiosHeaders = new AxiosHeaders() | ||
| 68 | + headers?.forEach((v, k) => { | ||
| 69 | + requestHeaders.set(k, v); | ||
| 70 | + }); | ||
| 71 | + let config: AxiosRequestConfig = { | ||
| 72 | + headers: requestHeaders as RawAxiosRequestHeaders, | ||
| 73 | + } | ||
| 74 | + return service.post(url, data1, config) | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + static put<T = ResponseDTO<string>>(url: string, data?: object, headers?: HashMap<string, string>): Promise<T> { | ||
| 78 | + let config: AxiosRequestConfig = { | ||
| 79 | + headers: HttpRequest.buildHeaderWithGlobalHeader(headers) | ||
| 80 | + } | ||
| 81 | + return service.put(url, data, config) | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + static delete<T = ResponseDTO<string>>(url: string, headers?: HashMap<string, string>): Promise<T> { | ||
| 85 | + let config: AxiosRequestConfig = { | ||
| 86 | + headers: HttpRequest.buildHeaderWithGlobalHeader(headers) | ||
| 87 | + } | ||
| 88 | + return service.delete(url, config) | ||
| 89 | + } | ||
| 90 | +} |
| 1 | +import HashMap from '@ohos.util.HashMap' | ||
| 2 | +import { ConfigConstants } from 'wdConstant' | ||
| 3 | +import { DateTimeUtils, Logger } from 'wdKit' | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 网络请求业务侧工具类 | ||
| 7 | + */ | ||
| 8 | +export class HttpUrlUtils { | ||
| 9 | + /** | ||
| 10 | + * uat环境url | ||
| 11 | + */ | ||
| 12 | + static readonly HOST_UAT: string = "https://pd-apis-uat.pdnews.cn"; | ||
| 13 | + /** | ||
| 14 | + * 中文端sit环境 | ||
| 15 | + */ | ||
| 16 | + static readonly HOST_SIT: string = "https://pd-apis-sit.pdnews.cn"; | ||
| 17 | + /** | ||
| 18 | + * 正式环境url | ||
| 19 | + */ | ||
| 20 | + static readonly HOST_PRODUCT: string = "https://pdapis.pdnews.cn"; | ||
| 21 | + /** | ||
| 22 | + * dev环境url | ||
| 23 | + */ | ||
| 24 | + static readonly HOST_DEV: string = "https://pd-apis-dev.pdnews.cn"; | ||
| 25 | + /** | ||
| 26 | + * 启动接口(底导接口) | ||
| 27 | + */ | ||
| 28 | + static readonly BOTTOM_NAV_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/bottomNavGroup"; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 展现pageInfo接口 | ||
| 32 | + */ | ||
| 33 | + static readonly PAGE_INFO_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/pageInfo"; | ||
| 34 | + /** | ||
| 35 | + * 展现comp接口 | ||
| 36 | + */ | ||
| 37 | + static readonly COMP_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/compInfo"; | ||
| 38 | + /** | ||
| 39 | + * 详情页面详情接口 | ||
| 40 | + */ | ||
| 41 | + static readonly DETAIL_PATH: string = "/api/rmrb-bff-display-zh/content/zh/c/content/detail"; | ||
| 42 | + /** | ||
| 43 | + * 批查接口,查询互动相关数据,如收藏数、评论数等 | ||
| 44 | + */ | ||
| 45 | + static readonly INTERACT_DATA_PATH: string = "/api/rmrb-contact/contact/zh/c/content/interactData"; | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * 电子报信息 | ||
| 49 | + */ | ||
| 50 | + static readonly E_NEWSPAPER_INFO_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/paperApi/paperTime"; | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * 电子报列表 | ||
| 54 | + */ | ||
| 55 | + static readonly E_NEWSPAPER_LIST_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/paperApi/paperList"; | ||
| 56 | + | ||
| 57 | + private static hostUrl: string = HttpUrlUtils.HOST_PRODUCT; | ||
| 58 | + | ||
| 59 | + static getCommonHeaders(): HashMap<string, string> { | ||
| 60 | + let headers: HashMap<string, string> = new HashMap<string, string>() | ||
| 61 | + headers.set('User-Agent', 'Dalvik/2.1.0 (Linux; U; Android 13; 22101317C Build/TKQ1.221013.002)') | ||
| 62 | + headers.set('channel', HttpUrlUtils.getChannel()) | ||
| 63 | + //headers.set('appCode', ConfigConstants.appCode) | ||
| 64 | + headers.set('plat', HttpUrlUtils.getPlat()) | ||
| 65 | + //headers.set('Authorization', 'APPCODE 83092caa603a421aa0222308b3f6b27a') | ||
| 66 | + headers.set('Content-Type', 'application/json; charset=utf-8') | ||
| 67 | + headers.set('timestamp', HttpUrlUtils.getTimestamp()) | ||
| 68 | + headers.set('RMRB-X-TOKEN', HttpUrlUtils.getXToken()) | ||
| 69 | + headers.set('device_id', HttpUrlUtils.getDeviceId()) | ||
| 70 | + headers.set('cookie', 'RMRB-X-TOKEN=eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc') | ||
| 71 | + headers.set('build_version', HttpUrlUtils.getVersion()) | ||
| 72 | + headers.set('adcode', HttpUrlUtils.getAdCode()) | ||
| 73 | + headers.set('os_version', HttpUrlUtils.getOsVersion()) | ||
| 74 | + //headers.set('X-Ca-Stage', 'PRE') | ||
| 75 | + headers.set('versionCode', HttpUrlUtils.getVersionCode()) | ||
| 76 | + headers.set('system', HttpUrlUtils.getTerminalId()) | ||
| 77 | + headers.set('version_name', HttpUrlUtils.getVersionName()) | ||
| 78 | + headers.set('EagleEye-TraceID', 'D539562E48554A60977AF4BECB6D6C7A') | ||
| 79 | + headers.set('imei', HttpUrlUtils.getImei()) | ||
| 80 | + headers.set('Accept-Language', 'zh') | ||
| 81 | + headers.set('city', HttpUrlUtils.getCity()) | ||
| 82 | + headers.set('city_dode', HttpUrlUtils.getCityCode()) | ||
| 83 | + // TODO 判断是否登录 | ||
| 84 | + headers.set('userId', HttpUrlUtils.getUserId()) | ||
| 85 | + headers.set('userType', HttpUrlUtils.getUserType()) | ||
| 86 | + | ||
| 87 | + headers.set('mpassid', 'ZbHTMeTsfaYDAHqt8ZHIzcPs') | ||
| 88 | + HttpUrlUtils.addSpecialHeaders(headers); | ||
| 89 | + // Logger.debug("TAG", '******************* commonHeaders headers start ******************************** '); | ||
| 90 | + // headers.forEach((v,k)=>{ | ||
| 91 | + // Logger.debug("TAG", 'getCommonHeaders header: ' + k + ': ' + v); | ||
| 92 | + // }) | ||
| 93 | + // Logger.debug("TAG", '******************* commonHeaders headers end ******************************** '); | ||
| 94 | + return headers; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + static addSpecialHeaders(headers: HashMap<string, string>) { | ||
| 98 | + switch (HttpUrlUtils.hostUrl) { | ||
| 99 | + case HttpUrlUtils.HOST_UAT: | ||
| 100 | + // TODO 待优化到常量类里 | ||
| 101 | + headers.set('X-Ca-Stage', 'PRE'); | ||
| 102 | + headers.set('Authorization', 'APPCODE 83092caa603a421aa0222308b3f6b27a'); | ||
| 103 | + headers.set('appCode', '83092caa603a421aa0222308b3f6b27a'); | ||
| 104 | + break | ||
| 105 | + case HttpUrlUtils.HOST_SIT: | ||
| 106 | + headers.set('X-Ca-Stage', 'TEST'); | ||
| 107 | + headers.set('Authorization', 'APPCODE 0af1f9085e484c97b2a44704bae72c07'); | ||
| 108 | + headers.set('appCode', '0af1f9085e484c97b2a44704bae72c07'); | ||
| 109 | + break | ||
| 110 | + case HttpUrlUtils.HOST_PRODUCT: | ||
| 111 | + headers.set('X-Ca-Stage', 'RELEASE'); | ||
| 112 | + headers.set('Authorization', 'APPCODE 3d4181bceeb94d9780e10dbb6c67bbf6'); | ||
| 113 | + headers.set('appCode', '3d4181bceeb94d9780e10dbb6c67bbf6'); | ||
| 114 | + break | ||
| 115 | + case HttpUrlUtils.HOST_DEV: | ||
| 116 | + headers.set('X-Ca-Stage', 'TEST'); | ||
| 117 | + headers.set('Authorization', 'APPCODE ff33172859e14f9a8299e3bd769e79f9'); | ||
| 118 | + headers.set('appCode', 'ff33172859e14f9a8299e3bd769e79f9'); | ||
| 119 | + break | ||
| 120 | + default: | ||
| 121 | + break | ||
| 122 | + } | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + static getHost() { | ||
| 126 | + return HttpUrlUtils.hostUrl; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + private static getCity() { | ||
| 130 | + // TODO 对接定位 | ||
| 131 | + return '%E5%90%88%E8%82%A5%E5%B8%82'; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + private static getChannel() { | ||
| 135 | + // TODO 对接配置 | ||
| 136 | + return 'rmrb_china_0000'; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + private static getPlat() { | ||
| 140 | + return 'Phone'; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + private static getTimestamp() { | ||
| 144 | + // return DateTimeUtils.getCurrentTime() + ''; | ||
| 145 | + // TODO 暂时写死,有些page 真实时间戳 返回数据为空 | ||
| 146 | + return '155203523'; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + private static getXToken() { | ||
| 150 | + return 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc'; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + private static getDeviceId() { | ||
| 154 | + // TODO | ||
| 155 | + return '8a81226a-cabd-3e1b-b630-b51db4a720ed'; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + private static getVersion() { | ||
| 159 | + // TODO | ||
| 160 | + return '202401242103'; | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + private static getVersionCode() { | ||
| 164 | + // TODO | ||
| 165 | + return '7301'; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + private static getVersionName() { | ||
| 169 | + // TODO | ||
| 170 | + return '7.3.0.1'; | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + private static getAdCode() { | ||
| 174 | + return '340000'; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + private static getOsVersion() { | ||
| 178 | + // TODO | ||
| 179 | + return '12'; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + public static getCityCode() { | ||
| 183 | + // TODO | ||
| 184 | + return '340100'; | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + public static getProvinceCode() { | ||
| 188 | + // TODO | ||
| 189 | + return '340000'; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + /** | ||
| 193 | + * 地区code | ||
| 194 | + */ | ||
| 195 | + public static getDistrictCode() { | ||
| 196 | + // TODO | ||
| 197 | + return '340103'; | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + private static getTerminalId() { | ||
| 201 | + return 'Android'; | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + private static getImei() { | ||
| 205 | + // TODO | ||
| 206 | + return '8a81226a-cabd-3e1b-b630-b51db4a720ed'; | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + private static getUserId() { | ||
| 210 | + // TODO 对接登录 | ||
| 211 | + return '459776297474949'; | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + private static getUserType() { | ||
| 215 | + return '2'; | ||
| 216 | + } | ||
| 217 | +} |
| 1 | +// import { ResponseLogin } from '../bean/account/ResponseLogin'; | ||
| 2 | +import { Logger } from 'wdKit'; | ||
| 3 | + | ||
| 4 | +// import { UserInfo } from '../bean/account/UserInfo'; | ||
| 5 | +// import { ConfigConstants } from '../constants/ConfigConstants'; | ||
| 6 | +// import { AccountManagerUtils } from './AccountManagerUtils'; | ||
| 7 | +// import { AppUtils } from './AppUtils'; | ||
| 8 | +// import { DeviceUtil } from './DeviceUtil'; | ||
| 9 | +// import { Logger } from './Logger'; | ||
| 10 | +// import { StringUtils } from './StringUtils'; | ||
| 11 | + | ||
| 12 | +const TAG: string = '[HttpUtils]' | ||
| 13 | + | ||
| 14 | +export class HttpUtils { | ||
| 15 | + static buildHeaders(): Record<string, string> { | ||
| 16 | + let timestamp: number = new Date().getTime(); // 单位毫秒 | ||
| 17 | + // let clientId = DeviceUtil.clientId() | ||
| 18 | + | ||
| 19 | + let headers: Record<string, string> = {}; | ||
| 20 | + // 通用请求头 | ||
| 21 | + headers["version"] = 'V3'; | ||
| 22 | + // headers["appId"] = ConfigConstants.appId; // 应用id | ||
| 23 | + // headers["terminalId"] = ConfigConstants.terminalId; // 终端ID | ||
| 24 | + // headers["sourceId"] = ConfigConstants.sourceId; // 咪咕视频 | ||
| 25 | + // headers["appType"] = ConfigConstants.appType; // 手机客户端App(安卓) | ||
| 26 | + // headers["clientType"] = ConfigConstants.clientType; // 客户端类型 | ||
| 27 | + // headers["appVersion"] = AppUtils.getAppVersionCode() + ''; // 客户端版本号:2600010500 | ||
| 28 | + // headers["APP-VERSION-CODE"] = AppUtils.getAppVersionCode() + ''; // APP版本号:250006577 | ||
| 29 | + // headers["appVersionName"] = AppUtils.getAppVersionName() // app对外显示版本: '6.1.5.00' | ||
| 30 | + // headers["appCode"] = ConfigConstants.appCode; // 应用编码:产品_渠道_应用的拼接串,用下划线_ 拼接而成 | ||
| 31 | + // headers["ptvCode"] = ConfigConstants.ptvCode; // 基线版本号_应用版本号 todo: | ||
| 32 | + // headers["clientProvinceCode"] = ''; // 客户端分省号 // 02 | ||
| 33 | + // headers["provinceCode"] = ''; // 客户端分省号 // 02 | ||
| 34 | + // headers["clientCityId"] = ''; // 客户端城市ID // 0210 | ||
| 35 | + // headers["carrierCode"] = ''; // 运营商信息 | ||
| 36 | + | ||
| 37 | + // 设备信息请求头 | ||
| 38 | + // headers["User-Agent"] = ''; // 终端UA,自动获取 | ||
| 39 | + headers["Content-Type"] = 'application/json;charset=UTF-8'; // 返回/响应的HTTP内容类型 | ||
| 40 | + headers["os"] = 'android'; // 操作系统类型:鸿蒙、安卓或iOS | ||
| 41 | + // headers["osInfo"] = 'AD'; // 操作系统信息 | ||
| 42 | + headers["Phone-Info"] = 'HUAWEI'; // 手机信息: todo | ||
| 43 | + // headers["oaid"] = ''; // 开放匿名设备ID,是中国移动安全联盟(MSA)发起并制定标准用户识别ID | ||
| 44 | + headers["networkInfo"] = 'WIFI'; // 网络类型: todo | ||
| 45 | + headers["cache-control"] = 'no-cache'; // 请求和响应遵循的缓存机制 | ||
| 46 | + // headers["clientId"] = clientId; // 客户端编号:客户端初始化时生成的客户端ID,保证唯一性 | ||
| 47 | + headers["imei"] = 'd1de6d3ae0db44bea1b3f0e20a14d90a'; // 终端手机序列号: todo | ||
| 48 | + headers["X-UP-CLIENT-CHANNEL-ID"] = '2600010500-99000-101700010130012'; // 客户端渠道ID: todo | ||
| 49 | + headers["channelCode"] = 'VIDEO_APPMAIL'; // 渠道编码 | ||
| 50 | + // headers["l_c"] = clientId; // 客户端id,同clientId | ||
| 51 | + // headers["l_t"] = timestamp + ''; // 本机时间戳 | ||
| 52 | + // headers["l_s"] = ''; // l_c和l_t拼接后的MD5校验 | ||
| 53 | + | ||
| 54 | + // 签名相关请求头 | ||
| 55 | + headers["timeStamp"] = timestamp + ''; // 服务端时间戳(毫秒):1701667763664 | ||
| 56 | + headers["signType"] = 'RSA'; // 签名类型,固定RSA | ||
| 57 | + | ||
| 58 | + // 业务请求头 | ||
| 59 | + // headers["promotionID"] = '54b0f421-a6df-41d3-9be2-92820b2c5d8c'; // 促销Id todo | ||
| 60 | + // headers["tenantId"] = ''; // 租户Id | ||
| 61 | + | ||
| 62 | + // 添加其他header | ||
| 63 | + // headers["sdkCeId"] = '27fb3129-5a54-45bc-8af1-7dc8f1155501'; // 用户中台老接口定义的ID,保持不变,现网:咪咕视频Android版,27fb3129-5a54-45bc-8af1-7dc8f1155501 todo | ||
| 64 | + headers["support-pendant"] = '1'; // 挂件标识, "1":客户端支持挂件节目结构;非"1":不支持挂件节目结构-展示通用对象 | ||
| 65 | + Logger.info(TAG, "buildHeader headers:" + JSON.stringify(headers)); | ||
| 66 | + return headers; | ||
| 67 | + } | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +// export default new HttpUtils() |
| 1 | +{ | ||
| 2 | + "module": { | ||
| 3 | + "name": "wdNetwork", | ||
| 4 | + "type": "shared", | ||
| 5 | + "description": "$string:shared_desc", | ||
| 6 | + "deviceTypes": [ | ||
| 7 | + "phone", | ||
| 8 | + "tablet", | ||
| 9 | + "2in1" | ||
| 10 | + ], | ||
| 11 | + "deliveryWithInstall": true, | ||
| 12 | + "requestPermissions": [ | ||
| 13 | + { | ||
| 14 | + "name": "ohos.permission.INTERNET" | ||
| 15 | + } | ||
| 16 | + ] | ||
| 17 | + } | ||
| 18 | +} |
| 1 | +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; | ||
| 2 | + | ||
| 3 | +export default function localUnitTest() { | ||
| 4 | + describe('localUnitTest',() => { | ||
| 5 | + // Defines a test suite. Two parameters are supported: test suite name and test suite function. | ||
| 6 | + beforeAll(() => { | ||
| 7 | + // Presets an action, which is performed only once before all test cases of the test suite start. | ||
| 8 | + // This API supports only one parameter: preset action function. | ||
| 9 | + }); | ||
| 10 | + beforeEach(() => { | ||
| 11 | + // Presets an action, which is performed before each unit test case starts. | ||
| 12 | + // The number of execution times is the same as the number of test cases defined by **it**. | ||
| 13 | + // This API supports only one parameter: preset action function. | ||
| 14 | + }); | ||
| 15 | + afterEach(() => { | ||
| 16 | + // Presets a clear action, which is performed after each unit test case ends. | ||
| 17 | + // The number of execution times is the same as the number of test cases defined by **it**. | ||
| 18 | + // This API supports only one parameter: clear action function. | ||
| 19 | + }); | ||
| 20 | + afterAll(() => { | ||
| 21 | + // Presets a clear action, which is performed after all test cases of the test suite end. | ||
| 22 | + // This API supports only one parameter: clear action function. | ||
| 23 | + }); | ||
| 24 | + it('assertContain', 0, () => { | ||
| 25 | + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. | ||
| 26 | + let a = 'abc'; | ||
| 27 | + let b = 'b'; | ||
| 28 | + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. | ||
| 29 | + expect(a).assertContain(b); | ||
| 30 | + expect(a).assertEqual(a); | ||
| 31 | + }); | ||
| 32 | + }); | ||
| 33 | +} |
sight_harmony/commons/wdRouter/.gitignore
0 → 100644
sight_harmony/commons/wdRouter/Index.ets
0 → 100644
| 1 | +{ | ||
| 2 | + "apiType": "stageMode", | ||
| 3 | + "buildOption": { | ||
| 4 | + "arkOptions": { | ||
| 5 | + // "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */ | ||
| 6 | + } | ||
| 7 | + }, | ||
| 8 | + "buildOptionSet": [ | ||
| 9 | + { | ||
| 10 | + "name": "release", | ||
| 11 | + "arkOptions": { | ||
| 12 | + "obfuscation": { | ||
| 13 | + "ruleOptions": { | ||
| 14 | + "enable": true, | ||
| 15 | + "files": [ | ||
| 16 | + "./obfuscation-rules.txt" | ||
| 17 | + ] | ||
| 18 | + } | ||
| 19 | + } | ||
| 20 | + } | ||
| 21 | + }, | ||
| 22 | + ], | ||
| 23 | + "targets": [ | ||
| 24 | + { | ||
| 25 | + "name": "default" | ||
| 26 | + } | ||
| 27 | + ] | ||
| 28 | +} |
sight_harmony/commons/wdRouter/hvigorfile.ts
0 → 100644
| 1 | +# Define project specific obfuscation rules here. | ||
| 2 | +# You can include the obfuscation configuration files in the current module's build-profile.json5. | ||
| 3 | +# | ||
| 4 | +# For more details, see | ||
| 5 | +# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md | ||
| 6 | + | ||
| 7 | +# Obfuscation options: | ||
| 8 | +# -disable-obfuscation: disable all obfuscations | ||
| 9 | +# -enable-property-obfuscation: obfuscate the property names | ||
| 10 | +# -enable-toplevel-obfuscation: obfuscate the names in the global scope | ||
| 11 | +# -compact: remove unnecessary blank spaces and all line feeds | ||
| 12 | +# -remove-log: remove all console.* statements | ||
| 13 | +# -print-namecache: print the name cache that contains the mapping from the old names to new names | ||
| 14 | +# -apply-namecache: reuse the given cache file | ||
| 15 | + | ||
| 16 | +# Keep options: | ||
| 17 | +# -keep-property-name: specifies property names that you want to keep | ||
| 18 | +# -keep-global-name: specifies names that you want to keep in the global scope |
| 1 | +{ | ||
| 2 | + "meta": { | ||
| 3 | + "stableOrder": true | ||
| 4 | + }, | ||
| 5 | + "lockfileVersion": 3, | ||
| 6 | + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", | ||
| 7 | + "specifiers": { | ||
| 8 | + "wdBean@../../../../features/wdBean": "wdBean@../../features/wdBean", | ||
| 9 | + "wdKit@../../../../commons/wdKit": "wdKit@../wdKit" | ||
| 10 | + }, | ||
| 11 | + "packages": { | ||
| 12 | + "wdBean@../../features/wdBean": { | ||
| 13 | + "name": "wdbean", | ||
| 14 | + "resolved": "../../features/wdBean", | ||
| 15 | + "registryType": "local" | ||
| 16 | + }, | ||
| 17 | + "wdKit@../wdKit": { | ||
| 18 | + "name": "wdkit", | ||
| 19 | + "resolved": "../wdKit", | ||
| 20 | + "registryType": "local" | ||
| 21 | + } | ||
| 22 | + } | ||
| 23 | +} |
| 1 | { | 1 | { |
| 2 | - "license": "", | 2 | + "license": "Apache-2.0", |
| 3 | "devDependencies": {}, | 3 | "devDependencies": {}, |
| 4 | "author": "", | 4 | "author": "", |
| 5 | - "name": "entry", | 5 | + "name": "wdrouter", |
| 6 | "description": "Please describe the basic information.", | 6 | "description": "Please describe the basic information.", |
| 7 | - "main": "", | 7 | + "main": "Index.ets", |
| 8 | "version": "1.0.0", | 8 | "version": "1.0.0", |
| 9 | "dependencies": { | 9 | "dependencies": { |
| 10 | - "wdComponent": "file:../wdComponent", | ||
| 11 | - "wdConstant": "file:../wdConstant", | ||
| 12 | "wdKit": "file:../wdKit", | 10 | "wdKit": "file:../wdKit", |
| 13 | - "wdWebComponent": "file:../wdWebComponent", | ||
| 14 | - "wdBean": "file:../wdBean", | ||
| 15 | - "wdRouter": "file:../wdRouter", | ||
| 16 | - "wdNetwork": "file:../wdNetwork" | 11 | + "wdBean": "file:../../features/wdBean" |
| 17 | } | 12 | } |
| 18 | } | 13 | } |
| 1 | +import ArrayList from '@ohos.util.ArrayList'; | ||
| 2 | +import { Action } from 'wdBean' | ||
| 3 | +import { WDRouterPage } from './WDRouterPage' | ||
| 4 | + | ||
| 5 | +interface HandleObject { | ||
| 6 | + handle: (action: Action) => (WDRouterPage | undefined) | ||
| 7 | + priority: number | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +export class Action2Page { | ||
| 11 | + private static handles: Record<string, ArrayList<HandleObject>> = {}; | ||
| 12 | + | ||
| 13 | + static register(actionType: string, handle: (action: Action) => (WDRouterPage | undefined), priority: number = 0) { | ||
| 14 | + let handles = Action2Page.handles[actionType] ?? new ArrayList(); | ||
| 15 | + let obj: HandleObject = { | ||
| 16 | + handle: handle, | ||
| 17 | + priority: priority | ||
| 18 | + }; | ||
| 19 | + handles.add(obj); | ||
| 20 | + handles.sort((f, s) => { | ||
| 21 | + return f.priority - s.priority; | ||
| 22 | + }) | ||
| 23 | + Action2Page.handles[actionType] = handles; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + static get(action?: Action): WDRouterPage | undefined { | ||
| 27 | + if (!action || !action.type) { | ||
| 28 | + return undefined; | ||
| 29 | + } | ||
| 30 | + let handles = Action2Page.handles[action.type]; | ||
| 31 | + if (!handles) { | ||
| 32 | + return undefined; | ||
| 33 | + } | ||
| 34 | + let page: WDRouterPage | undefined | ||
| 35 | + for (let i = 0; i < handles.length; i++) { | ||
| 36 | + let tmp = (handles[i] as HandleObject).handle(action); | ||
| 37 | + if (tmp) { | ||
| 38 | + page = tmp; | ||
| 39 | + break | ||
| 40 | + } | ||
| 41 | + } | ||
| 42 | + return page | ||
| 43 | + } | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +export function registerRouter() { | ||
| 47 | + // Action2Page.register("USER_LOGIN", (action: Action) => { | ||
| 48 | + // return WDRouterPage.webLoginPage | ||
| 49 | + // }) | ||
| 50 | + | ||
| 51 | + Action2Page.register("JUMP_DETAIL_PAGE", (action: Action) => { | ||
| 52 | + // if (action.params?.detailPageType == 2 || action.params?.detailPageType == 6) { | ||
| 53 | + // return WDRouterPage.detailPlayLivePage | ||
| 54 | + // } | ||
| 55 | + if (action.params?.detailPageType == 7 || action.params?.detailPageType == 8) { | ||
| 56 | + return WDRouterPage.detailPlayShortVideoPage | ||
| 57 | + } | ||
| 58 | + return WDRouterPage.detailPlayVodPage | ||
| 59 | + }) | ||
| 60 | + | ||
| 61 | + Action2Page.register("JUMP_H5_BY_WEB_VIEW", (action) => { | ||
| 62 | + return WDRouterPage.defaultWebPage | ||
| 63 | + }) | ||
| 64 | + | ||
| 65 | + Action2Page.register("JUMP_INNER_NEW_PAGE", (action) => { | ||
| 66 | + if (action.params?.pageID == "E_NEWSPAPER") { | ||
| 67 | + return WDRouterPage.eNewspaper | ||
| 68 | + } else if (action.params?.pageID == "MorningEveningPaper"){ | ||
| 69 | + return WDRouterPage.morningEveningPaperPage | ||
| 70 | + } else if (action.params?.pageID == "IMAGE_TEXT_DETAIL"){ | ||
| 71 | + return WDRouterPage.imageTextDetailPage | ||
| 72 | + } | ||
| 73 | + return undefined | ||
| 74 | + }) | ||
| 75 | +} |
| 1 | +import bundleManager from '@ohos.bundle.bundleManager' | ||
| 2 | + | ||
| 3 | +export class WDRouterPage { | ||
| 4 | + private moduleName: string | ||
| 5 | + private pagePath: string | ||
| 6 | + | ||
| 7 | + constructor(moduleName: string, pagePath: string) { | ||
| 8 | + this.moduleName = moduleName | ||
| 9 | + this.pagePath = pagePath | ||
| 10 | + } | ||
| 11 | + | ||
| 12 | + url() { | ||
| 13 | + let bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT) | ||
| 14 | + return `@bundle:${bundleInfo.name}/${this.moduleName}/${this.pagePath}` | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + // 主页 | ||
| 18 | + static index = new WDRouterPage("entry", "ets/pages/Index"); | ||
| 19 | + // 关于页面 | ||
| 20 | + // static aboutPage = new WDRouterPage("entry", "ets/pages/about/AboutPage"); | ||
| 21 | + // web默认页面 | ||
| 22 | + static defaultWebPage = new WDRouterPage("entry", "ets/pages/web/DefaultWebPage"); | ||
| 23 | + // 电子报页面 | ||
| 24 | + static eNewspaper = new WDRouterPage("entry", "ets/pages/ENewspaper") | ||
| 25 | + // 早晚报页面 | ||
| 26 | + static morningEveningPaperPage = new WDRouterPage("entry", "ets/pages/MorningEveningPaperPage") | ||
| 27 | + // 图文详情页 | ||
| 28 | + static imageTextDetailPage = new WDRouterPage("entry", "ets/pages/ImageAndTextDetailPage"); | ||
| 29 | + // 短视频详情页 | ||
| 30 | + static detailPlayShortVideoPage = new WDRouterPage("wdDetailPlayShortVideo", "ets/pages/DetailPlayShortVideoPage"); | ||
| 31 | + // 点播详情页 | ||
| 32 | + static detailPlayVodPage = new WDRouterPage("wdDetailPlayVod", "ets/pages/DetailPlayVodPage"); | ||
| 33 | + // 直播详情页 | ||
| 34 | + static detailPlayLivePage = new WDRouterPage("wdDetailPlayLive", "ets/pages/DetailPlayLivePage"); | ||
| 35 | +} |
| 1 | +import router from '@ohos.router' | ||
| 2 | +import { Action } from 'wdBean' | ||
| 3 | +import { ToastUtils } from 'wdKit' | ||
| 4 | +import { Action2Page } from './Action2Page' | ||
| 5 | +import { WDRouterPage } from './WDRouterPage' | ||
| 6 | + | ||
| 7 | +export class WDRouterRule { | ||
| 8 | + static jumpWithAction(action?: Action) { | ||
| 9 | + if (!action || !action.type) { | ||
| 10 | + ToastUtils.showToast("跳转参数异常", 1000); | ||
| 11 | + return | ||
| 12 | + } | ||
| 13 | + let page = Action2Page.get(action); | ||
| 14 | + WDRouterRule.jumpWithPage(page, action) | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + private static jumpWithPage(page?: WDRouterPage, params?: object) { | ||
| 18 | + if (page) { | ||
| 19 | + if (params) { | ||
| 20 | + // router.pushUrl({ url: 'pages/routerpage2', , params: params }) | ||
| 21 | + router.pushUrl({ url: page.url(), params: params }) | ||
| 22 | + } else { | ||
| 23 | + router.pushUrl({ url: page.url() }) | ||
| 24 | + } | ||
| 25 | + } else { | ||
| 26 | + ToastUtils.showToast("功能开发中", 1000); | ||
| 27 | + } | ||
| 28 | + } | ||
| 29 | +} |
-
Please register or login to post a comment