1.2.0部分代码

This commit is contained in:
xiaoxiao 2025-09-09 13:27:34 +08:00
parent e89a5f15ce
commit 3013b441a6
80 changed files with 4824 additions and 105 deletions

View File

@ -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'
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'

View File

@ -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 })
}

View File

@ -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'//云信

View File

@ -0,0 +1,2 @@
export const APP_ID = "wxbf3658f5e674667c"
export const APP_SECRET = "c4505a04a9910c65efea8e11ffc93f92"

View File

@ -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; // 错误信息(失败时)
}

View File

@ -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<OnWXReq, OnWXReq> = new Map
private onRespCallbacks: Map<OnWXResp, OnWXResp> = 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

View File

@ -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);
}
}

View File

@ -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`
}
}

View File

@ -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();

View File

@ -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<string, FileInfo> = new Map();
private downloadTasks: Map<string, request.DownloadTask> = 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<void> {
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<string> {
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<void> {
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<boolean> {
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<FileInfo[]> {
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<boolean> {
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<boolean> {
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<boolean> {
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<boolean> {
// 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;
// }
// }
}

View File

@ -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<string, DownloadTask> = new Map();
private downloadCallbacks: Map<string, DownloadCallback> = new Map();
private fileCache: Map<string, FileInfo> = 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<void> {
try {
this.preferencesHelper = await preferences.getPreferences(this.context, this.STORE_NAME);
} catch (error) {
console.error('初始化偏好设置失败:', error);
}
}
/**
* 从存储加载文件信息
*/
private async loadFileInfoFromStorage(): Promise<void> {
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<void> {
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<void> {
try {
if (!fileIo.accessSync(this.downloadDir)) {
fileIo.mkdirSync(this.downloadDir);
}
} catch (error) {
console.error('创建下载目录失败:', error);
}
}
/**
* 下载文件
* @param fileInfo 文件信息
* @param callback 下载回调
* @returns Promise<boolean>
*/
async downloadFile(fileInfo: FileInfo, callback?: DownloadCallback): Promise<boolean> {
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<DownloadTask> {
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<boolean> {
//
// 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<boolean> {
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<FileInfo[]> {
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<FileInfo[]> {
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<boolean> {
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<filePreview.PreviewInfo> = 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<string, string> = {
'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<boolean> {
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<void> {
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<void> {
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 });
}
}

View File

@ -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<void> {
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<boolean> {
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<boolean> {
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<boolean> {
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<WPSFile | null> {
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<string> {
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;
// }
}
}

View File

@ -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<T> {
}
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 {

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,179 @@
import { gandanfileModel, guideModel } from "../model/HomeModel";
@Component
export struct HomeGanDanFileComp {
@Prop gandanFileList:gandanfileModel[]
@Prop guideList:guideModel[]
@State currentIndex: number = 0
private tabsController: TabsController = new TabsController()
build() {
Column() {
this.headerView()
this.tabContent()
}
.width('100%')
.backgroundColor('#F5F5F5')
}
@Builder
headerView() {
Stack() {
Row() {
Image($r('app.media.home_guideAndShare_icon'))
.width('70%')
.height(50)
.objectFit(ImageFit.Cover)
}
.width('100%')
.height(50)
.justifyContent(FlexAlign.End)
Row() {
Row() {
Column() {
Text('实用指南')
.fontSize(this.currentIndex === 0 ? 17 :14)
.fontColor(this.currentIndex === 0 ? '#000000' : '#666666')
.fontWeight(this.currentIndex === 0 ? FontWeight.Bold : FontWeight.Normal)
Blank()
.width(32)
.height(2)
.margin({top:5})
.backgroundColor($r('app.color.main_color'))
.visibility(this.currentIndex == 0? Visibility.Visible: Visibility.Hidden)
}
.width(80)
.height(50)
.justifyContent(FlexAlign.Center)
.onClick(() => {
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 })
}
}

View File

@ -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<string>(BasicConstant.applyList,{
expertUuid: authStore.getUser().uuid,
} as updateExtraData).then(async (res: HdResponse<string>) => {
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<string, string> = new HashMap();
hdHttp.httpReq<string>(BasicConstant.indexV2,hashMap).then(async (res: HdResponse<string>) => {
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)

View File

@ -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)

View File

@ -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)

View File

@ -12,7 +12,7 @@ import { http } from '@kit.NetworkKit';
@Entry
@Component
export struct VideoPage {
@State params:Record<string, string> = router.getParams() as Record<string, string>
@State notselectImg: ResourceStr = $r('app.media.triangle_normal');
@State selectImg: ResourceStr = $r('app.media.triangle_green_theme');
@State monthWords:Array<string> =[]
@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -4,9 +4,13 @@ import { TwoSection } from '../view/TwoSection'
import { ThreeSection } from '../view/ThreeSection'
import { FourSection } from '../view/FourSection'
import { OtherList } from '../view/OtherList'
import { HdNav,hdHttp,HdResponse,BasicConstant,ExpertData,authStore,RequestDefaultModel } from '@itcast/basic'
import { HdNav,hdHttp,HdResponse,BasicConstant,ExpertData,authStore,RequestDefaultModel,
ChangeUtil,
logger,
HdLoadingDialog} from '@itcast/basic'
import { BusinessError, emitter } from '@kit.BasicServicesKit';
import HashMap from '@ohos.util.HashMap'
import { router } from '@kit.ArkUI'
interface heroFirst {
id: string;
@ -18,13 +22,23 @@ export struct MyHomePage {
@State title: string = '我的';
@StorageProp('topHeight')
topHeight: number = 0
@State rightBottom:string = ''
@State rightBottomPath:string = ''
@State rightBottomTitle:string = ''
@State myInfoBackGround:string = '';
@State heroArray:Array<object> = [];
@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<string, string> = new HashMap()
this.dialog.open()
hashMap.clear()
hashMap.set('id','6')
hdHttp.httpReq<string>(BasicConstant.getAppActivity,hashMap).then(async (res: HdResponse<string>) => {
logger.info('Response addBonusPoints'+res)
this.dialog.close()
let json:Record<string,string | Record<string,string>> = JSON.parse(res+'') as Record<string,string | Record<string,string>>
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%')

View File

@ -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<MyPageSectionClass> = [
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<Array<MyPageSectionClass>> {
@ -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)
}

View File

@ -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<MyPageSectionClass> = [
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<Array<MyPageSectionClass>> {
@ -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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -2,4 +2,18 @@ export { SchoolhouseComp } from './src/main/ets/components/SchoolhouseComp';
export { KeepStudyComp } from './src/main/ets/components/KeepStudyComp';
export { CoursewareComp } from './src/main/ets/components/CoursewareComp';
export { CoursewareComp } from './src/main/ets/components/CoursewareComp';
export { PayComp } from './src/main/ets/components/PayComp'
export { NewsComp } from './src/main/ets/components/NewsComp'
export { newsUtil } from './src/main/ets/utils/NewsUtil'
export { newsRollNewRequest,newsRequestOfData } from './src/main/ets/models/NewsModel'
export { NewsListComp } from './src/main/ets/components/NewsListComp'
export { SendFollowComp } from './src/main/ets/components/SendFollowComp'
export { FlowerDetailsComp } from './src/main/ets/components/FlowerDetailsComp'

View File

@ -242,6 +242,9 @@ export struct CoursewareComp {
ForEach(this.data, (item: KeJianModel) => {
ListItem() {
KeJianItemComp({item:item})
.onClick(()=>{
router.pushUrl({url:"pages/WebView/KeJianDetailsWebPage",params:{"model":item}})
})
}
})
}

View File

@ -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<string, string> = new HashMap();
hashMap.set('page',this.pageNumber.toString());
this.dialog.open()
hdHttp.httpReq<string>(BasicConstant.getFlowerList,hashMap).then(async (res: HdResponse<string>) => {
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
}

View File

@ -79,6 +79,6 @@ export struct KeepStudyComp {
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
.backgroundColor('#f1f1f1')
}
}

View File

@ -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%')
}
}

View File

@ -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%')
}
}

View File

@ -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<string,string>
this.dialog.open()
hdHttp.post<string>(BasicConstant.newsTagList, entity).then(async (res: HdResponse<string>) => {
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<string, string> = new HashMap();
this.dialog.open()
hashMap.clear();
hashMap.set('page',this.pageNumber.toString())
if (!isDefault)
hashMap.set('newstagid', this.selectedTagId)//点击标签的ID
hdHttp.httpReq<string>(isDefault?BasicConstant.defaultNewsListNew:BasicConstant.newsListNew,hashMap).then(async (res: HdResponse<string>) => {
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)
}
}

View File

@ -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<string,string | Record<string,string> | FileOrderData> = router.getParams() as Record<string,string | Record<string,string> | 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<string,string | Record<string,string>> = {}
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<string,string | Record<string,string>>
} 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<string, string> = new HashMap()
this.dialog.open()
hashMap.clear()
hdHttp.httpReq<string>(BasicConstant.getBalance,hashMap).then(async (res: HdResponse<string>) => {
console.info('Response getBalance'+res)
this.dialog.close()
let json:Record<string,string> = JSON.parse(res+'') as Record<string,string>;
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<string, string> = 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<string>(this.params.page == '课件详情'?BasicConstant.payGanDanFileOrder:BasicConstant.payXinYiOrder,hashMap).then(async (res: HdResponse<string>) => {
console.info('Response payGanDanFileOrder'+res)
this.dialog.close()
let json:Record<string,string | Record<string,string>> = JSON.parse(res+'') as Record<string,string | Record<string,string>>;
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<string, string> = 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<string>(BasicConstant.getOrderStatus,hashMap).then(async (res: HdResponse<string>) => {
console.info('Response getOrderStatus'+res)
this.dialog.close()
let json:Record<string,string | Record<string,string>> = JSON.parse(res+'') as Record<string,string | Record<string,string>>;
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
}

View File

@ -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<string,string>
this.dialog.open()
hdHttp.post<string>(BasicConstant.read, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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 })
})
}
}

View File

@ -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<string, string> = new HashMap();
hashMap.set('page',this.pageNumber.toString());
this.dialog.open()
hdHttp.httpReq<string>(BasicConstant.allXinyiList,hashMap).then(async (res: HdResponse<string>) => {
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<string, string> = new HashMap();
this.dialog.open()
hdHttp.httpReq<string>(BasicConstant.xinyiPrice,hashMap).then(async (res: HdResponse<string>) => {
this.dialog.close();
let json:Record<string , string> = JSON.parse(res+'') as Record<string , string>;
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<string, string> = new HashMap();
this.dialog.open()
hashMap.set('message',ChangeUtil.stringIsUndefinedAndNull(this.message)?'祝肝胆相照平台越来越好!':this.message)
hashMap.set('amount',this.selectedAmount.toString())
hdHttp.httpReq<string>(BasicConstant.createXinYiOrder,hashMap).then(async (res: HdResponse<string>) => {
this.dialog.close();
let json:Record<string , string | Record<string,string>> = JSON.parse(res+'') as Record<string , string | Record<string,string>>
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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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<string, string> = new HashMap();
readNews(uuid:string,model:newsRequestOfData) {
hdHttp.post<string>(BasicConstant.read, {
user_uuid: authStore.getUser().uuid,
news_article_uuid:uuid,
type: '1',
} as readExtraData).then(async (res: HdResponse<string>) => {
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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()

View File

@ -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<string,string>
this.dialog.open()
hdHttp.post<string>(BasicConstant.read, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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 })
})
}
}

View File

@ -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 = ''

View File

@ -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)
}
}

View File

@ -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<string, string> = new HashMap();
this.dialog.open()
hashMap.clear();
hdHttp.httpReq<string>(BasicConstant.newsRollNew,hashMap).then(async (res: HdResponse<string>) => {
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%')
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -4,7 +4,7 @@ import { window } from '@kit.ArkUI';
import notificationManager from '@ohos.notificationManager';
import { PLVMediaPlayerStartUp } from '../startup/PLVMediaPlayerStartUp';
import contextConstant from '@ohos.app.ability.contextConstant';
import { patientDbManager } from '@itcast/basic';
import { patientDbManager, WXApi, WXEventHandler } from '@itcast/basic';
import { HMRouterMgr } from '@hadss/hmrouter'
import { BusinessError } from '@kit.BasicServicesKit'
@ -16,6 +16,8 @@ export default class EntryAbility extends UIAbility {
this.checkNotificationStatus(); // 首次检查
// 初始化患者数据库
this.initPatientDatabase();
//微信
this.handleWeChatCallIfNeed(want)
this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
@ -89,4 +91,12 @@ export default class EntryAbility extends UIAbility {
// 错误处理,例如保持当前状态或设置为默认值
}
}
onNewWant(want: Want, _launchParam: AbilityConstant.LaunchParam): void {
this.handleWeChatCallIfNeed(want)
}
private handleWeChatCallIfNeed(want: Want) {
WXApi.handleWant(want, WXEventHandler)
}
}

View File

@ -0,0 +1,37 @@
import { HdNav } from '@itcast/basic'
import { router } from '@kit.ArkUI'
@Entry
@Component
struct AllDownloadPage {
build() {
Column() {
HdNav({title:'我的下载',showRightIcon:false,showRightText:false})
Column() {
Row(){
Text('课件文档')
.fontSize(16)
.layoutWeight(1)
Image($r('app.media.arrow_right'))
.width(7)
.height(10)
.margin({right:10})
}
.width('100%')
.height('calc(100% - 1vp)')
}
.width('100%')
.height(50)
.padding(10)
.backgroundColor(Color.White)
.onClick(()=>{
router.pushUrl({url:'pages/Download/KeJianDownloadPage'})
})
}
.height('100%')
.width('100%')
.backgroundColor('#f1f1f1')
}
}

View File

@ -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()
})
}
}

View File

@ -0,0 +1,14 @@
import { FlowerDetailsComp } from 'study'
@Entry
@Component
struct FlowerDetailsPage {
build() {
Column() {
FlowerDetailsComp()
}
.height('100%')
.width('100%')
}
}

View File

@ -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())
}
}

View File

@ -0,0 +1,14 @@
import { VideoPage } from 'home'
@Entry
@Component
struct MeetingPage {
build() {
Column(){
VideoPage()
}
.width('100%')
.height('100%')
}
}

View File

@ -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

View File

@ -0,0 +1,14 @@
import { NewsListComp } from 'study'
@Entry
@Component
struct GandanNewsListPage {
build() {
Column() {
NewsListComp()
}
.height('100%')
.width('100%')
}
}

View File

@ -0,0 +1,14 @@
import { NewsComp } from 'study'
@Entry
@Component
struct GandanNewsPages {
build() {
Column() {
NewsComp()
}
.height('100%')
.width('100%')
}
}

View File

@ -0,0 +1,14 @@
import { PayComp } from 'study';
@Entry
@Component
struct PayPage {
build() {
Column() {
PayComp()
}
.height('100%')
.width('100%')
}
}

View File

@ -0,0 +1,14 @@
import { SendFollowComp } from 'study'
@Entry
@Component
struct SendFollowPage {
build() {
Column() {
SendFollowComp()
}
.height('100%')
.width('100%')
}
}

View File

@ -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<string,string>
this.dialog.open()
hdHttp.post<string>(BasicConstant.getKePuCollection, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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<string,string>
this.dialog.open()
hdHttp.post<string>(type=='0'?BasicConstant.discollection:BasicConstant.collection, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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<string,string>
this.dialog.open()
hdHttp.post<string>(type=='0'?BasicConstant.disagree:BasicConstant.agree, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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
}

View File

@ -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<string, string> = new HashMap()
this.dialog.open()
hashMap.clear()
hashMap.set('file_uuid', this.params.model.uuid)
hdHttp.httpReq<string>(BasicConstant.ganDanFileDetials,hashMap).then(async (res: HdResponse<string>) => {
console.info('Response ganDanFileDetials'+res)
this.dialog.close()
let json:Record<string,string | RequestData> = JSON.parse(res+'') as Record<string,string | RequestData>;
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<string,string>
this.dialog.open()
hdHttp.post<string>(type=='0'?BasicConstant.discollection:BasicConstant.collection, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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<string, string> = new HashMap()
this.dialog.open()
hashMap.clear()
hashMap.set('file_uuid', this.params.model.uuid)
hdHttp.httpReq<string>(BasicConstant.createGanDanFileOrder,hashMap).then(async (res: HdResponse<string>) => {
console.info('Response ganDanFileDetials'+res)
this.dialog.close()
let json:Record<string,string | FileOrderData> = JSON.parse(res+'') as Record<string,string | FileOrderData>;
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<string, string> = new HashMap()
this.dialog.open()
hashMap.clear()
hashMap.set('type', '2')
hashMap.set('other_uuid',this.params.model.uuid)
hdHttp.httpReq<string>(BasicConstant.useWelfareNum,hashMap).then(async (res: HdResponse<string>) => {
console.info('Response useWelfareNum'+res)
this.dialog.close()
let json:Record<string,string > = JSON.parse(res+'') as Record<string,string>;
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
}

View File

@ -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<string,string>
this.dialog.open()
hdHttp.post<string>(BasicConstant.newsDetial, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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<string,string>
this.dialog.open()
hdHttp.post<string>(type=='0'?BasicConstant.discollection:BasicConstant.collection, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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<string,string>
this.dialog.open()
hdHttp.post<string>(type=='0'?BasicConstant.disagree:BasicConstant.agree, entity).then(async (res: HdResponse<string>) => {
this.dialog.close();
console.info('Response delConditionRecord'+res);
let json:Record<string,string | Record<string,string> | Array<Record<string,string>>> = JSON.parse(res+'') as Record<string,string | Record<string,string> | Array<Record<string,string>>>;
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
}

View File

@ -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"
]
}
}

View File

@ -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"
]
}