2026-07-30 11:23:50 +08:00
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
const { t } = useI18n();
|
2026-07-31 19:02:00 +08:00
|
|
|
|
const siteStore = useSiteStore();
|
|
|
|
|
|
const { footer, social, site } = storeToRefs(siteStore);
|
|
|
|
|
|
|
2026-07-30 11:23:50 +08:00
|
|
|
|
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);
|
2026-07-30 11:23:50 +08:00
|
|
|
|
</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>
|
2026-07-30 11:23:50 +08:00
|
|
|
|
</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>
|