yanlu

fix:16994 功能缺陷--进入直播,点击直播预告,点击更多按钮,进入直播预告详情页,已预约直播间,显示预约按钮,预期显示已预约按钮

@@ -26,6 +26,9 @@ export enum EmitterEventId { @@ -26,6 +26,9 @@ export enum EmitterEventId {
26 // 换绑成功 26 // 换绑成功
27 PHONE_CHANGE_SUCCESS = 9, 27 PHONE_CHANGE_SUCCESS = 9,
28 28
  29 + // 直播间-取消-预约成功
  30 + LIVE_ROOM_SUBSCRIBE = 10,
  31 +
29 // App回到前台 32 // App回到前台
30 APP_ENTER_FOREGROUD = 100, 33 APP_ENTER_FOREGROUD = 100,
31 // App进入后台 34 // App进入后台
@@ -213,7 +213,7 @@ export class HttpUrlUtils { @@ -213,7 +213,7 @@ export class HttpUrlUtils {
213 /** 213 /**
214 * 预约状态 214 * 预约状态
215 */ 215 */
216 - static readonly LIVE_APPOINTMENT_BATCH_PATH: string = "api/live-center-message/zh/c/live/subscribe/user/batch"; 216 + static readonly LIVE_APPOINTMENT_BATCH_PATH: string = "/api/live-center-message/zh/c/live/subscribe/user/batch";
217 /** 217 /**
218 218
219 * 搜索结果 显示tab 数 219 * 搜索结果 显示tab 数
@@ -123,7 +123,7 @@ export class WDRouterPage { @@ -123,7 +123,7 @@ export class WDRouterPage {
123 //直播更多页 123 //直播更多页
124 static liveMorePage = new WDRouterPage("wdComponent", "ets/components/page/LiveMorePage"); 124 static liveMorePage = new WDRouterPage("wdComponent", "ets/components/page/LiveMorePage");
125 //预约更多页 125 //预约更多页
126 - static reserveMorePage = new WDRouterPage("wdComponent", "ets/components/page/ReserveMorePage"); 126 + static reserveMorePage = new WDRouterPage("wdComponent", "ets/components/reserveMore/ReserveMorePage");
127 //金刚位聚合页 127 //金刚位聚合页
128 static themeListPage = new WDRouterPage("wdComponent", "ets/components/page/ThemeListPage"); 128 static themeListPage = new WDRouterPage("wdComponent", "ets/components/page/ThemeListPage");
129 // 栏目页面、频道详情 129 // 栏目页面、频道详情
@@ -169,3 +169,6 @@ export { ClassBean } from './src/main/ets/bean/content/ClassBean'; @@ -169,3 +169,6 @@ export { ClassBean } from './src/main/ets/bean/content/ClassBean';
169 export { CreatorsBean } from './src/main/ets/bean/content/CreatorsBean'; 169 export { CreatorsBean } from './src/main/ets/bean/content/CreatorsBean';
170 170
171 export { MasterDetailRes } from './src/main/ets/bean/user/MasterDetailRes'; 171 export { MasterDetailRes } from './src/main/ets/bean/user/MasterDetailRes';
  172 +
  173 +export { ReserveItemBean } from './src/main/ets/bean/live/ReserveItemBean';
  174 +
  1 +
  2 +@Observed export class ReserveItemBean {
  3 + liveId: number
  4 + relationId: string
  5 + subscribe: boolean
  6 + constructor( liveId: number, relationId: string, subscribe: boolean) {
  7 + this.liveId = liveId;
  8 + this.relationId = relationId;
  9 + this.subscribe = subscribe;
  10 + }
  11 +}
1 -import { CompDTO, ContentDTO, Params, Action } from 'wdBean'; 1 +import { CompDTO, ContentDTO, Params, Action, ReserveItemBean} from 'wdBean';
2 import { WDRouterPage, WDRouterRule } from 'wdRouter/Index'; 2 import { WDRouterPage, WDRouterRule } from 'wdRouter/Index';
3 import { postInteractAccentionOperateParams } from 'wdBean'; 3 import { postInteractAccentionOperateParams } from 'wdBean';
4 import { PageRepository } from '../../repository/PageRepository'; 4 import { PageRepository } from '../../repository/PageRepository';
@@ -16,11 +16,6 @@ import { SpConstants } from 'wdConstant/Index' @@ -16,11 +16,6 @@ import { SpConstants } from 'wdConstant/Index'
16 */ 16 */
17 const TAG = 'Zh_Single_Row-03' 17 const TAG = 'Zh_Single_Row-03'
18 18
19 -interface reserveItem {  
20 - liveId: number,  
21 - relationId: string,  
22 - subscribe: boolean  
23 -}  
24 19
25 interface reserveReqItem { 20 interface reserveReqItem {
26 liveId: string, 21 liveId: string,
@@ -54,7 +49,8 @@ export struct ZhSingleRow03 { @@ -54,7 +49,8 @@ export struct ZhSingleRow03 {
54 }) 49 })
55 const res = await LiveModel.getAppointmentStatus(reserveBean); 50 const res = await LiveModel.getAppointmentStatus(reserveBean);
56 // this.reserveStatus = res; 51 // this.reserveStatus = res;
57 - res.map((item: reserveItem) => { 52 + Logger.debug(TAG, '数据信息:' + `${JSON.stringify(res)}`)
  53 + res.map((item: ReserveItemBean) => {
58 if (item.subscribe) { 54 if (item.subscribe) {
59 this.reservedIds.push(item.liveId.toString()) 55 this.reservedIds.push(item.liveId.toString())
60 } 56 }
1 -import { ContentDTO, ReserveBean } from 'wdBean';  
2 -import { ProcessUtils } from 'wdRouter';  
3 -import { CommonConstants } from 'wdConstant/Index';  
4 -import PageViewModel from '../../viewmodel/PageViewModel';  
5 -import RefreshLayout from '../page/RefreshLayout';  
6 -import { RefreshLayoutBean } from '../page/RefreshLayoutBean';  
7 -import PageModel from '../../viewmodel/PageModel';  
8 -import { LazyDataSource } from 'wdKit/Index';  
9 -import { router } from '@kit.ArkUI';  
10 -import { LiveModel } from '../../viewmodel/LiveModel';  
11 -  
12 -const TAG: string = 'ReserveMorePage';  
13 -  
14 -/**  
15 - * 预约更多:  
16 - * type=1 直播  
17 - * type=2 预约  
18 - * 卡片结构:上下结构  
19 - * 卡片宽度:充满父窗口  
20 - * 卡片高度,仅包含横板图片:图片高度由图片的宽度及宽高比决定,图片宽度占父窗口'100%',宽高比为16:9:  
21 - */  
22 -@Entry  
23 -@Component  
24 -struct ReserveMorePage {  
25 - @State private pageModel: PageModel = new PageModel();  
26 - @State data: LazyDataSource<ContentDTO> = new LazyDataSource();  
27 - reserveBean: ReserveBean[] = []  
28 - topSafeHeight: number = AppStorage.get<number>('topSafeHeight') as number;  
29 - type: number = 2;  
30 - currentPage: number = 1;  
31 - pageSize: number = 20;  
32 - operDataList: ContentDTO[] = [];  
33 - title: string = '预约列表'  
34 - //是否预约过直播  
35 - @State isAppointmentLive: boolean = false  
36 - @State contentDTO: ContentDTO = new ContentDTO()  
37 - // appStyle: '15',  
38 - // coverType: 1,  
39 - // objectType: '9',  
40 - // coverUrl: 'https://rmrbcmsonline.peopleapp.com/rb_recsys/img/2024/0413/VL20Z09ISBEKXZU_963672030241091584.jpeg?x-oss-process=image/resize,m_fill,h_450,w_800/quality,q_90',  
41 - // fullColumnImgUrls: [  
42 - // {  
43 - // landscape: 2,  
44 - // size: 1,  
45 - // url: 'https://rmrbcmsonline.peopleapp.com/rb_recsys/img/2024/0413/VL20Z09ISBEKXZU_963672030241091584.jpeg?x-oss-process=image/resize,m_fill,h_450,w_800/quality,q_90',  
46 - // weight: 1170  
47 - // }  
48 - // ],  
49 - // newsTitle: '押解画面公开!被湖北民警从柬埔寨押解回国被湖北民警从柬埔寨押解回国的130名涉赌诈嫌疑人是他们被湖北民警从柬埔寨押解回国的130名涉赌诈嫌疑人是他们的130名涉赌诈嫌疑人是他们',  
50 - // publishTime: '1712993333000',  
51 - // rmhInfo: {  
52 - // authIcon: '',  
53 - // authTitle: '',  
54 - // authTitle2: '',  
55 - // banControl: 0,  
56 - // cnIsAttention: 1,  
57 - // rmhDesc: '中共武汉市委机关报长江日报官方人民号',  
58 - // rmhHeadUrl: 'https://uatjdcdnphoto.aikan.pdnews.cn/vod/content/202302/202302Sa121448724/TUw.png?x-oss-process=image/resize,l_100/auto-orient,1/quality,q_90/format,jpg',  
59 - // rmhId: '4255270',  
60 - // rmhName: '长江日报',  
61 - // userId: '513696944662469',  
62 - // userType: '3'  
63 - // },  
64 - // videoInfo: {  
65 - // firstFrameImageUri: '',  
66 - // videoDuration: 12,  
67 - // // videoLandscape: 2,  
68 - // videoUrl: 'https://rmrbcmsonline.peopleapp.com/rb_recsys/video/2024/0413/VL20Z09ISBEKXZU_963672027208609792.mp4'  
69 - // },  
70 - // photoNum: '9',  
71 - // voiceInfo: {  
72 - // voiceDuration: 12  
73 - // }  
74 - // } as ContentDTO;  
75 -  
76 - async aboutToAppear(): Promise<void> {  
77 - // PageViewModel.get  
78 -  
79 - PageViewModel.getLiveMoreUrl(this.type, this.currentPage, this.pageSize).then(async (liveReviewDTO) => {  
80 - // this.operDataList = []  
81 - // this.operDataList.push(...liveReviewDTO.list)  
82 - this.data.push(...liveReviewDTO.list)  
83 - this.reserveBean = this.transformToLiveDetailsBeans(liveReviewDTO.list)  
84 -  
85 - const apointMentStatus = await LiveModel.getAppointmentStatus(this.reserveBean)  
86 - // console.info(`cj2024 ${apointMentStatus.code}`)  
87 - })  
88 -  
89 -  
90 - }  
91 -  
92 - // 这个函数遍历liveReviewDTO.list并转换为LiveDetailsBean数组  
93 - transformToLiveDetailsBeans(list: ContentDTO[]): ReserveBean[] {  
94 - const liveDetailsBeans: ReserveBean[] = [];  
95 - list.forEach(item => {  
96 - liveDetailsBeans.push({  
97 - relationId: item.relId,  
98 - liveId: item.objectId,  
99 - });  
100 - });  
101 - return liveDetailsBeans  
102 - }  
103 -  
104 - build() {  
105 - // Navigation() {  
106 - // //滑动区域  
107 - // this.ListLayout()  
108 - // }  
109 - // .titleMode(NavigationTitleMode.Mini)  
110 - // .title('直播列表')  
111 -  
112 - Column() {  
113 - this.TabbarNormal()  
114 - Column() {  
115 - this.ListLayout()  
116 - }  
117 - .padding({  
118 - left: $r('app.float.card_comp_pagePadding_lf'),  
119 - right: $r('app.float.card_comp_pagePadding_lf'),  
120 - bottom: $r('app.float.card_comp_pagePadding_tb')  
121 - })  
122 - }  
123 - .backgroundColor('#F5F5F5')  
124 -  
125 - // .onClick((event: ClickEvent) => {  
126 - // ProcessUtils.processPage(this.contentDTO)  
127 - // })  
128 - }  
129 -  
130 - @Builder  
131 - ListLayout() {  
132 - List() {  
133 - // 下拉刷新  
134 - ListItem() {  
135 - RefreshLayout({  
136 - refreshBean: new RefreshLayoutBean(this.pageModel.isVisiblePullDown, this.pageModel.pullDownRefreshImage,  
137 - this.pageModel.pullDownRefreshText, this.pageModel.pullDownRefreshHeight)  
138 - })  
139 - }  
140 -  
141 - LazyForEach(this.data, (contentDTO: ContentDTO, contentIndex: number) => {  
142 - ListItem() {  
143 - // Column() {  
144 - // CompParser({ compDTO: compDTO, compIndex: compIndex });  
145 - // }  
146 - this.buildItem(contentDTO)  
147 - }  
148 - },  
149 - (contentDTO: ContentDTO, contentIndex: number) => contentDTO.pageId + contentIndex.toString()  
150 - )  
151 - }  
152 - .scrollBar(BarState.Off)  
153 - .cachedCount(8)  
154 - .height(CommonConstants.FULL_PARENT)  
155 - .backgroundColor('#F5F5F5')  
156 - .onScrollIndex((start: number, end: number) => {  
157 - // Listen to the first index of the current list.  
158 - this.pageModel.startIndex = start;  
159 - // 包含了 头尾item,判断时需要考虑+2  
160 - this.pageModel.endIndex = end;  
161 - })  
162 - }  
163 -  
164 - /**  
165 - * 组件项  
166 - *  
167 - * @param programmeBean item 组件项, 上面icon,下面标题  
168 - */  
169 - @Builder  
170 - buildItem(item: ContentDTO) {  
171 - Column({ space: 8 }) {  
172 - Stack() {  
173 - Image(item.fullColumnImgUrls[0].url)  
174 - .width('100%')  
175 - .height(196)  
176 - .borderRadius(4)  
177 - this.LiveImage()  
178 -  
179 - }  
180 - .alignContent(Alignment.BottomEnd)  
181 -  
182 - Text(item.newsTitle)  
183 - .fontSize(17)  
184 - .maxLines(2)  
185 - .textOverflow({ overflow: TextOverflow.Ellipsis })  
186 - .margin({ top: 16, left: 12, right: 12 })  
187 - .alignSelf(ItemAlign.Start)  
188 - Row() {  
189 - Row() {  
190 - Image($r('app.media.reserve_play_icon'))  
191 - .width(20)  
192 - .height(20)  
193 - .margin({ left: 10, top: 2, bottom: 2, right: 6 })  
194 - // Text(DateTimeUtils.formatDate(item.liveInfo.liveStartTime, "MM月dd日 HH:mm"))  
195 - Text(this.getReserveDate(item.liveInfo.liveStartTime, 1))  
196 - .fontSize(12)  
197 - .fontWeight(500)  
198 - .fontColor('#ED2800')  
199 - .fontFamily('PingFang SC-Medium')  
200 - .maxLines(1)  
201 - .textOverflow({ overflow: TextOverflow.Ellipsis })  
202 - .margin({ top: 8, bottom: 8 })  
203 - .align(Alignment.Start)  
204 -  
205 - Image($r('app.media.point_icon'))  
206 - .objectFit(ImageFit.Auto)  
207 - .interpolation(ImageInterpolation.High)  
208 - .width(6)  
209 - .height(16)  
210 - .margin(2)  
211 -  
212 - Text(this.getReserveDate(item.liveInfo.liveStartTime, 2))  
213 - .fontSize(12)  
214 - .fontWeight(500)  
215 - .fontColor('#ED2800')  
216 - .fontFamily('PingFang SC-Medium')  
217 - .maxLines(1)  
218 - .textOverflow({ overflow: TextOverflow.Ellipsis })  
219 - .margin({ top: 8, bottom: 8, right: 10 })  
220 - .align(Alignment.Start)  
221 - }  
222 - .backgroundColor('#F5F5F5')  
223 - .margin(12)  
224 -  
225 - Flex({ justifyContent: FlexAlign.Center }) {  
226 - Text(this.isAppointmentLive ? '已预约' : '预约')  
227 - .fontSize(12)  
228 - .fontWeight(400)  
229 - .fontFamily('PingFang SC-Regular')  
230 - .width(52)  
231 - .height(24)  
232 - .fontColor(Color.White)  
233 - .textAlign(TextAlign.Center)  
234 - .onClick(() => {  
235 - this.liveAppointment(item)  
236 - })  
237 - }  
238 - .width(52)  
239 - .backgroundColor('#ED2800')  
240 - .borderRadius(3)  
241 - .margin({ right: 12 })  
242 - }  
243 - .width('100%')  
244 - .justifyContent(FlexAlign.SpaceBetween)  
245 -  
246 - }  
247 - .borderRadius(4)  
248 - .backgroundColor(Color.White)  
249 - .width('100%')  
250 - .margin({ top: 12, bottom: 8 })  
251 - .onClick(() => {  
252 - ProcessUtils.processPage(item)  
253 - })  
254 - }  
255 -  
256 - getReserveDate(eventDateTimeString: string, type: number): string {  
257 - // 解析事件的日期和时间  
258 - const eventDateTime = new Date(eventDateTimeString);  
259 - const currentDateTime = new Date();  
260 -  
261 - // 截取事件时间的小时和分钟(假设事件时间是按照24小时制)  
262 - const eventHour = eventDateTime.getHours();  
263 - const eventMinutes = eventDateTime.getMinutes();  
264 - const eventTimeStr = `${eventHour}:${eventMinutes.toString().padStart(2, '0')}开始`; // 格式化时间,确保分钟是两位数  
265 -  
266 - // 计算时间差  
267 - const timeDifference = eventDateTime.getTime() - currentDateTime.getTime();  
268 -  
269 - // 如果事件在24小时内  
270 - if (type === 1) {  
271 - if (timeDifference > 0 && timeDifference <= 24 * 60 * 60 * 1000) {  
272 - return `今天`;  
273 - } else {  
274 - // 如果事件不在24小时内  
275 - const month = eventDateTime.getMonth() + 1; // 月份从0开始  
276 - const date = eventDateTime.getDate();  
277 - return `${month}月${date}日`;  
278 - }  
279 - } else {  
280 - return `${eventTimeStr}`;  
281 - }  
282 - }  
283 -  
284 - async liveAppointment(item: ContentDTO) {  
285 - // this.liveViewModel.liveAppointment(  
286 - // this.liveDetailsBean.reLInfo ? this.liveDetailsBean.reLInfo.relId : '',  
287 - // this.liveDetailsBean.newsId,  
288 - // !this.isAppointmentLive).then(  
289 - // (data) => {  
290 - // if (data.success) {  
291 - // this.isAppointmentLive = !this.isAppointmentLive  
292 - // }  
293 - // },  
294 - // () => {  
295 - //  
296 - // })  
297 - const liveDetail = await LiveModel.liveAppointment(item?.relId || '', item?.objectId || '', this.isAppointmentLive || false)  
298 - // const liveDetail = await LiveModel.getAppointmentStatus(item?.relId || '', item?.objectId || '', this.isAppointmentLive || false)  
299 - }  
300 -  
301 - /*导航栏*/  
302 - @Builder  
303 - TabbarNormal() {  
304 - RelativeContainer() {  
305 - //标题栏目  
306 - Image($r('app.media.icon_arrow_left'))  
307 - .width(24)  
308 - .height(24)  
309 - .objectFit(ImageFit.Auto)  
310 - .id("back_icon")  
311 - .alignRules({  
312 - center: { anchor: "__container__", align: VerticalAlign.Center },  
313 - left: { anchor: "__container__", align: HorizontalAlign.Start }  
314 - })  
315 - .onClick(() => {  
316 - router.back()  
317 - })  
318 -  
319 - Text(this.title)// .height('42lpx')  
320 - .maxLines(1)  
321 - .id("title")  
322 - .fontSize('35lpx')  
323 - .fontWeight(400)  
324 - .fontColor($r('app.color.color_222222'))  
325 - .lineHeight('42lpx')  
326 - .alignRules({  
327 - center: { anchor: "__container__", align: VerticalAlign.Center },  
328 - middle: { anchor: "__container__", align: HorizontalAlign.Center }  
329 - })  
330 - }  
331 - .backgroundColor('#FFFFFF')  
332 - .height(44)  
333 - .width('100%')  
334 - }  
335 -  
336 - @Builder  
337 - LiveImage() {  
338 - Row() {  
339 - Image($r('app.media.reserve_icon'))  
340 - .width(22)  
341 - .height(18)  
342 - Text('预约')  
343 - .fontSize('11fp')  
344 - .fontWeight(400)  
345 - .fontColor(Color.White)  
346 - }  
347 - .backgroundColor('#4D000000')  
348 - .margin({ right: 8, bottom: 8 })  
349 - }  
350 -}  
  1 +import { ContentDTO, ReserveBean, ReserveItemBean } from 'wdBean/Index';
  2 +import { ProcessUtils } from 'wdRouter/Index';
  3 +import PageViewModel from '../../viewmodel/PageViewModel';
  4 +import { Logger, EmitterEventId, EmitterUtils, ToastUtils } from 'wdKit/Index';
  5 +import { router } from '@kit.ArkUI';
  6 +import { LiveModel } from '../../viewmodel/LiveModel';
  7 +import { ViewType } from 'wdConstant/src/main/ets/enum/ViewType';
  8 +import { EmptyComponent } from '../view/EmptyComponent';
  9 +import { ErrorComponent } from '../view/ErrorComponent';
  10 +import { CustomPullToRefresh } from '../reusable/CustomPullToRefresh';
  11 +import { PeopleShipNoMoreData } from '../reusable/PeopleShipNoMoreData';
  12 +import { HttpUtils } from 'wdNetwork/Index';
  13 +import { WDRouterPage, WDRouterRule } from 'wdRouter'
  14 +import { LazyDataSource } from 'wdKit/Index';
  15 +
  16 +const TAG: string = 'ReserveMorePage';
  17 +
  18 +/**
  19 + * 预约更多:
  20 + * type=1 直播
  21 + * type=2 预约
  22 + * 卡片结构:上下结构
  23 + * 卡片宽度:充满父窗口
  24 + * 卡片高度,仅包含横板图片:图片高度由图片的宽度及宽高比决定,图片宽度占父窗口'100%',宽高比为16:9:
  25 + */
  26 +@Entry
  27 +@Component
  28 +struct ReserveMorePage {
  29 + @State data: LazyDataSource<ContentDTO> = new LazyDataSource();
  30 + @State reserveList: ReserveItemBean[] = []
  31 + topSafeHeight: number = AppStorage.get<number>('topSafeHeight') as number;
  32 + type: number = 2;
  33 + pageSize: number = 20;
  34 + title: string = '预约列表'
  35 + //是否预约过直播
  36 + @State isAppointmentLive: boolean = false
  37 + @State contentDTO: ContentDTO = {} as ContentDTO;
  38 + @State private hasMore: boolean = true
  39 + @State private currentPage: number = 1
  40 + @State private isLoading: boolean = false
  41 + @State viewType: ViewType = ViewType.LOADING
  42 + private scroller: Scroller = new Scroller()
  43 + @State reservedIds: string[] = []
  44 + @State isShow: boolean = false
  45 + @State private liveId: string = ''
  46 + @State isLoadingAttention: boolean = false
  47 +
  48 + build() {
  49 + Column(){
  50 + this.TabbarNormal()
  51 + if (this.viewType == ViewType.LOADING) {
  52 + this.LoadingLayout()
  53 + } else if (this.viewType == ViewType.ERROR) {
  54 + ErrorComponent()
  55 + .onTouch(() => {
  56 + if (this.viewType === ViewType.ERROR) {
  57 + this.getData()
  58 + }
  59 + })
  60 + } else if (this.viewType == ViewType.EMPTY) {
  61 + EmptyComponent()
  62 + } else {
  63 + CustomPullToRefresh({
  64 + alldata: this.data,
  65 + scroller: this.scroller,
  66 + hasMore: false,
  67 + customList: () => {
  68 + this.ListLayout()
  69 + },
  70 + onRefresh: (resolve) => {
  71 + this.currentPage = 1
  72 + this.getData(resolve)
  73 + },
  74 + })
  75 + }
  76 +
  77 + }.backgroundColor($r('app.color.color_F5F5F5'))
  78 +
  79 + }
  80 +
  81 + @Builder
  82 + LoadingLayout() {
  83 + }
  84 +
  85 + @Builder
  86 + ListLayout() {
  87 + List({scroller: this.scroller}) {
  88 + // 下拉刷新
  89 + LazyForEach(this.data, (contentDTO: ContentDTO, index: number) => {
  90 + ListItem() {
  91 + this.buildItem(contentDTO, index)
  92 + }
  93 + },
  94 + (contentDTO: ContentDTO, contentIndex: number) => contentDTO.pageId + contentIndex.toString()
  95 + )
  96 + // 加载更多
  97 + ListItem() {
  98 + if (!this.hasMore && !this.isLoading) {
  99 + PeopleShipNoMoreData()
  100 + }
  101 + }
  102 + }
  103 + .cachedCount(8)
  104 + .edgeEffect(EdgeEffect.None)
  105 + .scrollBar(BarState.Off)
  106 + .backgroundColor('#F5F5F5')
  107 + .layoutWeight(1)
  108 + .onReachEnd(() => {
  109 + Logger.debug(TAG, "触底了");
  110 + if(!this.isLoading && this.hasMore){
  111 + //加载分页数据
  112 + this.currentPage++;
  113 + this.getData()
  114 + }
  115 + })
  116 + }
  117 +
  118 + /**
  119 + * 组件项
  120 + *
  121 + * @param programmeBean item 组件项, 上面icon,下面标题
  122 + */
  123 + @Builder
  124 + buildItem(item: ContentDTO, index: number) {
  125 + Column() {
  126 + Stack() {
  127 + Image(item.fullColumnImgUrls[0].url)
  128 + .width('100%')
  129 + .height(196)
  130 + .borderRadius(4)
  131 + this.LiveImage()
  132 +
  133 + }
  134 + .alignContent(Alignment.BottomEnd)
  135 +
  136 + Text(item.newsTitle)
  137 + .fontSize(17)
  138 + .maxLines(2)
  139 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  140 + .margin({ top: 16, left: 12, right: 12 })
  141 + .alignSelf(ItemAlign.Start)
  142 + Row() {
  143 + Row() {
  144 + Image($r('app.media.reserve_play_icon'))
  145 + .width(20)
  146 + .height(20)
  147 + .margin({ left: 10, top: 2, bottom: 2, right: 6 })
  148 + // Text(DateTimeUtils.formatDate(item.liveInfo.liveStartTime, "MM月dd日 HH:mm"))
  149 + Text(this.getReserveDate(item.liveInfo.liveStartTime, 1))
  150 + .fontSize(12)
  151 + .fontWeight(500)
  152 + .fontColor('#ED2800')
  153 + .fontFamily('PingFang SC-Medium')
  154 + .maxLines(1)
  155 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  156 + .margin({ top: 8, bottom: 8 })
  157 + .align(Alignment.Start)
  158 +
  159 + Image($r('app.media.point_icon'))
  160 + .objectFit(ImageFit.Auto)
  161 + .interpolation(ImageInterpolation.High)
  162 + .width(6)
  163 + .height(16)
  164 + .margin(2)
  165 +
  166 + Text(this.getReserveDate(item.liveInfo.liveStartTime, 2))
  167 + .fontSize(12)
  168 + .fontWeight(500)
  169 + .fontColor('#ED2800')
  170 + .fontFamily('PingFang SC-Medium')
  171 + .maxLines(1)
  172 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  173 + .margin({ top: 8, bottom: 8, right: 10 })
  174 + .align(Alignment.Start)
  175 + }
  176 + .backgroundColor('#F5F5F5')
  177 + .margin(12)
  178 +
  179 + // Flex({ justifyContent: FlexAlign.Center }) {
  180 + // Text(this.isAppointmentLive ? '已预约' : '预约')
  181 + // .fontSize(12)
  182 + // .fontWeight(400)
  183 + // .fontFamily('PingFang SC-Regular')
  184 + // .width(52)
  185 + // .height(24)
  186 + // .fontColor(Color.White)
  187 + // .textAlign(TextAlign.Center)
  188 + // .onClick(() => {
  189 + // this.liveAppointment(item)
  190 + // })
  191 + // }
  192 + // .width(52)
  193 + // .backgroundColor('#ED2800')
  194 + // .borderRadius(3)
  195 + // ReserveMoreAttentionComponent({reserveItem: this.getAttentionItem(item), })
  196 + // .margin({ right: 12 })
  197 + Row() {
  198 + LoadingProgress()
  199 + .width(20)
  200 + .height(20)
  201 + .color(!this.isReserved(item) ? $r('app.color.color_fff') : $r('app.color.color_CCCCCC'))
  202 + .visibility((this.isLoadingAttention && this.liveId == item.objectId) ? Visibility.Visible : Visibility.None)
  203 +
  204 + Text(!this.isReserved(item) ? '关注' : '已关注')
  205 + .fontSize($r('app.float.vp_12'))
  206 + .fontWeight(500)
  207 + .fontColor(!this.isReserved(item) ? $r('app.color.color_fff') : $r('app.color.color_CCCCCC'))
  208 + .width('100%')
  209 + .height('100%')
  210 + .textAlign(TextAlign.Center)
  211 + .visibility((this.isLoadingAttention && this.liveId == item.objectId) ? Visibility.None : Visibility.Visible)
  212 + .margin({
  213 + right: '10vp'
  214 + })
  215 + .backgroundColor(!this.isReserved(item) ? $r('app.color.color_ED2800') : $r('app.color.color_F5F5F5'))
  216 + .borderRadius(3)
  217 +
  218 + }.onClick(() => {
  219 + this.bookAndCancel(item)
  220 + })
  221 + .justifyContent(FlexAlign.Center)
  222 + .alignItems(VerticalAlign.Center)
  223 + .borderRadius(3)
  224 + .width('52vp')
  225 + .height('24vp')
  226 + .margin({right: 12})
  227 +
  228 + }
  229 + .width('100%')
  230 + .justifyContent(FlexAlign.SpaceBetween)
  231 +
  232 + }
  233 + .borderRadius(4)
  234 + .backgroundColor(Color.White)
  235 + .width('calc(100% - 24vp)')
  236 + .margin({
  237 + left: '12vp',
  238 + right: '12vp',
  239 + top: index == 0 ? '12vp' : '8vp'
  240 + })
  241 + .onClick(() => {
  242 + ProcessUtils.processPage(item)
  243 + })
  244 + }
  245 +
  246 + /*导航栏*/
  247 + @Builder
  248 + TabbarNormal() {
  249 + RelativeContainer() {
  250 + //标题栏目
  251 + Image($r('app.media.icon_arrow_left'))
  252 + .width(24)
  253 + .height(24)
  254 + .objectFit(ImageFit.Auto)
  255 + .id("back_icon")
  256 + .alignRules({
  257 + center: { anchor: "__container__", align: VerticalAlign.Center },
  258 + left: { anchor: "__container__", align: HorizontalAlign.Start }
  259 + })
  260 + .onClick(() => {
  261 + router.back()
  262 + })
  263 +
  264 + Text(this.title)// .height('42lpx')
  265 + .maxLines(1)
  266 + .id("title")
  267 + .fontSize('35lpx')
  268 + .fontWeight(400)
  269 + .fontColor($r('app.color.color_222222'))
  270 + .lineHeight('42lpx')
  271 + .alignRules({
  272 + center: { anchor: "__container__", align: VerticalAlign.Center },
  273 + middle: { anchor: "__container__", align: HorizontalAlign.Center }
  274 + })
  275 + }
  276 + .backgroundColor('#FFFFFF')
  277 + .height(44)
  278 + .width('100%')
  279 + }
  280 +
  281 + @Builder
  282 + LiveImage() {
  283 + Row() {
  284 + Image($r('app.media.reserve_icon'))
  285 + .width(22)
  286 + .height(18)
  287 + Text('预约')
  288 + .fontSize('11fp')
  289 + .fontWeight(400)
  290 + .fontColor(Color.White)
  291 + }
  292 + .backgroundColor('#4D000000')
  293 + .margin({ right: 8, bottom: 8 })
  294 + }
  295 +
  296 + async aboutToAppear(): Promise<void> {
  297 + // PageViewModel.get
  298 + this.currentPage = 1
  299 + this.getData()
  300 + // 登录成功
  301 + EmitterUtils.receiveEvent(EmitterEventId.LOGIN_SUCCESS, () => {
  302 + this.currentPage = 1
  303 + this.getData()
  304 + })
  305 +
  306 + // 获取预约
  307 + EmitterUtils.receiveEvent(EmitterEventId.LIVE_ROOM_SUBSCRIBE, (str?: string) => {
  308 + Logger.debug(TAG, 'receiveEvent LIVE_ROOM_SUBSCRIBE: ' + str)
  309 + if (str) {
  310 + // 跳转指定频道场景,传参底导id、频道id
  311 + const model: ReserveItemBean = JSON.parse(str)
  312 + Logger.debug(TAG,'是否关注元数据0:' +` ${model.liveId}`)
  313 + if (model && model.liveId && this.reserveList) {
  314 + // 修改源数据
  315 + this.reserveList.forEach((element) => {
  316 + if (element.liveId == model.liveId) {
  317 + if (element && element.subscribe != model.subscribe) {
  318 + Logger.debug(TAG,'是否关注元数据2:' +` ${JSON.stringify(element.subscribe)}`)
  319 + element.subscribe = !element.subscribe
  320 + Logger.debug(TAG,'是否关注元数据3:' +` ${JSON.stringify(element.subscribe)}`)
  321 + this.data.reloadData()
  322 + this.isShow = true
  323 + }
  324 + }
  325 + })
  326 + }
  327 + }
  328 + })
  329 + }
  330 +
  331 + onPageShow(): void {
  332 + if (this.isShow) {
  333 + this.data.reloadData()
  334 + this.isShow = false
  335 + }
  336 + }
  337 +
  338 + private async getData(resolve?: (value: string | PromiseLike<string>) => void) {
  339 + if (this.isLoading) {
  340 + if (resolve) {
  341 + resolve('已更新至最新')
  342 + }
  343 + return
  344 + }
  345 + this.isLoading = true
  346 + try {
  347 + const liveReviewDTO = await PageViewModel.getLiveMoreUrl(this.type, this.currentPage, this.pageSize)
  348 +
  349 + if (liveReviewDTO && liveReviewDTO.list && liveReviewDTO.list.length > 0) {
  350 + if (liveReviewDTO.list.length === this.pageSize) {
  351 + this.hasMore = true;
  352 + } else {
  353 + this.hasMore = false;
  354 + }
  355 + if (this.currentPage == 1) {
  356 + this.data.clear()
  357 + this.reserveList = []
  358 + }
  359 + this.data.push(...liveReviewDTO.list)
  360 + //批量查询关注状态
  361 + this.getAppointmentInfo(liveReviewDTO.list)
  362 + } else {
  363 + this.hasMore = false;
  364 + }
  365 + this.resolveEnd(true, resolve)
  366 + if (liveReviewDTO.list.length == 0 && this.currentPage == 1) {
  367 + this.viewType = ViewType.EMPTY
  368 + }
  369 + }catch (exception) {
  370 + this.resolveEnd(false, resolve)
  371 + }
  372 + // PageViewModel.getLiveMoreUrl(this.type, this.currentPage, this.pageSize).then(async (liveReviewDTO) => {
  373 + // // this.operDataList = []
  374 + // // this.operDataList.push(...liveReviewDTO.list)
  375 + // this.data.push(...liveReviewDTO.list)
  376 + //
  377 + // // this.getAppointmentInfo()
  378 + // })
  379 + }
  380 +
  381 + private resolveEnd(isTop: boolean, resolve?: (value: string | PromiseLike<string>) => void) {
  382 + if (resolve) {
  383 + if (this.currentPage == 1 && isTop) {
  384 + resolve('已更新至最新')
  385 + }else {
  386 + resolve('')
  387 + }
  388 + }
  389 + if (this.currentPage == 1 && !isTop) {
  390 + this.viewType = ViewType.ERROR
  391 + } else {
  392 + this.viewType = ViewType.LOADED
  393 + }
  394 + this.isLoading = false
  395 + }
  396 +
  397 + async getAppointmentInfo(list: ContentDTO[]) {
  398 + if (HttpUtils.getUserId()) {
  399 + const reserveBean = this.transformToLiveDetailsBeans(list)
  400 + Logger.debug(TAG,'是否预约数据:' +` ${JSON.stringify(reserveBean)}`)
  401 + LiveModel.getAppointmentStatus(reserveBean).then((result) => {
  402 + Logger.debug(TAG,'是否预约数据:' +` ${JSON.stringify(result)}`)
  403 + if (result && result.length > 0) {
  404 + this.reserveList.push(...result)
  405 + this.data.reloadData()
  406 + }
  407 + }).catch(() =>{
  408 + // this.data.push(...list)
  409 + })
  410 + }else {
  411 + // this.data.push(...list)
  412 +
  413 + }
  414 + }
  415 +
  416 + // 判断是否预约
  417 + isReserved(item: ContentDTO) {
  418 + const objc = this.getAttentionItem(item)
  419 + if (objc) {
  420 + return objc.subscribe
  421 + }
  422 + return false
  423 + }
  424 +
  425 + getAttentionItem(item: ContentDTO) {
  426 + const objc = this.reserveList.find((element: ReserveItemBean) => {
  427 + return element.liveId.toString() == item.objectId
  428 + })
  429 + return objc
  430 + }
  431 +
  432 + // 这个函数遍历liveReviewDTO.list并转换为LiveDetailsBean数组
  433 + transformToLiveDetailsBeans(list: ContentDTO[]): ReserveBean[] {
  434 + const liveDetailsBeans: ReserveBean[] = [];
  435 + list.forEach(item => {
  436 + liveDetailsBeans.push({
  437 + relationId: item.relId,
  438 + liveId: item.objectId,
  439 + });
  440 + });
  441 + return liveDetailsBeans
  442 + }
  443 +
  444 + // 预约/取消预约
  445 + async bookAndCancel(item: ContentDTO) {
  446 +
  447 + // 未登录,跳转登录
  448 + if (!HttpUtils.getUserId()) {
  449 + WDRouterRule.jumpWithPage(WDRouterPage.loginPage)
  450 + return
  451 + }
  452 + if (!this.isLoadingAttention && this.liveId.length == 0) {
  453 + this.isLoadingAttention = true
  454 + this.liveId = item.objectId
  455 + const reserveItem = this.getAttentionItem(item)
  456 + if (reserveItem) {
  457 + this.isLoadingAttention = true
  458 + this.liveId = reserveItem.liveId.toString()
  459 + try {
  460 + const res = await LiveModel.liveAppointment(reserveItem.relationId, reserveItem.liveId.toString(), !reserveItem.subscribe);
  461 + if (res.code == 0) {
  462 + ToastUtils.shortToast(!reserveItem.subscribe ? '预约成功' : '取消预约成功')
  463 + // 修改源数据
  464 + this.reserveList.forEach((element) => {
  465 + if (element.liveId.toString() == item.objectId) {
  466 + Logger.debug(TAG,'是否关注元数据:' +` ${JSON.stringify(element.subscribe)}`)
  467 + element.subscribe = !element.subscribe
  468 + Logger.debug(TAG,'是否关注元数据1:' +` ${JSON.stringify(element.subscribe)}`)
  469 + this.data.reloadData()
  470 + }
  471 + })
  472 + }
  473 + this.isLoadingAttention = false
  474 + this.liveId = ''
  475 + } catch (e) {
  476 + this.liveId = ''
  477 + this.isLoadingAttention = false
  478 + }
  479 + }else {
  480 + this.liveId = ''
  481 + this.isLoadingAttention = false
  482 + }
  483 + }
  484 + }
  485 +
  486 + getReserveDate(eventDateTimeString: string, type: number): string {
  487 + // 解析事件的日期和时间
  488 + const eventDateTime = new Date(eventDateTimeString);
  489 + const currentDateTime = new Date();
  490 +
  491 + // 截取事件时间的小时和分钟(假设事件时间是按照24小时制)
  492 + const eventHour = eventDateTime.getHours();
  493 + const eventMinutes = eventDateTime.getMinutes();
  494 + const eventTimeStr = `${eventHour}:${eventMinutes.toString().padStart(2, '0')}开始`; // 格式化时间,确保分钟是两位数
  495 +
  496 + // 计算时间差
  497 + const timeDifference = eventDateTime.getTime() - currentDateTime.getTime();
  498 +
  499 + // 如果事件在24小时内
  500 + if (type === 1) {
  501 + if (timeDifference > 0 && timeDifference <= 24 * 60 * 60 * 1000) {
  502 + return `今天`;
  503 + } else {
  504 + // 如果事件不在24小时内
  505 + const month = eventDateTime.getMonth() + 1; // 月份从0开始
  506 + const date = eventDateTime.getDate();
  507 + return `${month}月${date}日`;
  508 + }
  509 + } else {
  510 + return `${eventTimeStr}`;
  511 + }
  512 + }
  513 +
  514 + async liveAppointment(item: ContentDTO) {
  515 + const liveDetail = await LiveModel.liveAppointment(item?.relId || '', item?.objectId || '', this.isAppointmentLive || false)
  516 + }
  517 +
  518 +
  519 +}
1 import { PullToRefresh, PullToRefreshConfigurator } from '@ohos/pulltorefresh'; 1 import { PullToRefresh, PullToRefreshConfigurator } from '@ohos/pulltorefresh';
  2 +import { LazyDataSource } from 'wdKit';
2 3
3 @Component 4 @Component
4 export struct CustomPullToRefresh { 5 export struct CustomPullToRefresh {
5 - @Link alldata: Object[]; 6 + @Link alldata: Object[] | LazyDataSource<Object>;
6 scroller: Scroller = new Scroller(); 7 scroller: Scroller = new Scroller();
7 @BuilderParam customList: () => void; 8 @BuilderParam customList: () => void;
8 onRefresh: (resolve?: (value: string | PromiseLike<string>) => void) => void = () => { 9 onRefresh: (resolve?: (value: string | PromiseLike<string>) => void) => void = () => {
@@ -15,7 +16,7 @@ export struct CustomPullToRefresh { @@ -15,7 +16,7 @@ export struct CustomPullToRefresh {
15 build() { 16 build() {
16 Column(){ 17 Column(){
17 PullToRefresh({ 18 PullToRefresh({
18 - data:this.alldata, 19 + data:$alldata,
19 scroller:this.scroller, 20 scroller:this.scroller,
20 refreshConfigurator:this.refreshConfigurator, 21 refreshConfigurator:this.refreshConfigurator,
21 customList:()=>{ 22 customList:()=>{
1 import { HttpUrlUtils, ResponseDTO } from 'wdNetwork'; 1 import { HttpUrlUtils, ResponseDTO } from 'wdNetwork';
2 import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest'; 2 import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest';
3 -import { Logger, ToastUtils } from 'wdKit';  
4 -import { LiveDetailsBean, ReserveBean } from 'wdBean/Index'; 3 +import { Logger, ToastUtils, EmitterEventId, EmitterUtils } from 'wdKit';
  4 +import { LiveDetailsBean, ReserveBean, ReserveItemBean } from 'wdBean/Index';
5 5
6 const TAG = 'LiveModel' 6 const TAG = 'LiveModel'
7 7
8 -interface ReserveRes {  
9 - code: string | number,  
10 - data: ReserveItem[]  
11 -}  
12 8
13 -interface ReserveItem {  
14 - liveId: number,  
15 - relationId: string,  
16 - subscribe: boolean  
17 -} 9 +
18 10
19 export class LiveModel { 11 export class LiveModel {
20 /** 12 /**
@@ -70,6 +62,10 @@ export class LiveModel { @@ -70,6 +62,10 @@ export class LiveModel {
70 ToastUtils.shortToast(data.message) 62 ToastUtils.shortToast(data.message)
71 return 63 return
72 } 64 }
  65 + if (data.code == 0) {
  66 + const reserveModel = new ReserveItemBean(Number(liveId), relationId, isSubscribe)
  67 + EmitterUtils.sendEvent(EmitterEventId.LIVE_ROOM_SUBSCRIBE, JSON.stringify(reserveModel))
  68 + }
73 success(data) 69 success(data)
74 Logger.info('liveAppointment', JSON.stringify(data)) 70 Logger.info('liveAppointment', JSON.stringify(data))
75 }, (error: Error) => { 71 }, (error: Error) => {
@@ -89,11 +85,12 @@ export class LiveModel { @@ -89,11 +85,12 @@ export class LiveModel {
89 static getAppointmentStatus(reserveBean: ReserveBean[]) { 85 static getAppointmentStatus(reserveBean: ReserveBean[]) {
90 // let params: Record<string, ArrayList<ReserveBean>> = {}; 86 // let params: Record<string, ArrayList<ReserveBean>> = {};
91 // params = reserveBean 87 // params = reserveBean
92 - return new Promise<Array<ReserveItem>>((success, fail) => {  
93 - HttpRequest.post<ResponseDTO<Array<ReserveItem>>>( 88 + return new Promise<Array<ReserveItemBean>>((success, fail) => {
  89 + HttpRequest.post<ResponseDTO<Array<ReserveItemBean>>>(
94 HttpUrlUtils.getAppointmentStatusUrl(), 90 HttpUrlUtils.getAppointmentStatusUrl(),
95 reserveBean, 91 reserveBean,
96 - ).then((data: ResponseDTO<Array<ReserveItem>>) => { 92 + ).then((data: ResponseDTO<Array<ReserveItemBean>>) => {
  93 + Logger.debug(TAG, 'getAppointmentStatus:' + `${JSON.stringify(data)}`)
97 if (!data || !data.data) { 94 if (!data || !data.data) {
98 fail("数据为空") 95 fail("数据为空")
99 return 96 return
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 "components/page/PeopleShipHomePage", 19 "components/page/PeopleShipHomePage",
20 "pages/MultiPictureListPage", 20 "pages/MultiPictureListPage",
21 "components/page/LiveMorePage", 21 "components/page/LiveMorePage",
22 - "components/page/ReserveMorePage", 22 + "components/reserveMore/ReserveMorePage",
23 "pages/VideoPlayPage", 23 "pages/VideoPlayPage",
24 "components/page/ThemeListPage", 24 "components/page/ThemeListPage",
25 "pages/ShowUserHeaderPage", 25 "pages/ShowUserHeaderPage",
1 import { HttpUrlUtils, ResponseDTO } from 'wdNetwork'; 1 import { HttpUrlUtils, ResponseDTO } from 'wdNetwork';
2 import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest'; 2 import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest';
3 -import { Logger, ToastUtils } from 'wdKit';  
4 -import { ContentDetailDTO, LiveDetailsBean, LiveRoomBean, LiveRoomDataBean } from 'wdBean/Index'; 3 +import { Logger, ToastUtils, EmitterEventId, EmitterUtils } from 'wdKit';
  4 +import { ContentDetailDTO, LiveDetailsBean, LiveRoomBean, LiveRoomDataBean, ReserveItemBean } from 'wdBean/Index';
5 import { ContentDetailRequest } from 'wdDetailPlayApi/Index'; 5 import { ContentDetailRequest } from 'wdDetailPlayApi/Index';
6 6
7 const TAG = 'LiveModel' 7 const TAG = 'LiveModel'
@@ -199,6 +199,10 @@ export class LiveModel { @@ -199,6 +199,10 @@ export class LiveModel {
199 ToastUtils.shortToast(data.message) 199 ToastUtils.shortToast(data.message)
200 return 200 return
201 } 201 }
  202 + if (data.code == 0) {
  203 + const reserveModel = new ReserveItemBean(Number(liveId), relationId, isSubscribe)
  204 + EmitterUtils.sendEvent(EmitterEventId.LIVE_ROOM_SUBSCRIBE, JSON.stringify(reserveModel))
  205 + }
202 success(data) 206 success(data)
203 }, (error: Error) => { 207 }, (error: Error) => {
204 fail(error.message) 208 fail(error.message)