2026-01-14 17:41:42 +08:00

572 lines
14 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="consult-page">
<!-- 顶部导航与标签 -->
<navBar title="公益咨询" />
<view class="tabs">
<view :class="['tab', activeTab==='new' ? 'active' : '']" @tap="switchTab('new')">新的咨询</view>
<view class="bar"></view>
<view :class="['tab', activeTab==='mine' ? 'active' : '']" @tap="switchTab('mine')">我已回答</view>
</view>
<view class="tabs-spacer"></view>
<!-- 列表 -->
<scroll-view
scroll-y
class="list-scroll"
refresher-enabled
:refresher-triggered="isRefreshing"
@refresherrefresh="onRefresh"
@scrolltolower="onReachBottom"
lower-threshold="80"
>
<view v-for="(item, idx) in displayList" :key="idx" class="consult-card" @click="goDetail(item.id,item.patientUuid)">
<view class="card-head">
<view class="namebox">
<text class="user-name">{{ item.maskName }}</text>
<text class="user-avatar" v-if="bottomActive!=='quick'">({{item.sex==1?'':'' }}<text decode>&nbsp;</text>{{ calcAge(item.birthDate) }})</text>
</view>
<text class="date">{{ item.date }}</text>
</view>
<view class="card-body">
<text class="content twoline">{{ item.disease_describe }}</text>
</view>
<view class="card-foot" v-if="bottomActive==='multi'">
<text class="reply-count" v-if="item.answer_num>0">{{ item.answer_num }}位医生已回答</text>
<text class="reply-count-none" v-else>暂未有医生回答</text>
<view v-if="item.tag" class="tag">{{ item.tag }}</view>
</view>
<view class="card-foot" v-else>
<view class="left">
<view class="detail">问题详情</view>
<view v-if="item.tag" class="tag">{{ item.tag }}</view>
</view>
</view>
</view>
<empty v-if="displayList.length===0" />
<view v-if="isLoading" style="text-align:center;color:#9aa0a6;padding:10px 0;">加载中...</view>
<view v-else-if="!hasMore && displayList.length>0" style="text-align:center;color:#9aa0a6;padding:10px 0;">没有更多了</view>
</scroll-view>
<!-- 底部操作条:双按钮 Tab -->
<view class="bottom-bar" :style="{height: bottomBarHeight+'px'}">
<view :class="['bottom-tab', bottomActive==='quick' ? 'active' : '']" @click="switchBottomTab('quick')">快速问医生</view>
<view :class="['bottom-tab', bottomActive==='multi' ? 'active' : '']" @click="switchBottomTab('multi')">多对一解惑</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { onShow,onBackPress,onLoad } from '@dcloudio/uni-app'
import navBar from '@/components/navBar/navBar.vue'
import empty from '@/components/empty/empty.vue'
import api from '@/api/api.js'
import navTo from '@/utils/navTo.js'
const activeTab = ref('new');
const bottomBarHeight = 56
const page=ref(1)
const pageSize=ref(10)
const hasMore = ref(true)
const isLoading = ref(false)
const isRefreshing = ref(false)
onBackPress(()=>{
plus.runtime.quit();
return true;
})
const goDetail=async(uuid,patientUuid)=>{
if(bottomActive.value==='quick'){
if(activeTab.value==='new'){
navTo({
url:'/pages_app/freeDetail/freeDetail?uuid='+uuid
})
}else{
let userId=uni.getStorageSync('userInfo').uuid.toLowerCase();
uni.sendNativeEvent('goConsultPage', {
msg: 'chat'
},ret => {
console.log(ret);
})
//let conversationId=userId+'|1|'+patientUuid.toLowerCase();
//await uni.$UIKitStore.uiStore.selectConversation(conversationId)
// navTo({
// url:'/pages_chat/chat/index?from=consult&&patientUuid='+patientUuid+'&&uuid='+uuid
// })
}
}else{
let status=0;
if(activeTab.value==='new'){
status=0;
}else{
status=1;
}
navTo({
url:'/pages_app/consultDetail/consultDetail?uuid='+uuid+'&status='+status
})
}
};
function maskName(name){
if(!name) return '**'
const first = name.slice(0,1)
return `${first}**`
}
// 根据出生日期计算年龄birth 可以是 'YYYY-MM-DD' 或可被 Date 解析的字符串 / 时间戳)
function calcAge(birth) {
if (!birth) return ''
const birthDate = new Date(birth)
if (isNaN(birthDate.getTime())) {
return ''
}
const today = new Date()
let age = today.getFullYear() - birthDate.getFullYear()
const m = today.getMonth() - birthDate.getMonth()
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age--
}
// 年龄小于 0 视为无效
return age >= 0 ? age : ''
}
const newConsultList=async(isRefresh=false)=>{
if(isLoading.value) return
isLoading.value = true
if(isRefresh){
page.value = 1
hasMore.value = true
listNew.value = []
}
const res=await api.newConsultList({
page:page.value,
pageSize:pageSize.value
})
console.log(res)
if(res && res.code===200 && res.data && res.data.consult_list){
const list = Array.isArray(res.data.consult_list.list) ? res.data.consult_list.list : []
const mapped = list.map(item=>({
maskName: item.realName,
date: (item.createDate || '').slice(0,16),
content: item.content || '',
replyCount: 0,
sex: item.sex || 0,
birthDate: item.birthDate || item.birthday,
tag: item.diseaseName || '',
id:item.uuid || '',
patientUuid:item.patientUuid || ''
}))
if(isRefresh){
listNew.value = mapped
}else{
listNew.value = page.value===1 ? mapped : [...listNew.value, ...mapped]
}
const totalPage = Number(res.data.consult_list.totalPage || 1)
hasMore.value = page.value < totalPage
}
isLoading.value = false
if(isRefresh){
isRefreshing.value = false
}
}
const consultListHis=async(isRefresh=false)=>{
if(isLoading.value) return
isLoading.value = true
if(isRefresh){
page.value = 1
hasMore.value = true
listMine.value = []
}
const res=await api.consultListHis({
page:page.value,
pageSize:pageSize.value
})
console.log(res)
if(res.code==200){
const list = Array.isArray(res.data.list) ? res.data.list : []
const mapped = list.map(item=>({
maskName: item.realName,
date: (item.createDate || '').slice(0,16),
content: item.content || '',
replyCount: 0,
sex: item.sex || 0,
birthDate: item.birthDate || item.birthday,
tag: item.diseaseName || '',
id:item.uuid || '',
patientUuid:item.patientUuid || ''
}))
if(isRefresh){
listMine.value = mapped
}else{
listMine.value = page.value===1 ? mapped : [...listMine.value, ...mapped]
}
const totalPage = Number(res.data.totalPage || 1)
hasMore.value = page.value < totalPage
}
isLoading.value = false
if(isRefresh){
isRefreshing.value = false
}
}
const listNewInterrogation=async(isRefresh=false)=>{
if(isLoading.value) return
isLoading.value = true
if(isRefresh){
page.value = 1
hasMore.value = true
listNew.value = []
}
const res=await api.listNewInterrogation({
page:page.value,
pageSize:pageSize.value
})
if(res.code ==200){
const list =res.data.list;
console.log(1111)
console.log(list)
const mapped = list.map(item=>({
maskName: maskName(item.name || ''),
date: (item.create_date || '').slice(0,10),
content: item.your_question || '',
disease_describe:item.disease_describe || '',
sex: item.sex || 0,
birthDate: item.birthday || '',
answer_num: item.answer_num || 0,
tag: item.disease_name || '',
id:item.step1_uuid || ''
}))
if(isRefresh){
listNew.value = mapped
}else{
listNew.value = page.value===1 ? mapped : [...listNew.value, ...mapped]
}
const totalPage = Number(res.data.pages || 1)
hasMore.value = page.value < totalPage
}
isLoading.value = false
if(isRefresh){
isRefreshing.value = false
}
}
const listMyAnsweredInterrogation=async(isRefresh=false)=>{
if(isLoading.value) return
isLoading.value = true
if(isRefresh){
page.value = 1
hasMore.value = true
listMine.value = []
}
const res=await api.listMyAnsweredInterrogation({
page:page.value,
pageSize:pageSize.value
})
console.log(res)
if(res.code==200){
const list = Array.isArray(res.data.list) ? res.data.list : []
const mapped = list.map(item=>({
maskName: maskName(item.name || ''),
date: (item.create_date || '').slice(0,10),
content: item.your_question || '',
disease_describe:item.disease_describe || '',
sex: item.sex || 0,
birthDate: item.birthday || '',
answer_num: item.answer_num || 0,
tag: item.disease_name || '',
id:item.step1_uuid || ''
}))
if(isRefresh){
listMine.value = mapped
}else{
listMine.value = page.value===1 ? mapped : [...listMine.value, ...mapped]
}
const totalPage = Number(res.data.pages || 1)
hasMore.value = page.value < totalPage
}
isLoading.value = false
if(isRefresh){
isRefreshing.value = false
}
};
onLoad(()=>{
page.value = 1
hasMore.value = true;
listNew.value = [];
listMine.value=[];
if(bottomActive.value==='quick'){
if(activeTab.value==='new'){
newConsultList(false)
}else{
consultListHis(false)
}
}else{
if(activeTab.value==='new'){
listNewInterrogation(false)
}else{
listMyAnsweredInterrogation(false)
}
}
})
const listNew = ref([])
const listMine = ref([])
const displayList = computed(() => (activeTab.value === 'new' ? listNew.value : listMine.value))
function switchTab(key) {
activeTab.value = key;
isLoading.value = false;
listNew.value = [];
listMine.value=[];
page.value = 1
hasMore.value = true;
if(bottomActive.value==='quick'){
if(activeTab.value==='new'){
newConsultList(false)
}else{
consultListHis(false)
}
}else{
if(activeTab.value==='new'){
listNewInterrogation(false)
}else{
listMyAnsweredInterrogation(false)
}
}
}
function goBack() {
// #ifdef H5
history.back()
// #endif
// #ifndef H5
uni.navigateBack({ delta: 1 })
// #endif
}
// 底部tab交互
const bottomActive = ref('multi')
const switchBottomTab=(key)=>{
isLoading.value = false;
bottomActive.value = key;
page.value = 1
hasMore.value = true;
listNew.value = [];
listMine.value=[];
if(key=='quick'){
try {
plus.runtime.quit();
} catch (error) {
}
if(activeTab.value==='new'){
newConsultList(false)
}else{
consultListHis(false)
}
}else{
if(activeTab.value==='new'){
console.log('listNewInterrogation')
listNewInterrogation(false);
}else{
listMyAnsweredInterrogation(false)
}
}
}
// 下拉刷新
function onRefresh(){
if(isRefreshing.value) return
isRefreshing.value = true
page.value = 1
hasMore.value = true
listNew.value = [];
listMine.value=[];
if(bottomActive.value==='quick'){
if(activeTab.value==='new'){
newConsultList(true)
}else{
consultListHis(true)
}
}else{
if(activeTab.value==='new'){
listNewInterrogation(true)
}else{
listMyAnsweredInterrogation(true)
}
}
}
// 触底加载
function onReachBottom(){
if(!hasMore.value || isLoading.value) return
page.value += 1
if(bottomActive.value==='quick'){
if(activeTab.value==='new'){
newConsultList(false)
}else{
consultListHis(false)
}
}else{
if(activeTab.value==='new'){
listNewInterrogation(false)
}else{
listMyAnsweredInterrogation(false)
}
}
}
</script>
<style lang="scss" scoped>
.consult-page {
background-color: #f7f7f7;
height: 100vh;
display: flex;
flex-direction: column;
}
.tabs {
display: flex;
justify-content: space-around;
align-items: center;
height: 48px;
padding: 0 16px;
position: fixed;
top: calc(var(--status-bar-height) + 44px);
left: 0;
right: 0;
z-index: 10;
background-color: #ffffff;
border-bottom: 1px solid #e5e5e5;
.bar{
width:1px;
height: 100%;
background-color: #e5e5e5;
}
.tab {
flex: 1;
text-align: center;
font-size: 36rpx;
color: #7a7a7a;
padding: 10px 0;
&.active { color: #8B2316; position: relative; }
}
}
.tabs-spacer { height: 44px; }
.namebox{
display: flex;
align-items: center;
justify-content: center;
.user-avatar{
margin-left: 10rpx;
font-size:32rpx;
color: #666;
}
}
.list-scroll {
flex: 1;
position: fixed;
top: calc(var(--status-bar-height) + 44px + 48px);
bottom:56px;
margin: 20rpx rpx 0;
box-sizing: border-box;
width:100%;
}
.consult-card {
background-color: #ffffff;
border-radius: 8px;
padding: 12px;
margin-bottom: 12px;
.card-head {
display: flex;
justify-content: space-between;
align-items: center;
.user-name { font-size: 36rpx; color: #a31712; }
.date { font-size: 36rpx; color: #9aa0a6; }
}
.card-body {
background: #efefef;
padding: 20rpx;
margin: 10px 0;
.content {
word-break: break-all;
font-size: 15px; color: #2b2f33; line-height: 1.6;
} }
.card-foot {
.left{
display: flex;
.detail{
font-size: 28rpx;
background: #a31712;
color:#fff;
border-radius: 14rpx;
margin-right: 10rpx;
padding: 8rpx 16rpx;
border-radius: 28rpx;
font-size: 28rpx;
display: flex;
align-items: center;
justify-content: center;
border:2rpx solid #a31712;
}
}
display: flex; align-items: center; justify-content: space-between; margin-top: 8px;
.reply-count { font-size:28rpx; color: #8B2316; }
.reply-count-none{
font-size:28rpx;
color: #999;
position: relative;
padding-left: 25rpx;
}
.reply-count-none::after{
content: '';
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 0;
width: 20rpx;
height: 20rpx;
background: red;
border-radius: 50%;
}
.tag {
display: flex;
align-items: center;
justify-content: center;
padding: 0rpx 16rpx; background: #fff; color: #a31712; border-radius: 28rpx; font-size: 24rpx; border:2rpx solid #a31712;}
}
}
.bottom-bar {
border-top: 1px solid #e5e5e5;
position: fixed;
left: 0; right: 0; bottom: 0;
background-color: #ffffff;
box-shadow: 0 -2px 8px rgba(0,0,0,0.06);
display: flex;
align-items: center;
justify-content: center;
.bottom-tab {
flex: 1;
height: 56px;
line-height: 56px;
text-align: center;
font-size: 36rpx;
color: #999;
background-color: #fff;
}
.bottom-tab.active {
background-color: #a31712;
color: #ffffff;
}
}
</style>