Files
xk-client-wx/subPackages/doctor/doctor-detail.vue
李琦 2d2a8abfd4 feat(home/chat): 列表骨架屏、聊天室己方头像与协议/医生详情优化
- 新增分包组件 ListSkeleton(doctor/message/product/article/category/zone)
- 首页/消息/资讯首次加载改用骨架屏,刷新不再清空旧数据避免闪空
  · 去掉 home getList、消息 onShow 中的数组清空
  · 三页 pages.json 增加 easycom 与 componentPlaceholder 主包异步引用
- 聊天室己方头像改为读取本地 userinfo.avatarurl(登录后微信头像),
  mycollection 上传头像成功后同步写回 storage
- 修复协议抽屉点不开:page-container 改为 v-if + :show;
  协议名单独可点节点,匹配放宽 name/desc 双向 includes
- 医生气泡头像可点击进入 doctor-detail?readonly=1 只读医生详情,
  隐藏预约挂号区
2026-07-19 16:08:04 +08:00

712 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="container safe-area-inset-bottom">
<MessageNotification />
<!-- 名片 -->
<view class="card">
<!-- 姓名 -->
<view class="card_top">
<view class="card_top_left">
<view class="name">
{{doctorList.name}}
</view>
<text>{{doctorList.title}} &nbsp; {{doctorList.depart}}</text>
<text>{{doctorList.store}}</text>
</view>
<!-- 图片 -->
<view class="card_top_right">
<image :src="doctorList.avator || 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/mine/avatar_1.png'" mode="医生头像"></image>
</view>
</view>
<!-- 好评率 擅长 -->
<view class="card_center">
<view class="card_center_top">
<view class="txt">问诊量 <text>{{doctorList.inquiry_num}}</text></view>
<view class="txt">接诊率<text>{{doctorList.accept_percent}}</text></view>
<view class="txt">综合评分 <text>{{doctorList.overall_score}}</text></view>
</view>
<view class="going">
专业擅长{{doctorList.good_at}}
</view>
</view>
<!-- 详细信息 通知栏 -->
<view class="card_bottom">
<view class="info" @click="godoctor">
查看全部 <text class="iconfont icon-jiantou1"></text>
</view>
</view>
</view>
<!-- 到店医生 预约挂号聊天室只读进入时不展示挂号入口 -->
<view class="appoin" v-if="!readonly">
<view class="title">预约挂号</view>
<view class="list">
<view class="yard">
<view class="stores">
<view class="times">{{registList.time}}</view>
<text class="price">{{registList.register_price}}</text>
</view>
<view class="btn" :class="(registList.left_num || 0) <= 0 ? 'active' : ''" @click="goAdd">
{{(registList.left_num || 0) > 0 ? '挂号' : '约满'}}
</view>
</view>
<view class="yard">
<view class="num">剩余号 <text>{{registList.left_num}}</text> </view>
<view class="num">总号数{{registList.register_num}}</view>
</view>
</view>
</view>
<!-- 患者评价 -->
<!-- <view class="evaluation">
<view class="lists" @click="goevalua">
<view class="lists_left">
患者评价({{userList.length}})
</view>
<view class="lists_right">
<text>查看全部</text>
<text class="iconfont icon-jiantou1"></text>
</view>
</view>
<view class="empty" v-if="userList.length<=0">
<image src="https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/empty/orders.png" mode="aspectFit"></image>
</view>
<view class="items" v-for="(item,index) in userList" :key="item.id">
<image :src="item.avator || 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/mine/avatar_1.png'" mode=""></image>
<view class="items_right">
<view class="item_name">
<view class="title">
<text>{{item.nickname || '微信用户'}}</text>
<u-rate :count="count" v-model="item.score" :disabled="true" active-color="#FB8C00"
inactive-color="#E2E8F0" size="20"></u-rate>
</view>
<view class="time">
{{item.created_at}}
</view>
</view>
<view class="info">
{{item.comment}}
</view>
</view>
</view>
</view> -->
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
commentList,
doctorDetail,
registerList,
storeChange,
userList
} from '@/request/api/api'
import { isGuestMode, isLoggedIn, saveRedirectInfo, buildUrlWithParams } from '@/common/utils/auth.js';
export default {
data() {
return {
follow: true,
isshow: 1,
actived: 0,
doctorID: "", // 医生id
doctorList: {}, // 医生列表
id: "",
num: 0,
count: 5,
value: 2,
userList: [],
registList: [],
peopleList: [],
rType: '0', // 挂号类型
// 聊天室等场景只读查看:隐藏挂号按钮区
readonly: false,
}
},
onLoad(e) {
console.log(e, 'e');
this.readonly = e.readonly === '1' || e.readonly === 1;
// 允许未登录访问,移除登录跳转
// 如果是guest模式强制设置store_id为11001
if (isGuestMode()) {
uni.setStorageSync('store_id', '11001');
}
// 扫码之后
if (e.scene) {
const id = uni.getStorageSync('st_id')
const doctorID = uni.getStorageSync('doctors_id')
if (e.scene && id && doctorID) {
this.toChang(id)
uni.setStorageSync('store_id', id)
}
const st_id = decodeURIComponent(e.scene).split('&')
const doctors_id = decodeURIComponent(e.scene).split('=')
uni.setStorageSync('doctors_id', st_id[0].split('su_id=')[1])
uni.setStorageSync('st_id', doctors_id[2])
// console.log(st_id, '2222');
this.doctorID = uni.getStorageSync('doctors_id')
this.getDocdetail();
this.getUser();
// 只读模式不拉号源,避免无用请求
if (!this.readonly) {
this.getRegist();
}
console.log(this.doctorID, '6666');
} else {
// 点击详情
this.doctorID = e.id
this.rType = e.r_type || '0' // 接收挂号类型参数
// 未登录时强制使用11001
if (isGuestMode()) {
uni.setStorageSync('store_id', '11001');
this.getDocdetail();
if (!this.readonly) {
this.getRegist();
}
} else {
const id = e.sts_id || uni.getStorageSync('store_id')
if (id!='undefined' && id) {
console.log('idddd');
this.toChang(id)
uni.setStorageSync('store_id', id)
}
}
}
},
methods: {
// 医生信息
godoctor() {
uni.navigateTo({
url: "/subPackages/doctor/doctor-info?id=" + this.id
})
},
// 挂号
goAdd() {
// 只读模式不允许挂号
if (this.readonly) return;
// 如果未登录,保存跳转信息并跳转到登录页
if (!isLoggedIn()) {
const storeId = uni.getStorageSync('store_id') || '11001';
saveRedirectInfo('/subPackages/doctor/doctor-detail', {
id: this.doctorID,
store_id: storeId,
r_type: this.rType
});
uni.navigateTo({
url: buildUrlWithParams('/pages/login/login', {
redirect: 'doctor-detail',
doctor_id: this.doctorID,
store_id: storeId
})
});
return;
}
if (this.num == 0) {
uni.showToast({
title: '暂无号源',
duration: 2000,
icon: "error"
});
return
}
if (this.peopleList.length <= 0) {
uni.navigateTo({
url: "/subPackages/my/myinfo-add?id=",
})
return
}
uni.navigateTo({
url: "/subPackages/doctor/doctor-userinfo?id=" + this.doctorID + "&r_type=" + this.rType,
})
},
// 评价
goevalua() {
uni.navigateTo({
url: "/subPackages/doctor/doctor-evaluation?id=" + this.doctorID,
})
},
// 医生详情
getDocdetail() {
doctorDetail({
method: "post",
data: {
doctor_id: this.doctorID,
store_id: uni.getStorageSync('store_id') || '11001',
}
}).then((res) => {
// console.log(res, 'ress');
const isGuest = isGuestMode();
const isNewFormat = isGuest && (res.data.code === 0 || res.data.code === '0');
const isOldFormat = !isGuest && (res.data.errcode === 0 || res.data.errcode === '0');
if (isNewFormat || isOldFormat) {
const responseData = isGuest && res.data.result ? res.data.result : res.data.data;
this.doctorList = responseData;
this.id = responseData.id;
} else {
const errorMsg = isGuest ? res.data.message : res.data.msg;
this.$refs.uToast.show({
title: errorMsg || '获取失败',
type: 'default',
icon: false
})
}
})
},
// 患者评价
getUser() {
commentList({
method: "post",
data: {
su_id: this.doctorID,
store_id: uni.getStorageSync('store_id') || '11001',
}
}).then((res) => {
// console.log(res, 'user');
const isGuest = isGuestMode();
const isNewFormat = isGuest && (res.data.code === 0 || res.data.code === '0');
const isOldFormat = !isGuest && (res.data.errcode === 0 || res.data.errcode === '0');
if (isNewFormat || isOldFormat) {
const responseData = isGuest && res.data.result ? res.data.result : res.data.data;
this.userList = (responseData.list || []).slice(0, 3);
}
})
},
// 预约挂号
getRegist() {
registerList({
method: "post",
data: {
service_user_id: this.doctorID,
store_id: uni.getStorageSync('store_id') || '11001',
}
}).then((res) => {
// console.log(res, 'reg');
const isGuest = isGuestMode();
const isNewFormat = isGuest && (res.data.code === 0 || res.data.code === '0');
const isOldFormat = !isGuest && (res.data.errcode === 0 || res.data.errcode === '0');
if (isNewFormat || isOldFormat) {
const responseData = isGuest && res.data.result ? res.data.result : res.data.data;
// 确保所有字段都有默认值,避免显示 undefined
this.registList = {
time: responseData.time || '',
register_price: responseData.register_price || 0,
left_num: parseInt(responseData.left_num) || 0,
register_num: parseInt(responseData.register_num) || 0,
register_status: responseData.register_status || 1
};
this.num = this.registList.left_num;
}
})
},
// 就诊人列表
getPeople() {
userList({
method: "post",
data: {
store_id: uni.getStorageSync('store_id') || '11001',
}
}).then((res) => {
// console.log(res, 'reg');
const isGuest = isGuestMode();
const isNewFormat = isGuest && (res.data.code === 0 || res.data.code === '0');
const isOldFormat = !isGuest && (res.data.errcode === 0 || res.data.errcode === '0');
if (isNewFormat || isOldFormat) {
const responseData = isGuest && res.data.result ? res.data.result : res.data.data;
this.peopleList = responseData.list || responseData || [];
}
})
},
// 切换门店
toChang(e) {
// console.log(e, 'id');
storeChange({
method: "post",
data: {
store_id: e
}
}).then((res) => {
if (res.data.errcode == 0) {
// uni.showToast({
// title: '切换成功',
// duration: 2000,
// icon: "success"
// });
}
})
},
},
mounted() {
this.getDocdetail();
this.getUser();
// 只读模式不拉号源/就诊人相关挂号数据
if (!this.readonly) {
this.getRegist();
this.getPeople();
}
if (!this.doctorList && doctorID) {
this.getDocdetail();
this.doctorID = uni.getStorageSync('doctors_id')
setTimeout(() => {
this.getDocdetail();
}, 900)
}
},
onShow() {
this.getPeople();
},
onUnload() {
// uni.removeStorageSync('doctors_id')
}
}
</script>
<style lang="scss" scoped>
.container {
width: 100vw;
min-height: 100vh;
max-height: 100%;
background-color: #F8FAFC;
padding-bottom: env(safe-area-inset-bottom);
.card {
width: 750rpx;
padding: 20rpx 0;
background: #fff;
border-radius: 8rpx;
.card_top {
width: 686rpx;
padding-top: 20rpx;
margin: 0 auto 10rpx;
display: flex;
justify-content: space-between;
align-items: center;
.card_top_left {
display: flex;
flex-direction: column;
.name {
height: 56rpx;
font-size: 40rpx;
font-family: PingFang SC-Semibold, PingFang SC;
font-weight: 600;
color: #1E293B;
}
text {
height: 38rpx;
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #1E293B;
margin: 8rpx 0;
}
}
.card_top_right {
position: relative;
image {
width: 144rpx;
height: 144rpx;
border-radius: 50%;
}
}
}
.card_center {
width: 686rpx;
margin: 10rpx auto 0;
.card_center_top {
height: 44rpx;
font-size: 24rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 500;
color: #94A3B8;
margin: 20rpx 0;
display: flex;
align-items: center;
.txt {
margin-right: 30rpx;
text {
font-size: 28rpx;
color: #FEA54C;
margin: 0 10rpx;
}
}
}
.going {
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #1E293B;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
overflow: hidden;
}
}
.card_bottom {
width: 686rpx;
margin: 10rpx auto;
.info {
text-align: right;
height: 40rpx;
line-height: 40rpx;
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #475569;
margin-bottom: 20rpx;
.iconfont {
font-size: 26rpx;
margin-left: 12rpx;
}
}
}
}
.appoin {
width: 710rpx;
margin: 36rpx auto 20rpx;
display: flex;
flex-direction: column;
.title {
font-size: 32rpx;
font-family: PingFang SC-Bold, PingFang SC;
font-weight: bold;
color: #232323;
margin-bottom: 24rpx;
padding-left: 20rpx;
}
.list {
width: 710rpx;
margin: 8rpx auto;
padding: 24rpx 20rpx;
border-radius: 16rpx;
background: #FFFFFF;
.yard {
display: flex;
align-items: center;
justify-content: space-between;
margin: 8rpx 0;
.stores {
font-size: 28rpx;
font-family: PingFang SC-Bold, PingFang SC;
font-weight: 500;
color: #232323;
margin-bottom: 22rpx;
display: flex;
.price {
font-size: 26rpx;
font-weight: bold;
color: #FEA54C;
display: flex;
align-items: center;
margin-left: 18rpx;
}
.times {
color: #666666;
}
}
.num {
font-size: 27rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 500;
color: #666666;
white-space: 1rpx;
margin-top: 8rpx;
text {
color: #4175EE;
}
}
}
.btn {
width: 104rpx;
height: 42rpx;
line-height: 40rpx;
text-align: center;
background: #4175EE;
border-radius: 26rpx 26rpx 26rpx 26rpx;
font-size: 24rpx;
font-family: PingFang SC-Bold, PingFang SC;
font-weight: bold;
color: #FFFFFF;
}
.active {
background: #E0E1E3;
color: #232323;
}
}
}
.evaluation {
margin: 16rpx 0;
.lists {
width: 750rpx;
height: 128rpx;
background: #FFFFFF;
padding: 32rpx;
display: flex;
justify-content: space-between;
align-items: center;
.lists_left {
height: 50rpx;
font-size: 32rpx;
font-family: PingFang SC-Semibold, PingFang SC;
font-weight: 600;
color: #0F172A;
}
.lists_right {
text {
height: 40rpx;
font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #475569;
margin-left: 10rpx;
}
}
}
.empty {
width: 440rpx;
height: 393rpx;
margin: 10rpx auto;
image {
width: 100%;
height: 100%;
z-index: 10;
}
}
.items {
display: flex;
background-color: #fff;
justify-content: space-around;
padding: 10rpx 10rpx;
image {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
}
.items_right {
width: 602rpx;
padding-bottom: 20rpx;
.item_name {
display: flex;
justify-content: space-between;
align-items: center;
.title {
height: 34rpx;
font-size: 24rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #475569;
text {
margin-right: 10rpx;
}
.iconfont {
color: #FB8C00;
font-size: 26rpx;
margin-left: 10rpx;
}
}
.time {
height: 34rpx;
font-size: 24rpx;
font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400;
color: #94A3B8;
}
}
.info {
font-size: 28rpx;
line-height: 44rpx;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
overflow: hidden;
margin: 16rpx 0 0 0;
}
}
}
}
.footer {
width: 750rpx;
height: 110rpx;
display: flex;
align-items: center;
justify-content: center;
background: #FFFFFF;
position: fixed;
left: 0;
bottom: env(safe-area-inset-bottom);
z-index: 10;
button {
width: 686rpx;
height: 86rpx;
background: #4175EE;
border-radius: 64rpx;
font-size: 32rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #FFFFFF;
}
}
}
</style>