Orders.vue
6.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<template>
<div class="orders-page">
<div class="page-header">
<h1>申请单管理</h1>
<div class="header-actions">
<el-button v-if="pgxStore.currentRole === 'sampler'" type="primary" @click="$router.push('/pgx/register')">+ 新建申请单</el-button>
<el-button plain @click="handleExport">导出数据</el-button>
</div>
</div>
<!-- 搜索 + 筛选 -->
<div class="filter-bar">
<el-input v-model="searchText" placeholder="搜索患者姓名、申请单编号..." clearable style="width:280px" prefix-icon="Search" />
<el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" style="width:280px" />
</div>
<el-tabs v-model="activeTab" class="status-tabs">
<el-tab-pane label="全部" name="all" />
<el-tab-pane name="draft">
<template #label><span>草稿 <el-badge :value="pgxStore.stats.draft" :hidden="!pgxStore.stats.draft" /></span></template>
</el-tab-pane>
<el-tab-pane name="submitted">
<template #label><span>已提交 <el-badge :value="pgxStore.stats.submitted" :hidden="!pgxStore.stats.submitted" type="warning" /></span></template>
</el-tab-pane>
<el-tab-pane label="接收审核" name="received" />
<el-tab-pane label="检测中" name="testing" />
<el-tab-pane label="已出报告" name="reported" />
<el-tab-pane name="failed">
<template #label><span>检测异常 <el-badge :value="pgxStore.stats.failed" :hidden="!pgxStore.stats.failed" type="danger" /></span></template>
</el-tab-pane>
</el-tabs>
<el-table :data="filteredOrders" row-key="id" style="width:100%" @row-click="(row: any) => $router.push('/pgx/orders/' + row.id)">
<el-table-column type="index" width="50" />
<el-table-column label="申请单编号" width="160">
<template #default="{ row }">
<span class="order-no-link">{{ row.orderNo }}</span>
<el-tag v-if="row.urgency" type="danger" size="small" effect="plain" style="margin-left:4px">急</el-tag>
</template>
</el-table-column>
<el-table-column label="患者姓名" prop="patientName" width="100" />
<el-table-column label="检测项目" width="120">
<template #default="{ row }">
<el-tag size="small" effect="light">{{ row.productType }}</el-tag>
</template>
</el-table-column>
<el-table-column label="送检单位" prop="hospitalName" min-width="180" show-overflow-tooltip />
<el-table-column label="提交日期" prop="submitDate" width="110" />
<el-table-column label="状态" width="110">
<template #default="{ row }">
<el-tag :type="statusType(row.status)" size="small" effect="light">{{ statusLabel(row.status) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="LIMS" width="120">
<template #default="{ row }">
<span :style="{ color: limsColor(row.limsStatus), fontSize:'12px' }">
{{ limsLabel(row.limsStatus) }}
</span>
</template>
</el-table-column>
<el-table-column label="操作" width="160" @click.stop>
<template #default="{ row }">
<el-button size="small" text type="primary" @click.stop="$router.push('/pgx/orders/' + row.id)">详情</el-button>
<el-button v-if="row.editable" size="small" text type="primary" @click.stop="$router.push('/pgx/orders/' + row.id)">编辑</el-button>
<el-button size="small" text type="danger" @click.stop="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="table-footer">
共 {{ filteredOrders.length }} 条记录
</div>
</div>
</template>
<script setup lang="ts">
import { usePGXStore, type Order } from '@/stores/pgx'
import { ElMessage, ElMessageBox } from 'element-plus'
const pgxStore = usePGXStore()
const router = useRouter()
const route = useRoute()
const searchText = ref('')
const activeTab = ref('all')
const dateRange = ref<[string, string] | null>(null)
// 从路由 query 初始化 tab
onMounted(() => {
if (route.query.tab) activeTab.value = route.query.tab as string
})
const filteredOrders = computed(() => {
let list = pgxStore.orders
if (activeTab.value !== 'all') {
if (activeTab.value === 'reported') {
list = list.filter(o => o.status === 'reported' || o.hasReport)
} else if (activeTab.value === 'failed') {
list = list.filter(o => o.failed)
} else {
list = list.filter(o => o.status === activeTab.value)
}
}
if (searchText.value) {
const kw = searchText.value.toLowerCase()
list = list.filter(o =>
o.patientName.toLowerCase().includes(kw) ||
o.orderNo.toLowerCase().includes(kw) ||
o.hospitalName.toLowerCase().includes(kw)
)
}
if (dateRange.value) {
const [start, end] = dateRange.value
list = list.filter(o => o.submitDate >= start && o.submitDate <= end)
}
return list
})
function statusLabel(s: string) {
return { draft:'草稿', submitted:'已提交', received:'接收审核', testing:'检测中', reported:'已出报告', failed:'检测异常' }[s] || s
}
function statusType(s: string) {
return { draft:'info', submitted:'warning', received:'', testing:'primary', reported:'success', failed:'danger' }[s] || ''
}
function limsLabel(s: string) {
return { pending:'⏳ 待推送', pushed:'✓ 已推送', failed:'⚠ 推送异常' }[s] || s
}
function limsColor(s: string) {
return { pending:'#aaa', pushed:'#52c41a', failed:'#ff4d4f' }[s] || '#aaa'
}
async function handleDelete(row: Order) {
await ElMessageBox.confirm(`确定删除申请单 ${row.orderNo} 吗?此操作不可恢复。`, '删除确认', { type: 'warning', confirmButtonText: '确定删除', cancelButtonText: '取消' })
pgxStore.deleteOrder(row.id)
ElMessage.success('已删除')
}
function handleExport() {
ElMessage.success('数据导出成功,文件已保存')
}
</script>
<style scoped>
.orders-page { padding: 24px; }
.page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
.page-header h1 { font-size: 20px; font-weight: 600; margin: 0; color: #1a1f2e; }
.header-actions { display: flex; gap: 10px; }
.filter-bar { display: flex; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.status-tabs { margin-bottom: 4px; }
.order-no-link { color: #409eff; font-size: 13px; cursor: pointer; }
.table-footer { padding: 12px 0; color: #888; font-size: 13px; text-align: right; }
:deep(.el-table__row) { cursor: pointer; }
:deep(.el-table__row:hover td) { background: #f0f7ff !important; }
</style>