liyubing

Merge remote-tracking branch 'origin/main'

Showing 31 changed files with 632 additions and 119 deletions
@@ -11,6 +11,15 @@ export enum EmitterEventId { @@ -11,6 +11,15 @@ export enum EmitterEventId {
11 // 跳转首页指定频道,事件id 11 // 跳转首页指定频道,事件id
12 JUMP_HOME_CHANNEL = 4, 12 JUMP_HOME_CHANNEL = 4,
13 13
14 - LOCATION = 5 14 + LOCATION = 5,
  15 + /*发布评论*/
  16 + COMMENT_PUBLISH = 6,
  17 +
  18 + // App回到前台
  19 + APP_ENTER_FOREGROUD = 100,
  20 + // App进入后台
  21 + APP_ENTER_BACKGROUD = 101,
  22 +
  23 +
15 } 24 }
16 25
@@ -289,4 +289,8 @@ export class LazyDataSource<T> extends BasicDataSource<T> { @@ -289,4 +289,8 @@ export class LazyDataSource<T> extends BasicDataSource<T> {
289 this.dataArray.splice(start, this.dataArray.length, ...data); 289 this.dataArray.splice(start, this.dataArray.length, ...data);
290 this.notifyDataReload() 290 this.notifyDataReload()
291 } 291 }
  292 +
  293 + public reloadData(): void {
  294 + this.notifyDataReload();
  295 + }
292 } 296 }
@@ -5,3 +5,5 @@ export { WDRouterPage } from './src/main/ets/router/WDRouterPage' @@ -5,3 +5,5 @@ export { WDRouterPage } from './src/main/ets/router/WDRouterPage'
5 export { registerRouter } from './src/main/ets/router/Action2Page' 5 export { registerRouter } from './src/main/ets/router/Action2Page'
6 6
7 export { ProcessUtils } from './src/main/ets/utils/ProcessUtils' 7 export { ProcessUtils } from './src/main/ets/utils/ProcessUtils'
  8 +
  9 +export { RouterJumpInterceptor, JumpInterceptorAction } from './src/main/ets/router/RouterJumpInterceptor'
  1 +import { WDRouterPage } from './WDRouterPage';
  2 +
  3 +export interface JumpInterceptorAction {
  4 + on(params?: object, singleMode?: boolean): boolean
  5 +}
  6 +
  7 +// TODO:待优化
  8 +// 临时解决跳转页面之前方法拦截,比如登录先走一键登录,直播请求接口等
  9 +//
  10 +export class RouterJumpInterceptor {
  11 +
  12 + private static actions: Record<string, JumpInterceptorAction> = {}
  13 +
  14 + static getInterceptorAction(jumpPage: WDRouterPage): JumpInterceptorAction | undefined {
  15 + return RouterJumpInterceptor.actions[jumpPage.url()]
  16 + }
  17 +
  18 + static register(jumpPage: WDRouterPage, interceptorAction: JumpInterceptorAction) {
  19 + RouterJumpInterceptor.actions[jumpPage.url()] = interceptorAction
  20 + }
  21 +
  22 +
  23 +}
@@ -66,6 +66,7 @@ export class WDRouterPage { @@ -66,6 +66,7 @@ export class WDRouterPage {
66 // 动态详情页 66 // 动态详情页
67 static dynamicDetailPage = new WDRouterPage("phone", "ets/pages/detail/DynamicDetailPage"); 67 static dynamicDetailPage = new WDRouterPage("phone", "ets/pages/detail/DynamicDetailPage");
68 static loginPage = new WDRouterPage("wdLogin", "ets/pages/login/LoginPage"); 68 static loginPage = new WDRouterPage("wdLogin", "ets/pages/login/LoginPage");
  69 + static oneKeyLoginPage = new WDRouterPage("wdLogin", "ets/pages/login/OneKeyLoginPage");
69 static forgetPasswordPage = new WDRouterPage("wdLogin", "ets/pages/login/ForgetPasswordPage"); 70 static forgetPasswordPage = new WDRouterPage("wdLogin", "ets/pages/login/ForgetPasswordPage");
70 //我的 预约 71 //我的 预约
71 static appointmentListPage = new WDRouterPage("wdComponent", "ets/components/page/AppointmentListPage"); 72 static appointmentListPage = new WDRouterPage("wdComponent", "ets/components/page/AppointmentListPage");
@@ -3,6 +3,7 @@ import { Action } from 'wdBean' @@ -3,6 +3,7 @@ import { Action } from 'wdBean'
3 import { ToastUtils } from 'wdKit' 3 import { ToastUtils } from 'wdKit'
4 import { Action2Page } from './Action2Page' 4 import { Action2Page } from './Action2Page'
5 import { WDRouterPage } from './WDRouterPage' 5 import { WDRouterPage } from './WDRouterPage'
  6 +import { RouterJumpInterceptor } from './RouterJumpInterceptor'
6 7
7 export class WDRouterRule { 8 export class WDRouterRule {
8 static jumpWithAction(action?: Action) { 9 static jumpWithAction(action?: Action) {
@@ -16,6 +17,11 @@ export class WDRouterRule { @@ -16,6 +17,11 @@ export class WDRouterRule {
16 17
17 static jumpWithPage(page?: WDRouterPage, params?: object, singleMode?: boolean) { 18 static jumpWithPage(page?: WDRouterPage, params?: object, singleMode?: boolean) {
18 if (page) { 19 if (page) {
  20 + let action = RouterJumpInterceptor.getInterceptorAction(page)
  21 + if (action && action.on(params, singleMode)) {
  22 + return
  23 + }
  24 +
19 let mode = router.RouterMode.Standard 25 let mode = router.RouterMode.Standard
20 if (singleMode) { 26 if (singleMode) {
21 mode = router.RouterMode.Single 27 mode = router.RouterMode.Single
@@ -36,6 +42,10 @@ export class WDRouterRule { @@ -36,6 +42,10 @@ export class WDRouterRule {
36 42
37 static jumpWithReplacePage(page?: WDRouterPage, params?: object) { 43 static jumpWithReplacePage(page?: WDRouterPage, params?: object) {
38 if (page) { 44 if (page) {
  45 + let action = RouterJumpInterceptor.getInterceptorAction(page)
  46 + if (action && action.on(params)) {
  47 + return
  48 + }
39 if (params) { 49 if (params) {
40 // router.pushUrl({ url: 'pages/routerpage2', , params: params }) 50 // router.pushUrl({ url: 'pages/routerpage2', , params: params })
41 router.replaceUrl({ url: page.url(), params: params }) 51 router.replaceUrl({ url: page.url(), params: params })
@@ -8,4 +8,5 @@ export interface commentInfo { @@ -8,4 +8,5 @@ export interface commentInfo {
8 newsId: string, 8 newsId: string,
9 relId: string; 9 relId: string;
10 relType: string; 10 relType: string;
  11 + userId: string;
11 } 12 }
@@ -21,7 +21,7 @@ export struct MultiPictureDetailItemComponent { @@ -21,7 +21,7 @@ export struct MultiPictureDetailItemComponent {
21 .alt($r('app.media.picture_loading')) 21 .alt($r('app.media.picture_loading'))
22 .width(this.imageWidth) 22 .width(this.imageWidth)
23 .aspectRatio(this.ratio) 23 .aspectRatio(this.ratio)
24 - .objectFit(ImageFit.Fill) 24 + .objectFit(ImageFit.Contain)
25 .interpolation(ImageInterpolation.High) 25 .interpolation(ImageInterpolation.High)
26 .onComplete(event => { 26 .onComplete(event => {
27 this.imageWidth = '100%' 27 this.imageWidth = '100%'
@@ -12,6 +12,7 @@ import display from '@ohos.display'; @@ -12,6 +12,7 @@ import display from '@ohos.display';
12 import font from '@ohos.font'; 12 import font from '@ohos.font';
13 import { OperRowListView } from './view/OperRowListView'; 13 import { OperRowListView } from './view/OperRowListView';
14 import { MultiPictureDetailItemComponent } from './MultiPictureDetailItemComponent'; 14 import { MultiPictureDetailItemComponent } from './MultiPictureDetailItemComponent';
  15 +import { ImageDownloadComponent } from '../components/ImageDownloadComponent';
15 import { EmptyComponent } from './view/EmptyComponent'; 16 import { EmptyComponent } from './view/EmptyComponent';
16 import { DateTimeUtils } from 'wdKit/Index'; 17 import { DateTimeUtils } from 'wdKit/Index';
17 import { HttpUrlUtils } from 'wdNetwork/Index'; 18 import { HttpUrlUtils } from 'wdNetwork/Index';
@@ -37,9 +38,10 @@ export struct MultiPictureDetailPageComponent { @@ -37,9 +38,10 @@ export struct MultiPictureDetailPageComponent {
37 private swiperController: SwiperController = new SwiperController() 38 private swiperController: SwiperController = new SwiperController()
38 private swiperControllerItem: SwiperController = new SwiperController() 39 private swiperControllerItem: SwiperController = new SwiperController()
39 @State swiperIndex: number = 0; 40 @State swiperIndex: number = 0;
40 - @Provide followStatus: string = '0' // 关注状态 41 + @Provide followStatus: string | undefined = undefined // 关注状态
41 private scroller: Scroller = new Scroller() 42 private scroller: Scroller = new Scroller()
42 @State netStatus: number | undefined = undefined // 存储网络状态用来展示缺省图 43 @State netStatus: number | undefined = undefined // 存储网络状态用来展示缺省图
  44 + @State showDownload: Boolean = false // 控制是否显示下载默认隐藏
43 45
44 //watch监听页码回调 46 //watch监听页码回调
45 onCurrentPageNumUpdated(): void { 47 onCurrentPageNumUpdated(): void {
@@ -146,8 +148,8 @@ export struct MultiPictureDetailPageComponent { @@ -146,8 +148,8 @@ export struct MultiPictureDetailPageComponent {
146 right: 0 148 right: 0
147 }) 149 })
148 150
149 - if (this.followStatus == '0') {  
150 Row() { 151 Row() {
  152 + if (this.followStatus == '0') {
151 Button({ type: ButtonType.Normal, stateEffect: true }) { 153 Button({ type: ButtonType.Normal, stateEffect: true }) {
152 Row() { 154 Row() {
153 Text('+关注').fontSize(12).fontColor(0xffffff) 155 Text('+关注').fontSize(12).fontColor(0xffffff)
@@ -160,15 +162,27 @@ export struct MultiPictureDetailPageComponent { @@ -160,15 +162,27 @@ export struct MultiPictureDetailPageComponent {
160 .onClick(() => { 162 .onClick(() => {
161 this.handleAccention() 163 this.handleAccention()
162 }) 164 })
  165 + } else {
  166 + Button({ type: ButtonType.Normal, stateEffect: true }) {
  167 + Row() {
  168 + Text('已关注').fontSize(12).fontColor(0xffffff)
  169 + }.alignItems(VerticalAlign.Center)
  170 + }
  171 + .borderRadius(4)
  172 + .backgroundColor('#B0B0B0')
  173 + .width(48)
  174 + .height(24)
  175 + }
  176 +
163 } 177 }
164 .justifyContent(FlexAlign.Center) 178 .justifyContent(FlexAlign.Center)
165 .alignItems(VerticalAlign.Center) 179 .alignItems(VerticalAlign.Center)
166 .width('21.6%') 180 .width('21.6%')
167 .height('100%') 181 .height('100%')
168 } 182 }
169 - }  
170 .width('100%') 183 .width('100%')
171 .height(44) 184 .height(44)
  185 + .zIndex(10)
172 .alignRules({ 186 .alignRules({
173 top: { anchor: "__container__", align: VerticalAlign.Top }, 187 top: { anchor: "__container__", align: VerticalAlign.Top },
174 middle: { anchor: "__container__", align: HorizontalAlign.Center } 188 middle: { anchor: "__container__", align: HorizontalAlign.Center }
@@ -195,7 +209,7 @@ export struct MultiPictureDetailPageComponent { @@ -195,7 +209,7 @@ export struct MultiPictureDetailPageComponent {
195 } 209 }
196 .index(this.swiperIndex) 210 .index(this.swiperIndex)
197 .width('100%') 211 .width('100%')
198 - .height(px2vp(this.picHeight) + 32) 212 + .height('100%')
199 .vertical(false) 213 .vertical(false)
200 .autoPlay(false) 214 .autoPlay(false)
201 .cachedCount(3) 215 .cachedCount(3)
@@ -207,10 +221,28 @@ export struct MultiPictureDetailPageComponent { @@ -207,10 +221,28 @@ export struct MultiPictureDetailPageComponent {
207 center: { anchor: "__container__", align: VerticalAlign.Center }, 221 center: { anchor: "__container__", align: VerticalAlign.Center },
208 middle: { anchor: "__container__", align: HorizontalAlign.Center } 222 middle: { anchor: "__container__", align: HorizontalAlign.Center }
209 }) 223 })
  224 + .zIndex(1)
210 .onChange((index: number) => { 225 .onChange((index: number) => {
211 this.swiperIndex = index 226 this.swiperIndex = index
212 }) 227 })
213 - 228 + .onClick(() => {
  229 + this.showDownload = !this.showDownload
  230 + })
  231 + }
  232 + if (this.netStatus !== undefined) {
  233 + EmptyComponent({
  234 + emptyType: this.netStatus, emptyButton: true, retry: () => {
  235 + this.getContentDetailData()
  236 + }
  237 + })
  238 + .id('e_empty_content')
  239 + .alignRules({
  240 + center: { anchor: "__container__", align: VerticalAlign.Center },
  241 + middle: { anchor: "__container__", align: HorizontalAlign.Center }
  242 + })
  243 + }
  244 + Column(){
  245 + Column(){
214 Row() { 246 Row() {
215 Scroll(this.scroller) { 247 Scroll(this.scroller) {
216 Row() { 248 Row() {
@@ -224,12 +256,14 @@ export struct MultiPictureDetailPageComponent { @@ -224,12 +256,14 @@ export struct MultiPictureDetailPageComponent {
224 .fontFamily('PingFang SC-Medium') 256 .fontFamily('PingFang SC-Medium')
225 .fontWeight(500) 257 .fontWeight(500)
226 .lineHeight(28) 258 .lineHeight(28)
227 - Span(`/${this.contentDetailData.photoList.length}`) 259 + Span(`/${this.contentDetailData?.photoList?.length}`)
228 .fontSize(14) 260 .fontSize(14)
229 .fontFamily('PingFang SC-Medium') 261 .fontFamily('PingFang SC-Medium')
230 .fontWeight(500) 262 .fontWeight(500)
231 .lineHeight(19) 263 .lineHeight(19)
232 - }.fontColor(Color.White).margin(4) 264 + }
  265 + .fontColor(Color.White)
  266 + .margin(4)
233 267
234 Text(`${this.contentDetailData.newsTitle}`) 268 Text(`${this.contentDetailData.newsTitle}`)
235 .fontColor(Color.White) 269 .fontColor(Color.White)
@@ -260,54 +294,60 @@ export struct MultiPictureDetailPageComponent { @@ -260,54 +294,60 @@ export struct MultiPictureDetailPageComponent {
260 } 294 }
261 } 295 }
262 .width('100%') 296 .width('100%')
263 - .margin({  
264 - top: 8,  
265 - left: 18,  
266 - bottom: 24,  
267 - right: 18  
268 - })  
269 } 297 }
270 .scrollable(ScrollDirection.Vertical) 298 .scrollable(ScrollDirection.Vertical)
271 .scrollBarWidth(0) 299 .scrollBarWidth(0)
272 .height(px2vp(this.titleHeight)) 300 .height(px2vp(this.titleHeight))
  301 + .align(Alignment.Bottom)
273 } 302 }
274 - .id('e_swiper_titles')  
275 - .alignRules({  
276 - bottom: { anchor: "__container__", align: VerticalAlign.Bottom },  
277 - middle: { anchor: "__container__", align: HorizontalAlign.Center } 303 + OperRowListView({
  304 + contentDetailData: this.contentDetailData,
278 }) 305 })
279 - .height(px2vp(this.titleHeight) + 64)  
280 - 306 + .width('100%')
  307 + .height(56)
  308 + .border({ width: { top: 0.5 }, color: '#FFFFFF' })
281 } 309 }
282 - if (this.netStatus !== undefined) {  
283 - EmptyComponent({  
284 - emptyType: this.netStatus, emptyButton: true, retry: () => {  
285 - this.getContentDetailData() 310 + .visibility(!this.showDownload ? Visibility.Visible : Visibility.None)
  311 + Column(){
  312 + Row() {
  313 + Flex({
  314 + direction: FlexDirection.Row,
  315 + justifyContent: FlexAlign.SpaceBetween
  316 + }) {
  317 + Text() {
  318 + Span(`${this.swiperIndex + 1}`)
  319 + .fontSize(24)
  320 + .fontFamily('PingFang SC-Medium')
  321 + .fontWeight(500)
  322 + .lineHeight(28)
  323 + Span(`/${this.contentDetailData?.photoList?.length}`)
  324 + .fontSize(14)
  325 + .fontFamily('PingFang SC-Medium')
  326 + .fontWeight(500)
  327 + .lineHeight(19)
286 } 328 }
287 - })  
288 - .id('e_empty_content')  
289 - .alignRules({  
290 - center: { anchor: "__container__", align: VerticalAlign.Center },  
291 - middle: { anchor: "__container__", align: HorizontalAlign.Center } 329 + .fontColor(Color.White)
  330 + .margin(4)
  331 +
  332 + ImageDownloadComponent({ url: this.contentDetailData.photoList?.[this.swiperIndex].picPath })
  333 + .margin({
  334 + top: 8,
  335 + left: 18,
  336 + bottom: 24,
  337 + right: 18
292 }) 338 })
293 } 339 }
294 - OperRowListView({  
295 - contentDetailData: this.contentDetailData,  
296 - }) 340 + }
  341 + .width('100%')
  342 + }
  343 + .visibility(this.showDownload ? Visibility.Visible : Visibility.None)
  344 + }
  345 + .zIndex(10)
  346 + .id('e_swiper_bottom')
297 .alignRules({ 347 .alignRules({
298 bottom: { anchor: "__container__", align: VerticalAlign.Bottom }, 348 bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
299 middle: { anchor: "__container__", align: HorizontalAlign.Center } 349 middle: { anchor: "__container__", align: HorizontalAlign.Center }
300 }) 350 })
301 - .width('100%')  
302 - .height(56)  
303 - .margin({  
304 - top: 16,  
305 - left: 16,  
306 - right: 16,  
307 - bottom: 0  
308 - })  
309 - .border({ width: { top: 0.5 }, color: '#FFFFFF' })  
310 - .id('e_oper_row')  
311 } 351 }
312 352
313 getContentDetailData() { 353 getContentDetailData() {
  1 +import { commentItemModel } from './CommentModel'
  2 +
1 @Observed 3 @Observed
2 export class publishCommentModel { 4 export class publishCommentModel {
3 5
@@ -25,7 +27,7 @@ export class publishCommentModel { @@ -25,7 +27,7 @@ export class publishCommentModel {
25 /*评论内容*/ 27 /*评论内容*/
26 commentContent: string = "" 28 commentContent: string = ""
27 /*1.文字 2.文字+表情 3.定制表情(客户端写死) 4.图片*/ 29 /*1.文字 2.文字+表情 3.定制表情(客户端写死) 4.图片*/
28 - commentType: string = '1' 30 + commentType: string = '2'
29 /*根评论id,如果是一级评论,传-1;否则,传当前评论所属的根评论id*/ 31 /*根评论id,如果是一级评论,传-1;否则,传当前评论所属的根评论id*/
30 rootCommentId: string = "-1" 32 rootCommentId: string = "-1"
31 /*父评论id,如果是其它评论的回复,该字段必填*/ 33 /*父评论id,如果是其它评论的回复,该字段必填*/
@@ -35,6 +37,10 @@ export class publishCommentModel { @@ -35,6 +37,10 @@ export class publishCommentModel {
35 //可选 37 //可选
36 placeHolderText: string = "优质评论会获得最佳评论人的称号" 38 placeHolderText: string = "优质评论会获得最佳评论人的称号"
37 39
  40 + //最新发布的评论
  41 + lastCommentModel: commentItemModel = new commentItemModel()
  42 +
  43 +
38 } 44 }
39 45
40 46
1 import ArrayList from '@ohos.util.ArrayList' 1 import ArrayList from '@ohos.util.ArrayList'
2 import { ViewType } from 'wdConstant/Index'; 2 import { ViewType } from 'wdConstant/Index';
3 -import { DateTimeUtils, LazyDataSource } from 'wdKit/Index'; 3 +import { DateTimeUtils, EmitterEventId, EmitterUtils, LazyDataSource } from 'wdKit/Index';
4 import PageModel from '../../../viewmodel/PageModel'; 4 import PageModel from '../../../viewmodel/PageModel';
5 import { commentItemModel, commentListModel, WDPublicUserType } from '../model/CommentModel'; 5 import { commentItemModel, commentListModel, WDPublicUserType } from '../model/CommentModel';
6 import commentViewModel from '../viewmodel/CommentViewModel' 6 import commentViewModel from '../viewmodel/CommentViewModel'
@@ -9,6 +9,7 @@ import measure from '@ohos.measure' @@ -9,6 +9,7 @@ import measure from '@ohos.measure'
9 import { CommentCustomDialog } from './CommentCustomDialog' 9 import { CommentCustomDialog } from './CommentCustomDialog'
10 import { publishCommentModel } from '../model/PublishCommentModel'; 10 import { publishCommentModel } from '../model/PublishCommentModel';
11 import { ifaa } from '@kit.OnlineAuthenticationKit'; 11 import { ifaa } from '@kit.OnlineAuthenticationKit';
  12 +import { HttpUrlUtils } from 'wdNetwork/Index';
12 13
13 const TAG = 'CommentComponent'; 14 const TAG = 'CommentComponent';
14 15
@@ -18,18 +19,13 @@ const testString = '因为读书的人\n是低着头向上看的人\n身处一 @@ -18,18 +19,13 @@ const testString = '因为读书的人\n是低着头向上看的人\n身处一
18 @Preview 19 @Preview
19 @Component 20 @Component
20 export struct CommentComponent { 21 export struct CommentComponent {
21 -  
22 // @State private browSingModel: commentListModel = new commentListModel() 22 // @State private browSingModel: commentListModel = new commentListModel()
23 /*必传*/ 23 /*必传*/
24 @ObjectLink publishCommentModel: publishCommentModel 24 @ObjectLink publishCommentModel: publishCommentModel
25 -  
26 isloading: boolean = false 25 isloading: boolean = false
27 -  
28 @State allDatas: LazyDataSource<commentItemModel> = new LazyDataSource(); 26 @State allDatas: LazyDataSource<commentItemModel> = new LazyDataSource();
29 -  
30 @State dialogController: CustomDialogController | null = null; 27 @State dialogController: CustomDialogController | null = null;
31 28
32 -  
33 // 在自定义组件即将析构销毁时将dialogControlle置空 29 // 在自定义组件即将析构销毁时将dialogControlle置空
34 aboutToDisappear() { 30 aboutToDisappear() {
35 this.dialogController = null // 将dialogController置空 31 this.dialogController = null // 将dialogController置空
@@ -37,12 +33,23 @@ export struct CommentComponent { @@ -37,12 +33,23 @@ export struct CommentComponent {
37 33
38 aboutToAppear() { 34 aboutToAppear() {
39 35
  36 + //注册通知,来自别的组件的评论成功通知
  37 + EmitterUtils.receiveEvent(EmitterEventId.COMMENT_PUBLISH, (targetId?: string) => {
  38 + if (targetId) {
  39 + if (targetId == this.publishCommentModel.targetId) {
  40 + //新增评论
  41 + this.addCommentLocal()
  42 + }
  43 + }
  44 + })
  45 +
  46 +
40 this.dialogController = new CustomDialogController({ 47 this.dialogController = new CustomDialogController({
41 builder: CommentCustomDialog({ 48 builder: CommentCustomDialog({
42 confirm: (value: Record<string, string>) => { 49 confirm: (value: Record<string, string>) => {
43 - 50 + this.addCommentLocal()
44 }, 51 },
45 - publishCommentModel:this.publishCommentModel 52 + publishCommentModel: this.publishCommentModel
46 }), 53 }),
47 autoCancel: true, 54 autoCancel: true,
48 alignment: DialogAlignment.Bottom, 55 alignment: DialogAlignment.Bottom,
@@ -57,6 +64,24 @@ export struct CommentComponent { @@ -57,6 +64,24 @@ export struct CommentComponent {
57 64
58 } 65 }
59 66
  67 + //
  68 + addCommentLocal() {
  69 + let model = commentViewModel.deepCopyCommentItemModel(this.publishCommentModel.lastCommentModel)
  70 + /*一级评论*/
  71 + if (this.publishCommentModel.lastCommentModel.parentId == '-1') {
  72 + this.allDatas.addFirstItem(model)
  73 + //TODO 跳转顶部
  74 + }else{
  75 + //二级评论
  76 + this.allDatas.getDataArray().forEach(element => {
  77 + if (element.id == this.publishCommentModel.lastCommentModel.rootCommentId) {
  78 + element.childCommentsLazyDataSource.addFirstItem(model)
  79 + }
  80 + });
  81 + }
  82 +
  83 + }
  84 +
60 /*标题:全部评论*/ 85 /*标题:全部评论*/
61 @Builder 86 @Builder
62 titleHeader() { 87 titleHeader() {
@@ -73,6 +98,11 @@ export struct CommentComponent { @@ -73,6 +98,11 @@ export struct CommentComponent {
73 98
74 } 99 }
75 .margin({ left: 16 }) 100 .margin({ left: 16 })
  101 + .onClick(()=>{
  102 + // this.allDatas.push(new commentItemModel())
  103 + // this.allDatas.addFirstItem(new commentItemModel())
  104 + // this.allDatas.reloadData();
  105 + })
76 106
77 }.height(44) 107 }.height(44)
78 .width('100%') 108 .width('100%')
@@ -92,7 +122,11 @@ export struct CommentComponent { @@ -92,7 +122,11 @@ export struct CommentComponent {
92 /*查看更多和收起*/ 122 /*查看更多和收起*/
93 @Builder 123 @Builder
94 GroupFooterView(item: commentItemModel, index: number) { 124 GroupFooterView(item: commentItemModel, index: number) {
95 - footerExpandedView({ item: item, contentId: this.publishCommentModel.targetId, contentType: this.publishCommentModel.targetType }) 125 + footerExpandedView({
  126 + item: item,
  127 + contentId: this.publishCommentModel.targetId,
  128 + contentType: this.publishCommentModel.targetType
  129 + })
96 } 130 }
97 131
98 build() { 132 build() {
@@ -114,7 +148,7 @@ export struct CommentComponent { @@ -114,7 +148,7 @@ export struct CommentComponent {
114 .onClick(() => { 148 .onClick(() => {
115 console.log(TAG) 149 console.log(TAG)
116 }) 150 })
117 - }) 151 + },(childItem: commentItemModel, subIndex: number) => JSON.stringify(childItem) + subIndex.toString())
118 } 152 }
119 } else { 153 } else {
120 ListItemGroup({ header: this.CommentHeaderItem(item, index) }) { 154 ListItemGroup({ header: this.CommentHeaderItem(item, index) }) {
@@ -129,23 +163,25 @@ export struct CommentComponent { @@ -129,23 +163,25 @@ export struct CommentComponent {
129 .onClick(() => { 163 .onClick(() => {
130 console.log(TAG) 164 console.log(TAG)
131 }) 165 })
132 - }) 166 + },(childItem: commentItemModel, subIndex: number) => JSON.stringify(childItem) + subIndex.toString())
133 } 167 }
134 } 168 }
135 - }) 169 + },(item: commentItemModel, index: number) => JSON.stringify(item) + index.toString())
136 }.layoutWeight(1) 170 }.layoutWeight(1)
137 } 171 }
138 } 172 }
139 173
140 //获取数据 174 //获取数据
141 async getData() { 175 async getData() {
142 - commentViewModel.fetchContentCommentList('1', this.publishCommentModel.targetId, this.publishCommentModel.targetType).then(commentListModel => { 176 + commentViewModel.fetchContentCommentList('1', this.publishCommentModel.targetId, this.publishCommentModel.targetType)
  177 + .then(commentListModel => {
143 if (commentListModel && commentListModel.list && commentListModel.list.length > 0) { 178 if (commentListModel && commentListModel.list && commentListModel.list.length > 0) {
144 commentListModel.list.forEach(element => { 179 commentListModel.list.forEach(element => {
145 element.hasMore = Number.parseInt(element.childCommentNum) ? true : false 180 element.hasMore = Number.parseInt(element.childCommentNum) ? true : false
146 let newModel = commentViewModel.deepCopyCommentItemModel(element) 181 let newModel = commentViewModel.deepCopyCommentItemModel(element)
147 - // newModel.targetId = this.publishCommentModel.targetId  
148 - // newModel.targetType = this.publishCommentModel.targetType 182 + // 点赞用
  183 + newModel.targetId = this.publishCommentModel.targetId
  184 + newModel.targetType = this.publishCommentModel.targetType
149 this.allDatas.push(newModel) 185 this.allDatas.push(newModel)
150 }); 186 });
151 187
@@ -243,6 +279,8 @@ struct ChildCommentItem { @@ -243,6 +279,8 @@ struct ChildCommentItem {
243 }) 279 })
244 .margin({ left: 95, right: 16, top: -5 }) 280 .margin({ left: 95, right: 16, top: -5 })
245 .onClick(() => { 281 .onClick(() => {
  282 +
  283 +
246 this.publishCommentModel.rootCommentId = this.item.rootCommentId 284 this.publishCommentModel.rootCommentId = this.item.rootCommentId
247 this.publishCommentModel.parentId = this.item.id 285 this.publishCommentModel.parentId = this.item.id
248 this.publishCommentModel.placeHolderText = '回复' + this.item.fromUserName + ':' 286 this.publishCommentModel.placeHolderText = '回复' + this.item.fromUserName + ':'
1 import { inputMethodEngine } from '@kit.IMEKit' 1 import { inputMethodEngine } from '@kit.IMEKit'
  2 +import { commentInfo } from 'wdBean/Index'
  3 +import { commentItemModel } from '../model/CommentModel'
2 import { publishCommentModel } from '../model/PublishCommentModel' 4 import { publishCommentModel } from '../model/PublishCommentModel'
3 import commentViewModel from '../viewmodel/CommentViewModel' 5 import commentViewModel from '../viewmodel/CommentViewModel'
4 6
@@ -22,9 +24,10 @@ export struct CommentCustomDialog { @@ -22,9 +24,10 @@ export struct CommentCustomDialog {
22 let bean: Record<string, string> = {}; 24 let bean: Record<string, string> = {};
23 // this.publishCommentModel.commentContent = this.commentText 25 // this.publishCommentModel.commentContent = this.commentText
24 //TODO 判断类型 26 //TODO 判断类型
25 - this.publishCommentModel.commentType = '1'  
26 - commentViewModel.publishComment(this.publishCommentModel).then(() => { 27 + this.publishCommentModel.commentType = '2'
  28 + commentViewModel.publishComment(this.publishCommentModel).then((model:commentItemModel) => {
27 this.publishCommentModel.commentContent = '' 29 this.publishCommentModel.commentContent = ''
  30 + this.publishCommentModel.lastCommentModel = model
28 // this.commentText = '' 31 // this.commentText = ''
29 if (this.controller != null) { 32 if (this.controller != null) {
30 this.controller.close() 33 this.controller.close()
  1 +import { EmitterEventId, EmitterUtils } from 'wdKit/Index'
1 import { publishCommentModel } from '../model/PublishCommentModel' 2 import { publishCommentModel } from '../model/PublishCommentModel'
  3 +import { CommentCustomDialog } from './CommentCustomDialog'
  4 +
2 5
3 @Preview 6 @Preview
4 @Component 7 @Component
@@ -8,6 +11,34 @@ export struct CommentTabComponent { @@ -8,6 +11,34 @@ export struct CommentTabComponent {
8 @State type:number = 1 11 @State type:number = 1
9 @State placeHolder: string = '说两句...' 12 @State placeHolder: string = '说两句...'
10 13
  14 + @State dialogController: CustomDialogController | null = null;
  15 +
  16 + /*回调方法*/
  17 + dialogControllerConfirm: () => void = () => {}
  18 +
  19 +
  20 +
  21 + aboutToAppear() {
  22 +
  23 + this.dialogController = new CustomDialogController({
  24 + builder: CommentCustomDialog({
  25 + confirm: (value: Record<string, string>) => {
  26 + this.dialogControllerConfirm();
  27 + EmitterUtils.sendEvent(EmitterEventId.COMMENT_PUBLISH,this.publishCommentModel.targetId)
  28 + },
  29 + publishCommentModel:this.publishCommentModel
  30 + }),
  31 + autoCancel: true,
  32 + alignment: DialogAlignment.Bottom,
  33 + customStyle: true,
  34 + offset: {
  35 + dx: 0,
  36 + dy: -20
  37 + },
  38 + })
  39 +
  40 + }
  41 +
11 build() { 42 build() {
12 Row(){ 43 Row(){
13 Stack({alignContent:Alignment.Start}){ 44 Stack({alignContent:Alignment.Start}){
@@ -15,6 +46,10 @@ export struct CommentTabComponent { @@ -15,6 +46,10 @@ export struct CommentTabComponent {
15 Text(this.placeHolder).fontSize(12).fontColor('#999999').margin({left:10}) 46 Text(this.placeHolder).fontSize(12).fontColor('#999999').margin({left:10})
16 } 47 }
17 }.width(151).height(30) 48 }.width(151).height(30)
  49 + .onClick(()=>{
  50 + this.publishCommentModel.parentId = '-1';
  51 + this.dialogController?.open();
  52 + })
18 } 53 }
19 } 54 }
20 55
@@ -25,25 +60,52 @@ export struct CommentIconComponent { @@ -25,25 +60,52 @@ export struct CommentIconComponent {
25 /*展示类型*/ 60 /*展示类型*/
26 @State type:number = 1 61 @State type:number = 1
27 62
  63 + /*回调方法*/
  64 + onClickItem: () => void = () => {}
  65 +
28 build() { 66 build() {
29 Row(){ 67 Row(){
30 Stack({alignContent:Alignment.TopEnd}){ 68 Stack({alignContent:Alignment.TopEnd}){
31 Image($r('app.media.comment_icon')).width(24).height(24) 69 Image($r('app.media.comment_icon')).width(24).height(24)
32 // Stack({alignContent:Alignment.Start}) { 70 // Stack({alignContent:Alignment.Start}) {
33 - // Image($r('app.media.comment_icon_number')).objectFit(ImageFit.Fill).width(12).height(12)  
34 - Text(this.publishCommentModel.totalCommentNumer + '12345' +' ') 71 + RelativeContainer() {
  72 + Image($r('app.media.comment_icon_number_bg'))
  73 + .objectFit(ImageFit.Fill)
  74 + .resizable({ slice: {top:1, left: 20 , right:1, bottom:1} })
  75 + .alignRules({
  76 + top: {anchor: "Text", align: VerticalAlign.Top},
  77 + left: {anchor: "Text", align: HorizontalAlign.Start},
  78 + right: {anchor: "Text", align: HorizontalAlign.End},
  79 + bottom : {anchor: "Text", align: VerticalAlign.Bottom},
  80 + })
  81 + // .offset({
  82 + // x:-6
  83 + // })
  84 + .id("Image")
  85 +
  86 + Text('123213123123123')
35 .fontSize(8) 87 .fontSize(8)
36 - .fontColor('#ffffff')  
37 - // .backgroundColor('#ED2800') 88 + .fontColor('#ffffff')// .backgroundColor('#ED2800')
38 .height(12) 89 .height(12)
39 - .margin({ left: 6 })  
40 - .backgroundImage($r('app.media.comment_icon_number'))  
41 - // }.width(25) 90 + .alignRules({
  91 + top: {anchor: "__container__", align: VerticalAlign.Top},
  92 + left: {anchor: "__container__", align: HorizontalAlign.Start}
  93 + })
  94 + // .margin({left: 4,right:4
  95 + // })
  96 + /*动态计算文字宽度*/
  97 + .width(50)
  98 + // .backgroundColor(Color.Green)
  99 + .id("Text")
  100 +
  101 + }
  102 + // }
42 103
43 .offset({ 104 .offset({
44 x:12 105 x:12
45 }) 106 })
46 } 107 }
47 }.width(24).height(24) 108 }.width(24).height(24)
  109 + // .backgroundColor(Color.Blue)
48 } 110 }
49 } 111 }
@@ -184,37 +184,14 @@ export struct QualityCommentsComponent { @@ -184,37 +184,14 @@ export struct QualityCommentsComponent {
184 Column() { 184 Column() {
185 Stack() { 185 Stack() {
186 this.titleHeader() 186 this.titleHeader()
187 - this.listLayout()  
188 -  
189 - // if(this.viewType == ViewType.ERROR){  
190 - // ErrorComponent()  
191 - // }else if(this.viewType == ViewType.EMPTY){  
192 - // EmptyComponent({emptyType:WDViewDefaultType.WDViewDefaultType_NoComment})  
193 - // }else {  
194 - // CustomPullToRefresh({  
195 - // alldata:[],  
196 - // scroller:this.scroller,  
197 - // customList:()=>{  
198 - // this.listLayout()  
199 - // // this.testLayout()  
200 - // },  
201 - // onRefresh:(resolve)=>{  
202 - // this.currentPage = 1  
203 - // this.getData(resolve)  
204 - // },  
205 - // onLoadMore:(resolve)=> {  
206 - // if (this.hasMore === false) {  
207 - // if(resolve) resolve('')  
208 - // return  
209 - // }  
210 - // this.currentPage++  
211 - // this.getData(resolve)  
212 - // }  
213 - // })  
214 - // }  
215 -  
216 -  
217 187
  188 + if(this.viewType == ViewType.ERROR){
  189 + ErrorComponent()
  190 + }else if(this.viewType == ViewType.EMPTY){
  191 + EmptyComponent({emptyType:WDViewDefaultType.WDViewDefaultType_NoComment})
  192 + }else {
  193 + this.listLayout()
  194 + }
218 195
219 }.alignContent(Alignment.Top) 196 }.alignContent(Alignment.Top)
220 }.backgroundColor(this.currentWindowColor).width('100%') 197 }.backgroundColor(this.currentWindowColor).width('100%')
@@ -250,12 +227,15 @@ export struct QualityCommentsComponent { @@ -250,12 +227,15 @@ export struct QualityCommentsComponent {
250 ListItem() { 227 ListItem() {
251 228
252 }.height(this.bottomSafeHeight) 229 }.height(this.bottomSafeHeight)
253 - } 230 + }.onReachEnd(()=>{
  231 + this.currentPage++
  232 + this.getData()
  233 + })
254 .margin({ top: 196 }) 234 .margin({ top: 196 })
255 .height("100%") 235 .height("100%")
256 .width("100%") 236 .width("100%")
257 - .edgeEffect(EdgeEffect.None) // 必须设置列表为滑动到边缘无效果  
258 - // .edgeEffect(EdgeEffect.Spring) 237 + // .edgeEffect(EdgeEffect.None) // 必须设置列表为滑动到边缘无效果
  238 + .edgeEffect(EdgeEffect.Spring)
259 .nestedScroll({ 239 .nestedScroll({
260 scrollForward: NestedScrollMode.PARENT_FIRST, 240 scrollForward: NestedScrollMode.PARENT_FIRST,
261 scrollBackward: NestedScrollMode.SELF_FIRST 241 scrollBackward: NestedScrollMode.SELF_FIRST
@@ -148,7 +148,7 @@ class CommentViewModel { @@ -148,7 +148,7 @@ class CommentViewModel {
148 bean['userName'] = UserDataLocal.getUserId(); 148 bean['userName'] = UserDataLocal.getUserId();
149 bean['userHeaderUrl'] = UserDataLocal.getUserHeaderUrl(); 149 bean['userHeaderUrl'] = UserDataLocal.getUserHeaderUrl();
150 150
151 - HttpRequest.post<ResponseDTO<commentStatusModel[]>>(url, bean, headers).then((data: ResponseDTO<commentStatusModel[]>) => { 151 + HttpBizUtil.post<ResponseDTO<commentStatusModel[]>>(url, bean, headers).then((data: ResponseDTO<commentStatusModel[]>) => {
152 if (data.code != 0) { 152 if (data.code != 0) {
153 fail() 153 fail()
154 return 154 return
@@ -164,7 +164,7 @@ class CommentViewModel { @@ -164,7 +164,7 @@ class CommentViewModel {
164 /*发布评论*/ 164 /*发布评论*/
165 publishComment(model: publishCommentModel) { 165 publishComment(model: publishCommentModel) {
166 166
167 - return new Promise<void>((success, fail) => { 167 + return new Promise<commentItemModel>((success, fail) => {
168 let url = HttpUrlUtils.getPublishCommentUrl() 168 let url = HttpUrlUtils.getPublishCommentUrl()
169 let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders(); 169 let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
170 let bean: Record<string, string> = {}; 170 let bean: Record<string, string> = {};
@@ -182,14 +182,15 @@ class CommentViewModel { @@ -182,14 +182,15 @@ class CommentViewModel {
182 bean['targetType'] = model.targetType 182 bean['targetType'] = model.targetType
183 bean['parentId'] = model.parentId 183 bean['parentId'] = model.parentId
184 184
185 - HttpRequest.post<ResponseDTO<commentStatusModel[]>>(url, bean, headers).then((data: ResponseDTO<commentStatusModel[]>) => { 185 + HttpRequest.post<ResponseDTO<commentItemModel>>(url, bean, headers).then((data: ResponseDTO<commentItemModel>) => {
186 if (data.code != 0) { 186 if (data.code != 0) {
187 ToastUtils.showToast(data.message, 1000); 187 ToastUtils.showToast(data.message, 1000);
188 fail() 188 fail()
189 return 189 return
190 } 190 }
191 ToastUtils.showToast(data.message, 1000); 191 ToastUtils.showToast(data.message, 1000);
192 - success() 192 + let model = data.data as commentItemModel
  193 + success(model)
193 }, (error: Error) => { 194 }, (error: Error) => {
194 ToastUtils.showToast('评论失败', 1000); 195 ToastUtils.showToast('评论失败', 1000);
195 fail() 196 fail()
@@ -240,7 +241,7 @@ class CommentViewModel { @@ -240,7 +241,7 @@ class CommentViewModel {
240 let promiseArray: Promise<commentStatusListModel | void>[] = []; 241 let promiseArray: Promise<commentStatusListModel | void>[] = [];
241 242
242 //未登录不用批查 243 //未登录不用批查
243 - if (HttpUrlUtils.getUserId()){ 244 + if (HttpUrlUtils.getUserId()) {
244 if (commentIDs.length > 0) { 245 if (commentIDs.length > 0) {
245 let promise1 = new Promise<void>((success) => { 246 let promise1 = new Promise<void>((success) => {
246 // HttpRequest HttpBizUtil 247 // HttpRequest HttpBizUtil
@@ -386,8 +387,6 @@ class CommentViewModel { @@ -386,8 +387,6 @@ class CommentViewModel {
386 387
387 } 388 }
388 389
389 -  
390 -  
391 deepCopyCommentItemModel(model: commentItemModel) { 390 deepCopyCommentItemModel(model: commentItemModel) {
392 let newModel = new commentItemModel() 391 let newModel = new commentItemModel()
393 392
@@ -411,10 +410,13 @@ class CommentViewModel { @@ -411,10 +410,13 @@ class CommentViewModel {
411 newModel.fromUserHeader = model.fromUserHeader 410 newModel.fromUserHeader = model.fromUserHeader
412 newModel.fromUserId = model.fromUserId 411 newModel.fromUserId = model.fromUserId
413 newModel.fromUserName = model.fromUserName 412 newModel.fromUserName = model.fromUserName
  413 + if (model.toUserType != null) {
414 newModel.fromUserType = model.fromUserType 414 newModel.fromUserType = model.fromUserType
  415 + }
415 newModel.id = model.id 416 newModel.id = model.id
  417 + if (model.likeNum) {
416 newModel.likeNum = model.likeNum.toString() 418 newModel.likeNum = model.likeNum.toString()
417 - 419 + }
418 if (Number.parseInt(newModel.likeNum) <= 0) { 420 if (Number.parseInt(newModel.likeNum) <= 0) {
419 newModel.likeNum = '' 421 newModel.likeNum = ''
420 } 422 }
@@ -13,7 +13,10 @@ import router from '@ohos.router'; @@ -13,7 +13,10 @@ import router from '@ohos.router';
13 import inputMethod from '@ohos.inputMethod'; 13 import inputMethod from '@ohos.inputMethod';
14 import { MultiPictureDetailViewModel } from '../../viewmodel/MultiPictureDetailViewModel'; 14 import { MultiPictureDetailViewModel } from '../../viewmodel/MultiPictureDetailViewModel';
15 import { LikeComponent } from './LikeComponent'; 15 import { LikeComponent } from './LikeComponent';
16 -import { CommentCustomDialog } from '../comment/view/CommentCustomDialog'; 16 +import { CommentTabComponent, CommentIconComponent, } from '../comment/view/CommentTabComponent';
  17 +import { publishCommentModel } from '../comment/model/PublishCommentModel'
  18 +
  19 +// import { CommentCustomDialog } from '../comment/view/CommentCustomDialog';
17 import { HttpUrlUtils } from 'wdNetwork/Index'; 20 import { HttpUrlUtils } from 'wdNetwork/Index';
18 import { WDRouterPage, WDRouterRule } from 'wdRouter/Index'; 21 import { WDRouterPage, WDRouterRule } from 'wdRouter/Index';
19 import { PageRepository } from '../../repository/PageRepository'; 22 import { PageRepository } from '../../repository/PageRepository';
@@ -38,6 +41,7 @@ export struct OperRowListView { @@ -38,6 +41,7 @@ export struct OperRowListView {
38 @State interactData: InteractDataDTO = {} as InteractDataDTO 41 @State interactData: InteractDataDTO = {} as InteractDataDTO
39 @State newsStatusOfUser: batchLikeAndCollectResult | undefined = undefined // 点赞、收藏状态 42 @State newsStatusOfUser: batchLikeAndCollectResult | undefined = undefined // 点赞、收藏状态
40 @State likeBean: Record<string, string> = {} 43 @State likeBean: Record<string, string> = {}
  44 + @State publishCommentModel: publishCommentModel = new publishCommentModel()
41 45
42 @State operationList: OperationItem[] = [ 46 @State operationList: OperationItem[] = [
43 { 47 {
@@ -81,13 +85,23 @@ export struct OperRowListView { @@ -81,13 +85,23 @@ export struct OperRowListView {
81 this.likeBean['channelId'] = this.contentDetailData.reLInfo?.channelId + '' 85 this.likeBean['channelId'] = this.contentDetailData.reLInfo?.channelId + ''
82 console.info(TAG, 'contentDetailData----', JSON.stringify(this.contentDetailData)) 86 console.info(TAG, 'contentDetailData----', JSON.stringify(this.contentDetailData))
83 console.info(TAG, 'likeBean----', JSON.stringify(this.likeBean)) 87 console.info(TAG, 'likeBean----', JSON.stringify(this.likeBean))
  88 + // 评论需要数据
  89 + this.publishCommentModel.targetId = this.contentDetailData.newsId + ''
  90 + this.publishCommentModel.targetRelId = this.contentDetailData.reLInfo?.relId + ''
  91 + this.publishCommentModel.targetTitle = this.contentDetailData.newsTitle + ''
  92 + this.publishCommentModel.targetRelType = this.contentDetailData.reLInfo?.relType + ''
  93 + this.publishCommentModel.targetRelObjectId = this.contentDetailData.reLInfo?.relObjectId + ''
  94 + this.publishCommentModel.keyArticle = this.contentDetailData.keyArticle + ''
  95 + this.publishCommentModel.targetType = this.contentDetailData.newsType + ''
  96 + this.publishCommentModel.totalCommentNumer = '10'
84 } 97 }
85 98
86 build() { 99 build() {
87 Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems:ItemAlign.Center }){ 100 Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems:ItemAlign.Center }){
88 Row() { 101 Row() {
89 Column() { 102 Column() {
90 - Image($r('app.media.icon_arrow_left_white')) 103 + // Image($r('app.media.icon_arrow_left_white'))
  104 + Image($r('app.media.icon_arrow_left'))
91 .width(24) 105 .width(24)
92 .height(24) 106 .height(24)
93 .aspectRatio(1) 107 .aspectRatio(1)
@@ -109,6 +123,10 @@ export struct OperRowListView { @@ -109,6 +123,10 @@ export struct OperRowListView {
109 /* CommentCustomDialog({ 123 /* CommentCustomDialog({
110 placeHolderText: '说两句' 124 placeHolderText: '说两句'
111 })*/ 125 })*/
  126 + if (this.publishCommentModel?.targetId) {
  127 + CommentTabComponent({publishCommentModel: this.publishCommentModel})
  128 + CommentIconComponent({publishCommentModel: this.publishCommentModel})
  129 + }
112 } 130 }
113 /*TextInput({placeholder:'说两句...'}) 131 /*TextInput({placeholder:'说两句...'})
114 .placeholderColor('#999999') 132 .placeholderColor('#999999')
@@ -140,7 +158,8 @@ export struct OperRowListView { @@ -140,7 +158,8 @@ export struct OperRowListView {
140 } 158 }
141 .width('100%') 159 .width('100%')
142 .height(50) 160 .height(50)
143 - .backgroundColor(Color.Black) 161 + // .backgroundColor(Color.Black)
  162 + .backgroundColor(Color.White)
144 .margin({ 163 .margin({
145 bottom: 20 164 bottom: 20
146 }) 165 })
@@ -107,7 +107,7 @@ export struct DetailPlayVLivePage { @@ -107,7 +107,7 @@ export struct DetailPlayVLivePage {
107 (data) => { 107 (data) => {
108 if (data.length > 0) { 108 if (data.length > 0) {
109 this.liveDetailsBean = data[0] 109 this.liveDetailsBean = data[0]
110 - this.liveState = 'end' // this.liveDetailsBean.liveInfo?.liveState //直播新闻-直播状态 wait待开播running直播中end已结束cancel已取消paused暂停 110 + this.liveState = this.liveDetailsBean.liveInfo?.liveState //直播新闻-直播状态 wait待开播running直播中end已结束cancel已取消paused暂停
111 if (this.liveDetailsBean.fullColumnImgUrls && this.liveDetailsBean.fullColumnImgUrls.length > 0) { 111 if (this.liveDetailsBean.fullColumnImgUrls && this.liveDetailsBean.fullColumnImgUrls.length > 0) {
112 this.imgUrl = this.liveDetailsBean.fullColumnImgUrls[0].url 112 this.imgUrl = this.liveDetailsBean.fullColumnImgUrls[0].url
113 } 113 }
@@ -22,7 +22,7 @@ export struct DetailVideoListPage { @@ -22,7 +22,7 @@ export struct DetailVideoListPage {
22 @Provide showComment: boolean = true 22 @Provide showComment: boolean = true
23 @Provide pageShow: number = -1 23 @Provide pageShow: number = -1
24 @Provide pageHide: number = -1 24 @Provide pageHide: number = -1
25 - @Provide switchVideoStatus: boolean = false 25 + @Provide switchVideoStatus: boolean = true
26 @State data: ContentDetailDTO[] = [] 26 @State data: ContentDetailDTO[] = []
27 @State currentIndex: number = 0 27 @State currentIndex: number = 0
28 @State interactDataList: InteractDataDTO[] = [] 28 @State interactDataList: InteractDataDTO[] = []
@@ -44,7 +44,7 @@ export struct VideoChannelDetail { @@ -44,7 +44,7 @@ export struct VideoChannelDetail {
44 @Provide windowWidth: number = AppStorage.get<number>('windowWidth') || 0 44 @Provide windowWidth: number = AppStorage.get<number>('windowWidth') || 0
45 @Consume @Watch('pageShowChange') pageShow: number 45 @Consume @Watch('pageShowChange') pageShow: number
46 @Consume @Watch('pageHideChange') pageHide: number 46 @Consume @Watch('pageHideChange') pageHide: number
47 - @Provide switchVideoStatus: boolean = false 47 + @Provide switchVideoStatus: boolean = true
48 @State data: ContentDetailDTO[] = [] 48 @State data: ContentDetailDTO[] = []
49 @State currentIndex: number = 0 49 @State currentIndex: number = 0
50 @State interactDataList: InteractDataDTO[] = [] 50 @State interactDataList: InteractDataDTO[] = []
1 export { add } from "./src/main/ets/utils/Calc" 1 export { add } from "./src/main/ets/utils/Calc"
2 export { SettingPasswordParams } from "./src/main/ets/pages/login/SettingPasswordLayout" 2 export { SettingPasswordParams } from "./src/main/ets/pages/login/SettingPasswordLayout"
  3 +
  4 +export { LoginModule } from './src/main/ets/LoginModule'
  1 +import HuaweiAuth from './utils/HuaweiAuth'
  2 +import { JumpInterceptorAction, RouterJumpInterceptor, WDRouterPage } from 'wdRouter'
  3 +import { BusinessError } from '@kit.BasicServicesKit'
  4 +import { router } from '@kit.ArkUI'
  5 +import { AccountManagerUtils } from 'wdKit/Index'
  6 +
  7 +class LoginJumpHandler implements JumpInterceptorAction {
  8 +
  9 + /// 说明是调用了跳转 WDRouterPage.loginPage 页面的行为
  10 + on(params?: object | undefined, singleMode?: boolean | undefined): boolean {
  11 +
  12 + HuaweiAuth.sharedInstance().fetchAnonymousPhone().then((anonymousPhone) => {
  13 +
  14 + router.pushUrl({url: WDRouterPage.oneKeyLoginPage.url()})
  15 + }).catch((error: string) => {
  16 + router.pushUrl({url: WDRouterPage.loginPage.url()})
  17 + })
  18 + return true
  19 + }
  20 +}
  21 +
  22 +export class LoginModule {
  23 +
  24 + static startup() {
  25 +
  26 + /// 初始化华为一键登录相关
  27 + if (HuaweiAuth.enable) {
  28 +
  29 + HuaweiAuth.sharedInstance().registerEvents()
  30 +
  31 + AccountManagerUtils.isLogin().then((login) => {
  32 + if (!login) {
  33 + HuaweiAuth.sharedInstance().rePrefetchAnonymousPhone()
  34 + }
  35 + })
  36 + RouterJumpInterceptor.register(WDRouterPage.loginPage, new LoginJumpHandler())
  37 + }
  38 +
  39 + }
  40 +}
@@ -9,6 +9,10 @@ import { WDRouterPage } from 'wdRouter/src/main/ets/router/WDRouterPage'; @@ -9,6 +9,10 @@ import { WDRouterPage } from 'wdRouter/src/main/ets/router/WDRouterPage';
9 import { WDRouterRule } from 'wdRouter/src/main/ets/router/WDRouterRule'; 9 import { WDRouterRule } from 'wdRouter/src/main/ets/router/WDRouterRule';
10 import { Params } from '../../../../../../../commons/wdRouter/oh_modules/wdBean/src/main/ets/bean/content/Params' 10 import { Params } from '../../../../../../../commons/wdRouter/oh_modules/wdBean/src/main/ets/bean/content/Params'
11 import {InterestsHobbiesModel} from '../../../../../../../products/phone/src/main/ets/pages/viewModel/InterestsHobbiesModel' 11 import {InterestsHobbiesModel} from '../../../../../../../products/phone/src/main/ets/pages/viewModel/InterestsHobbiesModel'
  12 +import HuaweiAuth from '../../utils/HuaweiAuth'
  13 +import { loginComponentManager, LoginWithHuaweiIDButton } from '@hms.core.account.LoginComponent'
  14 +import { BusinessError } from '@ohos.base'
  15 +
12 @Extend(Row) 16 @Extend(Row)
13 function otherStyle() { 17 function otherStyle() {
14 .backgroundImageSize(ImageSize.Cover) 18 .backgroundImageSize(ImageSize.Cover)
@@ -56,7 +60,6 @@ struct LoginPage { @@ -56,7 +60,6 @@ struct LoginPage {
56 }) 60 })
57 loginViewModel = new LoginViewModel() 61 loginViewModel = new LoginViewModel()
58 @State isProtocol:boolean=false 62 @State isProtocol:boolean=false
59 -  
60 onCodeSend() { 63 onCodeSend() {
61 Logger.debug(TAG, "isCodeSend:" + this.isCodeSend + "") 64 Logger.debug(TAG, "isCodeSend:" + this.isCodeSend + "")
62 if (this.isCodeSend) { 65 if (this.isCodeSend) {
@@ -15,6 +15,7 @@ struct LoginProtocolWebview { @@ -15,6 +15,7 @@ struct LoginProtocolWebview {
15 userProtocol = "https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1005.html" 15 userProtocol = "https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1005.html"
16 privateProtocol = 'https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1001.html' 16 privateProtocol = 'https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1001.html'
17 logoutProtocol = 'https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1003.html' 17 logoutProtocol = 'https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1003.html'
  18 + huaweiAuthProtocol = 'https://privacy.consumer.huawei.com/legal/id/authentication-terms.htm?code=CN&language=zh-CN'
18 19
19 async aboutToAppear() { 20 async aboutToAppear() {
20 if (router.getParams()) { 21 if (router.getParams()) {
@@ -30,6 +31,9 @@ struct LoginProtocolWebview { @@ -30,6 +31,9 @@ struct LoginProtocolWebview {
30 }else if(params.contentID == "3"){ //注销协议 31 }else if(params.contentID == "3"){ //注销协议
31 this.webUrl = await SPHelper.default.get(SpConstants.LOGOUT_PROTOCOL, this.logoutProtocol) as string 32 this.webUrl = await SPHelper.default.get(SpConstants.LOGOUT_PROTOCOL, this.logoutProtocol) as string
32 this.webviewController.loadUrl(this.webUrl) 33 this.webviewController.loadUrl(this.webUrl)
  34 + } else if(params.contentID == "4"){ //华为用户认证协议
  35 + this.webUrl = this.huaweiAuthProtocol
  36 + this.webviewController.loadUrl(this.webUrl)
33 } 37 }
34 } 38 }
35 39
  1 +import { router } from '@kit.ArkUI'
  2 +import { Params } from 'wdBean/Index'
  3 +import { WDRouterPage, WDRouterRule } from 'wdRouter/Index'
  4 +import HuaweiAuth from '../../utils/HuaweiAuth'
  5 +import { BusinessError } from '@kit.BasicServicesKit'
  6 +
  7 +@Entry
  8 +@Component
  9 +struct OneKeyLoginPage {
  10 + anonymousPhone: string = ''
  11 + @State agreeProtocol: boolean = false
  12 +
  13 + aboutToAppear(): void {
  14 + this.anonymousPhone = HuaweiAuth.sharedInstance().anonymousPhone||""
  15 + }
  16 +
  17 + build() {
  18 + Column() {
  19 + this.CloseRow()
  20 +
  21 + Image($r("app.media.login_logo"))
  22 + .width(120)
  23 + .height(66)
  24 + .margin({ top: 78, bottom: 74})
  25 + .align(Alignment.Center)
  26 +
  27 + Text(this.anonymousPhone)
  28 + .fontSize(30)
  29 + .fontWeight(600)
  30 + .fontColor("#222222")
  31 + .margin({bottom: 10})
  32 + .align(Alignment.Center)
  33 +
  34 + this.ProtocolRow()
  35 +
  36 + Row() {
  37 + Button("华为账号一键登录")
  38 + .type(ButtonType.Normal)
  39 + .height(48)
  40 + .backgroundColor(!this.agreeProtocol ? Color.Grey : Color.Red)
  41 + .width("100%")
  42 + .onClick((event) => {
  43 + if (!this.agreeProtocol) {
  44 + return
  45 + }
  46 + HuaweiAuth.sharedInstance().oneKeyLogin().then((authorizeCode) => {
  47 +
  48 + //TODO: 调用服务端接口登录
  49 + }).catch((error: BusinessError) => {
  50 +
  51 + })
  52 + })
  53 + }
  54 + .padding({ left: 25, right: 25 })
  55 + .margin({top: 15})
  56 +
  57 + Button("其他手机号登录")
  58 + .type(ButtonType.Normal)
  59 + .align(Alignment.Center)
  60 + .foregroundColor("#666666")
  61 + .backgroundColor(Color.White)
  62 + .onClick((event) => {
  63 + router.replaceUrl({url: WDRouterPage.loginPage.url()})
  64 + })
  65 + }
  66 + }
  67 +
  68 + @Builder ProtocolRow() {
  69 + Row({space: 4}) {
  70 + Image(this.agreeProtocol ? $r('app.media.login_checkbox_select') : $r('app.media.login_checkbox_unselected'))
  71 + .width(15)
  72 + .height(15)
  73 + .onClick(() => {
  74 + this.agreeProtocol = !this.agreeProtocol
  75 + })
  76 + Text() {
  77 + Span("我已阅读并同意").fontColor("#999999").fontSize(12)
  78 + Span("《用户协议》").fontColor("#ED2800").fontSize(12).onClick(() => {
  79 + let bean = { contentID: "1", pageID: "" } as Params
  80 + WDRouterRule.jumpWithPage(WDRouterPage.loginProtocolPage, bean)
  81 + })
  82 + Span("、").fontColor("#999999").fontSize(12)
  83 + Span("《隐私政策》").fontColor("#ED2800").fontSize(12).onClick(() => {
  84 + let bean = { contentID: "2", pageID: "" } as Params
  85 + WDRouterRule.jumpWithPage(WDRouterPage.loginProtocolPage, bean)
  86 + })
  87 + Span("和").fontColor("#999999").fontSize(12)
  88 + Span("《华为账号用户认证协议》").fontColor("#ED2800").fontSize(12).onClick(() => {
  89 + let bean = { contentID: "4", pageID: "" } as Params
  90 + WDRouterRule.jumpWithPage(WDRouterPage.loginProtocolPage, bean)
  91 + })
  92 + }
  93 + .layoutWeight(1)
  94 + }
  95 + .margin({top: 15})
  96 + .padding({ left: 25, right: 25 })
  97 + .width('100%')
  98 + }
  99 +
  100 + @Builder CloseRow() {
  101 + Row() {
  102 + Blank()
  103 + Image($r('app.media.login_closed'))
  104 + .width(24)
  105 + .height(24)
  106 + .onClick(() => router.back())
  107 + }.margin({ top: 15, right: 15 })
  108 + .width("100%")
  109 + }
  110 +}
  1 +import { authentication, extendService } from '@kit.AccountKit';
  2 +import { AccountManagerUtils, EmitterEventId, EmitterUtils, Logger } from 'wdKit/Index';
  3 +import { util } from '@kit.ArkTS';
  4 +import { DEFAULT } from '@ohos/hypium';
  5 +import { BusinessError } from '@kit.BasicServicesKit';
  6 +
  7 +const TAG = "HuaweiOneKeyAuth"
  8 +
  9 +export default class HuaweiAuth {
  10 +
  11 + // 是否开启
  12 + static enable = false
  13 + // 匿名手机号
  14 + private _anonymousPhone?: string
  15 + get anonymousPhone() {
  16 + return this._anonymousPhone
  17 + }
  18 +
  19 + private static instance: HuaweiAuth
  20 + static sharedInstance(): HuaweiAuth {
  21 + if (!HuaweiAuth.instance) {
  22 + HuaweiAuth.instance = new HuaweiAuth()
  23 + }
  24 + return HuaweiAuth.instance
  25 + }
  26 +
  27 + registerEvents() {
  28 + // 注册用户退出登录,取一次用来下次使用
  29 + EmitterUtils.receiveEvent(EmitterEventId.FORCE_USER_LOGIN_OUT, ((str?: string) => {
  30 + HuaweiAuth.sharedInstance().rePrefetchAnonymousPhone()
  31 + }))
  32 + EmitterUtils.receiveEvent(EmitterEventId.APP_ENTER_FOREGROUD, ((str?: string) => {
  33 + AccountManagerUtils.isLogin().then((login) => {
  34 + if (!login) {
  35 + HuaweiAuth.sharedInstance().rePrefetchAnonymousPhone()
  36 + }
  37 + })
  38 + }))
  39 + }
  40 +
  41 + // 重新预取手机号(App启动未登录、回前台未登录、和退出登录 时调用提前取号)
  42 + rePrefetchAnonymousPhone() {
  43 + this._anonymousPhone = undefined
  44 + this.fetchAnonymousPhone()
  45 + }
  46 +
  47 + // 要登录时,先调用。如果获取到手机号了 则弹起一键登录页面
  48 + fetchAnonymousPhone() : Promise<string> {
  49 +
  50 + return new Promise((resolve, fail) => {
  51 + if (this.anonymousPhone) {
  52 + resolve(this.anonymousPhone)
  53 + return
  54 + }
  55 +
  56 + let authRequest = new authentication.HuaweiIDProvider().createAuthorizationWithHuaweiIDRequest();
  57 + // 权限有 phone 、email、realTimePhone、quickLoginMobilePhone,这里用获取匿名手机号
  58 + authRequest.scopes = ['quickLoginAnonymousPhone'];
  59 + authRequest.state = util.generateRandomUUID();
  60 + authRequest.forceAuthorization = false;
  61 + let controller = new authentication.AuthenticationController(getContext(this));
  62 + try {
  63 + controller.executeRequest(authRequest).then((response: authentication.AuthorizationWithHuaweiIDResponse) => {
  64 + let anonymousPhone = response.data?.extraInfo?.quickLoginAnonymousPhone;
  65 + if (anonymousPhone) {
  66 + Logger.info(TAG, 'get anonymousPhone, ' + JSON.stringify(response));
  67 + this._anonymousPhone = anonymousPhone as string
  68 + resolve(this._anonymousPhone)
  69 + return;
  70 + }
  71 +
  72 + Logger.info(TAG, 'get anonymousPhone is empty. ' + JSON.stringify(response));
  73 + fail("获取匿名手机号为空")
  74 + }).catch((err: BusinessError) => {
  75 + Logger.error(TAG, 'get anonymousPhone failed. ' + JSON.stringify(err));
  76 + fail("获取匿名手机号失败")
  77 + })
  78 + } catch (err) {
  79 + Logger.error(TAG, 'get anonymousPhone fail. ' + JSON.stringify(err));
  80 + fail("获取匿名手机号失败")
  81 + }
  82 + })
  83 + }
  84 +
  85 + // 华为账号一键登录授权
  86 + // 返回结果为 Authorization Code
  87 + oneKeyLogin() : Promise<string> {
  88 +
  89 + let loginRequest = new authentication.HuaweiIDProvider().createLoginWithHuaweiIDRequest();
  90 + // 当用户未登录华为帐号时,是否强制拉起华为帐号登录界面
  91 + loginRequest.forceLogin = true;
  92 + loginRequest.state = util.generateRandomUUID();
  93 +
  94 + return new Promise((resolve, fail) => {
  95 +
  96 + try {
  97 + let controller = new authentication.AuthenticationController(getContext(this));
  98 + controller.executeRequest(loginRequest, (err, data) => {
  99 + if (err) {
  100 + Logger.error(TAG, 'login fail, ' + JSON.stringify(err))
  101 + fail(err)
  102 + return;
  103 + }
  104 + let loginWithHuaweiIDResponse = data as authentication.LoginWithHuaweiIDResponse;
  105 + let state = loginWithHuaweiIDResponse.state;
  106 + if (state != undefined && loginRequest.state != state) {
  107 + Logger.error(TAG, 'login fail, The state is different' + JSON.stringify(loginWithHuaweiIDResponse))
  108 + fail({
  109 + code: 99999,
  110 + name: "一键登录",
  111 + message:"状态错误:" + `请求状态 ${loginRequest.state}, 结果状态 ${state}`
  112 + } as BusinessError)
  113 + return;
  114 + }
  115 +
  116 + Logger.info(TAG, 'login success, ' + JSON.stringify(loginWithHuaweiIDResponse));
  117 + let loginWithHuaweiIDCredential = loginWithHuaweiIDResponse.data!;
  118 + let authorizationCode = loginWithHuaweiIDCredential.authorizationCode;
  119 + resolve(authorizationCode!)
  120 + });
  121 + } catch (error) {
  122 + Logger.error(TAG, 'login fail, ' + JSON.stringify(error))
  123 + fail(error)
  124 + }
  125 + });
  126 + }
  127 +
  128 + // 打开账户中心
  129 + openAccountCenter() {
  130 + try {
  131 + extendService.startAccountCenter(getContext(this), (err, data) => {
  132 + if (err) {
  133 + Logger.info(TAG, 'startAccountCenterWithCallback fail,error: ' + JSON.stringify(err));
  134 + return;
  135 + }
  136 + Logger.info(TAG, 'startAccountCenterWithCallback success');
  137 + });
  138 + } catch (error) {
  139 + Logger.error(TAG, 'startAccountCenterWithCallback fail,error: ' + JSON.stringify(error));
  140 + }
  141 + }
  142 +}
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 "pages/login/LoginProtocolWebview", 6 "pages/login/LoginProtocolWebview",
7 "pages/login/SettingPasswordPage", 7 "pages/login/SettingPasswordPage",
8 "pages/login/SettingPasswordLayout", 8 "pages/login/SettingPasswordLayout",
9 - "pages/guide/GuidePages" 9 + "pages/guide/GuidePages",
  10 + "pages/login/OneKeyLoginPage"
10 ] 11 ]
11 } 12 }
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 "wdRouter": "file:../../commons/wdRouter", 16 "wdRouter": "file:../../commons/wdRouter",
17 "wdNetwork": "file:../../commons/wdNetwork", 17 "wdNetwork": "file:../../commons/wdNetwork",
18 "wdHwAbility": "file:../../features/wdHwAbility", 18 "wdHwAbility": "file:../../features/wdHwAbility",
19 - "wdJsBridge": "file:../../commons/wdJsBridge" 19 + "wdJsBridge": "file:../../commons/wdJsBridge",
  20 + "wdLogin": "file:../../features/wdLogin"
20 } 21 }
21 } 22 }
@@ -15,12 +15,14 @@ import { @@ -15,12 +15,14 @@ import {
15 WindowModel 15 WindowModel
16 } from 'wdKit'; 16 } from 'wdKit';
17 import { HostEnum, HostManager, WDHttp } from 'wdNetwork'; 17 import { HostEnum, HostManager, WDHttp } from 'wdNetwork';
  18 +import { LoginModule } from 'wdLogin/src/main/ets/LoginModule';
18 19
19 export default class EntryAbility extends UIAbility { 20 export default class EntryAbility extends UIAbility {
20 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { 21 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
21 SPHelper.init(this.context); 22 SPHelper.init(this.context);
22 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 23 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
23 registerRouter(); 24 registerRouter();
  25 + LoginModule.startup()
24 NetworkManager.getInstance().init() 26 NetworkManager.getInstance().init()
25 WDHttp.initHttpHeader() 27 WDHttp.initHttpHeader()
26 const spHostUrl = SPHelper.default.getSync('hostUrl', '') as string 28 const spHostUrl = SPHelper.default.getSync('hostUrl', '') as string
@@ -94,10 +96,14 @@ export default class EntryAbility extends UIAbility { @@ -94,10 +96,14 @@ export default class EntryAbility extends UIAbility {
94 onForeground(): void { 96 onForeground(): void {
95 // Ability has brought to foreground 97 // Ability has brought to foreground
96 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); 98 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
  99 +
  100 + EmitterUtils.sendEmptyEvent(EmitterEventId.APP_ENTER_FOREGROUD)
97 } 101 }
98 102
99 onBackground(): void { 103 onBackground(): void {
100 // Ability has back to background 104 // Ability has back to background
101 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); 105 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
  106 +
  107 + EmitterUtils.sendEmptyEvent(EmitterEventId.APP_ENTER_BACKGROUD)
102 } 108 }
103 } 109 }
@@ -34,6 +34,10 @@ @@ -34,6 +34,10 @@
34 ] 34 ]
35 } 35 }
36 ], 36 ],
  37 + "metadata": [{
  38 + "name": "client_id",
  39 + "value": "220837707901830144"
  40 + }],
37 "requestPermissions": [ 41 "requestPermissions": [
38 { 42 {
39 "name": "ohos.permission.CAMERA", 43 "name": "ohos.permission.CAMERA",
@@ -88,6 +92,6 @@ @@ -88,6 +92,6 @@
88 { 92 {
89 "name": "ohos.permission.INTERNET" 93 "name": "ohos.permission.INTERNET"
90 } 94 }
91 - ], 95 + ]
92 } 96 }
93 } 97 }