feat(mobile-oa-h5): restyle payment schedule transfers as amount-first cards

Render schedule cards with metric grids and white transfer cards (amount, method·time, notes) in payment and protocol detail views.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-10-14 15:24:25 +08:00
1 parent 5ce18e56a0
commit 9d7a72673d
7 files changed
+404 -104

No files matched your search

@@ -1,54 +1,173 @@
<template>
<article class="market-detail-section__nested-card">
<strong>{{ card.title }}</strong>
<van-tag
v-if="card.statusText"
class="market-tag"
:type="card.statusTone"
round
:title="card.statusText"
>
{{ card.statusText }}
</van-tag>
<div
v-for="field in card.fields"
:key="field.label"
class="market-detail-section__nested-field"
:class="{ 'is-attachments': field.type === 'attachments' }"
>
<small>{{ field.label }}</small>
<MarketAttachmentCards
v-if="field.type === 'attachments'"
:model-value="field.value"
:editable="false"
/>
<van-tag
v-else-if="field.tag"
class="market-tag"
:type="field.tagType || 'primary'"
round
:title="field.value"
<article
class="market-detail-section__nested-card"
:class="{
'is-schedule': card.variant === 'schedule',
'is-transfer': card.variant === 'transfer'
}"
>
<template v-if="card.variant === 'transfer'">
<div class="market-detail-section__transfer-head">
<span class="market-detail-section__transfer-index">{{ card.transferIndex || 1 }}</span>
<div class="market-detail-section__transfer-main">
<strong class="market-detail-section__transfer-amount">{{ card.amount || '—' }}</strong>
<small v-if="card.meta" class="market-detail-section__transfer-meta">{{ card.meta }}</small>
</div>
<van-tag
v-if="card.statusText"
class="market-tag"
:type="card.statusTone"
round
:title="card.statusText"
>
{{ card.statusText }}
</van-tag>
</div>
<div
v-if="detailFields.length"
class="market-detail-section__transfer-grid"
>
{{ field.value }}
<div
v-for="field in detailFields"
:key="field.label"
class="market-detail-section__transfer-metric"
:class="{ 'is-wide': field.type === 'attachments' || field.wide }"
>
<span>{{ field.label }}</span>
<MarketAttachmentCards
v-if="field.type === 'attachments'"
:model-value="field.value"
:editable="false"
/>
<b v-else>{{ field.value }}</b>
</div>
</div>
<div
v-if="attachmentFields.length"
class="market-detail-section__transfer-voucher"
>
<div
v-for="field in attachmentFields"
:key="field.label"
class="market-detail-section__nested-field is-attachments"
>
<small>{{ field.label }}</small>
<MarketAttachmentCards
:model-value="field.value"
:editable="false"
/>
</div>
</div>
</template>
<template v-else-if="card.variant === 'schedule'">
<header class="market-detail-section__schedule-head">
<strong>{{ card.title }}</strong>
<van-tag
v-if="card.statusText"
class="market-tag"
:type="card.statusTone"
round
:title="card.statusText"
>
{{ card.statusText }}
</van-tag>
</header>
<div class="market-detail-section__schedule-metrics">
<div
v-for="field in metricFields"
:key="field.label"
class="market-detail-section__transfer-metric"
>
<span>{{ field.label }}</span>
<b :class="{ 'is-money': field.money }">{{ field.value }}</b>
</div>
</div>
<div class="market-detail-section__transfer-list">
<div class="market-detail-section__transfer-list-label">
{{ card.cardsLabel || '转账记录' }}({{ card.cards?.length || 0 }})
</div>
<div v-if="card.cards?.length" class="market-detail-section__subcards">
<MarketDetailNestedCard
v-for="child in card.cards"
:key="child.key"
:card="child"
/>
</div>
<p v-else class="market-detail-section__transfer-empty">暂无转账记录</p>
</div>
</template>
<template v-else>
<strong>{{ card.title }}</strong>
<van-tag
v-if="card.statusText"
class="market-tag"
:type="card.statusTone"
round
:title="card.statusText"
>
{{ card.statusText }}
</van-tag>
<span v-else>{{ field.value }}</span>
</div>
<div v-if="card.cards?.length" class="market-detail-section__subcards">
<MarketDetailNestedCard
v-for="child in card.cards"
:key="child.key"
:card="child"
/>
</div>
<div
v-for="field in card.fields"
:key="field.label"
class="market-detail-section__nested-field"
:class="{ 'is-attachments': field.type === 'attachments' }"
>
<small>{{ field.label }}</small>
<MarketAttachmentCards
v-if="field.type === 'attachments'"
:model-value="field.value"
:editable="false"
/>
<van-tag
v-else-if="field.tag"
class="market-tag"
:type="field.tagType || 'primary'"
round
:title="field.value"
>
{{ field.value }}
</van-tag>
<span v-else>{{ field.value }}</span>
</div>
<div v-if="card.cards?.length" class="market-detail-section__subcards">
<MarketDetailNestedCard
v-for="child in card.cards"
:key="child.key"
:card="child"
/>
</div>
</template>
</article>
</template>
<script setup>
import { computed } from 'vue'
import MarketAttachmentCards from './MarketAttachmentCards.vue'
defineOptions({ name: 'MarketDetailNestedCard' })
defineProps({
const props = defineProps({
card: { type: Object, required: true }
})
const metricFields = computed(() =>
(props.card.fields || []).filter((field) => field.type !== 'attachments' && !field.tag)
)
const detailFields = computed(() =>
(props.card.fields || []).filter((field) => field.type !== 'attachments')
)
const attachmentFields = computed(() =>
(props.card.fields || []).filter((field) => {
if (field.type !== 'attachments') return false
const raw = field.value
if (raw == null || raw === '' || raw === '—') return false
if (Array.isArray(raw) && raw.length === 0) return false
return true
})
)
</script>
@@ -58,7 +58,9 @@ function normalizeDetailField(field, index) {
value: type ? field?.value : String(field?.value ?? '-'),
type,
tag: Boolean(field?.tag),
tagType: field?.tagType
tagType: field?.tagType,
money: Boolean(field?.money),
wide: Boolean(field?.wide)
}
}
@@ -66,6 +68,11 @@ function normalizeCard(card, index, prefix = 'card') {
return {
key: String(card?.key || `${prefix}-${index}`),
title: String(card?.title || `明细 ${index + 1}`),
variant: String(card?.variant || ''),
transferIndex: Number(card?.transferIndex) || index + 1,
amount: card?.amount == null || card?.amount === '' ? '' : String(card.amount),
meta: card?.meta == null || card?.meta === '' ? '' : String(card.meta),
cardsLabel: String(card?.cardsLabel || ''),
statusText: String(card?.statusText || card?.statusLabel || ''),
statusTone: resolveStatusTone(
card?.statusText || card?.statusLabel,
@@ -427,13 +427,18 @@ test('payment detail presents every web field and nested transfer field with Chi
sections[0].fields.map((field) => field.label),
['协议号', '客户', '联系电话', '样本编码', '缴费方式', '合同额', '已缴 / 待缴', '整体进度', '协议状态', '缴费进度']
)
assert.equal(sections[1].cards[0].variant, 'schedule')
assert.deepEqual(
sections[1].cards[0].fields.map((field) => field.label),
['应缴金额', '应缴日', '已缴金额', '欠缴金额']
)
const transfer = sections[1].cards[0].cards[0]
assert.equal(transfer.variant, 'transfer')
assert.equal(transfer.amount, '¥3,000.00')
assert.match(transfer.meta, /微信转账/)
assert.deepEqual(
sections[1].cards[0].cards[0].fields.map((field) => field.label),
['转账方式', '转账金额', '转账时间', '转账凭证', '备注', '财务备注']
transfer.fields.map((field) => field.label),
['备注', '财务备注', '转账凭证']
)
})
+25 -14
View File
@@ -41,36 +41,42 @@ function displayDate(value) {
function transferCard(transfer, index) {
const statusText = label(PAY_STATUS, transfer?.payStatus)
const transferType = label(TRANSFER_TYPE, transfer?.transferType)
const transferTime = transfer?.transferTime || '—'
return {
key: String(transfer?.id || `transfer-${index}`),
title: `转账笔 ${index + 1}`,
variant: 'transfer',
transferIndex: index + 1,
amount: money(transfer?.transferAmount),
meta: `${transferType} · ${transferTime}`,
statusText,
statusTone: statusText.includes('确认中') ? 'warning' : statusText === '付款完成' ? 'success' : 'info',
fields: [
{ label: '转账方式', value: label(TRANSFER_TYPE, transfer?.transferType) },
{ label: '转账金额', value: money(transfer?.transferAmount) },
{ label: '转账时间', value: transfer?.transferTime || '—' },
{ label: '转账凭证', type: 'attachments', value: transfer?.transferAttachments || '' },
{ label: '备注', value: transfer?.remark || '—' },
{ label: '财务备注', value: transfer?.financeRemark || '—' }
{ label: '财务备注', value: transfer?.financeRemark || '—' },
{ label: '转账凭证', type: 'attachments', value: transfer?.transferAttachments || '' }
]
}
}
function scheduleCard(schedule, index) {
const statusText = label(SCHEDULE_STATUS, schedule?.scheduleStatus)
const transfers = schedule?.transfers || []
return {
key: String(schedule?.id || `schedule-${index}`),
title: `第 ${schedule?.scheduleNo || index + 1} 期`,
variant: 'schedule',
cardsLabel: '转账记录',
statusText,
statusTone: statusText === '已缴清' ? 'success' : statusText === '部分到账' ? 'primary' : 'warning',
fields: [
{ label: '应缴金额', value: money(schedule?.dueAmount) },
{ label: '应缴金额', value: money(schedule?.dueAmount), money: true },
{ label: '应缴日', value: displayDate(schedule?.dueDate) },
{ label: '已缴金额', value: money(schedule?.paidAmount) },
{ label: '欠缴金额', value: money(schedule?.arrearsAmount) }
{ label: '已缴金额', value: money(schedule?.paidAmount), money: true },
{ label: '欠缴金额', value: money(schedule?.arrearsAmount), money: true }
],
cards: (schedule?.transfers || []).map(transferCard)
cards: transfers.map(transferCard)
}
}
@@ -83,9 +89,13 @@ export default {
},
listParams: ({ status } = {}) => ({ payMode: status || '' }),
statusOptions: [{ text: '全部缴费模式', value: '' }],
filterFields: [
// 缴费列表用搜索下方 van-dropdown-menu(对齐预签约/运费),不走筛选弹层
filterFields: [],
inlineDropdownFilters: [
{
key: 'payMode', label: '缴费方式', type: 'select', options: [
key: 'payMode',
allText: '全部缴费方式',
options: [
{ text: '趸交', value: 'dj' },
{ text: '分期', value: 'fq' },
{ text: '分改趸', value: 'fgd' },
@@ -93,13 +103,14 @@ export default {
]
},
{
key: 'progressStatus', label: '缴费进度', type: 'select', options: [
key: 'progressStatus',
allText: '全部缴费进度',
options: [
{ text: '待缴清', value: 'dfj' },
{ text: '部分已缴', value: 'bfyj' },
{ text: '已缴清', value: 'yjq' }
]
},
{ key: 'dueDateRange', label: '应缴费时间', type: 'date-range' }
}
],
detailSections(detail) {
const progress = label(PAYMENT_PROGRESS, detail?.progressStatus || detail?.paymentProgress)
+48 -39
View File
@@ -25,6 +25,12 @@ const PAYMENT_STATUS_LABELS = Object.freeze({
dfj: '已付款', jfqrz: '付款确认中', yjf: '付款完成',
tfqrz: '退费确认中', ytf: '已退费'
})
const TRANSFER_TYPE_LABELS = Object.freeze({
wxzz: '微信转账', wx: '微信转账', wechat: '微信转账',
zzbzz: '支付宝转账', zfb: '支付宝转账', alipay: '支付宝转账',
yhkzz: '银行卡转账', bank: '银行卡转账',
xj: '现金', cash: '现金', lszz: '乐刷'
})
const SCHEDULE_STATUS_LABELS = Object.freeze({ open: '待缴清', cleared: '已缴清', void: '已作废' })
function value(source, key) {
@@ -79,7 +85,11 @@ function transferAttachmentValue(transfer) {
}
function transferTypeText(transfer) {
return String(transfer?.transferTypeLabel || transfer?.transferType || '').trim() || '—'
const backendLabel = String(transfer?.transferTypeLabel || '').trim()
if (backendLabel) return backendLabel
const code = String(transfer?.transferType || '').trim()
if (!code) return '—'
return TRANSFER_TYPE_LABELS[code] || (/[㐀-鿿]/u.test(code) ? code : code)
}
function namedItems(items) {
@@ -293,33 +303,40 @@ function sampleLifecycleCards(item, source) {
return cards
}
function paymentTransferCard(transfer, transferIndex) {
const statusText = label(PAYMENT_STATUS_LABELS, transfer?.payStatus)
const transferType = transferTypeText(transfer)
const transferTime = value(transfer, 'transferTime')
return {
key: String(transfer?.id || `transfer-${transferIndex}`),
title: `转账 ${transferIndex + 1}`,
variant: 'transfer',
transferIndex: transferIndex + 1,
amount: value(transfer, 'transferAmount'),
meta: `${transferType} · ${transferTime}`,
statusText,
fields: [
{ label: '备注', value: value(transfer, 'remark') },
{ label: '财务备注', value: value(transfer, 'financeRemark') },
{ label: '转账凭证', value: transferAttachmentValue(transfer), type: 'attachments' }
]
}
}
function paymentScheduleCards(pay) {
return (pay?.schedules || []).map((schedule, scheduleIndex) => ({
key: String(schedule?.id || `schedule-${scheduleIndex}`),
title: `第 ${schedule?.scheduleNo || scheduleIndex + 1} 期`,
variant: 'schedule',
cardsLabel: '转账记录',
statusText: label(SCHEDULE_STATUS_LABELS, schedule?.scheduleStatus),
fields: [
{ label: '期次', value: value(schedule, 'scheduleNo') },
{ label: '应缴金额', value: value(schedule, 'dueAmount') },
{ label: '实缴金额', value: value(schedule, 'paidAmount') },
{ label: '欠缴金额', value: value(schedule, 'arrearsAmount') },
{ label: '应缴金额', value: value(schedule, 'dueAmount'), money: true },
{ label: '应缴日期', value: value(schedule, 'dueDate') },
{ label: '状态', value: label(SCHEDULE_STATUS_LABELS, schedule?.scheduleStatus), tag: true }
{ label: '实缴金额', value: value(schedule, 'paidAmount'), money: true },
{ label: '欠缴金额', value: value(schedule, 'arrearsAmount'), money: true }
],
cards: (schedule?.transfers || []).map((transfer, transferIndex) => ({
key: String(transfer?.id || `transfer-${transferIndex}`),
title: `转账 ${transferIndex + 1}`,
statusText: label(PAYMENT_STATUS_LABELS, transfer?.payStatus),
fields: [
{ label: '转账方式', value: transferTypeText(transfer) },
{ label: '转账金额', value: value(transfer, 'transferAmount') },
{ label: '转账时间', value: value(transfer, 'transferTime') },
{ label: '转账凭证', value: transferAttachmentValue(transfer), type: 'attachments' },
{ label: '备注', value: value(transfer, 'remark') },
{ label: '财务备注', value: value(transfer, 'financeRemark') },
{ label: '状态', value: label(PAYMENT_STATUS_LABELS, transfer?.payStatus), tag: true }
]
}))
cards: (schedule?.transfers || []).map(paymentTransferCard)
}))
}
@@ -327,29 +344,21 @@ function legacyPaymentDetailCards(payment, details) {
return groupLegacyPaymentPeriods({ payment, details }).map((period, index) => ({
key: `legacy-payment-${period.scheduleNo || index + 1}`,
title: `第 ${period.scheduleNo || index + 1} 期`,
variant: 'schedule',
cardsLabel: '转账记录',
statusText: label(SCHEDULE_STATUS_LABELS, period.scheduleStatus),
fields: [
{ label: '期次', value: String(period.scheduleNo || index + 1) },
{ label: '应缴金额', value: period.dueAmount == null ? '—' : String(period.dueAmount) },
{ label: '确认实缴金额', value: String(period.paidAmount) },
{ label: '欠缴金额', value: period.arrearsAmount == null ? '—' : String(period.arrearsAmount) },
{ label: '应缴金额', value: period.dueAmount == null ? '—' : String(period.dueAmount), money: true },
{ label: '应缴日期', value: period.dueDate || '—' },
{ label: '期状态', value: label(SCHEDULE_STATUS_LABELS, period.scheduleStatus), tag: true }
{ label: '确认实缴金额', value: String(period.paidAmount), money: true },
{ label: '欠缴金额', value: period.arrearsAmount == null ? '—' : String(period.arrearsAmount), money: true }
],
cards: period.transfers.map((detail, transferIndex) => ({
key: String(detail?.id || `legacy-transfer-${period.scheduleNo}-${transferIndex}`),
title: `转账 ${transferIndex + 1}`,
statusText: label(PAYMENT_STATUS_LABELS, detail?.payStatus),
fields: [
{ label: '转账方式', value: transferTypeText(detail) },
{ label: '转账金额', value: value(detail, 'transferAmount') },
{ label: '转账时间', value: value(detail, 'transferTime') },
{ label: '转账凭证', value: transferAttachmentValue(detail), type: 'attachments' },
{ label: '备注', value: value(detail, 'remark') },
{ label: '财务备注', value: value(detail, 'financeRemark') },
{ label: '状态', value: label(PAYMENT_STATUS_LABELS, detail?.payStatus), tag: true }
]
}))
cards: period.transfers.map((detail, transferIndex) =>
paymentTransferCard(
{ ...detail, id: detail?.id || `legacy-transfer-${period.scheduleNo}-${transferIndex}` },
transferIndex
)
)
}))
}
@@ -138,13 +138,15 @@ test('v1 protocol detail renders readonly payment details with backend transfer
const payment = sections.find((section) => section.key === 'payment')
assert.equal(payment.cards.length, 1)
assert.equal(payment.cards[0].cards.length, 2)
assert.equal(payment.cards[0].variant, 'schedule')
assert.equal(payment.cards[0].fields.find((field) => field.label === '确认实缴金额').value, '600.00')
assert.equal(payment.cards[0].fields.find((field) => field.label === '欠缴金额').value, '400.00')
assert.equal(payment.cards[0].cards[0].fields.find((field) => field.label === '转账方式').value, '微信支付')
for (const expected of ['期次', '应缴金额', '确认实缴金额', '欠缴金额', '应缴日期', '期状态']) {
assert.match(payment.cards[0].cards[0].meta, /微信支付/)
assert.equal(payment.cards[0].cards[0].amount, '600')
for (const expected of ['应缴金额', '确认实缴金额', '欠缴金额', '应缴日期']) {
assert.ok(payment.cards[0].fields.some((field) => field.label === expected), `missing ${expected}`)
}
for (const expected of ['转账方式', '转账金额', '转账时间', '转账凭证', '备注', '财务备注', '状态']) {
for (const expected of ['转账凭证', '备注', '财务备注']) {
assert.ok(payment.cards[0].cards[0].fields.some((field) => field.label === expected), `missing transfer ${expected}`)
}
})
@@ -206,11 +208,15 @@ test('protocol detail exposes complete deposit and installment transfer fields',
])
const payment = sections.find((section) => section.key === 'payment').cards[0]
const schedule = payment.cards[0]
assert.equal(schedule.variant, 'schedule')
assert.deepEqual(schedule.fields.map((field) => field.label), [
'期次', '应缴金额', '实缴金额', '欠缴金额', '应缴日期', '状态'
'应缴金额', '应缴日期', '实缴金额', '欠缴金额'
])
assert.equal(schedule.cards[0].variant, 'transfer')
assert.equal(schedule.cards[0].amount, '3000')
assert.match(schedule.cards[0].meta, /微信/)
assert.deepEqual(schedule.cards[0].fields.map((field) => field.label), [
'转账方式', '转账金额', '转账时间', '转账凭证', '备注', '财务备注', '状态'
'备注', '财务备注', '转账凭证'
])
})
@@ -230,16 +236,21 @@ test('deposit and installment transfers prefer backend dictionary labels and fal
const deposit = sections.find((section) => section.key === 'deposit').cards[0]
assert.equal(deposit.fields.find((field) => field.label === '转账方式').value, '微信支付')
const transfers = sections.find((section) => section.key === 'payment').cards[0].cards[0].cards
assert.equal(transfers[0].fields.find((field) => field.label === '转账方式').value, '支付宝')
assert.equal(transfers[1].fields.find((field) => field.label === '转账方式').value, 'unknown-code')
assert.match(transfers[0].meta, /^支付宝 ·/)
assert.match(transfers[1].meta, /^unknown-code ·/)
})
test('detail renderer recursively renders transfer and task subcards', () => {
const section = source('./components/MarketDetailSection.vue')
const nested = source('./components/MarketDetailNestedCard.vue')
const styles = source('../styles/market.css')
assert.match(section, /<MarketDetailNestedCard/)
assert.match(nested, /<MarketDetailNestedCard/)
assert.match(nested, /card\.cards/)
assert.match(nested, /variant === 'transfer'/)
assert.match(nested, /variant === 'schedule'/)
assert.match(styles, /\.market-detail-section__nested-card\.is-transfer\s*\{/)
assert.match(styles, /\.market-detail-section__transfer-amount\s*\{/)
})
test('protocol transfer controls require backend nested capability and frontend whitelist', () => {
@@ -275,7 +286,8 @@ test('protocol uploads use the Web 20MB rich attachment policy', () => {
test('protocol list and nested payment actions keep 44px mobile touch targets', () => {
const styles = source('../styles/market.css')
const panel = source('./components/ProtocolSamplePaymentPanel.vue')
assert.match(styles, /\.market-list-card__actions \.van-button\s*\{[^}]*min-height:\s*44px;/)
assert.match(styles, /\.market-list-card__actions \.van-button\s*\{[^}]*min-height:\s*32px;/)
assert.match(styles, /\.market-list-card__actions \.van-button\s*\{[\s\S]*?padding:\s*0 8px;/)
assert.match(panel, /\.protocol-sample-pay__transfer-actions[\s\S]*?\.van-button\s*\{[^}]*min-height:\s*44px;/)
})
+137
View File
@@ -818,6 +818,143 @@ body.van-toast--unclickable .presign-order-page * {
font-size: 13px;
}
.market-detail-section__nested-card.is-schedule {
display: block;
padding: 0;
overflow: hidden;
border: 1px solid #eef4f1;
background: #fafcfb;
}
.market-detail-section__nested-card.is-transfer {
display: block;
padding: 12px;
border: 1px solid var(--market-border);
border-radius: 10px;
background: #fff;
box-shadow: 0 1px 0 rgb(8 127 87 / 4%);
}
.market-detail-section__schedule-head {
display: flex;
align-items: center;
gap: 8px;
padding: 12px;
background: var(--market-primary-soft);
}
.market-detail-section__schedule-head strong {
flex: 1;
font-size: 14px;
}
.market-detail-section__schedule-metrics {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px 14px;
padding: 12px;
border-bottom: 1px dashed #eef4f1;
}
.market-detail-section__transfer-list {
display: grid;
gap: 8px;
padding: 10px;
}
.market-detail-section__transfer-list-label {
color: var(--market-muted);
font-size: 12px;
font-weight: 600;
}
.market-detail-section__transfer-empty {
margin: 0;
padding: 4px 2px 2px;
color: var(--market-muted);
font-size: 12px;
}
.market-detail-section__transfer-head {
display: flex;
align-items: flex-start;
gap: 8px;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #eef4f1;
}
.market-detail-section__transfer-index {
display: grid;
width: 22px;
height: 22px;
flex: 0 0 22px;
place-items: center;
border-radius: 6px;
background: var(--market-primary-soft);
color: var(--market-primary-dark);
font-size: 11px;
font-weight: 700;
}
.market-detail-section__transfer-main {
min-width: 0;
flex: 1;
}
.market-detail-section__transfer-amount {
display: block;
color: #c98312;
font-size: 17px;
font-weight: 700;
line-height: 1.2;
}
.market-detail-section__transfer-meta {
display: block;
margin-top: 4px;
color: var(--market-muted);
font-size: 12px;
}
.market-detail-section__transfer-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px 12px;
}
.market-detail-section__transfer-metric {
display: flex;
min-width: 0;
flex-direction: column;
gap: 2px;
}
.market-detail-section__transfer-metric.is-wide {
grid-column: 1 / -1;
}
.market-detail-section__transfer-metric > span {
color: var(--market-muted);
font-size: 11px;
}
.market-detail-section__transfer-metric > b {
font-weight: 600;
overflow-wrap: anywhere;
}
.market-detail-section__transfer-metric > b.is-money {
color: #c98312;
font-weight: 700;
}
.market-detail-section__transfer-voucher {
margin-top: 8px;
padding-top: 8px;
border-top: 1px dashed #eef4f1;
}
.market-detail-section__nested-field {
display: flex;
grid-column: 1 / -1;