feat: 20250630

This commit is contained in:
mac·ufutx 2025-06-30 09:26:33 +08:00
parent 83aa8152b2
commit 76c246deec
37 changed files with 724 additions and 83 deletions

View File

@ -2,17 +2,16 @@
<html lang="en">
<head>
<meta charset="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/vite.svg"/>
<link rel="icon" type="image/svg+xml" href="/logo.svg"/>
<!-- <link href="https://cdn.jsdelivr.net/npm/element-plus@2.4.10/dist/index.min.css" rel="stylesheet">-->
<!-- <link href="https://cdn.jsdelivr.net/npm/element-plus@2.4.10/dist/index.min.css" rel="stylesheet">-->
<link href="https://cdn.jsdelivr.net/npm/element-plus@2.4.10/dist/index.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Vite + Vue + TS</title>
<title>友福同享官网</title>
</head>
<body>
<div id="app"></div>
<!--<script src="https://cdn.jsdelivr.net/npm/element-plus@2.4.10/dist/index.full.min.js"></script>-->
<script src="https://cdn.jsdelivr.net/npm/element-plus@2.4.10/dist/index.full.min.js"></script>
<!--<script src="https://cdn.jsdelivr.net/npm/element-plus@2.4.10/dist/index.full.min.js"></script>-->
<script type="module" src="/src/main.ts"></script>
</body>

View File

@ -23,6 +23,7 @@
"dependencies": {
"@vueuse/core": "^13.3.0",
"axios": "^1.9.0",
"echarts": "^5.6.0",
"element-plus": "^2.10.1",
"pinia": "^2.1.7",
"postcss-px-to-viewport": "^1.1.1",

3
public/logo.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.0661 20.4923C33.3664 19.8926 36.444 16.9381 38.6452 10.4776C38.9142 9.69271 40.0963 4.77392 36.4277 4.13391C33.8392 3.67906 30.6312 4.28284 26.3837 7.50702C23.5303 9.67258 20.6973 14.0077 21.8142 15.4487C21.951 15.6248 22.1903 15.2038 22.5321 14.6025C22.7606 14.2004 23.0349 13.7178 23.355 13.2792C24.688 11.4437 25.7723 10.7715 25.7723 10.7715C21.9324 15.5373 22.0588 17.7511 22.0588 17.7511C22.1158 18.7333 22.5439 18.532 23.7708 16.447C26.1473 12.4137 28.3974 11.5322 28.3974 11.5322C24.7206 15.4608 23.6811 17.9363 23.6811 17.9363C22.9963 19.5625 22.7395 21.0518 23.6322 20.4158C23.8295 20.2759 24.2408 19.7603 24.7888 19.0733C26.7322 16.6368 30.3955 12.0442 32.3351 14.4022C33.2971 15.5735 31.9315 18.2986 31.9315 18.2986C30.6149 21.1645 32.0661 20.4923 32.0661 20.4923ZM31.0099 21.4704C31.98 21.7683 34.4258 23.5394 36.5984 27.8463C36.8634 28.3696 38.176 31.6985 35.6731 32.4995C33.9081 33.067 31.6009 32.9503 28.3114 31.1027C26.102 29.8589 23.6929 27.0977 24.3329 25.9827C24.4114 25.8446 24.6228 26.1191 24.9235 26.5097C25.1225 26.768 25.3605 27.0772 25.6251 27.3512C26.7379 28.5065 27.5613 28.8768 27.5613 28.8768C24.4022 25.9102 24.2758 24.3484 24.2758 24.3484C24.2188 23.6561 24.5367 23.7567 25.6006 25.0971C27.6632 27.6934 29.3223 28.0919 29.3223 28.0919C26.3629 25.6969 25.3927 24.0627 25.3927 24.0627C24.7528 22.992 24.4266 21.9696 25.1155 22.3318C25.2686 22.4109 25.6094 22.7344 26.0632 23.165C27.6646 24.6848 30.6731 27.5397 31.8007 25.7049C32.3591 24.7952 31.1321 23.0161 31.1321 23.0161C29.9296 21.1404 31.0099 21.4704 31.0099 21.4704ZM2.58208 16.8127C7.07007 21.9891 11.0404 23.5952 12.4752 23.6716C12.4752 23.6716 14.0772 23.7562 11.766 21.5906C11.766 21.5906 9.46285 19.57 9.91532 18.1289C10.8256 15.2218 15.9704 18.1354 18.6926 19.677C19.4568 20.1097 20.03 20.4344 20.265 20.4917C21.3371 20.7534 20.534 19.4653 19.2826 18.2094C19.2826 18.2094 17.379 16.2975 12.4834 14.0112C12.4834 14.0112 14.9006 13.9991 18.6345 16.861C20.5667 18.3383 21.0354 18.3705 20.7175 17.4366C20.7175 17.4366 20.0001 15.3355 14.6316 12.3327C14.6316 12.3327 15.8912 12.5581 17.8233 13.7656C18.2833 14.0529 18.718 14.3972 19.0809 14.6846C19.6282 15.1179 20.0122 15.4221 20.0734 15.2067C20.5667 13.4637 16.2988 10.4851 12.8299 9.53112C7.66929 8.11023 4.46124 8.73414 2.2356 10.1108C-0.923528 12.0589 2.03585 16.1848 2.58208 16.8127ZM13.6006 24.2879C12.7853 24.944 11.1303 27.5845 10.7268 32.5637C10.6779 33.1674 10.7227 36.8746 13.4457 36.6855C15.3656 36.5526 17.5383 35.5584 19.98 32.5234C21.6186 30.4826 22.8497 26.9002 21.798 26.075C21.6685 25.9737 21.5741 26.315 21.4394 26.8025C21.3494 27.1281 21.2413 27.5189 21.0928 27.8864C20.4732 29.424 19.8251 30.0962 19.8251 30.0962C21.6961 26.0308 21.2069 24.4811 21.2069 24.4811C20.9909 23.7928 20.7218 24.0101 20.2245 25.7087C19.2585 28.9933 17.8195 30.0157 17.8195 30.0157C19.7232 26.5782 20.0207 24.634 20.0207 24.634C20.2164 23.358 20.1308 22.2511 19.609 22.8629C19.4946 22.9971 19.2963 23.4337 19.032 24.0158C18.091 26.088 16.3132 30.0029 14.5055 28.6673C13.6087 28.0031 14.0938 25.8255 14.0938 25.8255C14.5137 23.5553 13.6006 24.2879 13.6006 24.2879Z" fill="#313FA8"/>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -124,8 +124,11 @@ const openReport = (URL: string) => {
transform-origin: bottom; //
&:hover {
padding: 12px;
padding: 14px;
transform: scale(1.3);
.qr-image {
transform: scale(1.3);
}
}
.qr-image {
@ -134,9 +137,9 @@ const openReport = (URL: string) => {
object-fit: cover;
// 线
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:hover {
transform: scale(1.3);
}
//&:hover {
//transform: scale(1.3);
//}
}
}

8
src/lib/utils.ts Normal file
View File

@ -0,0 +1,8 @@
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
export type ObjectValues<T> = T[keyof T]

View File

@ -6,6 +6,7 @@ import routes from './router/routes'
import i18n from './locales/i18n' // 导入i18n配置
import './style.css'
import '@/styles/global.less' // 引入全局样式
import '@/styles/tailwindcss.less' // tailwindcss.less
// 修正:明确 meta.title 的类型为 string
// 引入 element-plus 核心库

View File

@ -282,4 +282,39 @@ html, body {
box-shadow: @shadow-hover;
transform: translateY(-2px);
}
}
.btn-glow {
padding: 12px 24px;
border: none;
color: white;
border-radius: 8px;
cursor: pointer;
font-size: 1rem;
position: relative;
overflow: hidden;
transition:
transform 0.4s,
box-shadow 0.4s;
}
.btn-glow:hover {
transform: scale(1.05);
box-shadow: 0 0 20px #9dbbf5;
}
.btn-glow::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
transition: 0.5s;
}
.btn-glow:hover::before {
left: 100%;
}

View File

@ -31,4 +31,5 @@ textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
}

View File

@ -0,0 +1,95 @@
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
:root {
--card: oklch(1 0 0);
--card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.21 0.006 285.885);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375);
--muted-foreground: oklch(0.552 0.016 285.938);
--accent: oklch(0.967 0.001 286.375);
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.92 0.004 286.32);
--input: oklch(0.92 0.004 286.32);
--ring: oklch(0.705 0.015 286.067);
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.141 0.005 285.823);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.141 0.005 285.823);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.21 0.006 285.885);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.396 0.141 25.723);
--destructive-foreground: oklch(0.637 0.237 25.331);
--border: oklch(0.274 0.006 286.033);
--input: oklch(0.274 0.006 286.033);
--ring: oklch(0.442 0.017 285.786);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}
html {
color-scheme: light dark;
}
html.dark {
color-scheme: dark;
}
html.light {
color-scheme: light;
}

View File

@ -4,6 +4,8 @@
<CompanyIntro />
<!-- 友福同享简介-->
<CompanyTimeline />
<!-- // -->
<BranchDistribution />
<!-- 我们重新定义健康未来-->
<RedefineHealth />
<!-- 应用场景-->
@ -27,6 +29,7 @@ import QualificationCarousel from './sections/QualificationCarousel.vue'
import MissionVision from './sections/MissionVision.vue'
import Partners from './sections/Partners.vue'
import CompanyTimeline from '@/views/About/sections/CompanyTimeline.vue'
import BranchDistribution from '@/views/About/sections/BranchDistribution.vue'
</script>
<style scoped lang="less">

View File

@ -2,7 +2,7 @@
<section class="banner">
<div class="banner-bg">
<!-- 替换为实际背景图路径 -->
<img src="https://images.health.ufutx.com/202506/13/f976d275bb04340765102ae4873e41c1.png" alt="Banner背景" />
<img src="https://images.health.ufutx.com/202506/27/ae38015f070eeb51347359577acf1063.png" alt="Banner背景" />
</div>
<!-- <div class="news-panel">-->
<!-- <div-->

View File

@ -0,0 +1,307 @@
<template>
<section class="branch-section">
<h2 class="section-title">子公司布局</h2>
<p class="section-subtitle">覆盖华北华东东北等核心区域持续拓展服务网络</p>
<div class="branch-wrapper">
<!-- 左侧切换区 -->
<div class="branch-left">
<img
class="branch-icon"
src="https://images.health.ufutx.com/202506/27/3b341324addbadb9b6410bf32c0da783.png"
alt="floor"
/>
<h2 class="branch-title">全国正式运营的子公司</h2>
<!-- 带平移滑块的tabs容器 -->
<div class="branch-tabs">
<!-- 平移滑块核心 -->
<div
class="tab-slider"
:style="{
width: sliderWidth,
left: sliderLeft,
transition: `all 0.5s cubic-bezier(0.34, 1.2, 0.64, 1)`
}"
></div>
<!-- 选项卡 -->
<div
v-for="(item, index) in branchList"
:key="index"
ref="tabsRef"
class="branch-tab"
:class="{ active: activeIndex === index }"
@click="activeIndex = index"
@mouseenter="activeIndex = index"
>
{{ item.title }}
</div>
</div>
<div class="branch-details">
<p class="detail-item">公司全称{{ currentBranch.fullName }}</p>
<p
class="detail-item"
@click="gotoMapFn(currentBranch.coord[1], currentBranch.coord[0], currentBranch.fullName)"
>
详细地址{{ currentBranch.address }}
<img class="detail-icon" src="@/assets/icons/address.png" alt="" />
</p>
<p class="detail-item">联系电话{{ currentBranch.phone }}</p>
<p class="detail-item">经营理念{{ currentBranch.mission }}</p>
</div>
</div>
<!-- 右侧地图区 -->
<!-- <div class="branch-right" :style="{ backgroundImage: `url(${mapImage})` }"></div>-->
<!-- 右侧地图引入独立组件 -->
<div class="branch-right">
<BranchMap :branch-list="branchList" :active-index="activeIndex" @click="handleMapClick" />
</div>
</div>
</section>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, nextTick } from 'vue'
import BranchMap from './BranchMap.vue'
import { openExternalLink } from '@/utils/navigation.ts'
// 使ECharts
const branchList = [
{
name: '深圳(总部)',
title: '深圳',
fullName: '友福同享(深圳)智能科技有限公司',
address: '深圳市南山区南山街道南山社区南新路阳光科创中心一期A座3301A',
phone: '0755-86701981',
mission: '集团总部,统筹全国健康服务战略',
coord: [113.91535, 22.51409], //
isHeadquarters: true,
labelPosition: 'bottom'
},
{
name: '天津',
title: '天津',
fullName: '友福同享(天津)智能科技有限公司',
address: '天津市和平区南营门街道卫津路137号和畅园1号楼632天开和平园',
phone: '0755-86701981',
mission: '华北区域运营中心,专注数字健康服务落地',
coord: [117.180038, 39.111704], //
isHeadquarters: false,
labelPosition: 'right'
},
{
name: '南昌',
title: '南昌',
fullName: '友福同享(南昌)智能科技有限公司',
address: '江西省南昌市东湖区八一大道357号财富广场A座28层2802号房',
phone: '0755-86701981',
mission: '华东区域运营中心,推动健康产业创新',
coord: [115.903915, 28.67754], //
isHeadquarters: false,
labelPosition: 'right'
},
{
name: '哈尔滨',
title: '哈尔滨',
fullName: '友福同享(哈尔滨)智能科技有限公司',
address: '哈尔滨市松北区世茂大道78号13号楼火炬欧亚大厦12层1209室',
phone: '0755-86701981',
mission: '东北区域运营中心,助力健康服务下沉',
coord: [126.510806, 45.803214], //
isHeadquarters: false,
labelPosition: 'right'
}
]
const activeIndex = ref(0)
const currentBranch = computed(() => branchList[activeIndex.value])
// const mapImage = 'https://images.health.ufutx.com/202506/27/373a2a49b270dc77cbc9ea62f7925108.png'
// tab
const tabsRef = ref<HTMLElement[]>([])
const sliderWidth = ref('0px')
const sliderLeft = ref('0px')
//
const handleMapClick = (index: number) => {
activeIndex.value = index
}
const gotoMapFn = (latitude: any, longitude: any, detail: any) => {
console.log(latitude, longitude, detail)
openExternalLink(
// `http://maps.googleapis.com/maps/api/staticmap?center=${latitude},${longitude}&zoom=14&size=400x300&sensor=false`
// `http://maps.google.com/map/api/staticmap?center=${latitude},${longitude}&size=640*640&sensor=true`
`https://uri.amap.com/marker?position=${longitude},${latitude}&name=${detail}`,
'_blank'
// `http://api.map.baidu.com/marker?location=${latitude},${longitude}&name==${detail}&output=html`
)
}
//
const calculateSliderPosition = () => {
const activeTab = tabsRef.value[activeIndex.value]
if (activeTab) {
// tab
sliderWidth.value = `${activeTab.offsetWidth}px`
sliderLeft.value = `${activeTab.offsetLeft}px`
}
}
//
onMounted(() => {
nextTick(calculateSliderPosition)
})
// activeIndex
activeIndex.value &&
activeIndex.value.toString() &&
activeIndex.value.toString().length &&
activeIndex.value
.toString()
.split('')
.forEach(() => {
nextTick(calculateSliderPosition)
})
//
watch(activeIndex, () => {
nextTick(calculateSliderPosition)
})
</script>
<style scoped lang="less">
.branch-section {
background-color: #fff;
padding: 50px 192px 50px;
border-top: 50px solid #f6f8fe;
}
.section-title {
font-size: @font-size-xxl;
font-weight: bold;
color: @text-color;
margin-bottom: 10px;
}
.section-subtitle {
font-size: 20px;
color: @text-color-secondary;
margin-bottom: 40px;
}
.branch-wrapper {
display: flex;
align-items: flex-start;
justify-content: space-between;
.mt(50px);
}
/* 左侧区域 */
.branch-left {
.mt(110px);
padding: 16px 16px 16px 0;
text-align: left;
width: 496px;
.branch-icon {
width: 56px;
height: 52px;
margin-bottom: 20px;
}
}
.branch-title {
font-size: 32px;
font-weight: 600;
color: @text-color;
margin-bottom: 24px;
}
/* Tabs容器关键修改 */
.branch-tabs {
display: flex;
gap: 10px;
margin-bottom: 20px;
background: #f6f8fe;
padding: 6px;
width: 463px;
border-radius: 100px;
position: relative; /* 作为滑块的定位容器 */
}
/* 平移滑块(核心动画元素) */
.tab-slider {
position: absolute;
top: 6px; /* 与tabs容器padding一致 */
bottom: 6px;
border-radius: 100px;
color: #fff;
background-color: #165dff; /* 与active状态一致 */
z-index: 1; /* 位于tab文字下方 */
transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1); /* 平移动画 */
}
/* Tab按钮去除原有active样式由滑块替代 */
.branch-tab {
padding: 12px 30px;
border-radius: 100px;
color: @text-color-secondary;
cursor: pointer;
font-size: 20px;
position: relative;
z-index: 2; /* 确保文字在滑块上方 */
transition: color 0.3s ease; /* 文字颜色过渡 */
/* 被选中时文字变白(滑块在下方衬托) */
&.active,
.branch-tabs:hover &:hover {
color: #fff;
}
}
.branch-details {
.detail-item {
font-size: 20px;
color: @text-color-secondary;
line-height: 40px;
margin-bottom: 8px;
}
.detail-icon {
width: 20px;
height: 18px;
margin-bottom: 2px;
}
}
/* 右侧地图区 */
.branch-right {
width: 870px;
height: 850px;
//width: 1200px;
//height: 1200px;
flex-shrink: 0;
overflow: hidden; /* 裁剪超出部分 */
margin-left: 60px;
position: relative; /* 作为地图的定位容器 */
z-index: 10; /* 父容器层级,控制整体显示优先级 */
}
/* 响应式适配 */
@media (max-width: 1200px) {
.branch-section {
padding: 60px 40px;
}
.branch-wrapper {
flex-direction: column;
align-items: center;
}
.branch-left {
margin-bottom: 40px;
}
.branch-right {
margin: 0;
width: 100%;
}
}
</style>

View File

@ -0,0 +1,209 @@
<template>
<div ref="chartRef" class="branch-map"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, watch, nextTick, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import chinaJson from '@/assets/map/china.json'
echarts.registerMap('china', chinaJson)
const props = defineProps<{
branchList: Array<{
name: string
coord: [number, number]
fullName: string
address: string
phone: string
mission: string
labelPosition?: string
isHeadquarters?: boolean
}>
activeIndex: number
}>()
const emit = defineEmits<{
(e: 'click', index: number): void
}>()
const chartRef = ref<HTMLDivElement | null>(null)
let myChart: echarts.ECharts | null = null
//
const getHeadquartersIndex = () => {
const index = props.branchList.findIndex(item => item.isHeadquarters)
return index !== -1 ? index : 0
}
//
const initChart = () => {
if (!chartRef.value) return
myChart = echarts.init(chartRef.value)
const headquartersIndex = getHeadquartersIndex()
const option = {
backgroundColor: '#fff',
geo: {
map: 'china',
roam: false,
zoom: 1.2, // 1.0 1.5
center: [114, 34],
label: { show: false },
itemStyle: {
borderColor: '#d0d4e0',
borderWidth: 1,
areaColor: '#f5f7fc'
},
emphasis: {
itemStyle: {
areaColor: '#aec8fb' //
}
}
},
series: [
// 1. 线
{
name: '连线',
type: 'lines',
coordinateSystem: 'geo',
zlevel: 1,
effect: {
show: true,
period: 8,
trailWidth: 1,
trailLength: 0.6,
trailOpacity: 0.5,
trailColor: 'rgba(22, 93, 255, 0.6)'
},
lineStyle: {
color: 'rgba(22, 93, 255, 0.4)',
width: 0.5,
curveness: 0.2,
opacity: 0.5
},
data: props.branchList
.filter((_, i) => i !== headquartersIndex)
.map(item => ({
coords: [props.branchList[headquartersIndex].coord, item.coord]
}))
},
// 2. emphasis
{
name: '子公司',
type: 'scatter',
coordinateSystem: 'geo',
zlevel: 2,
data: props.branchList.map((item, index) => ({
...item,
value: item.coord,
itemStyle: {
color:
index === headquartersIndex
? 'rgb(22,101,252)'
: index === props.activeIndex
? 'rgba(22, 93, 255, 0.9)'
: 'rgba(105, 177, 255, 0.8)',
borderColor: '#fff',
borderWidth: 1.5,
shadowBlur: 6,
shadowColor: 'rgba(22, 93, 255, 0.3)'
},
symbolSize: index === headquartersIndex ? 14 : index === props.activeIndex ? 12 : 10
})),
label: {
show: true,
position: (p: any) => p.data.labelPosition || 'right',
formatter: '{b}',
color: '#313FA8',
fontSize: 15,
fontWeight: '500',
offset: [20, -4]
}
},
// 3.
{
name: '光环',
type: 'effectScatter',
coordinateSystem: 'geo',
zlevel: 0,
data: props.branchList.map((item, index) => ({
...item,
value: item.coord,
itemStyle: {
color:
index === headquartersIndex
? 'rgb(22,101,252)' //
: index === props.activeIndex
? 'rgba(22, 93, 255, 0.6)' //
: 'rgba(177,191,211,0.4)' //
},
symbolSize: index === headquartersIndex ? 20 : index === props.activeIndex ? 18 : 16,
rippleEffect: {
brushType: 'stroke',
scale: 1.0,
period: 6
}
})),
showEffectOn: 'render'
}
]
}
myChart.setOption(option)
myChart.on('click', (params: any) => {
if (params.componentType === 'series' && params.seriesType === 'scatter') {
emit('click', params.dataIndex)
}
})
}
//
const updateChart = () => {
if (!myChart) return
const headquartersIndex = getHeadquartersIndex()
const option = myChart.getOption() as echarts.EChartsOption
if (option.series && option.series[1]) {
option.series[1].data = props.branchList.map((item, index) => ({
...item,
value: item.coord,
itemStyle: {
color:
index === headquartersIndex
? 'rgba(22, 93, 255, 0.9)'
: index === props.activeIndex
? 'rgba(22, 93, 255, 0.9)'
: 'rgba(105, 177, 255, 0.8)',
borderColor: '#fff',
borderWidth: 1.5,
shadowBlur: 6,
shadowColor: 'rgba(22, 93, 255, 0.3)'
},
symbolSize: index === headquartersIndex ? 14 : index === props.activeIndex ? 12 : 10
}))
}
myChart.setOption(option)
}
//
onMounted(() => nextTick(initChart))
onUnmounted(() => myChart?.dispose())
watch(() => [props.activeIndex, props.branchList], updateChart, { deep: true })
</script>
<style scoped lang="less">
.branch-map {
width: 120%; /* 填满父容器宽度 */
height: 100%; /* 填满父容器高度 */
z-index: 1; /* 降低层级,避免遮挡其他元素 */
position: absolute;
top: -82px;
//background: none;
//right: 0px;
//border: 1px solid #e6f1ff;
}
</style>

View File

@ -87,19 +87,19 @@ const timelineData = [
}
}
.timeline-section {
padding: 50px 192px;
padding: 50px 0px;
margin: 0 192px;
background-image: url('https://images.health.ufutx.com/202506/20/26691a92ed7a9b632cd635c08e35fb17.png');
background-size: cover;
background-repeat: no-repeat;
background-position: top;
height: 955px; //
background-size: contain;
//
.timeline-container {
position: relative;
width: 100%;
height: 955px; //
height: 100%;
margin: 0 auto;
overflow: hidden;
//
.timeline-stage {
position: absolute;
@ -132,7 +132,8 @@ const timelineData = [
color: #666;
line-height: 34px;
position: relative;
padding-left: 12px;
text-align: left;
//background: red;
&::before {
// ·
//content: '·';
@ -150,10 +151,15 @@ const timelineData = [
left: 0;
top: 0;
justify-items: end;
.stage-content {
li {
}
}
&:after {
content: '';
position: absolute;
top: 0;
top: 14px;
right: -16px;
width: 2px;
height: 336px;
@ -164,12 +170,13 @@ const timelineData = [
.stage-1 {
/* 中下2019-2022 */
left: 400px;
bottom: 0;
top: 477px;
//background: linear-gradient(180deg, #2458c1 0%, rgba(36, 88, 193, 0) 100%);
justify-items: start;
&:after {
content: '';
position: absolute;
top: 0;
top: 14px;
left: -16px;
width: 2px;
height: 336px;
@ -185,7 +192,7 @@ const timelineData = [
&:after {
content: '';
position: absolute;
top: 0;
top: 14px;
right: -16px;
width: 2px;
height: 336px;
@ -201,7 +208,7 @@ const timelineData = [
&:after {
content: '';
position: absolute;
top: 0;
top: 14px;
left: -16px;
width: 2px;
height: 336px;

View File

@ -1,6 +1,6 @@
<template>
<div class="app-page">
<Banner />
<BannerCarousel />
<div class="section-divider">全方位健康生活方式的引领者</div>
<FeatureNav />
<!-- // -->
@ -17,7 +17,7 @@
</template>
<script setup lang="ts">
import Banner from './sections/Banner.vue'
import BannerCarousel from './sections/BannerCarousel.vue'
import HealthDevice from './sections/HealthDevice.vue'
import SpeechModule from './sections/SpeechModule.vue'
import ApplicationScenes from './sections/ApplicationScenes.vue'

View File

@ -1,6 +1,6 @@
<template>
<div class="dating-page">
<Banner />
<BannerCarousel />
<PainPoints />
<AiTags />
<SuccessStories />
@ -8,7 +8,7 @@
</template>
<script setup lang="ts">
import Banner from './sections/Banner.vue'
import BannerCarousel from './sections/BannerCarousel.vue'
import PainPoints from './sections/PainPoints.vue'
import AiTags from './sections/AiTags.vue'
import SuccessStories from './sections/SuccessStories.vue'

View File

@ -4,7 +4,7 @@
<h2 class="tags-title">友福AI婚恋-专属单身标签</h2>
<p class="tags-subtitle">Right Beside You, They Love Each Other!</p>
<!-- <el-button type="primary" class="download-btn">立即下载</el-button>-->
<div class="download-btn">立即下载</div>
<div class="btn-glow download-btn">立即下载</div>
<div class="tags-icon">
<img src="https://images.health.ufutx.com/202506/18/3b16ca61dc63eb22c102aed934301c0a.png" alt="" />
</div>

View File

@ -2,7 +2,7 @@
<section class="success-stories">
<h2 class="section-title">就在你身边他们相爱啦</h2>
<p class="section-subtitle">Right Beside You, They Love Each Other!</p>
<div class="download-btn">立即下载</div>
<div class="download-btn btn-glow">立即下载</div>
<div class="stories-icon">
<img src="https://images.health.ufutx.com/202506/18/1a837037ce7fb8502a211a01e19fbf55.png" alt="" />
</div>

View File

@ -1,7 +1,7 @@
<template>
<div class="ecosystem-page">
<!-- // -->
<Banner />
<BannerCarousel />
<!-- // -->
<CoreAdvantages />
<!-- // -->
@ -24,7 +24,7 @@
</template>
<script setup lang="ts">
import Banner from './sections/Banner.vue'
import BannerCarousel from './sections/BannerCarousel.vue'
import CoreAdvantages from './sections/CoreAdvantages.vue'
import RegionCooperation from './sections/RegionCooperation.vue'
import HealthManagement from './sections/HealthManagement.vue'

View File

@ -226,11 +226,11 @@ const currentIdx = ref(0)
}
@media (max-width: 1200px) {
padding: 60px 40px;
//padding: 60px 40px;
.nav-bar {
gap: 30px;
}
//.nav-bar {
// gap: 30px;
//}
.content {
flex-direction: column;

View File

@ -16,27 +16,27 @@
<script setup lang="ts">
const advantages = [
{
icon: 'https://images.health.ufutx.com/202506/19/cde9fb5a9b0174733c1bd9ae19bb5a51.png',
icon: 'https://images.health.ufutx.com/202506/27/adc7fbfc2e08c14735876bcaeafe7cfb.png',
title: 'AI+生命科学创新系统'
},
{
icon: 'https://images.health.ufutx.com/202506/19/cde9fb5a9b0174733c1bd9ae19bb5a51.png',
icon: 'https://images.health.ufutx.com/202506/27/7ef824b51769e4e4bc15f44ee56fd394.png',
title: '市场验证与成功案例'
},
{
icon: 'https://images.health.ufutx.com/202506/19/cde9fb5a9b0174733c1bd9ae19bb5a51.png',
icon: 'https://images.health.ufutx.com/202506/27/be87f139c2c1a98f259db1fb3c82de6b.png',
title: '独有技术护城河'
},
{
icon: 'https://images.health.ufutx.com/202506/19/cde9fb5a9b0174733c1bd9ae19bb5a51.png',
icon: 'https://images.health.ufutx.com/202506/27/b53b04f8f7d32a786969997bedc70f24.png',
title: '完整的服务生态闭环'
},
{
icon: 'https://images.health.ufutx.com/202506/19/cde9fb5a9b0174733c1bd9ae19bb5a51.png',
icon: 'https://images.health.ufutx.com/202506/27/429c402e3432d018e4c341b1956eda7e.png',
title: '低风险的合作保障'
},
{
icon: 'https://images.health.ufutx.com/202506/19/cde9fb5a9b0174733c1bd9ae19bb5a51.png',
icon: 'https://images.health.ufutx.com/202506/27/ebfdb3a4daf3c832fa238f626514c80f.png',
title: '百亿赛道先行者'
}
]

View File

@ -23,6 +23,7 @@
:key="index"
:src="getSectorImage(index)"
class="sector-img"
:alt="item.title"
:class="`sector-img--${index}`"
@mouseenter="highlightSector(index)"
@mouseleave="resetHighlight"

View File

@ -1,7 +1,7 @@
<template>
<div class="home-page">
<!-- Banner 模块-->
<Banner />
<BannerCarousel />
<!-- 核心价值模块-->
<CoreValue />
<!-- 应用场景模块-->
@ -16,7 +16,7 @@
</template>
<script setup lang="ts">
import Banner from './sections/Banner.vue'
import BannerCarousel from './sections/BannerCarousel.vue'
import CoreValue from './sections/CoreValue.vue'
import UseCases from './sections/UseCases.vue'
import GlobalService from './sections/GlobalService.vue'

View File

@ -1,7 +1,7 @@
<template>
<div class="home-page">
<!-- Banner 模块-->
<Banner />
<BannerCarousel />
<!-- 七维度模块-->
<SevenDimensions />
<!-- 应用场景模块-->
@ -18,7 +18,7 @@
</template>
<script setup lang="ts">
import Banner from './sections/Banner.vue'
import BannerCarousel from './sections/BannerCarousel.vue'
import SevenDimensions from './sections/SevenDimensions.vue'
import UseCases from './sections/UseCases.vue'
import OneStopSolution from '@/views/Network/sections/OneStopSolution.vue'

View File

@ -34,40 +34,6 @@ const openReport = () => {
</script>
<style scoped lang="less">
.btn-glow {
padding: 12px 24px;
border: none;
color: white;
border-radius: 8px;
cursor: pointer;
font-size: 1rem;
position: relative;
overflow: hidden;
transition:
transform 0.4s,
box-shadow 0.4s;
}
.btn-glow:hover {
transform: scale(1.05);
box-shadow: 0 0 20px #9dbbf5;
}
.btn-glow::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
transition: 0.5s;
}
.btn-glow:hover::before {
left: 100%;
}
.app-promotion {
text-align: center;
}

View File

@ -2,7 +2,7 @@
<!-- 整体布局导航 + Banner + 内容 + 页脚 -->
<div class="page-container">
<!-- 已有Banner组件保持设计中的顶部视觉 -->
<Banner />
<BannerCarousel />
<!-- 核心内容区 -->
<div class="news-content">
@ -52,7 +52,7 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
//
import Banner from '@/views/News/sections/Banner.vue'
import BannerCarousel from '@/views/News/sections/BannerCarousel.vue'
//
const dynamicNews = [
@ -154,7 +154,7 @@ const resetPage = () => {
left: 0;
bottom: 0;
width: 100vw;
height: 0.3px;
height: 0.5px;
background-color: #b5b5b5;
z-index: var(--el-index-normal);
}

View File

@ -21,6 +21,7 @@
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"resolveJsonModule": true, // JSON
"esModuleInterop": true,
// CommonJS
/* Linting */