mirror of
https://gitee.com/xiongmao1988/rax-medical.git
synced 2025-08-24 13:04:57 +08:00
add: 一期代码
This commit is contained in:
parent
d90d5e4eef
commit
55320a8dd3
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -7,7 +7,7 @@ import ElementPlus, {ElDialog} from 'element-plus';
|
|||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
import TableAbility from '@/components/table-ability.vue'
|
||||
|
||||
|
||||
import './assets/font/all.css'
|
||||
import 'element-plus/dist/index.css';
|
||||
import './assets/css/global.scss';
|
||||
import './assets/font/iconfont.css';
|
||||
|
|
|
@ -4,7 +4,7 @@ import {ElMessage} from "element-plus";
|
|||
|
||||
// 本地调试版本:
|
||||
const vitalUrl = "ws://" + window.location.host + "/socket.io/admin/rax/vitalSignsMedicine?token=" + Session.getToken()
|
||||
const medicineUrl = "ws://" + window.location.host + "/socket.io/admin/rax/addMedicine?token=" + Session.getToken()
|
||||
// const medicineUrl = "ws://" + window.location.host + "/socket.io/admin/rax/addMedicine?token=" + Session.getToken()
|
||||
const chatUrl = "ws://" + window.location.host + "/socket.io/admin/rax/chatRoom?token=" + Session.getToken()
|
||||
|
||||
// 服务器部署版本
|
||||
|
@ -242,7 +242,7 @@ export const useRemoteWsStore = defineStore("remoteWs", {
|
|||
patientName: name,
|
||||
idNum: id,
|
||||
date: date,
|
||||
msg,
|
||||
msg: msg,
|
||||
msgType: "msg"
|
||||
}
|
||||
patient.chatWS.send(JSON.stringify(params))
|
||||
|
@ -256,6 +256,30 @@ export const useRemoteWsStore = defineStore("remoteWs", {
|
|||
})
|
||||
}
|
||||
},
|
||||
|
||||
sendAudio(name: string, id: string, date: string, audio: any, index: number, cb: any) {
|
||||
const patient: any = this.patient[name + id + date + index]
|
||||
if (patient) {
|
||||
const params = {
|
||||
patientName: name,
|
||||
idNum: id,
|
||||
date: date,
|
||||
content: audio,
|
||||
msgType: "audio"
|
||||
}
|
||||
patient.chatWS.send(JSON.stringify(params))
|
||||
cb({
|
||||
status: 0
|
||||
})
|
||||
} else {
|
||||
cb({
|
||||
status: 1,
|
||||
msg: "已断开连接"
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
disconnectVital(name: string, id: string, date: string, index: number) {
|
||||
const patient: any = this.patient[name + id + date + index]
|
||||
if (patient && patient.vitalWS) {
|
||||
|
@ -289,7 +313,7 @@ export const useRemoteWsStore = defineStore("remoteWs", {
|
|||
patient.chatWS.onmessage = (e: any) => {
|
||||
if (e && e.data) {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.msgType == "msg") {
|
||||
if (data.msgType == "msg" || data.msgType == "audio") {
|
||||
cb(e)
|
||||
} else {
|
||||
patient.chatWS.send(JSON.stringify({msgType: "heartbeat"}))
|
||||
|
|
|
@ -100,7 +100,10 @@
|
|||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="registerParams.phone" placeholder="请输入手机号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="医院" prop="hospital">
|
||||
<el-form-item label="医院" prop="hospital" class="before-hospital">
|
||||
<template #label>
|
||||
<span style="color: #f56c6c;">* </span>医院
|
||||
</template>
|
||||
<el-select v-model="registerParams.hospitalId" style="width: 100%;">
|
||||
<el-option v-for="item in hospitals" :key="item.id" :label="item.name"
|
||||
:value="item.id"/>
|
||||
|
@ -352,7 +355,7 @@ function getCaptchaCode() {
|
|||
}
|
||||
|
||||
function refreshImg() {
|
||||
randomStr = v4()
|
||||
randomStr = v4();
|
||||
captchaImgUrl.value = '/api/admin/code/textImage?randomStr=' + randomStr
|
||||
}
|
||||
|
||||
|
@ -564,6 +567,7 @@ const loginPost = (data: any) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.model {
|
||||
display: flex;
|
||||
text-align: center;
|
||||
|
@ -573,5 +577,7 @@ const loginPost = (data: any) => {
|
|||
color: #8c9094;
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -186,8 +186,9 @@ function getData() {
|
|||
remoteWsStore.subscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date, currentIndex, (res: any) => {
|
||||
if (res && res.data) {
|
||||
const data = JSON.parse(res.data);
|
||||
if (data.vitalSignsList && data.vitalSignsList.length > 0) {
|
||||
Object.assign(patientInfo.value, data.vitalSignsList[0]);
|
||||
// if (data.vitalSignsList && data.vitalSignsList.length > 0) {
|
||||
if (data.vitalSignsList) {
|
||||
Object.assign(patientInfo.value, data.vitalSignsList);
|
||||
patientInfo.value.state = (patientInfo.value.BIS_except || patientInfo.value.SBP_except ||
|
||||
patientInfo.value.DBP_except || patientInfo.value.HR_except);
|
||||
setLog(patientInfo.value)
|
||||
|
|
|
@ -75,11 +75,13 @@
|
|||
<!-- <source src="@/assets/medical.mp4" type="video/mp4"/>-->
|
||||
<!-- </video>-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!--聊天框 -->
|
||||
<div class="message-box">
|
||||
<ul ref="msgLog" class="message-log">
|
||||
<li v-for="(item, index) in mssageList" :key="'msg-log-' + index"
|
||||
:class="{ 'align-right': item.createUser == userInfo.account }">
|
||||
<span>{{ item.content }}</span>
|
||||
<span>{{ item.msg }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="send-box">
|
||||
|
@ -87,6 +89,30 @@
|
|||
<el-button color="#006080" @click="sendMsg">发送消息</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 聊天框, 添加音频组件 -->
|
||||
<!--<div class="message-box">-->
|
||||
<!-- <ul ref="msgLog" class="message-log">-->
|
||||
<!-- <li v-for="(item, index) in mssageList" :key="'msg-log-' + index"-->
|
||||
<!-- :class="{ 'align-right': item.createUser == userInfo.account }">-->
|
||||
<!-- <span v-if="item.msgType === 'msg'">{{ item.content }}</span>-->
|
||||
<!-- <audio v-if="item.msgType === 'audio'" controls>-->
|
||||
<!-- <source :src="'data:audio/mpeg;base64,' + item.content" type="audio/mpeg"/>-->
|
||||
<!-- 您的浏览器不支持音频元素。-->
|
||||
<!-- </audio>-->
|
||||
<!-- </li>-->
|
||||
<!-- </ul>-->
|
||||
<!-- <div class="send-box">-->
|
||||
<!-- <el-input style="width: 60%" v-model="msgVal" placeholder="请输入消息"/>-->
|
||||
<!-- <el-button style="color: #006080; width: 20%; margin-left: 10px;" @click="sendMsg">发送消息</el-button>-->
|
||||
<!-- <el-button style="color: #006080; width: 20%" class="mic-btn" @mousedown="startRecording" @mouseup="stopRecording"-->
|
||||
<!-- @mouseleave="stopRecording">录音</el-button>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="isRecording" class="mic-icon">-->
|
||||
<!-- <i class="fa-solid fa-microphone"></i> <!– 麦克风图标 –>-->
|
||||
<!-- 正在录音... {{ remainingTime }} 秒剩余-->
|
||||
<!-- </div>-->
|
||||
<!--</div>-->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- table1 -->
|
||||
|
@ -202,6 +228,7 @@ import imgHeartAlarm from '@/assets/imgs/heart_alarm.png';
|
|||
import {useRemoteWsStore} from "@/stores/remote-ws-store";
|
||||
import {useUserStore} from "@/stores/user-info-store";
|
||||
import {getPatientInfo, getPatientInfoM} from "@/api/patient";
|
||||
import axios from "axios";
|
||||
|
||||
|
||||
const router = useRouter()
|
||||
|
@ -244,8 +271,6 @@ const heartAlarm = ref(false); // 心脏警告
|
|||
const isAIDose = ref(false); // 是否AI给药
|
||||
const isVideoPlay = ref(false); // 视频是否播放
|
||||
const videoSrc = ref('https://www.runoob.com/try/demo_source/mov_bbb.mp4');
|
||||
const mssageList = ref([] as any);
|
||||
const msgVal = ref('');
|
||||
const unusual = ref([] as any);
|
||||
const fixedTableData = ref([] as any[]);
|
||||
const varTableData = ref([] as any[]);
|
||||
|
@ -260,6 +285,7 @@ onMounted(() => {
|
|||
router.replace('/remote-manage/remote-manage');
|
||||
return;
|
||||
}
|
||||
// msgLogScrollBottom();
|
||||
msgLogScrollBottom();
|
||||
initScale();
|
||||
subscribeWS();
|
||||
|
@ -270,7 +296,7 @@ onUnmounted(() => {
|
|||
remoteWsStore.unsubscribeChat(currentRemote.value.patient, currentRemote.value.patientId, currentRemote.value.date, currentIndex);
|
||||
// remoteWsStore.unsubscribeMedicine(currentRemote.value.patient, currentRemote.value.patientId, currentRemote.value.date, index);
|
||||
remoteWsStore.unsubscribeVital(currentRemote.value.patient, currentRemote.value.patientId, currentRemote.value.date, currentIndex);
|
||||
remoteWsStore.disconnectChat(currentRemote.value.patient, currentRemote.value.patientId, currentRemote.value.date, currentIndex)
|
||||
// remoteWsStore.disconnectChat(currentRemote.value.patient, currentRemote.value.patientId, currentRemote.value.date, currentIndex)
|
||||
if (!router.currentRoute.value.path.startsWith("/remote-manage/")) {
|
||||
const tasks: any = remoteWsStore.getRemoteTask()
|
||||
tasks.forEach((task: any) => {
|
||||
|
@ -326,7 +352,8 @@ const subscribeChat = () => {
|
|||
function (res: any) {
|
||||
const chatObj = JSON.parse(res.data);
|
||||
if (chatObj.history) {
|
||||
mssageList.value = chatObj.history;
|
||||
// mssageList.value = chatObj.history;
|
||||
mssageList.value = chatObj;
|
||||
} else {
|
||||
mssageList.value.push(JSON.parse(res.data));
|
||||
}
|
||||
|
@ -528,6 +555,8 @@ const playPause = () => {
|
|||
isVideoPlay.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const sendMsg = () => {
|
||||
if (msgVal.value.trim() == '') return;
|
||||
const index = remoteWsStore.getCurrentTaskIndex()
|
||||
|
@ -595,6 +624,123 @@ function startAI() {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 聊天室
|
||||
*/
|
||||
const msgVal = ref('');
|
||||
const mssageList = ref([] as any);
|
||||
const isRecording = ref(false); // 用于跟踪录音状态
|
||||
const mediaRecorder = ref(null);
|
||||
const audioChunks = ref([]);
|
||||
const remainingTime = ref(10); // 初始化剩余时间为 10 秒
|
||||
// 开始录音
|
||||
const startRecording = async () => {
|
||||
if (isRecording.value) return; // 预防多次点击
|
||||
isRecording.value = true; // 设置录音状态为开启
|
||||
remainingTime.value = 10; // 重置剩余时间为10秒
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
||||
mediaRecorder.value = new MediaRecorder(stream);
|
||||
|
||||
// 监听数据可用事件
|
||||
mediaRecorder.value.ondataavailable = (event) => {
|
||||
console.log("录音中...")
|
||||
audioChunks.value.push(event.data);
|
||||
console.log("当前音频数据块:", event.data); // 这里打印每个数据块
|
||||
};
|
||||
|
||||
// 监听停止事件
|
||||
mediaRecorder.value.onstop = async () => {
|
||||
isRecording.value = false; // 停止录音状态
|
||||
clearInterval(timer); // 清除倒计时
|
||||
|
||||
if (audioChunks.value.length === 0) {
|
||||
console.error("没有音频数据可用于创建 Blob");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取 Blob 数据
|
||||
const audioBlob = new Blob(audioChunks.value, {type: 'audio/webm; codecs=opus'});
|
||||
|
||||
try {
|
||||
// 转换为 Base64
|
||||
const base64Audio = await convertBlobToBase64(audioBlob);
|
||||
console.log("转换后的 Base64 字符串:", base64Audio);
|
||||
|
||||
// 准备 WebSocket 消息
|
||||
const index = remoteWsStore.getCurrentTaskIndex();
|
||||
// 发送消息
|
||||
remoteWsStore.sendAudio(
|
||||
currentRemote.value.patient,
|
||||
currentRemote.value.patientId,
|
||||
currentRemote.value.date,
|
||||
base64Audio,
|
||||
index,
|
||||
function (res) {
|
||||
if (res.code == 1) {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("转换为 Base64 失败:", error);
|
||||
}
|
||||
|
||||
audioChunks.value = []; // 可选: 重置音频块
|
||||
};
|
||||
|
||||
// 启动录音
|
||||
mediaRecorder.value.start();
|
||||
console.log("录音已开始"); // 别忘了在此处添加提示
|
||||
|
||||
// 设置最大录音时间为 10 秒,创建倒计时
|
||||
const timer = setInterval(() => {
|
||||
if (remainingTime.value > 0) {
|
||||
remainingTime.value--; // 每秒减少1
|
||||
} else {
|
||||
stopRecording(); // 达到0秒时自动停止
|
||||
console.log("录音时间到,已自动停止!");
|
||||
}
|
||||
}, 1000); // 每秒执行一次
|
||||
};
|
||||
|
||||
/**
|
||||
* 将 Blob 对象转换为 Base64 字符串
|
||||
* @param {Blob} blob - 需要转换的 Blob 对象
|
||||
* @returns {Promise<string>} - 返回一个 Promise,解析为 Base64 字符串
|
||||
*/
|
||||
const convertBlobToBase64 = (blob) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader(); // 创建 FileReader 实例
|
||||
|
||||
// 定义 onloadend 事件
|
||||
reader.onloadend = () => {
|
||||
// 读取完成后,result 包含了数据 URL 格式
|
||||
const base64String = reader.result.split(',')[1]; // 获取 Base64 部分
|
||||
resolve(base64String); // 返回 Base64 字符串
|
||||
};
|
||||
|
||||
// 定义错误处理
|
||||
reader.onerror = (error) => {
|
||||
reject(error); // 处理读取过程中可能出现的错误
|
||||
};
|
||||
|
||||
// 将 Blob 读取为数据 URL
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 停止录音
|
||||
const stopRecording = () => {
|
||||
if (mediaRecorder.value) {
|
||||
mediaRecorder.value.stop();
|
||||
isRecording.value = false; // 设置录音状态为关闭
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1038,4 +1184,29 @@ function startAI() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 麦克风图标样式
|
||||
.send-box {
|
||||
position: relative; /* 设置相对定位用于绝对定位子元素的参考 */
|
||||
}
|
||||
|
||||
.mic-icon {
|
||||
position: fixed; /* 使用固定定位 */
|
||||
bottom: 20px; /* 距离底部20px */
|
||||
left: 50%; /* 水平居中 */
|
||||
transform: translateX(-50%); /* 使图标真正居中 */
|
||||
background-color: rgba(255, 255, 255, 0.9); /* 背景颜色 */
|
||||
border-radius: 5px; /* 圆角 */
|
||||
padding: 10px; /* 内边距 */
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 阴影效果 */
|
||||
z-index: 1000; /* 确保图标在其他元素之上 */
|
||||
display: flex; /* 使用 flexbox 布局 */
|
||||
align-items: center; /* 垂直居中 */
|
||||
}
|
||||
|
||||
.mic-icon .fa-microphone {
|
||||
color: red; /* 麦克风图标颜色 */
|
||||
font-size: 80px; /* 调整图标大小 */
|
||||
margin-right: 5px; /* 图标与文本间的间距 */
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue
Block a user