Files
wordpress-theme-aksrt/assets/admin/src/components/DeferredPage.vue
T

163 lines
4.7 KiB
Vue

<template>
<div class="aksrt-deferred-page">
<div class="aksrt-deferred-page__icon">
<FaIcon :icon="resolvedIcon" :size="48" />
</div>
<h2 class="aksrt-deferred-page__title">{{ resolvedTitle }}</h2>
<p class="aksrt-deferred-page__desc">{{ resolvedDesc }}</p>
<div class="aksrt-deferred-page__meta">
<n-tag size="small" type="info">{{ resolvedStatus }}</n-tag>
<n-tag v-if="resolvedPhase" size="small" type="warning">Phase {{ resolvedPhase }}</n-tag>
</div>
<div v-if="resolvedDependsOn.length" class="aksrt-deferred-page__depends">
<span class="aksrt-deferred-page__label">依赖</span>
<div class="aksrt-deferred-page__depends-list">
<n-tag v-for="item in resolvedDependsOn" :key="item" size="small" type="default">{{ item }}</n-tag>
</div>
</div>
<div v-if="resolvedReason" class="aksrt-deferred-page__reason">
<span class="aksrt-deferred-page__label">原因</span>
<p>{{ resolvedReason }}</p>
</div>
<div v-if="resolvedFeatures && resolvedFeatures.length" class="aksrt-deferred-page__features">
<div
v-for="(feat, i) in resolvedFeatures"
:key="i"
class="aksrt-deferred-page__feature"
>
<FaIcon icon="fa fas fa-check-circle" :size="14" />
<span>{{ feat }}</span>
</div>
</div>
<div class="aksrt-deferred-page__badge">
<n-tag type="info" size="small">即将推出</n-tag>
</div>
</div>
</template>
<script setup>
/**
* DeferredPage — "Coming Soon" page component for deferred sections.
* Shows a friendly message instead of a blank page.
*
* When used as a route component, reads props from route.meta.deferredProps.
* When used directly, accepts props normally.
*/
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import FaIcon from './form/FaIcon.vue'
const props = defineProps({
title: { type: String, default: '' },
description: { type: String, default: '' },
icon: { type: String, default: '' },
features: { type: Array, default: () => [] },
status: { type: String, default: '' },
phase: { type: String, default: '' },
dependsOn: { type: Array, default: () => [] },
reason: { type: String, default: '' },
})
const route = useRoute()
/** Merge direct props with route meta deferredProps */
const resolvedTitle = computed(() => props.title || route.meta?.deferredProps?.title || '功能开发中')
const resolvedDesc = computed(() => props.description || route.meta?.deferredProps?.description || '此功能正在规划开发中,将在后续版本上线。')
const resolvedIcon = computed(() => props.icon || route.meta?.deferredProps?.icon || 'fa fas fa-rocket')
const resolvedStatus = computed(() => props.status || route.meta?.deferredProps?.status || 'deferred')
const resolvedPhase = computed(() => props.phase || route.meta?.deferredProps?.phase || '')
const resolvedDependsOn = computed(() => {
if (props.dependsOn && props.dependsOn.length) return props.dependsOn
return route.meta?.deferredProps?.dependsOn || []
})
const resolvedReason = computed(() => props.reason || route.meta?.deferredProps?.reason || '')
const resolvedFeatures = computed(() => {
if (props.features && props.features.length) return props.features
return route.meta?.deferredProps?.features || []
})
</script>
<style scoped>
.aksrt-deferred-page {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 400px;
text-align: center;
padding: 40px 20px;
}
.aksrt-deferred-page__icon {
color: var(--aksrt-color-border-strong);
margin-bottom: 20px;
}
.aksrt-deferred-page__title {
margin: 0 0 10px;
font-size: 20px;
font-weight: 600;
color: var(--aksrt-color-text);
}
.aksrt-deferred-page__desc {
margin: 0 0 20px;
font-size: 14px;
color: var(--aksrt-color-muted);
max-width: 400px;
line-height: 1.6;
}
.aksrt-deferred-page__meta {
display: flex;
gap: 10px;
margin-bottom: 18px;
}
.aksrt-deferred-page__depends,
.aksrt-deferred-page__reason {
width: min(520px, 100%);
margin-bottom: 18px;
text-align: left;
}
.aksrt-deferred-page__label {
display: inline-block;
margin-bottom: 8px;
font-size: 12px;
font-weight: 600;
color: var(--aksrt-color-text-secondary);
}
.aksrt-deferred-page__depends-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.aksrt-deferred-page__reason p {
margin: 0;
color: var(--aksrt-color-muted);
line-height: 1.7;
}
.aksrt-deferred-page__features {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 20px;
}
.aksrt-deferred-page__feature {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--aksrt-color-muted);
}
.aksrt-deferred-page__feature :deep(i) {
color: #52c41a;
}
</style>