Compare commits

...

2 Commits

Author SHA1 Message Date
5defd0e4d0 Merge branch 'wyfMain-dev' 2025-05-23 08:55:16 +08:00
ae3b14cd89 优化部分导航样式 2025-05-23 08:50:08 +08:00
13 changed files with 499 additions and 325 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -5,14 +5,15 @@
:class="{ 'header-scrolled': isScrolled }"
>
<div class="header-container">
<div class="logo">
<NImage width="108" height="33" :src="FiEELogo" preview-disabled />
<div class="logo" @click="handleToHome">
<NImage width="160" height="50" :src="FiEELogo" preview-disabled />
</div>
<div class="header-menu">
<NMenu
mode="horizontal"
:options="menuOptions"
:inverted="isScrolled"
v-model:value="selectedKey"
@update:value="handleMenuSelect"
/>
</div>
@ -21,15 +22,21 @@
</template>
<script setup>
import FiEELogo from "@/assets/images/header/logo.png";
import { ref, onMounted, onUnmounted } from "vue";
import { NMenu, NLayoutHeader, NImage } from "naive-ui";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
const { t } = useI18n();
const router = useRouter();
import FiEELogo from '@/assets/image/header/logo.png'
import { ref, onMounted, onUnmounted } from 'vue'
import { NMenu, NLayoutHeader, NImage } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { useHeaderMenuConfig } from '@/config/headerMenuConfig'
const isScrolled = ref(false);
const { t } = useI18n()
const router = useRouter()
// 使
const menuOptions = useHeaderMenuConfig()
const selectedKey = ref(null)
const isScrolled = ref(false)
//
function findMenuOptionByKey(options, key) {
@ -51,107 +58,6 @@ const handleMenuSelect = (key) => {
}
};
//
const menuOptions = [
{
label: t("header_menu.corporate_information.title"),
key: "corporate_information",
children: [
{
label: t("header_menu.corporate_information.company_overview"),
key: "company_overview",
},
{
label: t("header_menu.corporate_information.business_introduction"),
key: "business_introduction",
},
{
label: t("header_menu.corporate_information.management"),
key: "management",
},
{
label: t("header_menu.corporate_information.board_of_directors"),
key: "board_of_directors",
},
{
label: t("header_menu.corporate_information.committee_appointments"),
key: "committee_appointments",
},
{
label: t("header_menu.corporate_information.governance"),
key: "governance",
},
{
label: t("header_menu.corporate_information.corporate_video"),
key: "corporate_video",
},
],
},
{
label: t("header_menu.financial_information.title"),
key: "financial_information",
children: [
{
label: t("header_menu.financial_information.sec_filings"),
key: "sec_filings",
href: "/secfilings",
},
{
label: t("header_menu.financial_information.quarterly_results"),
key: "quarterly_results",
href: "/quarterlyresults",
},
],
},
{
label: t("header_menu.stock_information.title"),
key: "stock_information",
children: [
{
label: t("header_menu.stock_information.stock_quote"),
key: "stock_quote",
},
{
label: t("header_menu.stock_information.historic_stock_price"),
key: "historic_stock_price",
},
{
label: t("header_menu.stock_information.investment_calculator"),
key: "investment_calculator",
},
],
},
{
label: t("header_menu.news_releases.title"),
key: "news_releases",
children: [
{
label: t("header_menu.news_releases.press_releases"),
key: "press_releases",
href: "/new-releases",
},
{
label: t("header_menu.news_releases.events_calendar"),
key: "events_calendar",
},
],
},
{
label: t("header_menu.investor_resources.title"),
key: "investor_resources",
children: [
{
label: t("header_menu.investor_resources.ir_contacts"),
key: "ir_contacts",
},
{
label: t("header_menu.investor_resources.email_alerts"),
key: "email_alerts",
},
],
},
];
//
const handleScroll = () => {
//100pxheader
@ -163,13 +69,20 @@ onMounted(() => {
});
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
window.removeEventListener('scroll', handleScroll)
})
//
const handleToHome = () => {
router.push('/')
selectedKey.value = null //
}
</script>
<style scoped lang="scss">
.custom-header {
--header-height: 80px;
--primary-color: #8B59F7;
position: fixed;
top: 0;
left: 0;
@ -181,14 +94,15 @@ onUnmounted(() => {
&.header-scrolled {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(8px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
}
.header-container {
max-width: 1200px;
max-width: 1700px;
margin: 0 auto;
padding: 0 20px;
padding: 0 40px;
height: 100%;
display: flex;
align-items: center;
@ -197,9 +111,115 @@ onUnmounted(() => {
.logo {
flex-shrink: 0;
cursor: pointer;
transition: transform 0.3s ease;
margin-right: 100px;
&:hover {
transform: scale(1.05);
}
&:active {
transform: scale(0.98);
}
}
.header-menu {
display: block;
flex: 1;
:deep(.n-menu) {
background: transparent;
justify-content: flex-end;
}
:deep(.n-menu-item) {
position: relative;
margin: 0 20px;
transition: all 0.3s ease;
font-weight: 700;
font-size: 16px;
min-width: 120px;
text-align: center;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 2px;
background: var(--primary-color);
transition: all 0.3s ease;
transform: translateX(-50%);
opacity: 0;
border-radius: 2px;
}
&:hover {
&::after {
width: 80px;
height: 3px;
opacity: 1;
}
}
//
&.n-menu-item--selected {
&::after {
width: 40px;
opacity: 1;
}
}
}
//
:deep(.n-submenu) {
.n-submenu-children {
backdrop-filter: blur(16px);
background: rgba(255, 255, 255, 0.9);
border-radius: 12px;
padding: 8px 0;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
transform-origin: top;
animation: dropDown 0.3s ease;
.n-menu-item {
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--primary-color);
transform: translateX(-100%);
transition: transform 0.3s ease;
opacity: 0.1;
z-index: -1;
}
&:hover {
&::before {
transform: translateX(0);
}
}
}
}
}
}
@keyframes dropDown {
from {
opacity: 0;
transform: translateY(-10px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
</style>

View File

@ -5,16 +5,19 @@
:class="{ 'header-scrolled': isScrolled }"
>
<div class="header-container">
<div class="logo">
<div class="logo" @click="handleToHome">
<NImage
style="width: 108px; height: 33px; max-width: 100%"
:src="FiEELogo"
preview-disabled
/>
</div>
<div class="menu-btn" @click="toggleMenu">
<n-icon size="28">
<menu-outline />
<div class="menu-btn" :class="{ 'menu-open': showMenu }" @click="toggleMenu">
<n-icon size="28" class="menu-icon menu-icon-menu">
<menu-sharp />
</n-icon>
<n-icon size="28" class="menu-icon menu-icon-close">
<close-sharp />
</n-icon>
</div>
</div>
@ -27,6 +30,7 @@
:inverted="isScrolled"
class="mobile-menu"
accordion
v-model:value="selectedKey"
@update:value="handleMenuSelect"
/>
</div>
@ -34,17 +38,20 @@
</template>
<script setup>
import FiEELogo from "@/assets/images/header/logo.png";
import { ref, onMounted, onUnmounted } from "vue";
import { NMenu, NLayoutHeader, NImage, NIcon } from "naive-ui";
import { MenuOutline } from "@vicons/ionicons5";
import { useI18n } from "vue-i18n";
import { useRouter } from "vue-router";
const { t } = useI18n();
const router = useRouter();
import FiEELogo from '@/assets/image/header/logo.png'
import { ref, onMounted, onUnmounted } from 'vue'
import { NMenu, NLayoutHeader, NImage, NIcon } from 'naive-ui'
import { MenuSharp, CloseSharp } from '@vicons/ionicons5'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { useHeaderMenuConfig } from '@/config/headerMenuConfig'
const isScrolled = ref(false);
const showMenu = ref(false);
const { t } = useI18n()
const router = useRouter()
const isScrolled = ref(false)
const showMenu = ref(false)
const selectedKey = ref(null)
const toggleMenu = () => {
showMenu.value = !showMenu.value;
@ -74,106 +81,8 @@ const handleMenuSelect = (key) => {
}
};
//
const menuOptions = [
{
label: t("header_menu.corporate_information.title"),
key: "corporate_information",
children: [
{
label: t("header_menu.corporate_information.company_overview"),
key: "company_overview",
},
{
label: t("header_menu.corporate_information.business_introduction"),
key: "business_introduction",
},
{
label: t("header_menu.corporate_information.management"),
key: "management",
},
{
label: t("header_menu.corporate_information.board_of_directors"),
key: "board_of_directors",
},
{
label: t("header_menu.corporate_information.committee_appointments"),
key: "committee_appointments",
},
{
label: t("header_menu.corporate_information.governance"),
key: "governance",
},
{
label: t("header_menu.corporate_information.corporate_video"),
key: "corporate_video",
},
],
},
{
label: t("header_menu.financial_information.title"),
key: "financial_information",
children: [
{
label: t("header_menu.financial_information.sec_filings"),
key: "sec_filings",
href: "/secfilings",
},
{
label: t("header_menu.financial_information.quarterly_results"),
key: "quarterly_results",
href: "/quarterlyresults",
},
],
},
{
label: t("header_menu.stock_information.title"),
key: "stock_information",
children: [
{
label: t("header_menu.stock_information.stock_quote"),
key: "stock_quote",
},
{
label: t("header_menu.stock_information.historic_stock_price"),
key: "historic_stock_price",
},
{
label: t("header_menu.stock_information.investment_calculator"),
key: "investment_calculator",
},
],
},
{
label: t("header_menu.news_releases.title"),
key: "news_releases",
children: [
{
label: t("header_menu.news_releases.press_releases"),
key: "press_releases",
href: "/new-releases",
},
{
label: t("header_menu.news_releases.events_calendar"),
key: "events_calendar",
},
],
},
{
label: t("header_menu.investor_resources.title"),
key: "investor_resources",
children: [
{
label: t("header_menu.investor_resources.ir_contacts"),
key: "ir_contacts",
},
{
label: t("header_menu.investor_resources.email_alerts"),
key: "email_alerts",
},
],
},
];
// 使
const menuOptions = useHeaderMenuConfig()
//
const handleScroll = () => {
@ -186,8 +95,15 @@ onMounted(() => {
});
onUnmounted(() => {
window.removeEventListener("scroll", handleScroll);
});
window.removeEventListener('scroll', handleScroll)
})
//
const handleToHome = () => {
router.push('/')
selectedKey.value = null //
showMenu.value = false //
}
</script>
<style scoped lang="scss">
@ -235,17 +151,40 @@ onUnmounted(() => {
align-items: center;
justify-content: center;
cursor: pointer;
color: #465564;
font-size: 75px;
padding: 40px 70px;
border-radius: 30px;
background: #f7f8fa;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.03);
background: transparent;
user-select: none;
transition: background 0.2s;
}
.menu-btn:active {
background: #ececec;
position: relative;
.menu-icon {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%) rotate(0deg);
opacity: 1;
transition:
opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
pointer-events: none;
}
.menu-icon-close {
opacity: 0;
transform: translate(-50%, -50%) rotate(-90deg) scale(0.8);
}
&.menu-open {
.menu-icon-menu {
opacity: 0;
transform: translate(-50%, -50%) rotate(90deg) scale(0.8);
}
.menu-icon-close {
opacity: 1;
transform: translate(-50%, -50%) rotate(0deg) scale(1);
}
}
}
.mobile-menu-wrapper {
@ -259,6 +198,9 @@ onUnmounted(() => {
padding: 40px 0 80px 0;
max-height: 1500px;
overflow-y: auto;
:deep(.n-menu-item) {
font-weight: 600;
}
}
.fade-slide-enter-active,

View File

@ -0,0 +1,105 @@
import { useI18n } from 'vue-i18n'
export const useHeaderMenuConfig = () => {
const { t } = useI18n()
return [
{
label: t('header_menu.corporate_information.title'),
key: 'corporate_information',
children: [
{
label: t('header_menu.corporate_information.company_overview'),
key: 'company_overview',
},
{
label: t('header_menu.corporate_information.business_introduction'),
key: 'business_introduction',
},
{
label: t('header_menu.corporate_information.management'),
key: 'management',
},
{
label: t('header_menu.corporate_information.board_of_directors'),
key: 'board_of_directors',
},
{
label: t('header_menu.corporate_information.committee_appointments'),
key: 'committee_appointments',
},
{
label: t('header_menu.corporate_information.governance'),
key: 'governance',
},
{
label: t('header_menu.corporate_information.corporate_video'),
key: 'corporate_video',
},
],
},
{
label: t('header_menu.financial_information.title'),
key: 'financial_information',
children: [
{
label: t('header_menu.financial_information.sec_filings'),
key: 'sec_filings',
href: "/secfilings",
},
{
label: t('header_menu.financial_information.quarterly_results'),
key: 'quarterly_results',
href: "/quarterlyresults",
},
],
},
{
label: t('header_menu.stock_information.title'),
key: 'stock_information',
children: [
{
label: t('header_menu.stock_information.stock_quote'),
key: 'stock_quote',
},
{
label: t('header_menu.stock_information.historic_stock_price'),
key: 'historic_stock_price',
},
{
label: t('header_menu.stock_information.investment_calculator'),
key: 'investment_calculator',
},
],
},
{
label: t('header_menu.news_releases.title'),
key: 'news_releases',
children: [
{
label: t('header_menu.news_releases.press_releases'),
key: 'press_releases',
href: '/press-releases',
},
{
label: t('header_menu.news_releases.events_calendar'),
key: 'events_calendar',
},
],
},
{
label: t('header_menu.investor_resources.title'),
key: 'investor_resources',
children: [
{
label: t('header_menu.investor_resources.ir_contacts'),
key: 'ir_contacts',
},
{
label: t('header_menu.investor_resources.email_alerts'),
key: 'email_alerts',
},
],
},
]
}

View File

@ -1,77 +1,83 @@
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import { setupRouterGuards } from './router-guards';
import { createRouter, createWebHistory } from 'vue-router'
import { setupRouterGuards } from './router-guards'
const routes = [
{
path: '/',
{
path: '/',
name: 'index',
component: () => import('@/views/index/index.vue'),
// beforeEnter: (to, from, next) => {
// localStorage.clear()
// next()
// }
children: [
{
path: 'home',
name: 'home',
component: () => import('@/views/home/index.vue'),
// beforeEnter: (to, from, next) => {
// localStorage.clear()
// next()
// }
children: [
{
path: 'new-releases',
name: 'new-releases',
component: () => import('@/views/new-releases/index.vue')
},
{
path: '/quarterlyresults',
name: 'QuarterlyResults',
component: () => import('@/views/financialinformation/quarterlyresults/index.vue'),
},
{
path: '/secfilings',
name: 'SecFilings',
component: () => import('@/views/financialinformation/secfilings/index.vue'),
},
]
},
{
path: '/contacts',
name: 'contacts',
component: () => import('@/views/contacts/index.vue'),
},
// {
// path: '/companyprofil',
// name: 'Companyprofil',
// component: () => import('@/views/companyprofil/index.vue'),
// },
// {
// path: '/companyprofildetail',
// name: 'Companyprofildetail',
// component: () => import('@/views/companyprofildetail/index.vue'),
// },
// {
// path: '/businessintroduction',
// name: 'Businessintroduction',
// component: () => import('@/views/businessintroduction/index.vue'),
// },
// {
// path: '/investor',
// name: 'Investor',
// component: () => import('@/views/investor/index.vue'),
// },
// {
// path: '/investorhandbook',
// name: 'Investorhandbook',
// component: () => import('@/views/investorhandbook/index.vue'),
// },
];
},
{
path: 'press-releases',
name: 'press-releases',
component: () => import('@/views/press-releases/index.vue'),
},
{
path: '/quarterlyresults',
name: 'QuarterlyResults',
component: () =>
import('@/views/financialinformation/quarterlyresults/index.vue'),
},
{
path: '/secfilings',
name: 'SecFilings',
component: () =>
import('@/views/financialinformation/secfilings/index.vue'),
},
],
},
{
path: '/contacts',
name: 'contacts',
component: () => import('@/views/contacts/index.vue'),
},
// {
// path: '/companyprofil',
// name: 'Companyprofil',
// component: () => import('@/views/companyprofil/index.vue'),
// },
// {
// path: '/companyprofildetail',
// name: 'Companyprofildetail',
// component: () => import('@/views/companyprofildetail/index.vue'),
// },
// {
// path: '/businessintroduction',
// name: 'Businessintroduction',
// component: () => import('@/views/businessintroduction/index.vue'),
// },
// {
// path: '/investor',
// name: 'Investor',
// component: () => import('@/views/investor/index.vue'),
// },
// {
// path: '/investorhandbook',
// name: 'Investorhandbook',
// component: () => import('@/views/investorhandbook/index.vue'),
// },
]
const router = createRouter({
history: createWebHistory(),
routes
});
history: createWebHistory(),
routes,
})
router.beforeEach((to, from, next) => {
if (to.meta?.title) {
document.title = to.meta.title;
}
next()
});
setupRouterGuards(router);
export default router;
if (to.meta?.title) {
document.title = to.meta.title
}
next()
})
setupRouterGuards(router)
export default router

View File

@ -7,15 +7,10 @@ import customFooter from '@/components/customFooter/index.vue'
</script>
<template>
<!-- <header className="header">
1920
</header> -->
<!-- <main ref="main"></main> -->
<customHeader />
<div style="margin: 80px 0;">
<router-view />
</div>
<customFooter />
<header className="header">
1920
</header>
<main ref="main"></main>
</template>
<style scoped lang="scss">

View File

@ -7,16 +7,10 @@ import customFooter from '@/components/customFooter/index.vue'
</script>
<template>
<!-- <header className="header">
375
</header> -->
<!-- <main ref="main"></main> -->
<customHeader />
<div style="margin: 80px 0;">
<router-view />
</div>
<customFooter />
<header className="header">
375
</header>
<main ref="main"></main>
</template>
<style scoped lang="scss">

22
src/views/index/index.vue Normal file
View File

@ -0,0 +1,22 @@
<script setup>
import size1920 from '@/views/index/size1920/index.vue'
import size375 from '@/views/index/size375/index.vue'
import { computed } from 'vue'
import { useWindowSize } from '@vueuse/core'
const { width } = useWindowSize()
const viewComponent = computed(() => {
const viewWidth = width.value
if (viewWidth <= 450) {
return size375
} else if (viewWidth <= 1920 || viewWidth > 1920) {
return size1920
}
})
</script>
<template>
<component :is="viewComponent" />
</template>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,21 @@
<script setup>
import { NCarousel, NDivider, NMarquee, NPopselect } from 'naive-ui'
import { onUnmounted, ref, watch, onMounted, computed } from 'vue'
import customHeader from '@/components/customHeader/index.vue'
import customFooter from '@/components/customFooter/index.vue'
</script>
<template>
<customHeader></customHeader>
<div style="margin: 80px 0;">
<router-view />
</div>
<customFooter></customFooter>
</template>
<style scoped lang="scss">
main {
padding: var(--header-height, 80px) 0 0;
}
</style>

View File

@ -0,0 +1,26 @@
<script setup>
import { NCarousel, NDivider, NMarquee, NPopselect } from 'naive-ui'
import { onUnmounted, ref, watch, onMounted, computed } from 'vue'
import customHeader from '@/components/customHeader/index.vue'
import customFooter from '@/components/customFooter/index.vue'
</script>
<template>
<!-- <header className="header">
375
</header> -->
<!-- <main ref="main"></main> -->
<customHeader />
<div style="margin: 80px 0;">
<router-view />
</div>
<customFooter />
</template>
<style scoped lang="scss">
main {
padding: var(--header-height, 80px) 0 0;
}
</style>

View File

@ -0,0 +1,23 @@
<template>
<div class="new-releases-page">
<component :is="viewComponent" />
</div>
</template>
<script setup>
import size1920 from '@/views/press-releases/size1920/index.vue'
import size375 from '@/views/press-releases/size375/index.vue'
import { computed } from 'vue'
import { useWindowSize } from '@vueuse/core'
const { width } = useWindowSize()
const viewComponent = computed(() => {
const viewWidth = width.value
if (viewWidth <= 450) {
return size375
} else if (viewWidth <= 1920 || viewWidth > 1920) {
return size1920
}
})
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,10 @@
<template>
<div class="new-releases-page">
<customDefaultPage></customDefaultPage>
</div>
</template>
<script setup>
import customDefaultPage from '@/components/customDefaultPage/index.vue'
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,10 @@
<template>
<div class="new-releases-page">
<customDefaultPage></customDefaultPage>
</div>
</template>
<script setup>
import customDefaultPage from '@/components/customDefaultPage/index.vue'
</script>
<style scoped lang="scss"></style>