|
|
@@ -0,0 +1,501 @@
|
|
|
+<template>
|
|
|
+ <section v-if="syncedPayments.length" class="market-form-section protocol-sample-pay">
|
|
|
+ <h2>缴费信息</h2>
|
|
|
+ <p class="protocol-sample-pay__hint">按样本配置缴费方案,规则与管理端一致</p>
|
|
|
+
|
|
|
+ <div
|
|
|
+ v-for="(pay, pIdx) in syncedPayments"
|
|
|
+ :key="pay.sampleCode || pIdx"
|
|
|
+ class="protocol-sample-pay__card"
|
|
|
+ >
|
|
|
+ <div class="protocol-sample-pay__head">
|
|
|
+ <strong>{{ sampleTitle(pay) }}</strong>
|
|
|
+ <span class="protocol-sample-pay__code">{{ pay.sampleCode || '—' }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <van-cell-group inset>
|
|
|
+ <van-field
|
|
|
+ :model-value="payModeLabel(pay.payMode)"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ label="缴费模式"
|
|
|
+ placeholder="请选择"
|
|
|
+ :disabled="disabled"
|
|
|
+ @click="!disabled && openPayModeSheet(pIdx)"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ :model-value="pay.contractAmount == null ? '' : String(pay.contractAmount)"
|
|
|
+ type="number"
|
|
|
+ label="样本合同金额"
|
|
|
+ placeholder="请输入"
|
|
|
+ :disabled="disabled"
|
|
|
+ @update:model-value="(v) => onContractChange(pIdx, v)"
|
|
|
+ />
|
|
|
+ <template v-if="pay.payMode === 'dj'">
|
|
|
+ <van-field
|
|
|
+ :model-value="formatYmd(pay.lumpSumDeadline)"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ label="趸交截止时间"
|
|
|
+ placeholder="选择日期"
|
|
|
+ :disabled="disabled"
|
|
|
+ @click="!disabled && openDatePicker(pIdx, 'lumpSumDeadline')"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <van-field
|
|
|
+ :model-value="pay.installmentCount == null ? '' : String(pay.installmentCount)"
|
|
|
+ type="digit"
|
|
|
+ :label="pay.payMode === 'fgd' ? '期数' : '分期期数'"
|
|
|
+ :disabled="disabled"
|
|
|
+ @update:model-value="(v) => onFqField(pIdx, 'installmentCount', v)"
|
|
|
+ @blur="rebuildAt(pIdx)"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ :model-value="pay.installmentIntervalMonths == null ? '' : String(pay.installmentIntervalMonths)"
|
|
|
+ type="number"
|
|
|
+ label="每期间隔(月)"
|
|
|
+ :disabled="disabled"
|
|
|
+ @update:model-value="(v) => onFqField(pIdx, 'installmentIntervalMonths', v)"
|
|
|
+ @blur="rebuildAt(pIdx)"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ :model-value="formatYmd(pay.installmentStartDate)"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ label="分期开始时间"
|
|
|
+ placeholder="选择日期"
|
|
|
+ :disabled="disabled"
|
|
|
+ @click="!disabled && openDatePicker(pIdx, 'installmentStartDate')"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ :model-value="pay.installmentAdvanceDays == null ? '' : String(pay.installmentAdvanceDays)"
|
|
|
+ type="digit"
|
|
|
+ label="提前催缴预警(天)"
|
|
|
+ :disabled="disabled"
|
|
|
+ @update:model-value="(v) => onFqField(pIdx, 'installmentAdvanceDays', v)"
|
|
|
+ @blur="rebuildAt(pIdx)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </van-cell-group>
|
|
|
+
|
|
|
+ <div class="protocol-sample-pay__schedules">
|
|
|
+ <div class="protocol-sample-pay__sub">应缴批次</div>
|
|
|
+ <van-empty
|
|
|
+ v-if="!(pay.schedules || []).length"
|
|
|
+ description="请完善缴费参数后自动生成"
|
|
|
+ image-size="48"
|
|
|
+ />
|
|
|
+ <van-cell-group
|
|
|
+ v-for="(sch, sIdx) in pay.schedules || []"
|
|
|
+ :key="sch.id || sIdx"
|
|
|
+ inset
|
|
|
+ class="protocol-sample-pay__sch"
|
|
|
+ >
|
|
|
+ <div class="protocol-sample-pay__sch-title">第 {{ sch.scheduleNo || sIdx + 1 }} 期</div>
|
|
|
+ <van-field
|
|
|
+ :model-value="sch.dueAmount == null ? '' : String(sch.dueAmount)"
|
|
|
+ type="number"
|
|
|
+ label="应缴费金额"
|
|
|
+ :disabled="disabled || isScheduleLocked(sch)"
|
|
|
+ @update:model-value="(v) => onDueAmountChange(pIdx, sIdx, v)"
|
|
|
+ />
|
|
|
+ <van-field
|
|
|
+ :model-value="formatYmd(sch.dueDate)"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ label="应缴费时间"
|
|
|
+ placeholder="选择日期"
|
|
|
+ :disabled="disabled || isScheduleLocked(sch)"
|
|
|
+ @click="!disabled && !isScheduleLocked(sch) && openScheduleDate(pIdx, sIdx)"
|
|
|
+ />
|
|
|
+ </van-cell-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <van-action-sheet
|
|
|
+ v-model:show="modeSheetVisible"
|
|
|
+ :actions="modeSheetActions"
|
|
|
+ cancel-text="取消"
|
|
|
+ close-on-click-action
|
|
|
+ @select="onPayModeSelect"
|
|
|
+ />
|
|
|
+ <van-popup v-model:show="datePickerVisible" position="bottom" round>
|
|
|
+ <van-date-picker
|
|
|
+ v-model="datePickerValue"
|
|
|
+ title="选择日期"
|
|
|
+ :min-date="minDate"
|
|
|
+ :max-date="maxDate"
|
|
|
+ @confirm="onDateConfirm"
|
|
|
+ @cancel="datePickerVisible = false"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+ </section>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { computed, ref, watch } from 'vue'
|
|
|
+import { showConfirmDialog, showToast } from 'vant'
|
|
|
+import {
|
|
|
+ applyConsolidateRemainingToPayment,
|
|
|
+ applyExpandRemainingToInstallment,
|
|
|
+ applyLumpSumDeadlineToLastDueDate,
|
|
|
+ availableSamplePayModes,
|
|
|
+ calcLastPeriodDueAmount,
|
|
|
+ DEFAULT_INSTALLMENT_ADVANCE_DAYS,
|
|
|
+ rebuildSampleSchedules,
|
|
|
+ resolvePerSamplePaymentDefaults,
|
|
|
+ samplePaymentHasConfirmedTransfer,
|
|
|
+ shouldAutoFillLastPeriodDue
|
|
|
+} from '../protocol-sample-payment.js'
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ modelValue: { type: Array, default: () => [] },
|
|
|
+ samples: { type: Array, default: () => [] },
|
|
|
+ disabled: { type: Boolean, default: false }
|
|
|
+})
|
|
|
+const emit = defineEmits(['update:modelValue'])
|
|
|
+
|
|
|
+const lastPeriodDueOverrideByKey = ref({})
|
|
|
+const modeSheetVisible = ref(false)
|
|
|
+const modeSheetPayIdx = ref(-1)
|
|
|
+const modeSheetActions = ref([])
|
|
|
+const datePickerVisible = ref(false)
|
|
|
+const datePickerValue = ref(['2026', '10', '13'])
|
|
|
+const dateTarget = ref(null)
|
|
|
+const minDate = new Date(2020, 0, 1)
|
|
|
+const maxDate = new Date(2040, 11, 31)
|
|
|
+
|
|
|
+const syncedPayments = computed(() => props.modelValue || [])
|
|
|
+
|
|
|
+const PAY_MODE_LABELS = { dj: '趸交', fq: '分期', fgd: '分改趸' }
|
|
|
+function payModeLabel(mode) {
|
|
|
+ return PAY_MODE_LABELS[String(mode || '')] || '请选择'
|
|
|
+}
|
|
|
+
|
|
|
+function sampleTitle(pay) {
|
|
|
+ const sample = (props.samples || []).find(
|
|
|
+ (s) => String(s.sampleCode || '') === String(pay.sampleCode || '')
|
|
|
+ )
|
|
|
+ return String(sample?.sampleTypeName || sample?.sampleName || '样本')
|
|
|
+}
|
|
|
+
|
|
|
+function formatYmd(raw) {
|
|
|
+ const compact = String(raw || '').replace(/-/g, '')
|
|
|
+ if (!/^\d{8}$/.test(compact)) return ''
|
|
|
+ return `${compact.slice(0, 4)}-${compact.slice(4, 6)}-${compact.slice(6, 8)}`
|
|
|
+}
|
|
|
+
|
|
|
+function toYmdParts(raw) {
|
|
|
+ const compact = String(raw || '').replace(/-/g, '')
|
|
|
+ if (/^\d{8}$/.test(compact)) {
|
|
|
+ return [compact.slice(0, 4), compact.slice(4, 6), compact.slice(6, 8)]
|
|
|
+ }
|
|
|
+ const now = new Date()
|
|
|
+ return [
|
|
|
+ String(now.getFullYear()),
|
|
|
+ String(now.getMonth() + 1).padStart(2, '0'),
|
|
|
+ String(now.getDate()).padStart(2, '0')
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+function emitList(list) {
|
|
|
+ emit('update:modelValue', list)
|
|
|
+}
|
|
|
+
|
|
|
+function samplePayKey(pay, pIdx) {
|
|
|
+ return String(pay.sampleCode || pay.protocolSampleId || pIdx)
|
|
|
+}
|
|
|
+
|
|
|
+function isScheduleLocked(sch) {
|
|
|
+ return (sch.transfers || []).some((t) => t.payStatus === 'yjf')
|
|
|
+}
|
|
|
+
|
|
|
+function activeScheduleIndices(schedules) {
|
|
|
+ const idx = []
|
|
|
+ ;(schedules || []).forEach((s, i) => {
|
|
|
+ if (String(s.scheduleStatus || 'open') !== 'void' && !s._deleted) idx.push(i)
|
|
|
+ })
|
|
|
+ return idx
|
|
|
+}
|
|
|
+
|
|
|
+function emptyDjPayment(sample) {
|
|
|
+ const defaults = resolvePerSamplePaymentDefaults(sample, 'dj')
|
|
|
+ const amount = defaults.contractAmount
|
|
|
+ return rebuildSampleSchedules({
|
|
|
+ sampleCode: String(sample.sampleCode || ''),
|
|
|
+ protocolSampleId: sample.id || '',
|
|
|
+ payMode: 'dj',
|
|
|
+ contractAmount: amount,
|
|
|
+ lumpSumDeadline: '',
|
|
|
+ installmentCount: null,
|
|
|
+ installmentIntervalMonths: null,
|
|
|
+ installmentStartDate: '',
|
|
|
+ installmentAdvanceDays: DEFAULT_INSTALLMENT_ADVANCE_DAYS,
|
|
|
+ installmentRatios: [],
|
|
|
+ schedules: []
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.samples,
|
|
|
+ (samples) => {
|
|
|
+ const list = [...(props.modelValue || [])]
|
|
|
+ const byCode = new Map(list.map((p) => [String(p.sampleCode || ''), p]))
|
|
|
+ const next = []
|
|
|
+ for (const sample of samples || []) {
|
|
|
+ const code = String(sample.sampleCode || '').trim()
|
|
|
+ if (!code) continue
|
|
|
+ if (byCode.has(code)) {
|
|
|
+ const prev = { ...byCode.get(code), protocolSampleId: sample.id || byCode.get(code).protocolSampleId }
|
|
|
+ next.push(prev)
|
|
|
+ } else {
|
|
|
+ next.push(emptyDjPayment(sample))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const same =
|
|
|
+ next.length === list.length &&
|
|
|
+ next.every((p, i) => p.sampleCode === list[i]?.sampleCode)
|
|
|
+ if (!same) emitList(next)
|
|
|
+ },
|
|
|
+ { deep: true, immediate: true }
|
|
|
+)
|
|
|
+
|
|
|
+function patchPay(pIdx, patch, rebuild = false) {
|
|
|
+ const list = [...(props.modelValue || [])]
|
|
|
+ let next = { ...list[pIdx], ...patch }
|
|
|
+ if (rebuild) next = rebuildSampleSchedules(next)
|
|
|
+ list[pIdx] = next
|
|
|
+ emitList(list)
|
|
|
+}
|
|
|
+
|
|
|
+function rebuildAt(pIdx) {
|
|
|
+ patchPay(pIdx, {}, true)
|
|
|
+}
|
|
|
+
|
|
|
+function onContractChange(pIdx, raw) {
|
|
|
+ const n = raw === '' || raw == null ? null : Number(raw)
|
|
|
+ patchPay(pIdx, { contractAmount: Number.isFinite(n) ? n : null }, true)
|
|
|
+}
|
|
|
+
|
|
|
+function onFqField(pIdx, key, raw) {
|
|
|
+ const n = raw === '' || raw == null ? null : Number(raw)
|
|
|
+ patchPay(pIdx, { [key]: Number.isFinite(n) ? n : null }, false)
|
|
|
+}
|
|
|
+
|
|
|
+function onDueAmountChange(pIdx, sIdx, raw) {
|
|
|
+ const list = [...(props.modelValue || [])]
|
|
|
+ const pay = { ...list[pIdx] }
|
|
|
+ const schedules = [...(pay.schedules || [])]
|
|
|
+ const n = raw === '' || raw == null ? null : Number(raw)
|
|
|
+ schedules[sIdx] = {
|
|
|
+ ...schedules[sIdx],
|
|
|
+ dueAmount: Number.isFinite(n) ? n : null
|
|
|
+ }
|
|
|
+ const mode = String(pay.payMode || '')
|
|
|
+ const key = samplePayKey(pay, pIdx)
|
|
|
+ const activeIdx = activeScheduleIndices(schedules)
|
|
|
+
|
|
|
+ if (mode === 'fq' && activeIdx.length >= 2) {
|
|
|
+ const lastIdx = activeIdx[activeIdx.length - 1]
|
|
|
+ if (sIdx === lastIdx) {
|
|
|
+ lastPeriodDueOverrideByKey.value = { ...lastPeriodDueOverrideByKey.value, [key]: true }
|
|
|
+ } else if (activeIdx.slice(0, -1).includes(sIdx)) {
|
|
|
+ lastPeriodDueOverrideByKey.value = { ...lastPeriodDueOverrideByKey.value, [key]: false }
|
|
|
+ const lastSch = schedules[lastIdx]
|
|
|
+ const canFill = shouldAutoFillLastPeriodDue({
|
|
|
+ lastManualOverride: false,
|
|
|
+ lastLocked: isScheduleLocked(lastSch)
|
|
|
+ })
|
|
|
+ if (canFill) {
|
|
|
+ const priors = activeIdx.slice(0, -1).map((i) => schedules[i]?.dueAmount)
|
|
|
+ const lastAmt = calcLastPeriodDueAmount(pay.contractAmount, priors)
|
|
|
+ if (lastAmt != null) {
|
|
|
+ schedules[lastIdx] = { ...schedules[lastIdx], dueAmount: lastAmt }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pay.schedules = schedules
|
|
|
+ pay.installmentRatios = schedules.map((s) => {
|
|
|
+ const amt = Number(s.dueAmount)
|
|
|
+ return Number.isFinite(amt) && amt > 0 ? amt : 0
|
|
|
+ })
|
|
|
+ list[pIdx] = pay
|
|
|
+ emitList(list)
|
|
|
+}
|
|
|
+
|
|
|
+function openPayModeSheet(pIdx) {
|
|
|
+ const pay = props.modelValue?.[pIdx]
|
|
|
+ if (!pay) return
|
|
|
+ modeSheetPayIdx.value = pIdx
|
|
|
+ modeSheetActions.value = availableSamplePayModes(pay).map((value) => ({
|
|
|
+ name: PAY_MODE_LABELS[value] || value,
|
|
|
+ value
|
|
|
+ }))
|
|
|
+ modeSheetVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+async function onPayModeSelect(action) {
|
|
|
+ const pIdx = modeSheetPayIdx.value
|
|
|
+ const mode = action.value
|
|
|
+ const list = props.modelValue || []
|
|
|
+ const prev = list[pIdx]
|
|
|
+ const prevMode = String(prev?.payMode || '')
|
|
|
+ if (!prev || mode === prevMode) return
|
|
|
+
|
|
|
+ const hasPaid = samplePaymentHasConfirmedTransfer(prev)
|
|
|
+ const schCount = (prev.schedules || []).filter(
|
|
|
+ (s) => String(s.scheduleStatus || 'open') !== 'void' && !s._deleted
|
|
|
+ ).length
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (prevMode === 'fq' && (mode === 'dj' || mode === 'fgd') && schCount > 0) {
|
|
|
+ const label = mode === 'dj' ? '趸交' : '分改趸'
|
|
|
+ await showConfirmDialog({
|
|
|
+ title: `确认改为${label}`,
|
|
|
+ message: hasPaid
|
|
|
+ ? `改为${label}将保留已缴期,并把后续未缴合并至当前未清期。是否继续?`
|
|
|
+ : `改为${label}将把各期未缴合并为当前未清期。是否继续?`
|
|
|
+ })
|
|
|
+ const nextList = [...list]
|
|
|
+ nextList[pIdx] = applyConsolidateRemainingToPayment({ ...nextList[pIdx] }, mode)
|
|
|
+ emitList(nextList)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hasPaid && (prevMode === 'dj' || prevMode === 'fgd') && mode === 'fq') {
|
|
|
+ await showConfirmDialog({
|
|
|
+ title: '确认改为分期',
|
|
|
+ message: '改为分期将保留已缴期,剩余金额按分期期数自动生成后续应缴批次。是否继续?'
|
|
|
+ })
|
|
|
+ const cur = { ...list[pIdx] }
|
|
|
+ const count = Number(cur.installmentCount) || 6
|
|
|
+ const interval = Number(cur.installmentIntervalMonths) || 1
|
|
|
+ let startDate = String(cur.installmentStartDate || '').trim()
|
|
|
+ if (!startDate) startDate = String(cur.lumpSumDeadline || '').trim()
|
|
|
+ if (!startDate) {
|
|
|
+ const d = new Date()
|
|
|
+ startDate = `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, '0')}${String(d.getDate()).padStart(2, '0')}`
|
|
|
+ }
|
|
|
+ const nextList = [...list]
|
|
|
+ nextList[pIdx] = applyExpandRemainingToInstallment(cur, {
|
|
|
+ installmentCount: count,
|
|
|
+ installmentIntervalMonths: interval,
|
|
|
+ installmentStartDate: startDate,
|
|
|
+ installmentAdvanceDays: cur.installmentAdvanceDays ?? DEFAULT_INSTALLMENT_ADVANCE_DAYS
|
|
|
+ })
|
|
|
+ emitList(nextList)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const sample = (props.samples || []).find(
|
|
|
+ (s) => String(s.sampleCode || '') === String(prev?.sampleCode || '')
|
|
|
+ )
|
|
|
+ const presetMode = mode === 'fq' || mode === 'fgd' ? 'fq' : 'dj'
|
|
|
+ const defaults = resolvePerSamplePaymentDefaults(sample, presetMode)
|
|
|
+ const patch = {
|
|
|
+ payMode: mode,
|
|
|
+ contractAmount: defaults.contractAmount ?? prev?.contractAmount ?? null
|
|
|
+ }
|
|
|
+ if (mode === 'fq' || mode === 'fgd') {
|
|
|
+ patch.installmentCount = mode === 'fgd' ? 3 : defaults.installmentCount || 6
|
|
|
+ patch.installmentIntervalMonths = 1
|
|
|
+ patch.installmentAdvanceDays = DEFAULT_INSTALLMENT_ADVANCE_DAYS
|
|
|
+ patch.installmentRatios = []
|
|
|
+ } else {
|
|
|
+ patch.installmentCount = null
|
|
|
+ patch.installmentRatios = []
|
|
|
+ }
|
|
|
+ patchPay(pIdx, patch, true)
|
|
|
+ } catch (error) {
|
|
|
+ if (error === 'cancel' || error?.message === 'cancel') return
|
|
|
+ showToast(error?.message || '无法切换缴费模式')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function openDatePicker(pIdx, field) {
|
|
|
+ dateTarget.value = { type: 'pay', pIdx, field }
|
|
|
+ datePickerValue.value = toYmdParts(props.modelValue?.[pIdx]?.[field])
|
|
|
+ datePickerVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+function openScheduleDate(pIdx, sIdx) {
|
|
|
+ dateTarget.value = { type: 'schedule', pIdx, sIdx }
|
|
|
+ datePickerValue.value = toYmdParts(props.modelValue?.[pIdx]?.schedules?.[sIdx]?.dueDate)
|
|
|
+ datePickerVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+function onDateConfirm({ selectedValues }) {
|
|
|
+ const parts = selectedValues || datePickerValue.value
|
|
|
+ const ymd = `${parts[0]}${parts[1]}${parts[2]}`
|
|
|
+ const target = dateTarget.value
|
|
|
+ datePickerVisible.value = false
|
|
|
+ if (!target) return
|
|
|
+ if (target.type === 'pay') {
|
|
|
+ if (target.field === 'lumpSumDeadline') {
|
|
|
+ const list = [...(props.modelValue || [])]
|
|
|
+ const pay = { ...list[target.pIdx] }
|
|
|
+ pay.lumpSumDeadline = ymd
|
|
|
+ if (String(pay.payMode || '') === 'dj') {
|
|
|
+ pay.schedules = applyLumpSumDeadlineToLastDueDate(
|
|
|
+ [...(pay.schedules || [])],
|
|
|
+ ymd,
|
|
|
+ isScheduleLocked
|
|
|
+ )
|
|
|
+ }
|
|
|
+ list[target.pIdx] = pay
|
|
|
+ emitList(list)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ patchPay(target.pIdx, { [target.field]: ymd }, target.field === 'installmentStartDate')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (target.type === 'schedule') {
|
|
|
+ const list = [...(props.modelValue || [])]
|
|
|
+ const pay = { ...list[target.pIdx] }
|
|
|
+ const schedules = [...(pay.schedules || [])]
|
|
|
+ schedules[target.sIdx] = { ...schedules[target.sIdx], dueDate: ymd }
|
|
|
+ pay.schedules = schedules
|
|
|
+ list[target.pIdx] = pay
|
|
|
+ emitList(list)
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.protocol-sample-pay__hint {
|
|
|
+ margin: 0 16px 12px;
|
|
|
+ color: #64748b;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+.protocol-sample-pay__card {
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+.protocol-sample-pay__head {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 0 16px 8px;
|
|
|
+}
|
|
|
+.protocol-sample-pay__code {
|
|
|
+ color: #64748b;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+.protocol-sample-pay__sub {
|
|
|
+ padding: 12px 16px 8px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #334155;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+.protocol-sample-pay__sch {
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+.protocol-sample-pay__sch-title {
|
|
|
+ padding: 10px 16px 0;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #0a9f6d;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+</style>
|