844 lines
24 KiB
Vue
844 lines
24 KiB
Vue
<template>
|
||
<div class="progress-board">
|
||
<section class="board-section overview-section">
|
||
<div class="section-heading">
|
||
<div class="heading-copy">
|
||
<h2>今日面诊概览</h2>
|
||
<span class="heading-badge">{{ isOwnershipMode ? '按本人归属' : '与排班合并' }}</span>
|
||
</div>
|
||
<span class="scope-chip"><el-icon><Lock /></el-icon>{{ scopeLabel }}</span>
|
||
</div>
|
||
|
||
<div class="overview-grid">
|
||
<article class="overview-card">
|
||
<span>{{ isOwnershipMode ? '今日本人面诊' : '今日面诊总号源' }}</span>
|
||
<strong>{{ todayOverview.totalVisits }}</strong>
|
||
<small>{{ todayOverview.doctorCount }} 位{{ isOwnershipMode ? '接诊' : '排班' }}医生</small>
|
||
</article>
|
||
<article class="overview-card">
|
||
<span>{{ isOwnershipMode ? '待面诊' : '已预约' }}</span>
|
||
<strong>{{ todayOverview.booked }}</strong>
|
||
<small>{{ isOwnershipMode ? '本人归属患者的有效挂号' : '按有效挂号占用号源' }}</small>
|
||
</article>
|
||
<article :class="['overview-card', isOwnershipMode ? 'overview-card-completed' : 'overview-card-empty']">
|
||
<span>{{ isOwnershipMode ? '已完成' : '空号' }}</span>
|
||
<strong>{{ isOwnershipMode ? todayOverview.completed : todayOverview.emptySlots }}</strong>
|
||
<small>{{ isOwnershipMode ? `已过号 ${todayOverview.missed} 人` : '未被有效挂号占用' }}</small>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="board-section schedule-section">
|
||
<div class="section-heading">
|
||
<div class="heading-copy">
|
||
<h2>{{ isOwnershipMode ? '近一周面诊安排' : '近一周排班' }}</h2>
|
||
<span class="heading-badge">{{ isOwnershipMode ? '本人患者' : '今日起 7 天' }}</span>
|
||
</div>
|
||
<span class="schedule-range">{{ scheduleRange }}</span>
|
||
</div>
|
||
|
||
<div class="schedule-grid">
|
||
<button
|
||
v-for="day in weekSchedule"
|
||
:key="day.date"
|
||
type="button"
|
||
class="schedule-card"
|
||
:class="{
|
||
'is-today': day.date === today,
|
||
'is-selected': day.date === selectedScheduleDate
|
||
}"
|
||
:aria-pressed="day.date === selectedScheduleDate"
|
||
@click="selectScheduleDay(day.date)"
|
||
>
|
||
<span class="schedule-date">{{ day.date_text }} {{ day.weekday }}</span>
|
||
<strong>{{ isOwnershipMode ? day.total_appointments : day.total_slots }}</strong>
|
||
<span class="schedule-card-stats">
|
||
<span>{{ isOwnershipMode ? '待诊' : '已约' }} {{ isOwnershipMode ? day.waiting_appointments : day.booked_slots }}</span>
|
||
<i>/</i>
|
||
<span :class="{ 'is-completed': isOwnershipMode }">{{ isOwnershipMode ? '完成' : '空' }} {{ isOwnershipMode ? day.completed_appointments : day.empty_slots }}</span>
|
||
</span>
|
||
<span class="schedule-card-action">
|
||
<span>{{ day.doctor_count }} 位医生</span>
|
||
<span>{{ day.date === selectedScheduleDate ? '正在查看' : '查看明细' }} ›</span>
|
||
</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="schedule-drilldown">
|
||
<div class="drilldown-heading">
|
||
<div>
|
||
<h3>{{ selectedScheduleLabel }}{{ isOwnershipMode ? '面诊安排' : '排班明细' }}</h3>
|
||
<p>共 {{ selectedScheduleDay.doctor_count }} 位{{ isOwnershipMode ? '接诊' : '排班' }}医生,点击上方日期可切换</p>
|
||
</div>
|
||
<div :class="['drilldown-summary', { 'is-ownership': isOwnershipMode }]">
|
||
<span>{{ isOwnershipMode ? '面诊总数' : '总号源' }} <strong>{{ isOwnershipMode ? selectedScheduleDay.total_appointments : selectedScheduleDay.total_slots }}</strong></span>
|
||
<span>{{ isOwnershipMode ? '待面诊' : '已预约' }} <strong>{{ isOwnershipMode ? selectedScheduleDay.waiting_appointments : selectedScheduleDay.booked_slots }}</strong></span>
|
||
<span>{{ isOwnershipMode ? '已完成' : '空号' }} <strong>{{ isOwnershipMode ? selectedScheduleDay.completed_appointments : selectedScheduleDay.empty_slots }}</strong></span>
|
||
<span v-if="isOwnershipMode">已过号 <strong>{{ selectedScheduleDay.missed_appointments }}</strong></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-if="selectedScheduleDoctors.length" class="doctor-schedule-list">
|
||
<article
|
||
v-for="(doctor, index) in selectedScheduleDoctors"
|
||
:key="doctor.doctor_id"
|
||
class="doctor-schedule-row"
|
||
>
|
||
<div class="doctor-identity">
|
||
<span class="doctor-index">{{ index + 1 }}</span>
|
||
<div>
|
||
<strong>{{ doctor.doctor_name }}</strong>
|
||
<small>{{ isOwnershipMode ? '本人患者接诊医生' : '医生排班' }}</small>
|
||
</div>
|
||
</div>
|
||
<div class="doctor-windows">
|
||
<span>{{ isOwnershipMode ? '预约时刻' : '排班时段' }}</span>
|
||
<strong>{{ doctorWindows(doctor) }}</strong>
|
||
</div>
|
||
<div class="doctor-metric">
|
||
<span>{{ isOwnershipMode ? '面诊总数' : '总号源' }}</span>
|
||
<strong>{{ isOwnershipMode ? doctor.total_appointments : doctor.total_slots }}</strong>
|
||
</div>
|
||
<div class="doctor-metric doctor-metric-booked">
|
||
<span>{{ isOwnershipMode ? '待面诊' : '已预约' }}</span>
|
||
<strong>{{ isOwnershipMode ? doctor.waiting_appointments : doctor.booked_slots }}</strong>
|
||
</div>
|
||
<div :class="['doctor-metric', isOwnershipMode ? 'doctor-metric-completed' : 'doctor-metric-empty']">
|
||
<span>{{ isOwnershipMode ? '完成 / 过号' : '空号' }}</span>
|
||
<strong>{{ isOwnershipMode ? `${doctor.completed_appointments} / ${doctor.missed_appointments}` : doctor.empty_slots }}</strong>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
<el-empty
|
||
v-else
|
||
:image-size="56"
|
||
:description="isOwnershipMode ? '该日期暂无本人归属患者的有效挂号' : '该日期暂无当前权限范围内的医生排班'"
|
||
/>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="board-section queue-section">
|
||
<div class="section-heading queue-heading">
|
||
<div class="heading-copy">
|
||
<h2>{{ queueDateLabel }}候诊列表</h2>
|
||
<span class="heading-badge">按医生排队</span>
|
||
<span class="queue-count">共 {{ pager.count }} 人</span>
|
||
</div>
|
||
<span class="refresh-time">每 15 秒自动刷新</span>
|
||
</div>
|
||
|
||
<el-table
|
||
v-loading="pager.loading"
|
||
:data="pager.lists"
|
||
class="queue-table"
|
||
:row-class-name="tableRowClassName"
|
||
@row-dblclick="openDiagnosis"
|
||
>
|
||
<el-table-column label="排队" width="92">
|
||
<template #default="{ row }">
|
||
<span class="queue-number">{{ row.queue_no || '—' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="患者" min-width="170">
|
||
<template #default="{ row }">
|
||
<div class="patient-cell">
|
||
<strong>{{ row.patient_name || '未命名患者' }}</strong>
|
||
<span>{{ row.phone_masked || '无手机号' }}</span>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="doctor_name" label="医生" min-width="130" show-overflow-tooltip />
|
||
<el-table-column label="预约时间" min-width="135">
|
||
<template #default="{ row }">
|
||
<span class="appointment-clock">{{ appointmentClock(row) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="前方等待" min-width="180">
|
||
<template #default="{ row }">
|
||
<span :class="['waiting-text', `is-${row.queue_status || 'waiting'}`]">
|
||
{{ waitingText(row) }}
|
||
</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="状态" min-width="110">
|
||
<template #default="{ row }">
|
||
<el-tag size="small" round effect="light" :type="queueTagType(row.queue_status)">
|
||
{{ row.queue_status_text || '等待中' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<template #empty>
|
||
<el-empty :description="`当前权限范围内${queueDateLabel}暂无候诊患者`" />
|
||
</template>
|
||
</el-table>
|
||
|
||
<div v-if="pager.count > pager.size" class="pagination-wrap">
|
||
<pagination v-model="pager" @change="getLists" />
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||
import dayjs from 'dayjs'
|
||
import { Lock } from '@element-plus/icons-vue'
|
||
import { usePaging } from '@/hooks/usePaging'
|
||
import { myPatientProgressLists } from '@/api/first_visit'
|
||
|
||
const emit = defineEmits<{ openDiagnosis: [row: Record<string, any>] }>()
|
||
const today = dayjs().format('YYYY-MM-DD')
|
||
const selectedScheduleDate = ref(today)
|
||
const formData = reactive({
|
||
keyword: '',
|
||
status: 1 as const,
|
||
start_date: today,
|
||
end_date: today
|
||
})
|
||
|
||
const { pager, getLists, resetPage } = usePaging({
|
||
fetchFun: myPatientProgressLists as any,
|
||
params: formData,
|
||
size: 15,
|
||
firstLoading: true,
|
||
latestOnly: true
|
||
})
|
||
|
||
const todayOverview = computed(() => ({
|
||
totalVisits: Number(pager.extend?.today_overview?.total_visits || 0),
|
||
booked: Number(pager.extend?.today_overview?.booked || 0),
|
||
completed: Number(pager.extend?.today_overview?.completed || 0),
|
||
missed: Number(pager.extend?.today_overview?.missed || 0),
|
||
emptySlots: Number(pager.extend?.today_overview?.empty_slots || 0),
|
||
doctorCount: Number(pager.extend?.today_overview?.doctor_count || 0)
|
||
}))
|
||
const isOwnershipMode = computed(() => pager.extend?.schedule_mode === 'ownership')
|
||
|
||
const weekSchedule = computed(() => {
|
||
const rows = Array.isArray(pager.extend?.week_schedule) ? pager.extend.week_schedule : []
|
||
if (rows.length) return rows
|
||
|
||
return Array.from({ length: 7 }, (_, index) => {
|
||
const date = dayjs().add(index, 'day')
|
||
return {
|
||
date: date.format('YYYY-MM-DD'),
|
||
date_text: date.format('MM-DD'),
|
||
weekday: `周${'日一二三四五六'[date.day()]}`,
|
||
total_slots: 0,
|
||
booked_slots: 0,
|
||
empty_slots: 0,
|
||
doctor_count: 0,
|
||
doctors: [],
|
||
total_appointments: 0,
|
||
waiting_appointments: 0,
|
||
completed_appointments: 0,
|
||
missed_appointments: 0
|
||
}
|
||
})
|
||
})
|
||
|
||
const selectedScheduleDay = computed(() => {
|
||
return weekSchedule.value.find((day: any) => day.date === selectedScheduleDate.value) || weekSchedule.value[0] || {
|
||
date: today,
|
||
date_text: dayjs().format('MM-DD'),
|
||
weekday: `周${'日一二三四五六'[dayjs().day()]}`,
|
||
total_slots: 0,
|
||
booked_slots: 0,
|
||
empty_slots: 0,
|
||
doctor_count: 0,
|
||
doctors: [],
|
||
total_appointments: 0,
|
||
waiting_appointments: 0,
|
||
completed_appointments: 0,
|
||
missed_appointments: 0
|
||
}
|
||
})
|
||
const selectedScheduleDoctors = computed(() => {
|
||
return Array.isArray(selectedScheduleDay.value?.doctors) ? selectedScheduleDay.value.doctors : []
|
||
})
|
||
const selectedScheduleLabel = computed(() => {
|
||
const day = selectedScheduleDay.value
|
||
return `${day.date_text || ''} ${day.weekday || ''} `
|
||
})
|
||
const queueDateLabel = computed(() => {
|
||
if (selectedScheduleDate.value === today) return '今日'
|
||
return selectedScheduleLabel.value.trim() || selectedScheduleDate.value
|
||
})
|
||
|
||
const scopeLabel = computed(() => pager.extend?.scope?.label || '按权限加载')
|
||
const scheduleRange = computed(() => {
|
||
const rows = weekSchedule.value
|
||
if (!rows.length) return ''
|
||
return `${rows[0].date_text} 至 ${rows[rows.length - 1].date_text}`
|
||
})
|
||
|
||
let refreshTimer: ReturnType<typeof setInterval> | null = null
|
||
|
||
function refreshPanel(options?: { silent?: boolean }) {
|
||
return getLists(options)
|
||
}
|
||
|
||
function selectScheduleDay(date: string) {
|
||
if (!date) return
|
||
selectedScheduleDate.value = date
|
||
formData.start_date = date
|
||
formData.end_date = date
|
||
resetPage()
|
||
}
|
||
|
||
function doctorWindows(doctor: Record<string, any>) {
|
||
const source = isOwnershipMode.value ? doctor.appointment_times : doctor.schedule_windows
|
||
const windows = Array.isArray(source) ? source.filter(Boolean) : []
|
||
if (windows.length) return windows.join('、')
|
||
return isOwnershipMode.value ? '暂无预约时刻' : '未设置具体时段'
|
||
}
|
||
|
||
function appointmentClock(row: Record<string, any>) {
|
||
const time = String(row.appointment_time || '').slice(0, 5)
|
||
return time || '—'
|
||
}
|
||
|
||
function waitingText(row: Record<string, any>) {
|
||
if (row.queue_status === 'consulting') return '0(进行中)'
|
||
if (row.queue_status === 'next') return '0(待接诊)'
|
||
const ahead = Math.max(0, Number(row.ahead_count || 0))
|
||
if (ahead === 0) return '0 位'
|
||
return `${ahead} 位 · 约 ${Number(row.estimated_wait_minutes || ahead * 15)} 分钟`
|
||
}
|
||
|
||
function queueTagType(status: string): 'primary' | 'success' | 'warning' | 'danger' | 'info' {
|
||
if (status === 'consulting') return 'success'
|
||
if (status === 'next') return 'warning'
|
||
if (status === 'completed') return 'success'
|
||
if (status === 'missed') return 'danger'
|
||
return 'info'
|
||
}
|
||
|
||
function tableRowClassName({ row }: { row: Record<string, any> }) {
|
||
return Number(row.is_self_patient) === 1 ? 'queue-row-self' : ''
|
||
}
|
||
|
||
function openDiagnosis(row: Record<string, any>) {
|
||
emit('openDiagnosis', row)
|
||
}
|
||
|
||
defineExpose({ refresh: refreshPanel, loading: computed(() => pager.loading) })
|
||
|
||
onMounted(() => {
|
||
getLists()
|
||
refreshTimer = setInterval(() => getLists({ silent: true }), 15_000)
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
if (refreshTimer) clearInterval(refreshTimer)
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.progress-board {
|
||
display: grid;
|
||
gap: 14px;
|
||
color: #172033;
|
||
}
|
||
|
||
.board-section {
|
||
padding: 16px;
|
||
border: 1px solid #e1e7ee;
|
||
border-radius: 12px;
|
||
background: #fff;
|
||
}
|
||
|
||
.section-heading {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.heading-copy,
|
||
.scope-chip {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.heading-copy {
|
||
gap: 8px;
|
||
min-width: 0;
|
||
|
||
h2 {
|
||
margin: 0;
|
||
color: #172033;
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
|
||
.heading-badge {
|
||
padding: 3px 7px;
|
||
border-radius: 5px;
|
||
color: #758195;
|
||
background: #eef2f6;
|
||
font-size: 11px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.scope-chip {
|
||
gap: 5px;
|
||
color: #0f766e;
|
||
font-size: 12px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.overview-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 14px;
|
||
}
|
||
|
||
.overview-card {
|
||
min-height: 78px;
|
||
padding: 14px 16px;
|
||
border: 1px solid #dfe5ed;
|
||
border-radius: 10px;
|
||
background: #fff;
|
||
|
||
> span,
|
||
> small {
|
||
display: block;
|
||
color: #778398;
|
||
font-size: 12px;
|
||
}
|
||
|
||
> strong {
|
||
display: block;
|
||
margin: 7px 0 5px;
|
||
color: #111a2c;
|
||
font-size: 24px;
|
||
line-height: 1;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
> small {
|
||
color: #a0a9b7;
|
||
font-size: 11px;
|
||
}
|
||
}
|
||
|
||
.overview-card-empty > strong {
|
||
color: #ee4d55;
|
||
}
|
||
|
||
.overview-card-completed > strong {
|
||
color: #07886d;
|
||
}
|
||
|
||
.schedule-range,
|
||
.refresh-time,
|
||
.queue-count {
|
||
color: #929dac;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.schedule-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||
gap: 8px;
|
||
}
|
||
|
||
.schedule-card {
|
||
min-width: 0;
|
||
padding: 11px 8px;
|
||
text-align: center;
|
||
border: 1px solid #dfe5ed;
|
||
border-radius: 9px;
|
||
background: #fbfcfe;
|
||
color: inherit;
|
||
font: inherit;
|
||
cursor: pointer;
|
||
transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
|
||
|
||
&:hover {
|
||
border-color: #7ac9c2;
|
||
background: #f7fcfb;
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
&:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
&:focus-visible {
|
||
outline: 3px solid rgba(15, 145, 133, 0.18);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
&.is-today {
|
||
border-color: #8fd3cd;
|
||
background: #f4fbfa;
|
||
}
|
||
|
||
&.is-selected {
|
||
border-color: #0f9185;
|
||
background: #effaf8;
|
||
box-shadow: 0 8px 20px rgba(15, 118, 110, 0.1), inset 0 -3px 0 #0f9185;
|
||
}
|
||
|
||
> strong {
|
||
display: block;
|
||
margin: 7px 0 5px;
|
||
color: #131c2d;
|
||
font-size: 20px;
|
||
line-height: 1;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
}
|
||
|
||
.schedule-date {
|
||
display: block;
|
||
overflow: hidden;
|
||
color: #70809a;
|
||
font-size: 11px;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.schedule-card-stats {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
color: #0c9967;
|
||
font-size: 11px;
|
||
white-space: nowrap;
|
||
|
||
i {
|
||
color: #a5afbd;
|
||
font-style: normal;
|
||
}
|
||
|
||
span:last-child {
|
||
color: #d8862b;
|
||
}
|
||
|
||
span.is-completed {
|
||
color: #07886d;
|
||
}
|
||
}
|
||
|
||
.schedule-card-action {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 6px;
|
||
margin: 10px 2px 0;
|
||
padding-top: 8px;
|
||
border-top: 1px solid #e7ecef;
|
||
color: #7b8799;
|
||
font-size: 10px;
|
||
|
||
span:last-child {
|
||
color: #0f8077;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.schedule-drilldown {
|
||
margin-top: 14px;
|
||
padding: 15px;
|
||
border-radius: 10px;
|
||
background: #f7f9fb;
|
||
}
|
||
|
||
.drilldown-heading {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
gap: 20px;
|
||
margin-bottom: 11px;
|
||
|
||
h3 {
|
||
margin: 0;
|
||
color: #1e293b;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
p {
|
||
margin: 4px 0 0;
|
||
color: #8a95a6;
|
||
font-size: 11px;
|
||
}
|
||
}
|
||
|
||
.drilldown-summary {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 18px;
|
||
color: #7a8698;
|
||
font-size: 11px;
|
||
white-space: nowrap;
|
||
|
||
strong {
|
||
margin-left: 3px;
|
||
color: #243044;
|
||
font-size: 14px;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
span:last-child strong {
|
||
color: #d17820;
|
||
}
|
||
}
|
||
|
||
.doctor-schedule-list {
|
||
display: grid;
|
||
gap: 7px;
|
||
}
|
||
|
||
.doctor-schedule-row {
|
||
display: grid;
|
||
grid-template-columns: minmax(150px, 1fr) minmax(210px, 1.8fr) repeat(3, minmax(64px, 0.55fr));
|
||
align-items: center;
|
||
gap: 14px;
|
||
min-height: 58px;
|
||
padding: 8px 13px;
|
||
border: 1px solid #e4e9ef;
|
||
border-radius: 8px;
|
||
background: #fff;
|
||
}
|
||
|
||
.doctor-identity {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
min-width: 0;
|
||
|
||
> div {
|
||
min-width: 0;
|
||
}
|
||
|
||
strong,
|
||
small {
|
||
display: block;
|
||
}
|
||
|
||
strong {
|
||
overflow: hidden;
|
||
color: #202b3d;
|
||
font-size: 13px;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
small {
|
||
margin-top: 2px;
|
||
color: #9aa4b2;
|
||
font-size: 10px;
|
||
}
|
||
}
|
||
|
||
.doctor-index {
|
||
display: grid;
|
||
flex: 0 0 28px;
|
||
width: 28px;
|
||
height: 28px;
|
||
place-items: center;
|
||
border-radius: 7px;
|
||
color: #0f766e;
|
||
background: #e7f6f4;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.doctor-windows,
|
||
.doctor-metric {
|
||
min-width: 0;
|
||
|
||
span,
|
||
strong {
|
||
display: block;
|
||
}
|
||
|
||
span {
|
||
color: #98a2b3;
|
||
font-size: 10px;
|
||
}
|
||
|
||
strong {
|
||
margin-top: 3px;
|
||
color: #344054;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
}
|
||
|
||
.doctor-windows strong {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.doctor-metric {
|
||
text-align: right;
|
||
|
||
strong {
|
||
font-size: 15px;
|
||
}
|
||
}
|
||
|
||
.doctor-metric-booked strong {
|
||
color: #07886d;
|
||
}
|
||
|
||
.doctor-metric-empty strong {
|
||
color: #d17820;
|
||
}
|
||
|
||
.doctor-metric-completed strong {
|
||
color: #07886d;
|
||
}
|
||
|
||
.queue-heading {
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.queue-table {
|
||
width: 100%;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
|
||
:deep(th.el-table__cell) {
|
||
height: 40px;
|
||
color: #667085;
|
||
background: #f7f9fb;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
:deep(td.el-table__cell) {
|
||
height: 46px;
|
||
padding: 6px 0;
|
||
color: #253044;
|
||
font-size: 13px;
|
||
}
|
||
|
||
:deep(.queue-row-self > td.el-table__cell) {
|
||
background: #fff8e8 !important;
|
||
}
|
||
|
||
:deep(.queue-row-self > td.el-table__cell:first-child) {
|
||
border-left: 3px solid #f08332;
|
||
}
|
||
}
|
||
|
||
.queue-number {
|
||
display: inline-grid;
|
||
min-width: 26px;
|
||
height: 26px;
|
||
padding: 0 7px;
|
||
place-items: center;
|
||
border-radius: 8px;
|
||
color: #0f766e;
|
||
background: #e7f6f4;
|
||
font-weight: 700;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.patient-cell {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
|
||
strong {
|
||
color: #1f2937;
|
||
font-size: 13px;
|
||
}
|
||
|
||
span {
|
||
color: #98a2b3;
|
||
font-size: 11px;
|
||
}
|
||
}
|
||
|
||
.appointment-clock {
|
||
color: #263246;
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.waiting-text {
|
||
color: #667085;
|
||
font-size: 12px;
|
||
|
||
&.is-consulting {
|
||
color: #07886d;
|
||
font-weight: 600;
|
||
}
|
||
|
||
&.is-next {
|
||
color: #d17820;
|
||
}
|
||
}
|
||
|
||
.pagination-wrap {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
padding-top: 14px;
|
||
}
|
||
|
||
@media (max-width: 1180px) {
|
||
.schedule-grid {
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
}
|
||
|
||
.doctor-schedule-row {
|
||
grid-template-columns: minmax(140px, 1fr) minmax(180px, 1.5fr) repeat(3, minmax(56px, 0.5fr));
|
||
gap: 10px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 760px) {
|
||
.board-section {
|
||
padding: 12px;
|
||
}
|
||
|
||
.overview-grid,
|
||
.schedule-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.section-heading {
|
||
align-items: flex-start;
|
||
flex-direction: column;
|
||
gap: 7px;
|
||
}
|
||
|
||
.heading-copy {
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.drilldown-heading,
|
||
.drilldown-summary {
|
||
align-items: flex-start;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.drilldown-summary {
|
||
gap: 5px;
|
||
}
|
||
|
||
.doctor-schedule-row {
|
||
grid-template-columns: repeat(3, 1fr);
|
||
}
|
||
|
||
.doctor-identity,
|
||
.doctor-windows {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.doctor-metric {
|
||
text-align: left;
|
||
}
|
||
}
|
||
</style>
|