feat(home): implement workbench dashboard

This commit is contained in:
yelan
2026-08-27 17:08:51 +08:00
parent 4412a85adc
commit a61946b520
8 changed files with 1477 additions and 48 deletions
@@ -0,0 +1,215 @@
<script setup lang="ts">
import type { HomeTodoItem } from '../types'
defineProps<{
items: HomeTodoItem[]
}>()
const emit = defineEmits<{
select: [item: HomeTodoItem]
viewAll: []
}>()
function getStatusLabel(item: HomeTodoItem) {
if (item.status === 'overdue') {
return '已超时'
}
return item.method === 'pad' ? '待签署·手写板' : '待签署·短信'
}
function getStatusClass(item: HomeTodoItem) {
if (item.status === 'overdue') {
return 'todo-status--overdue'
}
return item.method === 'pad' ? 'todo-status--pad' : 'todo-status--sms'
}
function getHint(item: HomeTodoItem) {
return item.status === 'overdue' ? '⚠ 已超时,需重新发起' : '⏳ 等待患者签署'
}
</script>
<template>
<section class="home-panel todo-panel">
<div class="panel-heading">
<h2>我的待办</h2>
<button type="button" class="panel-more" @click="emit('viewAll')">全部 ›</button>
</div>
<div v-if="items.length" class="todo-list">
<button
v-for="item in items"
:key="item.id"
type="button"
class="todo-item"
@click="emit('select', item)"
>
<span class="todo-row">
<strong>{{ item.patientName }}</strong>
<span class="patient-id">{{ item.patientId }}</span>
<span class="todo-spacer" />
<span class="todo-status" :class="getStatusClass(item)">
{{ getStatusLabel(item) }}
</span>
</span>
<span class="todo-row todo-row--detail">
<span class="todo-document">📄 {{ item.documentName }}</span>
<span class="todo-hint">{{ getHint(item) }}</span>
</span>
</button>
</div>
<div v-else class="todo-empty">
<span aria-hidden="true">🎉</span>
<p>暂无待办</p>
</div>
</section>
</template>
<style scoped>
.home-panel {
min-width: 0;
padding: 16px 18px;
background: var(--card);
border-radius: var(--r);
box-shadow: var(--sh);
}
.panel-heading {
display: flex;
gap: 10px;
align-items: center;
margin-bottom: 14px;
}
.panel-heading h2 {
margin: 0;
color: var(--ink);
font-size: 14.5px;
line-height: 1.4;
}
.panel-more {
margin-left: auto;
padding: 0;
color: var(--brand);
font-size: 12px;
background: transparent;
}
.panel-more:hover {
color: var(--brand-d);
}
.todo-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.todo-item {
display: block;
width: 100%;
padding: 9px 11px;
color: var(--ink);
text-align: left;
background: #fff;
border: 1px solid var(--line);
border-radius: 9px;
transition:
border-color 0.15s ease,
background 0.15s ease;
}
.todo-item:hover {
background: #f8fcfd;
border-color: var(--brand);
}
.todo-row {
display: flex;
min-width: 0;
gap: 8px;
align-items: center;
}
.todo-row strong {
flex-shrink: 0;
font-size: 14px;
}
.patient-id {
overflow: hidden;
color: var(--mut);
font-size: 11px;
text-overflow: ellipsis;
white-space: nowrap;
}
.todo-spacer {
flex: 1;
}
.todo-status {
flex-shrink: 0;
padding: 2px 8px;
font-size: 11px;
font-weight: 700;
border-radius: 20px;
}
.todo-status--pad {
color: var(--brand);
background: var(--brand-l);
}
.todo-status--sms {
color: #7a4dbb;
background: #f3ecfb;
}
.todo-status--overdue {
color: var(--err);
background: var(--err-l);
}
.todo-row--detail {
margin-top: 5px;
color: var(--mut);
font-size: 12px;
}
.todo-document {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.todo-hint {
flex-shrink: 0;
margin-left: auto;
white-space: nowrap;
}
.todo-empty {
display: grid;
min-height: 202px;
color: var(--mut);
font-size: 13px;
place-items: center;
align-content: center;
}
.todo-empty span {
margin-bottom: 7px;
font-size: 34px;
opacity: 0.5;
}
.todo-empty p {
margin: 0;
}
</style>