1502 lines
47 KiB
Vue
1502 lines
47 KiB
Vue
<template>
|
||
<view>
|
||
<view class="navbar" :style="{ height: statusBarHeight+navbarHeight + 'px' }">
|
||
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
|
||
<view class="text-align-cen" :style="{ height:navbarHeight + 'px' ,lineHeight: navbarHeight + 'px'}">
|
||
工作台
|
||
</view>
|
||
</view>
|
||
<view class="header-wrap" :style="{ paddingTop: statusBarHeight + navbarHeight + 'px' }">
|
||
<view class="box">
|
||
<view class="store_" @click="openShow=true">
|
||
{{doctorInfo.store.store.name || '默认门店'}}
|
||
<u-icon name="map-fill" color="#fff" size="28" margin-left="12"></u-icon>
|
||
</view>
|
||
<view class="box_info">
|
||
<view class="box_info_left">
|
||
|
||
<u-image width="96rpx" height="96rpx" shape="circle" :src="doctorInfo.DoctorInfo.avatar">
|
||
<u-loading slot="loading"></u-loading>
|
||
</u-image>
|
||
<view class="flex-col flex-jus-sp" style="height: 106rpx;margin-left: 32rpx;">
|
||
<view class="flex-row flex-ali-center">
|
||
<text class="box_info_left_name">{{doctorInfo.DoctorInfo.name}}</text>
|
||
<text class="m-r-16">{{doctorInfo.DoctorInfo.title['name']}}</text>
|
||
<u-tag text="审核中" type="warning" size="mini" shape="circle" border-color="#FB8C00"
|
||
bgColor="#FB8C00" color="#fff" v-if="doctorInfo.DoctorInfo.user.status<=1" />
|
||
<u-tag text="已认证" type="warning" size="mini" shape="circle" border-color="#FB8C00"
|
||
bgColor="#FB8C00" color="#fff" v-if="doctorInfo.DoctorInfo.user.status==2" />
|
||
<u-tag v-if="doctorInfo.DoctorInfo.user.status==3" text="审核未通过" type="warning" size="mini"
|
||
border-color="#A7ABB0" bgColor="#A7ABB0" color="#fff" />
|
||
</view>
|
||
<text style="width: 400rpx;">
|
||
{{`${doctorInfo.store.store.name}(${doctorInfo.DoctorInfo.depart['name']})`}}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
<view class="box_info_right flex-col flex-jus-sp flex-ali-center"
|
||
@click="$go('../../subPackages/sub_workbench/workbench_code')">
|
||
<image src="../../static/image/mp.png"></image>
|
||
<d-text text="我的名片" className="w-c fs-2"></d-text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="header-spacer" :style="{ height: headerSpacerHeight + 'px' }"></view>
|
||
|
||
<view class="content">
|
||
<!-- 看板统计 -->
|
||
<view class="dashboard-panel">
|
||
<view class="dashboard-tabs">
|
||
<view
|
||
v-for="(tab, tabIndex) in statsRangeTabs"
|
||
:key="tab.value"
|
||
class="dashboard-tab"
|
||
:class="{ active: statsRange === tab.value }"
|
||
@click="selectStatsTab(tabIndex)"
|
||
>{{ tab.label }}</view>
|
||
</view>
|
||
<view class="dashboard-body">
|
||
<view v-if="statsLoading && !hasStatsCache(statsRange)" class="dashboard-loading-overlay">
|
||
<u-loading mode="circle" size="36"></u-loading>
|
||
</view>
|
||
<swiper
|
||
class="dashboard-swiper"
|
||
:current="statsTabIndex"
|
||
:duration="200"
|
||
@change="onStatsSwiperChange"
|
||
>
|
||
<swiper-item v-for="tab in statsRangeTabs" :key="tab.value">
|
||
<view class="dashboard-grid">
|
||
<view class="dashboard-stat">
|
||
<text class="dashboard-stat-value">{{ getStatsForRange(tab.value).prescription_count || 0 }}</text>
|
||
<text class="dashboard-stat-label">开方数量</text>
|
||
</view>
|
||
<view class="dashboard-stat">
|
||
<text class="dashboard-stat-value">{{ getStatsForRange(tab.value).wait_accept || 0 }}</text>
|
||
<text class="dashboard-stat-label">待接诊</text>
|
||
</view>
|
||
<view class="dashboard-stat">
|
||
<text class="dashboard-stat-value">{{ getStatsForRange(tab.value).accepting || 0 }}</text>
|
||
<text class="dashboard-stat-label">接诊中</text>
|
||
</view>
|
||
<view class="dashboard-stat">
|
||
<text class="dashboard-stat-value">{{ getStatsForRange(tab.value).completed || 0 }}</text>
|
||
<text class="dashboard-stat-label">已完成</text>
|
||
</view>
|
||
<view class="dashboard-stat dashboard-stat-wide">
|
||
<text class="dashboard-stat-value amount">{{ formatStatsAmount(getStatsForRange(tab.value).prescription_amount) }}</text>
|
||
<text class="dashboard-stat-label">处方金额(元)</text>
|
||
</view>
|
||
</view>
|
||
</swiper-item>
|
||
</swiper>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="function p-32" v-if="onlineConsultationConfigReady && canUseOnlineConsultation">
|
||
<view class="function_grid">
|
||
<view
|
||
class="function_item flex-col flex-ali-center flex-jus-sp"
|
||
v-for="(item, i) in receptionGridEntries"
|
||
:key="i"
|
||
@click="goReceptionEntry(item.url)"
|
||
>
|
||
<image :src="item.icon"></image>
|
||
<view>{{ item.name }}</view>
|
||
<u-badge
|
||
:count="i === 0 ? doctorInfo.wait_accept : 0"
|
||
v-if="i === 0"
|
||
:offset="[-6, 98]"
|
||
bgColor="#F44336"
|
||
></u-badge>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="function p-32" v-else-if="onlineConsultationConfigReady">
|
||
<view
|
||
class="offline-entry-row flex-row flex-ali-center"
|
||
@click="goReceptionEntry(offlineReceptionEntry.url)"
|
||
>
|
||
<image class="offline-entry-icon" :src="offlineReceptionEntry.icon"></image>
|
||
<view class="offline-entry-body flex-col flex-1">
|
||
<text class="offline-entry-title">{{ offlineReceptionEntry.name }}</text>
|
||
<text class="offline-entry-desc">到店开方、处理线下挂号</text>
|
||
</view>
|
||
<u-badge
|
||
v-if="doctorInfo.wait_accept > 0"
|
||
:count="doctorInfo.wait_accept"
|
||
:offset="[-8, 8]"
|
||
bgColor="#F44336"
|
||
></u-badge>
|
||
<u-icon name="arrow-right" color="#6acdbb" size="28"></u-icon>
|
||
</view>
|
||
</view>
|
||
<block>
|
||
<!-- 正在接诊模块 -->
|
||
<view class="news b-r-8" v-if="acceptingPatientList.length > 0">
|
||
<view class="news_title flex-row">
|
||
<view class="m-t-32">正在接诊</view>
|
||
</view>
|
||
<scroll-view scroll-y="true" style="padding: 10rpx 0rpx; max-height: 520rpx;">
|
||
<view
|
||
class="news_item flat-card flex-row flex-ali-start"
|
||
v-for="(item, aix) in acceptingPatientList"
|
||
:key="acceptingRowKey(item, aix)"
|
||
:data-idx="aix"
|
||
@tap="onAcceptingOfflineCardTap"
|
||
>
|
||
<view class="wb-avatar-wrap">
|
||
<u-image width="80rpx" height="80rpx" shape="circle"
|
||
:src="item.user_patient && item.user_patient.avatar || require(`../../static/image/${item.user_patient && item.user_patient.sex%2==0?'nv':'nan'}.png`)">
|
||
<u-loading slot="loading"></u-loading>
|
||
</u-image>
|
||
<u-badge
|
||
:key="acceptingBadgeKey(item, aix)"
|
||
v-if="item.consultation_channel === 'online' && Number(item.unread_count) > 0"
|
||
:count="Number(item.unread_count)"
|
||
:offset="[-4, -4]"
|
||
bgColor="#F44336"
|
||
:overflow-count="99"
|
||
></u-badge>
|
||
</view>
|
||
|
||
<view class="wb-card-body flex-col flex-1 text-hide">
|
||
<!-- 第一行:患者名、信息、标签、时间 -->
|
||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||
<view class="flex-row flex-ali-center flex-1 text-hide">
|
||
<text class="wb-name">{{ item.user_patient && item.user_patient.name || '患者' }}</text>
|
||
<text class="wb-meta">{{ acceptingSexAgeText(item) }}</text>
|
||
<u-tag
|
||
class="wb-tag"
|
||
:text="item.consultation_channel === 'online' ? '线上' : '线下'"
|
||
:type="item.consultation_channel === 'online' ? 'primary' : 'info'"
|
||
size="mini"
|
||
></u-tag>
|
||
<u-tag
|
||
v-if="item.special_prescription_patient_record"
|
||
class="wb-tag"
|
||
:text="item.special_prescription_patient_record.status === 0 ? '特色方·待应用' : '特色方'"
|
||
type="warning"
|
||
size="mini"
|
||
></u-tag>
|
||
</view>
|
||
<text class="wb-time">{{
|
||
item.consultation_channel === 'online' ? formatAcceptingMsgTime(item) : acceptingOfflineRegisterTimeText(item)
|
||
}}</text>
|
||
</view>
|
||
|
||
<!-- 第二行:纯文本预览 或 订单号 -->
|
||
<view v-if="item.consultation_channel === 'online'" class="wb-preview text-hide m-t-8">
|
||
<text>{{ acceptingLastMessageLine(item) }}</text>
|
||
</view>
|
||
<text
|
||
v-if="item.consultation_channel !== 'online' && acceptingOfflineOrderText(item)"
|
||
class="wb-sub text-hide m-t-8"
|
||
>{{ acceptingOfflineOrderText(item) }}</text>
|
||
<text
|
||
v-if="item.consultation_channel !== 'online'"
|
||
class="wb-sub text-hide m-t-8"
|
||
>推广员:{{ (item.salesperson && item.salesperson.nick_name) || '无' }}</text>
|
||
|
||
<!-- 第三行:状态与操作按钮 -->
|
||
<view class="flex-row flex-jus-sp flex-ali-center m-t-12">
|
||
<view class="wb-status">
|
||
<d-text
|
||
v-if="item.consultation_channel === '1online'"
|
||
:text="acceptingStatusLabel(item)"
|
||
:color="acceptingStatusColor(item)"
|
||
size="24"
|
||
></d-text>
|
||
</view>
|
||
<view class="wb-actions flex-row flex-ali-center">
|
||
<view
|
||
v-if="item.consultation_channel === 'online'"
|
||
class="wb-action-btn btn-primary"
|
||
:data-idx="aix"
|
||
@tap.stop="openAcceptingChatByIndex"
|
||
>进入诊室</view>
|
||
<view
|
||
v-else
|
||
class="wb-action-btn btn-ghost"
|
||
:data-idx="aix"
|
||
@tap.stop="openAcceptingPrescriptionByIndex"
|
||
>去开方</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
|
||
<view class="news b-r-8">
|
||
<view class="news_title flex-row">
|
||
<view class="m-t-32">消息通知</view>
|
||
</view>
|
||
<scroll-view scroll-y="true" style="padding: 20rpx 0rpx;" @scrolltolower="scrolltolower"
|
||
@refresherrefresh="page=1;status = 'loading';loading = true;infoList=[];$store.dispatch('getDocSession')"
|
||
:refresher-triggered="loading" :refresher-enabled="false" v-if="!loading">
|
||
|
||
<!-- 系统消息 -->
|
||
<view class="news_item flex-row flex-jus-sp flex-ali-center"
|
||
@click="$go('../../subPackages/sub_patient/patient_label?type=1')" v-if="systemList.num>0">
|
||
<view style="width: 80rpx;position: relative;">
|
||
<u-image width="80rpx" height="80rpx" shape="circle" src="/static/image/home1.png">
|
||
<u-loading slot="loading"></u-loading>
|
||
</u-image>
|
||
<u-badge :count="systemList.num" v-if="systemList.num>0" :offset="[0,0]"
|
||
bgColor="#F44336" :overflow-count="9999"></u-badge>
|
||
</view>
|
||
<view class="news_item_info flex-col flex-jus-sp">
|
||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||
<view class="flex-row flex-ali-center">
|
||
<d-text text="系统消息" className="content-c fs-32 m-r-16"></d-text>
|
||
</view>
|
||
<d-text :text="systemList.time" size="24"></d-text>
|
||
</view>
|
||
<view class="flex-row flex-jus-sp">
|
||
<view class="news_item_info_msg text-hide">
|
||
<text style="font-size: 24rpx;margin-right: 20rpx;"
|
||
v-if="systemList.num>0">你有{{systemList.num}}条未读消息</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 患者消息 -->
|
||
<view class="news_item flex-row flex-jus-sp flex-ali-center"
|
||
@click="$go('../../subPackages/sub_patient/patient_label?type=2')" v-if="infoList.num>0">
|
||
<view style="width: 80rpx;position: relative;">
|
||
<u-image width="80rpx" height="80rpx" shape="circle" :src="'/static/image/home2.png'">
|
||
<u-loading slot="loading"></u-loading>
|
||
</u-image>
|
||
<u-badge :count="infoList.num" v-if="infoList.num>0" :offset="[0,0]" bgColor="#F44336"
|
||
:overflow-count="9999"></u-badge>
|
||
</view>
|
||
<view class="news_item_info flex-col flex-jus-sp">
|
||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||
<view class="flex-row flex-ali-center">
|
||
<d-text text="患者消息" className="content-c fs-32 m-r-16"></d-text>
|
||
</view>
|
||
<d-text :text="infoList.time" size="24"></d-text>
|
||
</view>
|
||
<view class="flex-row flex-jus-sp">
|
||
<view class="news_item_info_msg text-hide">
|
||
<text style="font-size: 24rpx;margin-right: 20rpx;"
|
||
v-if="infoList.num>0">你有{{infoList.num}}名患者待接诊</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="news_item flex-row flex-jus-sp flex-ali-center"
|
||
v-if="!loading&&systemList.length==0"
|
||
@click="$go('../../subPackages/sub_patient/patient_label?type=1')">
|
||
<view style="width: 80rpx;position: relative;">
|
||
<u-image width="80rpx" height="80rpx" shape="circle" src="/static/image/home1.png">
|
||
<u-loading slot="loading"></u-loading>
|
||
</u-image>
|
||
</view>
|
||
<view class="news_item_info flex-col flex-jus-sp">
|
||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||
<view class="flex-row flex-ali-center">
|
||
<d-text text="系统消息" size="34" color="#000"></d-text>
|
||
</view>
|
||
<d-text :text="systemList.time" size="24"></d-text>
|
||
</view>
|
||
<view class="flex-row flex-jus-sp">
|
||
<view class="news_item_info_msg text-hide">
|
||
<text style="font-size: 28rpx;margin-right: 20rpx;">点击查看历史消息</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 历史患者 -->
|
||
<view class="news_item flex-row flex-jus-sp flex-ali-center" v-if="!loading&&infoList.length==0"
|
||
@click="$go('../../subPackages/sub_patient/patient_label?type=2')">
|
||
<view style="width: 80rpx;position: relative;">
|
||
<u-image width="80rpx" height="80rpx" shape="circle" :src="'/static/image/home2.png'">
|
||
<u-loading slot="loading"></u-loading>
|
||
</u-image>
|
||
</view>
|
||
<view class="news_item_info flex-col flex-jus-sp">
|
||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||
<view class="flex-row flex-ali-center">
|
||
<d-text text="患者消息" size="34" color="#000"></d-text>
|
||
</view>
|
||
<d-text :text="infoList.time" size="24"></d-text>
|
||
</view>
|
||
<view class="flex-row flex-jus-sp">
|
||
<view class="news_item_info_msg text-hide">
|
||
<text style="font-size: 28rpx;margin-right: 20rpx;">点击查看历史消息</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 处方 -->
|
||
<view v-if="noticeList.length" class="news_item flex-row flex-jus-sp flex-ali-center"
|
||
@click="$go('/subPackages/sub_workbench/prescriptionList')">
|
||
<view style="width: 80rpx;position: relative;">
|
||
<u-image width="80rpx" height="80rpx" shape="circle" src="/static/image/home1.png">
|
||
<u-loading slot="loading"></u-loading>
|
||
</u-image>
|
||
<u-badge :count="noticeList.length" :offset="[0,0]"
|
||
bgColor="#F44336" :overflow-count="9999"></u-badge>
|
||
</view>
|
||
<view class="news_item_info flex-col flex-jus-sp">
|
||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||
<view class="flex-row flex-ali-center">
|
||
<d-text text="待流转处方消息" className="content-c fs-32 m-r-16"></d-text>
|
||
</view>
|
||
</view>
|
||
<view class="flex-row flex-jus-sp">
|
||
<view class="news_item_info_msg text-hide">
|
||
<text style="font-size: 24rpx;margin-right: 20rpx;">你有{{noticeList.length}}条未读消息</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
<view @click="call" class="phone">咨询客服</view>
|
||
<view class="m-b-32 p-t-32"></view>
|
||
</block>
|
||
</view>
|
||
|
||
<!-- 切换门店精简 -->
|
||
<u-popup v-model="openShow" mode="bottom" border-radius="24" length="65%" :safe-area-inset-bottom="true">
|
||
<view class="content_popup">
|
||
<view class="top">
|
||
<view class="title">选择诊所</view>
|
||
<view class="search p-row-32">
|
||
<u-search placeholder="请输入诊所名称" @input="handleSearch" v-model="keyword"
|
||
:show-action="false"></u-search>
|
||
</view>
|
||
</view>
|
||
<scroll-view scroll-y="true" style="height: 600rpx;">
|
||
<view>
|
||
<view class="store_list" v-for="(item,index) in storeList" :key="item.id"
|
||
@click="changeStore(item.id)">
|
||
<text :class="{'active-store-text': store_id==item.id}">{{item.name}}</text>
|
||
<u-icon size="35" color="#6ACDBB" name="checkmark-circle-fill"
|
||
v-if="store_id==item.id"></u-icon>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
<view class="confrim-btn">
|
||
<view class="u-btn qx" @click="openShow=false">取消</view>
|
||
<view class="u-btn qd" @click="sure">确定</view>
|
||
</view>
|
||
</view>
|
||
</u-popup>
|
||
|
||
<d-top-message ref="topMessage"></d-top-message>
|
||
<d-tabbar></d-tabbar>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
chooseList,
|
||
hospitalList,
|
||
info,
|
||
noticeApi,
|
||
currentList,
|
||
homeSession,
|
||
getNotice
|
||
} from '@/api/all.js'
|
||
import {
|
||
registerList
|
||
} from '../../api/consult';
|
||
import {
|
||
getAcceptingPatientList as fetchAcceptingPatientListApi,
|
||
getOnlineConsultationPatientListApi,
|
||
getWorkbenchStats,
|
||
} from '../../api/reception';
|
||
import { checkOnlineConsultationConfigApi } from '../../api/storeConsultation.js';
|
||
|
||
/** 房间 ID 归一化(避免引入 chatRoomManager 整模块) */
|
||
function normalizeRoomId(id) {
|
||
return String(id == null ? '' : id).trim();
|
||
}
|
||
|
||
/** 会话列表相对时间(与 utils/chat/sessionListFormat.js 一致) */
|
||
function formatSessionRelativeTime(item) {
|
||
if (!item) return '';
|
||
const t =
|
||
item.last_message_time ||
|
||
item.updated_at ||
|
||
item.created_at ||
|
||
item.register_time;
|
||
if (t == null || t === '') return '';
|
||
const ms = typeof t === 'number' ? (t > 1e12 ? t : t * 1000) : new Date(t).getTime();
|
||
if (Number.isNaN(ms)) return '';
|
||
const d = new Date(ms);
|
||
const diff = Math.floor((Date.now() - ms) / 60000);
|
||
if (diff < 1) return '刚刚';
|
||
if (diff < 60) return `${diff}分钟前`;
|
||
const h = Math.floor(diff / 60);
|
||
if (h < 24) return `${h}小时前`;
|
||
const pad = (n) => (n < 10 ? '0' + n : '' + n);
|
||
return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||
}
|
||
|
||
const WORKBENCH_STATS_RANGE_KEY = 'workbench_stats_range';
|
||
const OFFLINE_RECEPTION_ENTRY = {
|
||
name: '线下接诊',
|
||
icon: '../../static/image/zxzx.png',
|
||
url: '../../subPackages/sub_workbench/workbench_consult?type=1',
|
||
};
|
||
const ONLINE_RECEPTION_ENTRY = {
|
||
name: '在线接诊',
|
||
icon: '../../static/image/xsfz.png',
|
||
url: '../../subPackages/sub_online_reception/pages/list',
|
||
};
|
||
const RECEPTION_GRID_ENTRIES = [OFFLINE_RECEPTION_ENTRY, ONLINE_RECEPTION_ENTRY];
|
||
const EMPTY_WORKBENCH_STATS = {
|
||
prescription_count: 0,
|
||
wait_accept: 0,
|
||
accepting: 0,
|
||
completed: 0,
|
||
prescription_amount: '0.000',
|
||
};
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
noticeList: [],
|
||
loading: false,
|
||
status: 'loading',
|
||
loadText: {
|
||
loadmore: '轻轻上拉',
|
||
loading: '努力加载中',
|
||
nomore: '实在没有了'
|
||
},
|
||
receptionGridEntries: RECEPTION_GRID_ENTRIES,
|
||
offlineReceptionEntry: OFFLINE_RECEPTION_ENTRY,
|
||
canUseOnlineConsultation: false,
|
||
onlineConsultationConfigReady: false,
|
||
states: {
|
||
1: {
|
||
name: '待接诊',
|
||
color: '#F44336'
|
||
},
|
||
2: {
|
||
name: '接诊中',
|
||
color: '#00C853'
|
||
},
|
||
3: {
|
||
name: '已结束',
|
||
color: '#C4C7CC'
|
||
},
|
||
3: {
|
||
name: '已取消',
|
||
color: '#C4C7CC'
|
||
}
|
||
},
|
||
state: true,
|
||
doctorInfo: [],
|
||
current: 0,
|
||
navbarHeight: this.$navbarHeight,
|
||
statusBarHeight: this.$statusBarHeight,
|
||
list: [],
|
||
page: 1,
|
||
totalPage: 1,
|
||
openShow: false,
|
||
keyword: "",
|
||
store: "",
|
||
storeList: [],
|
||
store_id: uni.getStorageSync('store_id') || '11001',
|
||
infoList: [],
|
||
systemList: [],
|
||
see_rate: "",
|
||
acceptingPatientList: [], // 正在接诊的患者列表
|
||
refreshTimer: null,
|
||
refreshIntervalMs: 20000,
|
||
isReceptionRefreshing: false,
|
||
statsRange: 'today',
|
||
statsTabIndex: 0,
|
||
statsSwiperChanging: false,
|
||
statsRangeTabs: [
|
||
{ label: '今日', value: 'today' },
|
||
{ label: '本周', value: 'week' },
|
||
{ label: '本月', value: 'month' },
|
||
{ label: '近一月', value: 'last_30d' },
|
||
],
|
||
statsCache: {
|
||
today: null,
|
||
week: null,
|
||
month: null,
|
||
last_30d: null,
|
||
},
|
||
workbenchStats: { ...EMPTY_WORKBENCH_STATS },
|
||
statsLoading: false,
|
||
statsInitialized: false,
|
||
};
|
||
},
|
||
watch: {
|
||
docSession: {
|
||
deep: true,
|
||
immediate: false,
|
||
handler(e) {
|
||
this.list = e.list;
|
||
this.totalPage = e.pagination.totalPage;
|
||
if (this.page >= this.totalPage) {
|
||
this.status = 'nomore'
|
||
} else {
|
||
this.status = 'loadmore'
|
||
}
|
||
this.$nextTick(() => {
|
||
this.loading = false
|
||
})
|
||
}
|
||
}
|
||
},
|
||
computed: {
|
||
headerSpacerHeight() {
|
||
const contentPx = typeof uni.upx2px === 'function' ? uni.upx2px(312) : 156;
|
||
return this.statusBarHeight + this.navbarHeight + contentPx;
|
||
},
|
||
},
|
||
onLoad() {
|
||
this.initStatsRangeFromStorage();
|
||
},
|
||
onUnload() {
|
||
this.stopRefreshTimer();
|
||
if (this.__doctorImRoomUpdateHandler) {
|
||
uni.$off('doctor-im-room-update', this.__doctorImRoomUpdateHandler);
|
||
this.__doctorImRoomUpdateHandler = null;
|
||
}
|
||
},
|
||
onShow() {
|
||
if (!this.__doctorImRoomUpdateHandler) {
|
||
this.__doctorImRoomUpdateHandler = this.applyDoctorImRoomUpdateToAccepting.bind(this);
|
||
}
|
||
uni.$off('doctor-im-room-update', this.__doctorImRoomUpdateHandler);
|
||
uni.$on('doctor-im-room-update', this.__doctorImRoomUpdateHandler);
|
||
this.refreshWorkbenchData();
|
||
this.startRefreshTimer();
|
||
},
|
||
onPullDownRefresh() {
|
||
this.refreshWorkbenchData().finally(() => {
|
||
uni.stopPullDownRefresh();
|
||
});
|
||
},
|
||
onHide() {
|
||
this.stopRefreshTimer();
|
||
if (this.__doctorImRoomUpdateHandler) {
|
||
uni.$off('doctor-im-room-update', this.__doctorImRoomUpdateHandler);
|
||
}
|
||
},
|
||
methods: {
|
||
initStatsRangeFromStorage() {
|
||
const saved = uni.getStorageSync(WORKBENCH_STATS_RANGE_KEY);
|
||
const tabIndex = this.statsRangeTabs.findIndex((tab) => tab.value === saved);
|
||
if (tabIndex >= 0) {
|
||
this.statsRange = saved;
|
||
this.statsTabIndex = tabIndex;
|
||
}
|
||
},
|
||
notifyWorkbenchRefreshed() {
|
||
if (this.$refs.topMessage) {
|
||
this.$refs.topMessage.show({ text: '数据已刷新', type: 'success' });
|
||
}
|
||
},
|
||
refreshWorkbenchData() {
|
||
const silentStats = this.statsInitialized || this.hasStatsCache(this.statsRange);
|
||
return Promise.all([
|
||
this.getNotice(),
|
||
this.getInfo(),
|
||
this.getStore(),
|
||
this.getList(),
|
||
this.getAcceptingPatientList(),
|
||
this.fetchOnlineConsultationConfig(),
|
||
this.fetchWorkbenchStats({ silent: silentStats })
|
||
]).then(() => {
|
||
this.notifyWorkbenchRefreshed();
|
||
});
|
||
},
|
||
refreshReceptionData() {
|
||
if (this.isReceptionRefreshing) {
|
||
return Promise.resolve();
|
||
}
|
||
this.isReceptionRefreshing = true;
|
||
return Promise.all([
|
||
this.getInfo(),
|
||
this.getList(),
|
||
this.getAcceptingPatientList(),
|
||
this.fetchOnlineConsultationConfig(),
|
||
this.fetchWorkbenchStats({ silent: true })
|
||
]).then(() => {
|
||
this.notifyWorkbenchRefreshed();
|
||
}).finally(() => {
|
||
this.isReceptionRefreshing = false;
|
||
});
|
||
},
|
||
startRefreshTimer() {
|
||
this.stopRefreshTimer();
|
||
this.refreshTimer = setInterval(() => {
|
||
this.refreshReceptionData();
|
||
}, this.refreshIntervalMs);
|
||
},
|
||
stopRefreshTimer() {
|
||
if (this.refreshTimer) {
|
||
clearInterval(this.refreshTimer);
|
||
this.refreshTimer = null;
|
||
}
|
||
},
|
||
call () {
|
||
uni.makePhoneCall({
|
||
phoneNumber: '18157126670',
|
||
success: (result) => {},
|
||
fail: (error) => {}
|
||
})
|
||
},
|
||
scrolltolower() {
|
||
if (this.loading) {
|
||
this.loading = false
|
||
return
|
||
}
|
||
if (this.page >= this.totalPage) {
|
||
this.status = 'nomore'
|
||
return
|
||
}
|
||
this.loading = true
|
||
this.status = 'loading'
|
||
this.page++
|
||
},
|
||
goReceptionEntry(url) {
|
||
const doctorInfo = this.doctorInfo || {};
|
||
const user = doctorInfo.DoctorInfo && doctorInfo.DoctorInfo.user;
|
||
if (user && user.status === 3) {
|
||
this.$go('../../subPackages/sub_workbench/workbench_upInfo/index');
|
||
return;
|
||
}
|
||
this.$go(url);
|
||
},
|
||
fetchOnlineConsultationConfig() {
|
||
const storeId = uni.getStorageSync('store_id') || '11001';
|
||
return checkOnlineConsultationConfigApi({ store_id: storeId })
|
||
.then((res) => {
|
||
const payload = (res && res.result) || (res && res.data) || {};
|
||
if (res && (res.code === 0 || res.errcode === 0)) {
|
||
this.canUseOnlineConsultation = !!payload.can_use;
|
||
} else {
|
||
this.canUseOnlineConsultation = false;
|
||
}
|
||
})
|
||
.catch(() => {
|
||
this.canUseOnlineConsultation = false;
|
||
})
|
||
.finally(() => {
|
||
this.onlineConsultationConfigReady = true;
|
||
});
|
||
},
|
||
getNotice() {
|
||
return getNotice({
|
||
page_size: 9999,
|
||
store_id: uni.getStorageSync('store_id') || '11001'
|
||
}).then(res => {
|
||
if (res.errcode === 401) {
|
||
uni.clearStorageSync()
|
||
uni.reLaunch({ url: '/pages/login/index' })
|
||
}
|
||
this.noticeList = res.data.list
|
||
})
|
||
},
|
||
|
||
// 医生详情
|
||
getInfo() {
|
||
return info({
|
||
store_id: uni.getStorageSync('store_id') || '11001'
|
||
}).then((res) => {
|
||
if (res.errcode == 0) {
|
||
this.doctorInfo = res.data
|
||
this.see_rate = res.data.store.store.see_rate
|
||
uni.setStorageSync('see_rate', this.see_rate)
|
||
uni.setStorageSync('doctorInfo', this.doctorInfo)
|
||
}
|
||
})
|
||
},
|
||
|
||
// 搜索门店
|
||
handleSearch() {
|
||
this.getStore()
|
||
},
|
||
|
||
// 门店列表
|
||
getStore() {
|
||
return currentList({
|
||
store_id: uni.getStorageSync('store_id') || '11001',
|
||
keyword: this.keyword
|
||
}).then((res) => {
|
||
if (res.errcode == 0) {
|
||
this.storeList = res.data.list
|
||
}
|
||
})
|
||
},
|
||
|
||
// 切换门店
|
||
changeStore(id) {
|
||
this.store_id = id
|
||
},
|
||
sure() {
|
||
chooseList({
|
||
store_id: uni.getStorageSync('store_id') || '11001',
|
||
store: this.store_id
|
||
}).then((res) => {
|
||
if (res.errcode == 0) {
|
||
this.$toast(res.data[0])
|
||
uni.setStorageSync('store_id', this.store_id)
|
||
} else {
|
||
this.$toast(res.msg || res.data[0])
|
||
this.store_id = uni.getStorageSync('store_id')
|
||
}
|
||
|
||
this.openShow = false
|
||
this.onlineConsultationConfigReady = false
|
||
this.refreshWorkbenchData()
|
||
})
|
||
},
|
||
selectStatsTab(index) {
|
||
if (this.statsSwiperChanging) return;
|
||
const tab = this.statsRangeTabs[index];
|
||
if (!tab) return;
|
||
this.statsTabIndex = index;
|
||
this.changeStatsRange(tab.value);
|
||
},
|
||
onStatsSwiperChange(e) {
|
||
const index = e.detail.current;
|
||
const tab = this.statsRangeTabs[index];
|
||
if (!tab || tab.value === this.statsRange) return;
|
||
this.statsSwiperChanging = true;
|
||
this.statsTabIndex = index;
|
||
this.changeStatsRange(tab.value);
|
||
this.$nextTick(() => {
|
||
this.statsSwiperChanging = false;
|
||
});
|
||
},
|
||
changeStatsRange(range) {
|
||
if (this.statsRange === range && this.hasStatsCache(range)) {
|
||
this.workbenchStats = { ...this.getStatsForRange(range) };
|
||
return;
|
||
}
|
||
this.statsRange = range;
|
||
uni.setStorageSync(WORKBENCH_STATS_RANGE_KEY, range);
|
||
const tabIndex = this.statsRangeTabs.findIndex((tab) => tab.value === range);
|
||
if (tabIndex >= 0) {
|
||
this.statsTabIndex = tabIndex;
|
||
}
|
||
if (this.hasStatsCache(range)) {
|
||
this.workbenchStats = { ...this.getStatsForRange(range) };
|
||
this.fetchWorkbenchStats({ silent: true });
|
||
return;
|
||
}
|
||
this.fetchWorkbenchStats({ silent: false });
|
||
},
|
||
hasStatsCache(range) {
|
||
return this.statsCache[range] != null;
|
||
},
|
||
getStatsForRange(range) {
|
||
return this.statsCache[range] || { ...EMPTY_WORKBENCH_STATS };
|
||
},
|
||
normalizeWorkbenchStats(payload = {}) {
|
||
return {
|
||
prescription_count: payload.prescription_count || 0,
|
||
wait_accept: payload.wait_accept || 0,
|
||
accepting: payload.accepting || 0,
|
||
completed: payload.completed || 0,
|
||
prescription_amount: payload.prescription_amount || '0.000',
|
||
};
|
||
},
|
||
formatStatsAmount(amount) {
|
||
const num = Number(amount)
|
||
if (Number.isNaN(num)) return '0.000'
|
||
return num.toFixed(3)
|
||
},
|
||
fetchWorkbenchStats(options = {}) {
|
||
const silent = options.silent === true;
|
||
const range = options.range || this.statsRange;
|
||
const hasCache = this.hasStatsCache(range);
|
||
if (!silent && !hasCache) {
|
||
this.statsLoading = true;
|
||
}
|
||
return getWorkbenchStats({
|
||
store_id: uni.getStorageSync('store_id') || '11001',
|
||
range,
|
||
}).then((res) => {
|
||
const payload = (res && res.result) || (res && res.data) || {}
|
||
if (res && (res.code === 0 || res.errcode === 0)) {
|
||
const stats = this.normalizeWorkbenchStats(payload);
|
||
this.$set(this.statsCache, range, stats);
|
||
if (range === this.statsRange) {
|
||
this.workbenchStats = { ...stats };
|
||
}
|
||
this.statsInitialized = true;
|
||
}
|
||
}).catch(() => {
|
||
this.$toast && this.$toast('看板数据加载失败')
|
||
return Promise.reject(new Error('看板数据加载失败'));
|
||
}).finally(() => {
|
||
this.statsLoading = false;
|
||
})
|
||
},
|
||
// 消息列表
|
||
getList() {
|
||
return homeSession({
|
||
store_id: uni.getStorageSync('store_id') || '11001',
|
||
}).then((res) => {
|
||
if (res.errcode == 0) {
|
||
this.systemList = (res.data.system) || []
|
||
this.infoList = (res.data.patient) || []
|
||
|
||
} else {
|
||
this.$toast(res.msg);
|
||
}
|
||
this.$nextTick(() => {
|
||
this.loading = false
|
||
})
|
||
});
|
||
},
|
||
applyDoctorImRoomUpdateToAccepting(payload) {
|
||
const rid = normalizeRoomId(payload && payload.roomId);
|
||
if (!rid) return;
|
||
const idx = this.acceptingPatientList.findIndex((item) => normalizeRoomId(item.room_id) === rid);
|
||
if (idx === -1) return;
|
||
const item = this.acceptingPatientList[idx];
|
||
const next = { ...item };
|
||
if (payload.last_message_preview != null && String(payload.last_message_preview).trim() !== '') {
|
||
next.last_message_preview = payload.last_message_preview;
|
||
}
|
||
if (payload.last_message_time != null && payload.last_message_time !== '') {
|
||
next.last_message_time = payload.last_message_time;
|
||
}
|
||
if (payload.incrementUnread) {
|
||
if (payload.unreadForRoom != null) {
|
||
next.unread_count = Number(payload.unreadForRoom);
|
||
} else {
|
||
next.unread_count = Number(next.unread_count || 0) + 1;
|
||
}
|
||
}
|
||
const arr = [...this.acceptingPatientList];
|
||
arr.splice(idx, 1, next);
|
||
arr.sort((a, b) => {
|
||
const ta = this._acceptingSortTs(a);
|
||
const tb = this._acceptingSortTs(b);
|
||
if (tb !== ta) return tb - ta;
|
||
return (Number(b.register_id || b.id) || 0) - (Number(a.register_id || a.id) || 0);
|
||
});
|
||
this.acceptingPatientList = arr;
|
||
},
|
||
// 获取正在接诊的患者列表(线下待接诊+接诊中 + 线上当前,按最后消息时间排序)
|
||
getAcceptingPatientList() {
|
||
const storeId = uni.getStorageSync('store_id') || '11001';
|
||
return Promise.all([
|
||
fetchAcceptingPatientListApi({ store_id: storeId }),
|
||
getOnlineConsultationPatientListApi({ type: 1 })
|
||
]).then(([offlineRes, onlineRes]) => {
|
||
const offlineOk = offlineRes && (offlineRes.code === 0 || offlineRes.errcode === 0);
|
||
const onlineOk = onlineRes && (onlineRes.code === 0 || onlineRes.errcode === 0);
|
||
const offlineList = offlineOk && Array.isArray(offlineRes.result) ? offlineRes.result : [];
|
||
const onlineList = onlineOk && Array.isArray(onlineRes.result) ? onlineRes.result : [];
|
||
const merged = [];
|
||
offlineList.forEach((row) => {
|
||
merged.push({
|
||
...row,
|
||
consultation_channel: row.consultation_channel || 'offline'
|
||
});
|
||
});
|
||
onlineList.forEach((row) => {
|
||
merged.push({
|
||
...row,
|
||
consultation_channel: 'online'
|
||
});
|
||
});
|
||
merged.sort((a, b) => {
|
||
const ta = this._acceptingSortTs(a);
|
||
const tb = this._acceptingSortTs(b);
|
||
if (tb !== ta) return tb - ta;
|
||
return (Number(b.register_id || b.id) || 0) - (Number(a.register_id || a.id) || 0);
|
||
});
|
||
this.acceptingPatientList = merged;
|
||
}).catch((err) => {
|
||
console.error('获取正在接诊列表失败', err);
|
||
return Promise.reject(err);
|
||
});
|
||
},
|
||
_acceptingSortTs(item) {
|
||
const t = item.last_message_time || item.updated_at || item.created_at || item.register_time;
|
||
if (!t) return 0;
|
||
const ms = typeof t === 'number' ? (t > 1e12 ? t : t * 1000) : new Date(t).getTime();
|
||
return Number.isNaN(ms) ? 0 : ms;
|
||
},
|
||
acceptingRowKey(item, index) {
|
||
const rid = item.register_id != null ? item.register_id : item.id;
|
||
const room = item.room_id != null && item.room_id !== '' ? String(item.room_id) : 'noroom';
|
||
return `${item.consultation_channel || 'off'}-${room}-${rid}-${index}`;
|
||
},
|
||
acceptingBadgeKey(item, index) {
|
||
const unread = item.unread_count != null ? Number(item.unread_count) : 0;
|
||
return `wb-ub-${this.acceptingRowKey(item, index)}-${unread}`;
|
||
},
|
||
acceptingPreview(item) {
|
||
const p = item.last_message_preview;
|
||
if (p != null && String(p).trim() !== '') return String(p);
|
||
return '暂无消息';
|
||
},
|
||
formatAcceptingMsgTime(item) {
|
||
return formatSessionRelativeTime(item);
|
||
},
|
||
acceptingSexAgeText(item) {
|
||
const up = item && item.user_patient;
|
||
if (!up) return '';
|
||
const sex = Number(up.sex) % 2 !== 0 ? '男' : '女';
|
||
const age = up.age != null && up.age !== '' ? `${up.age}岁` : '';
|
||
const parts = [sex, age].filter(Boolean);
|
||
return parts.length ? parts.join(' ') : '';
|
||
},
|
||
acceptingLastMessageLine(item) {
|
||
return this.acceptingPreview(item);
|
||
},
|
||
acceptingOfflineRegisterTimeText(item) {
|
||
const t = (item && (item.register_time || item.created_at)) || '';
|
||
if (t === '' || t == null) return '';
|
||
const ms = typeof t === 'number' ? (t > 1e12 ? t : t * 1000) : new Date(t).getTime();
|
||
if (Number.isNaN(ms)) return '';
|
||
const d = new Date(ms);
|
||
const pad = (n) => (n < 10 ? '0' + n : '' + n);
|
||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||
},
|
||
acceptingOfflineOrderText(item) {
|
||
if (!item) return '';
|
||
const o = item.order_no || item.prescription_no || item.register_no;
|
||
if (o == null || String(o).trim() === '') return '';
|
||
return `挂号订单:${o}`;
|
||
},
|
||
onAcceptingOfflineCardTap(e) {
|
||
const item = this._acceptingItemByEvent(e);
|
||
if (!item || item.consultation_channel === 'online') return;
|
||
const pid = item.user_patient_id || (item.user_patient && item.user_patient.id);
|
||
const reId = item.id;
|
||
if (pid == null || reId == null) return;
|
||
this.$go(`../../subPackages/sub_workbench/workbench_infoPatient?id=${pid}&re_id=${reId}`);
|
||
},
|
||
acceptingStatusLabel(item) {
|
||
const st = Number(item.status);
|
||
const m = { 1: '待接诊', 2: '接诊中', 3: '已结束' };
|
||
return m[st] || '接诊中';
|
||
},
|
||
acceptingStatusColor(item) {
|
||
const st = Number(item.status);
|
||
if (st === 1) return '#F44336';
|
||
if (st === 2) return '#00C853';
|
||
return '#C4C7CC';
|
||
},
|
||
_acceptingItemByEvent(e) {
|
||
const ds = e && e.currentTarget && e.currentTarget.dataset ? e.currentTarget.dataset : null;
|
||
const raw = ds != null ? ds.idx : undefined;
|
||
const idx = Number(raw);
|
||
if (Number.isNaN(idx) || idx < 0) return null;
|
||
const item = this.acceptingPatientList[idx];
|
||
return item && typeof item === 'object' ? item : null;
|
||
},
|
||
openAcceptingChatByIndex(e) {
|
||
const item = this._acceptingItemByEvent(e);
|
||
if (!item || item.consultation_channel !== 'online') return;
|
||
const regId = item.register_id != null ? item.register_id : item.id;
|
||
const name = encodeURIComponent((item.user_patient && item.user_patient.name) || (item.user && item.user.nick_name) || '患者');
|
||
const room = item.room_id || '';
|
||
const up = item.user_patient_id || (item.user_patient && item.user_patient.id) || '';
|
||
this.$go(
|
||
`../../subPackages/sub_online_reception/pages/chat?register_id=${regId}&room_id=${encodeURIComponent(String(room))}&patient_name=${name}&user_patient_id=${up}`
|
||
);
|
||
},
|
||
openAcceptingPrescriptionByIndex(e) {
|
||
const item = this._acceptingItemByEvent(e);
|
||
if (!item) return;
|
||
const regId = item.id;
|
||
if (regId == null) return;
|
||
const pid = item.user_patient_id || (item.user_patient && item.user_patient.id) || '';
|
||
let url = `../../subPackages/sub_workbench/prescription_v2/index?register_id=${regId}`;
|
||
if (pid) url += `&patient_id=${pid}`;
|
||
this.$go(url);
|
||
}
|
||
},
|
||
mounted() {
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style>
|
||
page {
|
||
background-color: #f7f8fa;
|
||
}
|
||
</style>
|
||
<style lang="scss" scoped>
|
||
.navbar {
|
||
background: transparent;
|
||
width: 100vw;
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
font-size: 34rpx;
|
||
font-family: PingFang SC-Medium, PingFang SC;
|
||
font-weight: 500;
|
||
color: #FFFFFF;
|
||
z-index: 99999;
|
||
}
|
||
|
||
.header-wrap {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
top: 0;
|
||
z-index: 100;
|
||
background: #6ACDBB;
|
||
border-radius: 0 60rpx 60rpx;
|
||
padding: 0 32rpx 32rpx;
|
||
}
|
||
|
||
.header-spacer {
|
||
width: 100%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.content {
|
||
padding: 0 24rpx;
|
||
position: relative;
|
||
z-index: 1;
|
||
margin-top: 0;
|
||
}
|
||
|
||
/* 顶部门店选择器扁平化 */
|
||
.content_popup {
|
||
padding: 24rpx;
|
||
background: #fff;
|
||
border-radius: 24rpx 24rpx 0 0;
|
||
|
||
.top {
|
||
height: 200rpx;
|
||
.search {
|
||
position: relative;
|
||
z-index: 982;
|
||
margin-top: 24rpx;
|
||
}
|
||
.title {
|
||
height: 54rpx;
|
||
line-height: 54rpx;
|
||
font-size: 32rpx;
|
||
text-align: center;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.store_list {
|
||
padding: 26rpx 16rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
border-bottom: 1rpx solid #f5f6f8;
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.active-store-text {
|
||
color: #6ACDBB;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.confrim-btn {
|
||
width: 100%;
|
||
height: 100rpx;
|
||
padding: 0 16rpx;
|
||
margin-top: 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.u-btn {
|
||
width: 310rpx;
|
||
height: 84rpx;
|
||
line-height: 84rpx;
|
||
text-align: center;
|
||
border-radius: 44rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.qx {
|
||
background: #f7f8fa;
|
||
color: #666;
|
||
}
|
||
|
||
.qd {
|
||
background: #6ACDBB;
|
||
color: #FFFFFF;
|
||
}
|
||
}
|
||
}
|
||
|
||
.box {
|
||
position: relative;
|
||
min-height: 200rpx;
|
||
|
||
&_info {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-wrap: nowrap;
|
||
justify-content: space-between;
|
||
|
||
&_left {
|
||
display: flex;
|
||
align-items: center;
|
||
align-content: flex-start;
|
||
flex-wrap: nowrap;
|
||
color: #FFFFFF;
|
||
font-size: 28rpx;
|
||
|
||
&_name {
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
margin-right: 16rpx;
|
||
}
|
||
}
|
||
|
||
&_right {
|
||
height: 106rpx;
|
||
image {
|
||
width: 72rpx;
|
||
height: 72rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.store_ {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
font-size: 28rpx;
|
||
color: #FFFFFF;
|
||
padding: 0 24rpx;
|
||
margin-bottom: 24rpx;
|
||
|
||
.u-icon {
|
||
margin-left: 12rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 看板统计 */
|
||
.dashboard-panel {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx 24rpx 8rpx;
|
||
margin-top: -24rpx;
|
||
margin-bottom: 20rpx;
|
||
position: relative;
|
||
z-index: 2;
|
||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.dashboard-tabs {
|
||
display: flex;
|
||
flex-direction: row;
|
||
margin-bottom: 24rpx;
|
||
background: #f5f6f8;
|
||
border-radius: 12rpx;
|
||
padding: 6rpx;
|
||
}
|
||
|
||
.dashboard-tab {
|
||
flex: 1;
|
||
text-align: center;
|
||
font-size: 24rpx;
|
||
color: #6c7380;
|
||
padding: 12rpx 0;
|
||
border-radius: 8rpx;
|
||
}
|
||
|
||
.dashboard-tab.active {
|
||
background: #fff;
|
||
color: #6acdbb;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.dashboard-body {
|
||
position: relative;
|
||
min-height: 280rpx;
|
||
}
|
||
|
||
.dashboard-swiper {
|
||
height: 280rpx;
|
||
}
|
||
|
||
.dashboard-loading-overlay {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 2;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: rgba(255, 255, 255, 0.72);
|
||
}
|
||
|
||
.dashboard-grid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
min-height: 280rpx;
|
||
}
|
||
|
||
.dashboard-stat {
|
||
width: 25%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 16rpx 0 24rpx;
|
||
}
|
||
|
||
.dashboard-stat-wide {
|
||
width: 100%;
|
||
border-top: 1rpx solid #f0f1f3;
|
||
margin-top: 8rpx;
|
||
padding-top: 24rpx;
|
||
}
|
||
|
||
.dashboard-stat-value {
|
||
font-size: 36rpx;
|
||
font-weight: 700;
|
||
color: #0d111a;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.dashboard-stat-value.amount {
|
||
font-size: 40rpx;
|
||
color: #6acdbb;
|
||
}
|
||
|
||
.dashboard-stat-label {
|
||
font-size: 22rpx;
|
||
color: #6c7380;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
/* 功能菜单:接诊入口 */
|
||
.function {
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
font-size: 28rpx;
|
||
font-family: PingFang SC-Regular, PingFang SC;
|
||
font-weight: 400;
|
||
color: #323233;
|
||
|
||
&_grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
grid-column-gap: 86rpx;
|
||
}
|
||
|
||
&_item {
|
||
position: relative;
|
||
width: 292rpx;
|
||
height: 144rpx;
|
||
}
|
||
|
||
image {
|
||
width: 96rpx;
|
||
height: 96rpx;
|
||
}
|
||
}
|
||
|
||
.offline-entry-row {
|
||
position: relative;
|
||
width: 100%;
|
||
min-height: 132rpx;
|
||
padding: 24rpx 28rpx;
|
||
box-sizing: border-box;
|
||
background: linear-gradient(135deg, #f0faf8 0%, #e8f7f4 100%);
|
||
border-radius: 16rpx;
|
||
border: 1rpx solid rgba(106, 205, 187, 0.25);
|
||
}
|
||
|
||
.offline-entry-icon {
|
||
width: 88rpx;
|
||
height: 88rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.offline-entry-body {
|
||
margin-left: 24rpx;
|
||
min-width: 0;
|
||
}
|
||
|
||
.offline-entry-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #0d111a;
|
||
line-height: 44rpx;
|
||
}
|
||
|
||
.offline-entry-desc {
|
||
margin-top: 6rpx;
|
||
font-size: 24rpx;
|
||
color: #6c7380;
|
||
line-height: 34rpx;
|
||
}
|
||
|
||
/* 通用板块平铺和消息通知:完全恢复至初始样式 */
|
||
.news {
|
||
background-color: #fff;
|
||
margin-top: 20rpx;
|
||
max-height: 100vh;
|
||
|
||
|
||
&_title {
|
||
height: 82rpx;
|
||
font-size: 32rpx;
|
||
font-family: PingFang SC-Semibold, PingFang SC;
|
||
font-weight: 600;
|
||
color: #0D111A;
|
||
padding: 0 26rpx;
|
||
box-sizing: border-box;
|
||
|
||
text {
|
||
font-size: 28rpx;
|
||
font-family: PingFang SC-Regular, PingFang SC;
|
||
font-weight: 400;
|
||
color: #6C7380;
|
||
}
|
||
}
|
||
|
||
&_item {
|
||
margin-top: 12rpx;
|
||
padding: 26rpx 20rpx;
|
||
position: relative;
|
||
|
||
&_info {
|
||
height: 92rpx;
|
||
width: 562rpx;
|
||
font-family: PingFang SC-Regular, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 32rpx;
|
||
|
||
&_msg {
|
||
font-size: 28rpx;
|
||
width: 462rpx;
|
||
color: #6C7380;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 正在接诊列表:保持扁平化优化和覆盖 */
|
||
.flat-card {
|
||
padding: 24rpx 20rpx;
|
||
border-bottom: 1rpx solid #f5f6f8;
|
||
margin-top: 0 !important; /* 覆盖原始 _item margin */
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.wb-avatar-wrap {
|
||
width: 80rpx;
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.wb-card-body {
|
||
width: auto !important;
|
||
height: auto !important;
|
||
min-width: 0;
|
||
}
|
||
|
||
.wb-name {
|
||
font-size: 32rpx;
|
||
font-weight: 500;
|
||
color: #333;
|
||
margin-right: 16rpx;
|
||
}
|
||
|
||
.wb-meta {
|
||
font-size: 24rpx;
|
||
color: #888;
|
||
}
|
||
|
||
.wb-tag {
|
||
margin-left: 12rpx;
|
||
transform: scale(0.9);
|
||
transform-origin: left center;
|
||
}
|
||
|
||
.wb-time {
|
||
flex-shrink: 0;
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
margin-left: 16rpx;
|
||
}
|
||
|
||
.wb-preview {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.wb-sub {
|
||
display: inline-block;
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.wb-actions {
|
||
flex-shrink: 0;
|
||
gap: 16rpx;
|
||
align-items: center;
|
||
}
|
||
|
||
.wb-action-btn {
|
||
padding: 10rpx 28rpx;
|
||
font-size: 24rpx;
|
||
border-radius: 30rpx;
|
||
font-weight: 500;
|
||
line-height: 1.4;
|
||
text-align: center;
|
||
}
|
||
|
||
.btn-primary {
|
||
color: #fff;
|
||
background: #6ACDBB;
|
||
}
|
||
|
||
.btn-ghost {
|
||
color: #6ACDBB;
|
||
background: #f0f9f7;
|
||
border: 1rpx solid #c2ece2;
|
||
}
|
||
|
||
.phone {
|
||
color: #999;
|
||
text-align: center;
|
||
padding-top: 24rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.text-hide {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.m-t-8 { margin-top: 8rpx; }
|
||
.m-t-12 { margin-top: 12rpx; }
|
||
.m-t-32 { margin-top: 32rpx; }
|
||
</style> |