Some checks failed
构建并部署前端到测试环境 / deploy (push) Failing after 4m33s
- 延期弹窗、沉默期流水弹窗的 allowed 未传时默认允许:Vue 会把未传的布尔 prop 当成 false,资产详情入口一律被拦截 - 沉默期相关弹窗挂到 body,避免在表格固定列里渲染被其他固定列盖住
601 lines
21 KiB
Vue
601 lines
21 KiB
Vue
<template>
|
||
<ElDialog
|
||
:model-value="true"
|
||
append-to-body
|
||
title="办理沉默期延期"
|
||
width="min(760px, 96vw)"
|
||
destroy-on-close
|
||
@close="$emit('close')"
|
||
>
|
||
<ElAlert
|
||
title="金额和延期截止时间以服务端试算及处理结果为准;待审批或已支付不代表延期已生效。"
|
||
type="info"
|
||
:closable="false"
|
||
/>
|
||
<ElAlert
|
||
v-if="error || eligibilityError"
|
||
:title="error || eligibilityError"
|
||
type="error"
|
||
:closable="false"
|
||
/>
|
||
<ElForm label-width="140px" :disabled="submitting || !!order || !!batch">
|
||
<ElFormItem label="办理方式"
|
||
><ElSelect v-model="mode"
|
||
><ElOption
|
||
v-if="hasAuth(P.extend) && usageId"
|
||
value="online"
|
||
label="扫码付费延期" /><ElOption
|
||
v-if="hasAuth(P.offline) && usageId"
|
||
value="offline"
|
||
label="登记线下付款" /><ElOption
|
||
v-if="hasAuth(P.extend)"
|
||
value="special"
|
||
label="特殊延期" /></ElSelect
|
||
></ElFormItem>
|
||
<template v-if="usageId">
|
||
<ElFormItem label="套餐记录"
|
||
>{{ usageId }}
|
||
<ElButton link :loading="eligibilityLoading" @click="loadEligibility"
|
||
>刷新资格</ElButton
|
||
></ElFormItem
|
||
>
|
||
<ElFormItem v-if="eligibility" label="延期资格"
|
||
><span
|
||
>{{
|
||
eligibility.reason || (eligibility.can_extend ? '可以付费延期' : '不能付费延期')
|
||
}};特殊延期:{{
|
||
eligibility.special_extension_available ? '可申请' : '不可申请'
|
||
}}</span
|
||
></ElFormItem
|
||
>
|
||
<ElFormItem v-if="eligibility?.pending_order_no" label="待处理订单"
|
||
>{{ eligibility.pending_order_no }}
|
||
<ElButton link :disabled="submitting" @click="resumeOrder">查看订单</ElButton></ElFormItem
|
||
>
|
||
</template>
|
||
<ElFormItem label="延期天数" required
|
||
><ElInputNumber v-model="days" :min="1" :precision="0" :step="1" /><span
|
||
v-if="mode !== 'special' && eligibility"
|
||
>({{ eligibility.min_days ?? '-' }}~{{ eligibility.max_days ?? '-' }} 天)</span
|
||
></ElFormItem
|
||
>
|
||
<template v-if="mode !== 'special'">
|
||
<ElFormItem label="后端试算"
|
||
><ElButton :loading="quoteLoading" :disabled="!eligibility?.can_extend" @click="loadQuote"
|
||
>试算</ElButton
|
||
><span v-if="quote"
|
||
>实际延长 {{ quote.billed_days ?? '-' }} 天,{{ silenceAmount(quote.amount) }},新截止日
|
||
{{ quote.new_deadline || '-' }}(当日 23:59:59)</span
|
||
></ElFormItem
|
||
>
|
||
<ElFormItem v-if="mode === 'online'" label="支付方式"
|
||
><ElSelect v-model="paymentMethod"
|
||
><ElOption value="wechat" label="微信支付" /><ElOption
|
||
value="alipay"
|
||
label="支付宝" /></ElSelect
|
||
></ElFormItem>
|
||
</template>
|
||
<template v-else>
|
||
<ElFormItem label="延期类型" required
|
||
><ElSelect v-model="specialType"
|
||
><ElOption v-for="item in specialTypes" :key="item.value" v-bind="item" /></ElSelect
|
||
></ElFormItem>
|
||
<ElFormItem label="原因" required><ElInput v-model="reason" type="textarea" /></ElFormItem>
|
||
<ElFormItem label="依据" required><ElInput v-model="basis" type="textarea" /></ElFormItem>
|
||
<ElFormItem v-if="hasAuth(P.batch)" label="批量 CSV"
|
||
><ElUpload :auto-upload="false" :show-file-list="false" accept=".csv" :on-change="readCsv"
|
||
><ElButton>选择 CSV 明细</ElButton></ElUpload
|
||
><p
|
||
>表头 package_usage_id,days;每行一笔。选中后将替代当前单项。天数由后端按 30
|
||
天向上取整。</p
|
||
></ElFormItem
|
||
>
|
||
<ElFormItem v-if="batchItems.length" label="导入明细"
|
||
><span>{{ batchItems.length }} 项</span
|
||
><ElButton link @click="batchItems = []">清除</ElButton></ElFormItem
|
||
>
|
||
<ElFormItem v-if="specialType === 'discount'" label="实收合计(元)" required
|
||
><ElInput v-model="paidYuan" inputmode="decimal"
|
||
/></ElFormItem>
|
||
</template>
|
||
<template v-if="requiresReceipt">
|
||
<ElFormItem label="线下收款方式" required
|
||
><ElSelect
|
||
v-model="methodId"
|
||
filterable
|
||
:loading="methodsLoading"
|
||
@visible-change="(value) => value && loadMethods()"
|
||
><ElOption
|
||
v-for="item in methods"
|
||
:key="item.id"
|
||
:value="item.id"
|
||
:label="item.name" /></ElSelect
|
||
></ElFormItem>
|
||
<ElFormItem label="交易单号" required><ElInput v-model="tradeNo" /></ElFormItem>
|
||
<ElFormItem v-if="mode === 'offline'" label="实收金额(元)" required
|
||
><ElInput v-model="paidYuan" inputmode="decimal"
|
||
/></ElFormItem>
|
||
<ElFormItem label="付款时间" required
|
||
><ElDatePicker
|
||
v-model="paidAt"
|
||
type="datetime"
|
||
value-format="YYYY-MM-DDTHH:mm:ssZ"
|
||
format="YYYY-MM-DD HH:mm:ss"
|
||
/></ElFormItem>
|
||
<ElFormItem label="收款凭证" required
|
||
><VoucherUpload
|
||
v-model="vouchers"
|
||
:key="`vouchers-${mode}`"
|
||
:max-count="5"
|
||
@uploading-change="(value) => (uploadingReceipt = value)"
|
||
/></ElFormItem>
|
||
</template>
|
||
<ElFormItem label="申请记录/截图"
|
||
><VoucherUpload
|
||
v-model="evidence"
|
||
:max-count="5"
|
||
@uploading-change="(value) => (uploadingEvidence = value)"
|
||
/></ElFormItem>
|
||
</ElForm>
|
||
<ElAlert
|
||
v-if="order"
|
||
:title="`订单 ${order.order_no || '-'}:${order.status_name || order.status || '-'};实际生效以完成状态为准`"
|
||
type="info"
|
||
:closable="false"
|
||
/>
|
||
<div v-if="order?.status === 'pending_payment' && order.qr_content" class="silence-qr"
|
||
><QrcodeVue :value="order.qr_content" :size="200" level="M" /><p
|
||
>支付截止:{{ order.expire_at ? formatDateTime(order.expire_at) : '-' }}</p
|
||
></div
|
||
>
|
||
<ElButton v-if="order?.id" :loading="checking" @click="refreshOrder">刷新订单状态</ElButton>
|
||
<ElAlert
|
||
v-if="batch"
|
||
:title="`批次 ${batch.batch_no || '-'}:${batch.status || '-'};审批 ${batch.approval_status || '-'};成功 ${batch.succeeded_count ?? '-'},失败 ${batch.failed_count ?? '-'}`"
|
||
:closable="false"
|
||
/>
|
||
<SilenceTable v-if="batch?.items?.length" :rows="batch.items" :definitions="resultFields" />
|
||
<ElTable v-if="rowErrors.length" :data="rowErrors"
|
||
><ElTableColumn label="行号"
|
||
><template #default="{ row }">{{ row.row_no ?? row.row ?? '-' }}</template></ElTableColumn
|
||
><ElTableColumn label="失败原因"
|
||
><template #default="{ row }">{{
|
||
row.reason || row.message || '-'
|
||
}}</template></ElTableColumn
|
||
></ElTable
|
||
>
|
||
<template #footer
|
||
><ElButton @click="$emit('close')">关闭</ElButton
|
||
><ElButton
|
||
v-if="!order && !batch"
|
||
type="primary"
|
||
:loading="submitting"
|
||
:disabled="!canSubmit || uploadingReceipt || uploadingEvidence"
|
||
@click="submit"
|
||
>确认提交</ElButton
|
||
></template
|
||
>
|
||
</ElDialog>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import { ref, computed, watch, onMounted, onBeforeUnmount, onDeactivated } from 'vue'
|
||
import { ElMessageBox } from 'element-plus'
|
||
import type { UploadFile } from 'element-plus'
|
||
import QrcodeVue from 'qrcode.vue'
|
||
import { PackageSilenceService as Service } from '@/api/modules/packageSilence'
|
||
import { EmployeeCollectionService } from '@/api/modules/employeeCollection'
|
||
import { useAuth } from '@/composables/useAuth'
|
||
import { useUserStore } from '@/store/modules/user'
|
||
import { useSchedulerRequest } from '@/composables/useSchedulerRequest'
|
||
import { pollingScope } from '@/utils/business/pollingScheduler'
|
||
import { PACKAGE_SILENCE_PERMISSIONS as P } from '@/config/constants/packageSilence'
|
||
import {
|
||
silenceData,
|
||
silenceId,
|
||
silenceDays,
|
||
silenceFen,
|
||
silenceDate,
|
||
silenceAmount,
|
||
parseSilenceCsv,
|
||
silenceRowsError,
|
||
SILENCE_SPECIAL_TYPES,
|
||
silenceOptions
|
||
} from '@/utils/business/silenceExtension'
|
||
import { gatewayError, requireGatewayAccess } from '@/utils/business/gateway'
|
||
import { formatDateTime } from '@/utils/business/format'
|
||
import type {
|
||
SilenceExtensionOrderResponse,
|
||
SilenceBatchResponse,
|
||
SilenceSpecialItem
|
||
} from '@/types/api/packageSilenceContract'
|
||
import VoucherUpload from '@/components/business/VoucherUpload.vue'
|
||
import SilenceTable from './SilenceTable.vue'
|
||
// allowed 未传时视为允许:Vue 会把未传的布尔 prop 当成 false,不设默认值时资产详情入口一律报"无权执行此操作"
|
||
const props = withDefaults(
|
||
defineProps<{ usageId?: number; allowed?: boolean; batchMode?: boolean }>(),
|
||
{ allowed: true, batchMode: false }
|
||
)
|
||
const emit = defineEmits<{ close: []; changed: [] }>()
|
||
const { hasAuth } = useAuth(),
|
||
user = useUserStore()
|
||
const mode = ref<'online' | 'offline' | 'special'>(
|
||
props.batchMode ? 'special' : hasAuth(P.extend) ? 'online' : 'offline'
|
||
)
|
||
const days = ref<number | undefined>(),
|
||
paymentMethod = ref('wechat'),
|
||
specialType = ref('free'),
|
||
reason = ref(''),
|
||
basis = ref('')
|
||
const methodId = ref<number>(),
|
||
tradeNo = ref(''),
|
||
paidYuan = ref(''),
|
||
paidAt = ref(''),
|
||
vouchers = ref<string[]>([]),
|
||
evidence = ref<string[]>([])
|
||
const batchItems = ref<SilenceSpecialItem[]>([]),
|
||
specialUncertain = ref(false),
|
||
error = ref(''),
|
||
submitting = ref(false),
|
||
checking = ref(false)
|
||
const uploadingReceipt = ref(false),
|
||
uploadingEvidence = ref(false),
|
||
methodsLoading = ref(false),
|
||
methods = ref<{ id: number; name: string }[]>([])
|
||
const order = ref<SilenceExtensionOrderResponse>(),
|
||
batch = ref<SilenceBatchResponse>(),
|
||
rowErrors = ref<ReturnType<typeof silenceRowsError>>([])
|
||
const specialTypes = silenceOptions(SILENCE_SPECIAL_TYPES)
|
||
const allowed = () =>
|
||
props.allowed !== false &&
|
||
(mode.value === 'offline' ? hasAuth(P.offline) : hasAuth(P.extend)) &&
|
||
(!props.batchMode || hasAuth(P.batch))
|
||
const eligibilityAllowed = computed(() => allowed() && !!props.usageId)
|
||
const {
|
||
data: eligibility,
|
||
loading: eligibilityLoading,
|
||
error: eligibilityError,
|
||
load: loadEligibility,
|
||
clear: clearEligibility
|
||
} = useSchedulerRequest(
|
||
async () => silenceData(await Service.eligibility(silenceId(props.usageId))),
|
||
() => eligibilityAllowed.value
|
||
)
|
||
const {
|
||
data: quote,
|
||
loading: quoteLoading,
|
||
load: requestQuote,
|
||
clear: clearQuote,
|
||
error: quoteError
|
||
} = useSchedulerRequest(
|
||
async () => {
|
||
const input = silenceDays(days.value),
|
||
usage = silenceId(props.usageId)
|
||
return { ...silenceData(await Service.quote(usage, input)), forDays: input, forUsage: usage }
|
||
},
|
||
() => eligibilityAllowed.value && !!eligibility.value?.can_extend
|
||
)
|
||
const requiresReceipt = computed(
|
||
() =>
|
||
mode.value === 'offline' ||
|
||
(mode.value === 'special' && specialType.value === 'discount' && Number(paidYuan.value) > 0)
|
||
)
|
||
const canSubmit = computed(
|
||
() =>
|
||
allowed() &&
|
||
!specialUncertain.value &&
|
||
(mode.value === 'special'
|
||
? batchItems.value.length
|
||
? hasAuth(P.batch)
|
||
: !!eligibility.value?.special_extension_available
|
||
: !!eligibility.value?.can_extend &&
|
||
!!quote.value?.valid &&
|
||
quote.value.forDays === days.value &&
|
||
quote.value.forUsage === props.usageId &&
|
||
Number.isSafeInteger(quote.value.amount))
|
||
)
|
||
let active = true,
|
||
version = 0,
|
||
timer: ReturnType<typeof setTimeout> | undefined
|
||
const requestIds = new Map<string, string>()
|
||
function stop() {
|
||
if (timer) clearTimeout(timer)
|
||
timer = undefined
|
||
}
|
||
function invalidate() {
|
||
version++
|
||
stop()
|
||
order.value = undefined
|
||
batch.value = undefined
|
||
rowErrors.value = []
|
||
error.value = ''
|
||
clearQuote()
|
||
clearEligibility()
|
||
vouchers.value = []
|
||
evidence.value = []
|
||
methods.value = []
|
||
methodsLoading.value = false
|
||
days.value = undefined
|
||
reason.value = ''
|
||
basis.value = ''
|
||
methodId.value = undefined
|
||
tradeNo.value = ''
|
||
paidYuan.value = ''
|
||
paidAt.value = ''
|
||
batchItems.value = []
|
||
}
|
||
watch(
|
||
() => [props.usageId, props.allowed, pollingScope(user)],
|
||
() => {
|
||
invalidate()
|
||
if (props.usageId && allowed()) void loadEligibility()
|
||
},
|
||
{ flush: 'sync' }
|
||
)
|
||
watch(
|
||
() => [mode.value, days.value],
|
||
() => {
|
||
clearQuote()
|
||
error.value = ''
|
||
},
|
||
{ flush: 'sync' }
|
||
)
|
||
watch(
|
||
() => allowed(),
|
||
(value) => {
|
||
if (!value) invalidate()
|
||
},
|
||
{ flush: 'sync' }
|
||
)
|
||
watch(quoteError, (value) => {
|
||
if (value) error.value = value
|
||
})
|
||
async function loadQuote() {
|
||
await requestQuote()
|
||
}
|
||
async function loadMethods() {
|
||
if (!allowed() || methodsLoading.value) return
|
||
const current = version,
|
||
scope = pollingScope(user)
|
||
methodsLoading.value = true
|
||
try {
|
||
const result = silenceData(
|
||
await EmployeeCollectionService.getPaymentMethods({
|
||
page: 1,
|
||
page_size: 100,
|
||
enabled: true
|
||
})
|
||
)
|
||
if (!active || current !== version || scope !== pollingScope(user) || !allowed()) return
|
||
const values = Array.isArray(result) ? result : result.items || []
|
||
methods.value = values.map((item) => ({ id: item.id, name: item.name }))
|
||
} catch (e) {
|
||
if (current === version) error.value = gatewayError(e)
|
||
} finally {
|
||
if (current === version) methodsLoading.value = false
|
||
}
|
||
}
|
||
async function readCsv(file: UploadFile) {
|
||
try {
|
||
requireGatewayAccess(allowed() && hasAuth(P.batch))
|
||
if (!file.raw || !file.name.toLowerCase().endsWith('.csv')) throw new Error('请选择 CSV 文件')
|
||
const current = version,
|
||
items = parseSilenceCsv(await file.raw.text())
|
||
if (active && current === version && allowed() && hasAuth(P.batch)) batchItems.value = items
|
||
} catch (e) {
|
||
error.value = gatewayError(e)
|
||
}
|
||
}
|
||
async function resumeOrder() {
|
||
const no = eligibility.value?.pending_order_no,
|
||
current = version
|
||
if (!no || !allowed()) return
|
||
try {
|
||
const result = silenceData(await Service.orders({ order_no: no, page: 1, page_size: 20 }))
|
||
if (active && current === version && allowed()) {
|
||
order.value = result.items?.find((item) => item.order_no === no)
|
||
schedule()
|
||
}
|
||
} catch (e) {
|
||
if (current === version) error.value = gatewayError(e)
|
||
}
|
||
}
|
||
function schedule() {
|
||
stop()
|
||
if (active && allowed() && ['pending_payment', 'paid'].includes(order.value?.status || ''))
|
||
timer = setTimeout(() => void refreshOrder(), 3000)
|
||
}
|
||
async function refreshOrder() {
|
||
stop()
|
||
const id = order.value?.id,
|
||
current = version,
|
||
scope = pollingScope(user)
|
||
if (!id || checking.value || !allowed()) return
|
||
checking.value = true
|
||
try {
|
||
const result = silenceData(await Service.order(id))
|
||
if (!active || current !== version || scope !== pollingScope(user) || !allowed()) return
|
||
order.value = result
|
||
if (result.status === 'completed') emit('changed')
|
||
schedule()
|
||
} catch (e) {
|
||
if (current === version) error.value = gatewayError(e)
|
||
} finally {
|
||
checking.value = false
|
||
}
|
||
}
|
||
async function submit() {
|
||
if (submitting.value) return
|
||
const current = version,
|
||
scope = pollingScope(user),
|
||
currentMode = mode.value
|
||
submitting.value = true
|
||
error.value = ''
|
||
rowErrors.value = []
|
||
let specialSent = false
|
||
try {
|
||
requireGatewayAccess(canSubmit.value && !uploadingReceipt.value && !uploadingEvidence.value)
|
||
const input =
|
||
currentMode === 'special' && batchItems.value.length ? 1 : silenceDays(days.value),
|
||
usage =
|
||
batchItems.value.length && currentMode === 'special'
|
||
? undefined
|
||
: silenceId(props.usageId)
|
||
const common = { package_usage_id: usage!, days: input, evidence_refs: [...evidence.value] }
|
||
const receipt = requiresReceipt.value
|
||
? {
|
||
offline_payment_method_id: silenceId(methodId.value, '收款方式'),
|
||
offline_trade_no: tradeNo.value.trim(),
|
||
paid_at: silenceDate(paidAt.value),
|
||
payment_voucher_keys: [...vouchers.value]
|
||
}
|
||
: undefined
|
||
if (
|
||
receipt &&
|
||
(!receipt.offline_trade_no ||
|
||
receipt.payment_voucher_keys.length < 1 ||
|
||
receipt.payment_voucher_keys.length > 5)
|
||
)
|
||
throw new Error('请填写交易单号,并上传 1~5 张收款凭证')
|
||
const amount =
|
||
currentMode === 'offline' || (currentMode === 'special' && specialType.value === 'discount')
|
||
? silenceFen(paidYuan.value)
|
||
: 0
|
||
if (currentMode === 'offline' && amount !== quote.value?.amount)
|
||
throw new Error('实收金额必须等于当前后端试算金额')
|
||
const items = batchItems.value.length
|
||
? batchItems.value.map((item) => ({ ...item }))
|
||
: [{ package_usage_id: usage!, days: input }]
|
||
if (currentMode === 'special' && (!reason.value.trim() || !basis.value.trim()))
|
||
throw new Error('请填写特殊延期原因和依据')
|
||
if (currentMode === 'special' && items.length > 1) requireGatewayAccess(hasAuth(P.batch))
|
||
const body =
|
||
currentMode === 'special'
|
||
? {
|
||
extension_type: specialType.value,
|
||
items,
|
||
reason: reason.value.trim(),
|
||
basis: basis.value.trim(),
|
||
amount,
|
||
evidence_refs: [...evidence.value],
|
||
...(receipt
|
||
? {
|
||
offline_payment_method_id: receipt.offline_payment_method_id,
|
||
offline_trade_no: receipt.offline_trade_no,
|
||
offline_paid_at: receipt.paid_at,
|
||
payment_voucher_keys: receipt.payment_voucher_keys
|
||
}
|
||
: {})
|
||
}
|
||
: currentMode === 'offline'
|
||
? { ...common, ...receipt!, paid_amount: amount }
|
||
: { ...common, payment_method: paymentMethod.value }
|
||
const fingerprint = JSON.stringify([currentMode, body])
|
||
if (!requestIds.has(fingerprint)) requestIds.set(fingerprint, crypto.randomUUID())
|
||
await ElMessageBox.confirm(
|
||
currentMode === 'special'
|
||
? `确认提交 ${items.length} 项特殊延期申请?结果以审批和逐项执行为准。`
|
||
: '确认提交延期订单?待支付或待审批并不代表已生效。',
|
||
'提交确认',
|
||
{ type: 'warning' }
|
||
)
|
||
requireGatewayAccess(
|
||
active &&
|
||
current === version &&
|
||
scope === pollingScope(user) &&
|
||
currentMode === mode.value &&
|
||
canSubmit.value
|
||
)
|
||
// 表单在确认框期间被锁定;同一快照重试复用幂等键,不自动重发写请求。
|
||
specialSent = currentMode === 'special'
|
||
const result =
|
||
currentMode === 'special'
|
||
? silenceData(await Service.special(body as Parameters<typeof Service.special>[0]))
|
||
: currentMode === 'offline'
|
||
? silenceData(
|
||
await Service.createOffline({
|
||
...body,
|
||
request_id: requestIds.get(fingerprint)!
|
||
} as Parameters<typeof Service.createOffline>[0])
|
||
)
|
||
: silenceData(
|
||
await Service.createQrcode({
|
||
...body,
|
||
request_id: requestIds.get(fingerprint)!
|
||
} as Parameters<typeof Service.createQrcode>[0])
|
||
)
|
||
if (!active || current !== version || scope !== pollingScope(user) || !allowed()) return
|
||
if (currentMode === 'special') batch.value = result as SilenceBatchResponse
|
||
else {
|
||
order.value = result as SilenceExtensionOrderResponse
|
||
schedule()
|
||
}
|
||
emit('changed')
|
||
} catch (e) {
|
||
if (active && current === version && e !== 'cancel' && e !== 'close') {
|
||
error.value = gatewayError(e)
|
||
rowErrors.value = silenceRowsError(e)
|
||
if (
|
||
specialSent &&
|
||
!(e as { code?: unknown; response?: unknown })?.code &&
|
||
!(e as { response?: unknown })?.response
|
||
) {
|
||
specialUncertain.value = true
|
||
error.value += '。提交结果未确认,请先到延期批次列表核对,不要重复提交。'
|
||
}
|
||
}
|
||
} finally {
|
||
submitting.value = false
|
||
}
|
||
}
|
||
const resultFields = [
|
||
['row_no', '行号'],
|
||
['asset_identifier', '资产'],
|
||
['package_name', '套餐'],
|
||
['status', '处理状态'],
|
||
['after_deadline_at', '延期后截止'],
|
||
['failure_summary', '失败原因']
|
||
].map(([prop, label]) => ({ prop, label }))
|
||
onMounted(() => {
|
||
if (props.usageId) void loadEligibility()
|
||
})
|
||
onDeactivated(() => {
|
||
active = false
|
||
invalidate()
|
||
})
|
||
onBeforeUnmount(() => {
|
||
active = false
|
||
invalidate()
|
||
})
|
||
</script>
|
||
<style scoped>
|
||
.silence-qr {
|
||
padding: 16px;
|
||
text-align: center;
|
||
}
|
||
|
||
.el-alert {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.el-form-item p {
|
||
margin: 0;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
@media (width <= 640px) {
|
||
:deep(.el-form-item) {
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
:deep(.el-form-item__label) {
|
||
justify-content: flex-start;
|
||
width: 100% !important;
|
||
}
|
||
|
||
:deep(.el-form-item__content) {
|
||
flex-basis: 100%;
|
||
margin-left: 0 !important;
|
||
}
|
||
}
|
||
</style>
|