Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e482980c7d | ||
|
|
900e957f25 | ||
|
|
15a20db725 | ||
|
|
3ac30a6c2c | ||
|
|
95d6b6025f | ||
|
|
d0eb97b167 |
No files matched your search
@@ -21,6 +21,7 @@ from app.services.sample_storage_cert_qc import (
|
||||
loads_payload,
|
||||
normalize_payload,
|
||||
resolve_sample_type_key,
|
||||
sanitize_payload_for_type,
|
||||
)
|
||||
from app.services.sample_storage_cert_qc_prefill import collect_prefill
|
||||
|
||||
@@ -44,7 +45,7 @@ def _row_to_dict(
|
||||
"collectionProtocolId": row.collection_protocol_id or "",
|
||||
"qcWorkOrderId": row.qc_work_order_id or "",
|
||||
"filledFlag": str(row.filled_flag or "0") == "1",
|
||||
"payload": loads_payload(row.payload),
|
||||
"payload": sanitize_payload_for_type(loads_payload(row.payload), row.sample_type_key),
|
||||
"createTime": row.create_time.isoformat(sep=" ", timespec="seconds") if row.create_time else "",
|
||||
"updateTime": row.update_time.isoformat(sep=" ", timespec="seconds") if row.update_time else "",
|
||||
}
|
||||
@@ -173,7 +174,7 @@ def upsert(
|
||||
key = resolve_sample_type_key(type_name)
|
||||
if not key:
|
||||
raise ValueError("该样本类型不支持填写储存证质检信息")
|
||||
clean = normalize_payload(payload)
|
||||
clean = sanitize_payload_for_type(normalize_payload(payload), key)
|
||||
now = datetime.now()
|
||||
row = (
|
||||
db.query(BizSampleStorageCertQc)
|
||||
|
||||
@@ -24,6 +24,16 @@ def supports_storage_cert_qc(sample_type_name: Optional[str]) -> bool:
|
||||
return resolve_sample_type_key(sample_type_name) is not None
|
||||
|
||||
|
||||
# 脐带间充质储存证不收录母亲血液三项核酸检测。
|
||||
UC_MSC_EXCLUDED_PAYLOAD_KEYS = frozenset(
|
||||
{
|
||||
"mother_hbv_dna",
|
||||
"mother_hcv_rna",
|
||||
"mother_hiv1_rna",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def normalize_payload(payload: Any) -> Dict[str, Any]:
|
||||
if not isinstance(payload, dict):
|
||||
raise ValueError("payload 必须为对象")
|
||||
@@ -38,6 +48,16 @@ def normalize_payload(payload: Any) -> Dict[str, Any]:
|
||||
return out
|
||||
|
||||
|
||||
def sanitize_payload_for_type(
|
||||
payload: Dict[str, Any],
|
||||
sample_type_key: Optional[str],
|
||||
) -> Dict[str, Any]:
|
||||
"""按样本类型去掉不应展示/落库的键。"""
|
||||
if sample_type_key != SAMPLE_TYPE_KEY_UC_MSC:
|
||||
return payload
|
||||
return {key: value for key, value in payload.items() if key not in UC_MSC_EXCLUDED_PAYLOAD_KEYS}
|
||||
|
||||
|
||||
def dumps_payload(payload: Dict[str, Any]) -> str:
|
||||
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
|
||||
|
||||
|
||||
@@ -168,6 +168,11 @@ _HSC_SEROLOGY_RULES = (
|
||||
)
|
||||
|
||||
_MOTHER_SEROLOGY_RULES = tuple(rule for rule in _HSC_SEROLOGY_RULES if str(rule[0]).startswith("mother_"))
|
||||
# 脐带间充质不预填母亲血液三项核酸。
|
||||
_UC_MSC_EXCLUDED_MOTHER_KEYS = frozenset({"mother_hbv_dna", "mother_hcv_rna", "mother_hiv1_rna"})
|
||||
_MOTHER_SEROLOGY_RULES_UC_MSC = tuple(
|
||||
rule for rule in _MOTHER_SEROLOGY_RULES if str(rule[0]) not in _UC_MSC_EXCLUDED_MOTHER_KEYS
|
||||
)
|
||||
|
||||
|
||||
def _serology_from_tasks(
|
||||
@@ -278,9 +283,19 @@ def _process_qual_from_tasks(tasks: List[Dict[str, Any]]) -> Dict[str, str]:
|
||||
return out
|
||||
|
||||
|
||||
def _fill_shared_mother(suggested: Dict[str, str], tasks: Optional[List[Dict[str, Any]]]) -> None:
|
||||
def _fill_shared_mother(
|
||||
suggested: Dict[str, str],
|
||||
tasks: Optional[List[Dict[str, Any]]],
|
||||
*,
|
||||
sample_type_key: str,
|
||||
) -> None:
|
||||
"""只补母亲血液空项。共享任务里的脐血不参与。"""
|
||||
shared = _serology_from_tasks(tasks or [], _MOTHER_SEROLOGY_RULES)
|
||||
rules = (
|
||||
_MOTHER_SEROLOGY_RULES_UC_MSC
|
||||
if sample_type_key == "uc_msc"
|
||||
else _MOTHER_SEROLOGY_RULES
|
||||
)
|
||||
shared = _serology_from_tasks(tasks or [], rules)
|
||||
for key, value in shared.items():
|
||||
suggested.setdefault(key, value)
|
||||
|
||||
@@ -330,7 +345,7 @@ def build_suggested(
|
||||
if count:
|
||||
suggested["available_cell_count_1e7"] = count
|
||||
suggested.update(_process_qual_from_tasks(process_tasks or []))
|
||||
suggested.update(_serology_from_tasks(gate_tasks or [], _MOTHER_SEROLOGY_RULES))
|
||||
suggested.update(_serology_from_tasks(gate_tasks or [], _MOTHER_SEROLOGY_RULES_UC_MSC))
|
||||
suggested.setdefault("bacteria_test", "阴性")
|
||||
suggested.setdefault("result_judgment", "合格")
|
||||
if freeze:
|
||||
@@ -338,7 +353,7 @@ def build_suggested(
|
||||
suggested.update(_FIXED_COMMON)
|
||||
suggested.update(_FIXED_UC_MSC)
|
||||
if sample_type_key in ("perinatal_hsc", "uc_msc"):
|
||||
_fill_shared_mother(suggested, shared_mother_tasks)
|
||||
_fill_shared_mother(suggested, shared_mother_tasks, sample_type_key=sample_type_key)
|
||||
return {key: value for key, value in suggested.items() if str(value).strip()}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ from app.services.sample_storage_cert_qc import (
|
||||
empty_detail,
|
||||
normalize_payload,
|
||||
resolve_sample_type_key,
|
||||
sanitize_payload_for_type,
|
||||
supports_storage_cert_qc,
|
||||
)
|
||||
from app.services.sample_storage_cert_qc_prefill import (
|
||||
@@ -51,6 +52,34 @@ class TestNormalizePayload(unittest.TestCase):
|
||||
self.assertNotIn(1, out)
|
||||
|
||||
|
||||
class TestSanitizePayloadForType(unittest.TestCase):
|
||||
def test_uc_msc_drops_mother_nucleic_acids(self):
|
||||
out = sanitize_payload_for_type(
|
||||
{
|
||||
"mother_hbsag": "阴性",
|
||||
"mother_hbv_dna": "阴性",
|
||||
"mother_hcv_rna": "阳性",
|
||||
"mother_hiv1_rna": "阴性",
|
||||
"mother_cmv_igm": "阴性",
|
||||
},
|
||||
SAMPLE_TYPE_KEY_UC_MSC,
|
||||
)
|
||||
self.assertEqual(out["mother_hbsag"], "阴性")
|
||||
self.assertEqual(out["mother_cmv_igm"], "阴性")
|
||||
self.assertNotIn("mother_hbv_dna", out)
|
||||
self.assertNotIn("mother_hcv_rna", out)
|
||||
self.assertNotIn("mother_hiv1_rna", out)
|
||||
|
||||
def test_perinatal_keeps_mother_nucleic_acids(self):
|
||||
payload = {
|
||||
"mother_hbv_dna": "阴性",
|
||||
"mother_hcv_rna": "阴性",
|
||||
"mother_hiv1_rna": "阴性",
|
||||
}
|
||||
out = sanitize_payload_for_type(payload, SAMPLE_TYPE_KEY_PERINATAL_HSC)
|
||||
self.assertEqual(out, payload)
|
||||
|
||||
|
||||
class TestEmptyDetail(unittest.TestCase):
|
||||
def test_shape(self):
|
||||
d = empty_detail(
|
||||
@@ -302,13 +331,13 @@ class TestStorageCertPrefill(unittest.TestCase):
|
||||
]
|
||||
suggested = build_suggested(sample_type_key="uc_msc", shared_mother_tasks=shared)
|
||||
self.assertEqual(suggested["mother_hbsag"], "阴性")
|
||||
self.assertEqual(suggested["mother_hbv_dna"], "阴性")
|
||||
self.assertNotIn("mother_hbv_dna", suggested)
|
||||
self.assertEqual(suggested["mother_anti_hcv"], "阴性")
|
||||
self.assertEqual(suggested["mother_hcv_rna"], "阴性")
|
||||
self.assertNotIn("mother_hcv_rna", suggested)
|
||||
self.assertEqual(suggested["mother_anti_tp"], "阴性")
|
||||
self.assertEqual(suggested["mother_cmv_igm"], "阴性")
|
||||
self.assertEqual(suggested["mother_anti_hiv"], "阴性")
|
||||
self.assertEqual(suggested["mother_hiv1_rna"], "阴性")
|
||||
self.assertNotIn("mother_hiv1_rna", suggested)
|
||||
self.assertNotIn("hbsag", suggested)
|
||||
|
||||
def test_own_mother_blood_wins_and_shared_only_fills_gaps(self):
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
buildFreightMergeRanges,
|
||||
buildPresignLedgerRows,
|
||||
buildResearchLedgerRows,
|
||||
formatLedgerDateTime
|
||||
formatLedgerDateTime,
|
||||
groupFlatRowsByFreightBatch
|
||||
} from './collection-ledger-export'
|
||||
import type { ProtocolAuditFlatRow } from './protocol-audit-flatten'
|
||||
|
||||
@@ -194,6 +195,71 @@ describe('buildCellStorageLedgerRows', () => {
|
||||
{ startRow: 2, endRow: 3, startCol: 54, endCol: 54 }
|
||||
])
|
||||
})
|
||||
|
||||
it('groups non-adjacent same freight batch before merging cells', () => {
|
||||
const shared = {
|
||||
protocol: { protocolStatus: 'sxz', remark: '', voidType: '', voidDesc: '' },
|
||||
sampleCollectTime: '2025-09-11 18:13:00',
|
||||
sampleTypeName: 'NK',
|
||||
regionName: '常州',
|
||||
hospitalName: '溧阳市人民医院',
|
||||
freightTransportLabel: '专线车',
|
||||
freightAmountLabel: '100'
|
||||
}
|
||||
const { rows, merges } = buildCellStorageLedgerRows([
|
||||
{
|
||||
...shared,
|
||||
motherName: '甲',
|
||||
sampleCode: 'S1',
|
||||
labStorageCode: 'UBMC1',
|
||||
freightId: 'batch-cell'
|
||||
} as unknown as ProtocolAuditFlatRow,
|
||||
{
|
||||
...shared,
|
||||
motherName: '丙',
|
||||
sampleCode: 'S3',
|
||||
labStorageCode: 'UBMC3',
|
||||
freightId: 'other',
|
||||
freightTransportLabel: '快递',
|
||||
freightAmountLabel: '25'
|
||||
} as unknown as ProtocolAuditFlatRow,
|
||||
{
|
||||
...shared,
|
||||
motherName: '乙',
|
||||
sampleCode: 'S2',
|
||||
labStorageCode: 'UBMC2',
|
||||
freightId: 'batch-cell'
|
||||
} as unknown as ProtocolAuditFlatRow
|
||||
])
|
||||
assert.equal(rows[0][8], '甲')
|
||||
assert.equal(rows[1][8], '乙')
|
||||
assert.equal(rows[2][8], '丙')
|
||||
assert.equal(rows[0][52], '专线车')
|
||||
assert.equal(rows[0][53], '100')
|
||||
assert.equal(rows[1][52], '')
|
||||
assert.equal(rows[1][53], '')
|
||||
assert.equal(rows[2][52], '快递')
|
||||
assert.equal(rows[2][53], '25')
|
||||
assert.deepEqual(merges, [
|
||||
{ startRow: 2, endRow: 3, startCol: 53, endCol: 53 },
|
||||
{ startRow: 2, endRow: 3, startCol: 54, endCol: 54 }
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('groupFlatRowsByFreightBatch', () => {
|
||||
it('keeps first-seen batch order and leaves empty freight rows in place', () => {
|
||||
const arranged = groupFlatRowsByFreightBatch([
|
||||
{ motherName: 'A', freightId: 'f1' },
|
||||
{ motherName: 'B', freightId: '' },
|
||||
{ motherName: 'C', freightId: 'f1' },
|
||||
{ motherName: 'D', freightId: 'f2' }
|
||||
] as unknown as ProtocolAuditFlatRow[])
|
||||
assert.deepEqual(
|
||||
arranged.map((row) => row.motherName),
|
||||
['A', 'C', 'B', 'D']
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('buildResearchLedgerRows', () => {
|
||||
@@ -335,6 +401,50 @@ describe('buildResearchLedgerRows', () => {
|
||||
{ startRow: 3, endRow: 4, startCol: 18, endCol: 18 }
|
||||
])
|
||||
})
|
||||
|
||||
it('groups non-adjacent same freight batch before merging research cells', () => {
|
||||
const shared = {
|
||||
protocol: { donationStatus: 'sxz', voidType: '', voidDesc: '', monthlyVerifyNo: '' },
|
||||
sampleCollectTime: '2025-09-11 18:13:00',
|
||||
sampleTypeName: 'NK',
|
||||
regionName: '常州',
|
||||
hospitalName: '溧阳市人民医院',
|
||||
freightTransportLabel: '专线车',
|
||||
freightAmountLabel: '100'
|
||||
}
|
||||
const { rows, merges } = buildResearchLedgerRows([
|
||||
{
|
||||
...shared,
|
||||
motherName: '甲',
|
||||
labStorageCode: 'A1',
|
||||
freightId: 'batch-a'
|
||||
} as unknown as ProtocolAuditFlatRow,
|
||||
{
|
||||
...shared,
|
||||
motherName: '散',
|
||||
labStorageCode: 'A9',
|
||||
freightId: '',
|
||||
freightTransportLabel: '',
|
||||
freightAmountLabel: ''
|
||||
} as unknown as ProtocolAuditFlatRow,
|
||||
{
|
||||
...shared,
|
||||
motherName: '乙',
|
||||
labStorageCode: 'A2',
|
||||
freightId: 'batch-a'
|
||||
} as unknown as ProtocolAuditFlatRow
|
||||
])
|
||||
assert.equal(rows[0][8], '甲')
|
||||
assert.equal(rows[1][8], '乙')
|
||||
assert.equal(rows[2][8], '散')
|
||||
assert.equal(rows[0][16], '专线车')
|
||||
assert.equal(rows[1][16], '')
|
||||
assert.equal(rows[1][17], '')
|
||||
assert.deepEqual(merges, [
|
||||
{ startRow: 2, endRow: 3, startCol: 17, endCol: 17 },
|
||||
{ startRow: 2, endRow: 3, startCol: 18, endCol: 18 }
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('buildCustomerServiceLedgerRows', () => {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import type { ProtocolAuditFlatRow } from './protocol-audit-flatten'
|
||||
|
||||
/** 采集大表导出入口开关;验收未完成前隐藏按钮,改 true 即可恢复。 */
|
||||
export const COLLECTION_LEDGER_EXPORT_ENABLED = false
|
||||
|
||||
type Row = Record<string, unknown>
|
||||
type PayDetail = {
|
||||
installmentNo?: number | null
|
||||
@@ -341,6 +338,36 @@ function researchMaternalBloodText(value: unknown): string {
|
||||
return text(value) ? text(value) : '无母血'
|
||||
}
|
||||
|
||||
/**
|
||||
* 将同一运费批次的行聚拢到一起(按首次出现顺序),无批次行保持相对位置。
|
||||
* 模版要求同批次运输方式/运费合并单元格,故导出前先归拢再合并。
|
||||
*/
|
||||
export function groupFlatRowsByFreightBatch(
|
||||
rows: ProtocolAuditFlatRow[]
|
||||
): ProtocolAuditFlatRow[] {
|
||||
const groups = new Map<string, ProtocolAuditFlatRow[]>()
|
||||
const sequence: Array<{ kind: 'batch'; id: string } | { kind: 'single'; row: ProtocolAuditFlatRow }> =
|
||||
[]
|
||||
for (const row of rows) {
|
||||
const freightId = text(row.freightId)
|
||||
if (!freightId) {
|
||||
sequence.push({ kind: 'single', row })
|
||||
continue
|
||||
}
|
||||
if (!groups.has(freightId)) {
|
||||
groups.set(freightId, [])
|
||||
sequence.push({ kind: 'batch', id: freightId })
|
||||
}
|
||||
groups.get(freightId)!.push(row)
|
||||
}
|
||||
const arranged: ProtocolAuditFlatRow[] = []
|
||||
for (const item of sequence) {
|
||||
if (item.kind === 'single') arranged.push(item.row)
|
||||
else arranged.push(...(groups.get(item.id) || []))
|
||||
}
|
||||
return arranged
|
||||
}
|
||||
|
||||
/**
|
||||
* 相邻且 freightId 相同的导出行,合并运输方式/运费列(Excel 行号含表头)。
|
||||
* @param transportCol 运输方式列(1-based)
|
||||
@@ -626,9 +653,10 @@ export function buildCellStorageLedgerRows(rows: ProtocolAuditFlatRow[]): {
|
||||
rows: string[][]
|
||||
merges: LedgerMergeRange[]
|
||||
} {
|
||||
const freightIds = rows.map((row) => text(row.freightId))
|
||||
const built = rows.map((row, index) => storageLedgerRow(row, index, false))
|
||||
// 自存表:运输方式=53,运费=54
|
||||
const arranged = groupFlatRowsByFreightBatch(rows)
|
||||
const freightIds = arranged.map((row) => text(row.freightId))
|
||||
const built = arranged.map((row, index) => storageLedgerRow(row, index, false))
|
||||
// 自存表:运输方式=53,运费=54(对齐模版《自存表》)
|
||||
return { rows: built, merges: applyFreightMerges(built, freightIds, 53, 54) }
|
||||
}
|
||||
|
||||
@@ -636,9 +664,10 @@ export function buildResearchLedgerRows(rows: ProtocolAuditFlatRow[]): {
|
||||
rows: string[][]
|
||||
merges: LedgerMergeRange[]
|
||||
} {
|
||||
const freightIds = rows.map((row) => text(row.freightId))
|
||||
const built = rows.map((row, index) => storageLedgerRow(row, index, true))
|
||||
// 科研表:运输方式=17,运费=18
|
||||
const arranged = groupFlatRowsByFreightBatch(rows)
|
||||
const freightIds = arranged.map((row) => text(row.freightId))
|
||||
const built = arranged.map((row, index) => storageLedgerRow(row, index, true))
|
||||
// 科研表:运输方式=17,运费=18(对齐模版《科研表》)
|
||||
return { rows: built, merges: applyFreightMerges(built, freightIds, 17, 18) }
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ export function supportsStorageCertQc(sampleTypeName?: string | null): boolean {
|
||||
return resolveStorageCertQcTypeKey(sampleTypeName) != null
|
||||
}
|
||||
|
||||
const MOTHER_BLOOD: StorageCertQcField[] = [
|
||||
/** 围产期造血:母亲血液含三项核酸检测。 */
|
||||
const MOTHER_BLOOD_PERINATAL: StorageCertQcField[] = [
|
||||
{ key: 'mother_hbsag', label: '乙型肝炎病毒表面抗原(HBsAg)', control: 'select_yny' },
|
||||
{ key: 'mother_hbv_dna', label: '乙型肝炎病毒核酸(HBV DNA)', control: 'select_yny' },
|
||||
{ key: 'mother_anti_hcv', label: '丙型肝炎病毒抗体(抗HCV)', control: 'select_yny' },
|
||||
@@ -48,6 +49,15 @@ const MOTHER_BLOOD: StorageCertQcField[] = [
|
||||
}
|
||||
]
|
||||
|
||||
/** 脐带间充质:不展示 HBV DNA / HCV RNA / HIV-1RNA。 */
|
||||
const MOTHER_BLOOD_UC_MSC: StorageCertQcField[] = [
|
||||
{ key: 'mother_hbsag', label: '乙型肝炎病毒表面抗原(HBsAg)', control: 'select_yny' },
|
||||
{ key: 'mother_anti_hcv', label: '丙型肝炎病毒抗体(抗HCV)', control: 'select_yny' },
|
||||
{ key: 'mother_anti_tp', label: '梅毒螺旋体特异性抗体(抗TP)', control: 'select_yny' },
|
||||
{ key: 'mother_cmv_igm', label: '巨细胞病毒 IgM 抗体 (CMV IgM)', control: 'select_yny' },
|
||||
{ key: 'mother_anti_hiv', label: '人类免疫缺陷病毒抗体(抗HIV-1/2)', control: 'select_yny' }
|
||||
]
|
||||
|
||||
export const STORAGE_CERT_QC_GROUPS: Record<StorageCertQcTypeKey, StorageCertQcGroup[]> = {
|
||||
perinatal_hsc: [
|
||||
{
|
||||
@@ -77,7 +87,7 @@ export const STORAGE_CERT_QC_GROUPS: Record<StorageCertQcTypeKey, StorageCertQcG
|
||||
{ key: 'cmv_igm', label: '巨细胞病毒 IgM 抗体 (CMV-IgM)', control: 'select_yny' }
|
||||
]
|
||||
},
|
||||
{ title: '母亲血液检测报告', variant: 'primary', fields: MOTHER_BLOOD },
|
||||
{ title: '母亲血液检测报告', variant: 'primary', fields: MOTHER_BLOOD_PERINATAL },
|
||||
{
|
||||
title: '储存证收尾信息',
|
||||
variant: 'meta',
|
||||
@@ -120,7 +130,7 @@ export const STORAGE_CERT_QC_GROUPS: Record<StorageCertQcTypeKey, StorageCertQcG
|
||||
}
|
||||
]
|
||||
},
|
||||
{ title: '母亲血液检测报告', variant: 'primary', fields: MOTHER_BLOOD },
|
||||
{ title: '母亲血液检测报告', variant: 'primary', fields: MOTHER_BLOOD_UC_MSC },
|
||||
{
|
||||
title: '储存证收尾信息',
|
||||
variant: 'meta',
|
||||
|
||||
@@ -75,12 +75,7 @@
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="COLLECTION_LEDGER_EXPORT_ENABLED"
|
||||
class="btn-ghost"
|
||||
:loading="exporting"
|
||||
@click="handleExport"
|
||||
>
|
||||
<el-button class="btn-ghost" :loading="exporting" @click="handleExport">
|
||||
<el-icon><Download /></el-icon>
|
||||
导出 Excel
|
||||
</el-button>
|
||||
@@ -467,7 +462,6 @@
|
||||
} from '@/utils/protocol-doc-label'
|
||||
import { loadVoidTypeDict } from '@/utils/void-type-dict'
|
||||
import {
|
||||
COLLECTION_LEDGER_EXPORT_ENABLED,
|
||||
RESEARCH_HEADERS,
|
||||
buildResearchLedgerRows,
|
||||
fetchAllPages,
|
||||
|
||||
@@ -79,12 +79,7 @@
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="COLLECTION_LEDGER_EXPORT_ENABLED"
|
||||
class="btn-ghost"
|
||||
:loading="exporting"
|
||||
@click="handleExport"
|
||||
>
|
||||
<el-button class="btn-ghost" :loading="exporting" @click="handleExport">
|
||||
<el-icon><Download /></el-icon>
|
||||
导出 Excel
|
||||
</el-button>
|
||||
@@ -435,7 +430,6 @@
|
||||
} from '@/utils/status-tag-registry'
|
||||
import { loadVoidTypeDict } from '@/utils/void-type-dict'
|
||||
import {
|
||||
COLLECTION_LEDGER_EXPORT_ENABLED,
|
||||
CELL_STORAGE_HEADERS,
|
||||
buildCellStorageLedgerRows,
|
||||
fetchAllPages,
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
登记入库
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="isCellStorage && COLLECTION_LEDGER_EXPORT_ENABLED"
|
||||
v-if="isCellStorage"
|
||||
class="btn-ghost"
|
||||
:loading="exporting"
|
||||
@click="handleExport"
|
||||
@@ -243,7 +243,7 @@
|
||||
<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>
|
||||
<template #default="{ row }">{{ formatNewbornSex(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>
|
||||
@@ -510,6 +510,7 @@
|
||||
donationStatusTagType,
|
||||
handleDoneFlagLabel,
|
||||
handleDoneFlagTagType,
|
||||
newbornSexLabel,
|
||||
protocolStatusDisplayLabel,
|
||||
protocolStatusTagType,
|
||||
sampleCollectionFlagLabel,
|
||||
@@ -522,7 +523,6 @@
|
||||
sampleStorageFlagTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import {
|
||||
COLLECTION_LEDGER_EXPORT_ENABLED,
|
||||
CUSTOMER_SERVICE_HEADERS,
|
||||
buildCustomerServiceLedgerRows,
|
||||
fetchAllPages,
|
||||
@@ -572,11 +572,11 @@
|
||||
const codeCorrectionVisible = ref(false)
|
||||
const codeCorrectionOldCode = ref('')
|
||||
|
||||
function sexLabel(sex: unknown) {
|
||||
const s = String(sex || '').trim()
|
||||
if (s === '1' || s === '男') return '男'
|
||||
if (s === '2' || s === '女') return '女'
|
||||
return s || '—'
|
||||
/** 与协议表单一致:'1'=男,'0'=女;空值显示 —(勿与客户 sexLabel 0男1女混淆) */
|
||||
function formatNewbornSex(sex: unknown) {
|
||||
const s = sex == null || sex === '' ? '' : String(sex).trim()
|
||||
if (!s) return '—'
|
||||
return newbornSexLabel(s) || '—'
|
||||
}
|
||||
|
||||
function openStorageCertQcEdit(row: Record<string, unknown>) {
|
||||
|
||||
+11
-23
@@ -70,21 +70,16 @@
|
||||
<dt>样本类型</dt>
|
||||
<dd>{{ row.sampleTypeName || '—' }}</dd>
|
||||
</div>
|
||||
<div class="sample-reception-card__meta-item sample-reception-card__meta-item--attachment">
|
||||
<dt>{{ attachmentMeta(row).label }}</dt>
|
||||
<div
|
||||
v-for="group in protocolAttachmentGroups(row)"
|
||||
:key="group.label"
|
||||
class="sample-reception-card__meta-item sample-reception-card__meta-item--attachment"
|
||||
>
|
||||
<dt>{{ group.label }}</dt>
|
||||
<dd>
|
||||
<ProtocolAttachmentMiniReadonly
|
||||
:files="attachmentMeta(row).files"
|
||||
@preview="handleAttachmentPreview"
|
||||
@download="handleAttachmentDownload"
|
||||
/>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="sample-reception-card__meta-item sample-reception-card__meta-item--attachment">
|
||||
<dt>{{ consentAttachmentMeta(row).label }}</dt>
|
||||
<dd>
|
||||
<ProtocolAttachmentMiniReadonly
|
||||
:files="consentAttachmentMeta(row).files"
|
||||
:files="group.files"
|
||||
empty-text="暂无附件"
|
||||
@preview="handleAttachmentPreview"
|
||||
@download="handleAttachmentDownload"
|
||||
/>
|
||||
@@ -252,10 +247,7 @@
|
||||
import SampleCodeWithSpecialDisplay from '@/components/business/sample-code-with-special-display/index.vue'
|
||||
import QcWorkOrderProtocolPaymentPanel from '@/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue'
|
||||
import ProtocolAttachmentMiniReadonly from '@/components/business/protocol-attachment-mini-readonly/index.vue'
|
||||
import {
|
||||
getConsentProtocolAttachment,
|
||||
getSourceProtocolAttachment
|
||||
} from '@/utils/protocol-source-attachment'
|
||||
import { getSourceProtocolAttachmentGroups } from '@/utils/protocol-source-attachment'
|
||||
import { useAttachmentActions } from '@/composables/useAttachmentActions'
|
||||
|
||||
defineOptions({ name: 'SampleReceptionCardList' })
|
||||
@@ -293,12 +285,8 @@
|
||||
|
||||
const { handleAttachmentPreview, handleAttachmentDownload } = useAttachmentActions()
|
||||
|
||||
function attachmentMeta(row: Record<string, unknown>) {
|
||||
return getSourceProtocolAttachment(row)
|
||||
}
|
||||
|
||||
function consentAttachmentMeta(row: Record<string, unknown>) {
|
||||
return getConsentProtocolAttachment(row)
|
||||
function protocolAttachmentGroups(row: Record<string, unknown>) {
|
||||
return getSourceProtocolAttachmentGroups(row)
|
||||
}
|
||||
|
||||
function protocolStatusLabelBySource(status: string, source: string, voidType?: string): string {
|
||||
|
||||
Reference in new issue
Block a user