提交
This commit is contained in:
1 parent
2e66e03792
commit
09afdb1d65
93 files changed
+22307
-15075
No files matched your search
@@ -155,6 +155,21 @@
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="expectedDeliveryDate"
|
||||
label="预产期"
|
||||
min-width="120"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sampleCollectSummary"
|
||||
label="是否已采集"
|
||||
min-width="160"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="registerDate"
|
||||
label="登记日期"
|
||||
@@ -219,6 +234,22 @@
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sampleTypeNames"
|
||||
label="样本类型"
|
||||
min-width="140"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sampleCodes"
|
||||
label="样本编码"
|
||||
min-width="160"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="regionName"
|
||||
label="采集地区"
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
<!-- 样本信息管理 · 样本质检信息 Tab -->
|
||||
<template>
|
||||
<div class="sample-qc-info-tab">
|
||||
<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.qcStatus"
|
||||
placeholder="全部"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option label="待质检" value="dzj" />
|
||||
<el-option label="质检中" value="zjz" />
|
||||
<el-option label="通过" value="tg" />
|
||||
<el-option label="不通过" value="btg" />
|
||||
<el-option label="已作废" value="yzf" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="通知状态">
|
||||
<el-select
|
||||
v-model="searchForm.smsNotified"
|
||||
placeholder="全部"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option label="已通知" value="1" />
|
||||
<el-option label="未通知" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="样本时间">
|
||||
<el-date-picker
|
||||
v-model="sampleTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint"
|
||||
>展示全部协议样本(每个样本一条);支持按协议号、姓名、样本编码检索;默认展示近 30 天内创建的样本。</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-body list-wrap">
|
||||
<el-table
|
||||
class="list-table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
row-key="id"
|
||||
@row-dblclick="handleView"
|
||||
>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
min-width="68"
|
||||
align="center"
|
||||
header-align="center"
|
||||
:index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="protocolNo"
|
||||
label="协议号"
|
||||
min-width="140"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="protocolStatus"
|
||||
label="协议状态"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="protocolStatusTagType(String(row.protocolStatus || ''))"
|
||||
size="small"
|
||||
>{{ protocolStatusLabel(String(row.protocolStatus || '')) }}</el-tag
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<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="130"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sampleTypeName"
|
||||
label="样本类型"
|
||||
min-width="110"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="qcCompleteTime"
|
||||
label="质检完成时间"
|
||||
min-width="170"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="qcStatusLabel"
|
||||
label="质检状态"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="qcStatusTagType(String(row.qcStatus || ''))" size="small">
|
||||
{{ row.qcStatusLabel || '待质检' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="smsNotified"
|
||||
label="通知状态"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.smsNotified == 1 ? 'success' : 'info'" size="small">
|
||||
{{ row.smsNotified == 1 ? '已通知' : '未通知' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
min-width="360"
|
||||
fixed="right"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button class="btn-op-item primary" @click="handleView(row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-button class="btn-op-item" @click="handleExtractSms(row)">
|
||||
<el-icon><ChatDotRound /></el-icon>提取短信
|
||||
</el-button>
|
||||
<el-button class="btn-op-item" @click="handleToggleNotified(row)">
|
||||
<el-icon><Bell /></el-icon>{{ row.smsNotified == 1 ? '标记未通知' : '标记已通知' }}
|
||||
</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>
|
||||
|
||||
<ProtocolViewDialog
|
||||
v-model="viewVisible"
|
||||
:protocol-id="viewProtocolId"
|
||||
:list-row="viewRow"
|
||||
show-audit-history
|
||||
show-storage-cert
|
||||
show-fullmoon-insurance
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Search, RefreshLeft, View, ChatDotRound, Bell } from '@element-plus/icons-vue'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import ProtocolViewDialog from '../protocol/ProtocolViewDialog.vue'
|
||||
import {
|
||||
fetchQcSmsList,
|
||||
fetchToggleQcSmsNotified,
|
||||
fetchGenerateQcSms
|
||||
} from '@/api/qc-sms-notification'
|
||||
import { type CollectionProtocolRow } from '@/api/collection-protocol'
|
||||
import {
|
||||
protocolStatusLabel,
|
||||
protocolStatusTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
|
||||
defineOptions({ name: 'CellStorageSampleQcInfoTab' })
|
||||
|
||||
function qcStatusTagType(status: string) {
|
||||
const map: Record<string, 'success' | 'warning' | 'danger' | 'info'> = {
|
||||
dzj: 'info',
|
||||
zjz: 'warning',
|
||||
tg: 'success',
|
||||
btg: 'danger',
|
||||
yzf: 'danger'
|
||||
}
|
||||
return map[status] || 'info'
|
||||
}
|
||||
|
||||
function isQcCompleted(row: Record<string, unknown>) {
|
||||
return row.qcStatus === 'tg' || row.qcStatus === 'btg'
|
||||
}
|
||||
|
||||
function formatLocalDate(d: Date): string {
|
||||
const y = d.getFullYear()
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
return `${y}-${m}-${day}`
|
||||
}
|
||||
|
||||
function getDefaultSampleTimeRange(): [string, string] {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({ keyword: '', qcStatus: '', smsNotified: '' })
|
||||
const sampleTimeRange = ref<[string, string] | null>(getDefaultSampleTimeRange())
|
||||
const tableData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
|
||||
|
||||
const viewVisible = ref(false)
|
||||
const viewProtocolId = ref<string | null>(null)
|
||||
const viewRow = ref<CollectionProtocolRow | null>(null)
|
||||
|
||||
const { copy } = useClipboard()
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await fetchQcSmsList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
qcStatus: searchForm.qcStatus || undefined,
|
||||
smsNotified: searchForm.smsNotified || undefined,
|
||||
qcCompleteTimeStart: sampleTimeRange.value?.[0] || undefined,
|
||||
qcCompleteTimeEnd: sampleTimeRange.value?.[1] || undefined
|
||||
})
|
||||
const res = (result as any) || {}
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total || 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
Object.assign(searchForm, { keyword: '', qcStatus: '', smsNotified: '' })
|
||||
sampleTimeRange.value = getDefaultSampleTimeRange()
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
function handleView(row: Record<string, unknown>) {
|
||||
const pid = String(row.collectionProtocolId || row.protocolId || '')
|
||||
if (!pid) {
|
||||
ElMessage.warning('缺少关联协议单,无法查看')
|
||||
return
|
||||
}
|
||||
viewProtocolId.value = pid
|
||||
viewRow.value = {
|
||||
id: pid,
|
||||
protocolNo: row.protocolNo,
|
||||
motherName: row.motherName,
|
||||
newbornName: row.newbornName
|
||||
}
|
||||
viewVisible.value = true
|
||||
}
|
||||
|
||||
async function handleExtractSms(row: any) {
|
||||
try {
|
||||
const result = await fetchGenerateQcSms(row.id, {
|
||||
qcWorkOrderId: row.qcWorkOrderId,
|
||||
protocolSampleId: row.protocolSampleId
|
||||
})
|
||||
const content = (result as any)?.smsContent || ''
|
||||
if (!content || content.startsWith('暂无短信内容')) {
|
||||
ElMessage.warning(content || '短信内容为空')
|
||||
return
|
||||
}
|
||||
await copy(content)
|
||||
ElMessage.success('短信内容已复制到剪贴板')
|
||||
} catch {
|
||||
ElMessage.error('提取短信失败')
|
||||
}
|
||||
}
|
||||
|
||||
async function handleToggleNotified(row: any) {
|
||||
if (!isQcCompleted(row)) {
|
||||
ElMessage.warning('质检尚未完成,暂不可标记通知状态')
|
||||
return
|
||||
}
|
||||
const newVal = row.smsNotified == 1 ? 0 : 1
|
||||
try {
|
||||
await fetchToggleQcSmsNotified(row.id, {
|
||||
smsNotified: newVal,
|
||||
qcWorkOrderId: row.qcWorkOrderId,
|
||||
protocolSampleId: row.protocolSampleId
|
||||
})
|
||||
ElMessage.success(newVal === 1 ? '已标记为已通知' : '已标记为未通知')
|
||||
loadData()
|
||||
} catch {
|
||||
ElMessage.error('操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
watchDebounced(
|
||||
[searchForm, sampleTimeRange],
|
||||
() => {
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
},
|
||||
{ debounce: 300, deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- 采集协议单管理 · 样本接收信息 Tab -->
|
||||
<!-- 样本信息管理 · 样本接收信息 Tab -->
|
||||
<template>
|
||||
<div class="sample-reception-info-tab">
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- 采集协议单管理 · 样本入库信息 Tab -->
|
||||
<!-- 样本信息管理 · 样本入库信息 Tab -->
|
||||
<template>
|
||||
<div class="storage-entry-info-tab">
|
||||
<div class="filter-block">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- 采集协议单管理(协议单 / 缴费 / 样本接收 / 入库 / 储存证 / 满月待办) -->
|
||||
<!-- 采集协议单管理(协议单 / 缴费 / 储存证 / 满月待办) -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<section class="panel">
|
||||
@@ -29,8 +29,6 @@
|
||||
|
||||
<ProtocolAuditTab v-if="activeTab === 'protocol'" />
|
||||
<PaymentInfoTab v-else-if="activeTab === 'payment-info'" />
|
||||
<SampleReceptionInfoTab v-else-if="activeTab === 'sample-reception'" />
|
||||
<StorageEntryInfoTab v-else-if="activeTab === 'storage-entry'" />
|
||||
<StorageCertTab v-else-if="activeTab === 'storage-cert'" />
|
||||
<FullmoonTodoTab v-else-if="activeTab === 'fullmoon-todo'" />
|
||||
</section>
|
||||
@@ -39,24 +37,17 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Component } from 'vue'
|
||||
import { Document, Wallet, Box, FolderOpened, Medal, Calendar } from '@element-plus/icons-vue'
|
||||
import { Document, Wallet, Medal, Calendar } from '@element-plus/icons-vue'
|
||||
import ProtocolAuditTab from './ProtocolAuditTab.vue'
|
||||
import PaymentInfoTab from './PaymentInfoTab.vue'
|
||||
import SampleReceptionInfoTab from './SampleReceptionInfoTab.vue'
|
||||
import StorageEntryInfoTab from './StorageEntryInfoTab.vue'
|
||||
import StorageCertTab from './StorageCertTab.vue'
|
||||
import FullmoonTodoTab from './FullmoonTodoTab.vue'
|
||||
|
||||
defineOptions({ name: 'CellStorageProtocolAudit' })
|
||||
|
||||
const VALID_TABS = [
|
||||
'protocol',
|
||||
'payment-info',
|
||||
'sample-reception',
|
||||
'storage-entry',
|
||||
'storage-cert',
|
||||
'fullmoon-todo'
|
||||
] as const
|
||||
const LEGACY_SAMPLE_TABS = ['sample-reception', 'storage-entry'] as const
|
||||
|
||||
const VALID_TABS = ['protocol', 'payment-info', 'storage-cert', 'fullmoon-todo'] as const
|
||||
|
||||
type EntityTabKey = (typeof VALID_TABS)[number]
|
||||
|
||||
@@ -78,18 +69,6 @@
|
||||
desc: '缴费计划与到账查询',
|
||||
icon: Wallet
|
||||
},
|
||||
{
|
||||
key: 'sample-reception',
|
||||
title: '样本接收信息',
|
||||
desc: '接收结论与短信通知',
|
||||
icon: Box
|
||||
},
|
||||
{
|
||||
key: 'storage-entry',
|
||||
title: '样本入库信息',
|
||||
desc: '样本入库记录查询',
|
||||
icon: FolderOpened
|
||||
},
|
||||
{
|
||||
key: 'storage-cert',
|
||||
title: '储存证管理',
|
||||
@@ -105,10 +84,18 @@
|
||||
]
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const activeTab = ref<EntityTabKey>('protocol')
|
||||
|
||||
onMounted(() => {
|
||||
const tab = String(route.query.tab || '')
|
||||
if (LEGACY_SAMPLE_TABS.includes(tab as (typeof LEGACY_SAMPLE_TABS)[number])) {
|
||||
router.replace({
|
||||
name: 'CellStorageSampleInfo',
|
||||
query: { ...route.query, tab }
|
||||
})
|
||||
return
|
||||
}
|
||||
if (VALID_TABS.includes(tab as EntityTabKey)) {
|
||||
activeTab.value = tab as EntityTabKey
|
||||
}
|
||||
|
||||
@@ -285,7 +285,17 @@
|
||||
<el-radio label="0">女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="新生儿分娩时间" class="form-col-span-2">
|
||||
<el-form-item label="预产期">
|
||||
<el-date-picker
|
||||
v-model="formData.expectedDeliveryDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择预产期"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="新生儿分娩时间">
|
||||
<el-date-picker
|
||||
v-model="formData.newbornDeliveryTime"
|
||||
type="datetime"
|
||||
@@ -469,11 +479,11 @@
|
||||
:disabled="!selectedSamples.length"
|
||||
@click="openBatchTransportDialog"
|
||||
>
|
||||
应用到选中样本
|
||||
批量配置运输信息
|
||||
</el-button>
|
||||
</div>
|
||||
<p v-if="formData.samples.length" class="sample-transport-hint"
|
||||
>勾选样本后,点击「应用到选中样本」可批量填写运输信息。点击展开可编辑单个运输信息。</p
|
||||
>勾选样本后,点击「批量配置运输信息」可统一填写运输信息。点击展开可编辑单个运输信息。</p
|
||||
>
|
||||
|
||||
<!-- Sample Cards -->
|
||||
@@ -1162,7 +1172,10 @@
|
||||
} from '@/api/admin'
|
||||
import { fetchEthnicList, type EthnicOption } from '@/api/ethnic'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { syncFqPaymentDetailRowCount } from '@/utils/protocol-payment-installment'
|
||||
import {
|
||||
calcFqInstallmentDueDate,
|
||||
syncFqPaymentDetailRowCount
|
||||
} from '@/utils/protocol-payment-installment'
|
||||
import AmountInput from '@/components/common/amount-input/index.vue'
|
||||
import { formatMoneyDisplay } from '@/utils/money-format'
|
||||
import {
|
||||
@@ -1434,6 +1447,7 @@
|
||||
fatherIdCard: '',
|
||||
newbornName: '',
|
||||
newbornIdCard: '',
|
||||
expectedDeliveryDate: '',
|
||||
newbornDeliveryTime: '',
|
||||
newbornSex: '',
|
||||
deliveryMode: '',
|
||||
@@ -1487,6 +1501,7 @@
|
||||
fatherIdCard: '',
|
||||
newbornName: '',
|
||||
newbornIdCard: '',
|
||||
expectedDeliveryDate: '',
|
||||
newbornDeliveryTime: '',
|
||||
newbornSex: '',
|
||||
deliveryMode: '',
|
||||
@@ -1634,17 +1649,46 @@
|
||||
syncPaymentDueAmounts()
|
||||
}
|
||||
|
||||
/** 日期加 N 个月,返回 YYYYMMDD 格式(入参支持 YYYYMMDD 或 YYYY-MM-DD) */
|
||||
function addMonths(dateStr: string, months: number): string {
|
||||
const compact = dateStr.replace(/-/g, '')
|
||||
const y = parseInt(compact.slice(0, 4), 10)
|
||||
const m = parseInt(compact.slice(4, 6), 10) - 1
|
||||
const d = parseInt(compact.slice(6, 8), 10)
|
||||
const date = new Date(y, m + months, d)
|
||||
const yy = date.getFullYear()
|
||||
const mm = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const dd = String(date.getDate()).padStart(2, '0')
|
||||
return `${yy}${mm}${dd}`
|
||||
/** 分期开始时间默认值:新生儿分娩时间 > 预产期 > 当前日期(YYYYMMDD) */
|
||||
function defaultInstallmentStartDateYmd(): string {
|
||||
const deliveryYmd = datetimeToYmd(formData.newbornDeliveryTime)
|
||||
if (deliveryYmd) return deliveryYmd
|
||||
const expectedYmd = datetimeToYmd(formData.expectedDeliveryDate)
|
||||
if (expectedYmd) return expectedYmd
|
||||
const now = new Date()
|
||||
const pad = (n: number) => String(n).padStart(2, '0')
|
||||
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}`
|
||||
}
|
||||
|
||||
function datetimeToYmd(val: string): string {
|
||||
const compact = String(val || '')
|
||||
.trim()
|
||||
.replace(/[-:\sT]/g, '')
|
||||
.slice(0, 8)
|
||||
return /^\d{8}$/.test(compact) ? compact : ''
|
||||
}
|
||||
|
||||
function isFqNumericFieldEmpty(val: unknown): boolean {
|
||||
if (val == null || val === '') return true
|
||||
const n = Number(val)
|
||||
return !Number.isFinite(n) || n < 1
|
||||
}
|
||||
|
||||
/**
|
||||
* 分期默认:期数、每期间隔均为 6;开始时间为空时按分娩/预产期/今日填充。
|
||||
* resetCountInterval:切换到分期时强制重置期数与间隔(与新增一致)。
|
||||
*/
|
||||
function applyFqPaymentDefaults(options?: { resetCountInterval?: boolean }) {
|
||||
const reset = options?.resetCountInterval ?? false
|
||||
if (reset || isFqNumericFieldEmpty(formData.installmentCount)) {
|
||||
formData.installmentCount = 6
|
||||
}
|
||||
if (reset || isFqNumericFieldEmpty(formData.installmentIntervalMonths)) {
|
||||
formData.installmentIntervalMonths = 6
|
||||
}
|
||||
if (!formData.installmentStartDate) {
|
||||
formData.installmentStartDate = defaultInstallmentStartDateYmd()
|
||||
}
|
||||
}
|
||||
|
||||
function toIntOrUndefined(val: unknown): number | undefined {
|
||||
@@ -1676,7 +1720,7 @@
|
||||
syncPaymentDueAmounts()
|
||||
formData.paymentDetails.forEach((d, i) => {
|
||||
d.installmentNo = i + 1
|
||||
d.installmentDueDate = addMonths(startDate, i * interval)
|
||||
d.installmentDueDate = calcFqInstallmentDueDate(startDate, i, interval)
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -1691,7 +1735,7 @@
|
||||
transferTime: '',
|
||||
payStatus: 'dfj',
|
||||
installmentNo: i + 1,
|
||||
installmentDueDate: addMonths(startDate, i * interval),
|
||||
installmentDueDate: calcFqInstallmentDueDate(startDate, i, interval),
|
||||
attachments: [] as Array<{
|
||||
id?: string
|
||||
fileName: string
|
||||
@@ -1710,6 +1754,7 @@
|
||||
/** 缴费模式切换回调 */
|
||||
function onPayModeChange(val: string) {
|
||||
if (val === 'fq') {
|
||||
applyFqPaymentDefaults({ resetCountInterval: true })
|
||||
tryGenerateInstallmentDetails()
|
||||
} else {
|
||||
// 趸交模式:将趸交截止时间同步到所有明细的应缴费时间
|
||||
@@ -1798,6 +1843,7 @@
|
||||
formData.fatherIdCard = String(pc.fatherIdCard || '')
|
||||
formData.newbornName = String(pc.newbornName || '')
|
||||
formData.newbornIdCard = String(pc.newbornIdCard || '')
|
||||
formData.expectedDeliveryDate = String(pc.expectedDeliveryDate || '')
|
||||
formData.newbornDeliveryTime = String(pc.newbornDeliveryTime || '')
|
||||
formData.newbornSex = String(pc.newbornSex ?? '')
|
||||
formData.deliveryMode = String(pc.deliveryMode || '')
|
||||
@@ -1831,6 +1877,9 @@
|
||||
formData.installmentCount = pay.installmentCount ?? null
|
||||
formData.installmentIntervalMonths = pay.installmentIntervalMonths ?? null
|
||||
formData.installmentStartDate = String(pay.installmentStartDate || '')
|
||||
if (formData.payMode === 'fq') {
|
||||
applyFqPaymentDefaults()
|
||||
}
|
||||
}
|
||||
|
||||
const pd = bundle.paymentDetails as Array<Record<string, any>> | null
|
||||
@@ -1971,6 +2020,7 @@
|
||||
fatherIdCard: formData.fatherIdCard || undefined,
|
||||
newbornName: formData.newbornName || undefined,
|
||||
newbornIdCard: formData.newbornIdCard || undefined,
|
||||
expectedDeliveryDate: formData.expectedDeliveryDate || undefined,
|
||||
newbornDeliveryTime: formData.newbornDeliveryTime || undefined,
|
||||
newbornSex: formData.newbornSex || undefined,
|
||||
deliveryMode: formData.deliveryMode || undefined,
|
||||
@@ -2531,8 +2581,8 @@
|
||||
sc: Api.BizSampleCode.SampleCodeItem,
|
||||
row: Record<string, any>
|
||||
) {
|
||||
if (!sc.usedInProtocol) return false
|
||||
return String(row.sampleCodeId || '') !== sc.id
|
||||
if (sc.usedInProtocol && String(row.sampleCodeId || '') !== sc.id) return true
|
||||
return formData.samples.some((s) => s !== row && String(s.sampleCodeId || '') === sc.id)
|
||||
}
|
||||
|
||||
function onSampleCodeChange(row: Record<string, any>) {
|
||||
|
||||
@@ -352,6 +352,12 @@
|
||||
><div class="data-label">新生儿身份证</div
|
||||
><div class="data-value">{{ dash(partyCustomer?.newbornIdCard) }}</div></div
|
||||
>
|
||||
<div class="data-item"
|
||||
><div class="data-label">预产期</div
|
||||
><div class="data-value">{{
|
||||
dash(partyCustomer?.expectedDeliveryDate)
|
||||
}}</div></div
|
||||
>
|
||||
<div class="data-item"
|
||||
><div class="data-label">新生儿分娩时间</div
|
||||
><div class="data-value">{{
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
<!-- 样本信息管理(样本接收 / 样本质检 / 样本入库) -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<section class="panel">
|
||||
<div
|
||||
class="panel-entity-switch panel-entity-switch--triple"
|
||||
role="tablist"
|
||||
aria-label="视图类型"
|
||||
>
|
||||
<button
|
||||
v-for="item in entityTabs"
|
||||
:key="item.key"
|
||||
type="button"
|
||||
class="entity-switch-card"
|
||||
:class="{ 'is-active': activeTab === item.key }"
|
||||
role="tab"
|
||||
:aria-selected="activeTab === item.key"
|
||||
@click="activeTab = item.key"
|
||||
>
|
||||
<span class="entity-switch-card__icon"
|
||||
><el-icon><component :is="item.icon" /></el-icon
|
||||
></span>
|
||||
<span class="entity-switch-card__main">
|
||||
<span class="entity-switch-card__title">{{ item.title }}</span>
|
||||
<span class="entity-switch-card__desc">{{ item.desc }}</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<SampleReceptionInfoTab v-if="activeTab === 'sample-reception'" />
|
||||
<SampleQcInfoTab v-else-if="activeTab === 'sample-qc'" />
|
||||
<StorageEntryInfoTab v-else-if="activeTab === 'storage-entry'" />
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Component } from 'vue'
|
||||
import { Box, DocumentChecked, FolderOpened } from '@element-plus/icons-vue'
|
||||
import SampleReceptionInfoTab from '../protocol-audit/SampleReceptionInfoTab.vue'
|
||||
import SampleQcInfoTab from '../protocol-audit/SampleQcInfoTab.vue'
|
||||
import StorageEntryInfoTab from '../protocol-audit/StorageEntryInfoTab.vue'
|
||||
|
||||
defineOptions({ name: 'CellStorageSampleInfo' })
|
||||
|
||||
const VALID_TABS = ['sample-reception', 'sample-qc', 'storage-entry'] as const
|
||||
|
||||
type EntityTabKey = (typeof VALID_TABS)[number]
|
||||
|
||||
const entityTabs: Array<{
|
||||
key: EntityTabKey
|
||||
title: string
|
||||
desc: string
|
||||
icon: Component
|
||||
}> = [
|
||||
{
|
||||
key: 'sample-reception',
|
||||
title: '样本接收信息',
|
||||
desc: '接收结论与短信通知',
|
||||
icon: Box
|
||||
},
|
||||
{
|
||||
key: 'sample-qc',
|
||||
title: '样本质检信息',
|
||||
desc: '质检结论与短信通知',
|
||||
icon: DocumentChecked
|
||||
},
|
||||
{
|
||||
key: 'storage-entry',
|
||||
title: '样本入库信息',
|
||||
desc: '样本入库记录查询',
|
||||
icon: FolderOpened
|
||||
}
|
||||
]
|
||||
|
||||
const route = useRoute()
|
||||
const activeTab = ref<EntityTabKey>('sample-reception')
|
||||
|
||||
onMounted(() => {
|
||||
const tab = String(route.query.tab || '')
|
||||
if (VALID_TABS.includes(tab as EntityTabKey)) {
|
||||
activeTab.value = tab as EntityTabKey
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.panel-entity-switch {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
padding: 16px 16px 12px;
|
||||
}
|
||||
|
||||
.panel-entity-switch--triple {
|
||||
flex-wrap: wrap;
|
||||
|
||||
.entity-switch-card {
|
||||
flex: 0 1 200px;
|
||||
min-width: 180px;
|
||||
max-width: 240px;
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.entity-switch-card__icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.entity-switch-card__title {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.entity-switch-card__desc {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
.entity-switch-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 14px 18px;
|
||||
border: 1px solid var(--mint-border, #d9e8e2);
|
||||
border-radius: 10px;
|
||||
background: var(--surface, #fff);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
background-color 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
|
||||
&:hover:not(.is-active) {
|
||||
border-color: #a7f3d0;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
border-color: var(--primary, #10b981);
|
||||
background: var(--primary-bg, #ecfdf5);
|
||||
box-shadow: 0 0 0 1px rgb(16 185 129 / 12%);
|
||||
}
|
||||
}
|
||||
|
||||
.entity-switch-card__icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 8px;
|
||||
background: #f1f5f9;
|
||||
color: #64748b;
|
||||
font-size: 20px;
|
||||
|
||||
.entity-switch-card.is-active & {
|
||||
background: #fff;
|
||||
color: var(--primary-dark, #059669);
|
||||
}
|
||||
}
|
||||
|
||||
.entity-switch-card__main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.entity-switch-card__title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text, #1e293b);
|
||||
line-height: 1.4;
|
||||
|
||||
.entity-switch-card.is-active & {
|
||||
color: var(--primary-dark, #059669);
|
||||
}
|
||||
}
|
||||
|
||||
.entity-switch-card__desc {
|
||||
font-size: 12px;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
line-height: 1.4;
|
||||
}
|
||||
</style>
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- 旧「样本接收信息」菜单入口:重定向至采集协议单管理 · 样本接收 Tab -->
|
||||
<!-- 旧「样本接收信息」菜单入口:重定向至样本信息管理 · 样本接收 Tab -->
|
||||
<template>
|
||||
<div />
|
||||
</template>
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
onMounted(() => {
|
||||
router.replace({
|
||||
name: 'CellStorageProtocolAudit',
|
||||
name: 'CellStorageSampleInfo',
|
||||
query: { ...route.query, tab: 'sample-reception' }
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- 旧「样本入库信息」菜单入口:重定向至采集协议单管理 · 样本入库 Tab -->
|
||||
<!-- 旧「样本入库信息」菜单入口:重定向至样本信息管理 · 样本入库 Tab -->
|
||||
<template>
|
||||
<div />
|
||||
</template>
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
onMounted(() => {
|
||||
router.replace({
|
||||
name: 'CellStorageProtocolAudit',
|
||||
name: 'CellStorageSampleInfo',
|
||||
query: { ...route.query, tab: 'storage-entry' }
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="modelValue"
|
||||
:title="(isEditMode ? '编辑体检信息' : '填写体检信息') + ' — ' + patientName"
|
||||
:title="(isEditMode ? '编辑预约信息' : '填写体检信息') + ' — ' + patientName"
|
||||
width="1080px"
|
||||
class="dialog-form-layout checkup-fill-dialog"
|
||||
align-center
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="modelValue"
|
||||
:title="'标记已体检 — ' + (patientName || '')"
|
||||
:title="(editMode ? '编辑体检信息' : '标记已体检') + ' — ' + (patientName || '')"
|
||||
width="1080px"
|
||||
class="dialog-form-layout checkup-mark-checked-dialog"
|
||||
align-center
|
||||
@@ -158,7 +158,11 @@
|
||||
<el-icon><Close /></el-icon>取消
|
||||
</el-button>
|
||||
<el-button class="btn-main" type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||
<el-icon><CircleCheck /></el-icon>确认标记已体检
|
||||
<el-icon>
|
||||
<Check v-if="editMode" />
|
||||
<CircleCheck v-else />
|
||||
</el-icon>
|
||||
{{ editMode ? '确定' : '确认标记已体检' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -480,6 +484,8 @@
|
||||
modelValue: boolean
|
||||
checkupId: string
|
||||
patientName?: string
|
||||
/** 编辑模式:仅保存体检登记信息,不变更体检状态 */
|
||||
editMode?: boolean
|
||||
}>()
|
||||
const emit = defineEmits(['update:modelValue', 'success'])
|
||||
|
||||
@@ -530,7 +536,7 @@
|
||||
|
||||
const requireInstitution = () => {
|
||||
if (!checkupInstitutionId.value) {
|
||||
ElMessage.warning('该记录未关联体检机构,请先在「编辑体检信息」中选择机构')
|
||||
ElMessage.warning('该记录未关联体检机构,请先在「编辑预约信息」中选择机构')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -814,8 +820,10 @@
|
||||
checkupRemark: checkupRemark.value || undefined,
|
||||
actualCheckupFee: actualTotal.value || undefined
|
||||
})
|
||||
await markPilotCheckupChecked({ id: props.checkupId })
|
||||
ElMessage.success('已标记为已体检')
|
||||
if (!props.editMode) {
|
||||
await markPilotCheckupChecked({ id: props.checkupId })
|
||||
}
|
||||
ElMessage.success(props.editMode ? '保存成功' : '已标记为已体检')
|
||||
emit('update:modelValue', false)
|
||||
emit('success')
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -221,8 +221,11 @@
|
||||
<el-dropdown-item v-if="hasPrimaryCheckupActions(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditCheckup(row)" command="edit">
|
||||
<el-icon><EditPen /></el-icon>编辑
|
||||
<el-dropdown-item v-if="canEditReserve(row)" command="editReserve">
|
||||
<el-icon><EditPen /></el-icon>编辑预约信息
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditActualCheckupInfo(row)" command="editActual">
|
||||
<el-icon><Edit /></el-icon>编辑体检信息
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
@@ -251,7 +254,7 @@
|
||||
@success="onBatchReserveSuccess"
|
||||
/>
|
||||
|
||||
<!-- 填写 / 编辑体检信息弹窗 -->
|
||||
<!-- 填写 / 编辑预约信息弹窗 -->
|
||||
<CheckupFillDialog
|
||||
v-model="fillDialogVisible"
|
||||
:checkup-id="currentCheckupId"
|
||||
@@ -263,11 +266,12 @@
|
||||
<!-- 查看弹窗 -->
|
||||
<CheckupViewDialog v-model="viewDialogVisible" :checkup-row="viewCheckupRow" />
|
||||
|
||||
<!-- 标记已体检弹窗 -->
|
||||
<!-- 标记已体检 / 编辑体检登记信息弹窗 -->
|
||||
<CheckupMarkCheckedDialog
|
||||
v-model="markCheckedVisible"
|
||||
:checkup-id="currentCheckupId"
|
||||
:patient-name="currentPatientName"
|
||||
:edit-mode="markCheckedEditMode"
|
||||
@success="loadData"
|
||||
/>
|
||||
</div>
|
||||
@@ -330,6 +334,7 @@
|
||||
const viewDialogVisible = ref(false)
|
||||
const viewCheckupRow = ref<any>(null)
|
||||
const markCheckedVisible = ref(false)
|
||||
const markCheckedEditMode = ref(false)
|
||||
const currentCheckupId = ref('')
|
||||
const currentPatientName = ref('')
|
||||
|
||||
@@ -387,8 +392,11 @@
|
||||
/** 待体检且已填写机构信息时可标记已体检 */
|
||||
const canMarkChecked = (row: any) => row.checkupStatus === 'dtj' && !!row.institutionName
|
||||
|
||||
/** 已填写机构信息时可编辑 */
|
||||
const canEditCheckup = (row: any) => !!row.institutionName
|
||||
/** 已填写机构信息时可编辑预约 */
|
||||
const canEditReserve = (row: any) => !!row.institutionName
|
||||
|
||||
/** 已体检时可编辑体检登记信息 */
|
||||
const canEditActualCheckupInfo = (row: any) => row.checkupStatus === 'ytj'
|
||||
|
||||
/** 是否存在填写体检信息 / 标记已体检主操作 */
|
||||
const hasPrimaryCheckupActions = (row: any) =>
|
||||
@@ -397,9 +405,9 @@
|
||||
/** 更多菜单是否展示 */
|
||||
const hasMoreCheckupActions = (row: any) => {
|
||||
if (hasPrimaryCheckupActions(row)) {
|
||||
return canEditCheckup(row) || canMarkChecked(row)
|
||||
return canEditReserve(row) || canMarkChecked(row)
|
||||
}
|
||||
return canEditCheckup(row)
|
||||
return canEditReserve(row) || canEditActualCheckupInfo(row)
|
||||
}
|
||||
|
||||
const handleDropdownCommand = (command: string, row: any) => {
|
||||
@@ -407,8 +415,11 @@
|
||||
case 'view':
|
||||
handleView(row)
|
||||
break
|
||||
case 'edit':
|
||||
handleEdit(row)
|
||||
case 'editReserve':
|
||||
handleEditReserve(row)
|
||||
break
|
||||
case 'editActual':
|
||||
handleEditActual(row)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -420,13 +431,20 @@
|
||||
fillDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleEdit = (row: any) => {
|
||||
const handleEditReserve = (row: any) => {
|
||||
currentCheckupId.value = row.id
|
||||
currentPatientName.value = row.patientName || ''
|
||||
fillEditRow.value = { ...row }
|
||||
fillDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleEditActual = (row: any) => {
|
||||
currentCheckupId.value = row.id
|
||||
currentPatientName.value = row.patientName || ''
|
||||
markCheckedEditMode.value = true
|
||||
markCheckedVisible.value = true
|
||||
}
|
||||
|
||||
const onFillSuccess = () => {
|
||||
fillEditRow.value = null
|
||||
loadData()
|
||||
@@ -461,6 +479,7 @@
|
||||
const handleMarkChecked = (row: any) => {
|
||||
currentCheckupId.value = row.id
|
||||
currentPatientName.value = row.patientName || ''
|
||||
markCheckedEditMode.value = false
|
||||
markCheckedVisible.value = true
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="editor.selectedStep.value.stepStatus === 'jxz'"
|
||||
class="btn-op-item"
|
||||
size="small"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="success"
|
||||
:loading="editor.stepActionLoading.value"
|
||||
:disabled="editor.manualSaveLoading.value"
|
||||
|
||||
@@ -331,7 +331,7 @@
|
||||
:is-completed-edit="completeConclusionIsEdit"
|
||||
:initial-conclusion="completeConclusionInitial.conclusion"
|
||||
:initial-remark="completeConclusionInitial.remark"
|
||||
@submit="submitCompleteWithConclusion"
|
||||
@submit="handleCompleteSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -386,10 +386,16 @@
|
||||
)
|
||||
|
||||
function handleClose() {
|
||||
dialogVisible.value = false
|
||||
emit('success')
|
||||
}
|
||||
|
||||
async function handleCompleteSubmit(payload: { conclusion: string; remark?: string }) {
|
||||
await submitCompleteWithConclusion(payload)
|
||||
if (taskDetail.value?.taskStatus === 'ywc') {
|
||||
dialogVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function stepSeqClass(status: string) {
|
||||
if (status === 'ywc') return 'seq-done'
|
||||
if (status === 'jxz') return 'seq-running'
|
||||
|
||||
@@ -156,6 +156,21 @@
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="expectedDeliveryDate"
|
||||
label="预产期"
|
||||
min-width="120"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sampleCollectSummary"
|
||||
label="是否已采集"
|
||||
min-width="160"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="donationDate"
|
||||
label="捐赠日期"
|
||||
@@ -220,6 +235,22 @@
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sampleTypeNames"
|
||||
label="样本类型"
|
||||
min-width="140"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sampleCodes"
|
||||
label="样本编码"
|
||||
min-width="160"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="regionName"
|
||||
label="采集地区"
|
||||
|
||||
@@ -212,7 +212,17 @@
|
||||
<el-radio label="0">女</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="新生儿分娩时间" class="form-col-span-2">
|
||||
<el-form-item label="预产期">
|
||||
<el-date-picker
|
||||
v-model="formData.expectedDeliveryDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择预产期"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="新生儿分娩时间">
|
||||
<el-date-picker
|
||||
v-model="formData.newbornDeliveryTime"
|
||||
type="datetime"
|
||||
@@ -396,11 +406,11 @@
|
||||
:disabled="!selectedSamples.length"
|
||||
@click="openBatchTransportDialog"
|
||||
>
|
||||
应用到选中样本
|
||||
批量配置运输信息
|
||||
</el-button>
|
||||
</div>
|
||||
<p v-if="formData.samples.length" class="sample-transport-hint"
|
||||
>勾选样本后,点击「应用到选中样本」可批量填写运输信息。点击展开可编辑单个运输信息。</p
|
||||
>勾选样本后,点击「批量配置运输信息」可统一填写运输信息。点击展开可编辑单个运输信息。</p
|
||||
>
|
||||
|
||||
<!-- Sample Cards -->
|
||||
@@ -1121,6 +1131,7 @@
|
||||
fatherIdCard: '',
|
||||
newbornName: '',
|
||||
newbornIdCard: '',
|
||||
expectedDeliveryDate: '',
|
||||
newbornDeliveryTime: '',
|
||||
newbornSex: '',
|
||||
deliveryMode: '',
|
||||
@@ -1166,6 +1177,7 @@
|
||||
fatherIdCard: '',
|
||||
newbornName: '',
|
||||
newbornIdCard: '',
|
||||
expectedDeliveryDate: '',
|
||||
newbornDeliveryTime: '',
|
||||
newbornSex: '',
|
||||
deliveryMode: '',
|
||||
@@ -1343,6 +1355,7 @@
|
||||
formData.fatherIdCard = String(pc.fatherIdCard || '')
|
||||
formData.newbornName = String(pc.newbornName || '')
|
||||
formData.newbornIdCard = String(pc.newbornIdCard || '')
|
||||
formData.expectedDeliveryDate = String(pc.expectedDeliveryDate || '')
|
||||
formData.newbornDeliveryTime = String(pc.newbornDeliveryTime || '')
|
||||
formData.newbornSex = String(pc.newbornSex ?? '')
|
||||
formData.deliveryMode = String(pc.deliveryMode || '')
|
||||
@@ -1496,6 +1509,7 @@
|
||||
fatherIdCard: formData.fatherIdCard || undefined,
|
||||
newbornName: formData.newbornName || undefined,
|
||||
newbornIdCard: formData.newbornIdCard || undefined,
|
||||
expectedDeliveryDate: formData.expectedDeliveryDate || undefined,
|
||||
newbornDeliveryTime: formData.newbornDeliveryTime || undefined,
|
||||
newbornSex: formData.newbornSex || undefined,
|
||||
deliveryMode: formData.deliveryMode || undefined,
|
||||
@@ -1965,8 +1979,8 @@
|
||||
sc: Api.BizSampleCode.SampleCodeItem,
|
||||
row: Record<string, any>
|
||||
) {
|
||||
if (!sc.usedInProtocol) return false
|
||||
return String(row.sampleCodeId || '') !== sc.id
|
||||
if (sc.usedInProtocol && String(row.sampleCodeId || '') !== sc.id) return true
|
||||
return formData.samples.some((s) => s !== row && String(s.sampleCodeId || '') === sc.id)
|
||||
}
|
||||
|
||||
function onSampleCodeChange(row: Record<string, any>) {
|
||||
|
||||
@@ -276,6 +276,10 @@
|
||||
><div class="data-label">新生儿身份证</div
|
||||
><div class="data-value">{{ dash(party?.newbornIdCard) }}</div></div
|
||||
>
|
||||
<div class="data-item"
|
||||
><div class="data-label">预产期</div
|
||||
><div class="data-value">{{ dash(party?.expectedDeliveryDate) }}</div></div
|
||||
>
|
||||
<div class="data-item"
|
||||
><div class="data-label">新生儿分娩时间</div
|
||||
><div class="data-value">{{ dash(party?.newbornDeliveryTime) }}</div></div
|
||||
|
||||
Reference in new issue
Block a user