feat: 更新网站页面和组件,新增多个页面(关于、专家、会员、政策等)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# Tenant / headers
|
||||
# - TenantId header will be sent on every request.
|
||||
# - Authorization header is taken from client storage (AccessToken) and forwarded by the Nuxt proxy.
|
||||
NUXT_PUBLIC_TENANT_ID=10584
|
||||
NUXT_PUBLIC_TENANT_ID=10588
|
||||
|
||||
# Upstream APIs (required)
|
||||
NUXT_PUBLIC_SERVER_API_BASE=https://server.websoft.top/api
|
||||
|
||||
@@ -9,8 +9,13 @@
|
||||
<script setup lang="ts">
|
||||
const theme = {
|
||||
token: {
|
||||
// Ant Design Vue primary color -> green
|
||||
colorPrimary: '#16a34a'
|
||||
colorPrimary: '#1E6FB5',
|
||||
colorInfo: '#1E6FB5',
|
||||
colorLink: '#1E6FB5',
|
||||
colorSuccess: '#2BA69A',
|
||||
colorText: '#333333',
|
||||
fontFamily:
|
||||
'"Source Han Sans SC","Noto Sans SC","Microsoft YaHei","PingFang SC",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Apple Color Emoji","Segoe UI Emoji"'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,3 +1,62 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--gov-blue: #1e6fb5;
|
||||
--gov-teal: #2ba69a;
|
||||
|
||||
--text-primary: #333333;
|
||||
--text-secondary: #4b5563;
|
||||
--text-tertiary: #6b7280;
|
||||
|
||||
--bg-page: #f7f9fc;
|
||||
--bg-surface: #ffffff;
|
||||
--border-subtle: rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
html {
|
||||
color: var(--text-primary);
|
||||
background: var(--bg-page);
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
text-size-adjust: 100%;
|
||||
font-family: "Source Han Sans SC", "Noto Sans SC", "Microsoft YaHei", "PingFang SC", system-ui,
|
||||
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
|
||||
"Apple Color Emoji", "Segoe UI Emoji";
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: var(--text-primary);
|
||||
background: var(--bg-page);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--gov-blue);
|
||||
text-decoration-thickness: 1px;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #185d96;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--gov-teal);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
#main-content {
|
||||
scroll-margin-top: 120px;
|
||||
}
|
||||
|
||||
html[data-contrast='high'] {
|
||||
--text-primary: #0f172a;
|
||||
--text-secondary: #111827;
|
||||
--text-tertiary: #111827;
|
||||
--bg-page: #ffffff;
|
||||
--border-subtle: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
69
app/components/Breadcrumbs.vue
Normal file
69
app/components/Breadcrumbs.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<nav v-if="items.length > 1" class="breadcrumbs" aria-label="面包屑导航">
|
||||
<a-breadcrumb>
|
||||
<a-breadcrumb-item v-for="(it, idx) in items" :key="`${it.key}::${idx}`">
|
||||
<NuxtLink v-if="it.to && idx < items.length - 1" :to="it.to">
|
||||
{{ it.label }}
|
||||
</NuxtLink>
|
||||
<span v-else>{{ it.label }}</span>
|
||||
</a-breadcrumb-item>
|
||||
</a-breadcrumb>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { mainNav, type NavItem } from '@/config/nav'
|
||||
|
||||
type Crumb = { key: string; label: string; to?: string }
|
||||
|
||||
const route = useRoute()
|
||||
const currentPath = computed(() => route.path || '/')
|
||||
|
||||
function bestTrail(items: NavItem[], path: string): NavItem[] {
|
||||
let best: NavItem[] = []
|
||||
|
||||
const walk = (list: NavItem[], ancestors: NavItem[]) => {
|
||||
for (const item of list) {
|
||||
const nextAncestors = [...ancestors, item]
|
||||
const to = item.to || ''
|
||||
const isPrefix = to && to !== '/' && (path === to || path.startsWith(`${to}/`))
|
||||
const isExact = to && path === to
|
||||
|
||||
if (isExact || isPrefix) {
|
||||
if (nextAncestors.length > best.length) best = nextAncestors
|
||||
}
|
||||
|
||||
if (item.children?.length) walk(item.children, nextAncestors)
|
||||
}
|
||||
}
|
||||
|
||||
walk(items, [])
|
||||
return best
|
||||
}
|
||||
|
||||
const items = computed<Crumb[]>(() => {
|
||||
const home: Crumb = { key: 'home', label: '首页', to: '/' }
|
||||
if (currentPath.value === '/') return [home]
|
||||
|
||||
const trail = bestTrail(mainNav, currentPath.value)
|
||||
if (!trail.length) {
|
||||
return [home, { key: currentPath.value, label: currentPath.value.replace(/^\//, '') || '当前页面' }]
|
||||
}
|
||||
|
||||
return [
|
||||
home,
|
||||
...trail.map((it) => ({ key: it.key, label: it.label, to: it.to }))
|
||||
]
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.breadcrumbs {
|
||||
padding: 10px 0;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.breadcrumbs :deep(.ant-breadcrumb) {
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
@@ -24,6 +24,13 @@
|
||||
aria-label="carousel-slide"
|
||||
>
|
||||
<img class="carousel-img" :src="it.src" :alt="it.alt || 'slide'" loading="lazy" />
|
||||
<div v-if="it.title || it.desc" class="carousel-overlay">
|
||||
<div class="carousel-overlay-inner">
|
||||
<div v-if="it.title" class="carousel-title">{{ it.title }}</div>
|
||||
<div v-if="it.desc" class="carousel-desc">{{ it.desc }}</div>
|
||||
<div v-if="it.ctaLabel" class="carousel-cta">{{ it.ctaLabel }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
<a
|
||||
v-else-if="it.href"
|
||||
@@ -34,8 +41,24 @@
|
||||
aria-label="carousel-slide"
|
||||
>
|
||||
<img class="carousel-img" :src="it.src" :alt="it.alt || 'slide'" loading="lazy" />
|
||||
<div v-if="it.title || it.desc" class="carousel-overlay">
|
||||
<div class="carousel-overlay-inner">
|
||||
<div v-if="it.title" class="carousel-title">{{ it.title }}</div>
|
||||
<div v-if="it.desc" class="carousel-desc">{{ it.desc }}</div>
|
||||
<div v-if="it.ctaLabel" class="carousel-cta">{{ it.ctaLabel }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<img v-else class="carousel-img" :src="it.src" :alt="it.alt || 'slide'" loading="lazy" />
|
||||
<div v-else class="carousel-link" aria-label="carousel-slide">
|
||||
<img class="carousel-img" :src="it.src" :alt="it.alt || 'slide'" loading="lazy" />
|
||||
<div v-if="it.title || it.desc" class="carousel-overlay">
|
||||
<div class="carousel-overlay-inner">
|
||||
<div v-if="it.title" class="carousel-title">{{ it.title }}</div>
|
||||
<div v-if="it.desc" class="carousel-desc">{{ it.desc }}</div>
|
||||
<div v-if="it.ctaLabel" class="carousel-cta">{{ it.ctaLabel }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-carousel>
|
||||
|
||||
@@ -71,6 +94,9 @@ type CarouselItem = {
|
||||
src: string
|
||||
href?: string
|
||||
alt?: string
|
||||
title?: string
|
||||
desc?: string
|
||||
ctaLabel?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -123,7 +149,9 @@ function prev() {
|
||||
background: #fff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.04);
|
||||
border-radius: 14px;
|
||||
border: 1px solid var(--border-subtle);
|
||||
box-shadow: 0 14px 30px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.carousel {
|
||||
@@ -137,6 +165,7 @@ function prev() {
|
||||
.carousel-link {
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.carousel-img {
|
||||
@@ -146,6 +175,45 @@ function prev() {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.carousel-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 18px;
|
||||
background: linear-gradient(180deg, rgba(15, 23, 42, 0.08), rgba(15, 23, 42, 0.74));
|
||||
}
|
||||
|
||||
.carousel-overlay-inner {
|
||||
max-width: 860px;
|
||||
}
|
||||
|
||||
.carousel-title {
|
||||
color: rgba(255, 255, 255, 0.98);
|
||||
font-size: 28px;
|
||||
line-height: 1.25;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.carousel-desc {
|
||||
margin-top: 10px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.carousel-cta {
|
||||
display: inline-flex;
|
||||
margin-top: 12px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 10px;
|
||||
background: rgba(30, 111, 181, 0.95);
|
||||
color: rgba(255, 255, 255, 0.98);
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.carousel :deep(.slick-list),
|
||||
.carousel :deep(.slick-track),
|
||||
.carousel :deep(.slick-slide),
|
||||
|
||||
46
app/components/SectionStub.vue
Normal file
46
app/components/SectionStub.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<section class="py-10">
|
||||
<a-typography-title :level="1" class="!mb-2">
|
||||
{{ title }}
|
||||
</a-typography-title>
|
||||
<a-typography-paragraph v-if="description" class="!text-gray-600 !mb-6">
|
||||
{{ description }}
|
||||
</a-typography-paragraph>
|
||||
|
||||
<a-row v-if="links?.length" :gutter="[16, 16]">
|
||||
<a-col v-for="it in links" :key="it.to" :xs="24" :md="12" :lg="8">
|
||||
<a-card size="small" class="h-full">
|
||||
<NuxtLink class="text-base font-semibold" :to="it.to">
|
||||
{{ it.label }}
|
||||
</NuxtLink>
|
||||
<div v-if="it.desc" class="mt-2 text-sm text-gray-500">
|
||||
{{ it.desc }}
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-result
|
||||
v-if="showResult"
|
||||
class="mt-8"
|
||||
status="info"
|
||||
title="页面建设中"
|
||||
sub-title="该栏目正在完善中,可先通过导航进入其他栏目。"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
type LinkItem = { label: string; to: string; desc?: string }
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
title: string
|
||||
description?: string
|
||||
links?: LinkItem[]
|
||||
showResult?: boolean
|
||||
}>(),
|
||||
{ description: '', links: () => [], showResult: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -3,35 +3,54 @@
|
||||
<div class="mx-auto max-w-screen-xl px-4 py-10">
|
||||
<a-row :gutter="[24, 24]">
|
||||
<a-col :xs="24" :md="8">
|
||||
<div class="text-base font-semibold text-white">关注我们</div>
|
||||
<div class="mt-4 flex items-center gap-4">
|
||||
<a-avatar shape="square" :size="96" src="https://oss.wsdns.cn/20260127/74041127623e4a8faa49a24e0818dae6.png" />
|
||||
<div class="text-sm leading-6 text-gray-400">
|
||||
小程序
|
||||
<br />
|
||||
获取最新动态
|
||||
</div>
|
||||
<div class="text-base font-semibold text-white">联系我们</div>
|
||||
<div class="mt-4 grid gap-2 text-sm text-gray-300">
|
||||
<div>咨询服务:<NuxtLink class="text-gray-100 hover:text-white underline-offset-4 hover:underline" to="/consulting/intro">服务简介</NuxtLink></div>
|
||||
<div>建议反馈:<NuxtLink class="text-gray-100 hover:text-white underline-offset-4 hover:underline" to="/suggest">建言献策</NuxtLink></div>
|
||||
<div>联系方式:<NuxtLink class="text-gray-100 hover:text-white underline-offset-4 hover:underline" to="/contact">联系我们</NuxtLink></div>
|
||||
</div>
|
||||
</a-col>
|
||||
|
||||
<a-col :xs="24" :md="8">
|
||||
<div class="text-base font-semibold text-white">快速入口</div>
|
||||
<div class="mt-4 grid gap-2 text-sm text-gray-400">
|
||||
<NuxtLink class="hover:text-white" to="/products">经营范围</NuxtLink>
|
||||
<NuxtLink class="hover:text-white" to="/contact">联系我们</NuxtLink>
|
||||
<NuxtLink class="hover:text-white" to="/policy/latest">政策要闻</NuxtLink>
|
||||
<NuxtLink class="hover:text-white" to="/reference/data">数据服务</NuxtLink>
|
||||
<NuxtLink class="hover:text-white" to="/experts/apply">专家申请</NuxtLink>
|
||||
<NuxtLink class="hover:text-white" to="/downloads">资料下载</NuxtLink>
|
||||
<NuxtLink class="hover:text-white" to="/search">站内搜索</NuxtLink>
|
||||
<NuxtLink class="hover:text-white" to="/sitemap">站点地图</NuxtLink>
|
||||
</div>
|
||||
</a-col>
|
||||
|
||||
<a-col :xs="24" :md="8">
|
||||
<div class="text-base font-semibold text-white">备案信息</div>
|
||||
<div class="mt-4 text-sm text-gray-400">{{ icpText }}</div>
|
||||
<div class="mt-4 grid gap-2 text-sm text-gray-300">
|
||||
<div>{{ icpText }}</div>
|
||||
<div>{{ policeText }}</div>
|
||||
<div>{{ siteCodeText }}</div>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<div class="mt-10 border-t border-white/10 pt-6">
|
||||
<div class="text-base font-semibold text-white">友情链接</div>
|
||||
<div class="mt-3 flex flex-wrap gap-x-5 gap-y-2 text-sm text-gray-300">
|
||||
<a v-for="it in friendLinks" :key="it.url" class="hover:text-white hover:underline underline-offset-4" :href="it.url" target="_blank" rel="noreferrer">
|
||||
{{ it.name }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-10 flex flex-col gap-2 border-t border-white/10 pt-6 text-xs text-gray-500 md:flex-row md:items-center md:justify-between"
|
||||
>
|
||||
<div>© {{ year }} {{ siteName }}. All rights reserved.</div>
|
||||
<div class="flex flex-wrap items-center gap-x-3 gap-y-1 text-gray-400">
|
||||
<NuxtLink class="hover:text-gray-200" to="/privacy">隐私政策</NuxtLink>
|
||||
<NuxtLink class="hover:text-gray-200" to="/terms">使用条款</NuxtLink>
|
||||
<NuxtLink class="hover:text-gray-200" to="/disclaimer">免责声明</NuxtLink>
|
||||
</div>
|
||||
<div class="tools flex items-center opacity-80 hover:opacity-90 text-gray-100 text-xs">
|
||||
Powered by
|
||||
<a
|
||||
@@ -52,7 +71,7 @@
|
||||
import { getCmsWebsiteFieldByCode } from '@/api/cms/cmsWebsiteField'
|
||||
|
||||
const { data: siteInfo } = useSiteInfo()
|
||||
const siteName = computed(() => String((siteInfo.value as any)?.data?.websiteName || '桂乐淘'))
|
||||
const siteName = computed(() => String((siteInfo.value as any)?.data?.websiteName || '广西决策咨询网'))
|
||||
|
||||
const { data: icpField } = useAsyncData('cms-website-field-icpNo', async () => {
|
||||
try {
|
||||
@@ -62,6 +81,22 @@ const { data: icpField } = useAsyncData('cms-website-field-icpNo', async () => {
|
||||
}
|
||||
})
|
||||
|
||||
const { data: policeField } = useAsyncData('cms-website-field-policeNo', async () => {
|
||||
try {
|
||||
return await getCmsWebsiteFieldByCode('policeNo')
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
const { data: siteCodeField } = useAsyncData('cms-website-field-siteCode', async () => {
|
||||
try {
|
||||
return await getCmsWebsiteFieldByCode('siteCode')
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
const icpNo = computed(() => {
|
||||
const v = icpField.value?.value ?? icpField.value?.defaultValue
|
||||
if (typeof v === 'string' && v.trim()) return v.trim()
|
||||
@@ -69,13 +104,36 @@ const icpNo = computed(() => {
|
||||
return typeof fallback === 'string' ? fallback.trim() : ''
|
||||
})
|
||||
|
||||
const icpText = computed(() => (icpNo.value ? `备案号:${icpNo.value}` : '备案号:'))
|
||||
const policeNo = computed(() => {
|
||||
const v = policeField.value?.value ?? policeField.value?.defaultValue
|
||||
if (typeof v === 'string' && v.trim()) return v.trim()
|
||||
const fallback = (siteInfo.value as any)?.data?.policeNo
|
||||
return typeof fallback === 'string' ? fallback.trim() : ''
|
||||
})
|
||||
|
||||
const siteCode = computed(() => {
|
||||
const v = siteCodeField.value?.value ?? siteCodeField.value?.defaultValue
|
||||
if (typeof v === 'string' && v.trim()) return v.trim()
|
||||
const fallback = (siteInfo.value as any)?.data?.siteCode
|
||||
return typeof fallback === 'string' ? fallback.trim() : ''
|
||||
})
|
||||
|
||||
const icpText = computed(() => (icpNo.value ? `桂 ICP 备:${icpNo.value}` : '桂 ICP 备:'))
|
||||
const policeText = computed(() => (policeNo.value ? `桂公网安备:${policeNo.value}` : '桂公网安备:'))
|
||||
const siteCodeText = computed(() => (siteCode.value ? `网站标识码:${siteCode.value}` : '网站标识码:'))
|
||||
const year = new Date().getFullYear()
|
||||
|
||||
const friendLinks = [
|
||||
{ name: '广西壮族自治区人民政府', url: 'https://www.gxzf.gov.cn' },
|
||||
{ name: '国务院发展研究中心', url: 'https://www.drc.gov.cn' },
|
||||
{ name: '中国社会科学院', url: 'https://www.cass.cn' },
|
||||
{ name: '广西社科联', url: 'http://www.gxskl.gov.cn' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.footer {
|
||||
background: #4b5563;
|
||||
background: #111827;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,50 +1,71 @@
|
||||
<template>
|
||||
<header class="site-header">
|
||||
<div class="topbar">
|
||||
<div class="mx-auto flex max-w-screen-xl items-center justify-between gap-4 px-4">
|
||||
<div class="topbar-left">
|
||||
<span class="topbar-date">{{ todayText }}</span>
|
||||
</div>
|
||||
<a href="#main-content" class="skip-link">跳到主要内容</a>
|
||||
|
||||
<div class="topbar-right">
|
||||
<div class="hidden md:flex items-center gap-2">
|
||||
<a-button size="small" @click="navigateTo('/join')">招商加盟</a-button>
|
||||
<a-button v-if="isLoggedIn" size="small" type="primary" @click="navigateTo('/console')">用户中心</a-button>
|
||||
<a-button v-else size="small" type="primary" @click="navigateTo('/login')">会员登录</a-button>
|
||||
</div>
|
||||
<a-affix :offset-top="0">
|
||||
<div class="header-affix">
|
||||
<div v-if="showBrandbar" class="brandbar">
|
||||
<div class="mx-auto grid max-w-screen-xl grid-cols-[1fr_auto_1fr] items-center gap-3 px-4 py-3">
|
||||
<div class="hidden md:block text-left text-xs text-white/85">
|
||||
{{ todayText }}
|
||||
</div>
|
||||
|
||||
<a-button class="md:hidden" size="small" @click="open = true">菜单</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="showBrandbar" class="brandbar">
|
||||
<div class="brandbar-inner mx-auto grid max-w-screen-xl grid-cols-12 items-center gap-6 px-4 py-4">
|
||||
<NuxtLink to="/" class="col-span-12 flex items-center gap-4 md:col-span-6">
|
||||
<img class="brand-logo" :src="`https://oss.wsdns.cn/20260127/989e5cf82b0847ed9168023baf68f4a9.png`" :alt="siteName" />
|
||||
</NuxtLink>
|
||||
|
||||
<div class="col-span-12 hidden text-right md:col-span-6 md:block">
|
||||
<div class="brand-mission">{{ missionText }}</div>
|
||||
<div class="brand-values">{{ valuesText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden md:block">
|
||||
<a-affix :offset-top="0" @change="onAffixChange">
|
||||
<div class="navbar">
|
||||
<div class="mx-auto flex max-w-screen-xl items-center justify-between gap-3 px-4">
|
||||
<NuxtLink v-if="isAffixed" to="/" class="navbar-brand">
|
||||
<img class="navbar-logo" :src="logoUrl" :alt="siteName" />
|
||||
<span class="navbar-brand-name">
|
||||
{{ siteName }}
|
||||
</span>
|
||||
<NuxtLink to="/" class="brand-center" aria-label="返回首页">
|
||||
<img class="brand-logo" :src="logoUrl" :alt="siteName" />
|
||||
<div class="brand-text">
|
||||
<div class="brand-name">{{ siteName }}</div>
|
||||
<div class="brand-slogan">{{ siteSlogan }}</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
<nav class="nav hidden md:flex">
|
||||
|
||||
<div class="brand-actions">
|
||||
<a-button
|
||||
size="small"
|
||||
class="action-btn hidden md:inline-flex"
|
||||
:aria-pressed="highContrast"
|
||||
@click="toggleContrast"
|
||||
>
|
||||
无障碍
|
||||
</a-button>
|
||||
|
||||
<a-segmented
|
||||
class="lang-switch hidden md:inline-flex"
|
||||
size="small"
|
||||
:options="langOptions"
|
||||
:value="locale"
|
||||
@change="setLocale"
|
||||
/>
|
||||
|
||||
<a-button
|
||||
v-if="isLoggedIn"
|
||||
size="small"
|
||||
type="primary"
|
||||
class="action-btn"
|
||||
@click="navigateTo('/console')"
|
||||
>
|
||||
用户中心
|
||||
</a-button>
|
||||
<a-button
|
||||
v-else
|
||||
size="small"
|
||||
type="primary"
|
||||
class="action-btn"
|
||||
@click="navigateTo('/login')"
|
||||
>
|
||||
登录
|
||||
</a-button>
|
||||
|
||||
<a-button class="md:hidden action-btn" size="small" @click="open = true">菜单</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar">
|
||||
<div class="mx-auto flex max-w-screen-xl items-center gap-3 px-4">
|
||||
<nav class="nav hidden md:flex" aria-label="主导航">
|
||||
<template v-for="item in navItems" :key="item.key">
|
||||
<a-dropdown v-if="item.children?.length" :trigger="['hover', 'click']">
|
||||
<a class="nav-link" :class="{ active: isActive(item) }" @click.prevent>
|
||||
<a class="nav-link" :class="{ active: isActive(item) }" @click.prevent="onNavClick(item)">
|
||||
{{ item.label }}
|
||||
</a>
|
||||
<template #overlay>
|
||||
@@ -70,13 +91,31 @@
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</nav>
|
||||
|
||||
<div class="hidden md:flex flex-1 justify-end">
|
||||
<a-input-search
|
||||
class="site-search"
|
||||
placeholder="站内搜索"
|
||||
:allow-clear="true"
|
||||
:maxlength="50"
|
||||
@search="onSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-affix>
|
||||
</div>
|
||||
</div>
|
||||
</a-affix>
|
||||
</header>
|
||||
|
||||
<a-drawer v-model:open="open" title="导航" placement="right">
|
||||
<a-input-search
|
||||
class="mb-3"
|
||||
placeholder="站内搜索"
|
||||
:allow-clear="true"
|
||||
:maxlength="50"
|
||||
@search="onSearch"
|
||||
/>
|
||||
|
||||
<a-menu mode="inline" :selected-keys="selectedKeys">
|
||||
<template v-for="item in navItems" :key="item.key">
|
||||
<a-menu-item v-if="!item.children?.length" :key="item.key" @click="onNavClick(item)">
|
||||
@@ -96,9 +135,10 @@
|
||||
|
||||
<div class="mt-4">
|
||||
<a-space direction="vertical" class="w-full">
|
||||
<a-button type="primary" block @click="onNav('/contact')">联系我们</a-button>
|
||||
<a-button block @click="onNav('/products')">经营范围</a-button>
|
||||
<a-button block @click="onNav('/join')">招商加盟</a-button>
|
||||
<a-button type="primary" block @click="onNav('/login')">登录</a-button>
|
||||
<a-button block :aria-pressed="highContrast" @click="toggleContrast">无障碍(高对比度)</a-button>
|
||||
<a-button block @click="onNav('/contact')">联系我们</a-button>
|
||||
<a-button block @click="onNav('/sitemap')">站点地图</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</a-drawer>
|
||||
@@ -107,12 +147,10 @@
|
||||
<script setup lang="ts">
|
||||
import { mainNav } from '@/config/nav'
|
||||
import type { CmsNavigation } from '@/api/cms/cmsNavigation/model'
|
||||
import { COMPANY } from '@/config/company'
|
||||
import { getToken } from '@/utils/token-util'
|
||||
|
||||
const route = useRoute()
|
||||
const open = ref(false)
|
||||
const isAffixed = ref(false)
|
||||
const isHydrated = ref(false)
|
||||
const token = ref('')
|
||||
|
||||
@@ -171,7 +209,9 @@ function pickString(source: unknown, key: string) {
|
||||
|
||||
const siteName = computed(() => {
|
||||
const websiteName = siteData.value?.websiteName
|
||||
return typeof websiteName === 'string' && websiteName.trim() ? websiteName.trim() : '桂乐淘'
|
||||
return typeof websiteName === 'string' && websiteName.trim()
|
||||
? websiteName.trim()
|
||||
: '广西决策咨询网'
|
||||
})
|
||||
|
||||
const showBrandbar = computed(() => {
|
||||
@@ -196,12 +236,9 @@ const siteSlogan = computed(() => {
|
||||
pickString(data?.setting, 'slogan') ||
|
||||
pickString(data?.setting, 'subtitle') ||
|
||||
pickString(data?.config, 'slogan')
|
||||
return slogan || `${COMPANY.projectName} · 品质服务与合规经营`
|
||||
return slogan || '权威发布 · 决策支持 · 服务发展'
|
||||
})
|
||||
|
||||
const missionText = computed(() => '生物基材料研发 · 技术服务 · 食品与农产品流通')
|
||||
const valuesText = computed(() => '真诚 · 奉献 · 规范 · 聚力')
|
||||
|
||||
function normalizePath(path: unknown) {
|
||||
if (typeof path !== 'string') return ''
|
||||
const p = path.trim()
|
||||
@@ -242,6 +279,19 @@ function normalizeNavTree(list: CmsNavigation[]): HeaderNavItem[] {
|
||||
.map(normalizeOne)
|
||||
}
|
||||
|
||||
function normalizeLocalNavTree(list: typeof mainNav): HeaderNavItem[] {
|
||||
const normalizeOne = (n: (typeof mainNav)[number]): HeaderNavItem => {
|
||||
const children = Array.isArray(n.children) && n.children.length ? n.children.map(normalizeOne) : undefined
|
||||
return {
|
||||
key: n.key || n.to || n.label,
|
||||
label: n.label,
|
||||
...(n.href ? { href: n.href, target: n.target || '_blank' } : { to: n.to || '/' }),
|
||||
...(children?.length ? { children } : {})
|
||||
}
|
||||
}
|
||||
return list.map(normalizeOne)
|
||||
}
|
||||
|
||||
const navItems = computed<HeaderNavItem[]>(() => {
|
||||
const apiNavs = siteData.value?.topNavs
|
||||
if (Array.isArray(apiNavs) && apiNavs.length) {
|
||||
@@ -249,7 +299,7 @@ const navItems = computed<HeaderNavItem[]>(() => {
|
||||
return normalizeNavTree(apiNavs as CmsNavigation[])
|
||||
}
|
||||
// Fallback when CMS has not configured topNavs.
|
||||
return mainNav.map((n) => ({ key: n.key || n.to, label: n.label, to: n.to }))
|
||||
return normalizeLocalNavTree(mainNav)
|
||||
})
|
||||
|
||||
function isActive(item: HeaderNavItem) {
|
||||
@@ -281,8 +331,45 @@ const todayText = computed(() => {
|
||||
return `${d.getFullYear()}年${pad(d.getMonth() + 1)}月${pad(d.getDate())}日 星期${week}`
|
||||
})
|
||||
|
||||
function onAffixChange(affixed: boolean) {
|
||||
isAffixed.value = affixed
|
||||
const locale = useState<'zh-CN' | 'en'>('site-locale', () => 'zh-CN')
|
||||
const highContrast = useState<boolean>('site-high-contrast', () => false)
|
||||
|
||||
const langOptions = [
|
||||
{ label: '简体', value: 'zh-CN' },
|
||||
{ label: 'EN', value: 'en' }
|
||||
]
|
||||
|
||||
function applyPreferences() {
|
||||
if (!import.meta.client) return
|
||||
document.documentElement.lang = locale.value === 'en' ? 'en' : 'zh-CN'
|
||||
document.documentElement.dataset.contrast = highContrast.value ? 'high' : 'normal'
|
||||
}
|
||||
|
||||
function setLocale(value: unknown) {
|
||||
locale.value = value === 'en' ? 'en' : 'zh-CN'
|
||||
try {
|
||||
localStorage.setItem('site-locale', locale.value)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
applyPreferences()
|
||||
}
|
||||
|
||||
function toggleContrast() {
|
||||
highContrast.value = !highContrast.value
|
||||
try {
|
||||
localStorage.setItem('site-high-contrast', highContrast.value ? '1' : '0')
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
applyPreferences()
|
||||
}
|
||||
|
||||
function onSearch(value: string) {
|
||||
const q = String(value || '').trim()
|
||||
if (!q) return
|
||||
open.value = false
|
||||
navigateTo({ path: '/search', query: { q } })
|
||||
}
|
||||
|
||||
function syncToken() {
|
||||
@@ -291,6 +378,14 @@ function syncToken() {
|
||||
|
||||
onMounted(() => {
|
||||
isHydrated.value = true
|
||||
try {
|
||||
const savedLocale = localStorage.getItem('site-locale')
|
||||
locale.value = savedLocale === 'en' ? 'en' : 'zh-CN'
|
||||
highContrast.value = localStorage.getItem('site-high-contrast') === '1'
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
applyPreferences()
|
||||
syncToken()
|
||||
window.addEventListener(TOKEN_EVENT, syncToken)
|
||||
})
|
||||
@@ -302,146 +397,133 @@ onBeforeUnmount(() => {
|
||||
|
||||
<style scoped>
|
||||
.site-header {
|
||||
background: #fff;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
background: #f7f7f7;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
font-size: 12px;
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transform: translateY(-140%);
|
||||
background: #ffffff;
|
||||
color: #0f172a;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: 10px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.topbar-left {
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
padding: 6px 0;
|
||||
.skip-link:focus {
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
.topbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 0;
|
||||
.header-affix {
|
||||
box-shadow: 0 8px 22px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
.brandbar {
|
||||
background:
|
||||
linear-gradient(0deg, rgba(255, 255, 255, 0.88), rgba(255, 255, 255, 0.88)),
|
||||
radial-gradient(circle at 25% 20%, rgba(220, 38, 38, 0.12), transparent 60%),
|
||||
radial-gradient(circle at 80% 20%, rgba(59, 130, 246, 0.12), transparent 55%),
|
||||
linear-gradient(180deg, #f2f4f7, #ffffff);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||
background: var(--gov-blue);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
|
||||
.brand-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
text-decoration: none;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.brand-logo {
|
||||
height: 62px;
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.brand-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
.brand-text {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
font-size: 28px;
|
||||
line-height: 1.1;
|
||||
color: #ffffff;
|
||||
font-size: 20px;
|
||||
line-height: 1.2;
|
||||
font-weight: 800;
|
||||
color: #15803d;
|
||||
}
|
||||
|
||||
.brand-sub {
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.08em;
|
||||
color: rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
.brand-mission {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.brand-values {
|
||||
margin-top: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background: #16a34a;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
height: 48px;
|
||||
text-decoration: none;
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
font-weight: 700;
|
||||
transition: opacity 0.18s ease, transform 0.18s ease;
|
||||
}
|
||||
|
||||
.navbar-logo {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.navbar-brand-name {
|
||||
color: #e7ffe5;
|
||||
font-size: 15px;
|
||||
letter-spacing: 0.02em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 220px;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.navbar-brand:hover {
|
||||
color: #fff;
|
||||
.brand-slogan {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.88);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.brand-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.lang-switch :deep(.ant-segmented) {
|
||||
background: rgba(255, 255, 255, 0.16);
|
||||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
padding: 0 18px;
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
height: 50px;
|
||||
padding: 0 14px;
|
||||
color: #111827;
|
||||
font-weight: 600;
|
||||
border-radius: 10px;
|
||||
text-decoration: none;
|
||||
transition: background 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: #fff;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: var(--gov-blue);
|
||||
background: rgba(30, 111, 181, 0.08);
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
color: #fff;
|
||||
background: rgba(30, 111, 181, 0.12);
|
||||
color: var(--gov-blue);
|
||||
}
|
||||
|
||||
.nav-spacer {
|
||||
height: 48px;
|
||||
.site-search {
|
||||
max-width: 360px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.brandbar-inner {
|
||||
height: 160px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
.brand-name {
|
||||
max-width: 240px;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,86 @@
|
||||
export type NavItem = {
|
||||
key: string
|
||||
label: string
|
||||
to: string
|
||||
key: string
|
||||
label: string
|
||||
to?: string
|
||||
href?: string
|
||||
target?: string
|
||||
children?: NavItem[]
|
||||
}
|
||||
|
||||
export const mainNav: NavItem[] = [
|
||||
{key: 'home', label: '首页', to: '/'},
|
||||
{key: 'products', label: '经营范围', to: '/products'},
|
||||
{key: 'join', label: '招商加盟', to: '/join'},
|
||||
{key: 'contact', label: '联系我们', to: '/contact'}
|
||||
{ key: 'home', label: '首页', to: '/' },
|
||||
{
|
||||
key: 'policy',
|
||||
label: '政策要闻',
|
||||
to: '/policy',
|
||||
children: [
|
||||
{ key: 'policy-latest', label: '最新资讯', to: '/policy/latest' },
|
||||
{ key: 'policy-cities', label: '市县决策', to: '/policy/cities' },
|
||||
{ key: 'policy-hotspots', label: '研究热点', to: '/policy/hotspots' },
|
||||
{ key: 'policy-events', label: '学术活动', to: '/policy/events' },
|
||||
{ key: 'policy-release', label: '政策发布', to: '/policy/release' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'reference',
|
||||
label: '决策参考',
|
||||
to: '/reference',
|
||||
children: [
|
||||
{ key: 'reference-docs', label: '政策文件', to: '/reference/docs' },
|
||||
{ key: 'reference-data', label: '数据服务', to: '/reference/data' },
|
||||
{ key: 'reference-results', label: '研究成果', to: '/reference/results' },
|
||||
{ key: 'reference-opinions', label: '专家视点', to: '/reference/opinions' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'membership',
|
||||
label: '会员服务',
|
||||
to: '/member',
|
||||
children: [
|
||||
{ key: 'member-qualification', label: '会员资格', to: '/member/qualification' },
|
||||
{ key: 'member-apply', label: '会员申请', to: '/member/apply' },
|
||||
{ key: 'member-downloads', label: '资料下载', to: '/downloads' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'consulting',
|
||||
label: '咨询服务',
|
||||
to: '/consulting',
|
||||
children: [
|
||||
{ key: 'consulting-intro', label: '服务简介', to: '/consulting/intro' },
|
||||
{ key: 'consulting-results', label: '研究成果', to: '/consulting/results' },
|
||||
{ key: 'consulting-contact', label: '联系', to: '/contact' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'thinktank',
|
||||
label: '智库动态',
|
||||
to: '/thinktank',
|
||||
children: [
|
||||
{ key: 'thinktank-party', label: '智库党建', to: '/thinktank/party' },
|
||||
{ key: 'thinktank-coop', label: '交流合作', to: '/thinktank/coop' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'experts',
|
||||
label: '专家智库平台',
|
||||
to: '/experts',
|
||||
children: [
|
||||
{ key: 'experts-db', label: '智库专家库', to: '/experts/db' },
|
||||
{ key: 'experts-style', label: '专家风采', to: '/experts/style' },
|
||||
{ key: 'experts-apply', label: '专家申请', to: '/experts/apply' },
|
||||
{ key: 'experts-downloads', label: '资料下载', to: '/downloads' }
|
||||
]
|
||||
},
|
||||
{ key: 'suggest', label: '建言献策', to: '/suggest' },
|
||||
{
|
||||
key: 'about',
|
||||
label: '关于我们',
|
||||
to: '/about',
|
||||
children: [
|
||||
{ key: 'about-org', label: '组织机构', to: '/about/org' },
|
||||
{ key: 'about-staff', label: '机构人员', to: '/about/staff' },
|
||||
{ key: 'about-contact', label: '联系我们', to: '/contact' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -3,5 +3,5 @@ export const MODULES_API_URL = '/api/_modules'
|
||||
export const FILE_SERVER = '/api/_file'
|
||||
|
||||
// Some endpoints use this as a special TenantId override (defaults to current tenant)
|
||||
export const TEMPLATE_ID = '10584'
|
||||
export const TEMPLATE_ID = '10588'
|
||||
|
||||
|
||||
@@ -3,9 +3,15 @@
|
||||
<a-layout class="min-h-screen layout-shell" :class="{ 'layout-shell--pending': spinning }">
|
||||
<SiteHeader />
|
||||
<a-layout-content class="content">
|
||||
<slot />
|
||||
<div class="mx-auto w-full max-w-screen-xl px-4">
|
||||
<Breadcrumbs />
|
||||
</div>
|
||||
<main id="main-content" class="mx-auto w-full max-w-screen-xl px-4 pb-12">
|
||||
<slot />
|
||||
</main>
|
||||
</a-layout-content>
|
||||
<SiteFooter />
|
||||
<a-back-top />
|
||||
</a-layout>
|
||||
</a-spin>
|
||||
</template>
|
||||
@@ -13,6 +19,7 @@
|
||||
<script setup lang="ts">
|
||||
import SiteFooter from '@/components/SiteFooter.vue'
|
||||
import SiteHeader from '@/components/SiteHeader.vue'
|
||||
import Breadcrumbs from '@/components/Breadcrumbs.vue'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
const nuxtApp = useNuxtApp()
|
||||
|
||||
20
app/pages/about/index.vue
Normal file
20
app/pages/about/index.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="关于我们"
|
||||
description="介绍机构定位、组织架构与人员队伍建设,展示平台治理与服务体系。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '关于我们', description: '关于我们栏目入口。', path: '/about' })
|
||||
|
||||
const links = [
|
||||
{ label: '组织机构', to: '/about/org' },
|
||||
{ label: '机构人员', to: '/about/staff' },
|
||||
{ label: '联系我们', to: '/contact' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/about/org.vue
Normal file
10
app/pages/about/org.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="组织机构" description="展示机构职能分工与工作机制,明确对外服务窗口与责任部门。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '组织机构', description: '关于我们 - 组织机构。', path: '/about/org' })
|
||||
</script>
|
||||
|
||||
10
app/pages/about/staff.vue
Normal file
10
app/pages/about/staff.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="机构人员" description="展示人员队伍与研究方向,支持按领域查看与对接。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '机构人员', description: '关于我们 - 机构人员。', path: '/about/staff' })
|
||||
</script>
|
||||
|
||||
20
app/pages/consulting/index.vue
Normal file
20
app/pages/consulting/index.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="咨询服务"
|
||||
description="围绕决策需求提供咨询服务与研究支撑,覆盖需求对接、成果交付与持续跟踪。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '咨询服务', description: '咨询服务栏目入口。', path: '/consulting' })
|
||||
|
||||
const links = [
|
||||
{ label: '服务简介', to: '/consulting/intro' },
|
||||
{ label: '研究成果', to: '/consulting/results' },
|
||||
{ label: '联系', to: '/contact' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/consulting/intro.vue
Normal file
10
app/pages/consulting/intro.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="服务简介" description="介绍服务范围、交付形式与协作机制,支持在线咨询与需求提交。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '服务简介', description: '咨询服务 - 服务简介。', path: '/consulting/intro' })
|
||||
</script>
|
||||
|
||||
10
app/pages/consulting/results.vue
Normal file
10
app/pages/consulting/results.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="咨询成果" description="展示决策咨询成果与典型案例(可按权限分级展示)。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '咨询成果', description: '咨询服务 - 研究成果。', path: '/consulting/results' })
|
||||
</script>
|
||||
|
||||
10
app/pages/disclaimer.vue
Normal file
10
app/pages/disclaimer.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="免责声明" description="本页面用于发布免责声明与内容使用说明。" :show-result="false" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '免责声明', description: '免责声明。', path: '/disclaimer' })
|
||||
</script>
|
||||
|
||||
22
app/pages/downloads.vue
Normal file
22
app/pages/downloads.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="资料下载"
|
||||
description="提供申报模板、政策文件、数据手册与成果简报等工具服务(可按权限分级开放)。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
|
||||
usePageSeo({ title: '资料下载', description: '资料下载与模板入口。', path: '/downloads' })
|
||||
|
||||
const links = [
|
||||
{ label: '申报模板', to: '/downloads?type=templates', desc: '会员/专家申请书等' },
|
||||
{ label: '政策文件', to: '/downloads?type=policies' },
|
||||
{ label: '数据手册', to: '/downloads?type=data' },
|
||||
{ label: '成果简报', to: '/downloads?type=briefs' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/experts/apply.vue
Normal file
10
app/pages/experts/apply.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="专家申请" description="在线提交专家入库申请并上传材料,进入审核与归档流程。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '专家申请', description: '专家智库平台 - 专家申请。', path: '/experts/apply' })
|
||||
</script>
|
||||
|
||||
10
app/pages/experts/db.vue
Normal file
10
app/pages/experts/db.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="智库专家库" description="按学科领域与研究方向检索专家,支持匹配推荐与联系对接。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '智库专家库', description: '专家智库平台 - 智库专家库。', path: '/experts/db' })
|
||||
</script>
|
||||
|
||||
21
app/pages/experts/index.vue
Normal file
21
app/pages/experts/index.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="专家智库平台"
|
||||
description="建设多学科专家库,支持分类检索、专家匹配与成果展示。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '专家智库平台', description: '专家智库平台入口。', path: '/experts' })
|
||||
|
||||
const links = [
|
||||
{ label: '智库专家库', to: '/experts/db', desc: '分类检索与专家匹配' },
|
||||
{ label: '专家风采', to: '/experts/style', desc: '访谈、观点集锦与成果展示' },
|
||||
{ label: '专家申请', to: '/experts/apply' },
|
||||
{ label: '资料下载', to: '/downloads' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/experts/style.vue
Normal file
10
app/pages/experts/style.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="专家风采" description="展示专家访谈、观点集锦与代表性研究成果。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '专家风采', description: '专家智库平台 - 专家风采。', path: '/experts/style' })
|
||||
</script>
|
||||
|
||||
@@ -1,370 +1,339 @@
|
||||
<template>
|
||||
<main class="portal-home">
|
||||
<header class="site-header">
|
||||
<div class="mx-auto max-w-screen-xl px-4">
|
||||
<div class="site-brand-wrap">
|
||||
<div class="site-badge">政务</div>
|
||||
<div>
|
||||
<h1 class="site-title">广西决策咨询网</h1>
|
||||
<p class="site-subtitle">权威发布 · 决策支持 · 服务发展</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="home py-8">
|
||||
<section aria-label="焦点要闻">
|
||||
<Carousel :items="heroSlides" height="clamp(260px, 42vw, 480px)" effect="fade" />
|
||||
</section>
|
||||
|
||||
<nav class="top-nav" aria-label="主导航">
|
||||
<NuxtLink
|
||||
v-for="item in navItems"
|
||||
:key="item.label"
|
||||
:to="item.to"
|
||||
class="nav-item"
|
||||
>
|
||||
{{ item.label }}
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<section class="mt-8">
|
||||
<div class="grid grid-cols-12 gap-6">
|
||||
<a-card class="col-span-12 lg:col-span-4" :bordered="false">
|
||||
<template #title>
|
||||
<div class="section-title">政策要闻</div>
|
||||
</template>
|
||||
<ul class="list">
|
||||
<li v-for="it in policyNews" :key="it.title">
|
||||
<NuxtLink :to="it.to">{{ it.title }}</NuxtLink>
|
||||
<span class="date">{{ it.date }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<NuxtLink class="more" to="/policy/latest">查看更多</NuxtLink>
|
||||
</a-card>
|
||||
|
||||
<section class="hero-panel">
|
||||
<div class="mx-auto max-w-screen-xl px-4 py-8">
|
||||
<p class="hero-eyebrow">政府门户 · 官方导向</p>
|
||||
<h2 class="hero-title">聚焦广西决策咨询服务,建设高水平智库平台</h2>
|
||||
<p class="hero-desc">
|
||||
围绕政策解读、课题研究、战略合作与会员服务,提供规范、及时、可追溯的政务信息发布与决策支持。
|
||||
</p>
|
||||
<a-card class="col-span-12 lg:col-span-4" :bordered="false">
|
||||
<template #title>
|
||||
<div class="section-title">智库动态</div>
|
||||
</template>
|
||||
<ul class="list">
|
||||
<li v-for="it in thinktankNews" :key="it.title">
|
||||
<NuxtLink :to="it.to">{{ it.title }}</NuxtLink>
|
||||
<span class="date">{{ it.date }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<NuxtLink class="more" to="/thinktank">查看更多</NuxtLink>
|
||||
</a-card>
|
||||
|
||||
<a-card class="col-span-12 lg:col-span-4" :bordered="false">
|
||||
<template #title>
|
||||
<div class="section-title">会员风采</div>
|
||||
</template>
|
||||
<ul class="list">
|
||||
<li v-for="it in memberSpotlight" :key="it.title">
|
||||
<NuxtLink :to="it.to">{{ it.title }}</NuxtLink>
|
||||
<span class="date">{{ it.date }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<NuxtLink class="more" to="/member">查看更多</NuxtLink>
|
||||
</a-card>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mx-auto max-w-screen-xl px-4 py-8">
|
||||
<div class="content-grid">
|
||||
<article class="module-card">
|
||||
<h3 class="module-title">政策文件</h3>
|
||||
<ul class="module-list">
|
||||
<li v-for="item in policyDocs" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="module-card">
|
||||
<h3 class="module-title">重要通知</h3>
|
||||
<ul class="module-list">
|
||||
<li v-for="item in notices" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="module-card">
|
||||
<h3 class="module-title">领导讲话</h3>
|
||||
<ul class="module-list">
|
||||
<li v-for="item in speeches" :key="item">{{ item }}</li>
|
||||
</ul>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="feature-block">
|
||||
<h3 class="feature-title">重点工作</h3>
|
||||
<div class="feature-grid">
|
||||
<div v-for="item in focusWorks" :key="item.title" class="feature-card">
|
||||
<h4>{{ item.title }}</h4>
|
||||
<p>{{ item.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<section class="mt-6 hidden lg:block" aria-label="会员单位展示位">
|
||||
<div class="ad-slot">
|
||||
会员单位展示位(广告)- 预留横幅
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="mx-auto max-w-screen-xl px-4 py-6">
|
||||
<h3 class="friend-title">友情链接</h3>
|
||||
<div class="friend-links">
|
||||
<a v-for="item in friendLinks" :key="item.name" :href="item.url" target="_blank" rel="noreferrer">
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</div>
|
||||
<p class="copyright">© 广西决策咨询网 | 政务信息仅供公开发布与查询使用</p>
|
||||
<section class="mt-8" aria-label="决策咨询">
|
||||
<a-card :bordered="false">
|
||||
<template #title>
|
||||
<div class="section-title">决策咨询</div>
|
||||
</template>
|
||||
|
||||
<a-tabs v-model:active-key="consultingTab" animated>
|
||||
<a-tab-pane key="reports" tab="研究报告">
|
||||
<ul class="list list--dense">
|
||||
<li v-for="it in reports" :key="it.title">
|
||||
<NuxtLink :to="it.to">{{ it.title }}</NuxtLink>
|
||||
<span class="meta">
|
||||
<a-tag v-if="it.status" color="blue">{{ it.status }}</a-tag>
|
||||
<span class="date">{{ it.date }}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="briefs" tab="咨政专报">
|
||||
<ul class="list list--dense">
|
||||
<li v-for="it in briefs" :key="it.title">
|
||||
<NuxtLink :to="it.to">{{ it.title }}</NuxtLink>
|
||||
<span class="meta">
|
||||
<span class="date">{{ it.date }}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="collections" tab="其他汇编">
|
||||
<ul class="list list--dense">
|
||||
<li v-for="it in collections" :key="it.title">
|
||||
<NuxtLink :to="it.to">{{ it.title }}</NuxtLink>
|
||||
<span class="meta">
|
||||
<span class="date">{{ it.date }}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="instructions" tab="领导批示">
|
||||
<ul class="list list--dense">
|
||||
<li v-for="it in instructions" :key="it.title">
|
||||
<NuxtLink :to="it.to">{{ it.title }}</NuxtLink>
|
||||
<span class="meta">
|
||||
<a-tag v-if="it.status" color="green">{{ it.status }}</a-tag>
|
||||
<span class="date">{{ it.date }}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</section>
|
||||
|
||||
<section class="mt-8" aria-label="快捷入口">
|
||||
<div class="grid grid-cols-12 gap-6">
|
||||
<a-card class="col-span-12 lg:col-span-4" :bordered="false">
|
||||
<template #title><div class="section-title">决策参考</div></template>
|
||||
<div class="quick-desc">政策文件、数据服务、研究成果与专家视点等支撑信息。</div>
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<a-button type="primary" @click="navigateTo('/reference/data')">数据服务</a-button>
|
||||
<a-button @click="navigateTo('/reference/docs')">政策文件</a-button>
|
||||
<a-button @click="navigateTo('/reference/results')">研究成果</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
<a-card class="col-span-12 lg:col-span-4" :bordered="false">
|
||||
<template #title><div class="section-title">建言献策</div></template>
|
||||
<div class="quick-desc">面向公众与会员征集意见建议,支持在线提交与反馈。</div>
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<a-button type="primary" @click="navigateTo('/suggest')">提交建议</a-button>
|
||||
<a-button @click="navigateTo('/sitemap')">站点地图</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
<a-card class="col-span-12 lg:col-span-4" :bordered="false">
|
||||
<template #title><div class="section-title">咨询服务</div></template>
|
||||
<div class="quick-desc">需求对接、专题研究、政策解读与成果交付,支持分级权限管理。</div>
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<a-button type="primary" @click="navigateTo('/consulting/intro')">了解服务</a-button>
|
||||
<a-button @click="navigateTo('/contact')">联系咨询</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
</section>
|
||||
|
||||
<section class="mt-8" aria-label="专家智库平台">
|
||||
<a-card :bordered="false">
|
||||
<template #title><div class="section-title">专家智库平台</div></template>
|
||||
<div class="grid grid-cols-12 gap-6 items-start">
|
||||
<div class="col-span-12 lg:col-span-8">
|
||||
<div class="quick-desc">
|
||||
覆盖多学科领域的专家库,支持分类检索、专家匹配与成果展示。
|
||||
</div>
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<a-button type="primary" @click="navigateTo('/experts/db')">进入专家库</a-button>
|
||||
<a-button @click="navigateTo('/experts/style')">专家风采</a-button>
|
||||
<a-button @click="navigateTo('/experts/apply')">专家申请</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 lg:col-span-4">
|
||||
<a-alert
|
||||
show-icon
|
||||
type="info"
|
||||
message="提示"
|
||||
description="专家视点、成果下载等栏目可配置会员权限与分级开放。"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePageSeo } from "@/composables/usePageSeo"
|
||||
import Carousel from '@/components/Carousel.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
|
||||
usePageSeo({
|
||||
title: "广西决策咨询网",
|
||||
description: "广西决策咨询网门户首页,发布政策文件、重要通知、领导讲话与课题研究信息。",
|
||||
path: "/"
|
||||
title: '首页',
|
||||
description: '广西决策咨询网门户首页,聚焦政策要闻、决策咨询、专家智库与咨询服务。',
|
||||
path: '/'
|
||||
})
|
||||
|
||||
const navItems = [
|
||||
{ label: "网站首页", to: "/" },
|
||||
{ label: "学会活动", to: "/article/activities" },
|
||||
{ label: "决策资讯", to: "/article/news" },
|
||||
{ label: "战略合作", to: "/article/coop" },
|
||||
{ label: "会员服务", to: "/member" },
|
||||
{ label: "课题研究", to: "/article/research" },
|
||||
{ label: "学会党建", to: "/article/party" },
|
||||
{ label: "关于我们", to: "/about" }
|
||||
const heroSlides = [
|
||||
{
|
||||
src: '/hero/hero-1.svg',
|
||||
href: '/reference/results',
|
||||
alt: '智库要闻',
|
||||
title: '智库要闻 · 重大成果发布',
|
||||
desc: '聚焦党委政府重大课题、社科院及研究机构成果,提供权威发布与可追溯链接。',
|
||||
ctaLabel: '查看详情'
|
||||
},
|
||||
{
|
||||
src: '/hero/hero-2.svg',
|
||||
href: '/consulting/intro',
|
||||
alt: '决策咨询',
|
||||
title: '决策咨询 · 精要报告与咨政专报',
|
||||
desc: '围绕热点难点问题快速研判,标注批示/采纳状态,提升成果转化效率。',
|
||||
ctaLabel: '了解服务'
|
||||
},
|
||||
{
|
||||
src: '/hero/hero-3.svg',
|
||||
href: '/experts/db',
|
||||
alt: '专家智库',
|
||||
title: '专家智库 · 分类检索与专家匹配',
|
||||
desc: '覆盖多学科领域,支持按方向检索、匹配与协作对接,构建协同开放平台。',
|
||||
ctaLabel: '进入专家库'
|
||||
}
|
||||
]
|
||||
|
||||
const policyDocs = [
|
||||
"广西重点产业发展政策解读(2026年)",
|
||||
"自治区决策咨询课题管理办法(修订)",
|
||||
"关于加强高端智库成果转化的实施意见",
|
||||
"政务信息公开与数据安全管理规范"
|
||||
const consultingTab = ref<'reports' | 'briefs' | 'collections' | 'instructions'>('reports')
|
||||
|
||||
const policyNews = [
|
||||
{ title: '关于申报 2026 年度重点课题的通知', date: '2026-03-01', to: '/policy/latest' },
|
||||
{ title: '自治区决策咨询课题管理办法(修订)', date: '2026-02-18', to: '/policy/release' },
|
||||
{ title: '政务信息公开与数据安全管理规范要点', date: '2026-02-06', to: '/policy/hotspots' },
|
||||
{ title: '学术活动预告:专题研讨会(面向 RCEP)', date: '2026-01-26', to: '/policy/events' }
|
||||
]
|
||||
|
||||
const notices = [
|
||||
"关于申报2026年度重点课题的通知",
|
||||
"学会专家库入库审核结果公示",
|
||||
"战略合作单位联络员培训安排",
|
||||
"清明节假期值班与应急工作通知"
|
||||
const thinktankNews = [
|
||||
{ title: '交流合作:联合研究项目启动', date: '2026-03-03', to: '/thinktank/coop' },
|
||||
{ title: '智库党建:制度建设与工作要点', date: '2026-02-21', to: '/thinktank/party' },
|
||||
{ title: '政策解读:重点产业发展政策解读', date: '2026-02-10', to: '/reference/docs' },
|
||||
{ title: '东盟研究:经贸数据与国际比较专题', date: '2026-01-30', to: '/reference/data' }
|
||||
]
|
||||
|
||||
const speeches = [
|
||||
"坚持问题导向,提升咨政建言质量",
|
||||
"服务地方治理现代化的智库路径",
|
||||
"打造开放协同的决策咨询共同体",
|
||||
"推动研究成果向政策实践高效转化"
|
||||
const memberSpotlight = [
|
||||
{ title: '会员单位风采:成果转化典型案例', date: '2026-02-28', to: '/member' },
|
||||
{ title: '会员服务:培训活动与资源对接计划', date: '2026-02-14', to: '/member/qualification' },
|
||||
{ title: '资料下载:申报模板与数据手册更新', date: '2026-02-03', to: '/downloads' },
|
||||
{ title: '会员申请:线上资料提交与审核说明', date: '2026-01-20', to: '/member/apply' }
|
||||
]
|
||||
|
||||
const focusWorks = [
|
||||
{ title: "课题研究", desc: "围绕重大现实问题开展专题研究,形成可落地的政策建议。" },
|
||||
{ title: "战略合作", desc: "联动高校、研究机构与行业协会,构建协同创新平台。" },
|
||||
{ title: "会员服务", desc: "提供成果交流、培训活动和资源对接等综合服务。" },
|
||||
{ title: "学会党建", desc: "强化党建引领,推动业务发展与组织建设深度融合。" }
|
||||
const reports = [
|
||||
{ title: '重大课题研究报告(精要)', date: '2026-02-25', to: '/reference/results', status: '采纳' },
|
||||
{ title: '专题调研报告:向海经济发展路径', date: '2026-02-11', to: '/reference/results', status: '批示' },
|
||||
{ title: '政策评估报告:产业链协同效率提升', date: '2026-01-29', to: '/reference/results', status: '在研' }
|
||||
]
|
||||
|
||||
const friendLinks = [
|
||||
{ name: "广西壮族自治区人民政府", url: "https://www.gxzf.gov.cn" },
|
||||
{ name: "中国社会科学院", url: "https://www.cass.cn" },
|
||||
{ name: "国务院发展研究中心", url: "https://www.drc.gov.cn" },
|
||||
{ name: "广西社科联", url: "http://www.gxskl.gov.cn" }
|
||||
const briefs = [
|
||||
{ title: '咨政专报:热点问题快速研判(第 3 期)', date: '2026-03-02', to: '/consulting/results' },
|
||||
{ title: '咨政专报:重点领域风险提示(第 2 期)', date: '2026-02-16', to: '/consulting/results' },
|
||||
{ title: '咨政专报:阶段性建议汇总(第 1 期)', date: '2026-01-31', to: '/consulting/results' }
|
||||
]
|
||||
|
||||
const collections = [
|
||||
{ title: '历年决策咨询成果合集(电子版)', date: '2026-02-08', to: '/downloads' },
|
||||
{ title: '重大课题成果汇编(专题)', date: '2026-01-18', to: '/downloads' }
|
||||
]
|
||||
|
||||
const instructions = [
|
||||
{ title: '领导批示成果清单(可追溯链接)', date: '2026-02-20', to: '/consulting/results', status: '公开' },
|
||||
{ title: '采纳情况统计与典型案例', date: '2026-01-27', to: '/consulting/results', status: '公开' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.portal-home {
|
||||
min-height: 100vh;
|
||||
background: #f8f8f8;
|
||||
.home :deep(.ant-card) {
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 14px 28px rgba(15, 23, 42, 0.05);
|
||||
}
|
||||
|
||||
.site-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
background: linear-gradient(180deg, #9f1313, #c31818);
|
||||
border-bottom: 3px solid #f3d27a;
|
||||
box-shadow: 0 8px 20px rgba(110, 10, 10, 0.25);
|
||||
}
|
||||
|
||||
.site-brand-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 18px 0 14px;
|
||||
}
|
||||
|
||||
.site-badge {
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #8b1111;
|
||||
background: linear-gradient(180deg, #f8df9f, #e7bd5b);
|
||||
}
|
||||
|
||||
.site-title {
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
letter-spacing: 0.06em;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.site-subtitle {
|
||||
margin: 6px 0 0;
|
||||
color: rgba(255, 255, 255, 0.88);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.top-nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
color: #fff3d7;
|
||||
text-decoration: none;
|
||||
font-size: 15px;
|
||||
padding: 12px 18px;
|
||||
border-bottom: 3px solid transparent;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-item:hover,
|
||||
.nav-item.router-link-active {
|
||||
color: #fff;
|
||||
border-bottom-color: #f5d07a;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.hero-panel {
|
||||
background:
|
||||
linear-gradient(140deg, rgba(140, 12, 12, 0.9), rgba(173, 18, 18, 0.88)),
|
||||
repeating-linear-gradient(45deg, transparent, transparent 18px, rgba(255, 255, 255, 0.03) 18px, rgba(255, 255, 255, 0.03) 36px);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hero-eyebrow {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(255, 233, 190, 0.95);
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
margin: 12px 0;
|
||||
font-size: 34px;
|
||||
line-height: 1.35;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.hero-desc {
|
||||
margin: 0;
|
||||
max-width: 780px;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.module-card {
|
||||
grid-column: span 12;
|
||||
border: 1px solid #eed7d7;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.module-card {
|
||||
grid-column: span 4;
|
||||
}
|
||||
}
|
||||
|
||||
.module-title {
|
||||
margin: 0;
|
||||
padding: 14px 16px;
|
||||
font-size: 18px;
|
||||
color: #941515;
|
||||
background: linear-gradient(180deg, #fff6f6, #ffeaea);
|
||||
border-bottom: 1px solid #efd5d5;
|
||||
}
|
||||
|
||||
.module-list {
|
||||
list-style: none;
|
||||
padding: 10px 16px 16px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.module-list li {
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px dashed #ecd1d1;
|
||||
color: #2d2d2d;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.module-list li:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.feature-block {
|
||||
margin-top: 24px;
|
||||
border: 1px solid #efd4d4;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.feature-title {
|
||||
margin: 0;
|
||||
padding: 14px 16px;
|
||||
color: #941515;
|
||||
.section-title {
|
||||
font-size: 20px;
|
||||
border-bottom: 1px solid #efd4d4;
|
||||
background: linear-gradient(180deg, #fff9f9, #fff0f0);
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
.feature-grid {
|
||||
.list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
padding: 16px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
grid-column: span 12;
|
||||
background: #fffafa;
|
||||
border: 1px solid #f2dede;
|
||||
border-radius: 8px;
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
@media (min-width: 900px) {
|
||||
.feature-card {
|
||||
grid-column: span 6;
|
||||
}
|
||||
}
|
||||
|
||||
.feature-card h4 {
|
||||
margin: 0;
|
||||
color: #8f1313;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.feature-card p {
|
||||
margin: 8px 0 0;
|
||||
line-height: 1.7;
|
||||
color: #4b4b4b;
|
||||
}
|
||||
|
||||
.site-footer {
|
||||
margin-top: 20px;
|
||||
background: #f0ecec;
|
||||
border-top: 1px solid #dcc8c8;
|
||||
}
|
||||
|
||||
.friend-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
color: #6f6f6f;
|
||||
}
|
||||
|
||||
.friend-links {
|
||||
.list li {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px 16px;
|
||||
margin-top: 10px;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px dashed rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.friend-links a {
|
||||
color: #514a4a;
|
||||
.list li:last-child {
|
||||
border-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.list a {
|
||||
color: #111827;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.friend-links a:hover {
|
||||
color: #931414;
|
||||
.list a:hover {
|
||||
color: var(--gov-blue);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
margin: 14px 0 0;
|
||||
color: #7f7f7f;
|
||||
.date {
|
||||
flex: 0 0 auto;
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.meta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.list--dense li {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.more {
|
||||
display: inline-flex;
|
||||
margin-top: 12px;
|
||||
font-weight: 700;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 4px;
|
||||
}
|
||||
|
||||
.ad-slot {
|
||||
border: 1px dashed rgba(30, 111, 181, 0.35);
|
||||
background: rgba(30, 111, 181, 0.05);
|
||||
border-radius: 14px;
|
||||
padding: 14px 16px;
|
||||
color: rgba(30, 111, 181, 0.95);
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.quick-desc {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
</style>
|
||||
|
||||
10
app/pages/member/apply.vue
Normal file
10
app/pages/member/apply.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="会员申请" description="在线填写申请信息并上传材料,提交后进入资格审核流程。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '会员申请', description: '会员服务 - 会员申请。', path: '/member/apply' })
|
||||
</script>
|
||||
|
||||
21
app/pages/member/index.vue
Normal file
21
app/pages/member/index.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="会员服务"
|
||||
description="提供会员资格说明、会员申请与资料下载等服务,支持在线审核与权限化内容访问。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
|
||||
usePageSeo({ title: '会员服务', description: '会员服务栏目入口。', path: '/member' })
|
||||
|
||||
const links = [
|
||||
{ label: '会员资格', to: '/member/qualification' },
|
||||
{ label: '会员申请', to: '/member/apply', desc: '企业会员 / 个人会员在线申请与资料上传' },
|
||||
{ label: '资料下载', to: '/downloads' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/member/qualification.vue
Normal file
10
app/pages/member/qualification.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="会员资格" description="说明会员权益、准入条件与服务范围,支持按类型分层服务。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '会员资格', description: '会员服务 - 会员资格。', path: '/member/qualification' })
|
||||
</script>
|
||||
|
||||
10
app/pages/policy/cities.vue
Normal file
10
app/pages/policy/cities.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="市县决策" description="汇聚市县治理与决策实践动态,沉淀可复制的经验做法。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '市县决策', description: '政策要闻 - 市县决策。', path: '/policy/cities' })
|
||||
</script>
|
||||
|
||||
10
app/pages/policy/events.vue
Normal file
10
app/pages/policy/events.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="学术活动" description="展示学术交流、研讨会议与专题培训等活动信息。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '学术活动', description: '政策要闻 - 学术活动。', path: '/policy/events' })
|
||||
</script>
|
||||
|
||||
10
app/pages/policy/hotspots.vue
Normal file
10
app/pages/policy/hotspots.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="研究热点" description="跟踪热点难点议题,发布阶段性研判与专题研究动态。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '研究热点', description: '政策要闻 - 研究热点。', path: '/policy/hotspots' })
|
||||
</script>
|
||||
|
||||
23
app/pages/policy/index.vue
Normal file
23
app/pages/policy/index.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="政策要闻"
|
||||
description="围绕政策资讯、研究热点与学术活动,提供权威、清晰、可追溯的信息发布。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
|
||||
usePageSeo({ title: '政策要闻', description: '政策要闻栏目入口。', path: '/policy' })
|
||||
|
||||
const links = [
|
||||
{ label: '最新资讯', to: '/policy/latest' },
|
||||
{ label: '市县决策', to: '/policy/cities' },
|
||||
{ label: '研究热点', to: '/policy/hotspots' },
|
||||
{ label: '学术活动', to: '/policy/events' },
|
||||
{ label: '政策发布', to: '/policy/release' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/policy/latest.vue
Normal file
10
app/pages/policy/latest.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="最新资讯" description="发布最新政策资讯与智库要闻,支持按时间与关键词检索。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '最新资讯', description: '政策要闻 - 最新资讯。', path: '/policy/latest' })
|
||||
</script>
|
||||
|
||||
10
app/pages/policy/release.vue
Normal file
10
app/pages/policy/release.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="政策发布" description="转载并归档中央、自治区重要政策文件、规划纲要与权威解读链接。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '政策发布', description: '政策要闻 - 政策发布。', path: '/policy/release' })
|
||||
</script>
|
||||
|
||||
10
app/pages/privacy.vue
Normal file
10
app/pages/privacy.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="隐私政策" description="本页面用于发布隐私政策与个人信息保护说明。" :show-result="false" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '隐私政策', description: '隐私政策。', path: '/privacy' })
|
||||
</script>
|
||||
|
||||
20
app/pages/reference/data.vue
Normal file
20
app/pages/reference/data.vue
Normal file
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="数据服务"
|
||||
description="提供宏观经济、东盟经贸、产业发展等数据入口(可按权限分级开放)。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '数据服务', description: '决策参考 - 数据服务。', path: '/reference/data' })
|
||||
|
||||
const links = [
|
||||
{ label: '广西宏观经济数据', to: '/reference/data?source=gx-macro' },
|
||||
{ label: '东盟经贸数据', to: '/reference/data?source=asean-trade' },
|
||||
{ label: '产业发展数据', to: '/reference/data?source=industry' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/reference/docs.vue
Normal file
10
app/pages/reference/docs.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="政策文件" description="集中展示重要政策文件、规划纲要与权威发布渠道。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '政策文件', description: '决策参考 - 政策文件。', path: '/reference/docs' })
|
||||
</script>
|
||||
|
||||
22
app/pages/reference/index.vue
Normal file
22
app/pages/reference/index.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="决策参考"
|
||||
description="面向决策需求,提供政策文件、数据服务、研究成果与专家视点等支撑信息。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
|
||||
usePageSeo({ title: '决策参考', description: '决策参考栏目入口。', path: '/reference' })
|
||||
|
||||
const links = [
|
||||
{ label: '政策文件', to: '/reference/docs' },
|
||||
{ label: '数据服务', to: '/reference/data', desc: '链接宏观经济、东盟经贸、产业发展等信息库' },
|
||||
{ label: '研究成果', to: '/reference/results' },
|
||||
{ label: '专家视点', to: '/reference/opinions', desc: '部分内容可能需要会员权限' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/reference/opinions.vue
Normal file
10
app/pages/reference/opinions.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="专家视点" description="面向热点议题发布专家观点与解读(可配置会员访问控制)。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '专家视点', description: '决策参考 - 专家视点。', path: '/reference/opinions' })
|
||||
</script>
|
||||
|
||||
10
app/pages/reference/results.vue
Normal file
10
app/pages/reference/results.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="研究成果" description="汇聚党委政府重大课题、研究机构成果与专题调研报告。 " />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '研究成果', description: '决策参考 - 研究成果。', path: '/reference/results' })
|
||||
</script>
|
||||
|
||||
41
app/pages/search.vue
Normal file
41
app/pages/search.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<section class="py-10">
|
||||
<a-typography-title :level="1" class="!mb-2">站内搜索</a-typography-title>
|
||||
<a-typography-paragraph class="!text-gray-600 !mb-6">
|
||||
支持按栏目 / 时间 / 关键词筛选(待接入全文检索与权限控制)。
|
||||
</a-typography-paragraph>
|
||||
|
||||
<a-input-search
|
||||
v-model:value="q"
|
||||
placeholder="请输入关键词"
|
||||
:allow-clear="true"
|
||||
:maxlength="50"
|
||||
enter-button="搜索"
|
||||
@search="onSearch"
|
||||
/>
|
||||
|
||||
<a-card class="mt-6" size="small">
|
||||
<div class="text-sm text-gray-600">
|
||||
当前关键词:<span class="font-mono">{{ q || '-' }}</span>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
<a-result class="mt-6" status="info" title="搜索结果建设中" sub-title="接入全文检索后将在此展示结构化结果列表。" />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
|
||||
const route = useRoute()
|
||||
const q = ref(String(route.query.q || '').trim())
|
||||
|
||||
usePageSeo({ title: '站内搜索', description: '站内搜索与筛选入口。', path: '/search' })
|
||||
|
||||
function onSearch(value: string) {
|
||||
const next = String(value || '').trim()
|
||||
q.value = next
|
||||
navigateTo({ path: '/search', query: next ? { q: next } : {} })
|
||||
}
|
||||
</script>
|
||||
|
||||
49
app/pages/sitemap.vue
Normal file
49
app/pages/sitemap.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<section class="py-10">
|
||||
<a-typography-title :level="1" class="!mb-2">站点地图</a-typography-title>
|
||||
<a-typography-paragraph class="!text-gray-600 !mb-6">
|
||||
便捷入口汇总,支持快速定位栏目与服务。
|
||||
</a-typography-paragraph>
|
||||
|
||||
<a-card size="small">
|
||||
<ul class="sitemap">
|
||||
<li v-for="it in nav" :key="it.key">
|
||||
<NuxtLink v-if="it.to" :to="it.to">{{ it.label }}</NuxtLink>
|
||||
<span v-else>{{ it.label }}</span>
|
||||
<ul v-if="it.children?.length">
|
||||
<li v-for="c in it.children" :key="c.key">
|
||||
<NuxtLink v-if="c.to" :to="c.to">{{ c.label }}</NuxtLink>
|
||||
<span v-else>{{ c.label }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</a-card>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { mainNav } from '@/config/nav'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
|
||||
usePageSeo({ title: '站点地图', description: '站点地图与栏目入口汇总。', path: '/sitemap' })
|
||||
const nav = mainNav
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sitemap {
|
||||
margin: 0;
|
||||
padding-left: 18px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.sitemap li {
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.sitemap ul {
|
||||
margin-top: 6px;
|
||||
padding-left: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
13
app/pages/suggest.vue
Normal file
13
app/pages/suggest.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="建言献策"
|
||||
description="面向公众与会员征集意见建议,支持在线提交与进度反馈(可配置权限与实名)。"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '建言献策', description: '建言献策入口。', path: '/suggest' })
|
||||
</script>
|
||||
|
||||
10
app/pages/terms.vue
Normal file
10
app/pages/terms.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="使用条款" description="本页面用于发布网站使用条款与服务协议。" :show-result="false" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '使用条款', description: '使用条款与服务协议。', path: '/terms' })
|
||||
</script>
|
||||
|
||||
10
app/pages/thinktank/coop.vue
Normal file
10
app/pages/thinktank/coop.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="交流合作" description="发布合作项目、交流活动与联合研究进展,促进智库协同。 " />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '交流合作', description: '智库动态 - 交流合作。', path: '/thinktank/coop' })
|
||||
</script>
|
||||
|
||||
19
app/pages/thinktank/index.vue
Normal file
19
app/pages/thinktank/index.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<SectionStub
|
||||
title="智库动态"
|
||||
description="发布智库党建、交流合作与平台建设动态,展示协同开放成果。"
|
||||
:links="links"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '智库动态', description: '智库动态栏目入口。', path: '/thinktank' })
|
||||
|
||||
const links = [
|
||||
{ label: '智库党建', to: '/thinktank/party' },
|
||||
{ label: '交流合作', to: '/thinktank/coop' }
|
||||
]
|
||||
</script>
|
||||
|
||||
10
app/pages/thinktank/party.vue
Normal file
10
app/pages/thinktank/party.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<SectionStub title="智库党建" description="展示党建工作动态与制度建设成果,推动党建与业务深度融合。" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SectionStub from '@/components/SectionStub.vue'
|
||||
import { usePageSeo } from '@/composables/usePageSeo'
|
||||
usePageSeo({ title: '智库党建', description: '智库动态 - 智库党建。', path: '/thinktank/party' })
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function getTenantId(defaultTenantId = '10584') {
|
||||
export function getTenantId(defaultTenantId = '10588') {
|
||||
if (!import.meta.client) return defaultTenantId
|
||||
try {
|
||||
return localStorage.getItem('TenantId') || defaultTenantId
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'nuxt4-10584',
|
||||
name: 'nuxt4-10588',
|
||||
cwd: __dirname,
|
||||
script: '.output/server/index.mjs',
|
||||
interpreter: 'node',
|
||||
@@ -9,8 +9,8 @@ module.exports = {
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
NITRO_HOST: '0.0.0.0',
|
||||
NITRO_PORT: 10584,
|
||||
PORT: 10584,
|
||||
NITRO_PORT: 10588,
|
||||
PORT: 10588,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -6,7 +6,7 @@ function getOrigin(url: string) {
|
||||
}
|
||||
}
|
||||
|
||||
const tenantId = process.env.NUXT_PUBLIC_TENANT_ID || '10584'
|
||||
const tenantId = process.env.NUXT_PUBLIC_TENANT_ID || '10588'
|
||||
const serverApiBase =
|
||||
process.env.NUXT_PUBLIC_SERVER_API_BASE ||
|
||||
process.env.NUXT_PUBLIC_SERVER_API ||
|
||||
@@ -42,7 +42,8 @@ export default defineNuxtConfig({
|
||||
modules: ['@nuxtjs/tailwindcss', './modules/fix-tailwind-postcss'],
|
||||
app: {
|
||||
head: {
|
||||
titleTemplate: (titleChunk) => (titleChunk ? `${titleChunk} - 桂乐淘` : '桂乐淘'),
|
||||
titleTemplate: (titleChunk) =>
|
||||
titleChunk ? `${titleChunk} - 广西决策咨询网` : '广西决策咨询网',
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
|
||||
17
public/hero/hero-1.svg
Normal file
17
public/hero/hero-1.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-label="智库要闻背景图">
|
||||
<defs>
|
||||
<linearGradient id="g1" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#1E6FB5"/>
|
||||
<stop offset="1" stop-color="#2BA69A"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="r1" cx="70%" cy="20%" r="60%">
|
||||
<stop offset="0" stop-color="rgba(255,255,255,0.18)"/>
|
||||
<stop offset="1" stop-color="rgba(255,255,255,0)"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect width="1600" height="900" fill="url(#g1)"/>
|
||||
<rect width="1600" height="900" fill="url(#r1)"/>
|
||||
<path d="M0 640C220 560 360 610 540 690C720 770 900 780 1120 700C1340 620 1460 560 1600 520V900H0V640Z" fill="rgba(255,255,255,0.10)"/>
|
||||
<path d="M0 720C240 650 420 700 600 780C780 860 980 860 1220 780C1460 700 1520 670 1600 640V900H0V720Z" fill="rgba(15,23,42,0.10)"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 907 B |
23
public/hero/hero-2.svg
Normal file
23
public/hero/hero-2.svg
Normal file
@@ -0,0 +1,23 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-label="决策咨询背景图">
|
||||
<defs>
|
||||
<linearGradient id="g2" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0" stop-color="#0F3D73"/>
|
||||
<stop offset="0.55" stop-color="#1E6FB5"/>
|
||||
<stop offset="1" stop-color="#2BA69A"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="r2" cx="25%" cy="30%" r="65%">
|
||||
<stop offset="0" stop-color="rgba(255,255,255,0.16)"/>
|
||||
<stop offset="1" stop-color="rgba(255,255,255,0)"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect width="1600" height="900" fill="url(#g2)"/>
|
||||
<rect width="1600" height="900" fill="url(#r2)"/>
|
||||
<g fill="rgba(255,255,255,0.10)">
|
||||
<rect x="120" y="140" width="520" height="14" rx="7"/>
|
||||
<rect x="120" y="190" width="700" height="12" rx="6"/>
|
||||
<rect x="120" y="235" width="620" height="12" rx="6"/>
|
||||
<rect x="120" y="280" width="740" height="12" rx="6"/>
|
||||
</g>
|
||||
<path d="M0 660C260 580 420 650 600 730C780 810 980 820 1220 740C1460 660 1540 620 1600 590V900H0V660Z" fill="rgba(255,255,255,0.08)"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
21
public/hero/hero-3.svg
Normal file
21
public/hero/hero-3.svg
Normal file
@@ -0,0 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-label="专家智库背景图">
|
||||
<defs>
|
||||
<linearGradient id="g3" x1="0" y1="1" x2="1" y2="0">
|
||||
<stop offset="0" stop-color="#1E6FB5"/>
|
||||
<stop offset="1" stop-color="#0F3D73"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="r3" cx="75%" cy="35%" r="70%">
|
||||
<stop offset="0" stop-color="rgba(43,166,154,0.30)"/>
|
||||
<stop offset="1" stop-color="rgba(43,166,154,0)"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<rect width="1600" height="900" fill="url(#g3)"/>
|
||||
<rect width="1600" height="900" fill="url(#r3)"/>
|
||||
<g stroke="rgba(255,255,255,0.12)" stroke-width="2" fill="none">
|
||||
<circle cx="1260" cy="240" r="110"/>
|
||||
<circle cx="1260" cy="240" r="170"/>
|
||||
<circle cx="1260" cy="240" r="230"/>
|
||||
</g>
|
||||
<path d="M0 700C240 620 420 670 620 760C820 850 1040 850 1260 760C1480 670 1540 640 1600 620V900H0V700Z" fill="rgba(255,255,255,0.08)"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 968 B |
@@ -15,7 +15,7 @@ export default defineEventHandler(async (event) => {
|
||||
getHeader(event, 'tenantid') ||
|
||||
config.public.tenantId ||
|
||||
config.public.TenantId ||
|
||||
'10584'
|
||||
'10588'
|
||||
const authorization = getHeader(event, 'authorization')
|
||||
|
||||
const headers = {
|
||||
|
||||
@@ -12,7 +12,7 @@ export default defineEventHandler(async (event) => {
|
||||
getHeader(event, 'tenantid') ||
|
||||
config.public.tenantId ||
|
||||
config.public.TenantId ||
|
||||
'10584'
|
||||
'10588'
|
||||
const authorization = getHeader(event, 'authorization')
|
||||
|
||||
try {
|
||||
|
||||
@@ -9,7 +9,14 @@ module.exports = {
|
||||
'./nuxt.config.{js,ts}'
|
||||
],
|
||||
theme: {
|
||||
extend: {}
|
||||
extend: {
|
||||
colors: {
|
||||
gov: {
|
||||
blue: '#1E6FB5',
|
||||
teal: '#2BA69A'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
corePlugins: {
|
||||
preflight: false
|
||||
|
||||
Reference in New Issue
Block a user