feat: 20260901

This commit is contained in:
mac·ufutx 2026-09-01 12:53:38 +08:00
parent 91bb3cd5d8
commit 52518efbe1
9 changed files with 1335 additions and 262 deletions

View File

@ -0,0 +1,81 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"DirectiveBinding": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"PropType": true,
"Ref": true,
"Slot": true,
"Slots": true,
"VNode": true,
"WritableComputedRef": true,
"computed": true,
"createApp": true,
"customRef": true,
"defineAsyncComponent": true,
"defineComponent": true,
"effectScope": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"inject": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onUnmounted": true,
"onUpdated": true,
"onWatcherCleanup": true,
"provide": true,
"reactive": true,
"readonly": true,
"ref": true,
"resolveComponent": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"toRaw": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"unref": true,
"useAttrs": true,
"useCssModule": true,
"useCssVars": true,
"useId": true,
"useLink": true,
"useModel": true,
"useRoute": true,
"useRouter": true,
"useSlots": true,
"useTemplateRef": true,
"watch": true,
"watchEffect": true,
"watchPostEffect": true,
"watchSyncEffect": true
}
}

2
components.d.ts vendored
View File

@ -18,6 +18,8 @@ declare module 'vue' {
ElInput: typeof import('element-plus/es')['ElInput']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
Footer: typeof import('./src/components/Footer.vue')['default']

BIN
dist.zip Normal file

Binary file not shown.

76
src/auto-imports.d.ts vendored Normal file
View File

@ -0,0 +1,76 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}

View File

@ -76,7 +76,7 @@ const openReport = (URL: string) => {
<style scoped lang="less">
.footer {
width: 100%;
width: 100vw;
background-color: #0b101b;
color: #fff;
//padding: @space-xl @container-padding;

View File

@ -45,6 +45,7 @@ const navItems = [
{ path: '/dating', label: 'AI婚恋' },
{ path: '/app', label: '友福同享APP' },
{ path: '/ecosystem', label: '生态合作' },
{ path: '/recruit', label: '人才招聘' },
{ path: '/about', label: '关于我们' }
]
const changeLanguage = () => {

View File

@ -77,6 +77,15 @@ const routes: RouteRecordRaw[] = [
},
component: () => import('@/views/Ecosystem/Ecosystem.vue')
},
{
path: 'recruit',
name: 'Recruit',
meta: {
title: '人才招聘',
keepAlive: false
},
component: () => import('@/views/Recruit/Recruit.vue')
},
{
path: 'about',
name: 'About',

View File

@ -1,29 +1,25 @@
<template>
<section class="branch-section">
<h2 class="section-title">子公司布局</h2>
<p class="section-subtitle">覆盖华北华东东北等核心区域持续拓展服务网络</p>
<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容器 -->
<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)`
transition: `all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1)`
}"
></div>
<!-- 选项卡 -->
<div
v-for="(item, index) in branchList"
:key="index"
@ -51,9 +47,6 @@
</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>
@ -62,10 +55,10 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, nextTick } from 'vue'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import BranchMap from './BranchMap.vue'
import { gotoMapFn } from '@/utils/tools.ts'
// 使ECharts
const branchList = [
{
name: '深圳(总部)',
@ -74,21 +67,10 @@ const branchList = [
address: '深圳市南山区南山街道南山社区南新路阳光科创中心一期A座3301A',
phone: '0755-86701981',
mission: '集团总部,统筹全国健康服务战略',
coord: [113.91535, 22.51409], //
coord: [113.9154, 22.5429],
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: '南昌',
@ -96,7 +78,18 @@ const branchList = [
address: '江西省南昌市东湖区八一大道357号财富广场A座28层2802号房',
phone: '0755-86701981',
mission: '华东区域运营中心,推动健康产业创新',
coord: [115.903915, 28.67754], //
coord: [115.9081, 28.6811],
isHeadquarters: false,
labelPosition: 'right'
},
{
name: '襄城县',
title: '襄城',
fullName: '友福同享(襄城县)智能科技有限公司',
address: '河南省许昌市襄城县茨沟街道曙光路中段',
phone: '0755-86701981',
mission: '华中区域运营中心,助力县域健康服务普及',
coord: [113.5866, 33.8322],
isHeadquarters: false,
labelPosition: 'right'
},
@ -107,58 +100,65 @@ const branchList = [
address: '哈尔滨市松北区世茂大道78号13号楼火炬欧亚大厦12层1209室',
phone: '0755-86701981',
mission: '东北区域运营中心,助力健康服务下沉',
coord: [126.510806, 45.803214], //
coord: [126.5116, 45.8005],
isHeadquarters: false,
labelPosition: 'right'
},
{
name: '惠州',
title: '惠州',
fullName: '友福粤越(惠州)智能科技有限公司',
address: '广东省惠州市惠城区江北街道文昌一路7号华贸大厦2号楼1503室',
phone: '0755-86701981',
mission: '华南区域运营中心,深耕粤港澳大湾区市场',
coord: [114.4186, 23.0807],
isHeadquarters: false,
labelPosition: 'right'
}
// {
// name: '',
// title: '',
// fullName: '',
// address: '1371632',
// phone: '0755-86701981',
// mission: '',
// coord: [117.180038, 39.111704],
// 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 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;
@ -178,178 +178,24 @@ watch(activeIndex, () => {
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; /* 父容器层级,控制整体显示优先级 */
}
</style>
<style scoped lang="less">
.branch-section {
background-color: #fff;
padding: 50px 192px 50px;
border-top: 50px solid #f6f8fe;
//
@media (max-width: 768px) {
padding: 30px 16px; // 16px
border-top-width: 20px; //
}
}
.section-title {
font-size: @font-size-xxl;
font-weight: bold;
color: @text-color;
margin-bottom: 10px;
//
@media (max-width: 768px) {
font-size: 24px; // xxl32px+24px
}
}
.section-subtitle {
font-size: 20px;
color: @text-color-secondary;
margin-bottom: 40px;
// +
@media (max-width: 768px) {
font-size: 14px;
margin-bottom: 20px;
}
}
.branch-wrapper {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-top: 50px;
//
@media (max-width: 768px) {
flex-direction: column; //
align-items: center;
margin-top: 20px; //
}
}
/* 左侧切换区 - 移动端适配 */
/* 左侧容器 - 桌面端固定宽度 */
.branch-left {
margin-top: 110px;
padding: 16px 16px 16px 0;
text-align: left;
width: 496px;
@media (max-width: 768px) {
width: 100%; //
margin-top: 0; //
padding: 0; //
}
max-width: 520px;
.branch-icon {
width: 56px;
height: 52px;
margin-bottom: 20px;
@media (max-width: 768px) {
width: 40px;
height: 38px;
margin-bottom: 12px;
}
}
}
@ -358,136 +204,173 @@ watch(activeIndex, () => {
font-weight: 600;
color: @text-color;
margin-bottom: 24px;
@media (max-width: 768px) {
font-size: 20px;
margin-bottom: 16px;
}
}
/* Tabs容器 - 移动端关键优化(避免超出屏幕) */
/* Tabs 核心样式 - 桌面端正常,移动端滚动 */
.branch-tabs {
display: flex;
gap: 10px;
gap: 6px;
margin-bottom: 20px;
background: #f6f8fe;
padding: 6px;
width: 463px; //
width: 84%;
border-radius: 100px;
position: relative;
/* 移动端横向滚动核心 */
overflow-x: auto;
scrollbar-width: none;
-ms-overflow-style: none;
@media (max-width: 768px) {
width: 100%; //
gap: 5px; // tab
padding: 4px; //
margin-bottom: 16px;
&::-webkit-scrollbar {
display: none;
}
}
/* 平移滑块 - 适配移动端Tabs尺寸 */
.tab-slider {
position: absolute;
top: 6px;
bottom: 6px;
border-radius: 100px;
color: #fff;
background-color: #165dff;
box-shadow: 0 2px 8px rgba(22, 93, 255, 0.3);
z-index: 1;
transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
@media (max-width: 768px) {
top: 4px; // Tabspadding
bottom: 4px;
}
}
/* Tab按钮 - 移动端缩小尺寸,避免换行 */
.branch-tab {
padding: 12px 30px;
padding: 10px 18px;
border-radius: 100px;
color: @text-color-secondary;
cursor: pointer;
font-size: 20px;
font-size: 18px;
position: relative;
z-index: 2;
transition: color 0.3s ease;
@media (max-width: 768px) {
padding: 8px 15px; //
font-size: 14px; //
}
text-align: center;
white-space: nowrap;
flex-shrink: 0; /* 禁止Tab压缩 */
&.active,
.branch-tabs:hover &:hover {
&:hover {
color: #fff;
}
}
/* 详情区 - 移动端缩小字体和行高 */
.branch-details {
.detail-item {
font-size: 20px;
color: @text-color-secondary;
line-height: 40px;
margin-bottom: 8px;
@media (max-width: 768px) {
font-size: 14px;
line-height: 28px; //
margin-bottom: 6px;
}
}
.detail-icon {
width: 20px;
height: 18px;
margin-bottom: 2px;
@media (max-width: 768px) {
width: 16px;
height: 14px;
margin-bottom: 1px;
vertical-align: middle; //
}
}
}
/* 右侧地图区 - 移动端关键适配(高度自适应) */
/* 右侧地图 */
.branch-right {
width: 870px;
height: 850px; //
height: 850px;
flex-shrink: 0;
overflow: hidden;
margin-left: 60px;
margin-left: 30px;
position: relative;
z-index: 10;
}
@media (max-width: 768px) {
width: 100%; //
height: 300px; // min-height: 50vh
margin-left: 0; //
margin-top: 20px; //
/* ============== 移动端适配768px以下 ============== */
@media (max-width: 768px) {
.branch-section {
padding: 30px 16px;
border-top-width: 20px;
}
.section-title {
font-size: 24px;
}
.section-subtitle {
font-size: 14px;
margin-bottom: 20px;
}
/* 移动端垂直布局 */
.branch-wrapper {
flex-direction: column;
align-items: center;
margin-top: 20px;
}
/* 左侧全屏宽度 */
.branch-left {
max-width: 100%;
width: 100%;
margin-top: 0;
padding: 0;
}
.branch-title {
font-size: 20px;
margin-bottom: 16px;
}
/* 移动端Tab样式优化 */
.branch-tabs {
gap: 4px;
padding: 4px;
margin-bottom: 16px;
}
.tab-slider {
top: 4px;
bottom: 4px;
}
.branch-tab {
padding: 8px 12px;
font-size: 14px;
}
/* 详情文字适配 */
.branch-details {
.detail-item {
font-size: 14px;
line-height: 28px;
margin-bottom: 6px;
}
.detail-icon {
width: 16px;
height: 14px;
}
}
/* 地图全屏适配 */
.branch-right {
width: 100%;
height: 300px;
margin-left: 0;
margin-top: 20px;
}
}
/* 平板过渡态768px~1200px- 补充中间尺寸适配 */
/* ============== 平板适配 ============== */
@media (min-width: 769px) and (max-width: 1200px) {
.branch-section {
padding: 40px 30px;
}
.branch-left {
width: 350px;
}
.branch-tabs {
width: 320px;
max-width: 400px;
}
.branch-right {
width: 600px;
height: 600px;
margin-left: 30px;
margin-left: 20px;
}
}
</style>

File diff suppressed because it is too large Load Diff