278 lines
5.2 KiB
Vue
278 lines
5.2 KiB
Vue
<script setup lang="ts">
|
||
import { readPendingTag } from '@/utils/signing-method'
|
||
|
||
import type { HomeTodoItem } from '../types'
|
||
|
||
defineProps<{
|
||
items: HomeTodoItem[]
|
||
}>()
|
||
|
||
const emit = defineEmits<{
|
||
select: [item: HomeTodoItem]
|
||
viewAll: []
|
||
}>()
|
||
|
||
function getStatusLabel(item: HomeTodoItem) {
|
||
switch (item.status) {
|
||
case 'created':
|
||
return '待发送'
|
||
case 'pending':
|
||
return readPendingTag(item.method).text
|
||
case 'generating':
|
||
return '文书生成中'
|
||
case 'overdue':
|
||
return '已超时'
|
||
case 'signed':
|
||
return '已签署'
|
||
case 'voided':
|
||
return '已作废'
|
||
case 'failed':
|
||
return '处理失败'
|
||
}
|
||
}
|
||
|
||
function getStatusClass(item: HomeTodoItem) {
|
||
if (item.status === 'overdue') {
|
||
return 'todo-status--overdue'
|
||
}
|
||
|
||
if (item.status === 'pending') {
|
||
// 与签署工作台同口径:待签署徽标按具体方式分色
|
||
return `todo-status--${readPendingTag(item.method).className.replace('tg-', '')}`
|
||
}
|
||
|
||
if (item.status === 'signed') {
|
||
return 'todo-status--success'
|
||
}
|
||
|
||
if (item.status === 'failed') {
|
||
return 'todo-status--danger'
|
||
}
|
||
|
||
return 'todo-status--muted'
|
||
}
|
||
|
||
function getHint(item: HomeTodoItem) {
|
||
switch (item.status) {
|
||
case 'created':
|
||
return '⏳ 等待发送'
|
||
case 'pending':
|
||
return '⏳ 等待患者签署'
|
||
case 'generating':
|
||
return '⌛ 正在生成签署文书'
|
||
case 'overdue':
|
||
return '⚠ 已超时,需重新发起'
|
||
case 'signed':
|
||
return '✓ 已完成签署'
|
||
case 'voided':
|
||
return '— 任务已作废'
|
||
case 'failed':
|
||
return '⚠ 任务处理失败'
|
||
}
|
||
}
|
||
</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;
|
||
/* 原型 .titem 是 margin-bottom:10px */
|
||
gap: 10px;
|
||
}
|
||
|
||
.todo-item {
|
||
display: block;
|
||
width: 100%;
|
||
/* 原型 .titem:padding 11px 13px + 圆角 10px */
|
||
padding: 11px 13px;
|
||
color: var(--ink);
|
||
text-align: left;
|
||
background: #fff;
|
||
border: 1px solid var(--line);
|
||
border-radius: 10px;
|
||
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;
|
||
/* 原型 .tag:padding 2px 10px / 11.5px / 圆角 20px */
|
||
padding: 2px 10px;
|
||
font-size: 11.5px;
|
||
font-weight: 700;
|
||
border-radius: 20px;
|
||
}
|
||
|
||
.todo-status--pad {
|
||
color: var(--brand);
|
||
background: var(--brand-l);
|
||
}
|
||
|
||
.todo-status--ipad {
|
||
color: #2b6cb0;
|
||
background: #e8f1fb;
|
||
}
|
||
|
||
.todo-status--sms {
|
||
color: #7a4dbb;
|
||
background: #f3ecfb;
|
||
}
|
||
|
||
.todo-status--overdue,
|
||
.todo-status--danger {
|
||
color: var(--err);
|
||
background: var(--err-l);
|
||
}
|
||
|
||
.todo-status--success {
|
||
color: var(--ok);
|
||
background: var(--ok-l);
|
||
}
|
||
|
||
/* 原型 .tg-void */
|
||
.todo-status--muted {
|
||
color: #8a9aa3;
|
||
background: #eceef0;
|
||
}
|
||
|
||
.todo-row--detail {
|
||
margin-top: 5px;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
color: var(--mut);
|
||
font-size: 12.5px;
|
||
}
|
||
|
||
.todo-document {
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.todo-hint {
|
||
flex-shrink: 0;
|
||
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>
|