feat(web-admin): customer-service toolbar and Excel-aligned wide list columns.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-10-13 11:02:11 +08:00
1 parent 1c225ec89d
commit 8cebb8e0b8
1 file changed
+231 -38
@@ -127,6 +127,42 @@
<el-icon><Collection /></el-icon>
登记保险
</el-button>
<el-button
v-if="isCellStorage"
class="btn-ghost"
:disabled="!selectedRows.length"
@click="openQuickRegister('sms')"
>
<el-icon><ChatDotRound /></el-icon>
登记短信
</el-button>
<el-button
v-if="isCellStorage"
class="btn-ghost"
:disabled="!selectedRows.length"
@click="openQuickRegister('followup')"
>
<el-icon><Phone /></el-icon>
登记回访
</el-button>
<el-button
v-if="isCellStorage"
class="btn-ghost"
:disabled="!selectedRows.length"
@click="openQuickRegister('fulfillment')"
>
<el-icon><Location /></el-icon>
登记履约
</el-button>
<el-button
v-if="isCellStorage"
class="btn-ghost"
:disabled="!selectedRows.length"
@click="openQuickRegister('all')"
>
<el-icon><Files /></el-icon>
登记全部
</el-button>
</div>
</div>
@@ -141,7 +177,7 @@
@selection-change="handleSelectionChange"
@row-dblclick="handleView"
>
<el-table-column type="selection" min-width="55" align="center" header-align="center" />
<el-table-column type="selection" min-width="55" align="center" header-align="center" fixed />
<el-table-column
type="index"
label="序号"
@@ -150,22 +186,24 @@
header-align="center"
:index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1"
/>
<el-table-column label="协议状态" min-width="100" align="center" header-align="center">
<!-- 细胞存储:对齐 Excel 客户服务宽表 -->
<template v-if="isCellStorage">
<el-table-column prop="labStorageCode" label="实验室流转编码" min-width="140" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.labStorageCode || '—' }}</template>
</el-table-column>
<el-table-column label="储存状态" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="statusTagType(row)" size="small">{{ statusLabel(row) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="expectedDeliveryDate" label="预产期" min-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="newbornName"
label="新生儿姓名"
min-width="110"
align="center"
header-align="center"
show-overflow-tooltip
/>
<el-table-column prop="sampleCode" label="样本编码" min-width="160" align="center" header-align="center">
<el-table-column prop="smsSendDate" label="发送日期" min-width="120" align="center">
<template #default="{ row }">{{ row.smsSendDate || '—' }}</template>
</el-table-column>
<el-table-column prop="smsSendStatus" label="短信发送情况" min-width="110" align="center">
<template #default="{ row }">{{ row.smsSendStatus || '—' }}</template>
</el-table-column>
<el-table-column prop="sampleCode" label="样本编码" min-width="160" align="center">
<template #default="{ row }">
<SampleCodeWithSpecialDisplay
class="sample-code-col"
@@ -177,64 +215,201 @@
/>
</template>
</el-table-column>
<el-table-column prop="labStorageCode" label="实验室入库编码" min-width="150" align="center" header-align="center">
<template #default="{ row }">{{ row.labStorageCode || '—' }}</template>
<el-table-column prop="motherName" label="母亲姓名" min-width="100" align="center" />
<el-table-column prop="motherPhone" label="母亲电话" min-width="120" align="center">
<template #default="{ row }">{{ row.motherPhone || '—' }}</template>
</el-table-column>
<el-table-column prop="sampleTypeName" label="样本类型" min-width="110" align="center" header-align="center" />
<el-table-column label="采集" min-width="90" align="center" header-align="center">
<el-table-column prop="motherIdCard" label="母亲身份证" min-width="160" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.motherIdCard || '—' }}</template>
</el-table-column>
<el-table-column prop="fatherName" label="父亲姓名" min-width="100" align="center">
<template #default="{ row }">{{ row.fatherName || '—' }}</template>
</el-table-column>
<el-table-column prop="fatherPhone" label="父亲电话" min-width="120" align="center">
<template #default="{ row }">{{ row.fatherPhone || '—' }}</template>
</el-table-column>
<el-table-column prop="fatherIdCard" label="父亲身份证" min-width="160" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.fatherIdCard || '—' }}</template>
</el-table-column>
<el-table-column prop="microbeFollowupDate" label="微生物回访日期" min-width="130" align="center">
<template #default="{ row }">{{ row.microbeFollowupDate || '—' }}</template>
</el-table-column>
<el-table-column prop="microbeFollowupStatus" label="微生物回访情况" min-width="120" align="center">
<template #default="{ row }">{{ row.microbeFollowupStatus || '—' }}</template>
</el-table-column>
<el-table-column prop="fullmoonFollowupDate" label="满月回访时间" min-width="120" align="center">
<template #default="{ row }">{{ row.fullmoonFollowupDate || '—' }}</template>
</el-table-column>
<el-table-column prop="fullmoonFollowupStatus" label="满月回访情况" min-width="120" align="center">
<template #default="{ row }">{{ row.fullmoonFollowupStatus || '—' }}</template>
</el-table-column>
<el-table-column prop="householdRegistered" label="是否上户口" min-width="100" align="center">
<template #default="{ row }">{{ row.householdRegistered || '—' }}</template>
</el-table-column>
<el-table-column prop="newbornName" label="宝宝姓名" min-width="100" align="center" show-overflow-tooltip />
<el-table-column prop="newbornIdCard" label="宝宝身份证" min-width="160" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.newbornIdCard || '—' }}</template>
</el-table-column>
<el-table-column prop="newbornSex" label="性别" min-width="70" align="center">
<template #default="{ row }">{{ sexLabel(row.newbornSex) }}</template>
</el-table-column>
<el-table-column prop="newbornDeliveryTime" label="分娩时间" min-width="160" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.newbornDeliveryTime || '—' }}</template>
</el-table-column>
<el-table-column prop="purchaseInsuranceTime" label="购买保险时间" min-width="160" align="center">
<template #default="{ row }">{{ row.purchaseInsuranceTime || '—' }}</template>
</el-table-column>
<el-table-column prop="policySendTime" label="保单发送时间" min-width="160" align="center">
<template #default="{ row }">{{ row.policySendTime || '—' }}</template>
</el-table-column>
<el-table-column prop="einvoiceSendTime" label="电子发票发送时间" min-width="160" align="center">
<template #default="{ row }">{{ row.einvoiceSendTime || '—' }}</template>
</el-table-column>
<el-table-column prop="mailCertTime" label="邮寄储存证时间" min-width="160" align="center">
<template #default="{ row }">{{ row.mailCertTime || '—' }}</template>
</el-table-column>
<el-table-column prop="effectiveAddress" label="有效地址" min-width="180" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.effectiveAddress || '—' }}</template>
</el-table-column>
<el-table-column prop="marketSpecialistName" label="市场专员" min-width="100" align="center">
<template #default="{ row }">{{ row.marketSpecialistName || '—' }}</template>
</el-table-column>
<el-table-column prop="payModeLabel" label="缴费方式" min-width="90" align="center">
<template #default="{ row }">{{ row.payModeLabel || '—' }}</template>
</el-table-column>
<el-table-column prop="protocolRemark" label="备注" min-width="140" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.protocolRemark || '—' }}</template>
</el-table-column>
<el-table-column label="协议书" min-width="80" align="center">
<template #default="{ row }">
<el-tag :type="row.protocolAttachmentPresent ? 'success' : 'info'" size="small">
{{ row.protocolAttachmentPresent ? '有' : '无' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="保险单" min-width="80" align="center">
<template #default="{ row }">
<el-tag :type="row.insuranceDocPresent ? 'success' : 'info'" size="small">
{{ row.insuranceDocPresent ? '有' : '无' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="知情同意书" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.informedConsentPresent ? 'success' : 'info'" size="small">
{{ row.informedConsentPresent ? '有' : '无' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="健康调查表" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.healthSurveyPresent ? 'success' : 'info'" size="small">
{{ row.healthSurveyPresent ? '有' : '无' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="expectedDeliveryDate" label="预产期" min-width="120" align="center" />
<el-table-column prop="sampleTypeName" label="样本类型" min-width="110" align="center" />
<el-table-column label="采集" min-width="90" align="center">
<template #default="{ row }">
<el-tag :type="sampleCollectionFlagTagType(String(row.collectionFlag || ''))" size="small">
{{ row.collectionFlagLabel || sampleCollectionFlagLabel(String(row.collectionFlag || '')) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="接收" min-width="90" align="center" header-align="center">
<el-table-column label="接收" min-width="90" align="center">
<template #default="{ row }">
<el-tag :type="sampleReceptionFlagTagType(String(row.receptionFlag || ''))" size="small">
{{ row.receptionFlagLabel || sampleReceptionFlagLabel(String(row.receptionFlag || '')) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="质检" min-width="90" align="center" header-align="center">
<el-table-column label="质检" min-width="90" align="center">
<template #default="{ row }">
<el-tag :type="sampleQcFlagTagType(String(row.qcFlag || ''))" size="small">
{{ row.qcFlagLabel || sampleQcFlagLabel(String(row.qcFlag || '')) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="入库" min-width="100" align="center" header-align="center">
<el-table-column label="入库" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="sampleStorageFlagTagType(String(row.storageFlag || ''))" size="small">
{{ row.storageFlagLabel || sampleStorageFlagLabel(String(row.storageFlag || '')) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="isCellStorage"
label="储存证"
min-width="90"
align="center"
header-align="center"
>
<el-table-column label="储存证" min-width="90" align="center">
<template #default="{ row }">
<el-tag :type="handleDoneFlagTagType(row.storageCertHandled ? '1' : '0')" size="small">
{{ handleDoneFlagLabel(row.storageCertHandled ? '1' : '0') }}
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="isCellStorage"
label="保险"
min-width="90"
align="center"
header-align="center"
>
<el-table-column label="保险" min-width="90" align="center">
<template #default="{ row }">
<el-tag :type="handleDoneFlagTagType(row.insuranceHandled ? '1' : '0')" size="small">
{{ handleDoneFlagLabel(row.insuranceHandled ? '1' : '0') }}
</el-tag>
</template>
</el-table-column>
</template>
<!-- 科研捐赠:保持精简列 -->
<template v-else>
<el-table-column label="捐赠状态" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="statusTagType(row)" size="small">{{ statusLabel(row) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="expectedDeliveryDate" label="预产期" min-width="120" align="center" />
<el-table-column prop="motherName" label="母亲姓名" min-width="100" align="center" />
<el-table-column prop="newbornName" label="新生儿姓名" min-width="110" align="center" show-overflow-tooltip />
<el-table-column prop="sampleCode" label="样本编码" min-width="160" align="center">
<template #default="{ row }">
<SampleCodeWithSpecialDisplay
class="sample-code-col"
:sample-code="row.sampleCode"
:is-special="!!row.isSpecial"
:special-remark="row.specialRemark"
layout="block"
monospace
/>
</template>
</el-table-column>
<el-table-column prop="labStorageCode" label="实验室入库编码" min-width="150" align="center">
<template #default="{ row }">{{ row.labStorageCode || '—' }}</template>
</el-table-column>
<el-table-column prop="sampleTypeName" label="样本类型" min-width="110" align="center" />
<el-table-column label="采集" min-width="90" align="center">
<template #default="{ row }">
<el-tag :type="sampleCollectionFlagTagType(String(row.collectionFlag || ''))" size="small">
{{ row.collectionFlagLabel || sampleCollectionFlagLabel(String(row.collectionFlag || '')) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="接收" min-width="90" align="center">
<template #default="{ row }">
<el-tag :type="sampleReceptionFlagTagType(String(row.receptionFlag || ''))" size="small">
{{ row.receptionFlagLabel || sampleReceptionFlagLabel(String(row.receptionFlag || '')) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="质检" min-width="90" align="center">
<template #default="{ row }">
<el-tag :type="sampleQcFlagTagType(String(row.qcFlag || ''))" size="small">
{{ row.qcFlagLabel || sampleQcFlagLabel(String(row.qcFlag || '')) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="入库" min-width="100" align="center">
<template #default="{ row }">
<el-tag :type="sampleStorageFlagTagType(String(row.storageFlag || ''))" size="small">
{{ row.storageFlagLabel || sampleStorageFlagLabel(String(row.storageFlag || '')) }}
</el-tag>
</template>
</el-table-column>
</template>
<el-table-column label="操作" min-width="280" fixed="right" align="center" header-align="center">
<template #default="{ row }">
<el-button class="btn-op-item primary" @click="handleView(row)">
@@ -297,20 +472,31 @@
</template>
<script setup lang="ts">
import { Box, Collection, Document, RefreshLeft, Search, Ticket, View } from '@element-plus/icons-vue'
import {
Box,
ChatDotRound,
Collection,
Document,
Files,
Location,
Phone,
RefreshLeft,
Search,
Ticket,
View
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import StorageCertQcDialog from '@/components/business/storage-cert-qc-dialog/index.vue'
import { supportsStorageCertQc } from '@/utils/storage-cert-qc-fields'
import { fetchProtocolSampleCollectionList } from '@/api/protocol-sample-collection'
import { fetchResearchDonationSampleCollectionList } from '@/api/research-donation-sample-collection'
import type { QuickRegisterKind } from '@/api/sample-info-handle'
import type { CollectionProtocolRow } from '@/api/collection-protocol'
import type { ResearchDonationRow } from '@/api/research-donation'
import ProtocolViewDialog from '@/views/cell-storage/protocol/ProtocolViewDialog.vue'
import DonationViewDialog from '@/views/research-donation/list/DonationViewDialog.vue'
import SampleCodeWithSpecialDisplay from '@/components/business/sample-code-with-special-display/index.vue'
import SampleInfoQuickRegisterDialog, {
type QuickRegisterKind
} from './SampleInfoQuickRegisterDialog.vue'
import SampleInfoQuickRegisterDialog from './SampleInfoQuickRegisterDialog.vue'
import { useMenuPerm } from '@/hooks/core/useMenuPerm'
import {
donationStatusDisplayLabel,
@@ -383,6 +569,13 @@
const storageCertQcSampleCode = ref('')
const storageCertQcSampleTypeName = ref('')
function sexLabel(sex: unknown) {
const s = String(sex || '').trim()
if (s === '1' || s === '男') return '男'
if (s === '2' || s === '女') return '女'
return s || '—'
}
function openStorageCertQcView(row: Record<string, unknown>) {
storageCertQcSampleCode.value = String(row.sampleCode || '')
storageCertQcSampleTypeName.value = String(row.sampleTypeName || '')