更新首页

This commit is contained in:
2026-09-11 12:25:38 +08:00
parent 9e24153eac
commit c29c3be942
326 changed files with 6564 additions and 44307 deletions
+252 -10
View File
@@ -1,25 +1,236 @@
<template>
<div class="container footer-main">
<div class="footer-left">
<p>扫一扫公众号</p>
<p>了解我们的动态</p>
<img src="/images/qrcode-mp-official.jpg" alt="公众号二维码" />
<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="footer-center">
<h3>广西决策咨询网</h3>
<p>Guangxi Decision-Making Consulting Network</p>
<p>运营方广西决策咨询网有限公司</p>
<p>地址广西壮族自治区南宁市中柬路XX号 XX楼 XX号房</p>
<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;
@@ -61,6 +272,22 @@
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;
@@ -72,5 +299,20 @@
.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>