diff --git a/public/images/robot-space.png b/public/images/robot-space.png new file mode 100644 index 0000000..88d8c63 Binary files /dev/null and b/public/images/robot-space.png differ diff --git a/public/images/星云.png b/public/images/星云.png new file mode 100644 index 0000000..ea1441b Binary files /dev/null and b/public/images/星云.png differ diff --git a/public/videos/starry-sky.mp4 b/public/videos/starry-sky.mp4 new file mode 100644 index 0000000..15b5c9c Binary files /dev/null and b/public/videos/starry-sky.mp4 differ diff --git a/public/videos/xingkong.mp4 b/public/videos/xingkong.mp4 new file mode 100644 index 0000000..8be0bf0 Binary files /dev/null and b/public/videos/xingkong.mp4 differ diff --git a/src/assets/images.ts b/src/assets/images.ts index 164aff6..b02357c 100644 --- a/src/assets/images.ts +++ b/src/assets/images.ts @@ -38,7 +38,7 @@ export const images = { manufacturing: 'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?w=800&h=450&fit=crop', finance: 'https://images.unsplash.com/photo-1563986768609-322da13575f3?w=800&h=450&fit=crop', healthcare: 'https://images.unsplash.com/photo-1576091160399-112ba8d25d1d?w=800&h=450&fit=crop', - education: 'https://images.unsplash.com/photo-1523050854058-8df90110c9f1?w=800&h=450&fit=crop', + education: 'https://images.unsplash.com/photo-1522202176988-66273c2fd55f?w=800&h=450&fit=crop', retail: 'https://images.unsplash.com/photo-1556742049-0cfed4f6a45d?w=800&h=450&fit=crop', logistics: 'https://images.unsplash.com/photo-1489599849927-2ee91cede3ba?w=800&h=450&fit=crop', diff --git a/src/components/CosmicBackground.vue b/src/components/CosmicBackground.vue new file mode 100644 index 0000000..b7d28af --- /dev/null +++ b/src/components/CosmicBackground.vue @@ -0,0 +1,372 @@ + + + + + \ No newline at end of file diff --git a/src/components/Footer.vue b/src/components/Footer.vue index d239be3..115f7ab 100644 --- a/src/components/Footer.vue +++ b/src/components/Footer.vue @@ -25,7 +25,7 @@ const currentYear = new Date().getFullYear() - 陕西省西安市高新区科技二路65号清华科技园E座 + 西安市未央区立讯未来中心
diff --git a/src/components/MouseTrail.vue b/src/components/MouseTrail.vue new file mode 100644 index 0000000..6a94cd3 --- /dev/null +++ b/src/components/MouseTrail.vue @@ -0,0 +1,227 @@ + + +
+
+ +
+ +
+
+ + + diff --git a/src/directives/neuralCard.ts b/src/directives/neuralCard.ts new file mode 100644 index 0000000..a3b76f6 --- /dev/null +++ b/src/directives/neuralCard.ts @@ -0,0 +1,120 @@ +import type { Directive } from 'vue' + +interface ActivatePoint { + id: number + x: number + y: number + progress: number +} + +const vNeuralCard: Directive = { + mounted(el: HTMLElement) { + const points: ActivatePoint[] = [] + let pointId = 0 + let animationId: number | null = null + let isHovering = false + + const createActivatePoint = () => { + const rect = el.getBoundingClientRect() + const edge = Math.floor(Math.random() * 4) + let x: number, y: number + + switch (edge) { + case 0: + x = rect.left + Math.random() * rect.width + y = rect.top + break + case 1: + x = rect.right + y = rect.top + Math.random() * rect.height + break + case 2: + x = rect.left + Math.random() * rect.width + y = rect.bottom + break + default: + x = rect.left + y = rect.top + Math.random() * rect.height + } + + points.push({ + id: pointId++, + x, + y, + progress: 0 + }) + + updateCSS() + } + + const updateCSS = () => { + if (points.length === 0) { + el.style.setProperty('--neural-points', '') + return + } + + const pointData = points + .map(p => `${p.x},${p.y},${p.progress}`) + .join('|') + el.style.setProperty('--neural-points', pointData) + el.style.setProperty('--neural-count', String(points.length)) + } + + const animate = () => { + points.forEach(p => { + p.progress += 0.02 + }) + + const activePoints = points.filter(p => p.progress < 1) + points.length = 0 + points.push(...activePoints) + + updateCSS() + + if (isHovering && points.length < 6) { + if (Math.random() > 0.7) { + createActivatePoint() + } + } + + animationId = requestAnimationFrame(animate) + } + + const handleMouseEnter = () => { + isHovering = true + el.classList.add('neural-active') + el.classList.add('neural-card-active') + } + + const handleMouseLeave = () => { + isHovering = false + el.classList.remove('neural-active') + el.classList.remove('neural-card-active') + } + + const handleMouseMove = (e: MouseEvent) => { + const rect = el.getBoundingClientRect() + const mouseX = ((e.clientX - rect.left) / rect.width) * 100 + const mouseY = ((e.clientY - rect.top) / rect.height) * 100 + + el.style.setProperty('--mouse-x', `${mouseX}%`) + el.style.setProperty('--mouse-y', `${mouseY}%`) + } + + el.addEventListener('mouseenter', handleMouseEnter) + el.addEventListener('mouseleave', handleMouseLeave) + el.addEventListener('mousemove', handleMouseMove) + + animate() + + el._neuralAnimationId = animationId + }, + + unmounted(el: HTMLElement) { + if (el._neuralAnimationId) { + cancelAnimationFrame(el._neuralAnimationId) + } + } +} + +export default vNeuralCard diff --git a/src/directives/ripple.ts b/src/directives/ripple.ts new file mode 100644 index 0000000..5168ebd --- /dev/null +++ b/src/directives/ripple.ts @@ -0,0 +1,94 @@ +import type { Directive, DirectiveBinding } from 'vue' + +interface RippleEvent extends MouseEvent { + _ripple?: HTMLElement +} + +const vRipple: Directive = { + mounted(el: HTMLElement, binding: DirectiveBinding) { + el.style.position = 'relative' + el.style.overflow = 'hidden' + + const handleClick = (e: RippleEvent) => { + const rect = el.getBoundingClientRect() + const x = e.clientX - rect.left + const y = e.clientY - rect.top + + const maxSize = Math.max(rect.width, rect.height) * 2 + + const rippleOuter = document.createElement('span') + rippleOuter.style.position = 'absolute' + rippleOuter.style.borderRadius = '50%' + rippleOuter.style.background = 'rgba(59, 130, 246, 0.5)' + rippleOuter.style.width = '30px' + rippleOuter.style.height = '30px' + rippleOuter.style.left = `${x}px` + rippleOuter.style.top = `${y}px` + rippleOuter.style.transform = 'translate(-50%, -50%) scale(0)' + rippleOuter.style.transition = 'transform 0.6s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.6s ease-out' + rippleOuter.style.pointerEvents = 'none' + rippleOuter.style.zIndex = '100' + rippleOuter.style.boxShadow = '0 0 40px rgba(59, 130, 246, 0.8), 0 0 80px rgba(147, 197, 253, 0.6), 0 0 120px rgba(139, 92, 246, 0.4)' + + const rippleMiddle = document.createElement('span') + rippleMiddle.style.position = 'absolute' + rippleMiddle.style.borderRadius = '50%' + rippleMiddle.style.background = 'rgba(147, 197, 253, 0.7)' + rippleMiddle.style.width = '20px' + rippleMiddle.style.height = '20px' + rippleMiddle.style.left = `${x}px` + rippleMiddle.style.top = `${y}px` + rippleMiddle.style.transform = 'translate(-50%, -50%) scale(0)' + rippleMiddle.style.transition = 'transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.5s ease-out' + rippleMiddle.style.pointerEvents = 'none' + rippleMiddle.style.zIndex = '101' + rippleMiddle.style.boxShadow = '0 0 30px rgba(147, 197, 253, 0.9), 0 0 60px rgba(59, 130, 246, 0.7), 0 0 90px rgba(255, 255, 255, 0.5)' + + const rippleInner = document.createElement('span') + rippleInner.style.position = 'absolute' + rippleInner.style.borderRadius = '50%' + rippleInner.style.background = 'radial-gradient(circle, rgba(255, 255, 255, 1) 0%, rgba(147, 197, 253, 1) 30%, rgba(59, 130, 246, 0.8) 70%, transparent 100%)' + rippleInner.style.width = '15px' + rippleInner.style.height = '15px' + rippleInner.style.left = `${x}px` + rippleInner.style.top = `${y}px` + rippleInner.style.transform = 'translate(-50%, -50%) scale(0)' + rippleInner.style.transition = 'transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease-out' + rippleInner.style.pointerEvents = 'none' + rippleInner.style.zIndex = '102' + rippleInner.style.boxShadow = '0 0 25px rgba(255, 255, 255, 1), 0 0 50px rgba(147, 197, 253, 0.9), 0 0 80px rgba(59, 130, 246, 0.7), 0 0 110px rgba(139, 92, 246, 0.5)' + + el.appendChild(rippleOuter) + el.appendChild(rippleMiddle) + el.appendChild(rippleInner) + + requestAnimationFrame(() => { + rippleOuter.style.transform = `translate(-50%, -50%) scale(${maxSize / 15})` + rippleOuter.style.opacity = '0' + + rippleMiddle.style.transform = `translate(-50%, -50%) scale(${maxSize / 10})` + rippleMiddle.style.opacity = '0' + + rippleInner.style.transform = `translate(-50%, -50%) scale(${maxSize / 7})` + rippleInner.style.opacity = '0' + }) + + setTimeout(() => { + rippleOuter.remove() + rippleMiddle.remove() + rippleInner.remove() + }, 700) + } + + el.addEventListener('click', handleClick) + el._rippleHandler = handleClick + }, + + unmounted(el: HTMLElement) { + if (el._rippleHandler) { + el.removeEventListener('click', el._rippleHandler) + } + } +} + +export default vRipple diff --git a/src/main.ts b/src/main.ts index 30a5e0f..1ed6660 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,8 +4,12 @@ import App from './App.vue' import router from './router' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' +import vRipple from './directives/ripple' +import vNeuralCard from './directives/neuralCard' const app = createApp(App) app.use(router) app.use(ElementPlus) +app.directive('ripple', vRipple) +app.directive('neural-card', vNeuralCard) app.mount('#app') \ No newline at end of file diff --git a/src/router/index.ts b/src/router/index.ts index 0c85050..5bda915 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -8,6 +8,11 @@ const router = createRouter({ name: 'Home', component: () => import('@/views/Home.vue') }, + { + path: '/landing', + name: 'Landing', + component: () => import('@/views/LandingPage.vue') + }, { path: '/products', name: 'Products', diff --git a/src/style.css b/src/style.css index 67e07d6..8ae212f 100644 --- a/src/style.css +++ b/src/style.css @@ -90,6 +90,21 @@ body { animation: float 6s ease-in-out infinite; } +.page-visible { + animation: page-fade-in 1s ease-out forwards; +} + +@keyframes page-fade-in { + 0% { + opacity: 0; + transform: scale(0.98); + } + 100% { + opacity: 1; + transform: scale(1); + } +} + /* 渐变背景 */ .bg-gradient-primary { background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 50%, #60a5fa 100%); @@ -143,3 +158,102 @@ body { .text-gradient { @apply bg-gradient-to-r from-primary-600 to-accent-500 bg-clip-text text-transparent; } + +/* 神经网络卡片激活效果 - 旋转光效 */ +.neural-card-active { + position: relative; + transform: translateY(-6px) scale(1.02); + box-shadow: + 0 0 30px rgba(59, 130, 246, 0.4), + 0 0 60px rgba(147, 197, 253, 0.3), + inset 0 0 20px rgba(147, 197, 253, 0.1); +} + +.neural-card-active::before { + content: ''; + position: absolute; + inset: -3px; + border-radius: inherit; + background: conic-gradient( + from 0deg, + transparent 0deg, + rgba(147, 197, 253, 0.3) 30deg, + rgba(59, 130, 246, 0.6) 60deg, + rgba(139, 92, 246, 0.8) 90deg, + rgba(59, 130, 246, 0.6) 120deg, + rgba(147, 197, 253, 0.3) 150deg, + transparent 180deg, + transparent 360deg + ); + -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + padding: 3px; + animation: neural-rotate 3s linear infinite; +} + +@keyframes neural-rotate { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.neural-card-active::after { + content: ''; + position: absolute; + inset: -3px; + border-radius: inherit; + background: conic-gradient( + from 180deg, + transparent 0deg, + rgba(59, 130, 246, 0.4) 45deg, + rgba(147, 197, 253, 0.7) 90deg, + rgba(255, 255, 255, 0.9) 110deg, + rgba(147, 197, 253, 0.7) 130deg, + rgba(59, 130, 246, 0.4) 180deg, + transparent 360deg + ); + -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + padding: 3px; + animation: neural-rotate-reverse 4s linear infinite; + opacity: 0.7; +} + +@keyframes neural-rotate-reverse { + from { + transform: rotate(360deg); + } + to { + transform: rotate(0deg); + } +} + +.neural-card-active .card-inner-glow { + position: absolute; + inset: 0; + border-radius: inherit; + background: radial-gradient( + circle at var(--mouse-x, 50%) var(--mouse-y, 50%), + rgba(147, 197, 253, 0.2) 0%, + rgba(59, 130, 246, 0.1) 30%, + transparent 60% + ); + pointer-events: none; + animation: neural-flicker 2s ease-in-out infinite; +} + +@keyframes neural-flicker { + 0%, 100% { + opacity: 0.5; + transform: scale(1); + } + 50% { + opacity: 1; + transform: scale(1.02); + } +} diff --git a/src/views/About.vue b/src/views/About.vue index 5fc70b4..e6e03e6 100644 --- a/src/views/About.vue +++ b/src/views/About.vue @@ -54,20 +54,19 @@ const advantages = [