This commit is contained in:
Your Name
2026-03-20 13:56:40 +08:00
parent 7147c8e148
commit d765517b74
258 changed files with 2481 additions and 364 deletions
+2 -2
View File
@@ -46,7 +46,7 @@ const wxcode = async (code) => {
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('userData', res.data)
if(res.code==1 &&res.data.diagnosis){
video(res.data)
//video(res.data)
}
console.log('请求结果:', res.data)
} catch (err) {
@@ -69,7 +69,7 @@ const userinfo = async (code) => {
}
uni.setStorageSync('userData', res.data)
if(res.code==1 && res.data.diagnosis){
video(res.data)
//video(res.data)
}
} catch (err) {
+329 -25
View File
@@ -14,6 +14,28 @@
@scroll="onScroll"
>
<view class="message-container">
<!-- 医生卡片视频通话开始或结束时自动隐藏 -->
<view v-if="doctorInfo && showDoctorCard" class="doctor-card" @click="goDoctorDetail">
<view class="doctor-card-main">
<view class="doctor-card-avatar-wrap">
<image :src="doctorInfo.avatar || '/static/user/user.png'" class="doctor-card-avatar" mode="aspectFill" />
<view class="doctor-card-status-dot"></view>
</view>
<view class="doctor-card-info">
<text class="doctor-card-name">{{ doctorInfo.name || '医生' }}</text>
<text class="doctor-card-title">{{ doctorInfo.title || '主任医师' }}</text>
<text class="doctor-card-hospital">{{ doctorInfo.hospital || '甄养堂医院' }}</text>
</view>
<view class="doctor-card-timer">
<!-- <text class="doctor-card-timer-value">{{ formatDoctorWaitTime(doctorWaitSeconds) }}</text> -->
<text class="doctor-card-timer-label">等待中</text>
</view>
</view>
<view class="doctor-card-tip">
<text class="doctor-card-tip-icon"></text>
<text class="doctor-card-tip-text">请等待医生医生即将进入诊室</text>
</view>
</view>
<view v-for="(msg, index) in messages" :key="index" class="message-wrapper" :class="msg.flow === 'out' ? 'message-wrapper-out' : 'message-wrapper-in'">
<!-- 头像 -->
<!-- 头像 -->
@@ -84,16 +106,16 @@
<text class="tool-label">表情</text>
</view> -->
<view class="tool-item tool-item-left" @click="toggleInputMode">
<uni-icons :type="inputMode === 'voice' ? 'compose' : 'mic'" size="38" color="#576b95"></uni-icons>
<uni-icons :type="inputMode === 'voice' ? 'compose' : 'mic'" size="28" color="#576b95"></uni-icons>
<text class="tool-label" v-if="inputMode === 'voice'">文字</text>
<text class="tool-label" v-else>语音</text>
</view>
<view class="tool-item" @click="chooseImage">
<uni-icons type="image " size="40" color="#576b95"></uni-icons>
<uni-icons type="image " size="30" color="#576b95"></uni-icons>
<text class="tool-label">图片</text>
</view>
<view class="tool-item" @click="chooseFile">
<uni-icons type="paperclip " size="40" color="#576b95"></uni-icons>
<uni-icons type="paperclip " size="30" color="#576b95"></uni-icons>
<text class="tool-label">文件</text>
</view>
</view>
@@ -181,20 +203,27 @@
</template>
<script setup>
import { ref, nextTick } from 'vue';
import { onLoad, onUnload } from '@dcloudio/uni-app';
import { ref, nextTick, getCurrentInstance } from 'vue';
import { onLoad, onShow, onUnload, onHide } from '@dcloudio/uni-app';
import TencentCloudChat from '@tencentcloud/lite-chat/basic';
import conversationPlugin from '@tencentcloud/lite-chat/plugins/conversation';
import messageEnhancerPlugin from '@tencentcloud/lite-chat/plugins/message-enhancer';
import richMediaMessagePlugin from '@tencentcloud/lite-chat/plugins/rich-media-message';
import groupPlugin from '@tencentcloud/lite-chat/plugins/group';
import * as GenerateTestUserSig from "@/debug/GenerateTestUserSig-es.js";
import { CallManager } from "@/TUICallKit/src/TUICallService/serve/callManager";
uni.CallManager = new CallManager();
const { proxy } = getCurrentInstance()
const messages = ref([]);
const inputText = ref('');
const scrollTop = ref(0);
const showEmoji = ref(false);
const keyboardHeight = ref(0);
const userAvatar = ref(''); // 当前用户头像
const doctorInfo = ref(null); // 医生信息(对方为医生时展示)
const showDoctorCard = ref(true); // 是否显示医生卡片(通话开始/结束时隐藏)
const doctorWaitSeconds = ref(0); // 等待医生计时(秒)
let doctorWaitTimer = null; // 等待计时器
const inputMode = ref('text'); // 'text' | 'voice'
const isRecording = ref(false);
const recordingDuration = ref(0);
@@ -212,6 +241,12 @@
let currentUserID = ''; // 当前登录用户ID
let scrollTimer = null; // 滚动定时器
const CONFIRMATION_MESSAGE = `我已确认以下信息:
1、本人确认已在线下确诊;
2、本人确认问诊单信息无误;
3、本人确认已知晓病情评估风险告知;
4、本人确认已阅读并同意《互联网诊疗知情同意书》。`;
const emojiList = [
'😀', '😃', '😄', '😁', '😆', '😅', '🤣', '😂',
'🙂', '🙃', '😉', '😊', '😇', '🥰', '😍', '🤩',
@@ -463,17 +498,51 @@
innerAudioContext = null;
uni.showToast({ title: '播放失败', icon: 'none' });
});
}
const video =async (userid)=>{
const uid=userid.replace('patient_', '')
console.log('userid',userid,uid)
const res = await proxy.apiUrl({
url: '/api/tcm/getPatientSignature',
method: 'GET',
data: {
patient_id: uid
},
}, false)
const {userId } = res.data;
const { userSig, SDKAppID } = GenerateTestUserSig.genTestUserSig({
userID:userId,
});
getApp().globalData.userID = userId;
getApp().globalData.userSig = userSig;
getApp().globalData.SDKAppID = SDKAppID;
const cc={
sdkAppID: SDKAppID, // 替换为用户自己的 sdkAppID
userID: userId, // 替换为用户自己的 userID
userSig: userSig, // 替换为用户自己的 userSig
globalCallPagePath: "TUICallKit/src/Components/TUICallKit", // 替换为步骤一里注册的全局监听页面
}
uni.setStorageSync('CallManager', userId)
await uni.CallManager.init(cc);
}
onLoad(async (options) => {
try {
console.log('进入onMounted:', options);
const app = getApp();
const userID = app.globalData.userID || options.userID;
const userSig = app.globalData.userSig || options.userSig;
const SDKAppID = app.globalData.SDKAppID || options.SDKAppID;
const userID = options.userID|| app.globalData.userID;
if(!userID.includes('patient')){
userID='patient_'+userID
}
await video(userID)
const userSig = options.userSig||app.globalData.userSig;
const SDKAppID = options.SDKAppID|| app.globalData.SDKAppID ;
targetUserID = options.targetUserID;
currentUserID = userID; // 保存当前用户ID
console.log('-------',userID,userSig,SDKAppID)
console.log('currentUserID',currentUserID)
// 获取用户头像
const userData = uni.getStorageSync('userData');
if (userData && userData.avatar) {
@@ -487,8 +556,22 @@
}
conversationID = `C2C${targetUserID}`;
console.log('当前用户:', currentUserID, '对方用户:', targetUserID,'conversationID'+conversationID);
console.log('currentUserID:', currentUserID, '对方用户:', targetUserID,'conversationID'+conversationID);
console.log('onMounted',userID,userSig,SDKAppID,conversationID)
// 切换账户前先登出,避免 IM 登录用户不匹配
const prevUserID = app.globalData.imChatUserID;
if (app.globalData.imChat && prevUserID !== userID) {
try {
app.globalData.imChat.off?.(TencentCloudChat.EVENT.MESSAGE_RECEIVED, onMessageReceived);
await app.globalData.imChat.logout();
await app.globalData.imChat.destroy?.();
} catch (e) {
console.warn('IM logout error:', e);
}
app.globalData.imChat = null;
app.globalData.imChatUserID = null;
}
if (!app.globalData.imChat) {
chat = TencentCloudChat.create({
SDKAppID: Number(SDKAppID),
@@ -500,18 +583,30 @@
chat.use(richMediaMessagePlugin);
chat.use(groupPlugin);
await chat.login({ userID, userSig });
let promise = chat.updateMyProfile({
nick: userData.nickname,
avatar: userData.avatar,
gender: TencentCloudChat.TYPES.GENDER_MALE,
})
promise.then(function(imResponse) {
console.log('sssssssssssssssssssss',imResponse.data,userData.avatar); // 更新资料成功
}).catch(function(imError) {
console.warn('updateMyProfile error:', imError); // 更新资料失败的相关信息
});
try {
await chat.login({ userID, userSig });
} catch (loginErr) {
const code = loginErr?.code ?? loginErr?.error?.code;
const msg = String(loginErr?.message ?? loginErr?.error?.message ?? '');
const isDuplicateLogin = code === 2025 || msg.includes('重复登录');
if (isDuplicateLogin) {
// 重复登录:SDK 可能已在内部处理,等待后继续;若仍不可用,后续 updateMyProfile/loadHistoryMessages 会静默失败
await new Promise(r => setTimeout(r, 300));
} else {
throw loginErr;
}
}
// updateMyProfile 非必需,失败不阻塞聊天(如 2024 用户未登录时可忽略)
try {
await chat.updateMyProfile({
avatar: userData?.avatar,
gender: TencentCloudChat.TYPES.GENDER_MALE,
});
} catch (profileErr) {
console.warn('updateMyProfile error:', profileErr);
}
app.globalData.imChat = chat;
app.globalData.imChatUserID = userID;
chat.on(TencentCloudChat.EVENT.MESSAGE_RECEIVED, onMessageReceived);
} else {
chat = app.globalData.imChat;
@@ -519,6 +614,14 @@
}
await loadHistoryMessages();
if(options.msg==1){
console.log('msg我进来了',options.msg)
await sendConfirmationMessage(); // 进入聊天时自动发送知情确认
}
loadDoctorInfo(); // 加载医生卡片信息(对方为医生时)
uni.$on('TUICall:callStart', onVideoCallStart);
uni.$on('TUICall:callEnd', onVideoCallEnd);
//uni.showToast({ title: '聊天已就绪', icon: 'success' });
// 监听键盘高度变化
@@ -540,7 +643,25 @@
}
});
onHide(() => {
const pages = getCurrentPages();
const top = pages[pages.length - 1];
if (top?.route?.includes('TUICallKit')) {
getApp().globalData._chatFromCallPage = true;
}
});
onShow(() => {
if (getApp().globalData._chatFromCallPage) {
getApp().globalData._chatFromCallPage = false;
hideDoctorCardByCall();
}
});
onUnload(() => {
uni.$off('TUICall:callStart', onVideoCallStart);
uni.$off('TUICall:callEnd', onVideoCallEnd);
stopDoctorWaitTimer();
if (chat) chat.off(TencentCloudChat.EVENT.MESSAGE_RECEIVED, onMessageReceived);
if (scrollTimer) clearTimeout(scrollTimer);
if (innerAudioContext) {
@@ -555,6 +676,7 @@
async function loadHistoryMessages() {
try {
const res = await chat.getMessageList({ conversationID, count: 15 });
console.log('消息',conversationID);
if (res.data && res.data.messageList) {
// SDK返回的消息是从新到旧,reverse后变成从旧到新,最新消息在底部
const parsedMessages = res.data.messageList
@@ -700,6 +822,24 @@
uni.showToast({ title: '发送失败', icon: 'none' });
}
}
async function sendConfirmationMessage() {
const alreadySent = messages.value.some(m => m.type === 'text' && m.text === CONFIRMATION_MESSAGE);
if (alreadySent) return;
try {
const message = chat.createTextMessage({
to: targetUserID,
conversationType: TencentCloudChat.TYPES.CONV_C2C,
payload: { text: CONFIRMATION_MESSAGE }
});
await chat.sendMessage(message);
messages.value.push({ type: 'text', text: CONFIRMATION_MESSAGE, time: Date.now(), flow: 'out', avatar: userAvatar.value });
scrollToBottom();
setTimeout(() => scrollToBottom(), 150);
} catch (error) {
console.error('发送确认信息失败:', error);
}
}
function chooseImage() {
// #ifdef MP-WEIXIN
@@ -876,6 +1016,7 @@
async function makeVideoCall() {
try {
hideDoctorCardByCall();
if (!uni.CallManager) {
uni.showToast({ title: '通话功能未初始化', icon: 'none' });
return;
@@ -887,6 +1028,69 @@
}
}
function startVideoCall() {
makeVideoCall();
}
async function loadDoctorInfo() {
if (!targetUserID || !targetUserID.startsWith('doctor_')) return;
const doctorId = targetUserID.replace('doctor_', '');
try {
const res = await proxy.apiUrl({
url: '/api/doctor/detail',
method: 'GET',
data: { id: doctorId }
}, false);
if (res && res.code === 1 && res.data) {
doctorInfo.value = res.data;
startDoctorWaitTimer();
}
} catch (e) {
console.warn('加载医生信息失败:', e);
}
}
function formatDoctorWaitTime(seconds) {
const m = Math.floor(seconds / 60);
const s = seconds % 60;
return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
}
function startDoctorWaitTimer() {
stopDoctorWaitTimer();
doctorWaitSeconds.value = 0;
doctorWaitTimer = setInterval(() => {
doctorWaitSeconds.value++;
}, 1000);
}
function stopDoctorWaitTimer() {
if (doctorWaitTimer) {
clearInterval(doctorWaitTimer);
doctorWaitTimer = null;
}
}
function goDoctorDetail() {
if (!doctorInfo.value?.id) return;
uni.navigateTo({ url: `/doctor/pages/doctor/doctor?id=${doctorInfo.value.id}` });
}
function hideDoctorCardByCall() {
showDoctorCard.value = false;
stopDoctorWaitTimer();
}
function onVideoCallStart() {
hideDoctorCardByCall();
}
function onVideoCallEnd() {
hideDoctorCardByCall();
uni.showToast({ title: '视频通话已结束', icon: 'success' });
}
function onInputFocus() {
console.log('输入框获得焦点');
showEmoji.value = false;
@@ -1024,6 +1228,106 @@
min-height: 100%;
}
/* 医生卡片 */
.doctor-card {
display: flex;
flex-direction: column;
margin-bottom: 32rpx;
background: linear-gradient(145deg, #ffffff 0%, #f8fafc 100%);
border-radius: 24rpx;
border: 2rpx solid #e8ecf0;
box-shadow: 0 4rpx 20rpx rgba(24, 144, 255, 0.06);
overflow: hidden;
}
.doctor-card-main {
display: flex;
align-items: center;
padding: 28rpx 32rpx;
}
.doctor-card-avatar-wrap {
position: relative;
flex-shrink: 0;
}
.doctor-card-avatar {
width: 96rpx;
height: 96rpx;
border-radius: 20rpx;
background: #e8ecf0;
}
.doctor-card-status-dot {
position: absolute;
right: 4rpx;
bottom: 4rpx;
width: 20rpx;
height: 20rpx;
background: #52c41a;
border: 4rpx solid #fff;
border-radius: 50%;
animation: doctorStatusPulse 1.5s ease-in-out infinite;
}
@keyframes doctorStatusPulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.1); }
}
.doctor-card-info {
flex: 1;
margin-left: 24rpx;
display: flex;
flex-direction: column;
gap: 6rpx;
}
.doctor-card-name {
font-size: 34rpx;
font-weight: 600;
color: #1a1a1a;
}
.doctor-card-title {
font-size: 26rpx;
color: #576b95;
}
.doctor-card-hospital {
font-size: 24rpx;
color: #94a3b8;
}
.doctor-card-timer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4rpx;
padding: 16rpx 28rpx;
background: linear-gradient(135deg, rgba(24, 144, 255, 0.12) 0%, rgba(24, 144, 255, 0.06) 100%);
border-radius: 20rpx;
min-width: 120rpx;
}
.doctor-card-timer-value {
font-size: 40rpx;
font-weight: 600;
color: #1890ff;
font-variant-numeric: tabular-nums;
}
.doctor-card-timer-label {
font-size: 22rpx;
color: #94a3b8;
}
.doctor-card-tip {
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
padding: 20rpx 24rpx;
background: linear-gradient(90deg, rgba(24, 144, 255, 0.08) 0%, rgba(24, 144, 255, 0.04) 100%);
border-top: 2rpx dashed rgba(24, 144, 255, 0.15);
}
.doctor-card-tip-icon {
font-size: 32rpx;
}
.doctor-card-tip-text {
font-size: 28rpx;
color: #576b95;
font-weight: 500;
}
.message-wrapper {
display: flex;
margin-bottom: 32rpx;
@@ -1095,7 +1399,7 @@
/* 文本消息 - 大字号 */
.message-text {
font-size: 38rpx;
font-size: 30rpx;
line-height: 1.6;
color: #1a1a1a;
word-break: break-all;
@@ -175,9 +175,17 @@ export default class EngineEventHandler {
TUIStore.update(StoreName.CALL, NAME.CALL_TIPS, { text: 'answered', duration: 2000 });
await this._callService.openMicrophone();
console.log(`${NAME.PREFIX}accept event data: ${JSON.stringify(event)}.`);
// 通知聊天页:视频/语音通话已接通,可关闭等待计时器
try {
uni.$emit('TUICall:callStart', event);
} catch (_) {}
}
private async _handleUserEnter(event: any): Promise<void> {
const { userID: userId, data } = analyzeEventData(event);
// 对方进入房间,通话已接通,通知聊天页关闭等待计时器
try {
uni.$emit('TUICall:callStart', event);
} catch (_) {}
if (userId && TUIStore.getData(StoreName.CALL, NAME.CALL_ROLE === CallRole.CALLEE)) {
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) === CallStatus.CALLING) {
@@ -232,6 +240,10 @@ export default class EngineEventHandler {
private _handleCallingEnd(event: any): void {
console.log(`${NAME.PREFIX}callEnd event data: ${JSON.stringify(event)}.`);
this._callService?._resetCallStore();
// 通知聊天页等:视频通话已结束,可关闭等待计时器等
try {
uni.$emit('TUICall:callEnd', event);
} catch (_) {}
}
private _handleKickedOut(event: any): void {
console.log(`${NAME.PREFIX}kickOut event data: ${JSON.stringify(event)}.`);
+341 -51
View File
@@ -28,7 +28,7 @@
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value">{{ formatPatientCount(doctor.patient_count) }}</text>
<text class="stat-value">100{{ formatPatientCount(doctor.patient_count) }}</text>
<text class="stat-label">患者数</text>
</view>
<view class="stat-divider"></view>
@@ -51,6 +51,21 @@
</view>
</section>
<!-- 医生资质 -->
<section class="qualification-section" v-if="qualificationImages.length > 0">
<text class="section-title-plain">医生资质</text>
<view class="qualification-grid">
<image
v-for="(img, idx) in qualificationImages"
:key="idx"
:src="img"
class="qualification-image"
mode="aspectFill"
@click="previewImage(img)"
/>
</view>
</section>
<!-- 专业领域 -->
<section class="expertise-section">
<text class="section-title-plain">专业领域</text>
@@ -108,16 +123,55 @@
<view v-if="doctor">
<!-- 底部操作栏 -->
<view v-if="doctor.enable_image_consult || doctor.enable_video_consult" class="bottom-bar">
<view class="btn-chat" @click="goChat" v-if="doctor.enable_image_consult">
<view class="btn-chat" @click="showCardSelector('chat')" v-if="doctor.enable_image_consult">
<text class="btn-icon">💬</text>
<text class="btn-text">图文问诊</text>
</view>
<view class="btn-video" @click="goVideo" v-if="doctor.enable_video_consult">
<view class="btn-video" @click="showCardSelector('video')" v-if="doctor.enable_video_consult">
<text class="btn-icon">📹</text>
<text class="btn-text">视频问诊</text>
</view>
</view>
</view>
<!-- 就诊人选择弹窗 -->
<view v-if="showCardModal" class="modal-overlay" @click="closeCardModal">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">选择就诊人</text>
<text class="modal-close" @click="closeCardModal"></text>
</view>
<view class="modal-body">
<!-- 加载中 -->
<view v-if="loadingCards" class="modal-loading">
<text class="loading-text">加载中...</text>
</view>
<!-- 就诊卡列表 -->
<view v-else-if="cardList.length > 0" class="card-list">
<view
v-for="card in cardList"
:key="card.id"
class="card-item"
@click="selectCard(card)"
>
<view class="card-info">
<text class="card-name">{{ card.patient_name }}</text>
<text class="card-detail">{{ card.gender_desc }} / {{ card.age }}</text>
</view>
<text class="card-arrow"></text>
</view>
</view>
<!-- 空状态 -->
<view v-else class="modal-empty">
<text class="empty-text">暂无就诊卡</text>
<view class="add-card-btn" @click="createNewCard">新建就诊卡</view>
</view>
</view>
</view>
</view>
</view>
</template>
@@ -138,6 +192,26 @@ const loading = ref(true)
const error = ref('')
const defaultAvatar = '/static/user/user.png'
// 就诊卡选择相关
const showCardModal = ref(false)
const cardList = ref([])
const loadingCards = ref(false)
const consultType = ref('') // 'chat' 或 'video'
// 医生资质图片
const qualificationImages = computed(() => {
if (!doctor.value?.qualification_images) return []
try {
const images = typeof doctor.value.qualification_images === 'string'
? JSON.parse(doctor.value.qualification_images)
: doctor.value.qualification_images
return Array.isArray(images) ? images : []
} catch (e) {
console.error('解析资质图片失败:', e)
return []
}
})
const formatPatientCount = (count) => {
if (count === undefined || count === null) return '1.2k+'
if (count >= 1000) return (count / 1000).toFixed(1) + 'k+'
@@ -149,6 +223,14 @@ const getExpertiseIcon = (icon) => {
return map[icon] || '📋'
}
// 预览资质图片
const previewImage = (current) => {
uni.previewImage({
current: current,
urls: qualificationImages.value
})
}
const loadDetail = async () => {
if (!doctorId.value) return
loading.value = true
@@ -192,68 +274,136 @@ const viewAllReviews = () => {
uni.showToast({ title: '查看全部评价', icon: 'none' })
}
const goChat = async () => {
// uni.navigateTo({
// url: `/TUIKit/pages/chat/chat?doctorId=${doctorId.value}&doctorName=${encodeURIComponent(doctor.value?.name || '')}`
// })
console.log('dfafafa',uni.getStorageSync('userData'))
if(!uni.getStorageSync('userData').diagnosis){
uni.navigateTo({
url: `/pages/Card/edit_card?add=1`
});
}else{
await loginHandler(uni.getStorageSync('userData').diagnosis.patient_id)
const doctor='doctor_'+doctorId.value
// 跳转到聊天页面
uni.navigateTo({
url: `/TUIKit/pages/chat/chat?userID=${encodeURIComponent(userId)}&userSig=${encodeURIComponent(userSig)}&SDKAppID=${SDKAppID}&targetUserID=${doctor}`
});
// 显示就诊卡选择弹窗
const showCardSelector = async (type) => {
consultType.value = type
showCardModal.value = true
await loadCardList()
}
// 关闭弹窗
const closeCardModal = () => {
showCardModal.value = false
}
// 加载就诊卡列表
const loadCardList = async () => {
loadingCards.value = true
try {
const token = uni.getStorageSync('token')
if (!token) {
uni.showToast({ title: '请先登录', icon: 'none' })
closeCardModal()
return
}
const userData = uni.getStorageSync('userData')
const userId = userData?.id
if (!userId) {
uni.showToast({ title: '用户信息不存在', icon: 'none' })
closeCardModal()
return
}
const res = await proxy.apiUrl({
url: '/api/tcm/getCardList',
method: 'GET',
data: { user_id: userId,patient_id:userId }
}, false)
if (res && res.code === 1) {
cardList.value = res.data || []
} else {
uni.showToast({ title: res?.msg || '获取失败', icon: 'none' })
}
} catch (e) {
console.error('加载就诊卡列表失败:', e)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
loadingCards.value = false
}
}
const goVideo = () => {
if(!uni.getStorageSync('userData').diagnosis){
uni.navigateTo({
url: `/pages/Card/edit_card?add=1`
});
}else{
uni.navigateTo({
url: `/pages/login/login?doctorId=${doctorId.value}&doctorName=${encodeURIComponent(doctor.value?.name || '')}`
// 选择就诊卡
const selectCard = async (card) => {
closeCardModal()
// 更新本地存储的就诊卡信息
const userData = uni.getStorageSync('userData') || {}
userData.diagnosis = {
patient_id: card.patient_id,
id: card.id,
patient_name: card.patient_name
}
uni.setStorageSync('userData', userData)
// 根据类型跳转
if (consultType.value === 'chat') {
await goChat(card)
} else if (consultType.value === 'video') {
await goChat(card)
}
}
// 新建就诊卡
const createNewCard = () => {
closeCardModal()
uni.navigateTo({
url: `/pages/Card/edit_card?add=1&returnUrl=/doctor/pages/doctor/doctor?id=${doctorId.value}`
})
}
const goChat = async (card) => {
console.log('开始图文问诊', uni.getStorageSync('userData'))
const userData = uni.getStorageSync('userData')
if (!userData.diagnosis) {
uni.showToast({ title: '请先选择就诊人', icon: 'none' })
return
}
await loginHandler(userData.diagnosis.patient_id)
const doctor = 'doctor_' + doctorId.value
uni.navigateTo({
url: `/TUIKit/pages/chat/chat?userID=${encodeURIComponent(userId.value)}&userSig=${encodeURIComponent(userSig.value)}&SDKAppID=${SDKAppID.value}&targetUserID=${doctor}&msg=0`
})
}
const loginHandler = async (patient_id) => {
console.log('获取签名开始:',patient_id);
const res = await proxy.apiUrl({
url: '/api/tcm/getPatientSignature',
method: 'GET',
data: { patient_id: patient_id },
}, false)
console.log('获取签名开始:', patient_id)
const res = await proxy.apiUrl({
url: '/api/tcm/getPatientSignature',
method: 'GET',
data: { patient_id: patient_id },
}, false)
const {userId } = res.data;
const { userSig, SDKAppID } = GenerateTestUserSig.genTestUserSig({
userID:userId,
});
console.log('获取签名成功:',userSig);
const { userId: patientUserId } = res.data
const { userSig: patientUserSig, SDKAppID: patientSDKAppID } = GenerateTestUserSig.genTestUserSig({
userID: patientUserId,
})
console.log('获取签名成功:', patientUserSig)
getApp().globalData.userID = userId;
getApp().globalData.userSig = userSig;
getApp().globalData.SDKAppID = SDKAppID;
getApp().globalData.isIMInitialized = false; // 标记IM未初始化
// 更新ref值
userId.value = patientUserId
userSig.value = patientUserSig
SDKAppID.value = patientSDKAppID
getApp().globalData.userID = patientUserId
getApp().globalData.userSig = patientUserSig
getApp().globalData.SDKAppID = patientSDKAppID
getApp().globalData.isIMInitialized = false
// 初始化视频通话
await uni.CallManager.init({
sdkAppID: SDKAppID,
userID: userId,
userSig: userSig,
sdkAppID: patientSDKAppID,
userID: patientUserId,
userSig: patientUserSig,
globalCallPagePath: "TUICallKit/src/Components/TUICallKit",
});
})
console.log('初始化完成,跳转到聊天页面');
};
console.log('初始化完成,跳转到聊天页面')
}
onMounted(() => {
const pages = getCurrentPages()
const current = pages[pages.length - 1]
@@ -453,6 +603,24 @@ $outline-variant: #c1c9be;
line-height: 1.8;
}
.qualification-section {
margin-bottom: 96rpx;
}
.qualification-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24rpx;
}
.qualification-image {
width: 100%;
height: 200rpx;
border-radius: 16rpx;
background: $surface-high;
object-fit: cover;
}
.expertise-section {
margin-bottom: 96rpx;
}
@@ -647,4 +815,126 @@ $outline-variant: #c1c9be;
.btn-icon {
font-size: 40rpx;
}
/* 弹窗样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
width: 640rpx;
max-height: 80vh;
background: $surface-lowest;
border-radius: 32rpx;
overflow: hidden;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 48rpx;
border-bottom: 2rpx solid $outline-variant;
}
.modal-title {
font-size: 40rpx;
font-weight: bold;
color: $on-surface;
}
.modal-close {
font-size: 48rpx;
color: $on-surface-variant;
width: 64rpx;
height: 64rpx;
display: flex;
align-items: center;
justify-content: center;
}
.modal-body {
max-height: 60vh;
overflow-y: auto;
}
.modal-loading {
padding: 120rpx 0;
text-align: center;
}
.card-list {
padding: 24rpx;
}
.card-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx;
margin-bottom: 16rpx;
background: $surface-low;
border-radius: 16rpx;
transition: all 0.3s;
&:active {
background: $surface-high;
transform: scale(0.98);
}
}
.card-info {
flex: 1;
}
.card-name {
display: block;
font-size: 36rpx;
font-weight: bold;
color: $on-surface;
margin-bottom: 8rpx;
}
.card-detail {
display: block;
font-size: 28rpx;
color: $on-surface-variant;
}
.card-arrow {
font-size: 48rpx;
color: $on-surface-variant;
margin-left: 16rpx;
}
.modal-empty {
display: flex;
flex-direction: column;
align-items: center;
padding: 120rpx 48rpx;
}
.empty-text {
font-size: 32rpx;
color: $on-surface-variant;
margin-bottom: 48rpx;
}
.add-card-btn {
padding: 24rpx 64rpx;
background: $primary;
color: $on-primary;
border-radius: 40rpx;
font-size: 32rpx;
font-weight: bold;
}
</style>
+1
View File
@@ -141,6 +141,7 @@
class="form-input-inline"
type="digit"
placeholder="请填写空腹血糖(数值)"
required
/>
<text class="form-unit">mmol/L</text>
</view>
+33 -23
View File
@@ -460,7 +460,7 @@ onMounted(() => {
onShareAppMessage((res) =>{
return {
title: '点击进入诊室',
path: '/pages/order/monad/monad?id='+diagnosisId+'&share_user_id='+share_user_id,
path: '/pages/order/monad/monad?id='+diagnosisId+'&share_user_id='+share_user_id+'&doctor_id='+doctorId.value,
imageUrl: '/static/zs.jpg',
desc: '点击进入诊室',
success() {
@@ -567,7 +567,7 @@ const loadDiagnosisDetail = async () => {
const params = proxy.$parsePageParams(currentPage.options);
dingdan_ok.value=false;
diagnosisId = params.id;
share_user_id = params.share_user_id;
share_user_id = params.share_user;
doctorId.value = params.doctor_id;
console.log('进入onMounted:', params, '诊单ID:', diagnosisId, '医生ID:', doctorId);
@@ -585,7 +585,7 @@ const loadDiagnosisDetail = async () => {
method: 'GET',
data: {
id: diagnosisId,
user_id: params.user_id || 0,
user_id: params.share_user_id || 0,
share_user_id: params.share_user || 0
},
}, false); // 不显示加载中
@@ -622,24 +622,29 @@ const closePatientModal = async () => {
confirmBtnLoading.value = true;
try {
const app = getApp();
const userID = app.globalData.userID;
const userSig = app.globalData.userSig;
const SDKAppID = app.globalData.SDKAppID;
// const userID = app.globalData.userID;
// const userSig = app.globalData.userSig;
// const SDKAppID = app.globalData.SDKAppID;
const doctor = 'doctor_' + doctorId.value;
confirmDiagnosis(diagnosisId);
if(!diagnosisId.includes('patient')){
diagnosisId='patient_'+diagnosisId
}
const { userSig, SDKAppID } = GenerateTestUserSig.genTestUserSig({
userID:diagnosisId,
});
if (!doctorId.value) {
uni.showToast({ title: '诊室号不存在,联系助理处理!', icon: 'none' });
return;
}
if (!userID || !userSig) {
await video();
}
console.log(userID, app.globalData, diagnosisId);
console.log(app.globalData, diagnosisId);
confirmDiagnosis();
showPatientModal.value = false;
uni.redirectTo({
url: `/TUIKit/pages/chat/chat?userID=${encodeURIComponent(userID)}&userSig=${encodeURIComponent(userSig)}&SDKAppID=${SDKAppID}&targetUserID=${doctor}`
url: `/TUIKit/pages/chat/chat?userID=${encodeURIComponent(diagnosisId)}&userSig=${encodeURIComponent(userSig)}&SDKAppID=${SDKAppID}&targetUserID=${doctor}&msg=1`
});
} catch (err) {
console.error(err);
@@ -807,14 +812,12 @@ const handleConfirm = () => {
};
// 提交确认诊单
const confirmDiagnosis = async () => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const params = proxy.$parsePageParams(currentPage.options);
const confirmDiagnosis = async (diagnosisId) => {
console.log('确认诊单参数:', params);
if (!params.id) {
console.log('确认诊单参数:', diagnosisId);
if (!diagnosisId) {
uni.showToast({ title: '缺少诊单ID', icon: 'none' });
return;
}
@@ -822,15 +825,22 @@ const confirmDiagnosis = async () => {
uni.showLoading({ title: '提交中...' });
const app = getApp();
const rawUserID = app?.globalData?.userID;
const userID = (typeof rawUserID === 'string' ? rawUserID : '').replace(/patient_/g, '');
if (!userID) {
uni.hideLoading();
uni.showToast({ title: '请先登录', icon: 'none' });
return;
}
try {
const res = await proxy.apiUrl({
url: '/api/tcm/confirmDiagnosis',
method: 'POST',
data: {
id: params.id,
user_id: params.user_id || 0,
share_user: params.share_user || 0
id: diagnosisId,
user_id: userID || 0,
share_user: share_user_id || 0
}
}, false);