feat(mobile-oa-h5): align research donation protocol card with excel fields
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
0ab0774e8a
commit
99e71096ac
2 files changed
+94
-66
No files matched your search
@@ -2,7 +2,6 @@ const SEARCH_PLACEHOLDERS = Object.freeze({
|
||||
protocol: '搜索母亲姓名 / 样本编码',
|
||||
'payment-chase': '搜索协议号 / 客户 / 样本编码',
|
||||
payment: '搜索协议号 / 客户 / 样本编码',
|
||||
sample: '搜索母亲姓名 / 样本编码',
|
||||
freight: '搜索批次号 / 母亲姓名 / 样本编码'
|
||||
})
|
||||
|
||||
@@ -19,13 +18,10 @@ const ACTION_LABELS = Object.freeze({
|
||||
'view-payment': '查看缴费',
|
||||
'view-payment-detail': '缴费明细',
|
||||
'view-protocol': '协议单',
|
||||
'view-storage-qc': '储存证质检信息',
|
||||
'register-transfer': '登记转账',
|
||||
'edit-transfer': '编辑转账',
|
||||
submit: '提交财务确认',
|
||||
withdraw: '撤回转账',
|
||||
'storage-cert': '登记储存证',
|
||||
insurance: '登记保险',
|
||||
link: '关联样本',
|
||||
unlink: '取消运费'
|
||||
})
|
||||
@@ -67,7 +63,7 @@ export function money(value) {
|
||||
}
|
||||
|
||||
export function marketSearchPlaceholder(module, source) {
|
||||
if (module === 'protocol' || module === 'sample') {
|
||||
if (module === 'protocol') {
|
||||
return PROTOCOL_SEARCH_PLACEHOLDERS[source] || SEARCH_PLACEHOLDERS[module]
|
||||
}
|
||||
return SEARCH_PLACEHOLDERS[module] || '搜索编号、姓名或关键词'
|
||||
@@ -82,16 +78,55 @@ function allowed(item, ownActions = []) {
|
||||
return ownActions.filter((action) => backend.has(action))
|
||||
}
|
||||
|
||||
function attachmentPresence(urls) {
|
||||
return String(urls || '').trim() ? '有' : '—'
|
||||
}
|
||||
|
||||
function protocolCard(item) {
|
||||
const actions = allowed(item, ['edit', 'delete'])
|
||||
const isDonation = item.source === 'research_donation'
|
||||
const status = label(PROTOCOL_STATUS_LABELS, item.protocolStatus || item.donationStatus || item.status)
|
||||
if (isDonation) {
|
||||
const collectDate = String(item.sampleCollectTime || '').slice(0, 10)
|
||||
return {
|
||||
title: text(item.motherName || item.customerName),
|
||||
subtitle: `${label(SOURCE_LABELS, item.source)} · ${text(item.labStorageCode || item.sampleCode)}`,
|
||||
status,
|
||||
fields: [
|
||||
field('采集日期', collectDate || item.donationDate),
|
||||
field('当月核量号', item.monthlyVerifyNo),
|
||||
field('实验室流转编号', item.labStorageCode || item.sampleCode, { wide: true }),
|
||||
field('协议状态', status, { tag: true }),
|
||||
field('废弃原因', item.voidDesc),
|
||||
field('母亲姓名', item.motherName || item.customerName),
|
||||
field('样本类型', item.sampleTypeName),
|
||||
field('采集地区', referenceName(item.regionName, item.regionId)),
|
||||
field('采集医院', referenceName(item.hospitalName, item.hospitalId), { wide: true }),
|
||||
field('分娩时间', item.newbornDeliveryTime, { wide: true }),
|
||||
field('采集时间', item.sampleCollectTime, { wide: true }),
|
||||
field('市场专员', personName(item.salesUserName, item.salesUserId)),
|
||||
field('地区经理', personName(item.regionManagerUserName || item.managerName, item.regionManagerUserId)),
|
||||
field('运输方式', item.transportModeLabel || item.transportMode),
|
||||
field('新生儿性别', label(NEWBORN_SEX_LABELS, item.newbornSex)),
|
||||
field('新生儿体重', item.newbornWeightGram),
|
||||
field('分娩方式', label(DELIVERY_MODE_LABELS, item.deliveryMode)),
|
||||
field('胎次', item.birthOrder),
|
||||
field('母血采集时间', item.maternalBloodCollectTime, { wide: true }),
|
||||
field('知情同意书', attachmentPresence(item.consentFormUrls)),
|
||||
field('传染病检测报告', attachmentPresence(item.infectiousDiseaseReportUrls)),
|
||||
field('协议书', attachmentPresence(item.attachmentUrls)),
|
||||
field('备注', item.remark, { wide: true })
|
||||
],
|
||||
actions: ['view', ...actions]
|
||||
}
|
||||
}
|
||||
return {
|
||||
title: text(item.motherName || item.customerName),
|
||||
subtitle: `${label(SOURCE_LABELS, item.source)} · ${text(item.sampleCode)}`,
|
||||
status,
|
||||
fields: [
|
||||
field('状态', status, { tag: true }),
|
||||
field(item.source === 'research_donation' ? '捐赠日期' : '登记日期', item.registerDate || item.donationDate),
|
||||
field('登记日期', item.registerDate || item.donationDate),
|
||||
field('母亲姓名', item.motherName || item.customerName),
|
||||
field('母亲电话', item.motherPhone),
|
||||
field('母亲身份证号', item.motherIdCard, { wide: true }),
|
||||
@@ -145,10 +180,10 @@ function paymentCard(item) {
|
||||
]
|
||||
})
|
||||
return {
|
||||
title: text(item.motherName), subtitle: text(item.protocolNo), status: progress,
|
||||
title: text(item.motherName), subtitle: text(item.sampleCode), status: progress,
|
||||
fields: [
|
||||
field('姓名', item.motherName), field('手机号', item.motherPhone),
|
||||
field('合同编号', item.protocolNo, { wide: true }), field('签署日期', item.signDate),
|
||||
field('样本编码', item.sampleCode, { wide: true }), field('签署日期', item.signDate),
|
||||
field('存储年限', item.storageYears), field('存储项目', item.sampleTypeName, { wide: true }),
|
||||
field('合同总额', money(item.contractAmount), { money: true }),
|
||||
field('缴费方式', label(PAY_MODE_LABELS, item.payMode), { tag: true }),
|
||||
@@ -163,39 +198,6 @@ function paymentCard(item) {
|
||||
}
|
||||
}
|
||||
|
||||
function progressLabel(item, key, fallback) {
|
||||
const value = item.progress?.[key]?.label
|
||||
return value ? label({}, value) : fallback
|
||||
}
|
||||
|
||||
function sampleCard(item) {
|
||||
const status = label(PROTOCOL_STATUS_LABELS, item.protocolStatus || item.donationStatus || item.statusLabel)
|
||||
return {
|
||||
title: text(item.motherName || item.customerName), subtitle: text(item.sampleCode), status,
|
||||
fields: [
|
||||
field('协议状态', status, { tag: true }), field('预产期', item.expectedDeliveryDate),
|
||||
field('母亲姓名', item.motherName || item.customerName), field('新生儿姓名', item.newbornName),
|
||||
field('样本编码', item.sampleCode, { wide: true }), field('实验室入库编码', item.labStorageCode, { wide: true }),
|
||||
field('样本类型', referenceName(item.sampleTypeName, item.sampleTypeId), { wide: true })
|
||||
],
|
||||
progressTags: [
|
||||
`采集 · ${progressLabel(item, 'collection', '未采集')}`,
|
||||
`接收 · ${progressLabel(item, 'reception', '未接收')}`,
|
||||
`质检 · ${progressLabel(item, 'qc', '未完成')}`,
|
||||
`入库 · ${progressLabel(item, 'storage', '未入库')}`,
|
||||
...(item.source === 'cell_storage' ? [
|
||||
`储存证 · ${item.storageCert?.label ? label({}, item.storageCert.label) : '未办理'}`,
|
||||
`保险 · ${item.insurance?.label ? label({}, item.insurance.label) : '未办理'}`
|
||||
] : [])
|
||||
],
|
||||
actions: [
|
||||
'view',
|
||||
...(item.source === 'cell_storage' ? ['view-storage-qc'] : []),
|
||||
...allowed(item, ['storage-cert', 'insurance'])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function freightCard(role, item) {
|
||||
const first = item.items?.[0] || {}
|
||||
const transportMode = label({}, item.transportModeLabel || item.transportMode)
|
||||
@@ -223,7 +225,6 @@ export function buildMarketCard(module, role, item = {}) {
|
||||
if (module === 'protocol') return protocolCard(item)
|
||||
if (module === 'payment-chase') return chaseCard(item)
|
||||
if (module === 'payment') return paymentCard(item)
|
||||
if (module === 'sample') return sampleCard(item)
|
||||
if (module === 'freight') return freightCard(role, item)
|
||||
return { title: text(item.title || item.name || item.code), subtitle: '', status: '', fields: [], actions: ['view'] }
|
||||
}
|
||||
@@ -19,15 +19,6 @@ test('remaining modules use the approved search placeholders', () => {
|
||||
)
|
||||
assert.equal(marketSearchPlaceholder('payment-chase'), '搜索协议号 / 客户 / 样本编码')
|
||||
assert.equal(marketSearchPlaceholder('payment'), '搜索协议号 / 客户 / 样本编码')
|
||||
assert.equal(marketSearchPlaceholder('sample'), '搜索母亲姓名 / 样本编码')
|
||||
assert.equal(
|
||||
marketSearchPlaceholder('sample', 'cell_storage'),
|
||||
'搜索母亲姓名 / 样本编码'
|
||||
)
|
||||
assert.equal(
|
||||
marketSearchPlaceholder('sample', 'research_donation'),
|
||||
'搜索母亲姓名 / 捐赠编号 / 样本编码'
|
||||
)
|
||||
assert.equal(marketSearchPlaceholder('freight'), '搜索批次号 / 母亲姓名 / 样本编码')
|
||||
})
|
||||
|
||||
@@ -56,6 +47,52 @@ test('protocol card exposes web parity fields without truncating to three rows',
|
||||
}).status, '转细胞存储')
|
||||
})
|
||||
|
||||
test('research donation protocol card matches excel-parity field set', () => {
|
||||
const card = buildMarketCard('protocol', 'specialist', {
|
||||
source: 'research_donation',
|
||||
motherName: '曹陆双',
|
||||
sampleCode: 'S-D1',
|
||||
donationStatus: 'sdfq',
|
||||
sampleCollectTime: '2025-08-29 12:27:00',
|
||||
monthlyVerifyNo: '202508001',
|
||||
labStorageCode: 'A0000001',
|
||||
voidDesc: '母血乙肝阳性',
|
||||
sampleTypeName: '围产期造血干细胞',
|
||||
regionName: '亳州',
|
||||
hospitalName: '涡阳县人民医院',
|
||||
newbornDeliveryTime: '2025-08-29 12:26:00',
|
||||
salesUserName: '杨莉莉',
|
||||
regionManagerUserName: '张颖',
|
||||
managerName: '张颖',
|
||||
transportMode: 'kdys',
|
||||
transportModeLabel: '快递运输',
|
||||
newbornSex: '0',
|
||||
newbornWeightGram: 3000,
|
||||
deliveryMode: 'sc',
|
||||
birthOrder: 1,
|
||||
maternalBloodCollectTime: '2025-08-29 13:30:00',
|
||||
consentFormUrls: 'https://x/a.pdf',
|
||||
infectiousDiseaseReportUrls: '',
|
||||
attachmentUrls: 'https://x/b.pdf',
|
||||
remark: '备注一',
|
||||
allowedActions: ['edit']
|
||||
})
|
||||
const labels = card.fields.map((f) => f.label)
|
||||
for (const label of [
|
||||
'当月核量号', '实验室流转编号', '协议状态', '废弃原因', '样本类型',
|
||||
'采集地区', '采集医院', '分娩时间', '采集时间', '市场专员', '地区经理',
|
||||
'运输方式', '新生儿性别', '新生儿体重', '分娩方式', '胎次', '母血采集时间',
|
||||
'知情同意书', '传染病检测报告', '协议书', '备注'
|
||||
]) {
|
||||
assert.ok(labels.includes(label), `missing ${label}`)
|
||||
}
|
||||
assert.equal(card.fields.find((f) => f.label === '当月核量号').value, '202508001')
|
||||
assert.equal(card.fields.find((f) => f.label === '知情同意书').value, '有')
|
||||
assert.equal(card.fields.find((f) => f.label === '传染病检测报告').value, '—')
|
||||
assert.equal(card.fields.find((f) => f.label === '协议书').value, '有')
|
||||
assert.ok(!labels.includes('是否同存'))
|
||||
})
|
||||
|
||||
test('payment card formats summary totals and progress', () => {
|
||||
const card = buildMarketCard('payment', 'manager', {
|
||||
protocolNo: 'P-1', motherName: '周雨桐', sampleCode: 'S-1', payMode: 'fq',
|
||||
@@ -67,6 +104,8 @@ test('payment card formats summary totals and progress', () => {
|
||||
allowedActions: ['register-transfer']
|
||||
})
|
||||
assert.equal(card.status, '部分缴费')
|
||||
assert.equal(card.subtitle, 'S-1')
|
||||
assert.ok(card.fields.some((field) => field.label === '样本编码' && field.value === 'S-1'))
|
||||
assert.ok(card.fields.some((field) => field.label === '签署日期' && field.value === '2026-10-01'))
|
||||
assert.ok(card.fields.some((field) => field.label === '存储项目' && field.value === '脐带血'))
|
||||
assert.ok(card.fields.some((field) => field.label === '第1期·应缴费金额(元)' && field.value === '¥3,000.00'))
|
||||
@@ -101,8 +140,6 @@ test('specialist freight card masks batch-wide counts while manager sees visible
|
||||
|
||||
test('action labels cover module-specific operations', () => {
|
||||
assert.equal(actionLabel('audit'), '审核')
|
||||
assert.equal(actionLabel('storage-cert'), '登记储存证')
|
||||
assert.equal(actionLabel('insurance'), '登记保险')
|
||||
assert.equal(actionLabel('link'), '关联样本')
|
||||
assert.equal(actionLabel('unlink'), '取消运费')
|
||||
assert.equal(actionLabel('internal-action-code'), '操作')
|
||||
@@ -132,19 +169,9 @@ test('list cards hide unresolved reference and dictionary codes while retaining
|
||||
assert.equal(freight.fields.find((field) => field.label === '样本编码').value, 'S-KEEP-2')
|
||||
|
||||
const payment = buildMarketCard('payment', 'manager', {
|
||||
protocolNo: 'P-KEEP-2', payMode: 'raw-pay-mode'
|
||||
protocolNo: 'P-KEEP-2', sampleCode: 'S-KEEP-2', payMode: 'raw-pay-mode'
|
||||
})
|
||||
assert.equal(payment.subtitle, 'P-KEEP-2')
|
||||
assert.equal(payment.subtitle, 'S-KEEP-2')
|
||||
assert.equal(payment.fields.find((field) => field.label === '样本编码').value, 'S-KEEP-2')
|
||||
assert.equal(payment.fields.find((field) => field.label === '缴费方式').value, '未知')
|
||||
|
||||
const sample = buildMarketCard('sample', 'specialist', {
|
||||
sampleCode: 'S-KEEP-3', protocolStatus: 'raw-status', sampleTypeId: 'type-raw',
|
||||
progress: { collection: { label: 'raw-progress' } },
|
||||
source: 'cell_storage', storageCert: { label: 'raw-cert-status' }
|
||||
})
|
||||
assert.equal(sample.subtitle, 'S-KEEP-3')
|
||||
assert.equal(sample.status, '未知')
|
||||
assert.equal(sample.fields.find((field) => field.label === '样本类型').value, '未知')
|
||||
assert.ok(sample.progressTags.includes('采集 · 未知'))
|
||||
assert.ok(sample.progressTags.includes('储存证 · 未知'))
|
||||
})
|
||||
Reference in new issue
Block a user