319 lines
6.8 KiB
Vue
319 lines
6.8 KiB
Vue
<template>
|
||
<div>
|
||
<div class="footer-nav">
|
||
<div class="container footer-nav-inner">
|
||
<span class="footer-nav-title">友情链接</span>
|
||
<div v-if="friendLinkGroups.length" class="friend-link-groups">
|
||
<div
|
||
v-for="group in friendLinkGroups"
|
||
:key="group.categoryKey"
|
||
class="friend-link-group"
|
||
tabindex="0"
|
||
>
|
||
<button type="button" class="friend-link-trigger">
|
||
<span>{{ group.categoryName }}</span>
|
||
<span class="friend-link-arrow">▾</span>
|
||
</button>
|
||
<div class="friend-link-menu">
|
||
<a
|
||
v-for="item in group.links"
|
||
:key="item.linkId || item.id"
|
||
:href="item.linkUrl"
|
||
:target="Number(item.target) === 1 ? '_blank' : undefined"
|
||
:rel="Number(item.target) === 1 ? 'noopener noreferrer' : undefined"
|
||
>
|
||
{{ item.title }}
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<span v-else class="footer-nav-empty">暂无友情链接</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="container footer-main">
|
||
<div class="footer-left">
|
||
<p>扫一扫公众号</p>
|
||
<p>了解我们的动态</p>
|
||
<img :src="wechatQrcode || '/images/qrcode-mp-official.jpg'" alt="公众号二维码" />
|
||
</div>
|
||
<div class="footer-center">
|
||
<h3>广西决策咨询网</h3>
|
||
<p>承办单位:{{ operatorName }}</p>
|
||
<p>地址:{{ address }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="footer-record">
|
||
<a
|
||
href="https://beian.miit.gov.cn/"
|
||
target="_blank"
|
||
rel="nofollow noopener noreferrer"
|
||
>桂ICP备2026004011号-1</a>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { listSiteDictionaryItems, listSiteFriendLinks, resolveSiteAssetUrl, type SiteFriendLink } from '@/api/site'
|
||
|
||
const operatorName = ref('广西决策咨询网有限公司')
|
||
const address = ref('广西壮族自治区南宁市良庆区五象大道401号五象航洋城3号楼')
|
||
const wechatQrcode = ref('')
|
||
const friendLinks = ref<SiteFriendLink[]>([])
|
||
|
||
const friendLinkGroups = computed(() => {
|
||
const groupMap = new Map<string, { categoryKey: string; categoryName: string; categorySort: number; links: SiteFriendLink[] }>()
|
||
|
||
friendLinks.value.forEach((item) => {
|
||
const categoryName = (item.categoryName || '其他链接').trim() || '其他链接'
|
||
const categoryKey = item.categoryId ? `${item.categoryId}` : categoryName
|
||
const current = groupMap.get(categoryKey)
|
||
|
||
if (current) {
|
||
current.links.push(item)
|
||
return
|
||
}
|
||
|
||
groupMap.set(categoryKey, {
|
||
categoryKey,
|
||
categoryName,
|
||
categorySort: Number(item.categorySort || 0),
|
||
links: [item],
|
||
})
|
||
})
|
||
|
||
return Array.from(groupMap.values()).sort((left, right) => {
|
||
const sortCompare = right.categorySort - left.categorySort
|
||
return sortCompare || left.categoryName.localeCompare(right.categoryName, 'zh-Hans-CN')
|
||
})
|
||
})
|
||
|
||
async function loadDictionary() {
|
||
try {
|
||
const items = await listSiteDictionaryItems({ dictCode: 'site_contact' })
|
||
const itemMap = Object.fromEntries((items || []).map((item) => [item.itemKey, item.itemValue]))
|
||
|
||
operatorName.value = itemMap.operator_name || operatorName.value
|
||
address.value = itemMap.address || address.value
|
||
wechatQrcode.value = resolveSiteAssetUrl(itemMap.wechat_qrcode || '')
|
||
} catch (error) {
|
||
console.error('加载站点联系字典失败', error)
|
||
}
|
||
}
|
||
|
||
async function loadFriendLinks() {
|
||
try {
|
||
friendLinks.value = await listSiteFriendLinks()
|
||
} catch (error) {
|
||
console.error('加载友情链接失败', error)
|
||
friendLinks.value = []
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
loadDictionary()
|
||
loadFriendLinks()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.container {
|
||
width: min(1200px, calc(100% - 32px));
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.footer-nav {
|
||
background: #1f4fa3;
|
||
}
|
||
|
||
.footer-nav-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
gap: 24px;
|
||
min-height: 58px;
|
||
flex-wrap: wrap;
|
||
padding: 10px 0;
|
||
}
|
||
|
||
.footer-nav-title {
|
||
color: #fff;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.friend-link-groups {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.friend-link-group {
|
||
position: relative;
|
||
z-index: 10;
|
||
}
|
||
|
||
.friend-link-trigger {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
min-height: 34px;
|
||
padding: 0 14px;
|
||
border: 1px solid rgba(255, 255, 255, 0.28);
|
||
border-radius: 4px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
color: rgba(255, 255, 255, 0.94);
|
||
font-size: 14px;
|
||
line-height: 1;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.friend-link-arrow {
|
||
font-size: 12px;
|
||
transition: transform 0.16s ease;
|
||
}
|
||
|
||
.friend-link-menu {
|
||
position: absolute;
|
||
left: 0;
|
||
top: calc(100% + 8px);
|
||
display: none;
|
||
min-width: 168px;
|
||
max-width: min(280px, calc(100vw - 32px));
|
||
padding: 8px;
|
||
border-radius: 6px;
|
||
background: #fff;
|
||
box-shadow: 0 12px 32px rgba(14, 37, 72, 0.18);
|
||
}
|
||
|
||
.friend-link-menu::after {
|
||
position: absolute;
|
||
left: 24px;
|
||
top: -6px;
|
||
width: 12px;
|
||
height: 12px;
|
||
background: #fff;
|
||
transform: rotate(45deg);
|
||
content: '';
|
||
}
|
||
|
||
.friend-link-menu a {
|
||
position: relative;
|
||
z-index: 1;
|
||
display: block;
|
||
padding: 9px 10px;
|
||
border-radius: 4px;
|
||
color: #31445a;
|
||
font-size: 14px;
|
||
line-height: 1.35;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.friend-link-menu a:hover {
|
||
background: #eef5ff;
|
||
color: #1f4fa3;
|
||
}
|
||
|
||
.friend-link-group:hover .friend-link-menu,
|
||
.friend-link-group:focus-within .friend-link-menu {
|
||
display: block;
|
||
}
|
||
|
||
.friend-link-group:hover .friend-link-arrow,
|
||
.friend-link-group:focus-within .friend-link-arrow {
|
||
transform: rotate(180deg);
|
||
}
|
||
|
||
.footer-nav-empty {
|
||
color: rgba(255, 255, 255, 0.9);
|
||
font-size: 14px;
|
||
}
|
||
|
||
.footer-main {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 60px;
|
||
padding: 28px 0 52px;
|
||
}
|
||
|
||
.footer-left {
|
||
color: #4f5c67;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.footer-left p {
|
||
margin: 0 0 8px;
|
||
}
|
||
|
||
.footer-left img {
|
||
width: 100px;
|
||
height: 100px;
|
||
margin-top: 10px;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.footer-center {
|
||
padding-top: 10px;
|
||
color: #697680;
|
||
text-align: left;
|
||
}
|
||
|
||
.footer-center h3 {
|
||
margin: 0 0 8px;
|
||
color: #27313a;
|
||
font-size: 30px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.footer-center p {
|
||
margin: 0 0 8px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.footer-record {
|
||
padding: 16px;
|
||
border-top: 1px solid #e7ebef;
|
||
color: #697680;
|
||
font-size: 13px;
|
||
text-align: center;
|
||
}
|
||
|
||
.footer-record a {
|
||
color: inherit;
|
||
}
|
||
|
||
.footer-record a:hover {
|
||
color: #1f4fa3;
|
||
}
|
||
|
||
@media (max-width: 1100px) {
|
||
.footer-main {
|
||
flex-direction: column;
|
||
gap: 24px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.container {
|
||
width: min(100%, calc(100% - 24px));
|
||
}
|
||
|
||
.footer-nav-inner {
|
||
gap: 18px;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.friend-link-groups {
|
||
width: 100%;
|
||
gap: 10px;
|
||
}
|
||
|
||
.friend-link-menu {
|
||
left: 0;
|
||
top: calc(100% + 8px);
|
||
}
|
||
}
|
||
</style>
|