提交
This commit is contained in:
1 parent
f1f5d24eff
commit
3c7a47981a
138 files changed
+18654
-12092
No files matched your search
@@ -0,0 +1,208 @@
|
||||
<!-- 临床应用缴费/退费提交信息只读展示 -->
|
||||
<template>
|
||||
<div class="clinical-payment-submit-readonly">
|
||||
<h4 v-if="title" class="detail-block-title">{{ title }}</h4>
|
||||
<dl class="view-kv-grid view-kv-grid--4">
|
||||
<div class="view-kv">
|
||||
<dt>申请单号</dt>
|
||||
<dd>{{ dash(detail?.applicationNo) }}</dd>
|
||||
</div>
|
||||
<div class="view-kv">
|
||||
<dt>患者姓名</dt>
|
||||
<dd>{{ dash(detail?.patientName) }}</dd>
|
||||
</div>
|
||||
<div class="view-kv">
|
||||
<dt>渠道名称</dt>
|
||||
<dd>{{ dash(detail?.channelName) }}</dd>
|
||||
</div>
|
||||
<div class="view-kv">
|
||||
<dt>细胞类型/规格</dt>
|
||||
<dd>{{ dash(detail?.cellTypeSpec) }}</dd>
|
||||
</div>
|
||||
<div class="view-kv">
|
||||
<dt>输注时间</dt>
|
||||
<dd>{{ dash(detail?.infusionTime) }}</dd>
|
||||
</div>
|
||||
<div v-if="showPayStatus" class="view-kv">
|
||||
<dt>缴费状态</dt>
|
||||
<dd>
|
||||
<el-tag :type="payStatusTagType(String(detail?.payStatus || ''))" size="small">
|
||||
{{ payStatusLabel(String(detail?.payStatus || '')) }}
|
||||
</el-tag>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
<template v-if="mode === 'refund'">
|
||||
<div class="view-kv">
|
||||
<dt>缴费金额(元)</dt>
|
||||
<dd>{{ formatAmount(detail?.paymentAmount ?? detail?.amount) }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="mode === 'receipt' || mode === 'full'">
|
||||
<div class="view-kv">
|
||||
<dt>缴费金额(元)</dt>
|
||||
<dd>{{ formatAmount(detail?.paymentAmount ?? detail?.amount) }}</dd>
|
||||
</div>
|
||||
<div v-if="detail?.remark" class="view-kv view-kv-span-2">
|
||||
<dt>备注</dt>
|
||||
<dd>{{ dash(detail?.remark) }}</dd>
|
||||
</div>
|
||||
<div class="view-field-block view-kv-span-2 clinical-payment-submit-readonly__attachments">
|
||||
<div class="view-field-block__label">转账凭证</div>
|
||||
<ProtocolAttachmentReadonly
|
||||
:files="receiptAttachmentFiles"
|
||||
@preview="(f) => emit('preview', f)"
|
||||
@download="(f) => emit('download', f)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="mode === 'refund' || (mode === 'full' && hasRefundInfo)">
|
||||
<div class="view-kv">
|
||||
<dt>退费金额(元)</dt>
|
||||
<dd>{{ formatAmount(detail?.refundAmount) }}</dd>
|
||||
</div>
|
||||
<div v-if="detail?.refundRemark" class="view-kv view-kv-span-2">
|
||||
<dt>退费备注</dt>
|
||||
<dd>{{ dash(detail?.refundRemark) }}</dd>
|
||||
</div>
|
||||
<div class="view-field-block view-kv-span-2 clinical-payment-submit-readonly__attachments">
|
||||
<div class="view-field-block__label">退费附件</div>
|
||||
<ProtocolAttachmentReadonly
|
||||
:files="refundAttachmentFiles"
|
||||
@preview="(f) => emit('preview', f)"
|
||||
@download="(f) => emit('download', f)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</dl>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
|
||||
import { formatMoneyDisplay } from '@/utils/money-format'
|
||||
import { payStatusLabel, payStatusTagType } from '@/utils/status-tag-registry'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
detail?: Record<string, unknown> | null
|
||||
title?: string
|
||||
mode?: 'receipt' | 'refund' | 'full'
|
||||
showPayStatus?: boolean
|
||||
}>(),
|
||||
{ mode: 'receipt', showPayStatus: false }
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'preview', file: Record<string, unknown>): void
|
||||
(e: 'download', file: Record<string, unknown>): void
|
||||
}>()
|
||||
|
||||
function dash(v: unknown) {
|
||||
if (v == null || v === '') return '—'
|
||||
return String(v)
|
||||
}
|
||||
|
||||
function formatAmount(v: unknown) {
|
||||
if (v == null || v === '') return '—'
|
||||
return '¥' + formatMoneyDisplay(v)
|
||||
}
|
||||
|
||||
function urlsToFiles(urlField: unknown) {
|
||||
const urls = String(urlField || '')
|
||||
if (!urls.trim()) return []
|
||||
return urls
|
||||
.split(',')
|
||||
.map((u, i) => {
|
||||
const url = u.trim()
|
||||
if (!url) return null
|
||||
const name = url.includes('/') ? url.split('/').pop() || `附件${i + 1}` : url
|
||||
return { id: `url_${i}`, fileUrl: url, fileName: name }
|
||||
})
|
||||
.filter(Boolean) as Array<Record<string, unknown>>
|
||||
}
|
||||
|
||||
const receiptAttachmentFiles = computed(() => urlsToFiles(props.detail?.transferAttachments))
|
||||
|
||||
const refundAttachmentFiles = computed(() => urlsToFiles(props.detail?.refundAttachments))
|
||||
|
||||
const hasRefundInfo = computed(() => {
|
||||
const d = props.detail
|
||||
if (!d) return false
|
||||
return (
|
||||
d.refundAmount != null ||
|
||||
Boolean(d.refundRemark) ||
|
||||
Boolean(String(d.refundAttachments || '').trim())
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.clinical-payment-submit-readonly {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.detail-block-title {
|
||||
margin: 0 0 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--mint-text, #334155);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.view-kv-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px 20px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.view-kv-grid--4 {
|
||||
@media (min-width: 720px) {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.view-kv {
|
||||
min-width: 0;
|
||||
|
||||
dt {
|
||||
margin: 0 0 4px;
|
||||
font-size: 12px;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: var(--mint-text, #334155);
|
||||
line-height: 1.5;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.view-kv-span-2 {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.view-field-block__label {
|
||||
font-size: 12px;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.clinical-payment-submit-readonly__attachments {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.form-section-divider--inner {
|
||||
height: 1px;
|
||||
margin: 16px 0;
|
||||
background: var(--mint-border, #e2e8f0);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,729 @@
|
||||
<!-- 临床应用 · 输注计划缴费明细(查看态,对齐 ProtocolViewDialog 缴费明细) -->
|
||||
<template>
|
||||
<div
|
||||
class="payment-detail-card"
|
||||
:class="{
|
||||
'payment-detail-card--refunded': payStatus === 'ytf',
|
||||
'payment-detail-card--refund-pending': payStatus === 'tfqrz'
|
||||
}"
|
||||
>
|
||||
<div class="pdc-header">
|
||||
<div class="pdc-header-left" :class="payDetailColorClass(payStatus)">
|
||||
缴费明细 ·
|
||||
<span class="pdc-header-amount" :class="payDetailColorClass(payStatus)">
|
||||
{{ fmtMoney(planAmount) }}
|
||||
</span>
|
||||
</div>
|
||||
<el-tag :type="payStatusTagType(payStatus)" size="small">
|
||||
{{ payStatusLabel(payStatus) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
<div class="pdc-info-row">
|
||||
<div class="pdc-info-item">
|
||||
<span class="info-label">应缴费金额(元)</span>
|
||||
<span class="info-value">{{ fmtMoney(planAmount) }}</span>
|
||||
</div>
|
||||
<div class="pdc-info-item">
|
||||
<span class="info-label">实缴金额(元)</span>
|
||||
<span class="info-value">{{ fmtMoney(payment?.transferAmount ?? planAmount) }}</span>
|
||||
</div>
|
||||
<div v-if="payment?.remark" class="pdc-info-item">
|
||||
<span class="info-label">备注</span>
|
||||
<span class="info-value">{{ dash(payment?.remark) }}</span>
|
||||
</div>
|
||||
<div v-if="payStatus !== 'dfj' && payment?.updateTime" class="pdc-info-item">
|
||||
<span class="info-label">提交时间</span>
|
||||
<span class="info-value">{{ dash(payment?.updateTime) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="transferAttachmentFiles.length" class="pdc-attachments-row">
|
||||
<div class="data-label">转账凭证</div>
|
||||
<ProtocolAttachmentReadonly
|
||||
:files="transferAttachmentFiles"
|
||||
@preview="(f) => emit('preview', f)"
|
||||
@download="(f) => emit('download', f)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<template v-if="flowSteps.length">
|
||||
<div class="flow-section">
|
||||
<div class="mini-flow">
|
||||
<template v-for="(step, sIdx) in flowSteps" :key="`c-${step.key}`">
|
||||
<div
|
||||
v-if="step.connectorToNext"
|
||||
class="mini-flow-connector"
|
||||
:class="step.connectorToNext"
|
||||
:style="miniFlowConnectorStyle(flowSteps.length, sIdx)"
|
||||
/>
|
||||
</template>
|
||||
<div v-for="step in flowSteps" :key="step.key" class="mini-flow-step">
|
||||
<div class="mini-flow-dot" :class="step.dotClass">{{ step.dotIcon }}</div>
|
||||
<div class="mini-flow-label" :class="step.labelClass">{{ step.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-detail-cards">
|
||||
<template v-for="step in flowSteps" :key="`d-${step.key}`">
|
||||
<div
|
||||
v-if="step.hasDetailCard"
|
||||
class="flow-detail-card"
|
||||
:class="'flow-detail-card--' + step.dotClass"
|
||||
>
|
||||
<div class="flow-detail-card__header">
|
||||
<span class="flow-detail-card__dot" :class="step.dotClass">{{
|
||||
step.dotIcon
|
||||
}}</span>
|
||||
<span class="flow-detail-card__title" :class="step.labelClass">{{
|
||||
step.label
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="flow-detail-card__body">
|
||||
<template v-if="step.key === 'pay'">
|
||||
<div class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">确认状态</span>
|
||||
<span class="flow-detail-card__value">
|
||||
<el-tag type="success" size="small">已提交</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="payment?.remark" class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">备注</span>
|
||||
<span class="flow-detail-card__value">{{ payment.remark }}</span>
|
||||
</div>
|
||||
<div v-if="transferAttachmentFiles.length" class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">转账凭证</span>
|
||||
<ProtocolAttachmentReadonly
|
||||
:files="transferAttachmentFiles"
|
||||
@preview="(f) => emit('preview', f)"
|
||||
@download="(f) => emit('download', f)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="step.key === 'receipt-finance'">
|
||||
<div class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">确认状态</span>
|
||||
<span class="flow-detail-card__value">
|
||||
<el-tag v-if="isReceiptFinanceConfirmed" type="success" size="small"
|
||||
>已确认</el-tag
|
||||
>
|
||||
<el-tag v-else type="warning" size="small">待确认</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="isReceiptFinanceConfirmed && receiptFinanceTime"
|
||||
class="flow-detail-card__kv"
|
||||
>
|
||||
<span class="flow-detail-card__label">确认时间</span>
|
||||
<span class="flow-detail-card__value">{{ receiptFinanceTime }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="isReceiptFinanceConfirmed && payment?.financeRemark"
|
||||
class="flow-detail-card__kv"
|
||||
>
|
||||
<span class="flow-detail-card__label">财务备注</span>
|
||||
<span class="flow-detail-card__value">{{ payment.financeRemark }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="isReceiptFinanceConfirmed && financeAttachmentFiles.length"
|
||||
class="flow-detail-card__kv"
|
||||
>
|
||||
<span class="flow-detail-card__label">财务附件</span>
|
||||
<ProtocolAttachmentReadonly
|
||||
:files="financeAttachmentFiles"
|
||||
@preview="(f) => emit('preview', f)"
|
||||
@download="(f) => emit('download', f)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="step.key === 'refund-apply'">
|
||||
<div class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">退费金额(元)</span>
|
||||
<span class="flow-detail-card__value" :class="payDetailColorClass(payStatus)">{{
|
||||
fmtMoney(payment?.refundAmount)
|
||||
}}</span>
|
||||
</div>
|
||||
<div v-if="payment?.refundRemark" class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">退费备注</span>
|
||||
<span class="flow-detail-card__value">{{ payment.refundRemark }}</span>
|
||||
</div>
|
||||
<div v-if="refundAttachmentFiles.length" class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">退费附件</span>
|
||||
<ProtocolAttachmentReadonly
|
||||
:files="refundAttachmentFiles"
|
||||
@preview="(f) => emit('preview', f)"
|
||||
@download="(f) => emit('download', f)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="step.key === 'refund-finance'">
|
||||
<div class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">确认状态</span>
|
||||
<span class="flow-detail-card__value">
|
||||
<el-tag type="danger" size="small">已退费</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="refundFinanceTime" class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">确认时间</span>
|
||||
<span class="flow-detail-card__value">{{ refundFinanceTime }}</span>
|
||||
</div>
|
||||
<div v-if="payment?.refundFinanceRemark" class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">财务备注</span>
|
||||
<span class="flow-detail-card__value">{{ payment.refundFinanceRemark }}</span>
|
||||
</div>
|
||||
<div v-if="refundFinanceAttachmentFiles.length" class="flow-detail-card__kv">
|
||||
<span class="flow-detail-card__label">财务附件</span>
|
||||
<ProtocolAttachmentReadonly
|
||||
:files="refundFinanceAttachmentFiles"
|
||||
@preview="(f) => emit('preview', f)"
|
||||
@download="(f) => emit('download', f)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
|
||||
import { formatMoneyDisplay } from '@/utils/money-format'
|
||||
import { payStatusLabel, payStatusTagType } from '@/utils/status-tag-registry'
|
||||
|
||||
const props = defineProps<{
|
||||
payment?: Record<string, any> | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'preview', file: Record<string, unknown>): void
|
||||
(e: 'download', file: Record<string, unknown>): void
|
||||
}>()
|
||||
|
||||
interface MiniFlowStep {
|
||||
key: string
|
||||
label: string
|
||||
dotClass: string
|
||||
dotIcon: string
|
||||
labelClass: string
|
||||
connectorToNext?: string
|
||||
hasDetailCard?: boolean
|
||||
}
|
||||
|
||||
const payStatus = computed(() => String(props.payment?.payStatus || 'dfj'))
|
||||
|
||||
const planAmount = computed(
|
||||
() => props.payment?.paymentAmount ?? props.payment?.amount ?? null
|
||||
)
|
||||
|
||||
const isReceiptFinanceConfirmed = computed(() => {
|
||||
const s = payStatus.value
|
||||
return s !== 'jfqrz' && s !== 'dfj'
|
||||
})
|
||||
|
||||
const receiptFinanceTime = computed(
|
||||
() => props.payment?.financeConfirmTime || props.payment?.updateTime || ''
|
||||
)
|
||||
|
||||
const refundFinanceTime = computed(
|
||||
() => props.payment?.refundFinanceConfirmTime || props.payment?.updateTime || ''
|
||||
)
|
||||
|
||||
const transferAttachmentFiles = computed(() =>
|
||||
urlsToAttachmentFiles(String(props.payment?.transferAttachments || ''))
|
||||
)
|
||||
|
||||
const financeAttachmentFiles = computed(() =>
|
||||
urlsToAttachmentFiles(String(props.payment?.financeConfirmAttachments || ''))
|
||||
)
|
||||
|
||||
const refundAttachmentFiles = computed(() =>
|
||||
urlsToAttachmentFiles(String(props.payment?.refundAttachments || ''))
|
||||
)
|
||||
|
||||
const refundFinanceAttachmentFiles = computed(() =>
|
||||
urlsToAttachmentFiles(String(props.payment?.refundFinanceConfirmAttachments || ''))
|
||||
)
|
||||
|
||||
const flowSteps = computed(() => buildMiniFlowSteps(props.payment || {}))
|
||||
|
||||
function dash(v: unknown) {
|
||||
if (v == null || v === '') return '—'
|
||||
return String(v)
|
||||
}
|
||||
|
||||
function fmtMoney(v: unknown) {
|
||||
if (v == null || v === '') return '—'
|
||||
return '¥' + formatMoneyDisplay(v)
|
||||
}
|
||||
|
||||
function urlsToAttachmentFiles(urls: string) {
|
||||
if (!urls.trim()) return []
|
||||
return urls
|
||||
.split(',')
|
||||
.map((u, i) => {
|
||||
const url = u.trim()
|
||||
if (!url) return null
|
||||
const name = url.includes('/') ? url.split('/').pop() || `附件${i + 1}` : url
|
||||
return { id: `url_${i}`, fileUrl: url, fileName: name, fileSize: 0 }
|
||||
})
|
||||
.filter(Boolean) as Array<Record<string, unknown>>
|
||||
}
|
||||
|
||||
function payDetailColorClass(status: string) {
|
||||
if (status === 'ytf') return 'red'
|
||||
if (status === 'tfqrz') return 'amber'
|
||||
return 'green'
|
||||
}
|
||||
|
||||
function buildMiniFlowSteps(detail: Record<string, any>): MiniFlowStep[] {
|
||||
const s = String(detail.payStatus || '')
|
||||
if (s === 'dfj') return []
|
||||
|
||||
const steps: MiniFlowStep[] = []
|
||||
|
||||
steps.push({
|
||||
key: 'pay',
|
||||
label: '缴费确认',
|
||||
dotClass: 'done',
|
||||
dotIcon: '✓',
|
||||
labelClass: 'done',
|
||||
connectorToNext: 'done',
|
||||
hasDetailCard: true
|
||||
})
|
||||
|
||||
if (s === 'jfqrz') {
|
||||
steps.push({
|
||||
key: 'receipt-finance',
|
||||
label: '财务确认',
|
||||
dotClass: 'current-amber',
|
||||
dotIcon: '●',
|
||||
labelClass: 'current-amber',
|
||||
hasDetailCard: true
|
||||
})
|
||||
} else {
|
||||
steps.push({
|
||||
key: 'receipt-finance',
|
||||
label: '财务确认',
|
||||
dotClass: 'done',
|
||||
dotIcon: '✓',
|
||||
labelClass: 'done',
|
||||
connectorToNext: s === 'yjf' ? undefined : 'done',
|
||||
hasDetailCard: true
|
||||
})
|
||||
}
|
||||
|
||||
if (s === 'tfqrz' || s === 'ytf') {
|
||||
steps.push({
|
||||
key: 'refund-apply',
|
||||
label: '退费申请',
|
||||
dotClass: s === 'tfqrz' ? 'current-amber' : 'done',
|
||||
dotIcon: s === 'tfqrz' ? '●' : '✓',
|
||||
labelClass: s === 'tfqrz' ? 'current-amber' : 'done',
|
||||
connectorToNext: s === 'tfqrz' ? 'pending-gray' : 'done-red',
|
||||
hasDetailCard: true
|
||||
})
|
||||
}
|
||||
|
||||
if (s === 'tfqrz') {
|
||||
steps.push({
|
||||
key: 'refund-finance',
|
||||
label: '退费确认',
|
||||
dotClass: 'pending-gray',
|
||||
dotIcon: '○',
|
||||
labelClass: 'pending-gray',
|
||||
hasDetailCard: false
|
||||
})
|
||||
} else if (s === 'ytf') {
|
||||
steps.push({
|
||||
key: 'refund-finance',
|
||||
label: '退费确认',
|
||||
dotClass: 'done-red',
|
||||
dotIcon: '✓',
|
||||
labelClass: 'done-red',
|
||||
hasDetailCard: true
|
||||
})
|
||||
}
|
||||
|
||||
if (steps.length) {
|
||||
delete steps[steps.length - 1].connectorToNext
|
||||
}
|
||||
|
||||
return steps
|
||||
}
|
||||
|
||||
function miniFlowConnectorStyle(total: number, index: number) {
|
||||
const leftPct = ((index + 0.5) / total) * 100
|
||||
const widthPct = 100 / total
|
||||
return `left: calc(${leftPct}% + 12px); width: calc(${widthPct}% - 12px);`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.payment-detail-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 14px 16px;
|
||||
border: 1px solid #e2e8f0;
|
||||
|
||||
&--refunded {
|
||||
border-left: 3px solid #dc2626;
|
||||
border-color: #e2e8f0;
|
||||
border-left-color: #dc2626;
|
||||
}
|
||||
|
||||
&--refund-pending {
|
||||
border-left: 3px solid #d97706;
|
||||
border-color: #e2e8f0;
|
||||
border-left-color: #d97706;
|
||||
}
|
||||
}
|
||||
|
||||
.pdc-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
.pdc-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 2px;
|
||||
height: 14px;
|
||||
border-radius: 1px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&.green::before {
|
||||
background: #10b981;
|
||||
}
|
||||
|
||||
&.red::before {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
&.amber::before {
|
||||
background: #d97706;
|
||||
}
|
||||
}
|
||||
|
||||
.pdc-header-amount {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
margin-left: 4px;
|
||||
|
||||
&.green {
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
&.red {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
&.amber {
|
||||
color: #d97706;
|
||||
}
|
||||
}
|
||||
|
||||
.pdc-info-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 14px 20px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.pdc-info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
.info-label {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 13px;
|
||||
color: #1e293b;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.pdc-attachments-row {
|
||||
margin-bottom: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px dashed #e2e8f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
.data-label {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.flow-section {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.mini-flow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
margin: 12px 0;
|
||||
padding: 10px 14px;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mini-flow-step {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.mini-flow-dot {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
z-index: 1;
|
||||
|
||||
&.done {
|
||||
background: #10b981;
|
||||
color: #fff;
|
||||
box-shadow: 0 0 0 3px rgb(16 185 129 / 15%);
|
||||
}
|
||||
|
||||
&.done-red {
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
box-shadow: 0 0 0 3px rgb(220 38 38 / 15%);
|
||||
}
|
||||
|
||||
&.current-amber {
|
||||
background: #fff;
|
||||
border: 2px solid #d97706;
|
||||
color: #d97706;
|
||||
box-shadow: 0 0 0 3px rgb(217 119 6 / 15%);
|
||||
}
|
||||
|
||||
&.pending-gray {
|
||||
background: #f1f5f9;
|
||||
color: #94a3b8;
|
||||
border: 2px solid #e2e8f0;
|
||||
}
|
||||
}
|
||||
|
||||
.mini-flow-label {
|
||||
font-size: 10px;
|
||||
margin-top: 6px;
|
||||
text-align: center;
|
||||
max-width: 80px;
|
||||
line-height: 1.3;
|
||||
|
||||
&.done {
|
||||
color: #059669;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&.done-red {
|
||||
color: #dc2626;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&.current-amber {
|
||||
color: #d97706;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&.pending-gray {
|
||||
color: #94a3b8;
|
||||
}
|
||||
}
|
||||
|
||||
.mini-flow-connector {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
height: 2px;
|
||||
z-index: 0;
|
||||
|
||||
&.done {
|
||||
background: #10b981;
|
||||
}
|
||||
|
||||
&.done-red {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
&.pending-gray {
|
||||
background: #e2e8f0;
|
||||
}
|
||||
}
|
||||
|
||||
.flow-detail-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.flow-detail-card {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
&--current-amber {
|
||||
border-color: #fde68a;
|
||||
background: #fffbeb;
|
||||
}
|
||||
|
||||
&--done-red {
|
||||
border-left: 3px solid #dc2626;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
&--pending-gray {
|
||||
border-style: dashed;
|
||||
background: #f8fafc;
|
||||
}
|
||||
}
|
||||
|
||||
.flow-detail-card__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
background: #f8fafc;
|
||||
|
||||
.flow-detail-card--done-red & {
|
||||
background: #fef2f2;
|
||||
border-bottom-color: #fecaca;
|
||||
}
|
||||
|
||||
.flow-detail-card--current-amber & {
|
||||
background: #fffbeb;
|
||||
border-bottom-color: #fde68a;
|
||||
}
|
||||
}
|
||||
|
||||
.flow-detail-card__dot {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.done {
|
||||
background: #10b981;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.done-red {
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.current-amber {
|
||||
background: #fff;
|
||||
border: 2px solid #d97706;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
&.pending-gray {
|
||||
background: #f1f5f9;
|
||||
border: 2px solid #e2e8f0;
|
||||
color: #94a3b8;
|
||||
}
|
||||
}
|
||||
|
||||
.flow-detail-card__title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
|
||||
&.done {
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
&.done-red {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
&.current-amber {
|
||||
color: #d97706;
|
||||
}
|
||||
}
|
||||
|
||||
.flow-detail-card__body {
|
||||
padding: 12px 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.flow-detail-card__kv {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.flow-detail-card__label {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.flow-detail-card__value {
|
||||
font-size: 13px;
|
||||
color: #1e293b;
|
||||
font-weight: 500;
|
||||
word-break: break-word;
|
||||
|
||||
&.red {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
&.amber {
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
&.green {
|
||||
color: #059669;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.pdc-info-row {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user