fix(mobile-oa-h5): finish storage-service tag tone parity for market details
Wire detail header statusTone for protocol/payment/freight/chase from the registry mirror, stop hardcoding primary on nested tags, and map 已过期 to warning so title and field colors stay consistent. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
d355cd0640
commit
48dcf991dc
11 files changed
+270
-260
No files matched your search
@@ -124,7 +124,7 @@
|
||||
<van-tag
|
||||
v-else-if="field.tag"
|
||||
class="market-tag"
|
||||
:type="field.tagType || 'primary'"
|
||||
:type="field.tagType || resolveStatusTone(field.value)"
|
||||
round
|
||||
:title="field.value"
|
||||
>
|
||||
@@ -145,6 +145,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { resolveStatusTone } from '../status-tone.js'
|
||||
import MarketAttachmentCards from './MarketAttachmentCards.vue'
|
||||
|
||||
defineOptions({ name: 'MarketDetailNestedCard' })
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
:model-value="field.value"
|
||||
:editable="false"
|
||||
/>
|
||||
<van-tag v-else-if="field.tag" class="market-tag" :type="field.tagType || 'primary'" round :title="field.value">
|
||||
<van-tag v-else-if="field.tag" class="market-tag" :type="field.tagType || resolveStatusTone(field.value)" round :title="field.value">
|
||||
{{ field.value }}
|
||||
</van-tag>
|
||||
<span v-else>{{ field.value }}</span>
|
||||
|
||||
@@ -287,6 +287,7 @@ import {
|
||||
PROTOCOL_ATTACHMENT_MAX_BYTES
|
||||
} from '../attachment-upload-policy.js'
|
||||
import MarketAttachmentCards from './MarketAttachmentCards.vue'
|
||||
import { resolveStatusTag, payStatus } from '../status-tag-registry.js'
|
||||
|
||||
const props = defineProps({
|
||||
payment: { type: Object, default: () => ({}) },
|
||||
@@ -360,21 +361,11 @@ function payModeLabel(value) {
|
||||
}
|
||||
|
||||
function statusLabel(value) {
|
||||
return {
|
||||
dfj: '已付款',
|
||||
jfqrz: '付款确认中',
|
||||
yjf: '付款完成',
|
||||
tfqrz: '退费确认中',
|
||||
ytf: '已退费'
|
||||
}[String(value ?? '')] || '状态异常'
|
||||
return resolveStatusTag(payStatus, value).label
|
||||
}
|
||||
|
||||
function statusTone(value) {
|
||||
const status = String(value ?? '')
|
||||
if (status === 'yjf') return 'success'
|
||||
if (status === 'jfqrz') return 'warning'
|
||||
if (status === 'dfj') return 'primary'
|
||||
return 'danger'
|
||||
return resolveStatusTag(payStatus, value).tagType
|
||||
}
|
||||
|
||||
function transferTypeLabel(value) {
|
||||
@@ -576,6 +567,8 @@ function removeAttachment(detailIndex, attachmentIndex) {
|
||||
.protocol-v1-pay__details-head .van-button,
|
||||
.protocol-v1-pay__delete {
|
||||
min-height: 44px;
|
||||
border-radius: 12px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.protocol-v1-pay__detail.is-locked {
|
||||
|
||||
@@ -539,7 +539,7 @@ test('nested market detail cards use explicit labels instead of API property nam
|
||||
const detailSection = source('./components/MarketDetailSection.vue')
|
||||
|
||||
assert.match(detailSection, /cards:/)
|
||||
assert.match(detailSection, /field\.tagType \|\| 'primary'/)
|
||||
assert.match(detailSection, /field\.tagType \|\| resolveStatusTone\(field\.value\)/)
|
||||
assert.doesNotMatch(detailSection, /function flattenFields/)
|
||||
})
|
||||
|
||||
|
||||
@@ -93,6 +93,9 @@ test('protocol summary status resolves real codes without exposing unknown codes
|
||||
assert.equal(protocol.statusLabel({ source: 'research_donation', basic: { donationStatus: 'yzf' } }), '已作废')
|
||||
assert.equal(protocol.statusLabel({ source: 'cell_storage', basic: { protocolStatus: 'raw-status' } }), '未知')
|
||||
assert.equal(protocol.statusLabel({ source: 'cell_storage', basic: { protocolStatus: '' } }), '—')
|
||||
assert.equal(protocol.statusTone({ source: 'cell_storage', basic: { protocolStatus: 'ygq' } }), 'warning')
|
||||
assert.equal(protocol.statusTone({ source: 'research_donation', basic: { donationStatus: 'ygq' } }), 'warning')
|
||||
assert.equal(protocol.statusTone({ source: 'cell_storage', protocol: { protocolStatus: 'sxz' } }), 'primary')
|
||||
})
|
||||
|
||||
test('protocol adapters preserve nested detail sections', () => {
|
||||
@@ -233,6 +236,34 @@ test('payment detail presents real backend progress and combined pay mode in sum
|
||||
assert.equal(summary.fields.find((field) => field.label === '缴费进度').value, '部分已缴')
|
||||
})
|
||||
|
||||
test('payment and freight detail headers use registry tagType instead of Chinese heuristics', () => {
|
||||
const payment = getMarketModule('payment')
|
||||
assert.equal(payment.statusLabel({ progressStatus: 'dfj' }), '待缴费')
|
||||
assert.equal(payment.statusTone({ progressStatus: 'dfj' }), 'info')
|
||||
assert.equal(payment.statusTone({ progressStatus: 'yjq' }), 'success')
|
||||
|
||||
const freight = getMarketModule('freight')
|
||||
assert.equal(
|
||||
freight.statusTone({ items: [{ sampleSource: 'research_donation' }] }),
|
||||
'warning'
|
||||
)
|
||||
assert.equal(
|
||||
freight.statusTone({ items: [{ sampleSource: 'cell_storage' }] }),
|
||||
'primary'
|
||||
)
|
||||
|
||||
const chase = getMarketModule('payment-chase')
|
||||
assert.equal(chase.statusTone({ progressStatus: 'dfj' }), 'info')
|
||||
assert.equal(
|
||||
chase.statusTone({
|
||||
chaseView: 'protocol',
|
||||
source: 'cell_storage',
|
||||
basic: { protocolStatus: 'ygq' }
|
||||
}),
|
||||
'warning'
|
||||
)
|
||||
})
|
||||
|
||||
test('payment progress dfj aligns with web-admin samplePaymentProgress 待缴费', () => {
|
||||
const payment = getMarketModule('payment')
|
||||
const byCode = payment.detailSections({ progressStatus: 'dfj' })
|
||||
|
||||
@@ -15,6 +15,11 @@ function person(name, id) {
|
||||
return referenceId ? '未知人员' : '—'
|
||||
}
|
||||
|
||||
function freightHeaderTag(detail) {
|
||||
const first = (detail?.items || [])[0] || {}
|
||||
return resolveStatusTag(receptionSource, first.sampleSource || detail?.sampleSource || detail?.source)
|
||||
}
|
||||
|
||||
function money(value) {
|
||||
const amount = Number(value)
|
||||
if (!Number.isFinite(amount)) return '—'
|
||||
@@ -80,7 +85,6 @@ export default {
|
||||
statusTone: source.tagType,
|
||||
fields: [
|
||||
{ label: '来源', value: source.label, tag: true, tagType: source.tagType },
|
||||
{ label: '协议单号', value: item?.protocolNo || '—' },
|
||||
{ label: '样本编码', value: item?.sampleCode || '—' },
|
||||
{ label: '样本类型', value: item?.sampleTypeName || '—' },
|
||||
{ label: '母亲姓名', value: item?.motherName || '—' },
|
||||
@@ -91,6 +95,12 @@ export default {
|
||||
}
|
||||
]
|
||||
},
|
||||
statusLabel(detail) {
|
||||
return freightHeaderTag(detail).label
|
||||
},
|
||||
statusTone(detail) {
|
||||
return freightHeaderTag(detail).tagType
|
||||
},
|
||||
usesPagedSampleOptions(action) {
|
||||
return ['create', 'link'].includes(action)
|
||||
},
|
||||
|
||||
@@ -32,7 +32,8 @@ export default {
|
||||
options: [
|
||||
{ text: '趸交', value: 'dj' },
|
||||
{ text: '分期', value: 'fq' },
|
||||
{ text: '分改趸', value: 'fgd' }
|
||||
{ text: '分改趸', value: 'fgd' },
|
||||
{ text: '趸交+分期', value: 'djfq' }
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -46,5 +47,15 @@ export default {
|
||||
return detail?.chaseView === 'protocol'
|
||||
? protocolModule.detailSections(detail)
|
||||
: paymentModule.detailSections(detail)
|
||||
},
|
||||
statusLabel(detail) {
|
||||
return detail?.chaseView === 'protocol'
|
||||
? protocolModule.statusLabel(detail)
|
||||
: paymentModule.statusLabel(detail)
|
||||
},
|
||||
statusTone(detail) {
|
||||
return detail?.chaseView === 'protocol'
|
||||
? protocolModule.statusTone(detail)
|
||||
: paymentModule.statusTone(detail)
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,12 @@ export default {
|
||||
}
|
||||
]
|
||||
},
|
||||
statusLabel(detail) {
|
||||
return progressTag(detail?.progressStatus || detail?.paymentProgress).label
|
||||
},
|
||||
statusTone(detail) {
|
||||
return progressTag(detail?.progressStatus || detail?.paymentProgress).tagType
|
||||
},
|
||||
initialForm(detail, target = {}) {
|
||||
const transfer = (detail?.schedules || [])
|
||||
.flatMap((row) => row.transfers || [])
|
||||
|
||||
@@ -22,6 +22,13 @@ const SAMPLE_STATUS_LABELS = Object.freeze({
|
||||
const VOID_TYPE_LABELS = Object.freeze({
|
||||
khhc: '客户毁存', jcbhg: '检测不合格'
|
||||
})
|
||||
const STATUS_CHANGE_TYPE_LABELS = Object.freeze({
|
||||
activate: '生效',
|
||||
expire: '过期',
|
||||
void: '作废',
|
||||
to_research: '转科研',
|
||||
to_storage: '转细胞存储'
|
||||
})
|
||||
const TRANSFER_TYPE_LABELS = Object.freeze({
|
||||
wxzz: '微信转账', wx: '微信转账', wechat: '微信转账',
|
||||
zzbzz: '支付宝转账', zfb: '支付宝转账', alipay: '支付宝转账',
|
||||
@@ -69,11 +76,106 @@ function auditTag(code) {
|
||||
return resolveStatusTag(auditStatus, code)
|
||||
}
|
||||
|
||||
function voidTypeText(source) {
|
||||
const backendLabel = String(source?.voidTypeLabel || '').trim()
|
||||
if (backendLabel) return backendLabel
|
||||
const code = String(source?.voidType || '').trim()
|
||||
return VOID_TYPE_LABELS[code] || code || '—'
|
||||
function statusChangeTypeTone(changeType) {
|
||||
if (changeType === 'void') return 'danger'
|
||||
if (changeType === 'expire') return 'warning'
|
||||
if (changeType === 'activate') return 'success'
|
||||
return 'primary'
|
||||
}
|
||||
|
||||
function statusChangeFlowText(row, statusRegistry) {
|
||||
const fromLabel = row?.fromStatus
|
||||
? resolveStatusTag(statusRegistry, row.fromStatus).label
|
||||
: ''
|
||||
const toLabel = resolveStatusTag(statusRegistry, row?.toStatus).label
|
||||
if (fromLabel) return `${fromLabel} → ${toLabel}`
|
||||
return toLabel || '—'
|
||||
}
|
||||
|
||||
function statusChangeDescText(row) {
|
||||
const changeType = String(row?.changeType || '')
|
||||
const desc = String(row?.changeDesc || '').trim()
|
||||
if (changeType === 'void') {
|
||||
const voidLabel =
|
||||
VOID_TYPE_LABELS[String(row?.voidType || '')] ||
|
||||
String(row?.voidTypeLabel || row?.voidType || '').trim()
|
||||
if (voidLabel && desc) return `作废类型:${voidLabel};${desc}`
|
||||
if (voidLabel) return `作废类型:${voidLabel}`
|
||||
}
|
||||
return desc || '—'
|
||||
}
|
||||
|
||||
function buildStatusChangeCards(rows, statusRegistry) {
|
||||
return (rows || []).map((row, index) => {
|
||||
const changeType = String(row?.changeType || '')
|
||||
return {
|
||||
key: String(row?.id || `status-${index}`),
|
||||
title: `变更 ${index + 1}`,
|
||||
statusText: STATUS_CHANGE_TYPE_LABELS[changeType] || changeType || '变更',
|
||||
statusTone: statusChangeTypeTone(changeType),
|
||||
fields: [
|
||||
{ label: '变更时间', value: value(row, 'changeTime') },
|
||||
{ label: '状态流转', value: statusChangeFlowText(row, statusRegistry) },
|
||||
{ label: '变更说明', value: statusChangeDescText(row) },
|
||||
{ label: '操作人', value: person(row?.operatorUserName, row?.operatorUserId) }
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 无 statusChanges 时,从主表快照字段合成卡片(对齐方案 A 单行展示) */
|
||||
function synthesizeStatusChangesFromBasic(basic, source) {
|
||||
const rows = []
|
||||
if (basic?.effectiveTime) {
|
||||
rows.push({
|
||||
id: 'snap-activate',
|
||||
changeType: 'activate',
|
||||
toStatus: 'sxz',
|
||||
changeTime: basic.effectiveTime,
|
||||
changeDesc: basic.effectiveDesc || ''
|
||||
})
|
||||
}
|
||||
if (basic?.expireTime) {
|
||||
rows.push({
|
||||
id: 'snap-expire',
|
||||
changeType: 'expire',
|
||||
toStatus: 'ygq',
|
||||
changeTime: basic.expireTime,
|
||||
changeDesc: basic.expireDesc || ''
|
||||
})
|
||||
}
|
||||
if (basic?.voidTime) {
|
||||
rows.push({
|
||||
id: 'snap-void',
|
||||
changeType: 'void',
|
||||
toStatus: 'yzf',
|
||||
changeTime: basic.voidTime,
|
||||
changeDesc: basic.voidDesc || '',
|
||||
voidType: basic.voidType || '',
|
||||
voidTypeLabel: basic.voidTypeLabel || ''
|
||||
})
|
||||
}
|
||||
if (source === 'research_donation') {
|
||||
const convertTime = basic?.convertTime || basic?.toStorageTime
|
||||
if (convertTime) {
|
||||
rows.push({
|
||||
id: 'snap-to-storage',
|
||||
changeType: 'to_storage',
|
||||
toStatus: 'zckc',
|
||||
changeTime: convertTime,
|
||||
changeDesc: basic?.convertDesc || basic?.toStorageDesc || ''
|
||||
})
|
||||
}
|
||||
} else if (basic?.toResearchTime) {
|
||||
rows.push({
|
||||
id: 'snap-to-research',
|
||||
changeType: 'to_research',
|
||||
toStatus: 'zky',
|
||||
changeTime: basic.toResearchTime,
|
||||
changeDesc: basic.toResearchDesc || ''
|
||||
})
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
function person(name, id) {
|
||||
@@ -110,6 +212,26 @@ function transferAttachmentValue(transfer) {
|
||||
return transfer?.attachments || transfer?.transferAttachmentFiles || transfer?.transferAttachments || ''
|
||||
}
|
||||
|
||||
function refundRecordAttachmentValue(row) {
|
||||
if (Array.isArray(row?.refundAttachmentFiles) && row.refundAttachmentFiles.length) {
|
||||
return row.refundAttachmentFiles
|
||||
}
|
||||
return row?.refundAttachments || ''
|
||||
}
|
||||
|
||||
function refundRecordCards(records) {
|
||||
return (records || []).map((row, index) => ({
|
||||
key: String(row?.id || `refund-${index}`),
|
||||
title: `退费登记 ${index + 1}`,
|
||||
fields: [
|
||||
{ label: '退费金额', value: value(row, 'refundAmount') },
|
||||
{ label: '退费时间', value: value(row, 'refundTime') },
|
||||
{ label: '备注', value: value(row, 'refundRemark') },
|
||||
{ label: '附件', type: 'attachments', value: refundRecordAttachmentValue(row) }
|
||||
]
|
||||
}))
|
||||
}
|
||||
|
||||
function transferTypeText(transfer) {
|
||||
const backendLabel = String(transfer?.transferTypeLabel || '').trim()
|
||||
if (backendLabel) return backendLabel
|
||||
@@ -118,115 +240,6 @@ function transferTypeText(transfer) {
|
||||
return TRANSFER_TYPE_LABELS[code] || (/[㐀-鿿]/u.test(code) ? code : code)
|
||||
}
|
||||
|
||||
function namedItems(items) {
|
||||
return (items || [])
|
||||
.map((item) => typeof item === 'string'
|
||||
? item
|
||||
: item?.itemName || item?.name || item?.itemCode || item?.id)
|
||||
.filter(Boolean)
|
||||
.join('、') || '—'
|
||||
}
|
||||
|
||||
function qcResultCard(result, index, prefix) {
|
||||
const unit = String(result?.paramUnit || '').trim()
|
||||
return {
|
||||
key: String(result?.id || `${prefix}-result-${index}`),
|
||||
title: `检测结果 ${index + 1}`,
|
||||
fields: [
|
||||
{ label: '参数名称', value: value(result, 'paramName') },
|
||||
{ label: '参数单位', value: unit || '—' },
|
||||
{ label: '参数值', value: value(result, 'paramValue') }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function qcTaskCard(task, index, prefix) {
|
||||
return {
|
||||
key: String(task?.id || `${prefix}-task-${index}`),
|
||||
title: task?.itemName || task?.taskName || task?.taskNo || `任务 ${index + 1}`,
|
||||
statusText: value(task, 'taskStatusLabel'),
|
||||
fields: [
|
||||
{ label: '任务号', value: value(task, 'taskNo') },
|
||||
{ label: '任务类型', value: value(task, 'taskTypeLabel') },
|
||||
{ label: '检测项目', value: value(task, 'itemName') },
|
||||
{ label: '检测机构', value: value(task, 'companyName') },
|
||||
{ label: '任务状态', value: value(task, 'taskStatusLabel'), tag: true },
|
||||
{ label: '结论', value: value(task, 'conclusionLabel'), tag: true },
|
||||
{ label: '完成时间', value: value(task, 'completedTime') },
|
||||
{ label: '备注', value: value(task, 'remark') },
|
||||
{ label: '任务附件', value: task?.attachmentFiles || task?.thirdPartyAttachments || '', type: 'attachments' }
|
||||
],
|
||||
cards: (task?.results || []).map((result, resultIndex) =>
|
||||
qcResultCard(result, resultIndex, `${prefix}-task-${index}`)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function qcBatchCard(batch, index, prefix) {
|
||||
return {
|
||||
key: String(batch?.id || `${prefix}-batch-${index}`),
|
||||
title: `检测批次 ${index + 1}`,
|
||||
fields: [
|
||||
{ label: '批次编号', value: value(batch, 'batchNo') },
|
||||
{ label: '批次名称', value: value(batch, 'batchName') },
|
||||
{ label: '负责人', value: value(batch, 'assigneeUserNames') },
|
||||
{ label: '实验室检测', value: batch?.hasLab ? '是' : '否' },
|
||||
{ label: '第三方检测', value: batch?.hasThirdParty ? '是' : '否' },
|
||||
{ label: '实验室项目', value: namedItems(batch?.labItems || batch?.labItemIds) },
|
||||
{ label: '第三方项目', value: namedItems(batch?.thirdPartyItems || batch?.thirdPartyItemIds) },
|
||||
{ label: '任务总数', value: value(batch, 'taskCount') },
|
||||
{ label: '已完成任务数', value: value(batch, 'completedTaskCount') }
|
||||
],
|
||||
cards: (batch?.tasks || []).map((task, taskIndex) =>
|
||||
qcTaskCard(task, taskIndex, `${prefix}-batch-${index}`)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function qcCard(info, title, index = 0) {
|
||||
return {
|
||||
key: String(info?.id || `${title}-${index}`),
|
||||
title,
|
||||
statusText: value(info, 'workOrderStatusLabel'),
|
||||
fields: [
|
||||
{ label: '工单号', value: value(info, 'workOrderNo') },
|
||||
{ label: '业务类型', value: value(info, 'qcBizTypeLabel') },
|
||||
{ label: '工单状态', value: value(info, 'workOrderStatusLabel'), tag: true },
|
||||
{ label: '触发来源', value: value(info, 'triggerSourceLabel') },
|
||||
{ label: '质检对象编码', value: value(info, 'cellProductCode') },
|
||||
{ label: '质检对象名称', value: value(info, 'cellProductName') },
|
||||
{ label: '生产工单号', value: value(info, 'productionWorkOrderNo') },
|
||||
{ label: '包含实验室检测', value: info?.hasLab ? '是' : '否' },
|
||||
{ label: '包含第三方检测', value: info?.hasThirdParty ? '是' : '否' },
|
||||
{ label: '实验室检测项目', value: namedItems(info?.labItems) },
|
||||
{ label: '第三方检测项目', value: namedItems(info?.thirdPartyItems) },
|
||||
{ label: '配置时间', value: value(info, 'configuredTime') },
|
||||
{ label: '检测批次', value: (info?.inspectionBatches || []).map((row) => row?.batchNo || row?.batchName).filter(Boolean).join('、') || '—' }
|
||||
],
|
||||
cards: [
|
||||
...(info?.inspectionBatches || []).map((batch, batchIndex) =>
|
||||
qcBatchCard(batch, batchIndex, `${title}-${index}`)
|
||||
),
|
||||
...(info?.tasks || []).map((task, taskIndex) =>
|
||||
qcTaskCard(task, taskIndex, `${title}-${index}`)
|
||||
)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function productionMaterialCard(item, index, kind, prefix) {
|
||||
const input = kind === 'input'
|
||||
return {
|
||||
key: String(item?.id || `${prefix}-${kind}-${index}`),
|
||||
title: `${input ? '投入物' : '产出物'} ${index + 1}`,
|
||||
fields: [
|
||||
{ label: input ? '投入物类型' : '产出物类型', value: value(item, input ? 'inputType' : 'outputType') },
|
||||
{ label: input ? '投入物编码' : '产出物编码', value: value(item, input ? 'inputCode' : 'outputCode') },
|
||||
{ label: input ? '投入物名称' : '产出物名称', value: value(item, input ? 'inputName' : 'outputName') }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function sampleLifecycleCards(item, source) {
|
||||
const cards = []
|
||||
const reception = item?.sampleReception
|
||||
@@ -270,41 +283,6 @@ function sampleLifecycleCards(item, source) {
|
||||
]
|
||||
})
|
||||
}
|
||||
if (item?.qcInfo) cards.push(qcCard(item.qcInfo, '门控质检'))
|
||||
;(item?.processQcInfoList || []).forEach((info, index) => cards.push(qcCard(info, `过程质检 ${index + 1}`, index)))
|
||||
const production = item?.productionInfo
|
||||
if (production) {
|
||||
cards.push({
|
||||
key: `${item?.id || item?.sampleCode}-production`,
|
||||
title: '生产信息',
|
||||
statusText: value(production, 'workOrderStatusLabel'),
|
||||
fields: [
|
||||
{ label: '工单号', value: value(production, 'workOrderNo') },
|
||||
{ label: '工单状态', value: value(production, 'workOrderStatusLabel'), tag: true }
|
||||
],
|
||||
cards: (production?.tasks || []).map((task, index) => ({
|
||||
key: String(task?.id || `production-task-${index}`),
|
||||
title: `生产任务 ${index + 1}`,
|
||||
statusText: value(task, 'taskStatusLabel'),
|
||||
fields: [
|
||||
{ label: '任务名称', value: value(task, 'taskName') },
|
||||
{ label: '任务号', value: value(task, 'taskNo') },
|
||||
{ label: '任务状态', value: value(task, 'taskStatusLabel'), tag: true },
|
||||
{ label: '开始时间', value: value(task, 'startedTime') },
|
||||
{ label: '完成时间', value: value(task, 'completedTime') },
|
||||
{ label: '生产结论', value: value(task, 'conclusionLabel'), tag: true }
|
||||
],
|
||||
cards: [
|
||||
...(task?.inputs || []).map((input, inputIndex) =>
|
||||
productionMaterialCard(input, inputIndex, 'input', `production-task-${index}`)
|
||||
),
|
||||
...(task?.outputs || []).map((output, outputIndex) =>
|
||||
productionMaterialCard(output, outputIndex, 'output', `production-task-${index}`)
|
||||
)
|
||||
]
|
||||
}))
|
||||
})
|
||||
}
|
||||
const release = item?.storageReleaseInfo
|
||||
if (release) {
|
||||
cards.push({
|
||||
@@ -434,6 +412,13 @@ export default {
|
||||
: basic?.protocolStatus
|
||||
return bizStatusTag(status, detail?.source).label
|
||||
},
|
||||
statusTone(detail) {
|
||||
const basic = detail?.protocol || detail?.basic || detail || {}
|
||||
const status = detail?.source === 'research_donation'
|
||||
? basic?.donationStatus
|
||||
: basic?.protocolStatus
|
||||
return bizStatusTag(status, detail?.source).tagType
|
||||
},
|
||||
detailSections(detail) {
|
||||
if (Array.isArray(detail?.sections)) {
|
||||
return detail.sections.map((item) => ({ ...item, fields: item?.fields || [], cards: item?.cards || [] }))
|
||||
@@ -442,26 +427,29 @@ export default {
|
||||
const basic = detail?.protocol || detail?.basic || detail || {}
|
||||
const statusKey = source === 'research_donation' ? 'donationStatus' : 'protocolStatus'
|
||||
const dateKey = source === 'research_donation' ? 'donationDate' : 'registerDate'
|
||||
const numberKey = source === 'research_donation' ? 'donationNo' : 'protocolNo'
|
||||
const bizStatus = bizStatusTag(basic?.[statusKey], source)
|
||||
const isDonation = source === 'research_donation'
|
||||
const values = [
|
||||
{
|
||||
key: 'protocol',
|
||||
title: source === 'research_donation' ? '捐赠信息' : '协议信息',
|
||||
fields: [
|
||||
{ label: source === 'research_donation' ? '捐赠编号' : '协议编号', value: value(basic, numberKey) },
|
||||
{
|
||||
label: source === 'research_donation' ? '捐赠状态' : '协议状态',
|
||||
value: bizStatus.label,
|
||||
tag: true,
|
||||
tagType: bizStatus.tagType
|
||||
},
|
||||
{ label: source === 'research_donation' ? '捐赠日期' : '登记日期', value: value(basic, dateKey) },
|
||||
...(source === 'cell_storage' ? [{ label: '协议总金额', value: value(basic, 'protocolTotalAmount') }] : []),
|
||||
{ label: '备注', value: value(basic, 'remark') },
|
||||
{ label: '创建时间', value: value(basic, 'createTime') },
|
||||
{ label: '更新时间', value: value(basic, 'updateTime') }
|
||||
],
|
||||
title: isDonation ? '基本信息' : '协议信息',
|
||||
fields: isDonation
|
||||
? [
|
||||
{ label: '状态', value: bizStatus.label, tag: true, tagType: bizStatus.tagType },
|
||||
{ label: '母亲姓名', value: value(detail?.customer, 'motherName') },
|
||||
{ label: '捐赠日期', value: value(basic, dateKey) },
|
||||
{ label: '创建时间', value: value(basic, 'createTime') },
|
||||
{ label: '备注', value: value(basic, 'remark') }
|
||||
]
|
||||
: [
|
||||
{ label: '协议状态', value: bizStatus.label, tag: true, tagType: bizStatus.tagType },
|
||||
{ label: '母亲姓名', value: value(detail?.customer, 'motherName') },
|
||||
{ label: '登记日期', value: value(basic, dateKey) },
|
||||
{ label: '协议总金额', value: value(basic, 'protocolTotalAmount') },
|
||||
{ label: '备注', value: value(basic, 'remark') },
|
||||
{ label: '创建时间', value: value(basic, 'createTime') },
|
||||
{ label: '更新时间', value: value(basic, 'updateTime') }
|
||||
],
|
||||
cards: []
|
||||
},
|
||||
{
|
||||
@@ -492,13 +480,13 @@ export default {
|
||||
['newbornIdCard', '新生儿身份证'],
|
||||
['deliveryMode', '分娩方式', { map: (item) => label(DELIVERY_LABELS, item) }],
|
||||
['birthOrder', '胎次'], ['newbornWeightGram', '新生儿体重(克)'],
|
||||
['apgar1min', '新生儿评分(1分钟)'], ['apgar5min', '新生儿评分(5分钟)'], ['remark', '备注']
|
||||
['apgar1min', '新生儿评分(1分钟)'], ['remark', '备注']
|
||||
]),
|
||||
cards: []
|
||||
},
|
||||
{
|
||||
key: 'samples',
|
||||
title: '样本信息',
|
||||
title: isDonation ? '样本及运输信息' : '样本信息',
|
||||
fields: [],
|
||||
cards: (detail?.samples || []).map((item, index) => ({
|
||||
key: String(item?.id || `sample-${index}`),
|
||||
@@ -508,7 +496,9 @@ export default {
|
||||
['sampleTypeName', '样本类型', { map: () => referenceName(item?.sampleTypeName, item?.sampleTypeId) }],
|
||||
['sampleCode', '样本编码'],
|
||||
['sampleStatus', '样本状态', { map: () => label(SAMPLE_STATUS_LABELS, item?.sampleStatusLabel || item?.sampleStatus) }],
|
||||
['price', '优惠价'], ['originalPrice', '原价'], ['storageYears', '存储年限'],
|
||||
...(source === 'cell_storage'
|
||||
? [['price', '优惠价'], ['originalPrice', '原价'], ['storageYears', '存储年限']]
|
||||
: []),
|
||||
[
|
||||
'transportMode',
|
||||
'运输方式',
|
||||
@@ -573,7 +563,7 @@ export default {
|
||||
})
|
||||
})
|
||||
}
|
||||
if (detail?.source === 'cell_storage' || detail?.payment || detail?.samplePayments) {
|
||||
if (detail?.source === 'cell_storage') {
|
||||
const samplePays = Array.isArray(detail?.samplePayments) ? detail.samplePayments : []
|
||||
if (samplePays.length) {
|
||||
values.push({
|
||||
@@ -623,50 +613,12 @@ export default {
|
||||
cards: legacyPaymentDetailCards(detail?.payment || {}, legacyDetails)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (detail?.source === 'cell_storage') {
|
||||
const cert = detail?.storageCert
|
||||
const refundRecords = Array.isArray(detail?.refundRecords) ? detail.refundRecords : []
|
||||
values.push({
|
||||
key: 'storageCert',
|
||||
title: '储存证',
|
||||
fields: cert
|
||||
? [
|
||||
{ label: '办理状态', value: Number(cert.makeStatus) === 1 || cert.handled ? '已办理' : '未办理', tag: true },
|
||||
{ label: '办理日期', value: value(cert, 'makeDate') },
|
||||
{ label: '办理人', value: person(cert.handlerUserName, cert.handlerUserId) },
|
||||
{ label: '办理时间', value: value(cert, 'handleTime') },
|
||||
{ label: '备注', value: value(cert, 'remark') },
|
||||
{
|
||||
label: '储存证图片',
|
||||
value: cert.certImageUrls || '',
|
||||
type: 'attachments'
|
||||
}
|
||||
]
|
||||
: [{ label: '办理状态', value: '暂无储存证记录' }],
|
||||
cards: []
|
||||
})
|
||||
const insurance = detail?.fullmoonTodo || {}
|
||||
values.push({
|
||||
key: 'insurance',
|
||||
title: '保险 / 满月待办',
|
||||
fields: [
|
||||
{ label: '办理状态', value: insurance.handled ? '已办理' : '未办理', tag: true },
|
||||
{ label: '满月日期', value: value(insurance, 'fullmoonDate') },
|
||||
{ label: '保险公司', value: value(insurance, 'insuranceCompanyName') },
|
||||
{ label: '保险类型', value: value(insurance, 'insuranceType') },
|
||||
{ label: '保单号', value: value(insurance, 'insurancePolicyNo') },
|
||||
{ label: '生效日', value: value(insurance, 'insuranceEffectiveDate') },
|
||||
{ label: '到期日', value: value(insurance, 'insuranceExpiryDate') },
|
||||
{ label: '办理人', value: person(insurance.handlerUserName, insurance.handlerUserId) },
|
||||
{ label: '办理时间', value: value(insurance, 'handleTime') },
|
||||
{ label: '办理备注', value: value(insurance, 'handleRemark') },
|
||||
{
|
||||
label: '保险附件',
|
||||
value: insurance.insuranceAttachments || '',
|
||||
type: 'attachments'
|
||||
}
|
||||
],
|
||||
cards: []
|
||||
key: 'refundRecords',
|
||||
title: '退费登记',
|
||||
fields: refundRecords.length ? [] : [{ label: '记录', value: '暂无退费登记' }],
|
||||
cards: refundRecordCards(refundRecords)
|
||||
})
|
||||
}
|
||||
const audits = Array.isArray(detail?.audits) ? detail.audits : []
|
||||
@@ -682,7 +634,6 @@ export default {
|
||||
statusText: audit.label,
|
||||
statusTone: audit.tagType,
|
||||
fields: [
|
||||
{ label: '审核状态', value: audit.label, tag: true, tagType: audit.tagType },
|
||||
{ label: '审核人', value: person(row?.auditorUserName, row?.auditorUserId) },
|
||||
{ label: '审核意见', value: value(row, 'auditRemark') },
|
||||
{ label: '时间', value: value(row, 'createTime') }
|
||||
@@ -690,40 +641,42 @@ export default {
|
||||
}
|
||||
})
|
||||
})
|
||||
const commonStatusFields = [
|
||||
['effectiveTime', '协议生效时间'],
|
||||
['effectiveDesc', '协议生效描述'],
|
||||
['expireTime', '协议过期时间'],
|
||||
['expireDesc', '协议过期描述'],
|
||||
['voidTime', '协议作废时间'],
|
||||
['voidDesc', '协议作废描述'],
|
||||
['voidType', '作废类型']
|
||||
]
|
||||
const sourceStatusFields = source === 'research_donation'
|
||||
? [['convertTime', '转细胞存储时间'], ['convertDesc', '转细胞存储描述']]
|
||||
: [['toResearchTime', '转科研时间'], ['toResearchDesc', '转科研描述']]
|
||||
const statusFields = [...commonStatusFields, ...sourceStatusFields].map(([key, textLabel]) => ({
|
||||
label: textLabel,
|
||||
value: key === 'voidType' ? voidTypeText(basic) : value(basic, key)
|
||||
})).filter((item) => item.value !== '—')
|
||||
values.push({
|
||||
key: 'statusChange',
|
||||
title: '状态变更记录',
|
||||
fields: statusFields.length ? statusFields : [{ label: '记录', value: '暂无状态变更记录' }],
|
||||
cards: []
|
||||
})
|
||||
values.push({
|
||||
key: 'attachments',
|
||||
title: '附件信息',
|
||||
fields: [
|
||||
{ label: '协议附件', type: 'attachments', value: detail?.attachments?.protocolAttachments || '' },
|
||||
{ label: '知情同意书', type: 'attachments', value: detail?.attachments?.consentFormUrls || '' },
|
||||
{ label: '孕妇健康调查表', type: 'attachments', value: detail?.attachments?.healthSurveyFormUrls || '' },
|
||||
{ label: '传染病检测报告', type: 'attachments', value: detail?.attachments?.infectiousDiseaseReportUrls || '' },
|
||||
{ label: '其他附件', type: 'attachments', value: detail?.attachments?.attachmentUrls || '' }
|
||||
],
|
||||
fields: isDonation
|
||||
? [
|
||||
{ label: '知情同意书', type: 'attachments', value: detail?.attachments?.consentFormUrls || '' },
|
||||
{ label: '传染病检测报告', type: 'attachments', value: detail?.attachments?.infectiousDiseaseReportUrls || '' },
|
||||
{ label: '其他附件', type: 'attachments', value: detail?.attachments?.attachmentUrls || '' }
|
||||
]
|
||||
: [
|
||||
{ label: '协议附件', type: 'attachments', value: detail?.attachments?.protocolAttachments || '' },
|
||||
{ label: '知情同意书', type: 'attachments', value: detail?.attachments?.consentFormUrls || '' },
|
||||
{ label: '孕妇健康调查表', type: 'attachments', value: detail?.attachments?.healthSurveyFormUrls || '' },
|
||||
{ label: '传染病检测报告', type: 'attachments', value: detail?.attachments?.infectiousDiseaseReportUrls || '' },
|
||||
{ label: '其他附件', type: 'attachments', value: detail?.attachments?.attachmentUrls || '' }
|
||||
],
|
||||
cards: []
|
||||
})
|
||||
const statusRegistry = source === 'research_donation' ? donationStatus : protocolStatus
|
||||
const statusChangeRows = Array.isArray(detail?.statusChanges) && detail.statusChanges.length
|
||||
? detail.statusChanges
|
||||
: synthesizeStatusChangesFromBasic(basic, source)
|
||||
const statusChangeCards = buildStatusChangeCards(statusChangeRows, statusRegistry)
|
||||
values.push({
|
||||
key: 'statusChange',
|
||||
title: '状态变更记录',
|
||||
fields: statusChangeCards.length
|
||||
? []
|
||||
: [{ label: '记录', value: '暂无状态变更记录' }],
|
||||
cards: statusChangeCards
|
||||
})
|
||||
if (isDonation) {
|
||||
const order = ['protocol', 'collection', 'samples', 'customer', 'audits', 'attachments', 'statusChange']
|
||||
const byKey = new Map(values.map((section) => [section.key, section]))
|
||||
return order.map((key) => byKey.get(key)).filter(Boolean)
|
||||
}
|
||||
return values
|
||||
},
|
||||
formSections: [
|
||||
|
||||
@@ -5,7 +5,7 @@ export function resolveStatusTone(statusText, backendTone) {
|
||||
if (VALID_TONES.has(preferred)) return preferred
|
||||
const status = String(statusText || '').trim().toLowerCase()
|
||||
if (/不通过|异常|拒绝|失败|逾期|作废|danger|error|reject/.test(status)) return 'danger'
|
||||
if (/待|未|部分|到期|进行|warning|pending|processing/.test(status)) return 'warning'
|
||||
if (/待|未|部分|到期|过期|进行|warning|pending|processing/.test(status)) return 'warning'
|
||||
if (/完成|通过|正常|启用|生效|已缴清|已入库|已采集|已接收|已办理|success|completed/.test(status)) return 'success'
|
||||
if (/停用|默认|info/.test(status)) return 'info'
|
||||
return 'primary'
|
||||
|
||||
@@ -12,3 +12,8 @@ test('matches negative status before positive substrings', () => {
|
||||
assert.equal(resolveStatusTone('不通过'), 'danger')
|
||||
assert.equal(resolveStatusTone('通过'), 'success')
|
||||
})
|
||||
|
||||
test('expired status is warning instead of primary green', () => {
|
||||
assert.equal(resolveStatusTone('已过期'), 'warning')
|
||||
assert.equal(resolveStatusTone('已过期', 'warning'), 'warning')
|
||||
})
|
||||
Reference in new issue
Block a user