Files
admin/www/app/components/AppFooter.vue
T

113 lines
4.2 KiB
Vue
Raw Normal View History

<script setup lang="ts">
const { t } = useI18n();
2026-07-31 19:02:00 +08:00
const siteStore = useSiteStore();
const { footer, social, site } = storeToRefs(siteStore);
const currentYear = new Date().getFullYear();
2026-07-31 19:02:00 +08:00
// 社交链接图标(系统内置,admin 只填链接/二维码)
const socialIcons: Record<string, string> = {
wechat: '💬',
weibo: '🌐',
bilibili: '📺',
youtube: '▶️',
facebook: '📘',
instagram: '📷'
};
// 仅显示已填写链接或二维码的社交入口
const visibleSocial = computed(() =>
(social.value || []).filter((s) => s.url || s.qrcode_url)
);
// 悬浮显示微信二维码
const wechatHover = ref(false);
</script>
<template>
<footer class="border-t border-gray-100 bg-gray-50 dark:bg-dark-900 dark:border-dark-700">
2026-07-31 19:02:00 +08:00
<div class="section-container py-48px">
<div class="flex flex-col md:flex-row md:items-start md:justify-between gap-32px">
<!-- 品牌与联系信息 -->
<div class="flex flex-col gap-12px">
<p class="text-lg font-bold text-gray-900 dark:text-white">
{{ site?.site_title || t('app.name') }}
</p>
<p v-if="footer?.company_name" class="text-sm text-gray-600 dark:text-gray-300">
{{ footer.company_name }}
</p>
<p v-if="footer?.company_address" class="text-sm text-gray-500 dark:text-gray-400">
{{ footer.company_address }}
</p>
<div class="flex flex-wrap items-center gap-16px text-sm text-gray-500 dark:text-gray-400">
<a v-if="footer?.contact_phone" :href="`tel:${footer.contact_phone}`" class="hover:text-primary transition-colors">
{{ footer.contact_phone }}
</a>
<a v-if="footer?.contact_email" :href="`mailto:${footer.contact_email}`" class="hover:text-primary transition-colors">
{{ footer.contact_email }}
</a>
</div>
</div>
<!-- 社交媒体 -->
<div v-if="visibleSocial.length" class="flex items-center gap-16px">
<template v-for="item in visibleSocial" :key="item.platform">
<!-- 微信悬浮显示二维码 -->
<div
v-if="item.platform === 'wechat' && item.qrcode_url"
class="relative"
@mouseenter="wechatHover = true"
@mouseleave="wechatHover = false"
>
<span class="w-40px h-40px flex-center rounded-full bg-white border border-gray-200 text-lg cursor-pointer hover:border-primary transition-colors dark:bg-dark-800 dark:border-dark-600">
{{ socialIcons[item.platform] || '🔗' }}
</span>
<transition name="qr">
<img
v-if="wechatHover"
:src="item.qrcode_url"
alt="WeChat QR"
class="absolute bottom-48px right-0 w-140px h-140px object-contain rounded-8px shadow-xl border border-gray-100 bg-white"
/>
</transition>
</div>
<!-- 其他平台外链 -->
<a
v-else-if="item.url"
:href="item.url"
target="_blank"
rel="noopener noreferrer"
class="w-40px h-40px flex-center rounded-full bg-white border border-gray-200 text-lg hover:border-primary transition-colors dark:bg-dark-800 dark:border-dark-600"
>
{{ socialIcons[item.platform] || '🔗' }}
</a>
</template>
</div>
</div>
<!-- 版权与备案 -->
<div class="mt-32px pt-24px border-t border-gray-200 dark:border-dark-700 flex flex-col md:flex-row md:items-center md:justify-between gap-8px">
<p class="text-xs text-gray-400 dark:text-gray-500">
{{ footer?.copyright_text || t('footer.copyright', { year: currentYear }) }}
</p>
<div class="flex flex-wrap items-center gap-16px text-xs text-gray-400 dark:text-gray-500">
<span v-if="footer?.icp_number">{{ footer.icp_number }}</span>
<span v-if="footer?.police_number">{{ footer.police_number }}</span>
</div>
</div>
</div>
</footer>
</template>
2026-07-31 19:02:00 +08:00
<style scoped>
.qr-enter-active,
.qr-leave-active {
transition: opacity 0.18s ease;
}
.qr-enter-from,
.qr-leave-to {
opacity: 0;
}
</style>