This commit is contained in:
Your Name
2026-03-16 15:08:28 +08:00
parent 294fee4d88
commit cda63b5ae2
26 changed files with 1695 additions and 492 deletions
+3 -2
View File
@@ -67,10 +67,11 @@ const userinfo = async (code) => {
wxcode(code)
}
if(res.code==1){
uni.setStorageSync('userData', res.data)
if(res.code==1 && res.data.diagnosis){
video(res.data)
}
uni.setStorageSync('userData', res.data)
} catch (err) {
+3 -3
View File
@@ -166,7 +166,7 @@
const SDKAppID = app.globalData.SDKAppID || options.SDKAppID;
targetUserID = options.targetUserID;
currentUserID = userID; // 保存当前用户ID
console.log('-------',userID,userSig,SDKAppID)
// 获取用户头像
const userData = uni.getStorageSync('userData');
if (userData && userData.avatar) {
@@ -180,7 +180,7 @@
}
conversationID = `C2C${targetUserID}`;
console.log('当前用户:', currentUserID, '对方用户:', targetUserID);
console.log('当前用户:', currentUserID, '对方用户:', targetUserID,'conversationID'+conversationID);
if (!app.globalData.imChat) {
chat = TencentCloudChat.create({
@@ -212,7 +212,7 @@
}
await loadHistoryMessages();
uni.showToast({ title: '聊天已就绪', icon: 'success' });
//uni.showToast({ title: '聊天已就绪', icon: 'success' });
// 监听键盘高度变化
uni.onKeyboardHeightChange((res) => {
@@ -0,0 +1,649 @@
<template>
<view class="page">
<!-- 加载中 -->
<view v-if="loading" class="loading-wrap">
<text class="loading-text">加载中...</text>
</view>
<!-- 医生详情 -->
<view v-else-if="doctor" class="main">
<!-- 医生头部 -->
<section class="hero-section">
<view class="hero-content">
<view class="avatar-wrap">
<image :src="doctor.avatar || defaultAvatar" class="avatar" mode="aspectFill"></image>
<view class="badge">{{ doctor.title || '主任医师' }}</view>
</view>
<view class="hero-info">
<text class="doctor-name">{{ doctor.name }}</text>
<text class="hospital">{{ doctor.hospital || '甄养堂医院' }}</text>
<view class="experience-row">
<text class="verified"></text>
<text class="experience">{{ doctor.experience || '24年临床经验' }}</text>
</view>
<view class="stats-row">
<view class="stat-item">
<text class="stat-value">{{ doctor.rating || '4.9' }}</text>
<text class="stat-label">评分</text>
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value">{{ formatPatientCount(doctor.patient_count) }}</text>
<text class="stat-label">患者数</text>
</view>
<view class="stat-divider"></view>
<view class="stat-item" v-if="doctor.license_no">
<text class="stat-value">执业证书编号</text>
<text class="stat-label">{{doctor.license_no}}</text>
</view>
</view>
</view>
</view>
</section>
<!-- 擅长领域 -->
<section class="about-section">
<view class="section-title-bar">
<text class="section-title">擅长领域</text>
</view>
<view class="about-content">
<text class="about-text">{{ doctor.about || '擅长运用传统中医理论与现代诊断相结合...' }}</text>
</view>
</section>
<!-- 专业领域 -->
<section class="expertise-section">
<text class="section-title-plain">专业领域</text>
<view class="expertise-grid">
<view
v-for="(item, idx) in (doctor.expertise || [])"
:key="idx"
class="expertise-card"
:class="{ 'expertise-wide': item.wide }"
>
<view class="expertise-icon" :class="'icon-' + (item.icon || 'default')">
<text class="icon-emoji">{{ getExpertiseIcon(item.icon) }}</text>
</view>
<view class="expertise-text">
<text class="expertise-title">{{ item.title }}</text>
<text class="expertise-desc">{{ item.desc }}</text>
</view>
</view>
</view>
</section>
<!-- 患者评价 -->
<section class="reviews-section">
<view class="reviews-header">
<text class="section-title-plain">患者评价</text>
<!-- <text class="view-all" @click="viewAllReviews">查看全部</text> -->
</view>
<view class="reviews-list">
<view
v-for="review in reviews"
:key="review.id"
class="review-card"
>
<view class="review-header">
<view class="review-avatar">{{ review.patient_initials }}</view>
<view class="review-meta">
<text class="review-name">{{ review.patient_name }}</text>
<view class="review-stars">
<text v-for="i in 5" :key="i" class="star"></text>
</view>
</view>
<text class="review-time">{{ review.create_time }}</text>
</view>
<text class="review-content">"{{ review.content }}"</text>
</view>
</view>
</section>
</view>
<!-- 错误 -->
<view v-else-if="!loading && error" class="error-wrap">
<text class="error-text">{{ error }}</text>
<view class="retry-btn" @click="loadDetail">重试</view>
</view>
<!-- 底部操作栏 -->
<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">
<text class="btn-icon">💬</text>
<text class="btn-text">图文问诊</text>
</view>
<view class="btn-video" @click="goVideo" v-if="doctor.enable_video_consult">
<text class="btn-icon">📹</text>
<text class="btn-text">视频问诊</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { getCurrentInstance } from 'vue'
import * as GenerateTestUserSig from "@/debug/GenerateTestUserSig-es.js";
import { CallManager } from "@/TUICallKit/src/TUICallService/serve/callManager";
const { proxy } = getCurrentInstance()
let userId = ref("");
let userSig= ref("");
let SDKAppID=ref("");
uni.CallManager = new CallManager();
const doctorId = ref('')
const doctor = ref(null)
const reviews = ref([])
const loading = ref(true)
const error = ref('')
const defaultAvatar = '/static/user/user.png'
const formatPatientCount = (count) => {
if (count === undefined || count === null) return '1.2k+'
if (count >= 1000) return (count / 1000).toFixed(1) + 'k+'
return count + '+'
}
const getExpertiseIcon = (icon) => {
const map = { psychiatry: '🌿', eco: '🌱', vital_signs: '💓' }
return map[icon] || '📋'
}
const loadDetail = async () => {
if (!doctorId.value) return
loading.value = true
error.value = ''
try {
const res = await proxy.apiUrl({
url: '/api/doctor/detail',
method: 'GET',
data: { id: doctorId.value }
}, false)
if (res && res.code === 1) {
doctor.value = res.data
} else {
error.value = res?.msg || '加载失败'
}
} catch (e) {
error.value = '网络异常,请重试'
console.error(e)
} finally {
loading.value = false
}
}
const loadReviews = async () => {
if (!doctorId.value) return
try {
const res = await proxy.apiUrl({
url: '/api/doctor/reviews',
method: 'GET',
data: { doctor_id: doctorId.value, page_no: 1, page_size: 10 }
}, false)
if (res && res.code === 1) {
reviews.value = res.data?.lists || []
}
} catch (e) {
console.error(e)
}
}
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 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 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)
const {userId } = res.data;
const { userSig, SDKAppID } = GenerateTestUserSig.genTestUserSig({
userID:userId,
});
console.log('获取签名成功:',userSig);
getApp().globalData.userID = userId;
getApp().globalData.userSig = userSig;
getApp().globalData.SDKAppID = SDKAppID;
getApp().globalData.isIMInitialized = false; // 标记IM未初始化
// 初始化视频通话
await uni.CallManager.init({
sdkAppID: SDKAppID,
userID: userId,
userSig: userSig,
globalCallPagePath: "TUICallKit/src/Components/TUICallKit",
});
console.log('初始化完成,跳转到聊天页面');
};
onMounted(() => {
const pages = getCurrentPages()
const current = pages[pages.length - 1]
const options = current.options || current.$page?.options || {}
doctorId.value = options.id || options.doctorId || ''
if (doctorId.value) {
loadDetail().then(() => loadReviews())
} else {
error.value = '缺少医生ID'
loading.value = false
}
})
</script>
<style lang="scss" scoped>
$bg: #faf9f5;
$primary: #204e2b;
$primary-container: #386641;
$on-primary: #ffffff;
$secondary-container: #fdc39a;
$on-secondary-container: #794e2e;
$surface-lowest: #ffffff;
$surface-low: #f4f4f0;
$surface-high: #e9e8e4;
$surface-container: #efeeea;
$on-surface: #1b1c1a;
$on-surface-variant: #414941;
$tertiary-container: #4b6500;
$outline-variant: #c1c9be;
.page {
background: $bg;
min-height: 100vh;
padding-bottom: 180rpx;
}
.loading-wrap, .error-wrap {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 60vh;
}
.loading-text, .error-text {
font-size: 28rpx;
color: $on-surface-variant;
}
.retry-btn {
margin-top: 24rpx;
padding: 16rpx 48rpx;
background: $primary;
color: $on-primary;
border-radius: 40rpx;
font-size: 28rpx;
}
.main {
padding: 32rpx 48rpx 40rpx;
}
.hero-section {
margin-bottom: 80rpx;
}
.hero-content {
display: flex;
flex-direction: column;
gap: 24rpx;
}
.avatar-wrap {
position: relative;
width: 320rpx;
height: 320rpx;
flex-shrink: 0;
}
.avatar {
width: 100%;
height: 100%;
border-radius: 24rpx;
background: $surface-high;
}
.badge {
position: absolute;
bottom: -16rpx;
right: -16rpx;
background: $tertiary-container;
color: $on-primary;
font-size: 22rpx;
padding: 12rpx 24rpx;
border-radius: 9999rpx;
font-weight: bold;
}
.hero-info {
flex: 1;
}
.doctor-name {
display: block;
font-size: 64rpx;
font-weight: bold;
color: $on-surface;
margin-bottom: 16rpx;
font-family: 'Noto Serif SC', 'STSong', 'SimSun', serif;
}
.hospital {
display: block;
font-size: 36rpx;
color: $primary;
font-weight: 500;
margin-bottom: 16rpx;
}
.experience-row {
display: flex;
align-items: center;
gap: 16rpx;
margin-bottom: 32rpx;
}
.verified {
font-size: 32rpx;
color: $primary;
}
.experience {
font-size: 28rpx;
color: $on-surface-variant;
}
.stats-row {
display: flex;
align-items: center;
gap: 32rpx;
}
.stat-item {
display: flex;
flex-direction: column;
}
.stat-value {
font-size: 48rpx;
font-weight: bold;
color: $on-surface;
font-family: 'Noto Serif SC', serif;
}
.stat-label {
font-size: 20rpx;
text-transform: uppercase;
letter-spacing: 0.1em;
color: $on-surface-variant;
font-weight: bold;
margin-top: 4rpx;
}
.stat-divider {
width: 2rpx;
height: 64rpx;
background: $outline-variant;
opacity: 0.3;
}
.about-section {
margin-bottom: 96rpx;
}
.section-title-bar {
padding-left: 32rpx;
border-left: 8rpx solid $secondary-container;
margin-bottom: 32rpx;
}
.section-title {
font-size: 48rpx;
font-weight: bold;
color: $on-surface;
font-family: 'Noto Serif SC', serif;
}
.about-content {
background: $surface-low;
padding: 48rpx;
border-radius: 24rpx;
}
.about-text {
font-size: 28rpx;
color: $on-surface-variant;
line-height: 1.8;
}
.expertise-section {
margin-bottom: 96rpx;
}
.section-title-plain {
display: block;
font-size: 48rpx;
font-weight: bold;
color: $on-surface;
margin-bottom: 48rpx;
font-family: 'Noto Serif SC', serif;
}
.expertise-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32rpx;
}
.expertise-card {
background: $surface-lowest;
padding: 40rpx;
border-radius: 16rpx;
display: flex;
flex-direction: column;
gap: 24rpx;
}
.expertise-card.expertise-wide {
grid-column: span 2;
flex-direction: row;
align-items: center;
gap: 48rpx;
}
.expertise-icon {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #ffdcc5;
display: flex;
align-items: center;
justify-content: center;
}
.expertise-icon.icon-eco {
background: #ccf078;
}
.expertise-icon.icon-vital_signs {
width: 96rpx;
height: 96rpx;
background: #bcefc0;
}
.icon-emoji {
font-size: 40rpx;
}
.expertise-title {
display: block;
font-size: 28rpx;
font-weight: 600;
color: $on-surface;
margin-bottom: 8rpx;
}
.expertise-desc {
font-size: 24rpx;
color: $on-surface-variant;
line-height: 1.5;
}
.reviews-section {
margin-bottom: 48rpx;
}
.reviews-header {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 48rpx;
}
.view-all {
font-size: 28rpx;
color: $primary;
font-weight: bold;
}
.reviews-list {
display: flex;
flex-direction: column;
gap: 32rpx;
}
.review-card {
background: $surface-lowest;
padding: 48rpx;
border-radius: 24rpx;
}
.review-header {
display: flex;
align-items: center;
gap: 24rpx;
margin-bottom: 24rpx;
}
.review-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: $surface-container;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: bold;
color: $on-surface-variant;
}
.review-meta {
flex: 1;
}
.review-name {
display: block;
font-size: 28rpx;
font-weight: bold;
color: $on-surface;
margin-bottom: 8rpx;
}
.review-stars {
color: #805533;
font-size: 24rpx;
}
.review-time {
font-size: 24rpx;
color: $on-surface-variant;
}
.review-content {
font-size: 28rpx;
color: $on-surface-variant;
line-height: 1.6;
font-style: italic;
}
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 48rpx;
display: flex;
gap: 32rpx;
background: rgba(250, 249, 245, 0.95);
z-index: 50;
}
.btn-chat {
flex: 1;
height: 112rpx;
background: $secondary-container;
color: $on-secondary-container;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 24rpx;
font-weight: bold;
font-size: 30rpx;
}
.btn-video {
flex: 1;
height: 112rpx;
background: linear-gradient(135deg, $primary 0%, $primary-container 100%);
color: $on-primary;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 24rpx;
font-weight: bold;
font-size: 30rpx;
}
.btn-icon {
font-size: 40rpx;
}
</style>
+35
View File
@@ -116,12 +116,47 @@ function apiUrl(promise, Loading = true) {
})
}
/**
* 解析页面参数(支持普通参数和扫码 scene 参数)
* @param {Object} options - 页面 options,如 getCurrentPages()[].options
* @returns {Object} 解析后的参数对象
*/
function parsePageParams(options) {
const params = {}
if (!options) return params
// 如果有 scene 参数(扫码进入),解析 scene
if (options.scene) {
try {
const decodedScene = decodeURIComponent(options.scene)
decodedScene.split('&').forEach(item => {
const [key, value] = item.split('=')
if (key && value) {
params[key] = value
}
})
} catch (error) {
console.error('解析scene参数失败:', error)
}
}
// 合并普通参数(普通跳转进入)
Object.keys(options).forEach(key => {
if (key !== 'scene' && options[key]) {
params[key] = options[key]
}
})
return params
}
export function createApp() {
const app = createSSRApp(App)
// Vue3挂载全局属性的方式
app.config.globalProperties.$url = baseUrl
app.config.globalProperties.apiUrl = apiUrl
app.config.globalProperties.$parsePageParams = parsePageParams
return {
app
+13 -2
View File
@@ -80,11 +80,22 @@
}
}
]
},
{
"root": "doctor",
"pages": [
{
"path": "pages/doctor/doctor",
"style": {
"navigationBarTitleText": "医生信息"
}
}
]
}
],
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#FFA500",
"color": "#8a8a8a",
"selectedColor": "#204e2b",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
+34 -11
View File
@@ -1,9 +1,7 @@
<template>
<view class="card-container">
<!-- 顶部标题栏 -->
<view class="header">
<text class="header-title">我的就诊卡</text>
</view>
<!-- 就诊卡列表 -->
<view class="card-list">
@@ -61,6 +59,7 @@
<view v-if="!loading && cardList.length === 0" class="empty-state">
<uni-icons type="wallet" size="60" color="#999"></uni-icons>
<text class="empty-text">暂无就诊卡</text>
<view class="add-card-btn" @click="createCard">新建就诊卡</view>
</view>
<!-- 加载状态 -->
@@ -73,7 +72,7 @@
<script setup>
import { ref, onMounted, getCurrentInstance } from 'vue'
import { onLaunch, onShow, onHide, onError ,onShareAppMessage} from '@dcloudio/uni-app'
const { proxy } = getCurrentInstance()
// 数据
@@ -84,7 +83,9 @@ const loading = ref(false)
onMounted(() => {
loadCardList()
})
onShow(() => {
loadCardList()
})
// 加载就诊卡列表
const loadCardList = async () => {
loading.value = true
@@ -93,9 +94,9 @@ const loadCardList = async () => {
const token = uni.getStorageSync('token')
if (!token) {
uni.showToast({ title: '请先登录', icon: 'none' })
setTimeout(() => {
uni.redirectTo({ url: '/pages/login/login' })
}, 1500)
// setTimeout(() => {
// uni.redirectTo({ url: '/pages/login/login' })
// }, 1500)
return
}
@@ -104,7 +105,7 @@ const loadCardList = async () => {
const patientId = userData?.diagnosis?.patient_id
if (!patientId) {
uni.showToast({ title: '患者信息不存在', icon: 'none' })
//uni.showToast({ title: '患者信息不存在', icon: 'none' })
return
}
@@ -137,6 +138,18 @@ const viewCardDetail = (card) => {
})
}
// 新建就诊卡(patient_id 创建后自动生成,仅需登录)
const createCard = () => {
const token = uni.getStorageSync('token')
if (!token) {
uni.showToast({ title: '请先登录', icon: 'none' })
return
}
uni.navigateTo({
url: '/pages/Card/edit_card?add=1'
})
}
// 获取状态文本
const getStatusText = (status) => {
return status === 1 ? '启用' : '禁用'
@@ -257,8 +270,8 @@ const formatDate = (timestamp) => {
&.status-confirmed {
background: #f6ffed;
color: #52c41a;
border: 2rpx solid #b7eb8f;
color: #204e2b;
border: 2rpx solid #204e2b;
}
&.status-pending {
@@ -343,9 +356,19 @@ const formatDate = (timestamp) => {
.empty-text {
font-size: 32rpx;
color: #999999;
margin-bottom: 40rpx;
}
}
.add-card-btn {
padding: 24rpx 64rpx;
background: #1890ff;
color: #ffffff;
font-size: 30rpx;
font-weight: 500;
border-radius: 48rpx;
}
.loading-state {
display: flex;
justify-content: center;
+37 -14
View File
@@ -821,6 +821,7 @@ const agreedToTerms = ref(true) // 默认选中"是"
const showDatePicker = ref(false)
const diagnosisId = ref(null)
const patientId = ref(null)
const isAddMode = ref(false) // 新建模式
// 表单数据
const formData = ref({
@@ -1063,23 +1064,37 @@ const loadCardDetail = async () => {
try {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
diagnosisId.value = currentPage.options.id
if (!diagnosisId.value) {
uni.showToast({ title: '诊单ID不存在', icon: 'none' })
setTimeout(() => uni.navigateBack(), 1500)
return
}
const options = currentPage.options || {}
diagnosisId.value = options.id
isAddMode.value = options.add === '1' || options.add === 1
const userData = uni.getStorageSync('userData')
patientId.value = userData?.diagnosis?.patient_id
// 新建模式:patient_id 可选(创建后自动生成),仅需登录
if (isAddMode.value) {
const token = uni.getStorageSync('token')
if (!token) {
uni.showToast({ title: '请先登录', icon: 'none' })
setTimeout(() => uni.redirectTo({ url: '/pages/login/login' }), 1500)
return
}
loading.value = false
return
}
if (!patientId.value) {
uni.showToast({ title: '请先登录', icon: 'none' })
setTimeout(() => uni.redirectTo({ url: '/pages/login/login' }), 1500)
return
}
if (!diagnosisId.value) {
uni.showToast({ title: '诊单ID不存在', icon: 'none' })
setTimeout(() => uni.navigateBack(), 1500)
return
}
const res = await proxy.apiUrl({
url: '/api/tcm/diagnosisDetail',
method: 'GET',
@@ -1302,18 +1317,26 @@ const submitForm = async () => {
submitData.diagnosis_date = submitData.local_hospital_visit_date
}
const apiUrl = isAddMode.value ? '/api/tcm/addCard' : '/api/tcm/updateCard'
const apiData = isAddMode.value
? { ...submitData, ...(patientId.value ? { patient_id: patientId.value } : {}) }
: { id: diagnosisId.value, patient_id: patientId.value, ...submitData }
const res = await proxy.apiUrl({
url: '/api/tcm/updateCard',
url: apiUrl,
method: 'POST',
data: {
id: diagnosisId.value,
patient_id: patientId.value,
...submitData
}
data: apiData
})
if (res.code === 1) {
uni.showToast({ title: '保存成功', icon: 'success' })
// 新建成功:若有返回 patient_id,写入 userData 供后续列表查询
if (isAddMode.value && res.data?.patient_id) {
const userData = uni.getStorageSync('userData') || {}
if (!userData.diagnosis) userData.diagnosis = {}
userData.diagnosis.patient_id = res.data.patient_id
uni.setStorageSync('userData', userData)
}
uni.showToast({ title: isAddMode.value ? '创建成功' : '保存成功', icon: 'success' })
setTimeout(() => {
uni.navigateBack()
}, 1500)
+531 -375
View File
@@ -1,39 +1,123 @@
<template>
<view class="container">
<!-- 搜索栏 -->
<view class="search-section">
<view class="search-bar">
<text class="search-icon">🔍</text>
<input class="search-input" placeholder="搜索药材、医生或症状..." type="text" />
<text class="search-filter"></text>
</view>
</view>
<!-- 问诊服务 -->
<!-- 科室分类 -->
<view class="department-section">
<view class="section-header">
<text class="section-title">科室分类</text>
<text class="more-link" @click="navigateToDepartments">查看全部</text>
</view>
<view class="department-grid">
<view class="dept-col-left">
<view
class="department-card large"
@click="navigateToDepartment(departments[0])"
>
<view class="dept-card-inner dept-green">
<view class="dept-icon"><text class="icon-text"></text></view>
<text class="dept-name text-white">针灸</text>
<text class="dept-desc text-white-sub">调理气血</text>
</view>
</view>
</view>
<view class="dept-col-right">
<view
class="department-card small"
@click="navigateToDepartment(departments[1])"
>
<view class="dept-card-inner dept-beige">
<view class="dept-icon-wrap">
<view class="dept-icon"><text class="icon-text"></text></view>
</view>
<view>
<text class="dept-name">中药</text>
<text class="dept-desc">古法方剂</text>
</view>
</view>
</view>
<view
class="department-card small"
@click="navigateToDepartment(departments[2])"
>
<view class="dept-card-inner dept-grey">
<view class="dept-icon-wrap">
<view class="dept-icon"><text class="icon-text"></text></view>
</view>
<view>
<text class="dept-name">推拿</text>
<text class="dept-desc">中医按摩</text>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 特色专科医师 -->
<!-- 名医推荐 -->
<view class="doctors-section">
<view class="section-header">
<view class="section-title-wrapper">
<view class="section-title">特色专科医师</view>
</view>
<view class="more-link" @click="navigateToAllDoctors">更多</view>
<text class="section-title">名医推荐</text>
<text class="more-link" @click="navigateToAllDoctors">查看全部</text>
</view>
<view class="doctors-grid">
<view class="doctors-list">
<view
v-for="doctor in doctors"
:key="doctor.id"
class="doctor-card"
@click="selectDoctor(doctor)"
>
<view class="doctor-avatar-wrapper">
<image :src="doctor.avatar" class="doctor-avatar" mode="aspectFill"></image>
<view class="avatar-frame"></view>
<image :src="doctor.avatar || defaultAvatar" class="doctor-photo" mode="aspectFill"></image>
<view class="doctor-info">
<view class="doctor-top">
<text class="doctor-name">{{ doctor.name }}</text>
<text class="doctor-rating"> {{ doctor.rating || '4.9' }}</text>
</view>
<text class="doctor-specialty">{{ doctor.specialty || doctor.title || '中医' }}</text>
<view class="doctor-price-row">
<text class="doctor-price">{{ doctor.price || '' }}</text>
<text class="doctor-unit">/</text>
</view>
<view class="doctor-actions">
<view class="appointment-btn" @click.stop="selectDoctor(doctor)">预约</view>
</view>
</view>
<view class="doctor-name">{{ doctor.name }}</view>
<view class="doctor-title">{{ doctor.title }}</view>
<view class="doctor-dept">{{ doctor.department || '内科' }}</view>
</view>
</view>
</view>
<!-- 健康百科 -->
<view class="encyclopedia-section">
<view class="section-header">
<text class="section-title">健康百科</text>
<text class="more-link" @click="navigateToEncyclopedia">查看全部</text>
</view>
<scroll-view class="encyclopedia-scroll no-scrollbar" scroll-x :show-scrollbar="false">
<view
v-for="article in articles"
:key="article.id"
class="article-card"
:class="{ 'article-card-secondary': article.id === 2 }"
@click="navigateToArticle(article)"
>
<view class="article-image-wrap">
<image :src="article.cover" class="article-image" mode="aspectFill"></image>
<view class="article-gradient" :class="{ 'gradient-secondary': article.id === 2 }"></view>
<view class="article-tag" :class="{ 'tag-secondary': article.id === 2 }">{{ article.tag }}</view>
</view>
<text class="article-title" :class="{ 'title-secondary': article.id === 2 }">{{ article.title }}</text>
<text class="article-desc">{{ article.desc }}</text>
</view>
</scroll-view>
</view>
</view>
</template>
@@ -45,51 +129,46 @@ const { proxy } = getCurrentInstance()
const doctors = ref([])
const loading = ref(false)
const defaultAvatar = '/static/user/user.png'
// 科室分类
const departments = ref([
{ id: 1, name: '针灸', desc: '调理气血', icon: '✦', iconClass: 'icon-acupuncture', bgColor: 'linear-gradient(135deg, #2d5a3d 0%, #3d7a4d 100%)', dark: true, size: 'large', pattern: true },
{ id: 2, name: '中药', desc: '古法方剂', icon: '◉', iconClass: 'icon-herb', bgColor: '#F5E6D3', dark: false, size: 'small' },
{ id: 3, name: '推拿', desc: '中医按摩', icon: '☯', iconClass: 'icon-massage', bgColor: '#E8E4DF', dark: false, size: 'small' }
])
// 健康百科
const articles = ref([
{ id: 1, title: '晨间生姜:脾胃健康的催化剂', desc: '了解每天早晨一片生姜如何改善您的新陈代谢...', tag: '膳食营养', cover: 'https://picsum.photos/seed/herb/300/180' },
{ id: 2, title: '四时呼吸:顺应节气养生', desc: '顺应节气,调养身心...', tag: '正念冥想', cover: 'https://picsum.photos/seed/nature/300/180' },
{ id: 3, title: '中医养生之道', desc: '传统智慧,现代健康...', tag: '养生保健', cover: 'https://picsum.photos/seed/health/300/180' }
])
const selectDoctor = (doctor) => {
uni.navigateTo({
url: `/pages/order/index?doctorId=${doctor.id}&doctorName=${doctor.name}`
url: `/doctor/pages/doctor/doctor?id=${doctor.id}`
})
}
const navigateToExperts = () => {
uni.navigateTo({
url: '/pages/experts/index'
})
const navigateToDepartments = () => {
uni.showToast({ title: '科室列表', icon: 'none' })
}
const navigateToConsultation = () => {
uni.navigateTo({
url: '/pages/consultation/index'
})
}
const navigateToQuickConsult = () => {
uni.navigateTo({
url: '/pages/quick-consult/index'
})
const navigateToDepartment = (item) => {
uni.showToast({ title: item.name, icon: 'none' })
}
const navigateToAllDoctors = () => {
uni.navigateTo({
url: '/pages/doctors/index'
})
uni.showToast({ title: '更多医生', icon: 'none' })
}
const navigateToHome = () => {
// 已在首页
const navigateToEncyclopedia = () => {
uni.showToast({ title: '健康百科', icon: 'none' })
}
const navigateToMessages = () => {
uni.navigateTo({
url: '/pages/messages/index'
})
}
const navigateToProfile = () => {
uni.navigateTo({
url: '/pages/profile/index'
})
const navigateToArticle = (article) => {
uni.showToast({ title: article.title, icon: 'none' })
}
const fetchDoctors = async () => {
@@ -124,377 +203,454 @@ onMounted(() => {
</script>
<style scoped lang="scss">
/* TCM Care 设计系统 - 源自 code.html */
$background: #faf9f5;
$primary: #204e2b;
$primary-container: #386641;
$on-primary: #ffffff;
$on-primary-container: #afe2b3;
$secondary-container: #fdc39a;
$on-secondary-container: #794e2e;
$surface-container-lowest: #ffffff;
$surface-container-low: #f4f4f0;
$surface-container-high: #e9e8e4;
$surface-container-highest: #e3e2df;
$on-surface: #1b1c1a;
$on-surface-variant: #414941;
$tertiary-container: #4b6500;
$tertiary: #384c00;
$outline: #727970;
.container {
background: #f5f3f0;
background: $background;
min-height: 100vh;
padding-bottom: 120rpx;
padding: 24rpx 32rpx 120rpx;
font-family: 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
// 古典卷轴横幅
.scroll-banner {
margin: 24rpx 16rpx;
.font-headline {
font-family: 'Noto Serif', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', serif;
}
// 搜索栏 - surface-container-low
.search-section {
margin-bottom: 32rpx;
}
.search-bar {
display: flex;
align-items: center;
position: relative;
background: $surface-container-low;
border-radius: 24rpx;
padding: 24rpx 32rpx;
}
.scroll-rod {
width: 32rpx;
height: 160rpx;
background: linear-gradient(180deg, #8B7355 0%, #6B5644 50%, #8B7355 100%);
border-radius: 16rpx;
position: relative;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.2);
&::before {
content: '';
position: absolute;
top: 16rpx;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 40rpx;
background: radial-gradient(circle, #D4AF37 0%, #B8941E 100%);
border-radius: 50%;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.3);
}
&::after {
content: '';
position: absolute;
bottom: 16rpx;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 40rpx;
background: radial-gradient(circle, #D4AF37 0%, #B8941E 100%);
border-radius: 50%;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.3);
}
.search-icon {
font-size: 36rpx;
color: $outline;
margin-right: 24rpx;
}
.scroll-rod-left {
margin-right: -8rpx;
z-index: 2;
}
.scroll-rod-right {
margin-left: -8rpx;
z-index: 2;
}
.scroll-content {
.search-input {
flex: 1;
background: linear-gradient(135deg, #F5E6D3 0%, #E8D7C3 100%);
border: 3rpx solid #8B7355;
border-radius: 12rpx;
padding: 24rpx;
box-shadow: inset 0 2rpx 8rpx rgba(139, 115, 85, 0.2);
position: relative;
&::before {
content: '';
position: absolute;
top: 12rpx;
left: 12rpx;
right: 12rpx;
bottom: 12rpx;
border: 1rpx solid rgba(139, 115, 85, 0.3);
border-radius: 8rpx;
pointer-events: none;
}
}
.scroll-inner {
display: flex;
align-items: center;
gap: 20rpx;
position: relative;
z-index: 1;
}
.scroll-text {
flex: 1;
}
.scroll-title {
font-size: 32rpx;
font-weight: bold;
color: #3E2723;
margin-bottom: 8rpx;
font-family: 'STKaiti', 'KaiTi', serif;
}
.scroll-subtitle {
font-size: 24rpx;
color: #5D4037;
font-family: 'STKaiti', 'KaiTi', serif;
}
.scroll-image {
width: 200rpx;
height: 120rpx;
border-radius: 8rpx;
border: 2rpx solid #8B7355;
}
// 问诊服务
.services-section {
padding: 32rpx 16rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #3E2723;
margin-bottom: 24rpx;
font-family: 'STKaiti', 'KaiTi', serif;
position: relative;
padding-left: 16rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 28rpx;
background: linear-gradient(180deg, #D4AF37 0%, #B8941E 100%);
border-radius: 3rpx;
}
}
.services-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16rpx;
}
.service-card {
border-radius: 20rpx;
padding: 24rpx 16rpx;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
min-height: 320rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
}
.card-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0.15;
z-index: 0;
}
.bg-decoration {
width: 100%;
height: 100%;
}
.card-content {
position: relative;
z-index: 1;
flex: 1;
display: flex;
flex-direction: column;
}
.service-expert {
background: linear-gradient(135deg, #FFF8DC 0%, #F5E6D3 100%);
border: 2rpx solid #E8D7C3;
}
.service-health {
background: linear-gradient(135deg, #E8F5E9 0%, #C8E6C9 100%);
border: 2rpx solid #A5D6A7;
}
.service-quick {
background: linear-gradient(135deg, #E0F2F1 0%, #B2DFDB 100%);
border: 2rpx solid #80CBC4;
}
.service-title {
background: transparent;
font-size: 28rpx;
font-weight: bold;
color: #3E2723;
margin-bottom: 12rpx;
font-family: 'STKaiti', 'KaiTi', serif;
color: $on-surface;
}
.service-desc {
font-size: 22rpx;
color: #5D4037;
line-height: 1.5;
margin-bottom: 16rpx;
flex: 1;
.search-input::placeholder {
color: #414941;
opacity: 0.5;
}
.service-icon {
font-size: 56rpx;
text-align: center;
margin: 16rpx 0;
opacity: 0.8;
}
.service-btn {
color: #fff;
padding: 16rpx 24rpx;
border-radius: 32rpx;
font-size: 24rpx;
font-weight: bold;
text-align: center;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.15);
position: relative;
z-index: 1;
}
.btn-orange {
background: linear-gradient(135deg, #D2691E 0%, #CD853F 100%);
}
.btn-green {
background: linear-gradient(135deg, #2E7D32 0%, #388E3C 100%);
}
.btn-purple {
background: linear-gradient(135deg, #4A148C 0%, #6A1B9A 100%);
}
// 特色专科医师
.doctors-section {
padding: 32rpx 16rpx;
.search-filter {
font-size: 36rpx;
color: $outline;
}
// 通用区块
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
align-items: flex-end;
margin-bottom: 32rpx;
}
.section-title-wrapper {
display: flex;
align-items: center;
gap: 8rpx;
}
.title-icon {
font-size: 28rpx;
.section-title {
font-size: 48rpx;
font-weight: bold;
color: $on-surface;
font-family: 'Noto Serif', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', serif;
}
.more-link {
font-size: 24rpx;
color: #D4AF37;
font-size: 28rpx;
color: $primary;
font-weight: 500;
}
.doctors-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16rpx;
// 科室分类 - grid 布局
.department-section {
margin-bottom: 64rpx;
}
.doctor-card {
background: #fff;
border-radius: 16rpx;
padding: 20rpx;
text-align: center;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
}
.doctor-avatar-wrapper {
position: relative;
margin-bottom: 16rpx;
.department-grid {
display: flex;
justify-content: center;
gap: 32rpx;
}
.doctor-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
border: 3rpx solid #E8E8E8;
.dept-col-left {
flex: 1;
}
.avatar-frame {
position: absolute;
top: -4rpx;
left: 50%;
transform: translateX(-50%);
width: 128rpx;
height: 128rpx;
border: 2rpx solid rgba(212, 175, 55, 0.3);
border-radius: 50%;
pointer-events: none;
}
.doctor-name {
font-size: 26rpx;
font-weight: bold;
color: #3E2723;
margin-bottom: 6rpx;
}
.doctor-title {
font-size: 22rpx;
color: #757575;
margin-bottom: 4rpx;
}
.doctor-dept {
font-size: 20rpx;
color: #9E9E9E;
}
// 底部导航
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
border-top: 1rpx solid #E8E8E8;
display: flex;
justify-content: space-around;
padding: 16rpx 0 24rpx 0;
box-shadow: 0 -2rpx 8rpx rgba(0, 0, 0, 0.05);
z-index: 100;
}
.nav-item {
.dept-col-right {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 6rpx;
flex: 1;
gap: 32rpx;
}
.department-card {
&.large {
height: 100%;
min-height: 320rpx;
}
&.active {
.nav-icon {
font-size: 40rpx;
}
.nav-text {
color: #D4AF37;
font-weight: bold;
}
&.small {
flex: 1;
min-height: 160rpx;
}
}
.nav-icon {
font-size: 36rpx;
transition: all 0.3s ease;
.dept-card-inner {
border-radius: 24rpx;
padding: 40rpx;
height: 100%;
min-height: 160rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.nav-text {
font-size: 22rpx;
color: #757575;
transition: all 0.3s ease;
/* 针灸 - primary-container */
.dept-green {
background: $primary-container;
color: $on-primary;
}
.dept-green .dept-icon .icon-text,
.dept-green .dept-name {
color: $on-primary;
}
.dept-green .dept-desc {
color: $on-primary-container;
font-size: 24rpx;
}
/* 中药 - secondary-container */
.dept-beige {
background: $secondary-container;
color: $on-secondary-container;
flex-direction: row;
align-items: center;
gap: 24rpx;
padding: 32rpx;
}
.dept-beige .dept-icon-wrap {
background: rgba(255, 255, 255, 0.4);
padding: 16rpx;
border-radius: 16rpx;
}
.dept-beige .dept-icon .icon-text {
font-size: 40rpx;
color: $on-secondary-container;
}
.dept-beige .dept-name {
color: $on-secondary-container;
margin-bottom: 4rpx;
display: block;
}
.dept-beige .dept-desc {
color: $on-secondary-container;
opacity: 0.8;
font-size: 20rpx;
display: block;
}
/* 推拿 - surface-container-high */
.dept-grey {
background: $surface-container-high;
color: $on-surface;
flex-direction: row;
align-items: center;
gap: 24rpx;
padding: 32rpx;
}
.dept-grey .dept-icon-wrap {
background: rgba(255, 255, 255, 0.6);
padding: 16rpx;
border-radius: 16rpx;
}
.dept-grey .dept-icon .icon-text {
font-size: 40rpx;
color: $primary;
}
.dept-grey .dept-name {
color: $on-surface;
display: block;
}
.dept-grey .dept-desc {
color: $on-surface-variant;
font-size: 20rpx;
display: block;
}
.dept-icon {
margin-bottom: 16rpx;
}
.dept-beige .dept-icon,
.dept-grey .dept-icon {
margin-bottom: 0;
}
.dept-icon .icon-text {
font-size: 56rpx;
color: $on-primary;
}
.dept-name {
font-size: 36rpx;
font-weight: 600;
color: $on-surface;
margin-bottom: 8rpx;
font-family: 'Noto Serif', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', serif;
&.text-white {
color: $on-primary;
}
}
.dept-desc {
font-size: 26rpx;
color: $on-surface-variant;
&.text-white-sub {
color: $on-primary-container;
}
}
// 名医推荐
.doctors-section {
margin-bottom: 64rpx;
}
.doctors-list {
display: flex;
flex-direction: column;
gap: 32rpx;
}
.doctor-card {
background: $surface-container-lowest;
border-radius: 24rpx;
padding: 40rpx;
display: flex;
align-items: center;
gap: 32rpx;
}
.doctor-photo {
width: 160rpx;
height: 230rpx;
border-radius: 16rpx;
flex-shrink: 0;
background: $surface-container-highest;
}
.doctor-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 192rpx;
}
.doctor-top {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 8rpx;
}
.doctor-name {
font-size: 36rpx;
font-weight: bold;
color: $on-surface;
font-family: 'Noto Serif', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', serif;
}
.doctor-rating {
font-size: 24rpx;
color: #805533;
font-weight: bold;
}
.doctor-specialty {
font-size: 28rpx;
color: $on-surface-variant;
margin-bottom: 16rpx;
}
.doctor-price-row {
margin-bottom: 16rpx;
}
.doctor-price {
font-size: 28rpx;
color: $primary;
font-weight: bold;
}
.doctor-unit {
font-size: 24rpx;
font-weight: normal;
color: $on-surface-variant;
}
.doctor-actions {
display: flex;
justify-content: flex-end;
}
.appointment-btn {
background: $primary;
color: $on-primary;
font-size: 24rpx;
font-weight: bold;
padding: 16rpx 32rpx;
border-radius: 9999rpx;
}
// 健康百科 - 横向滚动
.encyclopedia-section {
margin-bottom: 64rpx;
}
.encyclopedia-scroll {
white-space: nowrap;
margin: 0 -32rpx;
padding: 0 32rpx 32rpx;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.article-card {
display: inline-block;
width: 560rpx;
margin-right: 40rpx;
background: rgba(75, 101, 0, 0.06);
border-radius: 24rpx;
overflow: hidden;
vertical-align: top;
}
.article-card-secondary {
background: rgba(253, 195, 154, 0.1);
}
.article-card:last-child {
margin-right: 0;
}
.article-image-wrap {
position: relative;
width: 100%;
height: 256rpx;
overflow: hidden;
}
.article-image {
width: 100%;
height: 100%;
background: $tertiary-container;
opacity: 0.8;
}
.article-gradient {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
background: linear-gradient(to top, $tertiary-container, transparent);
}
.article-gradient.gradient-secondary {
background: linear-gradient(to top, $secondary-container, transparent);
}
.article-tag {
position: absolute;
bottom: 16rpx;
left: 24rpx;
background: $tertiary;
color: $on-primary;
font-size: 20rpx;
padding: 8rpx 16rpx;
border-radius: 9999rpx;
text-transform: uppercase;
font-weight: bold;
letter-spacing: 0.05em;
z-index: 1;
}
.article-tag.tag-secondary {
background: #805533;
color: #ffffff;
}
.article-title {
font-size: 28rpx;
font-weight: bold;
color: #394d00;
padding: 32rpx 32rpx 8rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
font-family: 'Noto Serif', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', serif;
}
.article-title.title-secondary {
color: $on-secondary-container;
}
.article-desc {
font-size: 24rpx;
color: $on-surface-variant;
padding: 0 32rpx 32rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>
+7 -4
View File
@@ -64,15 +64,17 @@ import { ref,onMounted,getCurrentInstance} from "vue";
const { proxy } = getCurrentInstance()
import * as GenerateTestUserSig from "@/debug/GenerateTestUserSig-es.js";
import { CallManager } from "@/TUICallKit/src/TUICallService/serve/callManager";
import { onLaunch, onShow, onHide, onError ,onShareAppMessage} from '@dcloudio/uni-app'
let userID = ref("4");
let avatarUrl = ref(""); // 声明为响应式变量
uni.CallManager = new CallManager();
onMounted(() => {
onLaunch(() => {
uni.login({
provider: 'weixin',
success: function (loginRes) {
wxcode(loginRes.code)
// 获取用户信息
@@ -105,7 +107,8 @@ onShareAppMessage((res) =>{
});
const wxcode = async (code) => {
return
try {
// 通过 proxy 调用全局的 apiUrl
const res = await proxy.apiUrl({
@@ -115,7 +118,7 @@ const wxcode = async (code) => {
code: code
},
}, false) // 不显示加载中
loginHandler(res.data.diagnosis.patient_id)
} catch (err) {
uni.showToast({ title: '请求失败', icon: 'none' })
+15 -6
View File
@@ -50,16 +50,17 @@
</template>
<script setup>
import { ref, getCurrentInstance } from "vue";
import { ref, getCurrentInstance,onMounted } from "vue";
import { onShow, onShareAppMessage } from '@dcloudio/uni-app'
const { proxy } = getCurrentInstance()
import * as GenerateTestUserSig from "@/debug/GenerateTestUserSig-es.js";
import { CallManager } from "@/TUICallKit/src/TUICallService/serve/callManager";
const { proxy } = getCurrentInstance()
let userId = ref("");
let userSig= ref("");
let SDKAppID=ref("");
uni.CallManager = new CallManager();
const doctorId = ref('')
const doctorName = ref('')
onShow(() => {
uni.login({
provider: 'weixin',
@@ -69,7 +70,15 @@ onShow(() => {
}
});
})
onMounted(() => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
// const options = current.options || current.$page?.options || {}
const options = proxy.$parsePageParams(currentPage.options|| currentPage.$page?.options || {});
doctorId.value = options.id || options.doctorId || ''
console.log('---------进入onMounted',options,doctorId.value)
})
onShareAppMessage((res) =>{
return {
title: '视频问诊通话邀请',
@@ -94,7 +103,7 @@ const wxcode = async (code) => {
data: { code: code },
}, false)
console.log('---------------',res.data)
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('userData', res.data)
loginHandler(res.data.diagnosis.patient_id)
} catch (err) {
@@ -103,7 +112,7 @@ const wxcode = async (code) => {
}
}
const url=()=>{
const doctor='doctor_'+uni.getStorageSync('userData').diagnosis.diagnosis_id
const doctor=doctorId.value?'doctor_'+doctorId.value:'doctor_'+uni.getStorageSync('userData').diagnosis.diagnosis_id
// 跳转到聊天页面
uni.navigateTo({
url: `/TUIKit/pages/chat/chat?userID=${encodeURIComponent(userId)}&userSig=${encodeURIComponent(userSig)}&SDKAppID=${SDKAppID}&targetUserID=${doctor}`
+3 -39
View File
@@ -519,51 +519,15 @@ const getDictData = async (type) => {
}
};
// 解析页面参数(支持普通参数和scene参数)
const parsePageParams = (options) => {
const params = {};
// 如果有scene参数(扫码进入),解析scene
if (options.scene) {
try {
// URL解码scene参数
const decodedScene = decodeURIComponent(options.scene);
// 解析键值对:id=4&share_user=1
decodedScene.split('&').forEach(item => {
const [key, value] = item.split('=');
if (key && value) {
params[key] = value;
}
});
} catch (error) {
console.error('解析scene参数失败:', error);
}
}
// 合并普通参数(普通跳转进入)
Object.keys(options).forEach(key => {
if (key !== 'scene' && options[key]) {
params[key] = options[key];
}
});
// 获取当前登录用户ID(从本地存储或全局状态获取)
// TODO: 根据你的项目实际情况获取用户ID
// 例如: const userInfo = uni.getStorageSync('userInfo');
// params.user_id = userInfo?.id || 0;
return params;
};
// 加载诊单详情
const loadDiagnosisDetail = async () => {
// 从页面参数获取诊单ID
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const params = parsePageParams(currentPage.options);
const params = proxy.$parsePageParams(currentPage.options);
dingdan_ok.value=uni.getStorageSync('dingdan_ok');
const diagnosisId = params.id;
console.log('页面参数:', params, '诊单ID:', diagnosisId);
console.log('进入onMounted:', params, '诊单ID:', diagnosisId);
if (!diagnosisId) {
uni.showToast({ title: '缺少诊单ID', icon: 'none' });
@@ -724,7 +688,7 @@ const handleConfirm = () => {
const confirmDiagnosis = async () => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const params = parsePageParams(currentPage.options);
const params = proxy.$parsePageParams(currentPage.options);
console.log('确认诊单参数:', params);
+1 -24
View File
@@ -100,36 +100,13 @@ onMounted(() => {
loadOrderDetail()
})
const parsePageParams = (options) => {
const params = {}
if (options.scene) {
try {
const decodedScene = decodeURIComponent(options.scene)
decodedScene.split('&').forEach(item => {
const [key, value] = item.split('=')
if (key && value) {
params[key] = value
}
})
} catch (error) {
console.error('解析scene参数失败:', error)
}
}
Object.keys(options).forEach(key => {
if (key !== 'scene' && options[key]) {
params[key] = options[key]
}
})
return params
}
const loadOrderDetail = async () => {
loading.value = true
errorMsg.value = ''
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const params = parsePageParams(currentPage.options || {})
const params = proxy.$parsePageParams(currentPage.options || {})
orderNo.value = params.order_no || ''
if (!orderNo.value) {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

+5 -1
View File
@@ -78,5 +78,9 @@ export const doctorApi = {
getDoctorDetail: (id) => get('/api/doctor/detail', { id }, false),
// 获取医生排班
getDoctorRoster: (doctorId, date) => get('/api/doctor/roster', { doctor_id: doctorId, date }, false)
getDoctorRoster: (doctorId, date) => get('/api/doctor/roster', { doctor_id: doctorId, date }, false),
// 获取医生评价列表
getDoctorReviews: (doctorId, pageNo = 1, pageSize = 10) =>
get('/api/doctor/reviews', { doctor_id: doctorId, page_no: pageNo, page_size: pageSize }, false)
}