在移动医疗应用开发中,实现便捷的多媒体交互功能对于提升用户体验至关重要。本文将详细介绍如何在医疗预约系统中集成录音和图片上传功能,结合 Vue3 和 Uniapp 框架,打造流畅的患者就诊记录交互体验。
功能概述
我们实现的医疗记录页面包含以下核心功能:
- 就诊人信息管理与切换
- 就诊详情展示
- 图片上传功能
- 录音录制与上传功能
- 预约确认流程
下面我们将重点解析图片上传和录音功能的实现细节,这两个功能是提升医疗记录丰富性的关键。
界面设计与布局
首先来看整体界面结构,我们采用了分区设计,将不同功能模块清晰分离:
<template>
<div class="medical-record-container">
<!-- 就诊人信息区域 -->
<div class="patient-info">
<!-- 就诊人信息内容 -->
</div>
<!-- 就诊详情区域 -->
<div class="visit-details">
<!-- 就诊详情内容 -->
<!-- 录音播放区域 -->
<div class="detail-item">
<span class="label">录音</span>
<span class="value" style="display: flex;align-items: center;gap: 10px;" @click="playAudio">
<uv-icon size="28" color="rgb(42,130,228)" name="play-circle-fill"></uv-icon> {{ audioDuration || '00:00' }}
</span>
</div>
<!-- 添加图片、录音按钮区域 -->
<div class="action-btns">
<div class="action-btn" @click="openPopups" style="border-right: 1px solid #ddd;">添加图片</div>
<div class="action-btn" @click="openPopupes">添加录音</div>
</div>
</div>
<!-- 文字描述输入区域 -->
<div class="desc-section">
<!-- 文字描述内容 -->
</div>
<!-- 费用及确认区域 -->
<div class="footer">
<!-- 费用及确认按钮 -->
</div>
<!-- 图片上传弹窗 -->
<uv-popup ref="popups" mode="bottom">
<!-- 图片上传组件 -->
</uv-popup>
<!-- 录音弹窗 -->
<uv-popup ref="popupes" mode="bottom">
<!-- 录音组件 -->
</uv-popup>
</div>
</template>
界面设计遵循了医疗应用的专业性与易用性原则,采用清晰的视觉层级和直观的交互方式,让用户能够轻松完成图片和录音的添加操作。
图片上传功能实现
图片上传功能允许用户添加医疗相关的图片资料,如检查报告、处方等,实现代码如下:
// 图片上传相关状态
const fileList1 = ref([]);
const imgurl = ref('');
// 打开图片上传弹窗
const openPopups = () => {
popups.value?.open();
};
// 删除图片
const deletePic = (event) => {
fileList1.value.splice(event.index, 1);
};
// 选择图片后处理
const afterRead = async (event) => {
// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file);
let fileListLen = fileList1.value.length;
lists.map((item) => {
fileList1.value.push({
...item,
status: 'uploading',
message: '上传中'
});
});
for (let i = 0; i < lists.length; i++) {
const result = await uploadFilePromise(lists[i].url);
let item = fileList1.value[fileListLen];
fileList1.value.splice(fileListLen, 1, Object.assign(item, {
status: 'success',
message: '',
url: result
}));
fileListLen++;
}
};
// 上传文件Promise封装
const uploadFilePromise = (urls) => {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: 'https://yiliao.kuxia.top/pc/Fileimg/file',
filePath: urls,
name: 'file',
formData: {
user: 'test'
},
success: (res) => {
setTimeout(() => {
const response = JSON.parse(res.data);
resolve(response.data.url);
imgurl.value = response.data.url;
}, 1000);
},
fail: (err) => {
reject(err);
}
});
});
};
图片上传流程设计考虑了以下几点:
- 使用弹窗形式展示上传界面,不占用主界面空间
- 实现了上传进度显示,提升用户体验
- 支持图片删除操作,方便用户纠错
- 通过 Promise 封装上传过程,便于异步流程控制
录音功能实现
录音功能是医疗记录中的重要补充,能够记录医生的口头医嘱或患者的症状描述,实现代码如下:
// 录音相关状态和变量
const audioDuration = ref('00:00');
const isRecording = ref(false);
const recorderManager = ref(null);
const audioPath = ref('');
const recordTime = ref(0);
const recordTimer = ref(null);
const audioUploaded = ref(false);
const audioUrl = ref('');
// 初始化录音管理器
const initRecorder = () => {
recorderManager.value = uni.getRecorderManager();
recorderManager.value.onStart(() => {
console.log('录音开始');
isRecording.value = true;
startRecordTimer();
});
recorderManager.value.onStop((res) => {
console.log('录音结束', res);
isRecording.value = false;
stopRecordTimer();
audioPath.value = res.tempFilePath;
// 更新显示的录音时长
updateAudioDuration(res.duration);
});
recorderManager.value.onError((err) => {
console.error('录音失败:', err);
isRecording.value = false;
stopRecordTimer();
uni.showToast({
title: '录音失败',
icon: 'none'
});
});
};
// 开始录音计时器
const startRecordTimer = () => {
recordTime.value = 0;
recordTimer.value = setInterval(() => {
recordTime.value++;
updateAudioDuration(recordTime.value * 1000);
}, 1000);
};
// 停止录音计时器
const stopRecordTimer = () => {
if (recordTimer.value) {
clearInterval(recordTimer.value);
recordTimer.value = null;
}
};
// 更新录音时长显示
const updateAudioDuration = (durationMs) => {
const durationSec = Math.floor(durationMs / 1000);
const minutes = Math.floor(durationSec / 60).toString().padStart(2, '0');
const seconds = (durationSec % 60).toString().padStart(2, '0');
audioDuration.value = `${minutes}:${seconds}`;
};
// 点击录音按钮事件
const toggleRecord = () => {
if (isRecording.value) {
// 停止录音
recorderManager.value.stop();
} else {
// 开始录音
recorderManager.value.start({
format: 'mp3',
duration: 600000, // 最长10分钟
sampleRate: 44100,
numberOfChannels: 1,
encodeBitRate: 192000
});
audioUploaded.value = false;
}
};
// 确认上传录音
const confirmUpload = async () => {
if (!audioPath.value) {
uni.showToast({
title: '请先录制音频',
icon: 'none'
});
return;
}
try {
uni.showLoading({
title: '上传中...'
});
// 上传录音文件
const uploadedUrl = await uploadAudioFile(audioPath.value);
uni.showToast({
title: '上传成功',
icon: 'success'
});
audioUploaded.value = true;
audioUrl.value = uploadedUrl;
popupes.value?.close();
} catch (error) {
console.error('上传失败:', error);
uni.showToast({
title: '上传失败',
icon: 'none'
});
} finally {
uni.hideLoading();
}
};
// 播放录音
const playAudio = () => {
if (!audioPath.value) {
uni.showToast({
title: '暂无录音',
icon: 'none'
});
return;
}
const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.src = audioPath.value;
innerAudioContext.play();
innerAudioContext.onError((res) => {
console.error('播放失败:', res);
uni.showToast({
title: '播放失败',
icon: 'none'
});
});
};
录音功能的设计亮点:
- 直观的录音时长显示,采用分:秒格式
- 录音状态清晰可见,通过颜色变化提示用户
- 完整的错误处理机制,确保录音过程稳定
- 支持录音播放功能,方便用户确认录音内容
数据提交与预约确认
最后,我们需要将所有信息(包括文字描述、图片和录音)提交到服务器,完成预约流程:
const confirm = async () => {
if (!visitdata.value?.card) {
uni.showToast({
title: '请选择就诊人',
icon: 'none'
});
return;
}
try {
console.log({
user_id: uni.getStorageSync('userInfo').id,
card: visitdata.value.card,
depart_id: department.value?.id,
doctor_id: doctor_id,
price: doctor.value?.doctorInfo?.money,
trends: desc.value,
img: imgurl.value,
audio: audioUrl.value,
status: 1,
create_time: time_date,
time: time_value,
});
const res = await addRegister({
// 提交的数据包括图片和录音的URL
user_id: uni.getStorageSync('userInfo').id,
card: visitdata.value.card,
depart_id: department.value?.id,
doctor_id: doctor_id,
price: doctor.value?.doctorInfo?.money,
trends: desc.value,
img: imgurl.value,
audio: audioUrl.value,
status: 1,
create_time: time_date,
time: time_value,
});
console.log(res);
if (res.code == 1) {
// 显示成功提示弹窗
successModal.value.open();
} else {
uni.showToast({
title: res.msg,
icon: 'none'
});
}
} catch (err) {
console.log(err);
uni.showToast({
title: '预约失败',
icon: 'none'
});
}
};
总结与优化建议
本文实现的图片和录音上传功能,为医疗预约系统增添了丰富的多媒体交互能力。在实际应用中,还可以考虑以下优化方向:
- 实现图片压缩功能,减少上传流量和时间
- 增加录音转文字功能,提高记录的可搜索性
- 支持多图上传和多段录音,满足复杂医疗场景需求
- 实现上传中断后的断点续传功能
通过这些功能的实现,医疗应用能够更好地服务于医患双方,提高医疗记录的完整性和准确性,为远程医疗和复诊提供更全面的参考资料。