患者相关
This commit is contained in:
@@ -91,4 +91,6 @@ export { ChatExtModel,ChatParam } from './src/main/ets/models/ChatExtModel'
|
||||
|
||||
export { PatientListModel,PatientsData } from './src/main/ets/models/PatientListModel'
|
||||
|
||||
export { applyListCallBacl, applyListModel, applyHistoryCallBacl , historyObjectModel, historyModel } from './src/main/ets/models/ApplyModel'
|
||||
export { applyListCallBacl, applyListModel, applyHistoryCallBacl , historyObjectModel, historyModel } from './src/main/ets/models/ApplyModel'
|
||||
|
||||
export { TripleOptionDialog } from './src/main//ets/Views/TripleOptionDialog'
|
||||
@@ -53,7 +53,7 @@ export struct DefaultHintProWindows {
|
||||
Text(this.confirmTitle)
|
||||
.fontSize(15)
|
||||
.fontColor(this.confirmTitleColor)
|
||||
}.width('45%').height(30).backgroundColor(this.cancleColor)
|
||||
}.width('45%').height(30).backgroundColor(this.confirmColor)
|
||||
.onClick(() => {
|
||||
this.selectedButton(1)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import { router } from "@kit.ArkUI";
|
||||
import { promptAction, router } from "@kit.ArkUI";
|
||||
import http from '@ohos.net.http'
|
||||
import fileio from '@ohos.fileio'
|
||||
import prompt from '@ohos.promptAction'
|
||||
@@ -8,11 +8,15 @@ import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { BasicConstant } from "../constants/BasicConstant";
|
||||
import { ViewImageInfo } from "../models/ViewImageInfo";
|
||||
import { PermissionsUtils } from "../utils/PermissionsUtils";
|
||||
import { fileIo, fileUri } from "@kit.CoreFileKit";
|
||||
import { photoAccessHelper } from "@kit.MediaLibraryKit";
|
||||
import fs from '@ohos.file.fs'
|
||||
|
||||
|
||||
@Component
|
||||
export struct PreviewPhotos {
|
||||
|
||||
private imageBuffer?: ArrayBuffer
|
||||
@State
|
||||
imgList: ViewImageInfo[]=[] // 传入图片数组
|
||||
@State params:paramPhoto= router.getParams() as paramPhoto
|
||||
@@ -46,54 +50,85 @@ export struct PreviewPhotos {
|
||||
}
|
||||
}
|
||||
|
||||
// 下载图片方法(伪代码,需根据实际API实现)
|
||||
async downloadImage(url: string) {
|
||||
// // 下载图片方法(伪代码,需根据实际API实现)
|
||||
// async downloadImage(url: string) {
|
||||
// try {
|
||||
// // 1. 检查权限
|
||||
// const hasPermission = await this.checkStoragePermission();
|
||||
// if (!hasPermission) {
|
||||
// // 申请权限
|
||||
// const granted = await this.requestStoragePermission();
|
||||
// if (!granted) {
|
||||
// prompt.showToast({ message: $r('app.string.netease_permission_denied_tips') });
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 显示下载中提示
|
||||
// prompt.showToast({ message: $r('app.string.netease_saving_image_tips') });
|
||||
//
|
||||
// // 2. 下载图片
|
||||
// const httpRequest = http.createHttp()
|
||||
// const response = await httpRequest.request(url, {
|
||||
// method: http.RequestMethod.GET,
|
||||
// expectDataType: http.HttpDataType.ARRAY_BUFFER,
|
||||
// connectTimeout: 30000, // 30秒连接超时
|
||||
// readTimeout: 30000, // 30秒读取超时
|
||||
// })
|
||||
// httpRequest.destroy()
|
||||
//
|
||||
// if (response.responseCode !== 200) {
|
||||
// prompt.showToast({ message: $r('app.string.netease_download_failed_tips') })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 3. 写入到公共图片目录
|
||||
// const fileName = 'img_' + Date.now() + '.jpg'
|
||||
// const filePath = '/storage/media/100/local/photos/' + fileName
|
||||
//
|
||||
// try {
|
||||
// const fd = await fileio.open(filePath, 0o2 | 0o100) // 写入+创建
|
||||
// await fileio.write(fd, new Uint8Array(response.result as ArrayBuffer))
|
||||
// await fileio.close(fd)
|
||||
// prompt.showToast({ message: $r('app.string.netease_save_success_tips') })
|
||||
// } catch (fileError) {
|
||||
// console.error('文件写入失败:', fileError);
|
||||
// prompt.showToast({ message: $r('app.string.netease_save_failed_tips') })
|
||||
// }
|
||||
// } catch (e) {
|
||||
// console.error('下载图片失败:', e);
|
||||
// prompt.showToast({ message: $r('app.string.netease_save_error_tips') })
|
||||
// }
|
||||
// }
|
||||
|
||||
async downloadImage(url: string,result: SaveButtonOnClickResult) {
|
||||
if (result !== SaveButtonOnClickResult.SUCCESS) {
|
||||
promptAction.showToast({ message: '权限获取失败', duration: 2000 })
|
||||
return
|
||||
}
|
||||
const context = getContext(this) as common.UIAbilityContext
|
||||
try {
|
||||
// 1. 检查权限
|
||||
const hasPermission = await this.checkStoragePermission();
|
||||
if (!hasPermission) {
|
||||
// 申请权限
|
||||
const granted = await this.requestStoragePermission();
|
||||
if (!granted) {
|
||||
prompt.showToast({ message: $r('app.string.netease_permission_denied_tips') });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 显示下载中提示
|
||||
prompt.showToast({ message: $r('app.string.netease_saving_image_tips') });
|
||||
|
||||
// 2. 下载图片
|
||||
const httpRequest = http.createHttp()
|
||||
const response = await httpRequest.request(url, {
|
||||
method: http.RequestMethod.GET,
|
||||
expectDataType: http.HttpDataType.ARRAY_BUFFER,
|
||||
connectTimeout: 30000, // 30秒连接超时
|
||||
readTimeout: 30000, // 30秒读取超时
|
||||
expectDataType: http.HttpDataType.ARRAY_BUFFER
|
||||
})
|
||||
httpRequest.destroy()
|
||||
this.imageBuffer = response.result as ArrayBuffer
|
||||
const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context)
|
||||
const uri = await phAccessHelper.createAsset(
|
||||
photoAccessHelper.PhotoType.IMAGE,
|
||||
'jpg' // 文件扩展名
|
||||
)
|
||||
|
||||
if (response.responseCode !== 200) {
|
||||
prompt.showToast({ message: $r('app.string.netease_download_failed_tips') })
|
||||
return
|
||||
}
|
||||
const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
|
||||
await fs.write(file.fd, this.imageBuffer)
|
||||
await fs.close(file.fd)
|
||||
|
||||
// 3. 写入到公共图片目录
|
||||
const fileName = 'img_' + Date.now() + '.jpg'
|
||||
const filePath = '/storage/media/100/local/photos/' + fileName
|
||||
|
||||
try {
|
||||
const fd = await fileio.open(filePath, 0o2 | 0o100) // 写入+创建
|
||||
await fileio.write(fd, new Uint8Array(response.result as ArrayBuffer))
|
||||
await fileio.close(fd)
|
||||
prompt.showToast({ message: $r('app.string.netease_save_success_tips') })
|
||||
} catch (fileError) {
|
||||
console.error('文件写入失败:', fileError);
|
||||
prompt.showToast({ message: $r('app.string.netease_save_failed_tips') })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('下载图片失败:', e);
|
||||
prompt.showToast({ message: $r('app.string.netease_save_error_tips') })
|
||||
promptAction.showToast({ message: '图片已保存到相册', duration: 2000 })
|
||||
} catch (error) {
|
||||
const err = error as BusinessError
|
||||
console.error(`保存失败: Code=${err.code}, Message=${err.message}`)
|
||||
promptAction.showToast({ message: `保存失败: ${err.code}` })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,25 +200,29 @@ export struct PreviewPhotos {
|
||||
.onClick(() => {
|
||||
router.back()
|
||||
})
|
||||
Row()
|
||||
{
|
||||
Image($r('app.media.ic_topbar_save')).width(30).height(30)
|
||||
.onClick(()=>{
|
||||
this.downloadImage( this.imgList[this.previewIndex].url?(BasicConstant.urlHtml + this.imgList[this.previewIndex].url): this.imgList[this.previewIndex].url)
|
||||
})
|
||||
Row() {
|
||||
SaveButton({icon:SaveIconStyle.FULL_FILLED,buttonType:ButtonType.Capsule})
|
||||
.iconSize(25)
|
||||
.iconColor($r('app.color.main_color'))
|
||||
.backgroundColor('rgba(255,255,255,0.01)')
|
||||
.width(50)
|
||||
.height(30)
|
||||
.onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
|
||||
const url = this.imgList[this.previewIndex].url
|
||||
? (BasicConstant.urlHtml + this.imgList[this.previewIndex].url)
|
||||
: this.imgList[this.previewIndex].url;
|
||||
this.downloadImage(url,result)
|
||||
})
|
||||
Blank()
|
||||
|
||||
Text(`${this.previewIndex + 1}/${this.imgList.length}`)
|
||||
.fontSize(18)
|
||||
.fontColor($r('app.color.top_title'))
|
||||
|
||||
|
||||
|
||||
}
|
||||
.visibility(this.downLoad?Visibility.Visible:Visibility.Hidden)
|
||||
.height(30)
|
||||
.width('100%')
|
||||
.padding({ left:20,right:20 })
|
||||
.padding({ left:10,right:20 })
|
||||
.margin({bottom:40})
|
||||
.alignRules({bottom: { anchor: "__container__", align: VerticalAlign.Bottom }} )
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
|
||||
@CustomDialog
|
||||
export struct TripleOptionDialog {
|
||||
controller: CustomDialogController; // 必须包含的控制器属性
|
||||
@Prop title: string = ''
|
||||
@Prop subTitle:string = ''
|
||||
@Prop oneButtonTitle:string = ''
|
||||
@Prop twoButtonTitle:string = ''
|
||||
|
||||
private buttonSelected: (actionType:string) => void = () => {};
|
||||
|
||||
// 按钮点击事件处理
|
||||
private handleAction(actionType: string) {
|
||||
this.buttonSelected(actionType)
|
||||
this.controller.close(); // 关闭弹窗
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Text(this.title)
|
||||
.fontSize(20)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.margin({ top: 20 })
|
||||
if (this.subTitle.length) {
|
||||
Text(this.subTitle)
|
||||
.fontSize(15)
|
||||
.padding({top:5})
|
||||
}
|
||||
Column() {
|
||||
Blank()
|
||||
.width('100%')
|
||||
.height(1)
|
||||
.backgroundColor('#f4f4f4')
|
||||
Text(this.oneButtonTitle)
|
||||
.height(40)
|
||||
.fontSize(14)
|
||||
.fontColor('#333333')
|
||||
.onClick(() => this.handleAction(this.oneButtonTitle))
|
||||
Blank()
|
||||
.width('100%')
|
||||
.height(1)
|
||||
.backgroundColor('#f4f4f4')
|
||||
Text(this.twoButtonTitle)
|
||||
.height(40)
|
||||
.fontSize(14)
|
||||
.fontColor('#333333')
|
||||
.onClick(() => this.handleAction(this.twoButtonTitle))
|
||||
Blank()
|
||||
.width('100%')
|
||||
.height(1)
|
||||
.backgroundColor('#f4f4f4')
|
||||
Text('取消')
|
||||
.height(40)
|
||||
.fontSize(14)
|
||||
.fontColor('#999999')
|
||||
.onClick(() => this.controller.close())
|
||||
}
|
||||
.width('100%')
|
||||
.margin({ top:20,bottom: 20 })
|
||||
}
|
||||
.backgroundColor(Color.Transparent)
|
||||
.borderRadius(16)
|
||||
.width('100%')
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,12 @@ export class BasicConstant {
|
||||
static readonly updateNicknameNote = BasicConstant.urlExpertAPI+'updateNicknameNote'
|
||||
static readonly applyListOperate = BasicConstant.urlExpert+'applyListOperate'
|
||||
static readonly patientListNoInThisGroup = BasicConstant.urlExpertAPI+'patientListNoInThisGroup'
|
||||
static readonly patientList = BasicConstant.urlExpert+'patientList'
|
||||
static readonly listGroupSendMsg = BasicConstant.urlExpertAPI+'listGroupSendMsg'
|
||||
static readonly delGroupSendMsg = BasicConstant.urlExpertAPI+'delGroupSendMsg'
|
||||
static readonly addGroupSendMsg4YunXin = BasicConstant.urlExpertAPI+'addGroupSendMsg4YunXin'
|
||||
static readonly addConditionRecord = BasicConstant.urlExpert+'addConditionRecord'
|
||||
static readonly upConditionRecord = BasicConstant.urlExpert+'upConditionRecord'
|
||||
static readonly patientCard = BasicConstant.urlExpertAPI+'patientCard'
|
||||
static readonly toAddNickname = BasicConstant.urlExpert+'toAddNickname'
|
||||
static readonly cancelRes = BasicConstant.urlExpert+'cancelRes'
|
||||
|
||||
@@ -9,6 +9,7 @@ import util from '@ohos.util';
|
||||
import { i18n } from '@kit.LocalizationKit';
|
||||
import { connection } from '@kit.NetworkKit';
|
||||
import http from '@ohos.net.http'
|
||||
import {BasicConstant} from '../constants/BasicConstant'
|
||||
export class ChangeUtil {
|
||||
/**
|
||||
* 将HashMap转成JsonString
|
||||
@@ -98,67 +99,6 @@ export class ChangeUtil {
|
||||
|
||||
return bf
|
||||
}
|
||||
/**
|
||||
* 将图片转换为base64字符串
|
||||
* @param imageUri 图片URI
|
||||
* @returns Promise<string> base64字符串
|
||||
*/
|
||||
static async imageToBase64(imageUri: string): Promise<string> {
|
||||
// 1. 验证URI有效性
|
||||
if (!imageUri || !imageUri.startsWith('file://')) {
|
||||
throw new Error('无效的图片URI,必须以file://开头');
|
||||
}
|
||||
let imageSource: image.ImageSource | undefined;
|
||||
let pixelMap: image.PixelMap | undefined;
|
||||
let imagePacker: image.ImagePacker | undefined;
|
||||
try {
|
||||
const file = fs.openSync(imageUri, fs.OpenMode.READ_ONLY);
|
||||
const imageSource = image.createImageSource(file.fd);
|
||||
if (!imageSource) {
|
||||
throw new Error('创建ImageSource失败,请检查图片路径');
|
||||
}
|
||||
logger.info('正在获取图片信息...');
|
||||
const imageInfo = await imageSource.getImageInfo();
|
||||
logger.info(`图片尺寸: ${imageInfo.size.width}x${imageInfo.size.height}`);
|
||||
pixelMap = await imageSource.createPixelMap({
|
||||
desiredSize: {
|
||||
width: imageInfo.size.width,
|
||||
height: imageInfo.size.height
|
||||
}
|
||||
});
|
||||
if (!pixelMap) {
|
||||
throw new Error('创建PixelMap失败');
|
||||
}
|
||||
// 5. 压缩图片
|
||||
imagePacker = image.createImagePacker();
|
||||
const packOpts: image.PackingOption = {
|
||||
format: "image/jpeg",
|
||||
quality: 80 // 适当提高质量保证清晰度
|
||||
};
|
||||
logger.info('正在压缩图片...');
|
||||
const arrayBuffer = await imagePacker.packing(pixelMap, packOpts);
|
||||
const unit8Array = new Uint8Array(arrayBuffer);
|
||||
let binary = '';
|
||||
unit8Array.forEach(byte => {
|
||||
binary += String.fromCharCode(byte);
|
||||
});
|
||||
const base64String = Base64Util.encodeToStrSync(binary);
|
||||
logger.info(`图片转换成功,大小: ${Math.round(base64String.length / 1024)}KB`);
|
||||
return base64String;
|
||||
} catch (error) {
|
||||
logger.error('图片处理失败: ' + JSON.stringify(error));
|
||||
throw new Error(`图片处理失败: ${error.message}`);
|
||||
} finally {
|
||||
// 7. 确保释放资源
|
||||
try {
|
||||
pixelMap?.release();
|
||||
imageSource?.release();
|
||||
imagePacker?.release();
|
||||
} catch (e) {
|
||||
logger.error('资源释放异常: ' + JSON.stringify(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static isLetter(char: string): boolean {
|
||||
if (char.length !== 1) return false;
|
||||
@@ -244,4 +184,107 @@ export class ChangeUtil {
|
||||
arr[arr.length - 1] = first; // 首位移至末尾
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将URI或URL数组转换为Base64字符串数组
|
||||
* @param items - 包含文件URI或网络URL的数组
|
||||
* @returns Promise<string[]> - Base64字符串数组
|
||||
*/
|
||||
static async convertUrisOrUrlsToBase64(items: string[]): Promise<string[]> {
|
||||
const results: string[] = [];
|
||||
|
||||
for (const item of items) {
|
||||
try {
|
||||
let arrayBuffer: ArrayBuffer;
|
||||
let mimeType = 'image/jpeg'; // 默认MIME类型
|
||||
// 处理本地文件URI
|
||||
if (item.startsWith('file://')) {// || !item.includes('://')
|
||||
arrayBuffer = await ChangeUtil.readLocalFile(item);
|
||||
}
|
||||
// 处理网络URL
|
||||
else if (item.startsWith('http://') || item.startsWith('https://') || ChangeUtil.isImageFileByRegex(item)) {
|
||||
arrayBuffer = await ChangeUtil.downloadNetworkResource(item);
|
||||
}
|
||||
// 处理其他类型资源
|
||||
else {
|
||||
throw new Error(`Unsupported URI scheme: ${item}`);
|
||||
}
|
||||
// 关键优化:添加图片压缩步骤[6,8](@ref)
|
||||
const compressedBuffer = await ChangeUtil.compression(
|
||||
arrayBuffer,
|
||||
mimeType,
|
||||
0.5 // 压缩质量为50%
|
||||
);
|
||||
// 转换为Base64
|
||||
results.push(ChangeUtil.convertToBase64(compressedBuffer));
|
||||
} catch (err) {
|
||||
console.error(`转换失败: ${JSON.stringify(err)}`);
|
||||
results.push(''); // 失败时返回空字符串
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取本地文件到ArrayBuffer
|
||||
* @param uri - 文件URI
|
||||
* @returns Promise<ArrayBuffer>
|
||||
*/
|
||||
static async readLocalFile(uri: string): Promise<ArrayBuffer> {
|
||||
try {
|
||||
// 打开文件
|
||||
const file = fs.openSync(uri, fs.OpenMode.READ_ONLY);
|
||||
// 获取文件大小
|
||||
const stat = fs.statSync(file.fd);
|
||||
const size = stat.size;
|
||||
// 创建缓冲区并读取数据
|
||||
const buffer = new ArrayBuffer(size);
|
||||
fs.readSync(file.fd, buffer);
|
||||
// 关闭文件
|
||||
fs.closeSync(file);
|
||||
return buffer;
|
||||
} catch (err) {
|
||||
throw new Error(`文件读取失败: ${JSON.stringify(err)}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载网络资源到ArrayBuffer
|
||||
* @param url - 资源URL
|
||||
* @returns Promise<ArrayBuffer>
|
||||
*/
|
||||
static async downloadNetworkResource(url: string): Promise<ArrayBuffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const httpRequest = http.createHttp();
|
||||
httpRequest.request(
|
||||
BasicConstant.urlImage+url,
|
||||
{
|
||||
method: http.RequestMethod.GET
|
||||
},
|
||||
(err, data) => {
|
||||
httpRequest.destroy();
|
||||
if (err) {
|
||||
reject(new Error(`网络请求失败: ${JSON.stringify(err)}`));
|
||||
return;
|
||||
}
|
||||
if (data.responseCode === 200) {
|
||||
resolve(data.result as ArrayBuffer);
|
||||
} else {
|
||||
reject(new Error(`HTTP错误: ${data.responseCode}`));
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
static convertToBase64(buffer: ArrayBuffer): string {
|
||||
const helper = new util.Base64Helper();
|
||||
const uint8Array = new Uint8Array(buffer);
|
||||
return helper.encodeToStringSync(uint8Array);
|
||||
}
|
||||
|
||||
static isImageFileByRegex(path: string): boolean {
|
||||
const pattern = /\.(jpg|jpeg|png|gif|bmp|webp)$/i;
|
||||
return pattern.test(path);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user