Files
shanxia2.0/web-admin/src/views/cell-storage/protocol/index.vue
T
2026-05-17 12:31:11 +08:00

416 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 采集协议单 -->
<!-- eslint-disable vue/no-v-model-argument -->
<template>
<div class="page-container">
<header class="page-head">
<h1>采集协议单</h1>
<p class="page-desc">查看与管理采集协议单主数据。</p>
</header>
<section class="panel">
<div class="panel-top">
<h2 class="title-bar-heading">协议单列表</h2>
</div>
<div class="filter-block">
<el-form :model="searchForm" class="filter-form" @submit.prevent>
<div class="filter-grid">
<el-form-item label="关键词">
<el-input v-model="searchForm.keyword" placeholder="协议号/备注" clearable />
</el-form-item>
<el-form-item label="协议状态">
<el-select
v-model="searchForm.protocolStatus"
clearable
placeholder="全部"
style="width: 100%"
>
<el-option label="待生效" value="dsx" />
<el-option label="生效中" value="sxz" />
<el-option label="已过期" value="ygq" />
<el-option label="已作废" value="yzf" />
<el-option label="转科研" value="zky" />
</el-select>
</el-form-item>
</div>
<div class="filter-actions-row">
<span class="filter-hint">列表为概要信息,详情见弹窗。</span>
<div class="filter-actions-end">
<el-button class="btn-ghost" @click="handleReset"
><el-icon><RefreshLeft /></el-icon>重置</el-button
>
<el-button class="btn-main" type="primary" @click="handleSearch"
><el-icon><Search /></el-icon>搜索</el-button
>
</div>
</div>
</el-form>
</div>
<div class="list-toolbar">
<div class="list-toolbar-row">
<div class="list-toolbar-selected">
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
</div>
<el-button type="primary" class="btn-main" @click="handleAdd">
<el-icon><Plus /></el-icon>
新增
</el-button>
<el-button class="btn-ghost" :disabled="!selectedRows.length" @click="handleBatchDelete">
<el-icon><Delete /></el-icon>
批量删除
</el-button>
</div>
</div>
<div class="list-body list-wrap">
<el-table
class="list-table"
:data="tableData"
v-loading="loading"
stripe
row-key="id"
@selection-change="handleSelectionChange"
@row-dblclick="handleView"
>
<el-table-column type="selection" width="55" align="center" header-align="center" />
<el-table-column
type="index"
label="序号"
width="68"
align="center"
header-align="center"
:index="(index) => (pagination.page - 1) * pagination.pageSize + index + 1"
/>
<el-table-column
prop="protocolNo"
label="协议号"
min-width="140"
align="center"
header-align="center"
/>
<el-table-column
prop="protocolStatus"
label="状态"
width="100"
align="center"
header-align="center"
>
<template #default="{ row }">{{
protocolStatusLabel(String(row.protocolStatus || ''))
}}</template>
</el-table-column>
<el-table-column
prop="registerDate"
label="登记日期"
width="120"
align="center"
header-align="center"
/>
<el-table-column
prop="motherName"
label="母亲姓名"
min-width="100"
align="center"
header-align="center"
/>
<el-table-column
prop="motherPhone"
label="母亲电话"
min-width="130"
align="center"
header-align="center"
/>
<el-table-column
prop="motherIdCard"
label="母亲身份证号"
min-width="190"
align="center"
header-align="center"
/>
<el-table-column
prop="fatherName"
label="父亲姓名"
min-width="100"
align="center"
header-align="center"
/>
<el-table-column
prop="newbornSex"
label="新生儿性别"
width="110"
align="center"
header-align="center"
>
<template #default="{ row }">{{
newbornSexLabel(String(row.newbornSex || ''))
}}</template>
</el-table-column>
<el-table-column
prop="deliveryMode"
label="分娩方式"
width="100"
align="center"
header-align="center"
>
<template #default="{ row }">{{
deliveryModeLabel(String(row.deliveryMode || ''))
}}</template>
</el-table-column>
<el-table-column
prop="newbornWeightGram"
label="新生儿体重(克)"
width="140"
align="center"
header-align="center"
/>
<el-table-column
prop="regionName"
label="采集地区"
min-width="120"
align="center"
header-align="center"
/>
<el-table-column
prop="hospitalName"
label="采集医院"
min-width="140"
align="center"
header-align="center"
/>
<el-table-column
prop="collectorUserName"
label="采集专员"
min-width="100"
align="center"
header-align="center"
/>
<el-table-column
prop="salesUserName"
label="销售人员"
min-width="100"
align="center"
header-align="center"
/>
<el-table-column
prop="sampleCollectTime"
label="样本采集时间"
min-width="180"
align="center"
header-align="center"
/>
<el-table-column
prop="createTime"
label="创建时间"
min-width="180"
align="center"
header-align="center"
/>
<el-table-column
label="操作"
width="320"
fixed="right"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-button class="btn-op-item" @click="handleView(row)"
><el-icon><View /></el-icon>查看</el-button
>
<el-button class="btn-op-item primary" @click="handleEdit(row)"
><el-icon><Edit /></el-icon>编辑</el-button
>
<el-button class="btn-op-item" @click="handleDelete(row)"
><el-icon><Delete /></el-icon>删除</el-button
>
</template>
</el-table-column>
</el-table>
<div class="pagination list-pager-bar">
<el-pagination
:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
@size-change="(val) => ((pagination.page = 1), (pagination.pageSize = val), loadData())"
@current-change="(val) => ((pagination.page = val), loadData())"
/>
</div>
</div>
<!-- 新增/编辑弹窗 -->
<ProtocolFormDialog
v-model="formDialogVisible"
:edit-id="formDialogEditId"
:list-row="formDialogRow"
@saved="onFormSaved"
/>
<!-- 查看弹窗 -->
<ProtocolViewDialog
v-model="viewVisible"
:protocol-id="viewProtocolId"
:list-row="viewRow"
show-audit-history
/>
</section>
</div>
</template>
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Plus,
View,
Edit,
Delete,
Search,
RefreshLeft
} from '@element-plus/icons-vue'
import ProtocolFormDialog from './ProtocolFormDialog.vue'
import ProtocolViewDialog from './ProtocolViewDialog.vue'
import { withFullscreenLoading, fullscreenLoadingText } from '@/utils/fullscreen-loading'
import {
fetchCollectionProtocolList,
fetchDeleteCollectionProtocol,
type CollectionProtocolRow
} from '@/api/collection-protocol'
defineOptions({ name: 'CellStorageProtocol' })
/* ====== 标签映射 ====== */
function protocolStatusLabel(s: string) {
const m: Record<string, string> = {
dsx: '待生效',
sxz: '生效中',
ygq: '已过期',
yzf: '已作废',
zky: '转科研'
}
return m[s] || s || '-'
}
function newbornSexLabel(s: string) {
if (s === '1') return '男'
if (s === '0') return '女'
return s || '-'
}
function deliveryModeLabel(s: string) {
if (s === 'sc') return '顺产'
if (s === 'pgc') return '剖宫产'
return s || '-'
}
/* ====== 列表 ====== */
const searchForm = reactive<{ keyword: string; protocolStatus: string }>({
keyword: '',
protocolStatus: ''
})
const tableData = ref<CollectionProtocolRow[]>([])
const selectedRows = ref<CollectionProtocolRow[]>([])
const loading = ref(false)
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
const handleSelectionChange = (rows: CollectionProtocolRow[]) => {
selectedRows.value = rows
}
async function loadData() {
loading.value = true
try {
const res = await fetchCollectionProtocolList({
page: pagination.page,
pageSize: pagination.pageSize,
keyword: searchForm.keyword || undefined,
protocolStatus: searchForm.protocolStatus || undefined
})
tableData.value = res.list || []
pagination.total = res.total ?? 0
} finally {
loading.value = false
}
}
function handleSearch() {
pagination.page = 1
loadData()
}
function handleReset() {
searchForm.keyword = ''
searchForm.protocolStatus = ''
pagination.page = 1
loadData()
}
/* ====== 查看弹窗 ====== */
const viewVisible = ref(false)
const viewProtocolId = ref<string | null>(null)
const viewRow = ref<CollectionProtocolRow | null>(null)
function handleView(row: CollectionProtocolRow) {
viewProtocolId.value = String(row.id)
viewRow.value = row
viewVisible.value = true
}
/* ====== 新增/编辑弹窗 ====== */
const formDialogVisible = ref(false)
const formDialogEditId = ref<string | null>(null)
const formDialogRow = ref<CollectionProtocolRow | null>(null)
function handleAdd() {
formDialogEditId.value = null
formDialogRow.value = null
formDialogVisible.value = true
}
function handleEdit(row: CollectionProtocolRow) {
formDialogEditId.value = row.id
formDialogRow.value = row
formDialogVisible.value = true
}
function onFormSaved() {
loadData()
}
/* ====== 删除 ====== */
function handleDelete(row: CollectionProtocolRow) {
ElMessageBox.confirm(`确认删除协议号「${row.protocolNo}」?`, '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
await fetchDeleteCollectionProtocol(String(row.id))
loadData()
})
.catch(() => {})
}
async function handleBatchDelete() {
if (!selectedRows.value.length) return
await ElMessageBox.confirm(`确认删除选中的 ${selectedRows.value.length} 条记录?`, '批量删除', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
const rows = [...selectedRows.value]
await withFullscreenLoading(async () => {
for (const row of rows) {
await fetchDeleteCollectionProtocol(String(row.id))
}
ElMessage.success('批量删除成功')
selectedRows.value = []
loadData()
}, fullscreenLoadingText.batchDelete)
}
onMounted(() => {
loadData()
})
</script>