Some checks failed
构建并部署前端到测试环境 / deploy (push) Has been cancelled
- 登记线下付款时收款凭证放到最前,上传后自动识别交易单号预填(复用凭证识别,需人工核对,不覆盖手填) - 试算后自动带入实收金额 - 延期弹窗显示套餐名称(及资产),不再显示套餐记录 ID
641 lines
21 KiB
Vue
641 lines
21 KiB
Vue
<template>
|
||
<ArtTableFullScreen
|
||
><div id="table-full-screen">
|
||
<ArtSearchBar
|
||
:filter="filters"
|
||
:items="searchItems"
|
||
:show-expand="searchItems.length >= 4"
|
||
label-width="100px"
|
||
@search="search"
|
||
@reset="reset"
|
||
/>
|
||
<ElCard shadow="never" class="art-table-card">
|
||
<ElAlert
|
||
v-if="error || actionError"
|
||
:title="error || actionError"
|
||
type="error"
|
||
:closable="false"
|
||
/>
|
||
<SilenceTable
|
||
:rows="displayRows"
|
||
:row-key="kind === 'usages' ? 'package_usage_id' : 'id'"
|
||
:definitions="fields"
|
||
:loading="loading"
|
||
:total="kind === 'policies' ? undefined : total"
|
||
:page="page"
|
||
:size="size"
|
||
@refresh="load"
|
||
@page="
|
||
(value) => {
|
||
page = value
|
||
load()
|
||
}
|
||
"
|
||
@size="
|
||
(value) => {
|
||
size = value
|
||
search()
|
||
}
|
||
"
|
||
>
|
||
<template #toolbar>
|
||
<ElButton
|
||
v-if="kind === 'policies' && canManagePolicy"
|
||
type="primary"
|
||
@click="editPolicy()"
|
||
>新增政策</ElButton
|
||
>
|
||
<ElButton v-if="kind === 'policies' && canManagePolicy" @click="matchVisible = true"
|
||
>查询套餐匹配政策</ElButton
|
||
>
|
||
<ElButton
|
||
v-if="kind === 'batches' && allowed && hasAuth(P.extend) && hasAuth(P.batch)"
|
||
type="primary"
|
||
@click="batchVisible = true"
|
||
>批量特殊延期</ElButton
|
||
>
|
||
<ElButton
|
||
v-if="exportPermission && allowed && hasAuth(exportPermission)"
|
||
@click="openExport"
|
||
>导出</ElButton
|
||
>
|
||
</template>
|
||
<ElTableColumn label="操作" fixed="right" min-width="200"
|
||
><template #default="{ row }">
|
||
<ElButton v-if="canDetail" type="primary" link @click="detail(row)">详情</ElButton>
|
||
<template v-if="kind === 'usages' && row.silence">
|
||
<ElButton link type="primary" @click="recordsId = row.package_usage_id"
|
||
>沉默期流水</ElButton
|
||
>
|
||
<ElButton
|
||
v-if="row.silence.extendable && (hasAuth(P.extend) || hasAuth(P.offline))"
|
||
link
|
||
type="primary"
|
||
@click="openExtension(row)"
|
||
>延期</ElButton
|
||
>
|
||
</template>
|
||
<template v-if="kind === 'policies' && canManagePolicy"
|
||
><ElButton link type="primary" @click="editPolicy(row)">编辑</ElButton
|
||
><ElButton link :disabled="changing" @click="togglePolicy(row)">{{
|
||
row.status === 1 ? '停用' : '启用'
|
||
}}</ElButton></template
|
||
>
|
||
</template></ElTableColumn
|
||
>
|
||
</SilenceTable>
|
||
<div v-if="kind === 'policies'" class="policy-pager">
|
||
<span>第 {{ page }} 页(接口未返回总数)</span>
|
||
<ElButton :disabled="page <= 1 || loading" @click="previousPolicyPage">上一页</ElButton>
|
||
<ElButton :disabled="rows.length < size || loading" @click="nextPolicyPage"
|
||
>下一页</ElButton
|
||
>
|
||
</div>
|
||
</ElCard>
|
||
<ElDialog
|
||
v-if="matchVisible"
|
||
:model-value="true"
|
||
title="查询套餐匹配政策"
|
||
width="min(600px,96vw)"
|
||
@close="closeMatch"
|
||
>
|
||
<ElForm label-width="80px">
|
||
<ElFormItem label="套餐" required>
|
||
<BusinessEntitySelect
|
||
v-model="matchPackage"
|
||
entity="package"
|
||
:allowed="canManagePolicy"
|
||
/>
|
||
</ElFormItem>
|
||
</ElForm>
|
||
<template #footer>
|
||
<ElButton @click="closeMatch">取消</ElButton>
|
||
<ElButton
|
||
type="primary"
|
||
:disabled="!matchPackage || !canManagePolicy"
|
||
:loading="matching"
|
||
@click="matchPolicy"
|
||
>查询</ElButton
|
||
>
|
||
</template>
|
||
</ElDialog>
|
||
<ElDialog
|
||
v-if="matchResult"
|
||
:model-value="true"
|
||
title="当前匹配政策"
|
||
width="min(600px,96vw)"
|
||
@close="matchResult = undefined"
|
||
><ElDescriptions :column="1" border
|
||
><ElDescriptionsItem label="是否匹配">{{
|
||
matchResult.matched ? '是' : '否'
|
||
}}</ElDescriptionsItem
|
||
><ElDescriptionsItem label="政策">{{
|
||
matchResult.policy?.name || '-'
|
||
}}</ElDescriptionsItem
|
||
><ElDescriptionsItem label="月单价">{{
|
||
silenceAmount(matchResult.policy?.unit_price)
|
||
}}</ElDescriptionsItem></ElDescriptions
|
||
></ElDialog
|
||
>
|
||
<SilenceExtendDialog
|
||
v-if="extendId || batchVisible"
|
||
:usage-id="extendId"
|
||
:package-name="extendRow?.package_name"
|
||
:asset-identifier="extendRow?.asset_identifier"
|
||
:batch-mode="batchVisible"
|
||
:allowed="allowed"
|
||
@close="closeExtension"
|
||
@changed="load"
|
||
/>
|
||
<SilenceRecordsDialog
|
||
v-if="recordsId"
|
||
:usage-id="recordsId"
|
||
:allowed="allowed"
|
||
@close="recordsId = undefined"
|
||
/>
|
||
<SilencePolicyDialog
|
||
v-if="policyVisible"
|
||
:id="policyId"
|
||
:allowed="canManagePolicy"
|
||
@close="policyVisible = false"
|
||
@saved="load"
|
||
/>
|
||
<ExportTaskCreateDialog
|
||
v-if="exportVisible && exportScene"
|
||
v-model="exportVisible"
|
||
:scene="exportScene"
|
||
:query="exportQuery"
|
||
:confirm-permission="exportPermission"
|
||
/> </div
|
||
></ArtTableFullScreen>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import {
|
||
ref,
|
||
reactive,
|
||
computed,
|
||
onMounted,
|
||
onBeforeUnmount,
|
||
onActivated,
|
||
onDeactivated,
|
||
watch
|
||
} from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { ElMessageBox } from 'element-plus'
|
||
import { PackageSilenceService as Service } from '@/api/modules/packageSilence'
|
||
import { useSchedulerRequest } from '@/composables/useSchedulerRequest'
|
||
import { useAuth } from '@/composables/useAuth'
|
||
import { useUserStore } from '@/store/modules/user'
|
||
import { pollingScope } from '@/utils/business/pollingScheduler'
|
||
import {
|
||
silenceData,
|
||
silenceRange,
|
||
silenceDate,
|
||
silenceId,
|
||
silenceAmount,
|
||
silenceOptions,
|
||
SILENCE_ORDER_STATUS,
|
||
SILENCE_SPECIAL_TYPES
|
||
} from '@/utils/business/silenceExtension'
|
||
import { compactGatewayQuery, gatewayError, requireGatewayAccess } from '@/utils/business/gateway'
|
||
import {
|
||
SILENCE_PAGES,
|
||
PACKAGE_SILENCE_PERMISSIONS as P
|
||
} from '@/config/constants/packageSilence'
|
||
import type { SearchFormItem } from '@/types'
|
||
import type { ExportTaskScene } from '@/types/api/exportTask'
|
||
import type { SilencePolicyMatchResponse } from '@/types/api/packageSilenceContract'
|
||
import SilenceTable from './SilenceTable.vue'
|
||
import SilenceExtendDialog from './SilenceExtendDialog.vue'
|
||
import SilenceRecordsDialog from './SilenceRecordsDialog.vue'
|
||
import SilencePolicyDialog from './SilencePolicyDialog.vue'
|
||
import ExportTaskCreateDialog from '@/components/business/ExportTaskCreateDialog.vue'
|
||
import BusinessEntitySelect from '@/components/business/BusinessEntitySelect.vue'
|
||
const props = defineProps<{ kind: 'orders' | 'batches' | 'usages' | 'policies' }>()
|
||
const router = useRouter(),
|
||
user = useUserStore(),
|
||
{ hasAuth } = useAuth(),
|
||
page = ref(1),
|
||
size = ref(20)
|
||
const allowed = computed(
|
||
() =>
|
||
hasAuth(SILENCE_PAGES[props.kind].page) && (props.kind !== 'policies' || hasAuth(P.policy))
|
||
)
|
||
const canManagePolicy = computed(() => allowed.value && hasAuth(P.policy))
|
||
const canDetail = computed(
|
||
() =>
|
||
allowed.value &&
|
||
(props.kind === 'orders' || props.kind === 'batches') &&
|
||
hasAuth(SILENCE_PAGES[props.kind as 'orders' | 'batches'].detail) &&
|
||
hasAuth(SILENCE_PAGES[props.kind as 'orders' | 'batches'].detailPage)
|
||
)
|
||
const filters = reactive<Record<string, any>>({}),
|
||
actionError = ref(''),
|
||
changing = ref(false)
|
||
const recordsId = ref<number>(),
|
||
extendId = ref<number>(),
|
||
extendRow = ref<Record<string, any>>(),
|
||
batchVisible = ref(false),
|
||
policyVisible = ref(false),
|
||
policyId = ref<number>(),
|
||
matchResult = ref<SilencePolicyMatchResponse>()
|
||
const matchVisible = ref(false),
|
||
matchPackage = ref<number>(),
|
||
matching = ref(false)
|
||
let matchSequence = 0
|
||
const exportVisible = ref(false),
|
||
exportQuery = ref<Record<string, unknown>>({})
|
||
const exportScene = computed<ExportTaskScene | undefined>(() =>
|
||
props.kind === 'orders'
|
||
? 'package_silence_order'
|
||
: props.kind === 'usages'
|
||
? 'package_silence_usage'
|
||
: undefined
|
||
)
|
||
const exportPermission = computed(() =>
|
||
props.kind === 'orders'
|
||
? SILENCE_PAGES.orders.export
|
||
: props.kind === 'usages'
|
||
? SILENCE_PAGES.usages.export
|
||
: ''
|
||
)
|
||
const queryKeys = {
|
||
orders: [
|
||
'package_usage_id',
|
||
'package_id',
|
||
'asset_identifier',
|
||
'order_no',
|
||
'status',
|
||
'source',
|
||
'payment_method',
|
||
'merchant_name',
|
||
'third_party_trade_no'
|
||
],
|
||
batches: ['batch_no', 'path', 'extension_type', 'status', 'has_exception'],
|
||
usages: ['view', 'within_days', 'asset_identifier', 'package_id', 'shop_id'],
|
||
policies: ['name', 'scope_type', 'status']
|
||
}
|
||
function query() {
|
||
const value: Record<string, unknown> = {}
|
||
for (const key of queryKeys[props.kind]) {
|
||
const raw = filters[key]
|
||
value[key] =
|
||
['package_usage_id', 'package_id', 'shop_id', 'within_days'].includes(key) &&
|
||
raw != null &&
|
||
raw !== ''
|
||
? silenceId(Number(raw), key)
|
||
: raw
|
||
}
|
||
if (props.kind === 'usages')
|
||
Object.assign(value, silenceRange(filters.time_range, 'deadline_start', 'deadline_end'))
|
||
if (props.kind === 'orders')
|
||
Object.assign(value, silenceRange(filters.time_range, 'paid_start', 'paid_end'))
|
||
if (props.kind === 'policies' && filters.effective_at)
|
||
value.effective_at = silenceDate(filters.effective_at)
|
||
return compactGatewayQuery(value)
|
||
}
|
||
const { data, loading, error, load, clear } = useSchedulerRequest(
|
||
async () => {
|
||
const params = { ...query(), page: page.value, page_size: size.value }
|
||
if (props.kind === 'orders') return silenceData(await Service.orders(params))
|
||
if (props.kind === 'batches') return silenceData(await Service.batches(params))
|
||
if (props.kind === 'usages') return silenceData(await Service.usages(params))
|
||
return silenceData(await Service.policies(params))
|
||
},
|
||
() => allowed.value
|
||
)
|
||
const rows = computed(() => (Array.isArray(data.value) ? data.value : data.value?.items || []))
|
||
const total = computed(() =>
|
||
Array.isArray(data.value) ? data.value.length : data.value?.total || 0
|
||
)
|
||
const input = (prop: string, label: string): SearchFormItem => ({
|
||
prop,
|
||
label,
|
||
type: 'input',
|
||
config: { clearable: true }
|
||
})
|
||
const select = (prop: string, label: string, map: Record<string, string>): SearchFormItem => ({
|
||
prop,
|
||
label,
|
||
type: 'select',
|
||
options: silenceOptions(map),
|
||
config: { clearable: true }
|
||
})
|
||
const number = (prop: string, label: string): SearchFormItem => ({
|
||
prop,
|
||
label,
|
||
type: 'input',
|
||
config: { inputmode: 'numeric', clearable: true }
|
||
})
|
||
const entity = (prop: string, label: string, kind: string): SearchFormItem => ({
|
||
prop,
|
||
label,
|
||
type: 'business-select',
|
||
config: {
|
||
entity: kind,
|
||
allowed: allowed.value,
|
||
...(kind === 'usage'
|
||
? {
|
||
context: {
|
||
asset_identifier: filters.asset_identifier || undefined,
|
||
package_id: filters.package_id || undefined
|
||
}
|
||
}
|
||
: {})
|
||
}
|
||
})
|
||
const time: SearchFormItem = {
|
||
prop: 'time_range',
|
||
label: props.kind === 'orders' ? '支付起止时间' : '截止起止时间',
|
||
type: 'datetimerange',
|
||
config: {
|
||
type: 'datetimerange',
|
||
rangeSeparator: '至',
|
||
startPlaceholder: '开始时间',
|
||
endPlaceholder: '结束时间',
|
||
valueFormat: 'YYYY-MM-DDTHH:mm:ssZ',
|
||
format: 'YYYY-MM-DD HH:mm:ss',
|
||
clearable: true
|
||
}
|
||
}
|
||
const searchItems = computed<SearchFormItem[]>(() =>
|
||
props.kind === 'orders'
|
||
? [
|
||
entity('asset_identifier', '资产', 'asset'),
|
||
input('order_no', '订单号'),
|
||
select('status', '订单状态', SILENCE_ORDER_STATUS),
|
||
select('source', '来源', { client: '客户端', admin: '后台', offline: '线下' }),
|
||
select('payment_method', '支付方式', {
|
||
wechat: '微信',
|
||
alipay: '支付宝',
|
||
offline: '线下'
|
||
}),
|
||
input('merchant_name', '收款商户'),
|
||
input('third_party_trade_no', '交易单号'),
|
||
entity('package_usage_id', '套餐记录', 'usage'),
|
||
entity('package_id', '套餐', 'package'),
|
||
time
|
||
]
|
||
: props.kind === 'batches'
|
||
? [
|
||
input('batch_no', '批次号'),
|
||
select('path', '办理路径', {
|
||
online: '在线',
|
||
offline: '线下',
|
||
special: '特殊延期',
|
||
adjust: '购买调整'
|
||
}),
|
||
select('extension_type', '延期类型', SILENCE_SPECIAL_TYPES),
|
||
input('status', '批次状态编码'),
|
||
{
|
||
prop: 'has_exception',
|
||
label: '含异常',
|
||
type: 'select',
|
||
options: [
|
||
{ label: '是', value: true },
|
||
{ label: '否', value: false }
|
||
],
|
||
config: { clearable: true }
|
||
}
|
||
]
|
||
: props.kind === 'usages'
|
||
? [
|
||
select('view', '视图', { expiring: '即将过期', expired: '已过期', all: '全部' }),
|
||
number('within_days', '临期天数'),
|
||
entity('asset_identifier', '资产', 'asset'),
|
||
entity('package_id', '套餐', 'package'),
|
||
entity('shop_id', '店铺', 'shop'),
|
||
time
|
||
]
|
||
: [
|
||
input('name', '政策名称'),
|
||
select('scope_type', '适用范围', {
|
||
all: '全部套餐',
|
||
series: '套餐系列',
|
||
package: '指定套餐'
|
||
}),
|
||
{
|
||
prop: 'status',
|
||
label: '状态',
|
||
type: 'select',
|
||
options: [
|
||
{ label: '启用', value: 1 },
|
||
{ label: '停用', value: 0 }
|
||
],
|
||
config: { clearable: true }
|
||
},
|
||
{
|
||
prop: 'effective_at',
|
||
label: '生效于',
|
||
type: 'datetime',
|
||
config: { type: 'datetime', valueFormat: 'YYYY-MM-DDTHH:mm:ssZ', clearable: true }
|
||
}
|
||
]
|
||
)
|
||
const definitions = {
|
||
orders: [
|
||
['order_no', '订单号'],
|
||
['asset_identifier', '资产标识'],
|
||
['package_name', '套餐'],
|
||
['status_name', '状态'],
|
||
['source_name', '来源'],
|
||
['extension_days', '延长天数'],
|
||
['amount', '应付'],
|
||
['paid_amount', '实付'],
|
||
['payment_method', '支付方式'],
|
||
['payment_merchant_name', '收款商户'],
|
||
['third_party_trade_no', '交易流水号'],
|
||
['paid_at', '支付时间'],
|
||
['expected_deadline_at', '预计截止'],
|
||
['completed_at', '生效时间'],
|
||
['created_at', '创建时间']
|
||
],
|
||
batches: [
|
||
['batch_no', '批次号'],
|
||
['path', '办理路径'],
|
||
['extension_type', '延期类型'],
|
||
['status', '状态'],
|
||
['approval_status', '审批状态'],
|
||
['requested_count', '总项数'],
|
||
['succeeded_count', '成功'],
|
||
['failed_count', '失败'],
|
||
['amount', '金额'],
|
||
['requested_at', '发起时间'],
|
||
['completed_at', '完成时间']
|
||
],
|
||
usages: [
|
||
['asset_identifier', '资产标识'],
|
||
['asset_type', '资产类型'],
|
||
['shop_name', '店铺'],
|
||
['package_name', '套餐'],
|
||
['package_usage_id', '套餐记录 ID'],
|
||
['silence_status_name', '沉默期状态'],
|
||
['silence_deadline_at', '截止时间'],
|
||
['silence_extended_days', '累计延期天数'],
|
||
['order_no', '购买订单'],
|
||
['created_at', '购买时间']
|
||
],
|
||
policies: [
|
||
['name', '政策名称'],
|
||
['scope_type_name', '适用范围'],
|
||
['scope_ids', '范围 ID'],
|
||
['unit_price', '月单价'],
|
||
['free_extension_limit', '免费次数'],
|
||
['paid_max_months', '付费累计最多月数'],
|
||
['single_max_months', '单次最多月数'],
|
||
['effective_from', '生效时间'],
|
||
['effective_to', '失效时间'],
|
||
['status', '状态'],
|
||
['updated_at', '更新时间']
|
||
]
|
||
}
|
||
const fields = computed(() => definitions[props.kind].map(([prop, label]) => ({ prop, label })))
|
||
const displayRows = computed(() =>
|
||
rows.value.map((row) =>
|
||
props.kind === 'usages' ? { ...row, ...('silence' in row ? row.silence : {}) } : row
|
||
)
|
||
)
|
||
// 用扁平显示行,同时保留原 silence 对象供操作入口判定。
|
||
function search() {
|
||
page.value = 1
|
||
void load()
|
||
}
|
||
function previousPolicyPage() {
|
||
page.value--
|
||
void load()
|
||
}
|
||
function nextPolicyPage() {
|
||
page.value++
|
||
void load()
|
||
}
|
||
function closeExtension() {
|
||
extendId.value = undefined
|
||
batchVisible.value = false
|
||
}
|
||
function reset() {
|
||
clear()
|
||
Object.keys(filters).forEach((key) => delete filters[key])
|
||
if (props.kind === 'usages') filters.view = 'expiring'
|
||
search()
|
||
}
|
||
function detail(row: Record<string, any>) {
|
||
requireGatewayAccess(canDetail.value)
|
||
void router.push(`/package-management/silence-${props.kind}/detail/${silenceId(row.id)}`)
|
||
}
|
||
function editPolicy(row?: Record<string, any>) {
|
||
if (!canManagePolicy.value) return
|
||
policyId.value = row?.id
|
||
policyVisible.value = true
|
||
}
|
||
function openExport() {
|
||
try {
|
||
requireGatewayAccess(allowed.value && hasAuth(exportPermission.value))
|
||
exportQuery.value = { filters: query() }
|
||
exportVisible.value = true
|
||
} catch (e) {
|
||
actionError.value = gatewayError(e)
|
||
}
|
||
}
|
||
function openExtension(row: Record<string, any>) {
|
||
extendRow.value = row
|
||
extendId.value = row.package_usage_id
|
||
}
|
||
async function matchPolicy() {
|
||
if (!canManagePolicy.value || !matchPackage.value || matching.value) return
|
||
const scope = pollingScope(user),
|
||
current = ++matchSequence,
|
||
packageId = matchPackage.value
|
||
matching.value = true
|
||
try {
|
||
requireGatewayAccess(active && canManagePolicy.value && scope === pollingScope(user))
|
||
const result = silenceData(await Service.match(silenceId(packageId, '套餐')))
|
||
if (
|
||
active &&
|
||
canManagePolicy.value &&
|
||
scope === pollingScope(user) &&
|
||
current === matchSequence &&
|
||
packageId === matchPackage.value
|
||
) {
|
||
matchResult.value = result
|
||
closeMatch()
|
||
}
|
||
} catch (e) {
|
||
if (active && current === matchSequence && scope === pollingScope(user))
|
||
actionError.value = gatewayError(e)
|
||
} finally {
|
||
if (current === matchSequence) matching.value = false
|
||
}
|
||
}
|
||
function closeMatch() {
|
||
matchSequence++
|
||
matchVisible.value = false
|
||
matchPackage.value = undefined
|
||
matching.value = false
|
||
}
|
||
watch(
|
||
() => [filters.asset_identifier, filters.package_id],
|
||
() => {
|
||
delete filters.package_usage_id
|
||
},
|
||
{ flush: 'sync' }
|
||
)
|
||
async function togglePolicy(row: Record<string, any>) {
|
||
if (changing.value) return
|
||
const scope = pollingScope(user),
|
||
id = silenceId(row.id),
|
||
status = row.status === 1 ? 0 : 1
|
||
changing.value = true
|
||
try {
|
||
requireGatewayAccess(canManagePolicy.value)
|
||
await ElMessageBox.confirm(`确认${status ? '启用' : '停用'} ${row.name}?`, '状态确认', {
|
||
type: 'warning'
|
||
})
|
||
requireGatewayAccess(active && canManagePolicy.value && scope === pollingScope(user))
|
||
silenceData(await Service.policyStatus(id, status))
|
||
if (active && scope === pollingScope(user)) await load()
|
||
} catch (e) {
|
||
if (e !== 'cancel' && e !== 'close') actionError.value = gatewayError(e)
|
||
} finally {
|
||
changing.value = false
|
||
}
|
||
}
|
||
watch(
|
||
() => [allowed.value, pollingScope(user)],
|
||
() => {
|
||
recordsId.value = undefined
|
||
extendId.value = undefined
|
||
batchVisible.value = false
|
||
policyVisible.value = false
|
||
exportVisible.value = false
|
||
matchResult.value = undefined
|
||
closeMatch()
|
||
actionError.value = ''
|
||
},
|
||
{ flush: 'sync' }
|
||
)
|
||
let active = true
|
||
function closeDialogs() {
|
||
recordsId.value = undefined
|
||
closeExtension()
|
||
policyVisible.value = false
|
||
exportVisible.value = false
|
||
matchResult.value = undefined
|
||
closeMatch()
|
||
}
|
||
onDeactivated(() => {
|
||
active = false
|
||
closeDialogs()
|
||
})
|
||
onActivated(() => {
|
||
active = true
|
||
})
|
||
onBeforeUnmount(() => {
|
||
active = false
|
||
closeDialogs()
|
||
})
|
||
onMounted(() => {
|
||
if (props.kind === 'usages') filters.view = 'expiring'
|
||
void load()
|
||
})
|
||
</script>
|