From 3013b441a6b311c0bca392528adf1455a9672781 Mon Sep 17 00:00:00 2001 From: xiaoxiao Date: Tue, 9 Sep 2025 13:27:34 +0800 Subject: [PATCH] =?UTF-8?q?1.2.0=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commons/basic/Index.ets | 14 +- .../main/ets/Views/DefaultHintProWindows.ets | 46 +- .../src/main/ets/constants/BasicConstant.ets | 26 + .../src/main/ets/constants/Constants.ets | 2 + .../basic/src/main/ets/models/FileModel.ets | 51 ++ .../basic/src/main/ets/models/WXApiWrap.ets | 44 + .../ets/utils/AESEncryptionDecryption.ets | 2 +- commons/basic/src/main/ets/utils/AppUtil.ets | 40 + .../basic/src/main/ets/utils/ChangeUtil.ets | 12 + .../main/ets/utils/FileDownloadManager.ets | 366 ++++++++ .../basic/src/main/ets/utils/FileManager.ets | 799 ++++++++++++++++++ .../src/main/ets/utils/FileManagerCopy.ets | 346 ++++++++ commons/basic/src/main/ets/utils/request.ets | 33 +- .../main/resources/base/media/fenxiang.png | Bin 0 -> 2153 bytes .../resources/base/media/huise_kongquan.png | Bin 0 -> 2221 bytes .../resources/base/media/wei_dian_zan.png | Bin 0 -> 2206 bytes .../resources/base/media/wei_shou_cang.png | Bin 0 -> 2017 bytes .../main/resources/base/media/yi_dian_zan.png | Bin 0 -> 1838 bytes .../resources/base/media/yi_shou_cang.png | Bin 0 -> 1644 bytes .../ets/components/HomeGanDanFileComp.ets | 179 ++++ .../src/main/ets/components/HomeIconComp.ets | 49 +- features/Home/src/main/ets/pages/HomePage.ets | 4 + .../Home/src/main/ets/pages/VideoGandan.ets | 12 + .../Home/src/main/ets/pages/VideoPage.ets | 4 +- .../base/media/home_guideAndShare_icon.png | Bin 0 -> 33261 bytes .../resources/base/media/home_kejian_icon.png | Bin 0 -> 8292 bytes .../resources/base/media/home_news_icon.png | Bin 0 -> 3473 bytes .../base/media/kejian_download_white.png | Bin 0 -> 1459 bytes .../resources/base/media/send_follow_icon.png | Bin 0 -> 7953 bytes .../mypage/src/main/ets/pages/MyHomePage.ets | 51 +- .../mypage/src/main/ets/view/ThreeSection.ets | 18 +- .../mypage/src/main/ets/view/TwoSection.ets | 14 +- .../base/media/my_page_coursewareDetails.png | Bin 0 -> 2049 bytes .../resources/base/media/my_page_download.png | Bin 0 -> 1581 bytes .../resources/base/media/my_page_myFlower.png | Bin 0 -> 3987 bytes features/study/Index.ets | 16 +- .../main/ets/components/CoursewareComp.ets | 3 + .../main/ets/components/FlowerDetailsComp.ets | 232 +++++ .../src/main/ets/components/KeepStudyComp.ets | 2 +- .../src/main/ets/components/MainPage.ets | 19 + .../src/main/ets/components/NewsComp.ets | 85 ++ .../src/main/ets/components/NewsListComp.ets | 188 +++++ .../study/src/main/ets/components/PayComp.ets | 323 +++++++ .../main/ets/components/SchoolhouseComp.ets | 22 - .../main/ets/components/SendFollowComp.ets | 343 ++++++++ .../study/src/main/ets/models/NewsModel.ets | 49 ++ .../study/src/main/ets/models/XinYiModel.ets | 17 + .../study/src/main/ets/utils/NewsUtil.ets | 33 + .../src/main/ets/views/ItemCompTeach.ets | 34 +- .../src/main/ets/views/KeJianItemComp.ets | 18 +- .../study/src/main/ets/views/NewsItemView.ets | 67 ++ .../src/main/ets/views/NewsSwiperView.ets | 79 ++ .../base/media/flower_accountJinbi_icon.png | Bin 0 -> 2560 bytes .../base/media/flower_expertFlower_icon.png | Bin 0 -> 2371 bytes .../base/media/home_top_scroll_default.png | Bin 0 -> 4380 bytes .../base/media/news_meeting_icon.png | Bin 0 -> 8916 bytes .../resources/base/media/news_new_icon.png | Bin 0 -> 4758 bytes .../base/media/patiemts_list_selected.png | Bin 0 -> 2304 bytes .../main/resources/base/media/patientLogo.png | Bin 0 -> 15347 bytes .../base/media/patients_list_noSelect.png | Bin 0 -> 3033 bytes .../resources/base/media/pay_account_icon.png | Bin 0 -> 2686 bytes .../main/resources/base/media/pay_wx_icon.png | Bin 0 -> 2865 bytes .../base/media/send_follow_list_icon.png | Bin 0 -> 2152 bytes .../base/media/send_header_follow_icon.png | Bin 0 -> 12543 bytes .../main/ets/entryability/EntryAbility.ets | 12 +- .../ets/pages/Download/AllDownloadPage.ets | 37 + .../ets/pages/Download/KeJianDownloadPage.ets | 149 ++++ .../ets/pages/Flower/FlowerDetailsPage.ets | 14 + .../main/ets/pages/LoginPage/LoginPage.ets | 3 +- .../main/ets/pages/Meeting/MeetingPage.ets | 14 + .../main/ets/pages/MinePage/SettingPage.ets | 2 +- .../ets/pages/News/GandanNewsListPage.ets | 14 + .../main/ets/pages/News/GandanNewsPages.ets | 14 + .../expert/src/main/ets/pages/Pay/PayPage.ets | 14 + .../src/main/ets/pages/Pay/SendFollowPage.ets | 14 + .../pages/WebView/EducationDetailsWebPage.ets | 178 +++- .../pages/WebView/KeJianDetailsWebPage.ets | 553 ++++++++++++ .../ets/pages/WebView/NewsDetailsWebPage.ets | 247 ++++++ products/expert/src/main/module.json5 | 9 + .../resources/base/profile/main_pages.json | 13 +- 80 files changed, 4824 insertions(+), 105 deletions(-) create mode 100644 commons/basic/src/main/ets/constants/Constants.ets create mode 100644 commons/basic/src/main/ets/models/FileModel.ets create mode 100644 commons/basic/src/main/ets/models/WXApiWrap.ets create mode 100644 commons/basic/src/main/ets/utils/FileDownloadManager.ets create mode 100644 commons/basic/src/main/ets/utils/FileManager.ets create mode 100644 commons/basic/src/main/ets/utils/FileManagerCopy.ets create mode 100644 commons/basic/src/main/resources/base/media/fenxiang.png create mode 100644 commons/basic/src/main/resources/base/media/huise_kongquan.png create mode 100644 commons/basic/src/main/resources/base/media/wei_dian_zan.png create mode 100644 commons/basic/src/main/resources/base/media/wei_shou_cang.png create mode 100644 commons/basic/src/main/resources/base/media/yi_dian_zan.png create mode 100644 commons/basic/src/main/resources/base/media/yi_shou_cang.png create mode 100644 features/Home/src/main/ets/components/HomeGanDanFileComp.ets create mode 100644 features/Home/src/main/resources/base/media/home_guideAndShare_icon.png create mode 100644 features/Home/src/main/resources/base/media/home_kejian_icon.png create mode 100644 features/Home/src/main/resources/base/media/home_news_icon.png create mode 100644 features/Home/src/main/resources/base/media/kejian_download_white.png create mode 100644 features/Home/src/main/resources/base/media/send_follow_icon.png create mode 100644 features/mypage/src/main/resources/base/media/my_page_coursewareDetails.png create mode 100644 features/mypage/src/main/resources/base/media/my_page_download.png create mode 100644 features/mypage/src/main/resources/base/media/my_page_myFlower.png create mode 100644 features/study/src/main/ets/components/FlowerDetailsComp.ets create mode 100644 features/study/src/main/ets/components/MainPage.ets create mode 100644 features/study/src/main/ets/components/NewsComp.ets create mode 100644 features/study/src/main/ets/components/NewsListComp.ets create mode 100644 features/study/src/main/ets/components/PayComp.ets create mode 100644 features/study/src/main/ets/components/SendFollowComp.ets create mode 100644 features/study/src/main/ets/models/NewsModel.ets create mode 100644 features/study/src/main/ets/models/XinYiModel.ets create mode 100644 features/study/src/main/ets/utils/NewsUtil.ets create mode 100644 features/study/src/main/ets/views/NewsItemView.ets create mode 100644 features/study/src/main/ets/views/NewsSwiperView.ets create mode 100644 features/study/src/main/resources/base/media/flower_accountJinbi_icon.png create mode 100644 features/study/src/main/resources/base/media/flower_expertFlower_icon.png create mode 100644 features/study/src/main/resources/base/media/home_top_scroll_default.png create mode 100644 features/study/src/main/resources/base/media/news_meeting_icon.png create mode 100644 features/study/src/main/resources/base/media/news_new_icon.png create mode 100644 features/study/src/main/resources/base/media/patiemts_list_selected.png create mode 100644 features/study/src/main/resources/base/media/patientLogo.png create mode 100644 features/study/src/main/resources/base/media/patients_list_noSelect.png create mode 100644 features/study/src/main/resources/base/media/pay_account_icon.png create mode 100644 features/study/src/main/resources/base/media/pay_wx_icon.png create mode 100644 features/study/src/main/resources/base/media/send_follow_list_icon.png create mode 100644 features/study/src/main/resources/base/media/send_header_follow_icon.png create mode 100644 products/expert/src/main/ets/pages/Download/AllDownloadPage.ets create mode 100644 products/expert/src/main/ets/pages/Download/KeJianDownloadPage.ets create mode 100644 products/expert/src/main/ets/pages/Flower/FlowerDetailsPage.ets create mode 100644 products/expert/src/main/ets/pages/Meeting/MeetingPage.ets create mode 100644 products/expert/src/main/ets/pages/News/GandanNewsListPage.ets create mode 100644 products/expert/src/main/ets/pages/News/GandanNewsPages.ets create mode 100644 products/expert/src/main/ets/pages/Pay/PayPage.ets create mode 100644 products/expert/src/main/ets/pages/Pay/SendFollowPage.ets create mode 100644 products/expert/src/main/ets/pages/WebView/KeJianDetailsWebPage.ets create mode 100644 products/expert/src/main/ets/pages/WebView/NewsDetailsWebPage.ets diff --git a/commons/basic/Index.ets b/commons/basic/Index.ets index c147c74..42fd37f 100644 --- a/commons/basic/Index.ets +++ b/commons/basic/Index.ets @@ -113,4 +113,16 @@ export { compressedImage,saveImageToGallery,CompressedImageInfo } from './src/ma export { ScreeningView } from './src/main/ets/Views/ScreeningView' -export { TagListModel, TagList} from './src/main/ets/models/TagListModel' \ No newline at end of file +export { TagListModel, TagList} from './src/main/ets/models/TagListModel' + +export { AppUtil } from './src/main/ets/utils/AppUtil' + +export { OnWXResp,WXApi,WXEventHandler } from './src/main/ets/models/WXApiWrap' + +// export { DBManager,FileDownloadManager } from './src/main/ets/utils/FileManager' + +export { FileManager } from './src/main/ets/utils/FileManager' + +export { FileInfo,DownloadCallback,PreviewConfig } from './src/main/ets/models/FileModel' + +export { FileDownloadManager } from './src/main/ets/utils/FileDownloadManager' \ No newline at end of file diff --git a/commons/basic/src/main/ets/Views/DefaultHintProWindows.ets b/commons/basic/src/main/ets/Views/DefaultHintProWindows.ets index 6c0c59c..bd89201 100644 --- a/commons/basic/src/main/ets/Views/DefaultHintProWindows.ets +++ b/commons/basic/src/main/ets/Views/DefaultHintProWindows.ets @@ -1,3 +1,5 @@ +import { ChangeUtil } from "../../../../Index"; +import { promptAction } from "@kit.ArkUI"; @CustomDialog export struct DefaultHintProWindows { @@ -12,16 +14,23 @@ export struct DefaultHintProWindows { @Prop cancleColor:ResourceStr = '#FFFFFF'; @Prop confirmColor:ResourceStr = '#FFFFFF'; controller: CustomDialogController; + @State inputContent:string = '' - // 添加回调函数属性 private selectedButton: (index: number) => void = () => {}; + private selectedButtonAndContent: (index: number,content:string) => void = () => {}; + // 修改构造函数 constructor(controller: CustomDialogController, selectedButton: (index:number) => void) { super(); this.controller = controller; this.selectedButton = selectedButton; } + constructor(controller:CustomDialogController,selectedButtonAndContent: (index: number,content:string) => void) { + super(); + this.controller = controller + this.selectedButtonAndContent = selectedButtonAndContent + } build() { Row(){ @@ -32,10 +41,21 @@ export struct DefaultHintProWindows { .textAlign(TextAlign.Center) .margin({ top: 20 }) - Text(this.message) - .fontSize(this.messageFont) - .textAlign(TextAlign.Center) - .margin({ top: 10 }) + if (!ChangeUtil.stringIsUndefinedAndNull(this.message)) { + Text(this.message) + .fontSize(this.messageFont) + .textAlign(TextAlign.Center) + .margin({ top: 10 }) + .padding({left:10,right:10}) + } else { + TextInput({placeholder:'请输入您的登录密码'}) + .margin(10) + .backgroundColor('#f4f4f4') + .borderRadius(5) + .onChange((value:string)=>{ + this.inputContent = value + }) + } Row({ space: 20 }) { Button({ buttonStyle: ButtonStyleMode.TEXTUAL }) { @@ -45,7 +65,11 @@ export struct DefaultHintProWindows { } .width('45%').height(30).backgroundColor(this.cancleColor) .onClick(() => { - this.selectedButton(0) + if (ChangeUtil.stringIsUndefinedAndNull(this.message)) { + this.selectedButtonAndContent(0,'') + } else { + this.selectedButton(0) + } }) .visibility(this.cancleTitle?Visibility.Visible:Visibility.None) @@ -55,7 +79,15 @@ export struct DefaultHintProWindows { .fontColor(this.confirmTitleColor) }.width('45%').height(30).backgroundColor(this.confirmColor) .onClick(() => { - this.selectedButton(1) + if (ChangeUtil.stringIsUndefinedAndNull(this.message)) { + if (ChangeUtil.stringIsUndefinedAndNull(this.inputContent)) { + promptAction.showToast({ message: '请输入您的登录密码', duration: 1000 }) + return + } + this.selectedButtonAndContent(1,this.inputContent) + } else { + this.selectedButton(1) + } }) }.margin({ top: 20, bottom: 20 }) } diff --git a/commons/basic/src/main/ets/constants/BasicConstant.ets b/commons/basic/src/main/ets/constants/BasicConstant.ets index 00aecf9..6820839 100644 --- a/commons/basic/src/main/ets/constants/BasicConstant.ets +++ b/commons/basic/src/main/ets/constants/BasicConstant.ets @@ -14,6 +14,7 @@ export class BasicConstant { static readonly wxUrl = "https://dev-wx.igandan.com/"; static readonly polvId = "11";//保利威视学员id static readonly urlApp="https://dev-app.igandan.com/app/" + static readonly expertPay = "https://dev-app.igandan.com/app/expertPay/" //正式环境 // static readonly urlExpertAPI = "https://app.igandan.com/app/expertAPI/"; // static readonly urlExpertApp = "http://app.igandan.com/app/expertApp/" @@ -23,7 +24,9 @@ export class BasicConstant { // static readonly wxUrl = "https://wx.igandan.com/";// 微信服务器地址 // static readonly polvId = "21";//保利威视学员id // static readonly urlApp="http://app.igandan.com/app/" + // static readonly expertPay = "https://app.igandan.com/app/expertPay/" + static readonly getSystemTime = BasicConstant.urlApp + 'manager/' + 'getSystemTime' static readonly getSystemTimeStamp = BasicConstant.urlApp+'manager/getSystemTimeStamp' static readonly addBonusPoints = BasicConstant.urlExpertApp+'addBonusPoints' static readonly indexV2 = BasicConstant.urlExpertAPI+'indexV2';//首页轮播 @@ -72,12 +75,33 @@ export class BasicConstant { static readonly deleteComment = BasicConstant.urlExpertApp+'deleteComment';//删除评论 static readonly meetingHistoryList = BasicConstant.urlExpertAPI + "meetingHistoryList"; static readonly videoRoll = BasicConstant.urlExpertAPI + "videoRoll"; + static readonly newsRollNew = BasicConstant.urlExpert + 'newsRollNew' + static readonly newsTagList = BasicConstant.urlExpert + 'newsTagList' + static readonly newsListNew = BasicConstant.urlExpert + 'newsListNew' + static readonly defaultNewsListNew = BasicConstant.urlExpert + 'defaultNewsListNew' static readonly expertVideoTypeList = BasicConstant.urlExpertAPI + "expertVideoTypeList"; static readonly patientVideoNew = BasicConstant.urlExpertApp + 'patientVideoNew'; static readonly videoByKeyWordsNew = BasicConstant.urlExpertApp + "videoByKeyWordsNew"; static readonly patientVideoByKeyWordsNew = BasicConstant.urlExpertApp + 'patientVideoByKeyWordsNew' static readonly feedBack = BasicConstant.urlExpert+'feedBack' static readonly ganDanFileByKeyWords = BasicConstant.urlExpertAPI+'ganDanFileByKeyWords'//肝胆课件 + static readonly getKePuCollection = BasicConstant.urlExpert+'getKePuCollection' + static readonly discollection = BasicConstant.urlExpert + 'discollection' + static readonly collection = BasicConstant.urlExpert + 'collection' + static readonly disagree = BasicConstant.urlExpert + 'disagree' + static readonly agree = BasicConstant.urlExpert + 'agree' + static readonly ganDanFileDetials = BasicConstant.urlExpertAPI + 'ganDanFileDetials' + static readonly newsDetial = BasicConstant.urlExpert + 'newsDetial' + static readonly createGanDanFileOrder = BasicConstant.expertPay + 'createGanDanFileOrder' + static readonly getBalance = BasicConstant.expertPay + 'getBalance' + static readonly payGanDanFileOrder = BasicConstant.expertPay + 'payGanDanFileOrder' + static readonly getOrderStatus = BasicConstant.expertPay + 'getOrderStatus' + static readonly useWelfareNum = BasicConstant.urlExpertAPI + 'useWelfareNum' + static readonly allXinyiList = BasicConstant.expertPay + 'allXinyiList' + static readonly xinyiPrice = BasicConstant.expertPay + 'xinyiPrice' + static readonly createXinYiOrder = BasicConstant.expertPay + 'createXinYiOrder' + static readonly payXinYiOrder = BasicConstant.expertPay + 'payXinYiOrder' + static readonly getFlowerList = BasicConstant.expertPay + 'getFlowerList' static readonly tagList = BasicConstant.urlExpertApp + "tagList"; static readonly meetingListBySearch = BasicConstant.urlExpertAPI + "meetingListBySearch"; static readonly videoBySearchNew = BasicConstant.urlExpertApp+'videoBySearchNew';//搜索肝胆视频列表 @@ -135,6 +159,8 @@ export class BasicConstant { static readonly notification_back_refreshData = 250529;//返回上页通知刷新数据 //首页tabContent切换事件通知 static readonly notification_home_tab_change = 25060413; + //课件支付成功返回上一页下载科技 + static readonly notification_kejian_pay_success = 202509041128; static readonly YX_accid='YX_accid'//云信 diff --git a/commons/basic/src/main/ets/constants/Constants.ets b/commons/basic/src/main/ets/constants/Constants.ets new file mode 100644 index 0000000..370a2cf --- /dev/null +++ b/commons/basic/src/main/ets/constants/Constants.ets @@ -0,0 +1,2 @@ +export const APP_ID = "wxbf3658f5e674667c" +export const APP_SECRET = "c4505a04a9910c65efea8e11ffc93f92" diff --git a/commons/basic/src/main/ets/models/FileModel.ets b/commons/basic/src/main/ets/models/FileModel.ets new file mode 100644 index 0000000..dfa75bc --- /dev/null +++ b/commons/basic/src/main/ets/models/FileModel.ets @@ -0,0 +1,51 @@ +// 文件信息接口 +export interface FileInfo { + fileId: string; + fileName: string; + fileType: string; + fileSize: number; + fileUrl: string; + filePath?: string; + downloadStatus: 'pending' | 'downloading' | 'downloaded' | 'failed' | 'cancelled'; + downloadProgress: number; + createTime: number; + updateTime: number; +} + +// 下载进度回调 +export interface DownloadCallback { + onProgress?: (progress: number) => void; + onSuccess?: (filePath: string) => void; + onFailed?: (error: string) => void; + onCancelled?: () => void; +} + +// 文件预览配置 +export interface PreviewConfig { + enableCache?: boolean; + maxCacheSize?: number; + supportedTypes?: string[]; +} + +// 定义下载状态枚举 +export enum DownloadStatus { + PENDING = 'pending', // 等待中 + DOWNLOADING = 'downloading', // 下载中 + PAUSED = 'paused', // 已暂停 + COMPLETED = 'completed', // 已完成 + FAILED = 'failed', // 失败 +} + +// 定义文件项接口 +export interface DownloadFileItem { + id: string; // 文件唯一标识 + name: string; // 文件名 + url: string; // 下载地址 + localPath: string; // 本地存储路径 + size: number; // 文件大小(字节) + downloadedSize: number; // 已下载大小(字节) + status: DownloadStatus; // 下载状态 + createTime: number; // 创建时间 + finishTime?: number; // 完成时间 + error?: string; // 错误信息(失败时) +} \ No newline at end of file diff --git a/commons/basic/src/main/ets/models/WXApiWrap.ets b/commons/basic/src/main/ets/models/WXApiWrap.ets new file mode 100644 index 0000000..af411be --- /dev/null +++ b/commons/basic/src/main/ets/models/WXApiWrap.ets @@ -0,0 +1,44 @@ +import * as wxopensdk from '@tencent/wechat_open_sdk'; +import { APP_ID } from '../constants/Constants'; + +export type OnWXReq = (req: wxopensdk.BaseReq) => void +export type OnWXResp = (resp: wxopensdk.BaseResp) => void + +const kTag = "WXApiEventHandlerImpl" + +class WXApiEventHandlerImpl implements wxopensdk.WXApiEventHandler { + private onReqCallbacks: Map = new Map + private onRespCallbacks: Map = new Map + + registerOnWXReqCallback(on: OnWXReq) { + this.onReqCallbacks.set(on, on) + } + unregisterOnWXReqCallback(on: OnWXReq) { + this.onReqCallbacks.delete(on) + } + + registerOnWXRespCallback(on: OnWXResp) { + this.onRespCallbacks.set(on, on) + } + unregisterOnWXRespCallback(on: OnWXResp) { + this.onRespCallbacks.delete(on) + } + + onReq(req: wxopensdk.BaseReq): void { + wxopensdk.Log.i(kTag, "onReq:%s", JSON.stringify(req)) + this.onReqCallbacks.forEach((on) => { + on(req) + }) + } + + onResp(resp: wxopensdk.BaseResp): void { + wxopensdk.Log.i(kTag, "onResp:%s", JSON.stringify(resp)) + this.onRespCallbacks.forEach((on) => { + on(resp) + }) + } +} + +export const WXApi = wxopensdk.WXAPIFactory.createWXAPI(APP_ID) +export const WXEventHandler = new WXApiEventHandlerImpl + diff --git a/commons/basic/src/main/ets/utils/AESEncryptionDecryption.ets b/commons/basic/src/main/ets/utils/AESEncryptionDecryption.ets index 1dad307..b080901 100644 --- a/commons/basic/src/main/ets/utils/AESEncryptionDecryption.ets +++ b/commons/basic/src/main/ets/utils/AESEncryptionDecryption.ets @@ -111,7 +111,7 @@ export class AESEncryptionDecryption { globalResult = AESEncryptionDecryption.uint8ArrayToString(result.data); console.info('解密后的明文:' + globalResult); } catch (err) { - console.info(err.message); + console.info('解密失败:',err.message); } } diff --git a/commons/basic/src/main/ets/utils/AppUtil.ets b/commons/basic/src/main/ets/utils/AppUtil.ets index 222c4d7..3dc1615 100644 --- a/commons/basic/src/main/ets/utils/AppUtil.ets +++ b/commons/basic/src/main/ets/utils/AppUtil.ets @@ -3,6 +3,7 @@ import { BusinessError } from '@ohos.base' import { KeyboardAvoidMode, window } from '@kit.ArkUI' import { resourceManager } from '@kit.LocalizationKit' import { common } from '@kit.AbilityKit' +import display from '@ohos.display' export class AppUtil { @@ -236,6 +237,22 @@ export class AppUtil { } + /** + * display width + * @returns width in px + */ + static getDisplayWindowWidth(): Pixels { + return px(display.getDefaultDisplaySync().width) + } + + /** + * display height + * @returns height in px + */ + static getDisplayWindowHeight(): Pixels { + return px(display.getDefaultDisplaySync().height) + } + /** * 设置沉浸式状态栏 * @param isLayoutFullScreen 窗口的布局是否为沉浸式布局(该沉浸式布局状态栏、导航栏仍然显示)。true表示沉浸式布局;false表示非沉浸式布局。 @@ -342,6 +359,29 @@ export class AppUtil { AppUtil.getContext().terminateSelf(); AppUtil.getContext().getApplicationContext().killAllProcesses(); } +} +export function px(value: number) { + return new Pixels(value) +} + +export class Pixels { + value: number; + + constructor(value: number) { + this.value = value; + } + + get px() { + return this.value + } + + get vp() { + return px2vp(this.value) + } + + toString() { + return `${this.value}px` + } } \ No newline at end of file diff --git a/commons/basic/src/main/ets/utils/ChangeUtil.ets b/commons/basic/src/main/ets/utils/ChangeUtil.ets index 7726f50..f6b4a20 100644 --- a/commons/basic/src/main/ets/utils/ChangeUtil.ets +++ b/commons/basic/src/main/ets/utils/ChangeUtil.ets @@ -315,6 +315,18 @@ export class ChangeUtil { return height } + static formatPrice(priceStr: string): string { + let priceInFen = parseFloat(priceStr); + let priceInYuan = priceInFen / 100; + return `${priceInYuan.toFixed(2)}`; + } + + static formatPrice2(priceStr: string,discount: string): string { + let priceInFen = parseFloat(priceStr); + let priceInYuan = priceInFen / 100 * parseFloat(discount); + return `${priceInYuan.toFixed(2)}`; + } + static Logout(phone:string) { authStore.delUser(); diff --git a/commons/basic/src/main/ets/utils/FileDownloadManager.ets b/commons/basic/src/main/ets/utils/FileDownloadManager.ets new file mode 100644 index 0000000..2e2d2ba --- /dev/null +++ b/commons/basic/src/main/ets/utils/FileDownloadManager.ets @@ -0,0 +1,366 @@ +import fileIO from '@ohos.fileio'; +import request from '@ohos.request'; +import common from '@ohos.app.ability.common'; +import hilog from '@ohos.hilog'; + +/** + * 文件下载状态枚举 + */ +export enum DownloadStatus { + DOWNLOADING = 'downloading', + COMPLETED = 'completed', + FAILED = 'failed' +} + +/** + * 文件信息接口 + */ +export interface FileInfo { + id: string; + name: string; + url: string; + format: string; + size: number; + status: DownloadStatus; + localPath: string; + downloadTime: number; +} + +/** + * 文件下载管理类 + */ +export class FileDownloadManager { + private static instance: FileDownloadManager; + private downloadQueue: Map = new Map(); + private downloadTasks: Map = new Map(); + private context: common.UIAbilityContext; + private downloadDir: string = ''; + + private constructor(context: common.UIAbilityContext) { + this.context = context; + this.initDownloadDirectory(); + } + + /** + * 获取单例实例 + */ + public static getInstance(context: common.UIAbilityContext): FileDownloadManager { + if (!FileDownloadManager.instance) { + FileDownloadManager.instance = new FileDownloadManager(context); + } + return FileDownloadManager.instance; + } + + /** + * 初始化下载目录 + */ + private async initDownloadDirectory(): Promise { + try { + const filesDir = this.context.filesDir; + this.downloadDir = `${filesDir}/downloads`; + + // 检查并创建下载目录 + try { + await fileIO.access(this.downloadDir); + } catch { + await fileIO.mkdir(this.downloadDir); + } + } catch (error) { + hilog.error(0x0000, 'FileDownloadManager', '初始化下载目录失败: %{public}s', String(error)); + } + } + + /** + * 开始下载文件 + */ + public async downloadFile(url: string,fileId:string, fileName: string, fileType:string): Promise { + try { + // 从URL中提取文件格式 + const format = this.extractFileFormat(url); + + // 生成文件名 + const finalFileName = `${fileName}/${fileId}.${fileType}`; + + // 创建文件信息 + const fileInfo: FileInfo = { + id: fileId, + name: finalFileName, + url: url, + format: format, + size: 0, + status: DownloadStatus.DOWNLOADING, + localPath: `${this.downloadDir}/${finalFileName}`, + downloadTime: Date.now() + }; + + // 添加到下载队列 + this.downloadQueue.set(fileId, fileInfo); + + // 开始下载 + await this.startDownload(fileInfo); + + return fileId; + } catch (error) { + hilog.error(0x0000, 'FileDownloadManager', '下载文件失败: %{public}s', String(error)); + throw new Error(String(error)); + } + } + + /** + * 开始下载任务 + */ + private async startDownload(fileInfo: FileInfo): Promise { + try { + const config: request.DownloadConfig = { + url: fileInfo.url, + title: fileInfo.name, + description: '文件下载中...', + filePath: fileInfo.localPath, + header: { + 'User-Agent': 'HarmonyOS File Downloader' + } + }; + + const downloadTask = await request.downloadFile(this.context, config); + this.downloadTasks.set(fileInfo.id, downloadTask); + + // 监听下载进度 + downloadTask.on('progress', (receivedSize: number, totalSize: number) => { + fileInfo.size = totalSize; + this.updateFileInfo(fileInfo); + }); + + // 监听下载完成 + downloadTask.on('complete', () => { + fileInfo.status = DownloadStatus.COMPLETED; + this.updateFileInfo(fileInfo); + this.downloadTasks.delete(fileInfo.id); + }); + + // 监听下载失败 + downloadTask.on('fail', (err: number) => { + fileInfo.status = DownloadStatus.FAILED; + this.updateFileInfo(fileInfo); + this.downloadTasks.delete(fileInfo.id); + hilog.error(0x0000, 'FileDownloadManager', '下载失败: %{public}d', err); + }); + + } catch (error) { + fileInfo.status = DownloadStatus.FAILED; + this.updateFileInfo(fileInfo); + throw new Error(String(error)); + } + } + + /** + * 更新文件信息 + */ + private updateFileInfo(fileInfo: FileInfo): void { + this.downloadQueue.set(fileInfo.id, fileInfo); + } + + /** + * 从URL提取文件格式 + */ + private extractFileFormat(url: string): string { + const supportedFormats = ['docx', 'txt', 'ppt', 'pdf', 'doc', 'pptx', 'xls', 'xlsx']; + const urlParts = url.split('.'); + const format = urlParts[urlParts.length - 1].toLowerCase(); + + return supportedFormats.includes(format) ? format : 'bin'; + } + + /** + * 获取下载状态 + */ + public getDownloadStatus(fileId: string): DownloadStatus | null { + const fileInfo = this.downloadQueue.get(fileId); + return fileInfo ? fileInfo.status : null; + } + + /** + * 获取文件信息 + */ + public getFileInfo(fileId: string): FileInfo | null { + return this.downloadQueue.get(fileId) || null; + } + + /** + * 获取所有文件信息 + */ + public getAllFiles(): FileInfo[] { + return Array.from(this.downloadQueue.values()); + } + + /** + * 获取指定状态的文件 + */ + public getFilesByStatus(status: DownloadStatus): FileInfo[] { + return Array.from(this.downloadQueue.values()).filter(file => file.status === status); + } + + /** + * 查看单个文件 + */ + public async viewFile(fileId: string): Promise { + try { + const fileInfo = this.downloadQueue.get(fileId); + if (!fileInfo || fileInfo.status !== DownloadStatus.COMPLETED) { + throw new Error('文件不存在或下载未完成'); + } + + // 检查文件是否存在 + try { + await fileIO.access(fileInfo.localPath); + } catch { + throw new Error('文件不存在'); + } + + // 获取文件信息 + const stat = await fileIO.stat(fileInfo.localPath); + hilog.info(0x0000, 'FileDownloadManager', '文件信息: %{public}s', JSON.stringify(stat)); + + return true; + } catch (error) { + hilog.error(0x0000, 'FileDownloadManager', '查看文件失败: %{public}s', String(error)); + return false; + } + } + + /** + * 查看所有文件 + */ + public async viewAllFiles(): Promise { + try { + const allFiles = this.getAllFiles(); + const completedFiles: FileInfo[] = []; + + for (const file of allFiles) { + if (file.status === DownloadStatus.COMPLETED) { + try { + await fileIO.access(file.localPath); + completedFiles.push(file); + } catch { + // 文件不存在,跳过 + } + } + } + + return completedFiles; + } catch (error) { + hilog.error(0x0000, 'FileDownloadManager', '查看所有文件失败: %{public}s', String(error)); + return []; + } + } + + /** + * 删除单个文件 + */ + public async deleteFile(fileId: string): Promise { + try { + const fileInfo = this.downloadQueue.get(fileId); + if (!fileInfo) { + throw new Error('文件不存在'); + } + + // 取消下载任务 + const downloadTask = this.downloadTasks.get(fileId); + if (downloadTask) { + downloadTask.off('progress'); + downloadTask.off('complete'); + downloadTask.off('fail'); + this.downloadTasks.delete(fileId); + } + + // 删除本地文件 + if (fileInfo.status === DownloadStatus.COMPLETED) { + try { + await fileIO.unlink(fileInfo.localPath); + } catch { + // 文件可能不存在,忽略错误 + } + } + + // 从队列中移除 + this.downloadQueue.delete(fileId); + + return true; + } catch (error) { + hilog.error(0x0000, 'FileDownloadManager', '删除文件失败: %{public}s', String(error)); + return false; + } + } + + /** + * 删除所有文件 + */ + public async deleteAllFiles(): Promise { + try { + const allFiles = Array.from(this.downloadQueue.keys()); + + for (const fileId of allFiles) { + await this.deleteFile(fileId); + } + + return true; + } catch (error) { + hilog.error(0x0000, 'FileDownloadManager', '删除所有文件失败: %{public}s', String(error)); + return false; + } + } + + /** + * 暂停下载 + */ + public pauseDownload(fileId: string): boolean { + const downloadTask = this.downloadTasks.get(fileId); + if (downloadTask) { + downloadTask.off('progress'); + downloadTask.off('complete'); + downloadTask.off('fail'); + this.downloadTasks.delete(fileId); + return true; + } + return false; + } + + /** + * 恢复下载 + */ + public async resumeDownload(fileId: string): Promise { + try { + const fileInfo = this.downloadQueue.get(fileId); + if (!fileInfo || fileInfo.status !== DownloadStatus.DOWNLOADING) { + return false; + } + + await this.startDownload(fileInfo); + return true; + } catch (error) { + hilog.error(0x0000, 'FileDownloadManager', '恢复下载失败: %{public}s', String(error)); + return false; + } + } + + /** + * 清理下载目录 + */ + // public async cleanDownloadDirectory(): Promise { + // try { + // // 使用fileIO.listDir替代readdir + // const files = await fileIO.listDir(this.downloadDir); + // for (const file of files) { + // const filePath = `${this.downloadDir}/${file}`; + // try { + // await fileIO.unlink(filePath); + // } catch { + // // 忽略删除失败的文件 + // } + // } + // return true; + // } catch (error) { + // hilog.error(0x0000, 'FileDownloadManager', '清理下载目录失败: %{public}s', String(error)); + // return false; + // } + // } +} \ No newline at end of file diff --git a/commons/basic/src/main/ets/utils/FileManager.ets b/commons/basic/src/main/ets/utils/FileManager.ets new file mode 100644 index 0000000..63fea47 --- /dev/null +++ b/commons/basic/src/main/ets/utils/FileManager.ets @@ -0,0 +1,799 @@ +import { http } from '@kit.NetworkKit'; +import { promptAction, router } from '@kit.ArkUI'; +import { common } from '@kit.AbilityKit'; +import { fileIo, fileUri } from '@kit.CoreFileKit'; +import { FileInfo,DownloadCallback } from '../models/FileModel' +import preferences from '@ohos.data.preferences'; +import { Want } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { filePreview } from '@kit.PreviewKit'; +import request from '@ohos.request'; + +// 下载任务接口 +export interface DownloadTask { + httpRequest: http.HttpRequest; + filePath: string; +} + +// 文件统计信息接口 +export interface FileStat { + size: number; + ctime: number; + mtime: number; +} + +/** + * 文件管理类 - 提供下载、查询、预览等功能 + */ +export class FileManager { + private context: common.Context; + private downloadTasks: Map = new Map(); + private downloadCallbacks: Map = new Map(); + private fileCache: Map = new Map(); + private downloadDir: string; + private isDownloading: boolean = false; + private preferencesHelper: preferences.Preferences | null = null; + private readonly STORE_NAME = 'file_manager_store'; + private readonly FILE_INFO_KEY = 'file_info_cache'; + + constructor(context: common.Context) { + this.context = context; + this.downloadDir = `${this.context.filesDir}/downloads`; + this.initDownloadDirectory(); + this.initPreferences(); + this.loadFileInfoFromStorage(); + } + + /** + * 初始化偏好设置存储 + */ + private async initPreferences(): Promise { + try { + this.preferencesHelper = await preferences.getPreferences(this.context, this.STORE_NAME); + } catch (error) { + console.error('初始化偏好设置失败:', error); + } + } + + /** + * 从存储加载文件信息 + */ + private async loadFileInfoFromStorage(): Promise { + try { + if (this.preferencesHelper) { + const fileInfoJson = await this.preferencesHelper.get(this.FILE_INFO_KEY, '[]'); + const fileInfoArray: FileInfo[] = JSON.parse(fileInfoJson as string); + + // 恢复缓存 + for (const fileInfo of fileInfoArray) { + this.fileCache.set(fileInfo.fileId, fileInfo); + } + + console.info(`从存储加载了 ${fileInfoArray.length} 个文件信息`); + } + } catch (error) { + console.error('加载文件信息失败:', error); + } + } + + /** + * 保存文件信息到存储 + */ + private async saveFileInfoToStorage(): Promise { + try { + if (this.preferencesHelper) { + const fileInfoArray = Array.from(this.fileCache.values()); + const fileInfoJson = JSON.stringify(fileInfoArray); + await this.preferencesHelper.put(this.FILE_INFO_KEY, fileInfoJson); + await this.preferencesHelper.flush(); + } + } catch (error) { + console.error('保存文件信息失败:', error); + } + } + + /** + * 初始化下载目录 + */ + private async initDownloadDirectory(): Promise { + try { + if (!fileIo.accessSync(this.downloadDir)) { + fileIo.mkdirSync(this.downloadDir); + } + } catch (error) { + console.error('创建下载目录失败:', error); + } + } + + /** + * 下载文件 + * @param fileInfo 文件信息 + * @param callback 下载回调 + * @returns Promise + */ + async downloadFile(fileInfo: FileInfo, callback?: DownloadCallback): Promise { + try { + // 检查是否正在下载 + if (this.downloadTasks.has(fileInfo.fileId)) { + promptAction.showToast({ message: '文件正在下载中,请勿重复操作', duration: 2000 }); + return false; + } + + // 检查文件是否已下载 + if (await this.isFileDownloaded(fileInfo.fileId)) { + promptAction.showToast({ message: '文件已下载', duration: 2000 }); + return true; + } + + // 设置下载状态 + this.isDownloading = true; + fileInfo.downloadStatus = 'downloading'; + fileInfo.downloadProgress = 0; + + // 保存回调 + if (callback) { + this.downloadCallbacks.set(fileInfo.fileId, callback); + } + + // 创建下载任务 + const downloadTask = await this.createDownloadTask(fileInfo); + this.downloadTasks.set(fileInfo.fileId, downloadTask); + + // 开始下载 + const success = await this.startDownload(downloadTask, fileInfo); + + if (success) { + fileInfo.downloadStatus = 'downloaded'; + fileInfo.downloadProgress = 100; + this.onDownloadSuccess(fileInfo); + } else { + fileInfo.downloadStatus = 'failed'; + this.onDownloadFailed(fileInfo, '下载失败'); + } + + return success; + } catch (error) { + console.error('下载文件失败:', error); + fileInfo.downloadStatus = 'failed'; + this.onDownloadFailed(fileInfo, '下载失败'); + return false; + } finally { + this.isDownloading = false; + this.downloadTasks.delete(fileInfo.fileId); + } + } + + /** + * 创建下载任务 + */ + private async createDownloadTask(fileInfo: FileInfo): Promise { + try { + // 创建文件名目录 + const fileNameDir = `${fileInfo.fileName}`; + const fileNameDirPath = `${this.downloadDir}/${fileNameDir}`; + + // 确保目录存在 + if (!fileIo.accessSync(fileNameDirPath)) { + fileIo.mkdirSync(fileNameDirPath); + } + + // 设置文件保存路径 - 格式:文件名/文件ID.文件格式 + const fileName = `${fileInfo.fileId}.${fileInfo.fileType}`; + const filePath = `${fileNameDirPath}/${fileName}`; + fileInfo.filePath = filePath; + + // 创建HTTP请求 + const httpRequest = http.createHttp(); + + const task: DownloadTask = { + httpRequest: httpRequest, + filePath: filePath + }; + + return task; + } catch (error) { + console.error('创建下载任务失败:', error); + throw new Error('创建下载任务失败'); + } + } + + /** + * 开始下载 + */ + private async startDownload(downloadTask: DownloadTask, fileInfo: FileInfo): Promise { + // + // let contexta = getContext(this) as common.UIAbilityContext; + // request.downloadFile(contexta.getApplicationContext(), { + // url: fileInfo.fileUrl, + // filePath: downloadTask.filePath, + // enableMetered:true + // }).then((downloadTask: request.DownloadTask) => { + // let progresCallback = (receivedSize: number, totalSize: number) => { + // console.info("downloadddd1 receivedSize:" + receivedSize + " totalSize:" + totalSize); + // }; + // let pauseCallback = () => { + // console.info('Downloadddd task pause.'); + // }; + // //开启进度回调 + // downloadTask.on('progress', progresCallback); + // //开启暂停回调 + // downloadTask.on('pause', pauseCallback); + // //开启下载完成回调 + // downloadTask.on('complete', async () => { + // const taskInfo = await downloadTask.getTaskInfo(); + // console.info('downloaddddTask1 complete:'+`status: ${taskInfo.status}`); + // // downloadTask.getTaskInfo(); + // + // }) + // return true + // }).catch((err: BusinessError) => { + // console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`); + // return false; + // }) + try { + const httpRequest = downloadTask.httpRequest; + const filePath = downloadTask.filePath; + + // 配置下载选项 - 参考iOS代码的请求头设置 + const options: http.HttpRequestOptions = { + method: http.RequestMethod.GET, + header: { + 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; HarmonyOS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', + 'Accept-Language': 'zh-CN,zh;q=0.9', + }, + expectDataType: http.HttpDataType.ARRAY_BUFFER, + usingCache: false, + connectTimeout: 60000, + readTimeout: 300000 + }; + + console.info(`开始下载文件: ${fileInfo.fileUrl}`); + console.info(`目标路径: ${filePath}`); + + // 发起下载请求 + const response = await httpRequest.request(fileInfo.fileUrl, options); + + console.info(`响应状态码: ${response.responseCode}`); + console.info(`响应头: ${JSON.stringify(response.header)}`); + + if (response.responseCode === 200) { + try { + // 验证响应数据 + if (!response.result) { + console.error('下载响应数据为空'); + return false; + } + + // 检查数据类型和大小 + if (!(response.result instanceof ArrayBuffer)) { + console.error('响应数据不是ArrayBuffer类型:', typeof response.result); + return false; + } + + const dataSize = response.result.byteLength; + console.info(`下载数据大小: ${dataSize} 字节`); + + if (dataSize <= 10) { + console.error('文件有误:',response.result) + return false + } + + // 确保目标目录存在 + const dirPath = filePath.substring(0, filePath.lastIndexOf('/')); + if (!fileIo.accessSync(dirPath)) { + fileIo.mkdirSync(dirPath); + } + + // 将下载的数据写入文件 + const file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY); + + try { + // 写入文件数据 + const bytesWritten = fileIo.writeSync(file.fd, response.result); + console.info(`写入文件成功,写入字节数: ${bytesWritten}`); + + // 验证写入的字节数 + if (bytesWritten !== dataSize) { + console.error(`写入字节数不匹配: 期望 ${dataSize}, 实际 ${bytesWritten}`); + fileIo.closeSync(file); + fileIo.unlinkSync(filePath); // 删除损坏的文件 + return false; + } + + // 同步文件到磁盘 + fileIo.fsyncSync(file.fd); + + // 关闭文件 + fileIo.closeSync(file); + + // 验证文件是否创建成功 + if (!fileIo.accessSync(filePath)) { + console.error('文件创建失败'); + return false; + } + + // 获取文件统计信息 + const stat = fileIo.statSync(filePath); + console.info(`文件创建成功: ${filePath}, 大小: ${stat.size} 字节`); + + // 验证文件大小 + if (stat.size !== dataSize) { + console.error(`文件大小不匹配: 期望 ${dataSize}, 实际 ${stat.size}`); + fileIo.unlinkSync(filePath); + return false; + } + + // 更新文件信息 + fileInfo.fileSize = stat.size; + await this.saveFileInfo(fileInfo); + + return true; + } catch (writeError) { + console.error('写入文件失败:', writeError); + fileIo.closeSync(file); + // 清理可能创建的文件 + try { + if (fileIo.accessSync(filePath)) { + fileIo.unlinkSync(filePath); + } + } catch (cleanupError) { + console.error('清理文件失败:', cleanupError); + } + return false; + } + } catch (writeError) { + console.error('文件写入过程失败:', writeError); + return false; + } + } else { + console.error(`下载失败,状态码: ${response.responseCode}`); + return false; + } + } catch (error) { + console.error('下载执行失败:', error); + return false; + } finally { + // 销毁HTTP请求 + downloadTask.httpRequest.destroy(); + } + } + + /** + * 取消下载 + */ + async cancelDownload(fileId: string): Promise { + try { + const task = this.downloadTasks.get(fileId); + if (task) { + // 销毁HTTP请求 + task.httpRequest.destroy(); + this.downloadTasks.delete(fileId); + + // 更新状态 + const fileInfo = this.fileCache.get(fileId); + if (fileInfo) { + fileInfo.downloadStatus = 'cancelled'; + fileInfo.downloadProgress = 0; + this.onDownloadCancelled(fileInfo); + } + + return true; + } + return false; + } catch (error) { + console.error('取消下载失败:', error); + return false; + } + } + + /** + * 查询已下载文件 + */ + async getDownloadedFiles(): Promise { + try { + const files: FileInfo[] = []; + + // 从缓存获取 + for (const fileInfo of this.fileCache.values()) { + if (fileInfo.downloadStatus === 'downloaded') { + files.push(fileInfo); + } + } + + // 从本地目录扫描 + const localFiles = await this.scanLocalFiles(); + files.push(...localFiles); + + // 按时间排序 + return files.sort((a, b) => b.updateTime - a.updateTime); + } catch (error) { + console.error('查询下载文件失败:', error); + return []; + } + } + + /** + * 扫描本地文件 + */ + private async scanLocalFiles(): Promise { + try { + const files: FileInfo[] = []; + + if (!fileIo.accessSync(this.downloadDir)) { + return files; + } + + const entryList = fileIo.listFileSync(this.downloadDir); + + for (let i = 0; i < entryList.length; i++) { + const entryName = entryList[i]; + const entryPath = `${this.downloadDir}/${entryName}`; + + // 优先按目录处理(当前下载结构是 按文件名建目录,目录下放置 文件ID.扩展名) + let childNames: string[] | null = null; + try { + childNames = fileIo.listFileSync(entryPath); + } catch (_e) { + childNames = null; + } + + if (childNames && childNames.length > 0) { + // 目录:遍历子文件 + for (let j = 0; j < childNames.length; j++) { + const childName = childNames[j]; + const childPath = `${entryPath}/${childName}`; + try { + const childStat = fileIo.statSync(childPath); + const fileInfo = this.parseFileName(childName, childPath, childStat); + if (fileInfo) { + files.push(fileInfo); + } + } catch (childErr) { + console.error('读取子文件失败:', childErr); + } + } + } else { + // 非目录项(兼容旧结构,直接作为文件解析) + try { + const stat = fileIo.statSync(entryPath); + const fileInfo = this.parseFileName(entryName, entryPath, stat); + if (fileInfo) { + files.push(fileInfo); + } + } catch (fileErr) { + console.error('读取文件失败:', fileErr); + } + } + } + + return files; + } catch (error) { + console.error('扫描本地文件失败:', error); + return []; + } + } + + /** + * 解析文件名 + */ + private parseFileName(fileName: string, filePath: string, stat: fileIo.Stat): FileInfo | null { + try { + // 新的文件名格式: 文件名/文件ID.扩展名 + const pathParts = filePath.split('/'); + if (pathParts.length < 2) return null; + + const fileNameDir = pathParts[pathParts.length - 2]; // 文件名目录 + const fileNameWithExt = pathParts[pathParts.length - 1]; // 文件ID.扩展名 + + const fileIdParts = fileNameWithExt.split('.'); + if (fileIdParts.length < 2) return null; + + const fileId = fileIdParts[0]; + const extension = fileIdParts[1]; + + return { + fileId, + fileName: fileNameDir, // 使用目录名作为文件名 + fileType: extension, + fileSize: stat.size, + fileUrl: '', + filePath: filePath, + downloadStatus: 'downloaded', + downloadProgress: 100, + createTime: stat.ctime, + updateTime: stat.mtime + }; + } catch (error) { + console.error('解析文件名失败:', error); + return null; + } + } + + /** + * 检查文件是否已下载 + */ + private async isFileDownloaded(fileId: string): Promise { + try { + // 检查缓存 + const cachedFile = this.fileCache.get(fileId); + if (cachedFile && cachedFile.downloadStatus === 'downloaded') { + return true; + } + + // 检查本地文件 + const localFiles = await this.scanLocalFiles(); + for (let i = 0; i < localFiles.length; i++) { + if (localFiles[i].fileId === fileId) { + return true; + } + } + return false; + } catch (error) { + console.error('检查文件下载状态失败:', error); + return false; + } + } + + /** + * 预览文件 - 使用系统原生方法 + */ + async previewFile(identifier: string) { + try { + // 1) 优先按 uuid 在缓存中查找 + let target: FileInfo | null = null; + const cachedById = this.fileCache.get(identifier); + if (cachedById) { + target = cachedById; + } + + // 2) 若未命中,再按文件名在缓存中查找(取最近更新) + if (!target) { + let latest: FileInfo | null = null; + for (const info of this.fileCache.values()) { + if (info.fileName === identifier) { + if (!latest || info.updateTime > latest.updateTime) { + latest = info; + } + } + } + target = latest; + } + + // 3) 若缓存仍未命中,扫描本地目录 + if (!target) { + const localFiles = await this.scanLocalFiles(); + let latest: FileInfo | null = null; + for (const info of localFiles) { + if (info.fileId === identifier || info.fileName === identifier) { + if (!latest || info.updateTime > latest.updateTime) { + latest = info; + } + } + } + target = latest; + } + + if (!target || !target.filePath) { + promptAction.showToast({ message: '未找到对应文件', duration: 2000 }); + return; + } + + const filePath = target.filePath; + const fileType = target.fileType || ''; + + // 文件是否存在 + if (!fileIo.accessSync(filePath)) { + promptAction.showToast({ message: '文件不存在', duration: 2000 }); + return; + } + + let uri = fileUri.getUriFromPath(filePath); + filePreview.canPreview(this.context, uri).then((result) => { // 传入支持的文件类型且项目存在时会返回true + console.info(`Succeeded in obtaining the result of whether it can be previewed. result = ${result}`); + }).catch((err: BusinessError) => { + console.error(`Failed to obtain the result of whether it can be previewed, err.code = ${err.code}, err.message = ${err.message}`); + }); + + let fileInfo: filePreview.PreviewInfo = { + title: target.fileName, + uri: uri, + mimeType: this.getMimeType(fileType) + }; + let files: Array = new Array(); + files.push(fileInfo); + filePreview.openPreview(this.context, files, 0).then(() => { + console.info('Succeeded in opening preview'); + }).catch((err: BusinessError) => { + console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`); + }); + } catch (error) { + console.error('打开文件异常:', error); + } + } + + /** + * 获取MIME类型 + */ + private getMimeType(fileType: string): string { + const mimeTypes: Record = { + 'pdf': 'application/pdf', + 'doc': 'application/msword', + 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'ppt': 'application/vnd.ms-powerpoint', + 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'xls': 'application/vnd.ms-excel', + 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'txt': 'text/plain', + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + 'gif': 'image/gif', + 'bmp': 'image/bmp', + 'mp4': 'video/mp4', + 'avi': 'video/x-msvideo', + 'mov': 'video/quicktime', + 'wmv': 'video/x-ms-wmv' + }; + return mimeTypes[fileType.toLowerCase()] || '*/*'; + } + + /** + * 删除文件 + */ + async deleteFile(identifier: string): Promise { + try { + // 1) 优先按 fileId 在缓存中查找 + let target: FileInfo | null = null; + const cachedById = this.fileCache.get(identifier); + if (cachedById) { + target = cachedById; + } + + // 2) 若未命中,再按文件名在缓存中查找(取最近更新) + if (!target) { + let latest: FileInfo | null = null; + for (const info of this.fileCache.values()) { + if (info.fileName === identifier) { + if (!latest || info.updateTime > latest.updateTime) { + latest = info; + } + } + } + target = latest; + } + + // 3) 若缓存仍未命中,扫描本地目录 + if (!target) { + const localFiles = await this.scanLocalFiles(); + let latest: FileInfo | null = null; + for (const info of localFiles) { + if (info.fileId === identifier || info.fileName === identifier) { + if (!latest || info.updateTime > latest.updateTime) { + latest = info; + } + } + } + target = latest; + } + + if (!target || !target.filePath) { + console.error('未找到要删除的文件:', identifier); + return false; + } + + // 删除本地文件 + if (fileIo.accessSync(target.filePath)) { + fileIo.unlinkSync(target.filePath); + console.info(`成功删除文件: ${target.filePath}`); + + // 删除文件后,检查并删除空的文件夹 + await this.cleanupEmptyDirectory(target.filePath); + } + + // 从缓存中移除 + this.fileCache.delete(target.fileId); + + // 更新持久化存储 + await this.saveFileInfoToStorage(); + + return true; + } catch (error) { + console.error('删除文件失败:', error); + return false; + } + } + + /** + * 清理空文件夹 + */ + private async cleanupEmptyDirectory(filePath: string): Promise { + try { + // 获取文件所在目录 + const dirPath = filePath.substring(0, filePath.lastIndexOf('/')); + + // 检查目录是否存在 + if (!fileIo.accessSync(dirPath)) { + return; + } + + // 检查目录是否为空 + const files = fileIo.listFileSync(dirPath); + if (files.length === 0) { + // 目录为空,删除目录 + fileIo.rmdirSync(dirPath); + console.info(`成功删除空文件夹: ${dirPath}`); + + // 递归检查父目录是否也为空(但不要删除下载根目录) + const parentDir = dirPath.substring(0, dirPath.lastIndexOf('/')); + if (parentDir !== this.downloadDir && fileIo.accessSync(parentDir)) { + const parentFiles = fileIo.listFileSync(parentDir); + if (parentFiles.length === 0) { + fileIo.rmdirSync(parentDir); + console.info(`成功删除空父文件夹: ${parentDir}`); + } + } + } + } catch (error) { + console.error('清理空文件夹失败:', error); + } + } + + /** + * 获取下载状态 + */ + isDownloadingFile(): boolean { + return this.isDownloading; + } + + /** + * 保存文件信息 + */ + private async saveFileInfo(fileInfo: FileInfo): Promise { + try { + this.fileCache.set(fileInfo.fileId, fileInfo); + // 保存到持久化存储 + await this.saveFileInfoToStorage(); + } catch (error) { + console.error('保存文件信息失败:', error); + } + } + + /** + * 下载成功回调 + */ + private onDownloadSuccess(fileInfo: FileInfo): void { + const callback = this.downloadCallbacks.get(fileInfo.fileId); + if (callback && callback.onSuccess) { + callback.onSuccess(fileInfo.filePath || ''); + } + this.downloadCallbacks.delete(fileInfo.fileId); + + promptAction.showToast({ message: '下载完成', duration: 2000 }); + } + + /** + * 下载失败回调 + */ + private onDownloadFailed(fileInfo: FileInfo, error: string): void { + const callback = this.downloadCallbacks.get(fileInfo.fileId); + if (callback && callback.onFailed) { + callback.onFailed(error); + } + this.downloadCallbacks.delete(fileInfo.fileId); + + promptAction.showToast({ message: error, duration: 2000 }); + } + + /** + * 下载取消回调 + */ + private onDownloadCancelled(fileInfo: FileInfo): void { + const callback = this.downloadCallbacks.get(fileInfo.fileId); + if (callback && callback.onCancelled) { + callback.onCancelled(); + } + this.downloadCallbacks.delete(fileInfo.fileId); + + promptAction.showToast({ message: '下载已取消', duration: 2000 }); + } +} \ No newline at end of file diff --git a/commons/basic/src/main/ets/utils/FileManagerCopy.ets b/commons/basic/src/main/ets/utils/FileManagerCopy.ets new file mode 100644 index 0000000..d4f0b67 --- /dev/null +++ b/commons/basic/src/main/ets/utils/FileManagerCopy.ets @@ -0,0 +1,346 @@ +// 导入必要的鸿蒙模块 +import http from '@ohos.net.http'; +import fs from '@ohos.file.fs'; +import relationalStore from '@ohos.data.relationalStore'; +import common from '@ohos.app.ability.common'; +import security from '@ohos.security.cryptoFramework'; +import util from '@ohos.util'; +import { BusinessError } from '@ohos.base'; +import promptAction from '@ohos.promptAction'; +import { cryptoFramework } from '@kit.CryptoArchitectureKit'; +import { authStore } from './auth'; +import { AESEncryptionDecryption } from './AESEncryptionDecryption'; +import { BasicConstant } from '../constants/BasicConstant'; +import { rcp } from '@kit.RemoteCommunicationKit'; +import fileIo from '@ohos.file.fs'; + +// 1. 定义数据模型和数据库结构 +// 文件信息实体 +class WPSFile { + fileId: string = ''; // 对应fileID + fileTitle: string = ''; // 对应fileTitle + fileType: string = ''; // 对应fileType + filePath: string = ''; // 本地存储路径 + downloadType: string = ''; // 下载状态: 'downloading', 'downloadFalse', 'downloaded' + md5?: string = ''; // 文件MD5值 +} + +// 数据库管理器 +export class DBManager { + private rdbStore: relationalStore.RdbStore | null = null; + private readonly TABLE_NAME: string = 'WPSFILELIST'; + private readonly STORE_CONFIG: relationalStore.StoreConfig = { + name: 'WPSFileDB.db', + securityLevel: relationalStore.SecurityLevel.S1, + }; + private context: common.Context; + + constructor(context: common.Context) { + this.context = context; + } + + // 初始化数据库 + async initializeDB(): Promise { + try { + this.rdbStore = await relationalStore.getRdbStore(this.context, this.STORE_CONFIG); + // 创建表 + const sql = ` + CREATE TABLE IF NOT EXISTS ${this.TABLE_NAME} ( + fileId TEXT PRIMARY KEY, + fileTitle TEXT NOT NULL, + fileType TEXT NOT NULL, + filePath TEXT, + downloadType TEXT NOT NULL, + md5 TEXT + )`; + await this.rdbStore.executeSql(sql); + console.log('数据库初始化成功'); + } catch (err) { + console.error(`数据库初始化失败: ${err.code}, ${err.message}`); + } + } + + // 插入文件记录 + async insertFile(file: WPSFile): Promise { + if (!this.rdbStore) { + await this.initializeDB(); + } + + try { + const valueBucket: relationalStore.ValuesBucket = { + 'fileId': file.fileId, + 'fileTitle': file.fileTitle, + 'fileType': file.fileType, + 'filePath': file.filePath, + 'downloadType': file.downloadType, + 'md5': file.md5 || '' + }; + + await this.rdbStore?.insert(this.TABLE_NAME, valueBucket); + console.log('文件记录插入成功'); + return true; + } catch (err) { + console.error(`插入文件记录失败: ${err.code}, ${err.message}`); + return false; + } + } + + // 更新下载状态 + async updateDownloadStatus(fileId: string, status: string): Promise { + if (!this.rdbStore) { + await this.initializeDB(); + } + + try { + const valueBucket: relationalStore.ValuesBucket = { + 'downloadType': status + }; + + let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates(this.TABLE_NAME); + predicates.equalTo('fileId', fileId); + + await this.rdbStore?.update(valueBucket, predicates); + console.log('下载状态更新成功'); + return true; + } catch (err) { + console.error(`更新下载状态失败: ${err.code}, ${err.message}`); + return false; + } + } + + // 删除文件记录 + async deleteFile(fileId: string): Promise { + if (!this.rdbStore) { + await this.initializeDB(); + } + + try { + let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates(this.TABLE_NAME); + predicates.equalTo('fileId', fileId); + + await this.rdbStore?.delete(predicates); + console.log('文件记录删除成功'); + return true; + } catch (err) { + console.error(`删除文件记录失败: ${err.code}, ${err.message}`); + return false; + } + } + + // 根据ID查询文件 + async getFileById(fileId: string): Promise { + if (!this.rdbStore) { + await this.initializeDB(); + } + + try { + let predicates: relationalStore.RdbPredicates = new relationalStore.RdbPredicates(this.TABLE_NAME); + predicates.equalTo('fileId', fileId); + + let resultSet = await this.rdbStore?.query(predicates, ['fileId', 'fileTitle', 'fileType', 'filePath', 'downloadType', 'md5']); + if (resultSet && resultSet.rowCount > 0) { + await resultSet.goToFirstRow(); + let file = new WPSFile(); + file.fileId = resultSet.getString(resultSet.getColumnIndex('fileId')) || ''; + file.fileTitle = resultSet.getString(resultSet.getColumnIndex('fileTitle')) || ''; + file.fileType = resultSet.getString(resultSet.getColumnIndex('fileType')) || ''; + file.filePath = resultSet.getString(resultSet.getColumnIndex('filePath')) || ''; + file.downloadType = resultSet.getString(resultSet.getColumnIndex('downloadType')) || ''; + file.md5 = resultSet.getString(resultSet.getColumnIndex('md5')) || ''; + resultSet.close(); + return file; + } + return null; + } catch (err) { + console.error(`查询文件失败: ${err.code}, ${err.message}`); + return null; + } + } +} + +// 1. 计算文件 MD5 (使用路径创建流) +async function calculateFileMD5(filePath: string): Promise { + let stream: fs.Stream = fs.createStreamSync(filePath, 'r'); + let md5AlgName: string = "MD5"; + let hash: cryptoFramework.Md = cryptoFramework.createMd(md5AlgName); + + let dataBuff: ArrayBuffer = new ArrayBuffer(4096); + let readCount: number = stream.readSync(dataBuff); + while (readCount > 0) { + let messageData: Uint8Array = new Uint8Array(dataBuff.slice(0, readCount)); + let updateMessageBlob: cryptoFramework.DataBlob = { data: messageData }; + hash.updateSync(updateMessageBlob); + readCount = stream.readSync(dataBuff); + } + stream.closeSync(); + + let md5Result: cryptoFramework.DataBlob = hash.digestSync(); + let md5Hex: string = Array.from(md5Result.data).map(byte => byte.toString(16).padStart(2, '0')).join(''); + return md5Hex; +} + +// 2. 文件下载管理器 +export class FileManagerCopy { + private httpRequest: http.HttpRequest = http.createHttp(); + private context: common.Context; + private dbManager: DBManager; + + constructor(context: common.Context) { + this.context = context; + this.dbManager = new DBManager(context); + } + + private generateRandomString(): string { + // 生成1到10之间的随机整数作为字符串长度[6,8](@ref) + const minLength: number = 1; + const maxLength: number = 10; + const targetLength: number = Math.floor(Math.random() * (maxLength - minLength + 1)) + minLength; + // 初始化一个空数组用于存储字符 + let charArray: string[] = []; + // 循环生成指定数量的随机大写字母[6](@ref) + for (let i = 0; i < targetLength; i++) { + // 生成65('A')到90('Z')之间的随机数[6](@ref) + const randomCharCode: number = Math.floor(Math.random() * 26) + 65; + // 将Unicode编码转换为字符并添加到数组 + charArray.push(String.fromCharCode(randomCharCode)); + } + return charArray.join(''); + } + + async downloadFile(wpsUuid: string, wpsTitle: string, wpsType: string, fileMd5: string, order_id:string , orderStatus: number, timestamp: string) { + // 检查是否正在下载 + let existingFile = await this.dbManager.getFileById(wpsUuid); + if (existingFile && existingFile.downloadType === 'downloading') { + promptAction.showToast({ message: '正在下载,请勿重复点击', duration: 2000 }); + // return false; + } + + let daijiami:string = '' + if (orderStatus == 1) {//免费 + daijiami = `${wpsUuid}|${order_id}|${authStore.getUser().uuid}|${timestamp}` + } + // else if (orderStatus == 8) {//复制iOS代码逻辑,有这样的内容 + // daijiami = `${wpsUuid}|${orderStatus}|${authStore.getUser().uuid}|${timestamp}` + // } + else { + daijiami = `${wpsUuid}|${order_id}|${authStore.getUser().uuid}|${timestamp}` + } + // f6f25104fa0345b38074710c9356948b|USEWELFARENUM|1CBMDQbuOX3xbxAcxE5|2025-09-01 11:02:42 + //ios-//f6f25104fa0345b38074710c9356948b|USEWELFARENUM|GA5LeMOXChsKxMrqFnL|2025-08-29 17:25:54 + const scanData = await AESEncryptionDecryption.aesEncrypt(daijiami,BasicConstant.ExpertAesKey) + //hGaao+F44L7qAHJW3s6SuuJHMpP5jrLrFbPRA6AuJY5jF7eBABjSJDjIJL7uvAusvVMJT9371Bvey44xs48MtAaBPRdKMufmGMUkiOiS/916uiWz8iNWCZMYLa4iKXw3 + const encodedString = encodeURIComponent(scanData) + // hGaao%2BF44L7qAHJW3s6SuuJHMpP5jrLrFbPRA6AuJY5jF7eBABjSJDjIJL7uvAusvVMJT9371Bvey44xs48MtAaBPRdKMufmGMUkiOiS%2F916uiWz8iNWCZMYLa4iKXw3 + //ios-//hGaao+F44L7qAHJW3s6SuuJHMpP5jrLrFbPRA6AuJY7QHyYsqbbyOz0oyH4orYtJgPbG1eN9syk0G2vJ1oxq9/0V/ZZMHwb7Qu6H1TEVKLsZOInUm1rOJBhY1/hac4Dv + let pinString = 'X'+encodedString + //XhGaao%2BF44L7qAHJW3s6SuuJHMpP5jrLrFbPRA6AuJY5jF7eBABjSJDjIJL7uvAusvVMJT9371Bvey44xs48MtAaBPRdKMufmGMUkiOiS%2F90X6zMHwPph2jDuPjTMzXqP + //ios-//XhGaao+F44L7qAHJW3s6SuuJHMpP5jrLrFbPRA6AuJY7QHyYsqbbyOz0oyH4orYtJgPbG1eN9syk0G2vJ1oxq9/0V/ZZMHwb7Qu6H1TEVKLsZOInUm1rOJBhY1/hac4Dv + const targetLength: number = Math.floor(Math.random() * (10 - 1 + 1)) + 1; + let downloadUrl = `${BasicConstant.urlExpertApp}downloadGanDanFile?&gdf=${pinString}&a=${targetLength}` + //https://dev-app.igandan.com/app/expertApp/downloadGanDanFile?&gdf=XhGaao%2BF44L7qAHJW3s6SuuJHMpP5jrLrFbPRA6AuJY5jF7eBABjSJDjIJL7uvAusvVMJT9371Bvey44xs48MtAaBPRdKMufmGMUkiOiS%2F90X6zMHwPph2jDuPjTMzXqP&a=10 + //ios-//https://dev-app.igandan.com/app/expertApp/downloadGanDanFile?&gdf=XhGaao+F44L7qAHJW3s6SuuJHMpP5jrLrFbPRA6AuJY7QHyYsqbbyOz0oyH4orYtJgPbG1eN9syk0G2vJ1oxq9/0V/ZZMHwb7Qu6H1TEVKLsZOInUm1rOJBhY1/hac4Dv&a=1 + + // 创建下载记录 + let wpsFile = new WPSFile(); + wpsFile.fileId = wpsUuid; + wpsFile.fileTitle = wpsTitle; + wpsFile.fileType = wpsType; + wpsFile.downloadType = 'downloading'; + wpsFile.md5 = fileMd5; + + //下载文件保存的文件夹路径,仅为示例,请按需求进行替换。 + const DOWNLOAD_TO_PATH = `/data/storage/el2/base/haps/entry/files`; + // 创建了一个安全配置对象,其中remoteValidation设置为'skip',表示将跳过远程验证。 + const securityConfig: rcp.SecurityConfiguration = { + remoteValidation: 'skip' + } + + // 创建了一个下载配置对象,其中kind设置为'folder',表示下载的目标是文件夹,path设置为之前定义的DOWNLOAD_TO_PATH。 + let downloadToFile: rcp.DownloadToFile = { + kind: 'folder', + path: DOWNLOAD_TO_PATH + } + + // 创建一个HTTP会话,其中请求配置包括传输超时设置和安全配置(配置可自定义) + const session = rcp.createSession({ + requestConfiguration: { + transfer: { timeout: { connectMs: 6000, transferMs: 6000, inactivityMs: 6000 } }, + security: securityConfig + } + }) + + // 检查目标路径是否存在 + if (fileIo.accessSync(DOWNLOAD_TO_PATH)) { + fileIo.rmdirSync(DOWNLOAD_TO_PATH); + } + // 发起请求,执行下载操作 + session.downloadToFile(downloadUrl, downloadToFile) + .then((response: rcp.Response) => { + console.info(`Successfully received the response, statusCode: ${JSON.stringify(response.statusCode)}`); + + }).catch((err: BusinessError) => { + console.error(`Failed, the error message is ${JSON.stringify(err)}`) + + }) + + // // 文件保存路径 + // let filesDir = this.context.filesDir; + // wpsFile.filePath = `${filesDir}/${wpsUuid}.${wpsType}`; + // + // // 插入数据库记录 + // let insertSuccess = await this.dbManager.insertFile(wpsFile); + // if (!insertSuccess) { + // promptAction.showToast({ message: '下载初始化失败', duration: 2000 }); + // return false; + // } + // + // promptAction.showToast({ message: '开始下载,请勿重复点击', duration: 2000 }); + // + // try { + // // 配置下载选项 + // let options: http.HttpRequestOptions = { + // method: http.RequestMethod.GET, + // header: { + // 'Content-Type': 'application/octet-stream' + // }, + // expectDataType: http.HttpDataType.ARRAY_BUFFER, + // usingCache: false, + // }; + // + // // 执行下载请求 + // let response = await this.httpRequest.request(downloadUrl, options); + // if (response.responseCode === 200) { + // // 保存文件到本地 + // let file = fs.openSync(wpsFile.filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + // fs.writeSync(file.fd, response.result as ArrayBuffer); + // fs.closeSync(file); + // + // // 验证MD5 + // let localMd5 = await calculateFileMD5(wpsFile.filePath) + // if (localMd5 === fileMd5) { + // // 更新数据库状态为下载成功 + // await this.dbManager.updateDownloadStatus(wpsUuid, 'downloaded'); + // promptAction.showToast({ message: '下载完成', duration: 2000 }); + // return true; + // } else { + // // MD5不匹配,删除文件 + // fs.unlinkSync(wpsFile.filePath); + // await this.dbManager.deleteFile(wpsUuid); + // promptAction.showToast({ message: '下载失败,文件校验错误', duration: 2000 }); + // return false; + // } + // } else { + // // 下载失败 + // await this.dbManager.deleteFile(wpsUuid); + // promptAction.showToast({ message: '下载失败,请重试', duration: 2000 }); + // return false; + // } + // } catch (err) { + // // 异常处理 + // await this.dbManager.deleteFile(wpsUuid); + // console.error(`下载失败: ${err.code}, ${err.message}`); + // promptAction.showToast({ message: '下载失败,请重试', duration: 2000 }); + // return false; + // } + } +} \ No newline at end of file diff --git a/commons/basic/src/main/ets/utils/request.ets b/commons/basic/src/main/ets/utils/request.ets index 92c8fb4..132d4ea 100644 --- a/commons/basic/src/main/ets/utils/request.ets +++ b/commons/basic/src/main/ets/utils/request.ets @@ -12,6 +12,7 @@ import { deviceInfo } from '@kit.BasicServicesKit'; import { cryptoFramework } from '@kit.CryptoArchitectureKit'; import { rcp } from '@kit.RemoteCommunicationKit'; import { BasicConstant } from '../../../../Index'; +import { connection } from '@kit.NetworkKit'; interface HdRequestOptions { baseURL?: string @@ -26,8 +27,14 @@ export interface HdResponse { } export interface TimestampBean { timestamp:string +} - +export enum NetworkStatus { + type_default = 0,//无网络 + type_wifi = 1,//wifi + type_traffic = 2,//蜂窝网络类型(2G/3G/4G/5G) + type_unknown = 3,//未知网络 + type_error = -1,//失败 } class HdHttp { @@ -431,6 +438,30 @@ class HdHttp { return result === 0 ? (a < b ? -1 : 1) : result; }); } + + getNetworkType():number { + try { + let netHandle = connection.getDefaultNetSync() + if (!netHandle || netHandle.netId === 0) { + console.info('当前网络状态:无网络') + return NetworkStatus.type_default; + } + let netCap = connection.getNetCapabilitiesSync(netHandle); + if (netCap.bearerTypes.includes(connection.NetBearType.BEARER_WIFI)) { + console.info('当前网络状态:wifi') + return NetworkStatus.type_wifi; + } else if (netCap.bearerTypes.includes(connection.NetBearType.BEARER_CELLULAR)) { + console.info('当前网络状态:2G/3G/4G/5G') + return NetworkStatus.type_traffic; + } else { + console.info('当前网络状态:未知网络') + return NetworkStatus.type_unknown; + } + } catch (error) { + console.error("Get net type failed, error: " + JSON.stringify(error)); + return NetworkStatus.type_error; + } + } } interface DataBlob { diff --git a/commons/basic/src/main/resources/base/media/fenxiang.png b/commons/basic/src/main/resources/base/media/fenxiang.png new file mode 100644 index 0000000000000000000000000000000000000000..c56556c6efd12dfa1b55486e7921dbed9435b162 GIT binary patch literal 2153 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 X#$Gd$P(GGs`eTS-b6NF_1nqwS!digc literal 0 HcmV?d00001 diff --git a/commons/basic/src/main/resources/base/media/wei_shou_cang.png b/commons/basic/src/main/resources/base/media/wei_shou_cang.png new file mode 100644 index 0000000000000000000000000000000000000000..1cdd2223c792587a7f6d3ed90f2879b042e61089 GIT binary patch literal 2017 zcmaJ?c~}!?9?l^uQIM?=g@O#R3KhxZ03?yfk%Rzp#1IIrRt(8NvLQ1=GLQ&T1X|Yv zLBOp_Q3N?u1o6OCVF9hJY`sw1LUmn4MJY!k*D6I|CsyqKvFtq0%=i1g?|t9j`8=~r z93irzI8X=#f>lVcK!UFf^E-bo{*{r&|AH^}m@pQLLJ}~8Tn7;Xlt?@TglOf7kOYz| zwD_cwJ6Re5PbcNs9d3eFd!aERKq-)sj-CysFggL z%qyG`j`AUuIyg-SMWsbZ6=@m;M@jQr2lyJfxPTVI+C$IyH)^5g0Hl%Hxp~j7P&G{XGRO`d${+zbg}7FwiJRK_;DHPH6@h9{&HKTJ3wZ z9+N6s>!v*MSwUX=O?d2WF^78az1+kb+p*M%^y@tbP37J7c zK>&x(nc)f$MT!=Ju^F!N53bj&T=OJoQQWft(y3D+WsnZh0&g?ss%MXdHLKn`u5$KR z*t2p$JQ&d2*Z=DC%n?33X7l~j;+yw#55f4b>+q>YPd+Us5az^$2m++W2LqojP~F0^Fm9Q_;vNM@5N85{k@S9&EqvlreTY>&57?4&(RJE z0w+`VEP1iQna{mFIBvY%^QdrzQ)tr5P~yJG=o%U2<~$wmRLq=u`=vCcHLz*)G}&|7 zX&h)%TQhxSGM9*NFM7astvUSh{NtCO5tCb8$q$?N8UzPwn=Vh=)oy1viaL$b17%A$ zKD(Fugvc#*{j&E18|}WPz4p=-c1B)ooY&iQq37Qs;O?Tu z8IJRxF1PtEBW`_p>^1Rf>_H~wWgjT3>1A}+4W(NT1fF1#ZX7iEt@U5B-W~RfPlpeY zR#=y%-F#%T<$TPRY}Jd{AM|Z^w^fodgpIA`6kAoZgt+zLR~w~Sx?8eU?P2Fza1$wa zI%RkK)I9jY=&_RGUfEq3-e8eE26t-eJG!aS{#@go2GYIhUFVLI3On$O&Yu}_O#Ywj|>TT#pH;gP`h+hutYs!f#W*~jT;f_4_R zp1!JxUy#Gv{}jv38GP_jWb#;m3)gaUq4Ghwt=xU0_Kl+=G+4cf z81v+dvjSU7C#&|pE-}@WY67wTBWV*~&Mk_H(AV1Z6ek^qR}F{MO{uI*+dFrq^aYk3 zzNjK4hc4@idRFvz7sLm>Qc?56pzrRQ^q!9S{6NQ_@<8Wtw8ZUx$%*)A zR^uzHFm_38vF9yIAhT7x^Lf84)Q#!%<7T@;iNnk6CHawOqI-OyUBvNC$9%WtWelCo zxNx$fA7n21*<`yYzsh~slocG;Hqk(icXjjQ+YjUghN*`v=sQfrgxyn%Kb^A=92uKT zP&zLoO>U>T9D6ej9bNG1m-x#yZAJIUlP*ZYZxz`&&T3wH=hbUEp8uN*1)q&MPc?TA zyoqEnB1ic?seg^*SO0wS-s`IU{vXw!?G*HlDlJV{KWE4N)JZ+4v+Mmv1ld@0JKmr2 ko)89DP1j1U_v91EgvyivO87c@hxw-)B8(8!1#Zdy4^$8?XaE2J literal 0 HcmV?d00001 diff --git a/commons/basic/src/main/resources/base/media/yi_dian_zan.png b/commons/basic/src/main/resources/base/media/yi_dian_zan.png new file mode 100644 index 0000000000000000000000000000000000000000..a284a7f99f43f67642ddcdd1426e0e16a1d18876 GIT binary patch literal 1838 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 { + this.currentIndex = 0 + this.tabsController.changeIndex(0) + }) + + Column() { + Text('课件分享') + .fontSize(this.currentIndex === 1 ? 17 : 14) + .fontColor(this.currentIndex === 1 ? '#000000' : '#666666') + .fontWeight(this.currentIndex === 1 ? FontWeight.Bold : FontWeight.Normal) + Blank() + .width(32) + .height(2) + .margin({top:5}) + .backgroundColor($r('app.color.main_color')) + .visibility(this.currentIndex == 1? Visibility.Visible: Visibility.Hidden) + } + .width(80) + .height(50) + .justifyContent(FlexAlign.Center) + .onClick(() => { + this.currentIndex = 1 + this.tabsController.changeIndex(1) + }) + } + .width('80%') + .justifyContent(FlexAlign.Start) + .margin({ left: 15 }) + + Row() { + Text('更多') + .fontSize(15) + .fontColor('#999999') + Image($r('app.media.arrow_right')) + .width(10) + .height(15) + .margin({ left: 5 }) + } + .width(100) + .height('100%') + .padding({right:10}) + } + .width('100%') + .height(60) + .alignItems(VerticalAlign.Center) + } + .width('100%') + .height(50) + .backgroundColor(Color.White) + } + + @Builder + tabContent() { + Tabs({ index: this.currentIndex, controller: this.tabsController }) { + TabContent() { + this.BuildGuideList() + } + TabContent() { + this.BuildShareList() + } + } + .onChange((index: number) => { + this.currentIndex = index + }) + .width('100%') + .barWidth(0) + .animationDuration(0) + .backgroundColor(Color.White) + } + + @Builder + BuildGuideList() { + Column() { + this.BuildListItem( + '一学就会的keynote教程番外篇】keynote 线下实训你们要的带练来了', + '查看' + ) + + this.BuildListItem( + '胆源性肝脏疾病一专题研讨会成功举行', + '查看' + ) + } + .width('100%') + } + + // 构建课件分享列表 + @Builder + BuildShareList() { + Column() { + this.BuildListItem( + '肝病学新领域:肝硬化合并慢性肾脏病 | 深度综述大的并慢性肾脏病 | 深度综述并慢并慢性...', + '↓' + ) + + this.BuildListItem( + '【一学就会的keynote教程番外篇】keynote 线下实训你们要的带练来了', + '↓' + ) + + this.BuildListItem( + '段钟平教授:终末期肝病营养治疗的价值及研究进展', + '↓' + ) + } + .width('100%') + } + + // 构建列表项 + @Builder + BuildListItem(title: string, action: string) { + Row() { + Text(title) + .fontSize(14) + .fontColor('#000000') + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .maxLines(2) + .layoutWeight(1) + + Text(action) + .fontSize(14) + .fontColor('#FF0000') + .margin({ left: 10 }) + } + .width('95%') + .padding(10) + .backgroundColor('#f4f4f4') + .borderRadius(8) + .margin({ left: 10, bottom: 10, right:10 }) + } +} diff --git a/features/Home/src/main/ets/components/HomeIconComp.ets b/features/Home/src/main/ets/components/HomeIconComp.ets index fe430b5..c208ce3 100644 --- a/features/Home/src/main/ets/components/HomeIconComp.ets +++ b/features/Home/src/main/ets/components/HomeIconComp.ets @@ -26,6 +26,7 @@ export struct HomeIconComp { @State consultation: string = '公益咨询'; @State consultationRed: boolean = false; @State iconListtmp:iconsModel[]=[]; + listener: (info: uiObserver.RouterPageInfo) => void = (info: uiObserver.RouterPageInfo) => { let routerInfo: uiObserver.RouterPageInfo | undefined = this.queryRouterPageInfo(); if (info.pageId == routerInfo?.pageId) { @@ -36,6 +37,7 @@ export struct HomeIconComp { } } } + aboutToAppear(): void { let uiObserver: UIObserver = this.getUIContext().getUIObserver(); uiObserver.on('routerPageUpdate', this.listener); @@ -79,52 +81,39 @@ export struct HomeIconComp { { consultcount++ } - } } } unreadCount=unreadCount-consultcount - if(unreadCount>0) - { + if(unreadCount>0) { this.patientRed=true - } - else - { + } else { this.patientRed=false hdHttp.post(BasicConstant.applyList,{ expertUuid: authStore.getUser().uuid, } as updateExtraData).then(async (res: HdResponse) => { let json:applyListCallBacl = JSON.parse(res+'') as applyListCallBacl; if(json.code == 1) { - if(json.data!=null&&json.data.length>0) - { + if(json.data!=null&&json.data.length>0) { this.patientRed=true } - } }).catch((err: BusinessError) => { }) } - if(consultcount>0) - { + if(consultcount>0) { this.consultationRed=true } - this.initList() const hashMap: HashMap = new HashMap(); hdHttp.httpReq(BasicConstant.indexV2,hashMap).then(async (res: HdResponse) => { let json:HomeModel = JSON.parse(res+'') as HomeModel; - if(json.data!=null&&json.data.consult_list!=null&&json.data.consult_list.list!=null) - { + if(json.data!=null&&json.data.consult_list!=null&&json.data.consult_list.list!=null) { consultcount=consultcount>0?consultcount:json.data.consult_list.list.length - if(consultcount>0) - { + if(consultcount>0) { this.consultationRed=true - - } - else - { + } else { this.consultationRed=false } this.initList() @@ -132,17 +121,18 @@ export struct HomeIconComp { }).catch((err: BusinessError) => { }) - } - initList() - { + initList() { + const targetNews:iconsModel | undefined = this.iconList.find((model: iconsModel) => model.name === '肝胆新闻'); + const targekejian:iconsModel | undefined = this.iconList.find((model: iconsModel) => model.name === '肝胆课件'); this.iconListtmp=[...[{ 'img': this.patientIcon, 'name': this.patientName,'isRed':this.patientRed } as iconsModel, { 'img': this.videoIcon, 'name': this.videoName} as iconsModel, - {'img':this.zixunIcon,'name':this.consultation,'isRed':this.consultationRed} as iconsModel]] + {'img':this.zixunIcon,'name':this.consultation,'isRed':this.consultationRed} as iconsModel], + {'img':targekejian == undefined?$r('app.media.home_kejian_icon'):targekejian?.img,'name':'肝胆课件','isRed':false} as iconsModel, + {'img':targetNews == undefined?$r('app.media.home_news_icon'):targetNews?.img,'name':'肝胆新闻','isRed':false} as iconsModel] } - build() { Row() { Grid() { @@ -173,8 +163,15 @@ export struct HomeIconComp { url:'pages/VideoPage/VideoGandanPage', params:{"page":"首页"} }) + } else if (item.name == '肝胆新闻') { + router.pushUrl({ + url:'pages/News/GandanNewsPages' + }) + } else if (item.name == '肝胆课件') { + router.pushUrl({ + url:'pages/Courseware/CoursewarePage' + }) } - }) }) }.width('100%').backgroundColor(Color.White) diff --git a/features/Home/src/main/ets/pages/HomePage.ets b/features/Home/src/main/ets/pages/HomePage.ets index 98ecc1f..ecabc1e 100644 --- a/features/Home/src/main/ets/pages/HomePage.ets +++ b/features/Home/src/main/ets/pages/HomePage.ets @@ -10,6 +10,7 @@ import { BasicConstant,hdHttp, HdResponse ,logger,HdHomeNav, ChangeUtil} from '@ import { HomeModel,dataModel, newsModel,iconsModel } from '../model/HomeModel'; import { DefaultHintProWindows,SignPopWindow,HdLoadingDialog } from '@itcast/basic' import { promptAction, router } from '@kit.ArkUI'; +import { HomeGanDanFileComp } from '../components/HomeGanDanFileComp' @Entry @Component @@ -158,6 +159,9 @@ export struct HomePage { if (this.homeData.video_list && this.homeData.video_list.length > 0) { HomeReplayVideoComp({ videoList: this.homeData.video_list }) } + if (this.homeData.gandanfile_list && this.homeData.gandanfile_list.length > 0) { + HomeGanDanFileComp({ gandanFileList:this.homeData.gandanfile_list,guideList:this.homeData.guide_ist }) + } } } .edgeEffect(EdgeEffect.Spring) diff --git a/features/Home/src/main/ets/pages/VideoGandan.ets b/features/Home/src/main/ets/pages/VideoGandan.ets index b354a4b..fa0dc88 100644 --- a/features/Home/src/main/ets/pages/VideoGandan.ets +++ b/features/Home/src/main/ets/pages/VideoGandan.ets @@ -75,6 +75,18 @@ export struct VideoGandan { }) }) + Image($r('app.media.send_follow_icon')) + .width(48) + .height(48) + .position({ x: '100%', y: '100%' }) + .translate({ x: -48, y: -176 }) + .visibility(ChangeUtil.stringIsUndefinedAndNull(this.rightBottom)?Visibility.None:Visibility.Visible) + .onClick(()=>{ + router.pushUrl({ + url: 'pages/Pay/SendFollowPage' + }) + }) + Image(BasicConstant.urlImage+this.rightBottom) .width(76) .height(40) diff --git a/features/Home/src/main/ets/pages/VideoPage.ets b/features/Home/src/main/ets/pages/VideoPage.ets index b0019a2..977dcfc 100644 --- a/features/Home/src/main/ets/pages/VideoPage.ets +++ b/features/Home/src/main/ets/pages/VideoPage.ets @@ -12,7 +12,7 @@ import { http } from '@kit.NetworkKit'; @Entry @Component export struct VideoPage { - + @State params:Record = router.getParams() as Record @State notselectImg: ResourceStr = $r('app.media.triangle_normal'); @State selectImg: ResourceStr = $r('app.media.triangle_green_theme'); @State monthWords:Array =[] @@ -42,7 +42,7 @@ export struct VideoPage { { Column() { - HdNav({ title: '肝胆会议', showRightIcon: false, showLeftIcon: false,showRightText:true,rightText:'扫一扫',rightTextColor:$r('app.color.main_color'),rightItemAction:()=>{ + HdNav({ title: '肝胆会议',showLeftIcon:this.params?true:false, showRightIcon: false,showRightText:true,rightText:'扫一扫',rightTextColor:$r('app.color.main_color'),rightItemAction:()=>{ if (ScanUtil.canIUseScan()) { ScanUtil.startScanForResult().then((scanResult) => { decryptString(scanResult.originalValue) diff --git a/features/Home/src/main/resources/base/media/home_guideAndShare_icon.png b/features/Home/src/main/resources/base/media/home_guideAndShare_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8982c0404aaa6177ec4085fe59b7765d88eb9bff GIT binary patch literal 33261 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 literal 0 HcmV?d00001 diff --git a/features/Home/src/main/resources/base/media/home_kejian_icon.png b/features/Home/src/main/resources/base/media/home_kejian_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0858fa29b501edf61a43c1176a80214083128aaf GIT binary patch literal 8292 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 HRw4ffgo1o{ literal 0 HcmV?d00001 diff --git a/features/Home/src/main/resources/base/media/kejian_download_white.png b/features/Home/src/main/resources/base/media/kejian_download_white.png new file mode 100644 index 0000000000000000000000000000000000000000..984daa4b12728228faba0e0001761934a48df783 GIT binary patch literal 1459 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL1|)l2v+e>Z$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%!-*I5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s0;1ij}FOvy-{8v$?CKo1vkhtGR`%v7?Kdv74cV zo0Ex~qZv%EOMY@`Zfaf$Om7N8uLVxMpp=kX0JPa9wJ5VJHN~wcKUV?lW2;QuZZXAa z9#n4%Znv1>)TVL91WY_2COp*wIq-C!ng>kmMZi?u!mg~rz`&&8>Eakt zaqG=3L+`^5BJ3aLO;w5&ag^CzDk5`a{RLn9#s}9dtUT_UZBuHJUA3BHo#>sY zBaZ0{FRXl^Aj_?~??m^p*LPK?@1Enilf6D;a?Gc?m|2&CAMMJ^6U){!U!2Mn)>xCE zrKab>bGJ)>LTSxko|`kKN=EbTiQ72ekbAQMD%zkaaZtW-DUYPr4P(KBQ4{2z$OfHd zSk<-n+lKG=KTTs}lH6T?df~U@zV-#@_AM*63R(a7L0#1`xs~6a3#hjmKTXI#_^Kl< zNAObV^4AKk#@o)nSl_+(zszx|6Nj$`F|2lV{FvbRpyYtkViyDX?@KtBb0sgdvI&tm z<1Og#aDAbp1b?VVZ+B6W+`2r5G8uMJ(Phly>|y=glNwh(N=fw6h@8=1-O)I?abv*u z39K{Y9@~_0S19iCQ*dE)V_DIZGrw@ZM&%ARc5yaki!g34R<&;7gIgAdBpO-B^|bE_ zc6{0JbH{A~8SZ1wTNNv>?khP^bi-rz#V4Zg7AM}@c6v#GRie_I?YROK_5w1~uV3x= zo53L-78STA{=zEL#y1XmD#x}IoKbmuI^XV{(xHvMC)VYKOnTiV95X$mZNaxaS3B3} z&e(OM;U{{SAlFDTS<-z5h=?zL!zUX~1y5YeHlA?Mg9F OG3x2+=d#Wzp$Py(M-})0 literal 0 HcmV?d00001 diff --git a/features/Home/src/main/resources/base/media/send_follow_icon.png b/features/Home/src/main/resources/base/media/send_follow_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6eb5179b7f8552dcaac02f4c23fe01f87a91384b GIT binary patch literal 7953 zcmaKRby$>Lw?0x1NOv;~A>9lu0}QDmB`E{UFmw(%ba$hGC>_!zEe+y`K?njvNrxyM zg22J=d*APz-|sr_d9M9D`&s+C?|ZGi*ZODg9jB|KK}yU-jDv$is-+3lzv)x|ya2+R z?}qwv+fB#lrDoz~;AZRPYmGwUDBHNfkw7gMYdfSq(%J^?@gAvwgM-K6U})lH^6-Hi z!p%k4`VU6f&&ByIjSvfH&;9n2u z#v97UR!$$P{+F*COA%!6<>f9XBI4`oE9@&F?1r)v5tEgb6%iE|5f>M_K?r%GUA?UR zgj_v2|5kt^JrO7ecP|GwSKuE-Yq*=Ymm=sU(tl6E#r;3BuAYA_)6Ig3_*uJ)hzX1S znbP0DhY$a6sEf;g(4JoU$p4P_e--vLM7twJ^pT!!-YCRP;%qtpxN?_MMIo)d+)##Y zZq9$NqOQH0mz$@(n>$cd707Gs;A-RM>&f>o_``>CTCSd6)~*Po7E}>*BOvVHU?V53 ztSSkWlob_KgUX1BsY$D-h)Jk`!Rk$f*A#SL7xbkw1C;A9? z%lFDx#<#sz%4=$Pg=6Dmljf7-<)&-9VvA~$3c`th#(!aJ_I`4k{>e1`Kn~<25(2~z zOSQS$H6jqG`&s4x_;|Z3Yc+Ud&VZ#-|3lE?#p!jAo{*4GNdX1_6URF=G-3av{XYgS zN2L^1(007Yq$@8kQHhmMk^J;-+?v!&W41aLSbOI(2W)#>0QVLiI(ONW z+K+UNwph3dl*$H4mO$r@e18IqnBX?VC$`@_luMejfo1p|8)enxQrQ2B{Ni!}-=PiX zojS~^%WKdJ{^*d4%3Sbhh^QpAKK^ zEIp%PRqcYq%gwXwxBKh1u%!upmwjbCj*bq6(PhO=tqp10$zc7-B~`=sRXd{`Sf4$d zXNNs69DSo|+l>!) zR42u-SszqaENXl>-6D~^X4QN=3V+0P+h+a1on{>=4!`VIMIr5k?|G7j(Y z8os3X^X{5iRrarjWAPnka@hBVxuyIcIlXNU{PD5xFpEcVNu>z}5}W(R8mSnv4gESK{5v6nnYa*E;dZV+sdh9^YH z$mQ8lpqAJqm`x9#I8EWp*%BXdYH@#=<&f|0>J=Vu-wI>%#izAJ{K)_#l#+jYAbpn+ zOeKl+qk4QY(Bm7^Wz^J1=?sagb-jYj_KA~!1lvA~)a!q}ukyt7%puIJd4qEDK_H6?}^6-QGq$$vieiHP_ zf(45{R0n=;GQkqT0Ym5Ud2IkGGByl@vo{_cd}Ia3t9$KMOj}b7pzGM2G}1A&gy_^+ z|6DIezvbz5wAZF)0|#+m1|Wcb7v=o`7oE7S);WGeG9ZtN;cuoblN(@D_lDw%xpMoO zC(%fgK&HF%;mX+%ak_w+Lcrj-9Y9H8d*nr1_`E)WXK2^UO{?8WS}rtDk3L;Tj6vnl zw;8WtHZQcRGoZke`ct2F!FSD9B(!m37mp)lL9xE=oL|MrBr8cnI3Jx34)~97RxLdD zG*2Tup$nMHeaC2qsSy zt&%4g)c9+OPH{2{E}Hde&{Q9$@}Y7V>IqDxqSrVjWl}E=;37PRy$Qaj>Dh7#HD@Mk zljh}*=P5mU_5JMUuI+38AvQ!^okh>MSTj_;?!tMTh~Ww>HDH9dn?Fe_86|xbHNK2k zy;VuZUbe+NH5%Wc7`<4vxk0!Ot69A@T6SoQWVGmBmp3!)$k-9qd<#R2%q9^dwjvl6 z3~WXU`*w%D0-l_BA75;iB~@+J$+rM13S*S$YG2ivloIrp;azOyc%S=%F+}M)rl*`i zM&^j`YA-$pBzL)qP}!H|Rld0=F^g(|d9I3Ho_>9((t&YIIP5sy`_=OX>{jr|sp>M_ z4jVmLq;WMpRKGo(1s(Tgai+)*k*D@d$SP^1!em(QvQpXtL~W>r-pTLhHa{wGb8@)a z&um^O&>{35{9uxckz*d6A~Rp}y_DFRuSEG*+gH`m_kz>FDr8hD>1ezG`YQ>kTw5E` zl8{NmvGD^7!)ng8z2H_PIbGMW5w1-S{0F(A&!(L@(FF4IOW9@i(OoL5Z(&Ue$C*1} z@YFEcv;0b8fBS$!dyY)L>^tYB@v8{sB6Ikv_pWjfVrA1QY5TlK@eLnm_xA?(h(rY( zY=Y~1Cf+N>a&zBvDeBkHYw}s0IUVkFx4ee>_mriRNlBaLTtq}h9$C6V6lb}^fM(!B zrX9{qIASZQff}?R*5Mz*Dr8krJVhuW+(7@3J@tOXFVKg*{hyBhp^E<2D0`1RGp! zrOMwz`ATNN=3;Z82Fj~;$DksB2Jfi2B{1I@aT6sYm?9Qy{$t6!ML)6 z08`4>=;orxyqWfaG<^T$xrziZ#O1ItoSIX76Gy@~Z@xJqvw`$W31Z{P;P&dlRbSc^ zATBXoLtqKUKdUA0y~C+lq_j#BXCK8uDEGkZxW=VcQ2@` z$WW7=@v7L8=@W*H29@?qi7HBkZC7Rt-oj2f`1BKzc49K+(4`ckDJ8QOo)oFLd>lmd zrBdo;U*{4cG8TMCG|_|p`;06DD2hebH5LsX^j^Q%U+7f24Kr2`RME_j@DRRZQe&-? zN+L@%KP@vtahUXRh`)u_&eiNYFRtRicb*>!l$~ZqqJ2;0iPG2kT0Fb=5gQMXh?BvR z)l?-s-?fAXIw4`|Lcs&$aJgAOOlVAaf3*L({I#&+1psm8YCEv_-~ur0G(PO+kU~lg zIRZ2#%^7@~#W{Jm>q!`MSvb=Bxk8Y>wvKKunWyxG{DY=Oy&G&F>|rDPORNX`_=+{uYZu2zQ_AWQ5?jZU|-$tjx`bx6MMihTA? ze1mYCsm)=Sj%{p)7T-&F!9cE@G`g1&SSf0GT1sdFhOZbY)i7>keR-1jo@Lb^(`~ttQ zyYA~(`H(f~BTs{jQvCE^S+6j#Scmc@qd|^amCY4DnPiT#p#XyH6_WiLJI`;+i$e=9 zdR94i1O;v87ne$p@t6AgjPQsk7m0lM1-bZxH`J8+M6>UWH;CKbY>mDwKc<4&Lo>WWa}qzj{6|_Ea4&< z9G{?14V7Ud()ms5%qk>`psWB;aL@#hjxVRQtJ;fQcL_eZMf+>-l778P@Yh|pOH&I5}(ATII)TVTcWP~(8l#s1hzf=1FIhaO&4m0h+>`MsyNHsBvIZ1#?!1_@a+ z+%bb0TH2H@I%-X_Z;~`Mz8x@SKE)c|o)F-&;TjIrTc&(4_rV!={^8H!+t_c5{->q4 zqe-MM2asIhPXofFrN6AC^?52+XqDP5h*#qBl$LyXd~2K{NlnVj#)U{qnx$y7`W}rE zIH8CNzO`2gmuqY$z5>4`(JDRLzk0(4S-l(IN=(a-7b})gN*PNs^8Nf+K!`hKAD9aK#ZqB?8;)EjoppR@p}{?{kC7` zsk7EE;n_Jqhcn|{8fF8)AWT22yroYKAAgtkiO548&|43IS=nENlaqzJt<4l*|&yCqMqyuG;KDuji0QfW^6uas3V9#5=d>EI`4YP-b{{xG!;=F34EoNiHcm~Cu+~bmMp7H6s;R$=8cg~m{=3Uk zNQAQF`iVX}X}~+?*c@{;P}LjNCj9gkQ>dD~RYCy5_`IpCmozxXh0u`5@q_aB8L)qa zb5?9!phK^P_wj>*Ga}V*Zs%j3)$u3;ULJY(Bq=$ISGAVh+WIzPg_f^Mh!DSC-s8JB zV)4$k3x9TQ)sZ9jh|QJ!>!wz;s)Cs8OmPk3%6 zOO*D)rs&Jcln0k3&m{Bb5scA+umsW4;O?E`jT&nnK|{9l6|9@fziR0(wfM@L_C-Bp{o@pWUwFj@#^HKDmgjh zQa;Y_)*6Bx()12`F;zQA@}l^3S$xpZq4A4~HBIWb?D_Y_A`HAN6NUyiwBt+B^}>0$ zGJ&vy1LM_QUH;|V;_%ZJ_X(LVcKn5Gn>*~?jY$wd&ACb4HB(3<1A{B!Pu{t22Cu`f zYGZIy-!X?xFj2h(+=)ET6*J!)sjfZJ$E_c;T_YjeZel%Z?<(Y=?57(^5tnY89`$W17D9lT7-Y%;XaZh-boNjkUj$;`O^n zOW_KMbmiHdU{3Q1iQ5TVc}5PJMPE_okwW!%ZOPzut!Ds~kbwLByYH7-9e5%!&9rfv z(eNB~i72q!+0jDK7QT`39fdTjUC!3DK(#IjvK}>A#{yx%YBPo2*Gvn*>COH#L4W+M zX|0F#)27w>4waE^UwB(ioLtcxG(FAKunw-W!s>Zog}P_=Q*g`5&r<%PM~+on{@t%1 zNsU%k6X*kD_47y61xdahGo>$+y~81Bo8)zwj3&_Cx#FUJ=(bMYSv6~F5rwEK*dTT7 zIe8POxaHtVX<|`)iGQHHX6>1C%2BB|UHfAh%KUlW985gBTvq*LD={C^OQ5cdl^2W~ z)hSLI3v7B5|8-(&4C(Ov-30c2(a@_0X8H*wT$L0QQ$)0>lBtgV0}R4e<9A;u@D5iy z(ej6BAA$P?3+8AD5RG}La!UNI&p%#(Y=1_IcM^9w$#663uW>%SpxDVlvpGZn+Fa3V^;CUxK>X{wBZAK#<7OQ(k?MNSd~Z5a-#GTZtFPA zpDpg2RR-yCX`7`mrsX}C_Xh)>tW}x(i1Iuc5>GMva(@txWg6Dw_@zQXj1lECs>2~8 zxRN;qjjOir2s=y)RbKo3=Ceiv)kz-4UN*~(--6MU*+*izx81@CiZHRvQMifS1EdAg zq~L5*^`(9ywPQ_Q*3@#a9)(ny#_Ftks=Nx>`~2_8OSk(XX^*fK&5p+lK>tZSQKdS+ zDu$j{F*lp^NbM%#wqLGk4=i4f6NV?gn>>u$>2s|QhpgZop*Z}`J}t}_{q)NT6CS%T zJqUzb`H+=RYlf*0LI@A2lorgHQwCKYkMqB+iFQ6U){F?fsJTXk?i9eD*h3QwcP;ru z#xBhx3GWfX_o%2^dQK$@a9)Sh?oV*O#}p?a+KZ}%YD``gU)AuWN~VP~#Ivp(dr-ny zf>?5aTlp~`h*NGySzxgR^3rYvYXLqNes*T|%(x+Qt;Swyj*s!e)5zUKp86ZtkK{3c zb9iR`beL*CIkMs{IO1vLHv<;{*nTxNH)bm5*c$IXjz0I7# zdIt@f<3#bxb=^59%U>&wV+{&zj_Gm>*Uwh5SD;4RX z;PVnm(ZXdvX6fyxu=nsjceQ?l@3qS%Y=S}*6oJ+gG8Oc3;6Mzi5`<(BM3<}_|w$M^e))V|=HPl)Mi zJBd1l^{zYpx*J>FX@L2%(+<`FjRrJcLrpiBn2)MSHjCeNZX5rCZEMJSp>&&`PZg%Ae#c!AfJ;a@X;B0m#PBmli zc3X|uu8$Q{IvvZFi{V>mSrHJk^cUnRil*4!>;xM)W_abF8w=gRf|iq_8cmDG34e7; z^H;N@;wqy>q!!AkxhU$P!-5Otr%s@Eem@Gk_JV6|5Om&e)%yWw7s7J;S-eX84+x7_ zP0e5`#?_Y#8=8CqWXl81^@k=pA^7Lvb1T6?d$v*6h4V`|rDXNeO(kz>0%%rx1fFZt zCCfRJt&pfRofW*nmsM~f5_HVbZKNEVCbz_sSHEE5rtmpI&rtJzJ?DbB^08PAC1*l$ z=6noULFK0_-Ccdu7_L^LKImYMd+NMTZZ9a>u}sZRpRiVWa%rH23WEvrWB{*76yk7G z)UC4DRSAELcPU7ErTc1^MXYd3Iq`OMxzhKGHJ7X1{1u%d7~yTI-g^P44KUbjO%<$n zfXKeHUa+OHhRM5xQg@FtbrfI@8Fyt%bLCx>)38shIY3d+f|3n9r6>XPB)KHz$9hL0G6L?;#8Pv^igOr>V=T9(hFkYfLL3<9*CP z6!GATGFOu|-Ysh4F!wtvQLly7LQuznDwH>A_>I-k2?^Y=X2B zyo`V+I8}c#vIf#jM=P(6pJ@Dsco{ZL|1P$I6ied060jxoAY?>YZqljIE%M!D`jrmX zqfz{WRDcDu@3vwJVP7eoj`r#8CfNuQz`A1gUK-}&p?<0 z0LBPz5r<($*Imm)b;f(?z5GC&DeM(4XM5}WFJd2YD@iCv zu4v2G_BAtJRz1bRqJW4mG4(IC*>)IDK5wlOB|zAy3S*qh77oidRcBPo7j*6LPqxWB z?MT5*njhQjPZmvF?np*Om>&MkBIK&me3c*N>AIGHxrTV}>I} zvCQ?-uZgFAO+@+<<2KNQHx79`XW#B3JeE6knc>=wF{iP_;sk_u$&Qmb=V@vIQvpLq zZ#(Zz1(3!@oG)Fpx;B=QPC4|leH&EY(F*9Qc<_ltJdQ%Rt2dtuSJdkunzTw#9`}7* zuiHDeK(pEI$&RfGBzau$z;~CBI#qkN_sWS54nLuTeQs~v2+=Qd^6H;KVA~{OMeSFx zn2+L(8`;4PukoC1f#0M*e_M=SoMZdJ%BYeIWhUs^OFN+q)O6p#Hwo{n8aqx!?0hgE1j=L1Kz9GV~fW|V@m~( z-LPw(bRkRLa;{H;z@RF9ql%rjsU^FD6uQ2Vx3Xk1iQewYXag5)R0^wcFYOqlB5DCF z#KoX3GLBUGw40OLn;V$4{b&t#NVD}cZinh#Y^`2mVjm8{0|C_-feCAY_Yksj4i?(D z0jzty@D6<<#ZVu2EW=7eyBczjr0OTdRM$8 z%8KY==HdDsMV~w-8!>gKMB>aqSqnI@piuYk%OmdRG-3S&C0`smQ~CR33DHXo--vTl zAZ9?4(Bew>J!3KvKOY%udb}w2RqG-Rm%Eks-N@vy^YMvmj_EHu$| = []; @State expertData:object | string = new Object; scroller = new Scroller() + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + aboutToAppear(): void { + this.getAppActivity() this.uploadBackImgAction(); emitter.on({ eventId: BasicConstant.notification_home_tab_change }, (eventData: emitter.EventData) => { if (eventData.data?.changeIndex === 2) { @@ -61,6 +75,25 @@ export struct MyHomePage { }) } + getAppActivity() { + const hashMap: HashMap = new HashMap() + this.dialog.open() + hashMap.clear() + hashMap.set('id','6') + hdHttp.httpReq(BasicConstant.getAppActivity,hashMap).then(async (res: HdResponse) => { + logger.info('Response addBonusPoints'+res) + this.dialog.close() + let json:Record> = JSON.parse(res+'') as Record> + if (json.code == '200') { + this.rightBottom = json.data['img'] + this.rightBottomPath = json.data['url_path'] + this.rightBottomTitle = json.data['name'] + } + }).catch((err: BusinessError) => { + this.dialog.close() + }) + } + build() { Column() { HdNav({ title: '我的', showLeftIcon:false , showRightIcon: false, hasBorder: true }) @@ -73,6 +106,8 @@ export struct MyHomePage { Column() { HeaderView({heroArray:this.heroArray,expertData:this.expertData}) OneSection() + TwoSection() + ThreeSection() FourSection() OtherList() } @@ -83,6 +118,20 @@ export struct MyHomePage { .layoutWeight(1) .scrollBar(BarState.Off) .align(Alignment.TopStart) + + + Image(BasicConstant.urlImage+this.rightBottom) + .width(76) + .height(40) + .position({ x: '100%', y: '100%' }) + .translate({ x: -76, y: -76 }) + .visibility(ChangeUtil.stringIsUndefinedAndNull(this.rightBottom)?Visibility.None:Visibility.Visible) + .onClick(()=>{ + router.pushUrl({ + url: 'pages/WebView/WebPage', + params: {'title':this.rightBottomTitle,'url':this.rightBottomPath} + }) + }) } .width('100%') .height('100%') diff --git a/features/mypage/src/main/ets/view/ThreeSection.ets b/features/mypage/src/main/ets/view/ThreeSection.ets index bd46de9..7718880 100644 --- a/features/mypage/src/main/ets/view/ThreeSection.ets +++ b/features/mypage/src/main/ets/view/ThreeSection.ets @@ -1,6 +1,7 @@ import { it } from "@ohos/hypium"; import { MyPageSectionClass } from "../model/MyPageSectionClass"; import { MyPageSectionItem } from '../view/MyPageSectionItem' +import { router } from "@kit.ArkUI"; @Preview @Component @@ -9,12 +10,12 @@ export struct ThreeSection { @State currentIndex: number = 0; @State threeSectionList:Array = [ - new MyPageSectionClass('oneItem',$r('app.media.app_icon'),'我的账户','/pages/MyHomePage',false), - new MyPageSectionClass('twoItem',$r('app.media.app_icon'),'我的积分','/pages/MyHomePage',false), - new MyPageSectionClass('threeItem',$r('app.media.app_icon'),'我的福利','/pages/MyHomePage',false), - new MyPageSectionClass('fourItem',$r('app.media.app_icon'),'我的鲜花','/pages/MyHomePage',false), - new MyPageSectionClass('fiveItem',$r('app.media.app_icon'),'课件明细','/pages/MyHomePage',false), - new MyPageSectionClass('fiveItem',$r('app.media.app_icon'),'课程明细','/pages/MyHomePage',false) + // new MyPageSectionClass('oneItem',$r('app.media.app_icon'),'我的账户','/pages/MyHomePage',false), + // new MyPageSectionClass('twoItem',$r('app.media.app_icon'),'我的积分','/pages/MyHomePage',false), + // new MyPageSectionClass('threeItem',$r('app.media.app_icon'),'我的福利','/pages/MyHomePage',false), + new MyPageSectionClass('oneItem',$r('app.media.my_page_myFlower'),'我的鲜花','pages/Flower/FlowerDetailsPage',false), + new MyPageSectionClass('twoItem',$r("app.media.my_page_coursewareDetails"),'课件明细','/pages/MyHomePage',false), + // new MyPageSectionClass('fiveItem',$r('app.media.app_icon'),'课程明细','/pages/MyHomePage',false) ]; private getPagedItems(): Array> { @@ -43,6 +44,11 @@ export struct ThreeSection { ForEach(pageItems, (item: MyPageSectionClass) => { GridItem() { MyPageSectionItem({ sectionItem: item }) + .onClick(()=>{ + router.pushUrl({ + url:item.path + }) + }) } }, (item: MyPageSectionClass) => item.id) } diff --git a/features/mypage/src/main/ets/view/TwoSection.ets b/features/mypage/src/main/ets/view/TwoSection.ets index f6930bb..b68229b 100644 --- a/features/mypage/src/main/ets/view/TwoSection.ets +++ b/features/mypage/src/main/ets/view/TwoSection.ets @@ -1,6 +1,7 @@ import { it } from "@ohos/hypium"; import { MyPageSectionClass } from "../model/MyPageSectionClass"; import { MyPageSectionItem } from '../view/MyPageSectionItem' +import { router } from "@kit.ArkUI"; @Preview @Component @@ -9,10 +10,10 @@ export struct TwoSection { @State currentIndex: number = 0; @State twoSectionList:Array = [ - new MyPageSectionClass('oneItem',$r('app.media.app_icon'),'我的视频','/pages/MyHomePage',false), - new MyPageSectionClass('twoItem',$r('app.media.app_icon'),'我的课程','/pages/MyHomePage',false), - new MyPageSectionClass('threeItem',$r('app.media.app_icon'),'我的下载','/pages/MyHomePage',false), - new MyPageSectionClass('fourItem',$r('app.media.app_icon'),'我的收藏','/pages/MyHomePage',false) + // new MyPageSectionClass('oneItem',$r('app.media.app_icon'),'我的视频','pages/MyHomePage',false), + // new MyPageSectionClass('twoItem',$r('app.media.app_icon'),'我的课程','pages/MyHomePage',false), + new MyPageSectionClass('oneItem',$r('app.media.my_page_download'),'我的下载','pages/Download/AllDownloadPage',false), + // new MyPageSectionClass('fourItem',$r('app.media.app_icon'),'我的收藏','pages/MyHomePage',false) ]; private getPagedItems(): Array> { @@ -41,6 +42,11 @@ export struct TwoSection { ForEach(pageItems, (item: MyPageSectionClass) => { GridItem() { MyPageSectionItem({ sectionItem: item }) + .onClick(()=>{ + router.pushUrl({ + url:item.path + }) + }) } }, (item: MyPageSectionClass) => item.id) } diff --git a/features/mypage/src/main/resources/base/media/my_page_coursewareDetails.png b/features/mypage/src/main/resources/base/media/my_page_coursewareDetails.png new file mode 100644 index 0000000000000000000000000000000000000000..15e4eb1d8f0895c6b38d417628c9cabd6fac621e GIT binary patch literal 2049 zcmV+c2>$npP)Px+yGcYrRCr$PoPTT_M-|7vZ}xmHNleQnXS+!XftptI$3OfMAOxvUgGfsY6-gFyC&M2!P^YL?a(C-X>ox^db=A^BArc@NLDe+0RTV^IJ87tZoX@qL zxf8Nf#dGB*?-p;(88A78hNPrrA7ADXDRK`OV1Bi58 ze-D6V&CSh=XBLfp~R)by_l0VtQt-O0@NmgsAOnRl*Uz53_f-QDVst7`ECXvdBn(OfR~ zI5V$Ty%W)3I2_*G+uJ){Rc%TLGYsRK%)HO_SoOO~sp9;WC8FDt$>i^eh^wj7k_04# zxL->7833PjK{`c5oylbKnQB5>s(^Obw*3MTJq}=9(PN0{p8(8MD)pOcdC`&tq&y{+ zO6@lc^0V?(ti^XoTZTq2l z6WJF4Y_%+F$fHi@RI3`Go)4|MLXtQF;9_6O5FLZ0UAsu0No&ij1(}Tf2^rzj8h!yaI~H zu_cj64Eu#tJ3x%TlOPMAf4h|;$crTKF)-Auycjbi0r$0Ba@h}zmtHz&@#z&%u^(O6 zI|2L{K#QyIL(0i4%ld~ONHqgQz+q|gS4#!rpLVp}Ow0)eE_D=so^8J6eDzJ!G^CVC zmq+YQrBZtqFqBNwG^Lc?#Xo_WnTUSX+}zyR+uQ4TiBva0d#+s7qUE(d2H)x!I;shL zcIWXoPR=*n3BXUg0I8sR06@un5Hp8~NWI;Zrxx>8>P7Ge0JmF~HR{Ea>IUecb?Yvg z(58Q;+}??%lPu+@yH1WDpRagVS69o_)Rc-JMQ`(BTd6vdhz?9oPk-m&!Gr%PC#Y_K z?)%84AK;w*B!G`PfQ|{)zIgX*8MRzEr9`k z1dF}Q{5b&HSwrYC8M5{74Ns_S;W;H9kB7&`#x_YQ@1Hjz^vx*{fSjb-JD|A}KmvuB zxq0rJ4O2{P>^d>77M}~2SS4&?H zj+KoG-h|GrRY^XpW<$)AAw;JcbPp}#{#wCNdISQ{-pivMHi_rKtTKJ7s8})z(42(2 zv*wy&!XHH_)PMKTsS!^wE2tC*Ko4}RS)1e8LkwJ980Wx~VG?G0IP#X;wrFdsyl!wX zUxB^8n+5{Vo{lwZ1<(E#z%>O67*E)k-M;(en{xp9wyp{d8i2|`YykRy1=QKuxiXi_ zT`7bJ`59?a%1L+rClDSqKS);^gJQAR=WW}52Ecp$z$w-xqDN+CW{m#+{&xZaXzvv( z*GN0`R55ujfTx;7zVogVr|0B@yc(EVfN_u23GzKdZPJDv2Y@3u~Zqb)5hU+C%SnFs`+#adCSoyu?Ny1qpS z@d;-36@!Rql9~I8*~51wplSkd09p#K`D*^-)t1%ppoRxk=2L<2AhpRelgWIFh;{;4 zTbW4}w|-Lyv2SQ-=+NNcU_KClwr$%M(KPK*0AH%uyebGFqStNP-k46Oj|BpdX_~E4 z$^if>5g&w-0q|wZvR)1ZAT`9s#>Q@wQhp!6@;Vc;g%AhZ+S-1kHg*OAkOM@`epgB< z-QUFP!D>34PLCBk4icbxz$n{i15jfgRMtrrtkCeFh6lY%JV@<0jYgv%%;)oqN|RQG z;eV~Aly7g?uwi8L=FNqVmVp>zYJXrho7L695&-H%Vm*tkc9Svlx78`2KmgjleS4b_ zLhbiaXDEVDMuiYxNhXs=0s%;EOR;VHLFc%pr%e$xrg%IQ3T@oKfB%U<08%;RSS)t6 zvkxZ-tN908TU(C=ZK+XXr&yf$KzPvNRKGB-8h{!T#mYRb;Xw@#3b+U9x?a~~;g#V5 zW@l&DN+}-(aIKO>M89L^Z&;R9_T0ax30=J}7N`^upWRrhj%*h8RjZ>2%zT%ZyFWYu zQZfU0HN|4NohG8KsZ{FMg`JdTidR4g*ySeW>?-wK!8y?0-oD%GEe)OlsU8D#J&s>M z>X4o~NcVJmd;7Cq;S`3W-=0*PdS9^QSLd0T88wuqEz5e_%dm3GUko6>`Yq}D4M5cj f(o5P6Dp3BvP_n|Z56h?{00000NkvXXu0mjfOjO`w literal 0 HcmV?d00001 diff --git a/features/mypage/src/main/resources/base/media/my_page_download.png b/features/mypage/src/main/resources/base/media/my_page_download.png new file mode 100644 index 0000000000000000000000000000000000000000..cea5074a46807797cccc78ad37268336f24eb28e GIT binary patch literal 1581 zcmV+|2GaS7P)Px)=Sf6CRCr$PoKI*YRUF5Ezc=Z$4Ype?h0^1)V(})PJP1WEB6?9%^dQ@&+jM&f zR2H;r5URK15OTmLD@g^0^9!p`Vc3VlCY3BXp7biM9CYhPc zpQJi-D(QQZ_df6YeZSv(Zzc%QRhIxpeCiX30NE%c0(4OT4Gj&&1_uWRxxKr)ySqC( zJEc~ze@iH6etupY92|@i(HuiT#Kr#p{@lXCf^0UVmH;$1Hui)N;xj~inSl_|H&V*C zH#awbivR&YI-Ty*G;N!Rh71MmsH!@=wzl>l0u%wV*TCrLXrHR8Ul7p?hJx;Cn)YTc zmx~m{KvJnx8~{E7fa?a%n*i``CX*@H;|;b%OH9(-#bh!$5R1j$;=fC!(&yQ1c0bsz zJG*N3i8G;nu8(* zMGEppAX1Pwe$gBhDd>NsphO~}_Vo0;$Xz}Z(sJdxiLwmH?0i0AHe8kbt=T0IKE0zB&jz?XcU?lrmv z1;~KI=lpM&qq3WT;|Nf#=w?9Lh{xleqFWGvcu)(4!jh2$Hk`6J24sS?LPVoxxgz2w z=T40($!|c$+{vMQ%+k&r5ly>krz=1ViL-4fC6CNCbCTu7Zhiu)Wh(&qR0uKacG=__ zkV#1y0C>%kiDrt$;@sBOmaAmaFF+$BBR%cy?TbW|vaAH|@Mmt6Q*|xoCOjK5_Qh^~ z0P@pTW)2N0sB#0p?B*4a-?s7%kY9H50w@Su`3lI7=+-EpplszkAg|G_5kNuODiA=G zjQjNTl=oR&MK`yA>e;HZvvb1FEg4UfbhW5wWUwm$Fk($6RaKo?TU$G})^h_WolbXa znzn3B0s&wv9*rf{r zC+F6+l>z5YJRVQ^Jt0?{lLDKA+}KS~luvYB-!Q)~rYOp|uIulZqg7b83SB|wwVST% zoC5GZjoEJZ0HBMAo-2n|#2*0Q#CScba&E=8;%GG;M6{|E(Lz&Dr2)poZM7S}o61|b zm5H362VgM5sK; zQ+}3jn#IhWNF)+UZ*On!`T2P_f8N&Cc6@kvc$m-U*_GhZsPruWJW2l~cMclSx<&A>wcM}W zJ+YT2e%!D7>bWhTkFWG4B;j`JcDM1C38dj0dk^yU?%)8>z%xXp9Res%p#PN%0ge%4 zLpS#JfAR!q9za~W(*L|p@)bnEzmRa@FCtk`P<;Jx@8J6dfVw}yW2>MGPs3veB0zqG fd5?o|p{xH1BQ$oDor4)j00000NkvXXu0mjfDS_f= literal 0 HcmV?d00001 diff --git a/features/mypage/src/main/resources/base/media/my_page_myFlower.png b/features/mypage/src/main/resources/base/media/my_page_myFlower.png new file mode 100644 index 0000000000000000000000000000000000000000..6251e045a6f254bc7293f12a0010661ad6b5e802 GIT binary patch literal 3987 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 { ListItem() { KeJianItemComp({item:item}) + .onClick(()=>{ + router.pushUrl({url:"pages/WebView/KeJianDetailsWebPage",params:{"model":item}}) + }) } }) } diff --git a/features/study/src/main/ets/components/FlowerDetailsComp.ets b/features/study/src/main/ets/components/FlowerDetailsComp.ets new file mode 100644 index 0000000..75cbf93 --- /dev/null +++ b/features/study/src/main/ets/components/FlowerDetailsComp.ets @@ -0,0 +1,232 @@ +import { BasicConstant, ChangeUtil, EmptyViewComp, hdHttp, HdLoadingDialog, HdNav, HdResponse } from '@itcast/basic'; +import { PullToRefreshLayout, RefreshController } from 'refreshlib'; +import { HashMap } from '@kit.ArkTS'; +import { promptAction } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; + +@Component +export struct FlowerDetailsComp { + public controller:RefreshController = new RefreshController(); + scroller = new Scroller(); + @State pageNumber:number = 1; + @State totalPageNumer:number = 1; + @State flowerList:flowerListData[] = [] + @State isEmptyViewVisible: boolean = false; // 控制显隐的状态变量 + @State allFlower:string = '0' + @State allTotalNum:string = '0.00' + + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + aboutToAppear(): void { + this.getFlowetListData() + } + + getFlowetListData() { + const hashMap: HashMap = new HashMap(); + hashMap.set('page',this.pageNumber.toString()); + this.dialog.open() + hdHttp.httpReq(BasicConstant.getFlowerList,hashMap).then(async (res: HdResponse) => { + this.dialog.close(); + let json:flowerRequest = JSON.parse(res+'') as flowerRequest; + if(json.code == 200) { + if(this.pageNumber==1) { + this.flowerList=[] + if(json.data!=null) { + this.flowerList = json.data.flower_data.list; + } + } else if(this.pageNumber>1) { + this.flowerList.push(...json.data.flower_data.list) + } + this.totalPageNumer = json.data.flower_data.pages + if (ChangeUtil.stringIsUndefinedAndNull(json.data.total_num.toString())) { + this.allFlower = '0' + } else { + this.allFlower = json.data.total_num.toString() + } + this.allTotalNum = ChangeUtil.formatPrice(json.data.total_amount.toString()) + } else { + promptAction.showToast({ message: json.message, duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + this.controller.refreshError(); + console.info(`Response fails: ${err}`); + }) + } + + build() { + Column() { + HdNav({title:'我的鲜花',showRightIcon:false,showRightText:false}) + + if (this.isEmptyViewVisible){ + EmptyViewComp({promptText:'您暂未收到鲜花',isVisibility:this.isEmptyViewVisible}).layoutWeight(1) + } else { + PullToRefreshLayout({ + scroller:this.scroller, + viewKey:"ListPage", + controller:this.controller, + contentView:()=>{ + this.contentView() + }, + + onRefresh:()=>{ + this.pageNumber = 1; + this.getFlowetListData(); + setTimeout(() => { + this.controller.refreshSuccess() + }, 1000) + }, + onCanPullRefresh:()=>{ + if (!this.scroller.currentOffset()) { + /*处理无数据,为空的情况*/ + return true + } + //如果列表到顶,返回true,表示可以下拉,返回false,表示无法下拉 + return this.scroller.currentOffset().yOffset <= 0 + }, + onLoad:()=>{ + this.pageNumber++; + this.getFlowetListData(); + setTimeout(() => { + this.controller.loadSuccess() + }, 1000) + + }, + onCanPullLoad: () => { + if (this.pageNumber >= this.totalPageNumer) { + return false; + } else { + return true; + } + } + }).width('100%').layoutWeight(1).clip(true) + } + } + .height('100%') + .width('100%') + .backgroundColor('#f1f1f1') + } + + @Builder + contentView() { + List({scroller:this.scroller}) { + ListItemGroup({header:this.headerView()}) { + ForEach(this.flowerList,(item:flowerListData)=>{ + ListItem() { + Row() { + Text(item.patient_name) + .fontColor(Color.Gray) + .width(130) + Blank() + .layoutWeight(1) + Text(item.create_date.substring(0,10)) + .fontColor(Color.Gray) + .width(180) + Blank() + .layoutWeight(1) + Text(item.num.toString()) + .textAlign(TextAlign.Center) + .fontColor(Color.Gray) + .width(40) + } + .padding(10) + .width('100%') + .height(50) + .backgroundColor(Color.White) + } + }) + } + } + .width('100%') + .height('100%') + } + + @Builder + headerView() { + Column() { + Row() { + Row() { + Image($r('app.media.flower_expertFlower_icon')) + .size({ width: 20, height: 20 }) + Text(this.allFlower) + .fontColor($r('app.color.main_color')) + .margin({ left: 10 }) + } + + Row() { + Image($r('app.media.flower_accountJinbi_icon')) + .size({ width: 20, height: 20 }) + Text(this.allTotalNum) + .fontColor($r('app.color.main_color')) + .margin({ left: 10 }) + } + .margin({ left: 50 }) + } + .padding(10) + .width('100%') + .height(45) + .backgroundColor(Color.White) + + Row(){ + Text('姓名') + .fontColor(Color.White) + Blank() + .layoutWeight(1) + Text('时间') + .fontColor(Color.White) + Blank() + .layoutWeight(1) + Text('数量') + .fontColor(Color.White) + } + .padding(10) + .width('100%') + .height(45) + .backgroundColor($r('app.color.main_color')) + } + .width('100%') + .height(90) + } +} + +export interface flowerRequest { + 'code':number + 'message':string + 'data':flowerData +} + +export interface flowerData { + 'flower_data':flower_data, + 'total_num':number + 'total_amount':number +} + +export interface flower_data { + 'isFirstPage':number + 'isLastPage':number + 'pageNum':number + 'pages':number + 'pageSize':number + 'total':number + 'list':flowerListData[] +} + +export interface flowerListData { + 'patiet_photo':string + 'expert_photo':string + 'expert_name':string + 'patient_name':string + 'patient_uuid':string + 'expert_uuid':string + 'num':number + 'create_date':string + 'trade_no':string + 'order_status':string + 'amount':number + 'message':string + 'id':string +} \ No newline at end of file diff --git a/features/study/src/main/ets/components/KeepStudyComp.ets b/features/study/src/main/ets/components/KeepStudyComp.ets index 9ca7a6d..060a735 100644 --- a/features/study/src/main/ets/components/KeepStudyComp.ets +++ b/features/study/src/main/ets/components/KeepStudyComp.ets @@ -79,6 +79,6 @@ export struct KeepStudyComp { } .width('100%') .height('100%') - .backgroundColor('#F1F3F5') + .backgroundColor('#f1f1f1') } } diff --git a/features/study/src/main/ets/components/MainPage.ets b/features/study/src/main/ets/components/MainPage.ets new file mode 100644 index 0000000..9de5eb3 --- /dev/null +++ b/features/study/src/main/ets/components/MainPage.ets @@ -0,0 +1,19 @@ +@Component +export struct MainPage { + @State message: string = 'Hello World'; + + build() { + Row() { + Column() { + Text(this.message) + .fontSize($r('app.float.page_text_font_size')) + .fontWeight(FontWeight.Bold) + .onClick(() => { + this.message = 'Welcome'; + }) + } + .width('100%') + } + .height('100%') + } +} diff --git a/features/study/src/main/ets/components/NewsComp.ets b/features/study/src/main/ets/components/NewsComp.ets new file mode 100644 index 0000000..fae24e2 --- /dev/null +++ b/features/study/src/main/ets/components/NewsComp.ets @@ -0,0 +1,85 @@ +import { AppUtil, HdNav } from "@itcast/basic" +import { NewsSwiperView } from "../views/NewsSwiperView" +import { router } from "@kit.ArkUI" + +@Component +export struct NewsComp { + build() { + Column() { + HdNav({title:'肝胆新闻',showRightIcon:false,showRightText:false}) + NewsSwiperView().height(AppUtil.getDisplayWindowWidth().vp / 16 * 9) + + Row(){ + Image($r('app.media.news_new_icon')) + .width(50) + .height(50) + .margin({left:10}) + .objectFit(ImageFit.Fill) + Column(){ + Text('肝胆新闻') + .fontSize(16) + Text('新鲜资讯,一触即达') + .fontSize(14) + .margin({top:5}) + .fontColor($r('app.color.common_gray_02')) + } + .alignItems(HorizontalAlign.Start) + .margin({left:10,right:10}) + .layoutWeight(1) + + Image($r('app.media.arrow_right')) + .width(12) + .height(15) + .margin({right:10}) + } + .width('95%') + .height(90) + .borderRadius(3) + .backgroundColor(Color.White) + .margin({left:10,top:10,right:10}) + .onClick(()=>{ + router.pushUrl({ + url:'pages/News/GandanNewsListPage', + }) + }) + + Row(){ + Image($r('app.media.news_meeting_icon')) + .width(50) + .height(50) + .margin({left:10}) + .objectFit(ImageFit.Fill) + Column(){ + Text('肝胆会议') + .fontSize(16) + Text('了解会议信息的最佳入口') + .fontSize(14) + .margin({top:5}) + .fontColor($r('app.color.common_gray_02')) + } + .alignItems(HorizontalAlign.Start) + .margin({left:10,right:10}) + .layoutWeight(1) + .onClick(()=>{ + router.pushUrl({ + url:'pages/Meeting/MeetingPage', + params:{"isLeft":"需要"} + }) + }) + + Image($r('app.media.arrow_right')) + .width(12) + .height(15) + .margin({right:10}) + } + .width('95%') + .height(90) + .borderRadius(3) + .backgroundColor(Color.White) + .margin({left:10,top:10,right:10}) + } + .backgroundColor('#f1f1f1') + .width('100%') + .height('100%') + } +} diff --git a/features/study/src/main/ets/components/NewsListComp.ets b/features/study/src/main/ets/components/NewsListComp.ets new file mode 100644 index 0000000..6035709 --- /dev/null +++ b/features/study/src/main/ets/components/NewsListComp.ets @@ -0,0 +1,188 @@ +import { AppUtil, BasicConstant, + EmptyViewComp, + hdHttp, HdLoadingDialog, HdNav, HdResponse, logger } from "@itcast/basic" +import { NewsSwiperView } from "../views/NewsSwiperView" +import { promptAction, router } from "@kit.ArkUI" +import { HashMap } from "@kit.ArkTS"; +import { + newsListRequest, + newsRequestOfData, newsRollNewRequest, newsTagRequest, newsTagsRequestData } from "../models/NewsModel"; +import { BusinessError } from "@kit.BasicServicesKit"; +import { PullToRefreshLayout, RefreshController } from "refreshlib"; +import { NewsItemView } from "../views/NewsItemView"; + +@Component +export struct NewsListComp { + @State tagsList:newsTagsRequestData[] = [] + @State newsList:newsRequestOfData[] = [] + @State isEmptyViewVisible: boolean = false; // 控制显隐的状态变量 + public controller:RefreshController = new RefreshController(); + scroller = new Scroller(); + @State pageNumber:number = 1; + @State totalPageNumer:number = 1; + @State selectedTagId:string = ''; + + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + aboutToAppear(): void { + this.getHeaderTags() + this.getNewsListData(true) + } + + getHeaderTags() { + const entity = {} as Record + this.dialog.open() + hdHttp.post(BasicConstant.newsTagList, entity).then(async (res: HdResponse) => { + logger.info('Response newsTagList'+res); + let json:newsTagRequest = JSON.parse(res+'') as newsTagRequest; + this.dialog.close(); + this.tagsList = json.data + }).catch((err: BusinessError) => { + this.dialog.close(); + }) + } + + getNewsListData(isDefault:boolean) { + const hashMap: HashMap = new HashMap(); + this.dialog.open() + hashMap.clear(); + hashMap.set('page',this.pageNumber.toString()) + if (!isDefault) + hashMap.set('newstagid', this.selectedTagId)//点击标签的ID + hdHttp.httpReq(isDefault?BasicConstant.defaultNewsListNew:BasicConstant.newsListNew,hashMap).then(async (res: HdResponse) => { + logger.info('Response newsListNew/defaultNewsListNew'+res); + this.dialog.close(); + let json:newsListRequest = JSON.parse(res+'') as newsListRequest; + if(json.code == '1') { + if(this.pageNumber==1) { + this.newsList = [] + if(json.data!=null) { + this.newsList = json.data; + } + } else if(this.pageNumber>1) { + this.newsList.push(...json.data) + } + this.totalPageNumer =json.totalPage; + if (this.newsList.length > 0) { + this.isEmptyViewVisible = false; + } else { + this.isEmptyViewVisible = true; + } + } else { + promptAction.showToast({ message: json.message, duration: 1000 }) + } + this.isEmptyViewVisible = !this.newsList || this.newsList.length === 0 + }).catch((err: BusinessError) => { + this.dialog.close(); + }) + } + + build() { + Column() { + HdNav({ title: '肝胆新闻',showRightIcon: true,rightIcon:$r('app.media.selected_hospital_ws') ,showRightText:false, + rightItemAction:()=>{ + router.pushUrl({ + url:'pages/SearchPage/VideoSearchPage', + params:{'pageName':'视频'} + }) + }}) + + //标签 + if (this.tagsList && this.tagsList.length > 0) { + Scroll() { + Row() { + ForEach(this.tagsList, (tag:newsTagsRequestData) => { + Text(tag.NAME) + .padding({ left: 12, right: 12, top: 6, bottom: 6 }) + .margin({ left: 6, right: 6, top: 10, bottom: 10 }) + .fontSize(16) + .fontColor(this.selectedTagId == tag.ID?$r('app.color.main_color'):Color.Black) + .borderRadius(16) + .onClick(() => { + if (this.selectedTagId !== tag.ID) { + this.selectedTagId = tag.ID + this.pageNumber = 1 + this.getNewsListData(false) + } + }) + }) + } + } + .scrollable(ScrollDirection.Horizontal) + .width('100%') + .height(48) + .scrollBar(BarState.Off) + .backgroundColor('#ffffff') + } + + //轮播 + NewsSwiperView().height(AppUtil.getDisplayWindowWidth().vp / 16 * 9) + + //列表 + if (this.isEmptyViewVisible){ + EmptyViewComp({promptText:'暂无肝胆资讯',isVisibility:this.isEmptyViewVisible}).layoutWeight(1) + } else { + PullToRefreshLayout({ + scroller:this.scroller, + viewKey:"ListPage", + controller:this.controller, + contentView:()=>{ + this.contentView() + }, + + onRefresh:()=>{ + this.pageNumber = 1; + this.getNewsListData(this.selectedTagId==='');//标签点击的第一个为true,后面是false + setTimeout(() => { + this.controller.refreshSuccess() + }, 1000) + }, + onCanPullRefresh:()=>{ + if (!this.scroller.currentOffset()) { + /*处理无数据,为空的情况*/ + return true + } + //如果列表到顶,返回true,表示可以下拉,返回false,表示无法下拉 + return this.scroller.currentOffset().yOffset <= 0 + }, + onLoad:()=>{ + this.pageNumber++; + this.getNewsListData(this.selectedTagId==='');//标签点击的第一个为true,后面是false + setTimeout(() => { + this.controller.loadSuccess() + }, 1000) + + }, + onCanPullLoad: () => { + if (this.pageNumber >= this.totalPageNumer) { + return false; + } else { + return true; + } + } + }).width('100%').layoutWeight(1).clip(true) + } + } + .backgroundColor('#f1f1f1') + .width('100%') + .height('100%') + } + + @Builder + contentView(){ + List({ scroller: this.scroller }) { + ForEach(this.newsList, (item: newsRequestOfData, index) => { + ListItem() { + NewsItemView({item:item}) + } + }) + } + .width('100%') + .height('100%') + .edgeEffect(EdgeEffect.None) + } +} diff --git a/features/study/src/main/ets/components/PayComp.ets b/features/study/src/main/ets/components/PayComp.ets new file mode 100644 index 0000000..1432e61 --- /dev/null +++ b/features/study/src/main/ets/components/PayComp.ets @@ -0,0 +1,323 @@ +import { BasicConstant, ChangeUtil, + DefaultHintProWindows, + hdHttp, HdLoadingDialog, HdNav, HdResponse, + OnWXResp, + WXApi, + WXEventHandler} from "@itcast/basic"; +import { promptAction, router } from "@kit.ArkUI"; +import { BusinessError, emitter } from "@kit.BasicServicesKit"; +import { HashMap } from "@kit.ArkTS"; +import * as wxopensdk from '@tencent/wechat_open_sdk'; +import { common } from "@kit.AbilityKit"; + +@Component +export struct PayComp { + @State params:Record | FileOrderData> = router.getParams() as Record | FileOrderData> + @State payType:number = 0//0没有选择支付;1;选择余额支付;2:选择微信支付 + @State balanceEnough: boolean = false + @State balanceMoney: string = '' + @State name:string = '' + @State hintMessage:string = '' + @State pwd:string = '' + + @State kejianData:FileOrderData = {} as FileOrderData + @State songhuaData:Record> = {} + + private wxApi = WXApi + private wxEventHandler = WXEventHandler + + private onWXResp: OnWXResp = (resp) => { + console.info('wxResp:'+JSON.stringify(resp ?? {}, null, 2)) + if (resp.errCode == 0) { + this.notificationRequest() + } else if (resp.errCode == -2) { + this.hintMessage = '支付取消' + this.alertView.open() + } + } + + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + alertView:CustomDialogController = new CustomDialogController({ + builder:DefaultHintProWindows({ + title:'提示', + message:this.hintMessage, + cancleTitle: '', + confirmTitleColor: '#666666', + selectedButton: (index:number)=>{ + this.alertView.close(); + if (this.hintMessage == '支付成功' || '您已经成功送给肝胆相照送出心意') { + let innerEvent: emitter.InnerEvent = { + eventId: BasicConstant.notification_kejian_pay_success + }; + let eventData: emitter.EventData = { + data:{"status":'success'} + }; + emitter.emit(innerEvent, eventData); + router.back() + } + } + }), + alignment: DialogAlignment.Center, + cornerRadius:24, + backgroundColor: ('rgba(0,0,0,0.5)'), + }) + + inputAlertView:CustomDialogController = new CustomDialogController({ + builder:DefaultHintProWindows({ + title:'提示', + message:'', + cancleTitleColor: '#333333', + confirmTitleColor: $r('app.color.main_color'), + selectedButtonAndContent:(index:number,content:string)=>{ + if (index == 0) { + this.inputAlertView.close() + } else { + if (!ChangeUtil.stringIsUndefinedAndNull(content)) { + this.pwd = content + this.inputAlertView.close() + this.payOrderRequest() + } + } + } + }), + alignment: DialogAlignment.Center, + cornerRadius:24, + backgroundColor: ('rgba(0,0,0,0.5)'), + }) + + aboutToDisappear(): void { + this.wxEventHandler.unregisterOnWXRespCallback(this.onWXResp) + } + + aboutToAppear(): void { + if (this.params.page == '送花') { + this.name = '肝胆相照' + this.songhuaData = this.params.data as Record> + } else if (this.params.page == '课件详情') { + this.kejianData = this.params.data as FileOrderData + this.name = this.kejianData.provider_name + } + this.getAccountData() + this.wxEventHandler.registerOnWXRespCallback(this.onWXResp) + } + + build() { + Column() { + HdNav({title:'在线支付',showRightIcon:false,showRightText:false}) + + Column() { + Row() { + Row() { + Text(this.params.page == '课件详情'?`下载${this.name}医生的`:`给${this.name}`) + .fontSize(16) + + Text(this.params.page == '课件详情'?'课件':'送心意') + .borderRadius(8) + .fontColor(Color.White) + .margin({ left: 20 }) + .size({ width: 50, height: 30 }) + .textAlign(TextAlign.Center) + .backgroundColor($r('app.color.main_color')) + } + .layoutWeight(1) + + Text(this.params.page == '课件详情'?ChangeUtil.formatPrice(this.kejianData.amount).toString():ChangeUtil.formatPrice(String(this.songhuaData.amount)).toString()+' 元') + .fontColor(Color.Red) + .width('40%') + .textAlign(TextAlign.End) + } + .padding(10) + .width('100%') + .backgroundColor(Color.White) + + Text('请通过以下方式支付') + .width('100%') + .padding(10) + + Row() { + Row() { + Image($r('app.media.pay_account_icon')) + .size({ width: 35, height: 35 }) + Text('余额支付') + .fontSize(16) + .margin({ left: 10 }) + Text(` ¥ ${ChangeUtil.formatPrice(this.balanceMoney)}`) + .fontSize(16) + } + .layoutWeight(1) + + Row() { + if (!this.balanceEnough) { + Text('余额不足') + .fontSize(16) + .fontColor(Color.Red) + .margin({ right: 20 }) + } + Image(this.payType == 1 ? $r('app.media.patiemts_list_selected') : $r('app.media.huise_kongquan')) + .width(15) + .height(15) + .enabled(this.balanceEnough)// 余额不足时禁用 + } + .width('40%') + .justifyContent(FlexAlign.End) + .onClick(() => { + if (this.balanceEnough) { + this.payType = 1 + } + }) + } + .width('100%') + .padding(10) + .backgroundColor(Color.White) + + Text('选择付款方式') + .width('100%') + .padding(10) + Row() { + Image($r('app.media.pay_wx_icon')) + .size({ width: 35, height: 35 }) + Text('微信支付') + .fontSize(16) + .margin({ left: 10 }) + .layoutWeight(1) + Image(this.payType == 2 ? $r('app.media.patiemts_list_selected') : $r('app.media.huise_kongquan')) + .width(15) + .height(15) + } + .width('100%') + .padding(10) + .backgroundColor(Color.White) + .onClick(() => { + this.payType = 2 + }) + } + .width('100%') + .layoutWeight(1) + + Button('立即支付') + .width('90%') + .height(40) + .fontColor(Color.White) + .backgroundColor($r('app.color.main_color')) + .margin({left:20,bottom:50,right:20}) + .onClick(() => { + if (this.payType == 0) { + this.hintMessage = '请选择支付方式' + this.alertView.open() + return + } else if (this.payType == 1) { + this.inputAlertView.open() + return + } + this.payOrderRequest() + }) + } + .backgroundColor('#f4f4f4') + .width('100%') + .height('100%') + } + + getAccountData() { + const hashMap: HashMap = new HashMap() + this.dialog.open() + hashMap.clear() + hdHttp.httpReq(BasicConstant.getBalance,hashMap).then(async (res: HdResponse) => { + console.info('Response getBalance'+res) + this.dialog.close() + let json:Record = JSON.parse(res+'') as Record; + if(json.code == '200') { + this.balanceMoney = json.data + let amount = this.params.page == '课件详情'?ChangeUtil.formatPrice(this.kejianData.amount):ChangeUtil.formatPrice(String(this.songhuaData.amount)) + if (ChangeUtil.formatPrice(this.balanceMoney)> amount) { + this.balanceEnough = true + } + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close() + console.error(`Response fails: ${err}`); + }) + } + + payOrderRequest() { + const hashMap: HashMap = new HashMap() + this.dialog.open() + let trade_no = this.params.page == '课件详情'?this.kejianData.trade_no:String(this.songhuaData.trade_no) + hashMap.clear() + hashMap.set('channel', this.payType == 1?'balance':'wx') + hashMap.set('trade_no',trade_no) + hashMap.set('pwd',this.pwd) + hdHttp.httpReq(this.params.page == '课件详情'?BasicConstant.payGanDanFileOrder:BasicConstant.payXinYiOrder,hashMap).then(async (res: HdResponse) => { + console.info('Response payGanDanFileOrder'+res) + this.dialog.close() + let json:Record> = JSON.parse(res+'') as Record>; + if(json.code == '200') { + if (json.data != undefined) { + let req = new wxopensdk.PayReq + req.partnerId = json.data['partnerid'] + req.appId = json.data['appid'] + req.packageValue = json.data['package_str'] + req.prepayId = json.data['prepayid'] + req.nonceStr = json.data['noncestr'] + req.timeStamp = json.data['timestamp'] + req.sign = json.data['sign'] + req.extData = 'extData' + + let finished = await this.wxApi.sendReq(getContext(this) as common.UIAbilityContext, req) + console.info("send request finished: ", finished) + } else { + if (this.payType == 1) { + this.hintMessage = this.params.page == '课件详情'?'支付成功':'您已经成功送给肝胆相照送出心意' + this.alertView.open() + } + } + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close() + console.error(`Response fails: ${err}`); + }) + } + + notificationRequest() { + const hashMap: HashMap = new HashMap() + let trade_no = this.params.page == '课件详情'?this.kejianData.trade_no:String(this.songhuaData.trade_no) + this.dialog.open() + hashMap.clear() + hashMap.set('trade_no',trade_no) + hdHttp.httpReq(BasicConstant.getOrderStatus,hashMap).then(async (res: HdResponse) => { + console.info('Response getOrderStatus'+res) + this.dialog.close() + let json:Record> = JSON.parse(res+'') as Record>; + if(json.code == '200') { + if (this.payType == 2) { + let tradeState = json.data['tradeState'] as string + if (tradeState == 'SUCCESS') { + this.hintMessage = this.params.page == '课件详情'?'支付成功':'您已经成功送给肝胆相照送出心意' + this.alertView.open() + } + } + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close() + console.error(`Response fails: ${err}`); + }) + } +} + +interface FileOrderData { + trade_no:string + order_id:string + amount:string + account:string + provider_name:string +} \ No newline at end of file diff --git a/features/study/src/main/ets/components/SchoolhouseComp.ets b/features/study/src/main/ets/components/SchoolhouseComp.ets index ec81301..fb7ad1f 100644 --- a/features/study/src/main/ets/components/SchoolhouseComp.ets +++ b/features/study/src/main/ets/components/SchoolhouseComp.ets @@ -258,7 +258,6 @@ export struct SchoolhouseComp { ForEach(this.data, (item: PatientTBean, index) => { ListItem() { ItemCompTeach({item:item}) - .onClick(()=>{this.pushDetailsView(item)}) } }) } @@ -266,25 +265,4 @@ export struct SchoolhouseComp { .height('100%') .edgeEffect(EdgeEffect.None) } - - private pushDetailsView(item: PatientTBean) { - const entity = { - "news_article_uuid":item.uuid, - "user_uuid": authStore.getUser().uuid, - "type":'2' - } as Record - this.dialog.open() - hdHttp.post(BasicConstant.read, entity).then(async (res: HdResponse) => { - this.dialog.close(); - console.info('Response delConditionRecord'+res); - let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; - if(json.code == '1') { - router.pushUrl({url:"pages/WebView/EducationDetailsWebPage",params:{"model":item}}) - } - }).catch((err: BusinessError) => { - this.dialog.close(); - console.error(`Response fails: ${err}`); - promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) - }) - } } diff --git a/features/study/src/main/ets/components/SendFollowComp.ets b/features/study/src/main/ets/components/SendFollowComp.ets new file mode 100644 index 0000000..dcc9e41 --- /dev/null +++ b/features/study/src/main/ets/components/SendFollowComp.ets @@ -0,0 +1,343 @@ +import { BasicConstant, ChangeUtil, + DefaultHintProWindows, + hdHttp, HdLoadingDialog, HdNav, HdResponse } from "@itcast/basic"; +import { PullToRefreshLayout, RefreshController } from "refreshlib"; +import { HashMap } from "@kit.ArkTS"; +import { xinyiListData, xinyiRequest } from "../models/XinYiModel"; +import { promptAction, router } from "@kit.ArkUI"; +import { BusinessError, emitter } from "@kit.BasicServicesKit"; + +@Component +export struct SendFollowComp { + public controller:RefreshController = new RefreshController(); + scroller = new Scroller(); + @State pageNumber:number = 1; + @State totalPageNumer:number = 1; + @State xinyiList:xinyiListData[] = [] + @State xinyiPrice:string = '' + @State sendPrice:string = '' + @State selectedAmount:number = 5 + @State message:string = '祝肝胆相照平台越来越好!' + moneyOptions:number[] = [1,2,5,10,50] + + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + alertView:CustomDialogController = new CustomDialogController({ + builder:DefaultHintProWindows({ + title:'提示', + message:'您确定是否送出', + cancleTitle:'否', + confirmTitle:'是', + cancleTitleColor: '#666666', + confirmTitleColor: $r('app.color.main_color'), + selectedButton: (index:number)=>{ + this.alertView.close(); + if (index == 1) { + this.createXinYiOrder() + } + } + }), + alignment: DialogAlignment.Center, + cornerRadius:24, + backgroundColor: ('rgba(0,0,0,0.5)'), + }) + + private refreshDataCallback = (eventData?: emitter.EventData): void => { + if (Object(eventData?.data)['status'] == 'success') { + this.pageNumber = 1; + this.getXinYiListData() + } + }; + + aboutToAppear(): void { + this.getXinyiPriceData() + this.getXinYiListData() + let innerEvent: emitter.InnerEvent = { + eventId: BasicConstant.notification_kejian_pay_success + } + emitter.on(innerEvent, this.refreshDataCallback) + } + + aboutToDisappear(): void { + emitter.off(BasicConstant.notification_kejian_pay_success, this.refreshDataCallback) + } + + getXinYiListData() { + const hashMap: HashMap = new HashMap(); + hashMap.set('page',this.pageNumber.toString()); + this.dialog.open() + hdHttp.httpReq(BasicConstant.allXinyiList,hashMap).then(async (res: HdResponse) => { + this.dialog.close(); + let json:xinyiRequest = JSON.parse(res+'') as xinyiRequest; + if(json.code == '200') { + if(this.pageNumber==1) { + this.xinyiList=[] + if(json.data!=null) { + this.xinyiList = json.data.list; + } + } else if(this.pageNumber>1) { + this.xinyiList.push(...json.data.list) + } + this.totalPageNumer = json.data.total; + } else { + promptAction.showToast({ message: json.message, duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + this.controller.refreshError(); + console.info(`Response fails: ${err}`); + }) + } + + getXinyiPriceData() { + const hashMap: HashMap = new HashMap(); + this.dialog.open() + hdHttp.httpReq(BasicConstant.xinyiPrice,hashMap).then(async (res: HdResponse) => { + this.dialog.close(); + let json:Record = JSON.parse(res+'') as Record; + if(json.code == '200') { + this.xinyiPrice = String(json.data) + this.sendPrice = ChangeUtil.formatPrice2(this.xinyiPrice,'5') + } + }).catch((err: BusinessError) => { + this.dialog.close(); + this.controller.refreshError(); + console.info(`Response fails: ${err}`); + }) + } + + createXinYiOrder() { + const hashMap: HashMap = new HashMap(); + this.dialog.open() + hashMap.set('message',ChangeUtil.stringIsUndefinedAndNull(this.message)?'祝肝胆相照平台越来越好!':this.message) + hashMap.set('amount',this.selectedAmount.toString()) + hdHttp.httpReq(BasicConstant.createXinYiOrder,hashMap).then(async (res: HdResponse) => { + this.dialog.close(); + let json:Record> = JSON.parse(res+'') as Record> + if(json.code == '200') { + router.pushUrl({ + url:"pages/Pay/PayPage", + params:{"data":json.data,"page":"送花"} + }) + } else { + promptAction.showToast({message:'服务器异常',duration:1000}) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + this.controller.refreshError(); + console.info(`Response fails: ${err}`); + }) + } + + build() { + Row() { + Column() { + HdNav({title:'表达暖暖心意',showRightIcon:false,showRightText:false}) + + PullToRefreshLayout({ + scroller:this.scroller, + viewKey:"ListPage", + controller:this.controller, + contentView:()=>{ + this.contentView() + }, + + onRefresh:()=>{ + this.pageNumber = 1; + setTimeout(() => { + this.controller.refreshSuccess() + }, 1000) + }, + onCanPullRefresh:()=>{ + if (!this.scroller.currentOffset()) { + /*处理无数据,为空的情况*/ + return true + } + //如果列表到顶,返回true,表示可以下拉,返回false,表示无法下拉 + return this.scroller.currentOffset().yOffset <= 0 + }, + onLoad:()=>{ + this.pageNumber++; + this.getXinYiListData(); + setTimeout(() => { + this.controller.loadSuccess() + }, 1000) + }, + onCanPullLoad: () => { + if (this.pageNumber >= this.totalPageNumer) { + return false; + } else { + return true; + } + } + }).width('100%').layoutWeight(1).clip(true) + } + .width('100%') + } + .height('100%') + } + + @Builder + contentView() { + Column() { + List({scroller:this.scroller}) { + ListItemGroup({header:this.headerView()}) { + ForEach(this.xinyiList, (item: xinyiListData, index: number) => { + ListItem() { + Column() { + Row() { + Image(BasicConstant.urlImage + item.user_photo) + .alt($r('app.media.userPhoto_default')) + .width(50) + .height(50) + .borderRadius(5) + + Column() { + Text(ChangeUtil.stringIsUndefinedAndNull(item.user_name) ? '账号已注销' : item.user_name) + .fontColor($r('app.color.main_color')) + .fontSize(16) + Text(item.message) + .fontSize(14) + .fontColor(Color.Grey) + } + .width('60%') + .alignItems(HorizontalAlign.Start) + .justifyContent(FlexAlign.Start) + .margin({left:10}) + + Text(item.create_date.length > 10 ? item.create_date.substring(0,10) : item.create_date) + .fontSize(12) + .textAlign(TextAlign.End) + .margin({top:10}) + } + .width('100%') + + Blank() + .height(1) + .width('100%') + .margin({top:10}) + .backgroundColor('rgb(227,227,227)') + } + .width('100%') + .padding(10) + } + }, (item: xinyiListData) => item.create_date + item.user_name) + } + } + .width('100%') + .layoutWeight(1) + } + } + + @Builder + headerView() { + Column() { + Blank() + .backgroundColor('rgb(227,228,229)') + .width('100%') + .height(10) + Image($r('app.media.patientLogo')) + .size({width:40,height:40}) + .margin({top:10}) + Text('肝胆相照') + .fontSize(16) + .margin({top:10}) + .fontColor($r('app.color.main_color')) + Text('您的心意将用于肝胆相照平台的持续发展,有了您的支持,肝胆相照会越来越好,同时将给大家带来更多、更好的服务。') + .fontSize(11) + .fontColor('rgb(102,102,102)') + .margin({ left: 8, right: 8, top: 10 }) + + Blank() + .backgroundColor('rgb(227,227,227)') + .width('100%') + .height(1) + .margin({top:10}) + + Image($r("app.media.send_header_follow_icon")) + .size({width:75,height:75}) + .margin({top:25}) + + Text(`¥ ${this.sendPrice}元`) + .fontSize(14) + .textAlign(TextAlign.Center) + .fontColor(Color.Red) + .margin({ top: 20 }) + + // 金额选项 + Row() { + ForEach(this.moneyOptions, (money:number) => { + Text(`${money}`) + .backgroundColor(this.selectedAmount === money ? $r('app.color.main_color') : Color.White) + .fontColor(this.selectedAmount === money ? Color.White : $r('app.color.main_color')) + .fontSize(16) + .border({ width: 1, color: $r('app.color.main_color') }) + .width(30) + .height(30) + .borderRadius(15) + .textAlign(TextAlign.Center) + .margin({ left: 10, right: 10, top: 12 }) + .onClick(() => { + this.selectedAmount = money + this.sendPrice = ChangeUtil.formatPrice2(this.xinyiPrice,String(money)) + }) + }) + } + .justifyContent(FlexAlign.Center) + .width('100%') + } + .width('100%') + + // 留言输入 + TextInput({ text: this.message, placeholder: '请输入您的祝福' }) + .onChange((val:string) => this.message = val) + .margin({ left: 10, right: 10, top: 15 }) + .height(55) + .borderRadius(8) + .fontSize(12) + .maxLength(100) + .backgroundColor('rgb(227,227,227)') + .onChange((value:string)=>{ + this.message = value + }) + + // 送出按钮 + Text('送出') + .fontSize(16) + .backgroundColor($r('app.color.main_color')) + .fontColor(Color.White) + .margin({ top: 10 }) + .height(40) + .textAlign(TextAlign.Center) + .width('100%') + .onClick(() => { + this.alertView.open() + }) + + Blank() + .width('100%') + .height(10) + .backgroundColor('rgb(227,228,229)') + + // 心意墙标题 + Row() { + Image($r('app.media.send_follow_list_icon')) + .size({width:25,height:25}) + Text('肝胆相照的心意墙') + .fontSize(18) + .fontColor($r('app.color.main_color')) + .margin({ left: 10 }) + } + .width('100%') + .padding(10) + + Blank() + .backgroundColor('rgb(227,228,229)') + .width('100%') + .height(1) + } +} diff --git a/features/study/src/main/ets/models/NewsModel.ets b/features/study/src/main/ets/models/NewsModel.ets new file mode 100644 index 0000000..45404e6 --- /dev/null +++ b/features/study/src/main/ets/models/NewsModel.ets @@ -0,0 +1,49 @@ +export interface newsRollNewRequest { + "code":string + "data":newsRequestOfData[] + "message":string +} + +export interface newsRequestOfData { + "path":string + "title":string + "imgs":string + "imgpath":string + "author":string + "headImg":string + "name":string + "uuid":string + "projectName":string + "content":string + "projectType":string + "createDateStr":string + "createDate":string + "create_date":string + "contentText":string + "endDate":string + "summary":string + "readnum":string + "agreenum":string + "public_name":string + "HEAD_IMG":string + "TITLE":string + "editType":string +} + +export interface newsTagRequest { + 'code':string + 'data':newsTagsRequestData[] +} + +export interface newsTagsRequestData { + "NAME":string + "ID":string +} + +export interface newsListRequest { + 'code':string + 'data':newsRequestOfData[] + 'message':string + 'totalPage':number +} + diff --git a/features/study/src/main/ets/models/XinYiModel.ets b/features/study/src/main/ets/models/XinYiModel.ets new file mode 100644 index 0000000..a104928 --- /dev/null +++ b/features/study/src/main/ets/models/XinYiModel.ets @@ -0,0 +1,17 @@ +export interface xinyiRequest { + 'code':string + 'message':string + 'data':xinyiRequestOfData +} + +export interface xinyiRequestOfData { + 'total':number + 'list':xinyiListData[] +} + +export interface xinyiListData { + 'user_photo':string + 'user_name':string + 'message':string + 'create_date':string +} \ No newline at end of file diff --git a/features/study/src/main/ets/utils/NewsUtil.ets b/features/study/src/main/ets/utils/NewsUtil.ets new file mode 100644 index 0000000..7c21320 --- /dev/null +++ b/features/study/src/main/ets/utils/NewsUtil.ets @@ -0,0 +1,33 @@ +import { BasicConstant,authStore } from '@itcast/basic' +import HashMap from '@ohos.util.HashMap'; +import { hdHttp, HdResponse} from '@itcast/basic/Index' +import { BusinessError } from '@kit.BasicServicesKit' +import { newsRequestOfData } from '../models/NewsModel'; +import { router } from '@kit.ArkUI'; + +class NewsUtil { + hashMap: HashMap = new HashMap(); + readNews(uuid:string,model:newsRequestOfData) { + hdHttp.post(BasicConstant.read, { + user_uuid: authStore.getUser().uuid, + news_article_uuid:uuid, + type: '1', + } as readExtraData).then(async (res: HdResponse) => { + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + router.pushUrl({url:"pages/WebView/NewsDetailsWebPage",params:{"model":model}}) + } + }).catch((err: BusinessError) => { + console.error(`Response fails: ${err}`); + }) + } +} + +interface readExtraData{ + user_uuid:string, + news_article_uuid:string, + type:string, +} + +export const newsUtil = new NewsUtil() \ No newline at end of file diff --git a/features/study/src/main/ets/views/ItemCompTeach.ets b/features/study/src/main/ets/views/ItemCompTeach.ets index bc8a891..769c208 100644 --- a/features/study/src/main/ets/views/ItemCompTeach.ets +++ b/features/study/src/main/ets/views/ItemCompTeach.ets @@ -1,5 +1,7 @@ -import { BasicConstant, TimestampUtil } from '@itcast/basic'; +import { authStore, BasicConstant, hdHttp, HdLoadingDialog, HdResponse, TimestampUtil } from '@itcast/basic'; import { PatientTBean } from '@itcast/basic/src/main/ets/models/TeachModel'; +import { promptAction, router } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; @Preview @@ -7,9 +9,12 @@ import { PatientTBean } from '@itcast/basic/src/main/ets/models/TeachModel'; export struct ItemCompTeach { @Prop item:PatientTBean; - aboutToAppear(): void { + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) - } build() { Column() { Row() { @@ -58,11 +63,32 @@ export struct ItemCompTeach { .width('100%') .padding(10) .onClick(() => { - + this.pushDetailsView(this.item) }) Text().backgroundColor($r('app.color.efefef')).width('100%').height(1) } .backgroundColor(Color.White) } + + private pushDetailsView(item: PatientTBean) { + const entity = { + "news_article_uuid":item.uuid, + "user_uuid": authStore.getUser().uuid, + "type":'2' + } as Record + this.dialog.open() + hdHttp.post(BasicConstant.read, entity).then(async (res: HdResponse) => { + this.dialog.close(); + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + router.pushUrl({url:"pages/WebView/EducationDetailsWebPage",params:{"model":item,"isAgree":json.isAgree}}) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) + }) + } } diff --git a/features/study/src/main/ets/views/KeJianItemComp.ets b/features/study/src/main/ets/views/KeJianItemComp.ets index ab36506..9c0f695 100644 --- a/features/study/src/main/ets/views/KeJianItemComp.ets +++ b/features/study/src/main/ets/views/KeJianItemComp.ets @@ -55,7 +55,7 @@ export struct KeJianItemComp { .margin({ left: 2 }) .fontSize(13) .fontColor(Color.Red) - Text(this.formatPrice(this.item.price)) + Text(ChangeUtil.formatPrice(this.item.price)) .fontColor(Color.Red) .fontSize(16) } @@ -79,14 +79,14 @@ export struct KeJianItemComp { .margin({ left: 2 }) .fontSize(13) .fontColor(Color.Red) - Text(this.formatPrice2(this.item.price, this.item.discount)) + Text(ChangeUtil.formatPrice2(this.item.price, this.item.discount)) .fontColor(Color.Red) .fontSize(16) Text('原价') .margin({ left: 10 }) .fontSize(12) .fontColor('#999999') - Text('¥'+this.formatPrice(this.item.price)) + Text('¥'+ChangeUtil.formatPrice(this.item.price)) .fontSize(12) .fontColor('#999999') .decoration({ type: TextDecorationType.LineThrough }) @@ -113,18 +113,6 @@ export struct KeJianItemComp { .backgroundColor(Color.White) } - private formatPrice(priceStr: string): string { - let priceInFen = parseFloat(priceStr); - let priceInYuan = priceInFen / 100; - return `${priceInYuan.toFixed(2)}`; - } - - private formatPrice2(priceStr: string,discount: string): string { - let priceInFen = parseFloat(priceStr); - let priceInYuan = priceInFen / 100 * parseFloat(discount); - return `${priceInYuan.toFixed(2)}`; - } - private contentShow(name:string,hospital:string):string { let newname:string = '' let newhospital:string = '' diff --git a/features/study/src/main/ets/views/NewsItemView.ets b/features/study/src/main/ets/views/NewsItemView.ets new file mode 100644 index 0000000..00d0b56 --- /dev/null +++ b/features/study/src/main/ets/views/NewsItemView.ets @@ -0,0 +1,67 @@ +import { authStore, BasicConstant, + ChangeUtil, + hdHttp, HdLoadingDialog, HdResponse, TimestampUtil } from '@itcast/basic'; +import { newsRequestOfData } from '../models/NewsModel'; +import { newsUtil } from '../utils/NewsUtil'; + +@Preview +@Component +export struct NewsItemView { + @Prop item:newsRequestOfData; + + build() { + Column() { + Row() { + Image(ChangeUtil.stringIsUndefinedAndNull(this.item.headImg)?BasicConstant.urlHtml+this.item.imgs:BasicConstant.urlHtml+this.item.headImg).width(114).height(76).alt($r('app.media.home_scroll_default1')) + .alt($r('app.media.home_top_scroll_default')) + Column() { + Text(ChangeUtil.stringIsUndefinedAndNull(this.item.title)?this.item.projectName:this.item.title).fontColor($r('app.color.common_gray_01')).fontSize(16) .textOverflow({ overflow: TextOverflow.Ellipsis }).height(40) + .ellipsisMode(EllipsisMode.END).maxLines(2) .textAlign(TextAlign.Start).align(Alignment.TopStart) + .width('100%') + Row() { + Row() { + Text('今日') + .borderRadius(30) + .fontColor(Color.White) + .backgroundColor('#f24d57') + .fontSize(11) + .padding({ left: 5, right: 5,top:2,bottom:2 }) + .visibility(TimestampUtil.isToday(this.item.createDate) ? Visibility.Visible : Visibility.None) + Text(this.item.createDate.length > 10 ? this.item.createDate.substring(5, 10) : this.item.createDate) + .fontColor($r('app.color.common_gray_03')) + .fontSize(12) + .visibility(!TimestampUtil.isToday(this.item.createDate) ? Visibility.Visible : Visibility.None) + }.width(80).align(Alignment.Start) + + Row() { + Image($r('app.media.read_commient')).width(10).height(10) + Text(Number(this.item.readnum) > 100000 ? Number(this.item.readnum) * 1.000 / 10000.00 + '万' : this.item.readnum + '') + .fontColor($r('app.color.common_gray_03')).padding({left:3}) + .fontSize(12) + }.width(80).align(Alignment.Start) + + Row() { + Image($r('app.media.argee_commient')).width(10).height(10) + Text(Number(this.item.agreenum) > 100000 ? Number(this.item.agreenum) * 1.000 / 10000.00 + '万' : this.item.agreenum + '') + .fontColor($r('app.color.common_gray_03')).padding({left:3}) + .fontSize(12) + }.width(80).align(Alignment.Start) + } + .margin({top:10}) + .width('100%') + }.padding({left:10}) + .layoutWeight(1) + + }.alignSelf(ItemAlign.Start) + + .width('100%') + .padding(10) + .onClick(() => { + newsUtil.readNews(this.item.uuid,this.item) + }) + Text().backgroundColor($r('app.color.efefef')).width('100%').height(1) + } + .backgroundColor(Color.White) + } +} + diff --git a/features/study/src/main/ets/views/NewsSwiperView.ets b/features/study/src/main/ets/views/NewsSwiperView.ets new file mode 100644 index 0000000..ba7235d --- /dev/null +++ b/features/study/src/main/ets/views/NewsSwiperView.ets @@ -0,0 +1,79 @@ +import { AppUtil, BasicConstant,hdHttp, HdResponse ,logger} from '@itcast/basic/Index' +import { BusinessError } from '@kit.BasicServicesKit'; +import { HdLoadingDialog } from '@itcast/basic' +import HashMap from '@ohos.util.HashMap'; +import { newsRequestOfData, newsRollNewRequest } from '../models/NewsModel'; +import { newsUtil } from '../utils/NewsUtil'; + +@Component +export struct NewsSwiperView { + @State list: newsRequestOfData[] = [] + + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + aboutToAppear(): void { + this.initData() + } + + initData() { + const hashMap: HashMap = new HashMap(); + this.dialog.open() + hashMap.clear(); + hdHttp.httpReq(BasicConstant.newsRollNew,hashMap).then(async (res: HdResponse) => { + logger.info('Response newsRollNew'+res); + let json:newsRollNewRequest = JSON.parse(res+'') as newsRollNewRequest; + this.dialog.close(); + this.list = json.data + }).catch((err: BusinessError) => { + this.dialog.close(); + }) + } + + build() { + Column() { // 使用堆叠布局实现按钮覆盖 + Swiper() { + ForEach(this.list, (item: newsRequestOfData) => { + Stack({alignContent:Alignment.Bottom}) { + Image(BasicConstant.urlHtml + item.headImg) + .objectFit(ImageFit.Fill)// 图片填充模式 + .width('100%') + .height(AppUtil.getDisplayWindowWidth().vp / 16 * 9) + Text(item.title) + .maxLines(1) + .height(30) + .fontColor('#F6F6F6') + .textAlign(TextAlign.Start) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .backgroundColor('#88000000') + .width('100%') + .padding({right:100,left:5}) + .margin({ bottom: 0 }) + }.onClick(()=>{ + newsUtil.readNews(item.uuid,item) + }) + }, (item: newsRequestOfData) => JSON.stringify(item)) + } + .indicator( + Indicator.dot() + .right(0) + .itemWidth(4) + .itemHeight(4) + .selectedItemWidth(4) + .selectedItemHeight(4) + .color($r('app.color.common_gray_02')) + .selectedColor('#3cc9c0') + ) + .loop(true) + .autoPlay(true) + .interval(3000) + .onChange((index: number) => { + + }) + } + .width('100%') + } +} \ No newline at end of file diff --git a/features/study/src/main/resources/base/media/flower_accountJinbi_icon.png b/features/study/src/main/resources/base/media/flower_accountJinbi_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..18f225adadcc20346a97d72c71c62b46a3235c88 GIT binary patch literal 2560 zcmaJ@c|25mA0A6~l`XqYLz2vD48|5_hMA1Y)`ZlUt%+I8jK-3hxk)J5vQ=Dbr4%A= zLW+`fqaynfs;fo16_v_6y48LEcze(1bIx!1JkRspolOV=Kf zA&biamJ}(W+(@AlSeofSC9ruvWjTWHZIU(&7DeH~5K#D1Nk4!j(*K9D*+0<&p%4Av zeE+Agz%QCdhxyP2+(uQYaqAolmC-xqLq^H~dEzx9sK$xq{tX9^mc{SZrf) zXk3wC{Wmy?gduPQLJEgUCt#hxQUNH7MZ>rvQEo^#EDnxB+aM4)TRR-w9dCnncSGRO zZb-cK4=$EVjbzg~!XI4Pzg+w;xl2x9^Q4inbUte@ordRg*}%7oF|1$b;{Hp$?_Aoi zbHVC&H2Zb)I3YupRSc2e)^uyk(!+^b#+&H(`yh&A(DV~^@|!D4h##| z@n6|IpS{X;gU)rO-9f126NR2tESBZ^Don;BR z8IN01T0F;Zn03t^iMSxsuhh6~U-yi`!QnMpioxmQd5j6YG=+Dd7=x}UP-ar4L|6Pw zqQxevnMbKEUm=^LUw=YuP-xJvuut`+;_`B4gIts3t=M&=3{R&!XC5Y#EmI@LwWw51 zs>Z%g26_|^=ZM`VA02M7+~qWT^=2>~RI*#fR&U-}ab_Y$c=;CCgg|H?(QM@4l(DG>ix9o+#n zoy&JpI!|JbqWH)}LGb zM_G+WMw&GtOO9&w>5~q*b+36}h*t^;Ij0;H?Z)T^M6jVg!%{Q;e2wk%h*AC2+!|mJ zH2QWrTQ|ZtlBS;@zrT{EELxbB4_KQwKkwM25RjvfQ`2peUzmNT^?5uB6njtB{K()1 z2eAAZh1z=m@|B3O9&+=Z0|w&>nEb&9-jCH=cPwO)&gC;TANuEAknvERaNJuB`8fDN zJa&zAS@FdExMO=3cMV*Rim6B8$JUsn$}-Nz`D^b#AU546^&MHoO6aaOKVFDWNn4&raSDRMC%z;W`D#<+090=sUE}AOb?X@ z`pn^VUYf_0--(+TrG=AFqVJPllhq}@7ynO>FAR_jm9G#F#{#qmE^&3UX9vQz z>LO~g4oZLf&O@gXtB|;8Z_5^R>|YkW7eCG)`cxvns>qC8|K?p_c#q)@tKj;4F4Hk) z#zQ9&Pm8MODtgZu3)KpgRxo}V`=&TjRURz)XMGPO`TzYL*s8)+^IGE9(WD&6ZoZ0q|q$!!+ zkTacu&QscvY7=q(=e}rb^Wp0ej%L3Hi_YN|_lm2F!)UwdYk_U)#it+zo|i?3s&6r_bYL>m zGr7(4hSMF;w5!mY@e0=at<+JN_*5 zlEvurO;5?ybC7{9zTO+%svB9lraBq#Q7)saG+x6zC@zceCpjshF%``bCJXjGfnqkJ z@Wid!Cl%cXdMUnB1N=Q)uI2`ng4{dpW_Pmxp0hJAKeK&REcRj6@a>bq(A0R!v7H*e zLGJISFh(~H{l1BrhGP>LUkuL^)YV4nkY!`K$LEzrk6auUOcb9 LZ|p_4UBCSYm_sor literal 0 HcmV?d00001 diff --git a/features/study/src/main/resources/base/media/flower_expertFlower_icon.png b/features/study/src/main/resources/base/media/flower_expertFlower_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fbf2c657606a67bd79388d92330f7e8740f23fd4 GIT binary patch literal 2371 zcmaJ@XH-+!77idN7(_uSIzkM^(30GQ0Et9OLIj1#kRTZp7bzDEkYW-H7-`a_StdNh zf+BHIL_o1nq&Nry;y4IM8{vs<1QZKJ5PiWB=lyuTyVkwuoV~v9+k2n={kUm9)NR^Y z>$M;dh_BOe0uczqA#t{BG++mFz#{=1VCM+fz%Xb4i$Y^j0M-`35YTu6fP;N| z;L2f7%Gw}L;*Bx|m8xAc;VxL?EII1mR1!=(A5C5s3E* zgfJ2bhVbX|IRdHJ@+;iio8ZY8OPG8%=t(BRl>$gEmqP&X0Gfn$a|Q4u3IMn}IO1?* zN5Gy;!YBhc5_*YC7O*3DAYZb?<^02S`yqGH2|S@PGZ_?d4}ctsNWg=A?U=y*aV?HN z)ceNe{J0kU54k91F{s74{@0wBLQ3;2Zoj)$dHC*okgqhmNa^aVJYX9HqJGnp>`IRu z7z$V!zRrE^nazG?`dSPtR!Pt&$gVqD_7*K<6?TDPRSfK~N@ja&;%u6st2U)OD1+?Q zJ)71rr7uCDyb9+Qf?>B8_EP?cacS{&15!=zRPed;ua|FGBCsPa@?dAxfg z;+(3Zajwodg#VI9+rN5JQ)q&Ad9+pCSlzxfaMe)xfriH};fP59O_{I=vJz?uwS_eo z70xNI;<7&gy58X%(QZ?%@w9jY)tR~#r=d=z)0&L~1y(wUl$e8nys@b;@=NnXGIzEihb2q9Ln>on3%Tj@>8Q)t<`-NvfVn;H62m6fWG z>X+G#cN7tXek2Ih2P3tMe_M`1iEd zmdIicDjps>nRwxlXI8)*l^f*WfBs5~yiX`ETeG)|8{KsCT`j%3bbMD-k#*&EdG&#+ z2VJ4nA=KtW!xPzwdV>N>6JNH}8G2rEt>5O3&*OA?Wujy6*$!TN}BW=6>w{a*998M75q4MRiN_u6i|g zCbcQEU}4UsGhJ_c_>qS22g8DbM2*MSdi!4{9xJKJxm!~NWN$8;8&6zQJ5=IqkY<=X zBU@WujJI|jI95Bp+iy5IhJQp)5x`N8);CM++oOH}A?3WkhRGbzA5|wcK z*$a9VR{B7jq$44wJ|zt(bYM(b2iA>N{5+VfOz>g%?x8-pi8SvW{Aqm{LR=?!|KR)#5v0 z4)u+Nh6C)X(A)tX)!)he@ioWUBa-vaVA#6o-SHm4%bFhF320|$dd;;gH-6>E*xOl~ zuFj}Zxyaj9T^)_0vGw8=SD!RPy)uq%pL6i`1O8G1+Lj$FaCsOr+ekUqkAVMbTLq}W+H9dNMMt6FDw(^RM_UF zQAj%57H}TOiPtEW`3&j4E1*W$J*?rL2ysi8&wab9q;6AoLcNJj=}#w~ePp&LKW_6f z{OfX&X>iJ)hVzlMhw=6=mq+PBjiATV?e<(B+cRozmutrePclGU;3Q7GkE`N^Wf;VN z?v1qUyOo#xEHCHKv`5(USs6Cwl2T>YW)uro-`=wNUsedGyk?Jyh?Xroe;mOzgvKJN3eGy(sI>)B{(q3uRE8<<9X*XscHBZtbK) g+!DIZmM_+g5Jj8_7gup&Vez-d)16Ab>=tzRKcUv<*#H0l literal 0 HcmV?d00001 diff --git a/features/study/src/main/resources/base/media/home_top_scroll_default.png b/features/study/src/main/resources/base/media/home_top_scroll_default.png new file mode 100644 index 0000000000000000000000000000000000000000..332899551ed28eb13cfade0adcc8c4d2269c0fa2 GIT binary patch literal 4380 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 I71xOW2CHHk_W%F@ literal 0 HcmV?d00001 diff --git a/features/study/src/main/resources/base/media/news_meeting_icon.png b/features/study/src/main/resources/base/media/news_meeting_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7e37400b8befdaa58b5e2d1712f658efd2b79aee GIT binary patch literal 8916 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 literal 0 HcmV?d00001 diff --git a/features/study/src/main/resources/base/media/patiemts_list_selected.png b/features/study/src/main/resources/base/media/patiemts_list_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..c60f6bb3d7fe988d5a7da5c590f11e2d983770cb GIT binary patch literal 2304 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 literal 0 HcmV?d00001 diff --git a/features/study/src/main/resources/base/media/patients_list_noSelect.png b/features/study/src/main/resources/base/media/patients_list_noSelect.png new file mode 100644 index 0000000000000000000000000000000000000000..5600189f4d2de7f9d8c2a5af2247410e7d3ee33a GIT binary patch literal 3033 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 MJGj}G+4;x*2R(BQ^Z)<= literal 0 HcmV?d00001 diff --git a/features/study/src/main/resources/base/media/pay_account_icon.png b/features/study/src/main/resources/base/media/pay_account_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d3106f12ece5d8cdd01fd7c8ef98408ea22cc277 GIT binary patch literal 2686 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 literal 0 HcmV?d00001 diff --git a/features/study/src/main/resources/base/media/pay_wx_icon.png b/features/study/src/main/resources/base/media/pay_wx_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3fa52bdf8c32aa857b6c1b69e404b6674d77c2ce GIT binary patch literal 2865 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 O?`Qh>)Bo-rmHr=o*lv~p literal 0 HcmV?d00001 diff --git a/features/study/src/main/resources/base/media/send_header_follow_icon.png b/features/study/src/main/resources/base/media/send_header_follow_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4c7ec96807277a71ce1cf143f016a13e0b2eeba0 GIT binary patch literal 12543 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 + router.pushUrl({url:'pages/Download/KeJianDownloadPage'}) + }) + } + .height('100%') + .width('100%') + .backgroundColor('#f1f1f1') + } +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/Download/KeJianDownloadPage.ets b/products/expert/src/main/ets/pages/Download/KeJianDownloadPage.ets new file mode 100644 index 0000000..c6a686c --- /dev/null +++ b/products/expert/src/main/ets/pages/Download/KeJianDownloadPage.ets @@ -0,0 +1,149 @@ +import { DefaultHintProWindows, HdNav } from '@itcast/basic' +import { FileManager } from '@itcast/basic' +import { FileInfo } from '@itcast/basic' +import { common } from '@kit.AbilityKit' +import { promptAction } from '@kit.ArkUI' + +@Entry +@Component +struct KeJianDownloadPage { + @State fileList: FileInfo[] = [] + private fileManager: FileManager | null = null + @State selected:number = 0 + + alertView:CustomDialogController = new CustomDialogController({ + builder:DefaultHintProWindows({ + title:'提示', + message:'确定删除该课件?', + cancleTitleColor: '#666666', + confirmTitleColor: $r('app.color.main_color'), + selectedButton: (index:number)=>{ + this.alertView.close(); + if (index == 1) { + this.deleteFile(this.fileList[this.selected].fileId) + } + } + }), + alignment: DialogAlignment.Center, + cornerRadius:24, + backgroundColor: ('rgba(0,0,0,0.5)'), + }) + + aboutToAppear() { + this.initFileManager() + this.loadDownloadedFiles() + } + + private initFileManager() { + try { + const context = getContext(this) as common.UIAbilityContext + this.fileManager = new FileManager(context) + } catch (error) { + console.error('初始化文件管理器失败:', error) + promptAction.showToast({ message: '初始化失败', duration: 2000 }) + } + } + + private async loadDownloadedFiles() { + try { + if (this.fileManager) { + this.fileList = await this.fileManager.getDownloadedFiles() + console.info(`加载了 ${this.fileList.length} 个已下载文件`) + } + } catch (error) { + console.error('加载文件列表失败:', error) + promptAction.showToast({ message: '加载失败', duration: 2000 }) + } + } + + private async previewFile(fileId: string) { + try { + if (this.fileManager) { + await this.fileManager.previewFile(fileId) + } + } catch (error) { + console.error('预览文件失败:', error) + promptAction.showToast({ message: '预览失败', duration: 2000 }) + } + } + + private async deleteFile(fileId: string) { + try { + if (this.fileManager) { + const success = await this.fileManager.deleteFile(fileId) + if (success) { + this.fileList = this.fileList.filter(file => file.fileId !== fileId) + } + } + } catch (error) { + console.error('删除文件失败:', error) + } + } + + build() { + Column() { + HdNav({title:'课件文档',showRightIcon:false,showRightText:false}) + + if (this.fileList.length === 0) { + Column() { + Text('暂无下载课件') + .fontSize(16) + .fontColor('#999999') + .margin({ top: 10 }) + } + .width('100%') + .height(200) + .justifyContent(FlexAlign.Center) + } else { + List() { + ForEach(this.fileList, (file: FileInfo, index: number) => { + ListItem() { + Row() { + Text(file.fileName) + .fontSize(16) + .fontColor('#333333') + .fontWeight(FontWeight.Medium) + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .layoutWeight(1) + } + .height(50) + .width('100%') + .padding(10) + .backgroundColor(Color.White) + .onClick(() => { + this.previewFile(file.fileId) + }) + } + .swipeAction({ + end: { + builder: () => { this.itemEnd(index) }, + } + }) + }, (file: FileInfo) => file.fileId) + } + .width('100%') + .height('100%') + .backgroundColor('#f1f1f1') + } + } + .height('100%') + .width('100%') + .backgroundColor('#F5F5F5') + } + + @Builder + itemEnd(index: number) { + Text('删除') + .fontSize(14) + .fontColor(Color.White) + .backgroundColor(Color.Red) + .textAlign(TextAlign.Center) + .size({width:60,height:50}) + .borderRadius(4) + .onClick(() => { + this.selected = index + this.alertView.open() + }) + } +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/Flower/FlowerDetailsPage.ets b/products/expert/src/main/ets/pages/Flower/FlowerDetailsPage.ets new file mode 100644 index 0000000..5ff8872 --- /dev/null +++ b/products/expert/src/main/ets/pages/Flower/FlowerDetailsPage.ets @@ -0,0 +1,14 @@ +import { FlowerDetailsComp } from 'study' + +@Entry +@Component +struct FlowerDetailsPage { + + build() { + Column() { + FlowerDetailsComp() + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/LoginPage/LoginPage.ets b/products/expert/src/main/ets/pages/LoginPage/LoginPage.ets index 15e2cee..b9c1d1d 100644 --- a/products/expert/src/main/ets/pages/LoginPage/LoginPage.ets +++ b/products/expert/src/main/ets/pages/LoginPage/LoginPage.ets @@ -3,7 +3,7 @@ import { NimRepository } from '../../entryability/NimRepository' import { AppConfig } from '../../constants/AppConfig' import { PerfactInputSheet } from '@itcast/basic/src/main/ets/Views/PerfactInputSheet' import { LengthMetrics, router } from '@kit.ArkUI' -import { TimestampUtil } from '@itcast/basic' +import { TimestampUtil, WXApi } from '@itcast/basic' @Entry @Component @@ -65,6 +65,7 @@ struct LoginPage { this.dialog.open() } + console.info('是否安装微信:',WXApi.isWXAppInstalled()) } } diff --git a/products/expert/src/main/ets/pages/Meeting/MeetingPage.ets b/products/expert/src/main/ets/pages/Meeting/MeetingPage.ets new file mode 100644 index 0000000..e3d0d45 --- /dev/null +++ b/products/expert/src/main/ets/pages/Meeting/MeetingPage.ets @@ -0,0 +1,14 @@ +import { VideoPage } from 'home' + +@Entry +@Component +struct MeetingPage { + + build() { + Column(){ + VideoPage() + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/MinePage/SettingPage.ets b/products/expert/src/main/ets/pages/MinePage/SettingPage.ets index 8385810..b435c4f 100644 --- a/products/expert/src/main/ets/pages/MinePage/SettingPage.ets +++ b/products/expert/src/main/ets/pages/MinePage/SettingPage.ets @@ -36,7 +36,7 @@ struct SettingPage { getVersion() { bundleManager.getBundleInfoForSelf( bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION | - bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_METADATA + bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_METADATA | bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO ) .then((res) => { this.version = 'V' + res.versionName diff --git a/products/expert/src/main/ets/pages/News/GandanNewsListPage.ets b/products/expert/src/main/ets/pages/News/GandanNewsListPage.ets new file mode 100644 index 0000000..20a3dba --- /dev/null +++ b/products/expert/src/main/ets/pages/News/GandanNewsListPage.ets @@ -0,0 +1,14 @@ +import { NewsListComp } from 'study' + +@Entry +@Component +struct GandanNewsListPage { + + build() { + Column() { + NewsListComp() + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/News/GandanNewsPages.ets b/products/expert/src/main/ets/pages/News/GandanNewsPages.ets new file mode 100644 index 0000000..7ddf0c8 --- /dev/null +++ b/products/expert/src/main/ets/pages/News/GandanNewsPages.ets @@ -0,0 +1,14 @@ +import { NewsComp } from 'study' + +@Entry +@Component +struct GandanNewsPages { + + build() { + Column() { + NewsComp() + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/Pay/PayPage.ets b/products/expert/src/main/ets/pages/Pay/PayPage.ets new file mode 100644 index 0000000..b91515e --- /dev/null +++ b/products/expert/src/main/ets/pages/Pay/PayPage.ets @@ -0,0 +1,14 @@ +import { PayComp } from 'study'; + +@Entry +@Component +struct PayPage { + + build() { + Column() { + PayComp() + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/Pay/SendFollowPage.ets b/products/expert/src/main/ets/pages/Pay/SendFollowPage.ets new file mode 100644 index 0000000..20f4dbb --- /dev/null +++ b/products/expert/src/main/ets/pages/Pay/SendFollowPage.ets @@ -0,0 +1,14 @@ +import { SendFollowComp } from 'study' + +@Entry +@Component +struct SendFollowPage { + + build() { + Column() { + SendFollowComp() + } + .height('100%') + .width('100%') + } +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/WebView/EducationDetailsWebPage.ets b/products/expert/src/main/ets/pages/WebView/EducationDetailsWebPage.ets index 35436ef..48cb9af 100644 --- a/products/expert/src/main/ets/pages/WebView/EducationDetailsWebPage.ets +++ b/products/expert/src/main/ets/pages/WebView/EducationDetailsWebPage.ets @@ -1,10 +1,7 @@ import webview from '@ohos.web.webview'; -import { BasicConstant, HdNav, preferenceStore } from '@itcast/basic'; +import { authStore, BasicConstant, hdHttp, HdLoadingDialog, HdNav, HdResponse, preferenceStore } from '@itcast/basic'; import router from '@ohos.router'; -import { image } from '@kit.ImageKit'; -import { photoAccessHelper } from '@kit.MediaLibraryKit'; import { promptAction } from '@kit.ArkUI'; -import { fileIo, fileUri } from '@kit.CoreFileKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { PatientTBean } from '@itcast/basic/src/main/ets/models/TeachModel'; @@ -13,6 +10,10 @@ import { PatientTBean } from '@itcast/basic/src/main/ets/models/TeachModel'; struct EducationDetailsWebPage { private controller: webview.WebviewController = new webview.WebviewController(); @State params:RouteParams = router.getParams() as RouteParams; + @State isDianZan:boolean = String(this.params.isAgree)=='1'?true:false + @State isShouCang:boolean = false + @State agreenum:string = this.params.model.agreenum.toString() + @State readnum:string = this.params.model.readnum.toString() // 修改为移动端User-Agent,解决链接中有视频的问题 private customUserAgent: string = 'Mozilla/5.0 (Linux; Android 10; HarmonyOS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 gdxz-expert'; @@ -22,6 +23,16 @@ struct EducationDetailsWebPage { @State url: string = BasicConstant.urlHtml+this.params.model.path; @State title: string = '患教详情'; + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + aboutToAppear(): void { + this.getKepuDetailsData() + } + onBackPress(): boolean | void { if (this.controller.accessStep(-1)) { this.controller.backward(); @@ -64,24 +75,173 @@ struct EducationDetailsWebPage { }) .width('100%') - .layoutWeight(1) - .height('calc(100% - 80vp)') + .height('calc(100% - 156vp)') + .clip(true) Row(){ Row(){ - Image('') + Image($r('app.media.eye_main_color')) .size({width:20,height:20}) + .objectFit(ImageFit.Contain) + Text(this.readnum) + .margin({left:10}) + .fontSize(15) + .fontColor(Color.Gray) } - .margin({left:15,top:12}) + .justifyContent(FlexAlign.Center) + .width(80) + .margin({top:12}) + .layoutWeight(1) + Row(){ + Image(this.isDianZan?$r('app.media.yi_dian_zan'):$r('app.media.wei_dian_zan')) + .objectFit(ImageFit.Contain) + .size({width:20,height:20}) + Text(this.agreenum) + .margin({left:10}) + .fontSize(15) + .fontColor(Color.Gray) + } + .justifyContent(FlexAlign.Center) + .width(80) + .margin({top:12}) + .layoutWeight(1) + .onClick(()=>{ + this.setAgreeData(this.isDianZan?"0":"1") + }) + Row(){ + Image(this.isShouCang?$r('app.media.yi_shou_cang'):$r('app.media.wei_shou_cang')) + .objectFit(ImageFit.Contain) + .size({width:20,height:20}) + Text('收藏') + .margin({left:10}) + .fontSize(15) + .fontColor(Color.Gray) + } + .justifyContent(FlexAlign.Center) + .width(80) + .margin({top:12}) + .layoutWeight(1) + .onClick(()=>{ + this.setCollectionData(this.isShouCang?"0":"1") + }) + Row(){ + Image($r('app.media.fenxiang')) + .objectFit(ImageFit.Contain) + .size({width:20,height:20}) + Text('分享') + .margin({left:10}) + .fontSize(15) + .fontColor(Color.Gray) + } + .justifyContent(FlexAlign.Center) + .width(80) + .margin({top:12}) + .layoutWeight(1) + .onClick(()=>{ + promptAction.showToast({ message:'敬请期待', duration: 1000 }) + }) } + .width('100%') .alignItems(VerticalAlign.Top) - .backgroundColor(Color.White) } .width('100%') .height('100%') } + + getKepuDetailsData() { + const entity = { + "uuid":this.params.model.uuid, + "user_uuid": authStore.getUser().uuid + } as Record + this.dialog.open() + hdHttp.post(BasicConstant.getKePuCollection, entity).then(async (res: HdResponse) => { + this.dialog.close(); + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + let isCollection = json.isCollection + if (isCollection == '1') { + this.isShouCang = true + } else { + this.isShouCang = false + } + this.readnum = String(json.readnum) + this.agreenum = String(json.agreenum) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) + }) + } + + setCollectionData(type:string) {//0取消收藏;1收藏 + const entity = { + "other_uuid":this.params.model.uuid, + "user_uuid": authStore.getUser().uuid, + "title":this.params.model.topic, + "path":this.params.model.path, + "imgpath":this.params.model.imgPath, + "readnum":this.readnum, + "type":"2" + } as Record + this.dialog.open() + hdHttp.post(type=='0'?BasicConstant.discollection:BasicConstant.collection, entity).then(async (res: HdResponse) => { + this.dialog.close(); + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + if (type == '0') { + this.isShouCang = false + promptAction.showToast({ message: '取消收藏成功', duration: 1000 }) + } else { + this.isShouCang = true + promptAction.showToast({ message: '收藏成功', duration: 1000 }) + } + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) + }) + } + + setAgreeData(type:string) {//0取消点赞;1点赞 + const entity = { + "news_article_uuid":this.params.model.uuid, + "user_uuid": authStore.getUser().uuid, + "type":"2" + } as Record + this.dialog.open() + hdHttp.post(type=='0'?BasicConstant.disagree:BasicConstant.agree, entity).then(async (res: HdResponse) => { + this.dialog.close(); + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + if (type == '0') { + this.agreenum = String(Number(this.agreenum)-1) + this.isDianZan = false + promptAction.showToast({ message: '取消点赞成功', duration: 1000 }) + } else { + this.agreenum = String(Number(this.agreenum)+1) + this.isDianZan = true + promptAction.showToast({ message: '点赞成功', duration: 1000 }) + } + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) + }) + } + } interface RouteParams { model:PatientTBean + isAgree:string } \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/WebView/KeJianDetailsWebPage.ets b/products/expert/src/main/ets/pages/WebView/KeJianDetailsWebPage.ets new file mode 100644 index 0000000..6c6c350 --- /dev/null +++ b/products/expert/src/main/ets/pages/WebView/KeJianDetailsWebPage.ets @@ -0,0 +1,553 @@ +import webview from '@ohos.web.webview'; +import { + authStore, BasicConstant, + ChangeUtil, + DefaultHintProWindows, + FileManager, + FileInfo, + hdHttp, HdLoadingDialog, HdNav, HdResponse, preferenceStore, + WXApi, + AESEncryptionDecryption} from '@itcast/basic'; +import router from '@ohos.router'; +import { promptAction } from '@kit.ArkUI'; +import { BusinessError, emitter } from '@kit.BasicServicesKit'; +import { KeJianModel } from 'study/src/main/ets/models/KeJianModel'; +import { HashMap } from '@kit.ArkTS'; +import * as wxopensdk from '@tencent/wechat_open_sdk'; +import { common, Want } from '@kit.AbilityKit'; +import { http } from '@kit.NetworkKit'; +import { fileIo } from '@kit.CoreFileKit'; +import request from '@ohos.request'; + +export enum OrderStatus { + status_default = 0,/**不能点击 */ + status_pay = 1,/**付费下载 */ + status_free = 2,/**免费下载 */ + status_download = 3,/**重新下载 */ + status_check = 4,/**查看课件 */ +} + +@Entry +@Component +struct KeJianDetailsWebPage { + private controller: webview.WebviewController = new webview.WebviewController(); + @State params:RouteParams = router.getParams() as RouteParams; + + // 修改为移动端User-Agent,解决链接中有视频的问题 + private customUserAgent: string = 'Mozilla/5.0 (Linux; Android 10; HarmonyOS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 gdxz-expert'; + private hcp_token:string = preferenceStore.getItemString(BasicConstant.EXPERT_HCP_TOKEN) + + private wxApi = WXApi + @State btnStatus: number = OrderStatus.status_default + @State contentWidth: number = 0; + @State contentHeight: number = 0; + @State url: string = BasicConstant.urlHtml+this.params.model.preview_path; + @State title: string = '课件详情'; + @State downloadImage: ResourceStr = '' + @State isShowDownloadImage: boolean = false + @State downloadState: string = '' + @State collectionIcon: ResourceStr = $r('app.media.wei_shou_cang') + @State kejianDetailsData : RequestData = {} as RequestData + @State hintMessage:string = '' + @State downType:string = '' + @State down_order_id:string = '' + @State isUseFreeRecord:boolean = false + @State isUserWelfareNum:boolean = false + @State system_time:string = '' + + private context: common.Context = getContext(this) as common.Context; + private fileManager: FileManager = new FileManager(this.context); + + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + alertView:CustomDialogController = new CustomDialogController({ + builder:DefaultHintProWindows({ + title:'提示', + message:this.hintMessage, + cancleTitleColor: '#666666', + confirmTitleColor: $r('app.color.main_color'), + selectedButton: (index:number)=>{ + this.alertView.close(); + if (index == 1) {//确定按钮 + if (this.btnStatus == OrderStatus.status_free) { + if (this.hintMessage.includes('确定要下载')) { + this.chackNetStatusAction() + } + } else if (this.btnStatus == OrderStatus.status_pay) { + if (this.hintMessage.includes('免费下载机会')) { + if (this.kejianDetailsData.welfareNum !== '0') { + this.isUserWelfareNum = true + this.useWelfareData() + } else { + if (this.kejianDetailsData.freeRecord !== '0') { + this.isUseFreeRecord = true + this.chackNetStatusAction() + } else { + this.chackNetStatusAction() + } + } + } else if (this.hintMessage.includes('确定要下载')) { + this.creatOrderData() + } else if (this.hintMessage.includes('正使用手机网络')) { + this.downloadFileAction() + } + } + } else {//取消按钮 + if (this.btnStatus == OrderStatus.status_pay) { + if (this.hintMessage.includes('免费下载机会')) { + this.creatOrderData() + } + } + } + } + }), + alignment: DialogAlignment.Center, + cornerRadius:24, + backgroundColor: ('rgba(0,0,0,0.5)'), + }) + + private refreshDataCallback = (eventData?: emitter.EventData): void => { + if (Object(eventData?.data)['status'] == 'success') { + this.chackNetStatusAction() + } + }; + + onPageShow(): void { + this.getKeJianDetailsData() + } + + aboutToDisappear(): void { + emitter.off(BasicConstant.notification_kejian_pay_success, this.refreshDataCallback) + } + + aboutToAppear(): void { + let innerEvent: emitter.InnerEvent = { + eventId: BasicConstant.notification_kejian_pay_success + } + emitter.on(innerEvent, this.refreshDataCallback) + if (this.params.model.preview_path.includes('http')) { + this.url = this.params.model.preview_path + } + } + + onBackPress(): boolean | void { + if (this.controller.accessStep(-1)) { + this.controller.backward(); + return true; + } + return false; + } + + build() { + Column() { + if (WXApi.isWXAppInstalled()) { + HdNav({ + title: this.title, + showRightIcon: true, + rightIcon: $r('app.media.fenxiang'), + twoRightIcon: this.collectionIcon, + hasBorder: true, + isLeftAction: true, + showTwoRightItem: true, + leftItemAction: () => { + if (this.controller.accessBackward()) { + this.controller.backward(); + } else { + if (this.fileManager.isDownloadingFile()) { + promptAction.showToast({message:'当前有课件正在下载,请稍等...'}) + } else { + router.back(); + } + } + }, + rightItemAction: () => { + let shareUrl = new wxopensdk.WXWebpageObject + shareUrl.type = 5 + shareUrl.webpageUrl = `${this.url}&fromtype=doctor` + let mediaMessage = new wxopensdk.WXMediaMessage() + mediaMessage.title = this.params.model.title + mediaMessage.description = '肝胆相照-国内专业优质肝胆课件共享平台' + mediaMessage.mediaObject = shareUrl + let req = new wxopensdk.SendMessageToWXReq() + req.scene = 0 + req.message = mediaMessage + let finished = this.wxApi.sendReq(getContext(this) as common.UIAbilityContext, req) + console.log("send request finished: ", finished) + }, + twoRightItemAction: () => { + this.setCollectionData(this.kejianDetailsData.iscollection == '0' ? '1' : '0') + } + }) + } else { + HdNav({ + title: this.title, + showRightIcon: true, + rightIcon: this.collectionIcon, + hasBorder: true, + isLeftAction: true, + leftItemAction: () => { + if (this.controller.accessBackward()) { + this.controller.backward(); + } else { + if (this.fileManager.isDownloadingFile()) { + promptAction.showToast({message:'当前有课件正在下载,请稍等...'}) + } else { + router.back(); + } + } + }, + rightItemAction: () => { + this.setCollectionData(this.kejianDetailsData.iscollection == '0' ? '1' : '0') + } + }) + } + Stack() { + Web({ + src: this.url, + controller: this.controller + }) + .id('webView') + .mixedMode(MixedMode.All) + .overScrollMode(OverScrollMode.ALWAYS) + .domStorageAccess(true) + .onControllerAttached(() => { + let userAgent = this.controller.getUserAgent() + this.customUserAgent; + this.controller.setCustomUserAgent(userAgent); + }) + .onPageBegin(() => { + this.dialog.open() + this.controller.runJavaScript(`document.cookie = 'hcp_from=expert_app; domain=.igandan.com; path=/';`) + this.controller.runJavaScript(`document.cookie = 'hcp_token=${this.hcp_token}; domain=.igandan.com; path=/';`) + }) + .onPageEnd(() => { + this.dialog.close() + // 注入JS获取body高度 + this.controller.runJavaScript( + 'document.documentElement.scrollWidth', (error, result) => { + if (!error) this.contentWidth = Number(result); + } + ); + this.controller.runJavaScript('document.body.scrollHeight', (error, result) => { + if (!error) this.contentHeight = Number(result); + }) + }) + .width('100%') + .layoutWeight(1) + + Row(){ + Image(this.downloadImage) + .size({width:16,height:16}) + .visibility(this.isShowDownloadImage?Visibility.Visible:Visibility.None) + Text(this.downloadState) + .fontSize(18) + .fontColor(Color.White) + } + .justifyContent(FlexAlign.Center) + .backgroundColor(Color.Gray) + .width('100%') + .height(44) + .onClick(()=>{ + if (this.btnStatus == OrderStatus.status_check) { + // 查看已下载文件 + this.fileManager.previewFile(this.params.model.uuid) + } else if (this.btnStatus == OrderStatus.status_download) { + // 重新下载 + this.downloadFileAction() + } else if (this.btnStatus == OrderStatus.status_pay) { + if (this.kejianDetailsData.welfareNum == '0') { + if (this.kejianDetailsData.freeRecord == '0') { + this.hintMessage = '您确定要下载该课件吗' + this.alertView.open() + } else { + this.hintMessage = `您还有${this.getFreeDownLoadCount()}次免费下载机会,希望本次下载免费吗?` + this.alertView.open() + } + } else { + this.hintMessage = `您还有${this.getFreeDownLoadCount()}次免费下载机会,希望本次下载免费吗?` + this.alertView.open() + } + } else if (this.btnStatus == OrderStatus.status_free) { + this.hintMessage = '您确定要下载该课件吗' + this.alertView.open() + } + }) + } + .alignContent(Alignment.Top) + } + .width('100%') + .height('100%') + } + + getKeJianDetailsData() { + const hashMap: HashMap = new HashMap() + this.dialog.open() + hashMap.clear() + hashMap.set('file_uuid', this.params.model.uuid) + hdHttp.httpReq(BasicConstant.ganDanFileDetials,hashMap).then(async (res: HdResponse) => { + console.info('Response ganDanFileDetials'+res) + this.dialog.close() + let json:Record = JSON.parse(res+'') as Record; + if(json.code == '200') { + this.kejianDetailsData = json.data as RequestData + if (this.kejianDetailsData.iscollection == '0') { + this.collectionIcon = $r('app.media.wei_shou_cang') + } else { + this.collectionIcon = $r('app.media.yi_shou_cang') + } + if (this.kejianDetailsData.order == null || this.kejianDetailsData.order == undefined) {//没有订单 + if (parseFloat(this.kejianDetailsData.price) < 0) { + this.btnStatus = 0 + this.downloadImage = '' + this.isShowDownloadImage = false + this.downloadState = '本课件不支持下载' + } else { + this.btnStatus = 2 + this.downloadImage = $r('app.media.kejian_download_white') + this.isShowDownloadImage = true + this.downloadState = ' 本课件免费下载' + } + if (parseFloat(this.kejianDetailsData.price) > 0) { + this.btnStatus = 1 + this.downloadImage = $r('app.media.kejian_download_white') + this.isShowDownloadImage = true + this.downloadState = `本课件下载${ChangeUtil.formatPrice(this.kejianDetailsData.price)}元` + } + } else {//有订单 + try { + const downloadedFiles = await this.fileManager.getDownloadedFiles(); + const downloadedFile = downloadedFiles.find(file => file.fileId === this.params.model.uuid); + if (downloadedFile && downloadedFile.filePath && fileIo.accessSync(downloadedFile.filePath)) { + // 本地已存在,显示查看文件 + this.btnStatus = OrderStatus.status_check + this.downloadImage = '' + this.isShowDownloadImage = false + this.downloadState = '查看课件' + } else { + // 本地不存在,显示重新下载 + this.down_order_id = `${this.kejianDetailsData.order['order_id']}&R` + this.btnStatus = OrderStatus.status_download + this.downloadImage = '' + this.isShowDownloadImage = false + this.downloadState = '重新下载本课件' + } + } catch (e) { + // 异常情况下,默认提供重新下载 + this.btnStatus = OrderStatus.status_download + this.downloadImage = '' + this.isShowDownloadImage = false + this.downloadState = ' 重新下载' + } + } + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close() + console.error(`Response fails: ${err}`); + }) + } + + chackNetStatusAction() { + if (hdHttp.getNetworkType() == 2) { + this.hintMessage = '您当前正使用手机网络,是否继续下载?' + this.alertView.open() + } else if (hdHttp.getNetworkType() == 1 || hdHttp.getNetworkType() == 3) { + this.downloadFileAction() + } else if (hdHttp.getNetworkType() == 0 || hdHttp.getNetworkType() == -1) { + this.hintMessage = '未连接网络,请设置' + this.alertView.open() + } + } + + downloadFileAction() { + let httpRequest = http.createHttp(); + let timeStampurl = BasicConstant.getSystemTime; + let promise = httpRequest.request(timeStampurl, { + method: http.RequestMethod.GET, + connectTimeout: 60000, + readTimeout: 60000, + header: { + 'Content-Type': 'application/json' + } + }); + promise.then(async (data) => { + if (data.responseCode === http.ResponseCode.OK) { + let json:TimestampBean = JSON.parse(data.result.toString()) as TimestampBean + let daijiami:string = '' + if (this.btnStatus == OrderStatus.status_free) { + daijiami = `${this.params.model.uuid}|FREE|${authStore.getUser().uuid}|${json.system_time}` + } else if (this.btnStatus == OrderStatus.status_download) { + daijiami = `${this.params.model.uuid}|${this.down_order_id}|${authStore.getUser().uuid}|${json.system_time}` + } + if (this.isUseFreeRecord) { + daijiami = `${this.params.model.uuid}|FREERECORD|${authStore.getUser().uuid}|${json.system_time}` + } + if (this.kejianDetailsData.welfareNum != '0') { + if (this.isUserWelfareNum) { + daijiami = `${this.params.model.uuid}|USEWELFARENUM|${authStore.getUser().uuid}|${json.system_time}` + } + } + const scanData = await AESEncryptionDecryption.aesEncrypt(daijiami,BasicConstant.ExpertAesKey) + let x: number = 10; + let valueINTT: number = Math.floor(Math.random() * x) + 1; + let pinString = `${getChars(valueINTT)}${scanData}` + let downloadUrl = `${BasicConstant.urlExpertApp}downloadGanDanFile?&gdf=${pinString}&a=${valueINTT}` + console.info('开始下载文件,URL:', downloadUrl); + const fileInfo: FileInfo = { + fileId: this.params.model.uuid, + fileName: this.params.model.title, + fileType: this.params.model.type, + fileSize: 0, + fileUrl: downloadUrl, + downloadStatus: 'pending', + downloadProgress: 0, + createTime: Date.now(), + updateTime: Date.now() + }; + promptAction.showToast({ message: '开始下载,请勿重复点击', duration: 1000 }) + this.fileManager.downloadFile(fileInfo, { + onSuccess: (filePath: string) => { + this.btnStatus = OrderStatus.status_check + this.downloadImage = '' + this.downloadState = '查看课件' + }, + onFailed: (error: string) => { + console.info('fileDownload,error:',error) + } + }); + } + } + ).catch((err: BusinessError) => { + return Promise.reject(err); + }).finally(() => { + httpRequest.destroy() + }) + } + + setCollectionData(type:string) {//0取消收藏;1收藏 + const entity = { + "other_uuid":this.params.model.uuid, + "user_uuid": authStore.getUser().uuid, + "title":this.params.model.title, + "path":this.params.model.preview_path, + "type":"6" + } as Record + this.dialog.open() + hdHttp.post(type=='0'?BasicConstant.discollection:BasicConstant.collection, entity).then(async (res: HdResponse) => { + this.dialog.close(); + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + if (type == '0') { + this.collectionIcon = $r('app.media.wei_shou_cang') + promptAction.showToast({ message: '取消收藏成功', duration: 1000 }) + } else { + this.collectionIcon = $r('app.media.yi_shou_cang') + promptAction.showToast({ message: '收藏成功', duration: 1000 }) + } + this.getKeJianDetailsData() + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) + }) + } + + creatOrderData() { + const hashMap: HashMap = new HashMap() + this.dialog.open() + hashMap.clear() + hashMap.set('file_uuid', this.params.model.uuid) + hdHttp.httpReq(BasicConstant.createGanDanFileOrder,hashMap).then(async (res: HdResponse) => { + console.info('Response ganDanFileDetials'+res) + this.dialog.close() + let json:Record = JSON.parse(res+'') as Record; + if(json.code == '200') { + router.pushUrl({ + url:"pages/Pay/PayPage", + params:{"data":json.data,"page":"课件详情"} + }) + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close() + console.error(`Response fails: ${err}`); + }) + } + + useWelfareData() { + const hashMap: HashMap = new HashMap() + this.dialog.open() + hashMap.clear() + hashMap.set('type', '2') + hashMap.set('other_uuid',this.params.model.uuid) + hdHttp.httpReq(BasicConstant.useWelfareNum,hashMap).then(async (res: HdResponse) => { + console.info('Response useWelfareNum'+res) + this.dialog.close() + let json:Record = JSON.parse(res+'') as Record; + if(json.code == '1') { + this.downloadFileAction() + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close() + console.error(`Response fails: ${err}`); + }) + } + + private getFreeDownLoadCount():string { + let count = Number(this.kejianDetailsData.welfareNum)+Number(this.kejianDetailsData.freeRecord) + return count.toString() + } +} + +interface RouteParams { + model:KeJianModel +} + +interface RequestData { + iscollection:string + welfareNum:string + freeRecord:string + fileSize:string + fileMD5:string + price:string + order:object +} + +interface FileOrderData { + trade_no:string + order_id:string + amount:string + account:string + provider_name:string + file_uuid:string + order_status:string +} + +export interface TimestampBean { + system_time:string +} + +export function getChars(number_od_chars:number):string { + // 创建字符数组并填充随机大写字母 + let data: string[] = []; + for (let i: number = 0; i < number_od_chars; i++) { + // 生成A-Z的随机字母 + let randomChar: string = String.fromCharCode(65 + Math.floor(Math.random() * 26)); + data.push(randomChar); + } + + // 将字符数组转换为字符串 + let stringValue: string = data.join(''); + return stringValue +} \ No newline at end of file diff --git a/products/expert/src/main/ets/pages/WebView/NewsDetailsWebPage.ets b/products/expert/src/main/ets/pages/WebView/NewsDetailsWebPage.ets new file mode 100644 index 0000000..8333bef --- /dev/null +++ b/products/expert/src/main/ets/pages/WebView/NewsDetailsWebPage.ets @@ -0,0 +1,247 @@ +import webview from '@ohos.web.webview'; +import { authStore, BasicConstant, hdHttp, HdLoadingDialog, HdNav, HdResponse } from '@itcast/basic'; +import router from '@ohos.router'; +import { promptAction } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { newsRequestOfData } from 'study'; + +@Entry +@Component +struct NewsDetailsWebPage { + private controller: webview.WebviewController = new webview.WebviewController(); + @State params:RouteParams = router.getParams() as RouteParams; + @State isDianZan:boolean = String(this.params.isAgree)=='1'?true:false + @State isShouCang:boolean = false + @State agreenum:string = this.params.model.agreenum.toString() + @State readnum:string = this.params.model.readnum.toString() + + // 修改为移动端User-Agent,解决链接中有视频的问题 + private customUserAgent: string = 'Mozilla/5.0 (Linux; Android 10; HarmonyOS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 gdxz-expert'; + + @State contentWidth: number = 0; + @State contentHeight: number = 0; + @State url: string = BasicConstant.urlHtml+this.params.model.path; + @Prop title: string = '新闻详情'; + + dialog: CustomDialogController = new CustomDialogController({ + builder: HdLoadingDialog({ message: '加载中...' }), + customStyle: true, + alignment: DialogAlignment.Center + }) + + aboutToAppear(): void { + this.getNewsDetailsData() + } + + onBackPress(): boolean | void { + if (this.controller.accessStep(-1)) { + this.controller.backward(); + return true; + } + return false; + } + + build() { + Column() { + HdNav({ title: this.title, showRightIcon: false, hasBorder: true ,isLeftAction:true,leftItemAction:()=>{ + if (this.controller.accessBackward()) { + this.controller.backward(); + } else { + router.back(); + } + }}) + Web({ + src: this.url, + controller: this.controller + }) + .id('webView') + .mixedMode(MixedMode.All) + .overScrollMode(OverScrollMode.ALWAYS) + .domStorageAccess(true) + .onControllerAttached(() => { + let userAgent = this.controller.getUserAgent() + this.customUserAgent; + this.controller.setCustomUserAgent(userAgent); + }) + .onPageEnd(() => { + // 注入JS获取body高度 + this.controller.runJavaScript( + 'document.documentElement.scrollWidth', (error, result) => { + if (!error) this.contentWidth = Number(result); + } + ); + this.controller.runJavaScript('document.body.scrollHeight',(error,result)=>{ + if (!error) this.contentHeight = Number(result); + }) + + }) + .width('100%') + .height('calc(100% - 156vp)') + .clip(true) + + Row(){ + Row(){ + Image($r('app.media.eye_main_color')) + .size({width:20,height:20}) + .objectFit(ImageFit.Contain) + Text(this.readnum) + .margin({left:10}) + .fontSize(15) + .fontColor(Color.Gray) + } + .justifyContent(FlexAlign.Center) + .width(80) + .margin({top:12}) + .layoutWeight(1) + Row(){ + Image(this.isDianZan?$r('app.media.yi_dian_zan'):$r('app.media.wei_dian_zan')) + .objectFit(ImageFit.Contain) + .size({width:20,height:20}) + Text(this.agreenum) + .margin({left:10}) + .fontSize(15) + .fontColor(Color.Gray) + } + .justifyContent(FlexAlign.Center) + .width(80) + .margin({top:12}) + .layoutWeight(1) + .onClick(()=>{ + this.setAgreeData(this.isDianZan?"0":"1") + }) + Row(){ + Image(this.isShouCang?$r('app.media.yi_shou_cang'):$r('app.media.wei_shou_cang')) + .objectFit(ImageFit.Contain) + .size({width:20,height:20}) + Text('收藏') + .margin({left:10}) + .fontSize(15) + .fontColor(Color.Gray) + } + .justifyContent(FlexAlign.Center) + .width(80) + .margin({top:12}) + .layoutWeight(1) + .onClick(()=>{ + this.setCollectionData(this.isShouCang?"0":"1") + }) + Row(){ + Image($r('app.media.fenxiang')) + .objectFit(ImageFit.Contain) + .size({width:20,height:20}) + Text('分享') + .margin({left:10}) + .fontSize(15) + .fontColor(Color.Gray) + } + .justifyContent(FlexAlign.Center) + .width(80) + .margin({top:12}) + .layoutWeight(1) + .onClick(()=>{ + promptAction.showToast({ message:'敬请期待', duration: 1000 }) + }) + } + .width('100%') + .alignItems(VerticalAlign.Top) + } + .width('100%') + .height('100%') + } + + getNewsDetailsData() { + const entity = { + "uuid":this.params.model.uuid, + "user_uuid": authStore.getUser().uuid + } as Record + this.dialog.open() + hdHttp.post(BasicConstant.newsDetial, entity).then(async (res: HdResponse) => { + this.dialog.close(); + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + let isCollection = json.isCollection + if (isCollection == '1') { + this.isShouCang = true + } else { + this.isShouCang = false + } + this.readnum = String(json.readnum) + this.agreenum = String(json.agreenum) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) + }) + } + + setCollectionData(type:string) {//0取消收藏;1收藏 + const entity = { + "other_uuid":this.params.model.uuid, + "user_uuid": authStore.getUser().uuid, + "title":this.params.model.title, + "path":this.params.model.path, + "imgpath":this.params.model.imgpath, + "readnum":this.readnum, + "type":"1" + } as Record + this.dialog.open() + hdHttp.post(type=='0'?BasicConstant.discollection:BasicConstant.collection, entity).then(async (res: HdResponse) => { + this.dialog.close(); + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + if (type == '0') { + this.isShouCang = false + promptAction.showToast({ message: '取消收藏成功', duration: 1000 }) + } else { + this.isShouCang = true + promptAction.showToast({ message: '收藏成功', duration: 1000 }) + } + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) + }) + } + + setAgreeData(type:string) {//0取消点赞;1点赞 + const entity = { + "news_article_uuid":this.params.model.uuid, + "user_uuid": authStore.getUser().uuid, + "type":"1" + } as Record + this.dialog.open() + hdHttp.post(type=='0'?BasicConstant.disagree:BasicConstant.agree, entity).then(async (res: HdResponse) => { + this.dialog.close(); + console.info('Response delConditionRecord'+res); + let json:Record | Array>> = JSON.parse(res+'') as Record | Array>>; + if(json.code == '1') { + if (type == '0') { + this.agreenum = String(Number(this.agreenum)-1) + this.isDianZan = false + promptAction.showToast({ message: '取消点赞成功', duration: 1000 }) + } else { + this.agreenum = String(Number(this.agreenum)+1) + this.isDianZan = true + promptAction.showToast({ message: '点赞成功', duration: 1000 }) + } + } else { + promptAction.showToast({ message: String(json.message), duration: 1000 }) + } + }).catch((err: BusinessError) => { + this.dialog.close(); + console.error(`Response fails: ${err}`); + promptAction.showToast({ message: String('患教文库数据请求失败!'), duration: 1000 }) + }) + } + +} + +interface RouteParams { + model:newsRequestOfData + isAgree:string +} \ No newline at end of file diff --git a/products/expert/src/main/module.json5 b/products/expert/src/main/module.json5 index 4b22400..41dbb39 100644 --- a/products/expert/src/main/module.json5 +++ b/products/expert/src/main/module.json5 @@ -72,7 +72,16 @@ "name": "ohos.permission.WRITE_MEDIA", "reason": "$string:media_reason", "usedScene": {} + }, + { + "name": "ohos.permission.READ_WRITE_USER_FILE", + "reason": "$string:write_file", + "usedScene": {} } + ], + "querySchemes": [ + "weixin", + "wxopensdk" ] } } \ No newline at end of file diff --git a/products/expert/src/main/resources/base/profile/main_pages.json b/products/expert/src/main/resources/base/profile/main_pages.json index c3e1b4b..0ac9ef7 100644 --- a/products/expert/src/main/resources/base/profile/main_pages.json +++ b/products/expert/src/main/resources/base/profile/main_pages.json @@ -49,6 +49,17 @@ "pages/VideoPage/CustomScanResultPage", "pages/VideoPage/EducationVideoPage", "pages/Courseware/CoursewarePage", - "pages/WebView/EducationDetailsWebPage" + "pages/WebView/EducationDetailsWebPage", + "pages/WebView/KeJianDetailsWebPage", + "pages/Pay/PayPage", + "pages/News/GandanNewsPages", + "pages/WebView/NewsDetailsWebPage", + "pages/Meeting/MeetingPage", + "pages/News/GandanNewsListPage", + "pages/Pay/SendFollowPage", + "pages/Download/AllDownloadPage", + "pages/Download/KeJianDownloadPage", + "pages/Flower/FlowerDetailsPage", + "pages/Courseware/CourseDetailsPage" ] } \ No newline at end of file