feat: 20250704
This commit is contained in:
parent
76c246deec
commit
09c3be2a0c
@ -1,5 +1,2 @@
|
|||||||
# .env.development (开发环境)
|
# .env.development (开发环境)
|
||||||
VITE_API_BASE_URL = 'http://localhost:3000/api'
|
VITE_API_BASE_URL = 'http://health.ufutx.net'
|
||||||
|
|
||||||
# .env.production (生产环境)
|
|
||||||
VITE_API_BASE_URL = 'https://your-api-domain.com/api'
|
|
||||||
|
|||||||
2
.env.production
Normal file
2
.env.production
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# .env.production (生产环境「线上」)
|
||||||
|
VITE_API_BASE_URL = 'https://health.ufutx.com'
|
||||||
@ -24,6 +24,11 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
plugins: ['vue', 'prettier', '@typescript-eslint'], // 显式注册所有插件
|
plugins: ['vue', 'prettier', '@typescript-eslint'], // 显式注册所有插件
|
||||||
rules: {
|
rules: {
|
||||||
|
'vue/no-v-html': 'warn', // 从 error 改为 warn(或 'off' 完全关闭)
|
||||||
|
|
||||||
|
// 限制 v-html 使用,仅允许明确标记为安全的内容
|
||||||
|
// 'vue/no-v-html': ['warn', { allow: ['trusted', 'safe'] }],
|
||||||
|
|
||||||
// 允许使用 router-link 和 router-view 组件
|
// 允许使用 router-link 和 router-view 组件
|
||||||
'vue/no-undef-components': [
|
'vue/no-undef-components': [
|
||||||
'error',
|
'error',
|
||||||
@ -31,16 +36,12 @@ module.exports = {
|
|||||||
ignorePatterns: [
|
ignorePatterns: [
|
||||||
'router-link',
|
'router-link',
|
||||||
'router-view',
|
'router-view',
|
||||||
'ElTabs',
|
|
||||||
'ElTabPane',
|
|
||||||
'ElButton',
|
|
||||||
'ElPagination',
|
|
||||||
// 添加其他使用的 Element Plus 组件
|
// 添加其他使用的 Element Plus 组件
|
||||||
'RouterLink',
|
'RouterLink',
|
||||||
'RouterView'
|
'RouterView',
|
||||||
|
'el-.*',
|
||||||
|
'El.*'
|
||||||
]
|
]
|
||||||
// 允许的组件前缀(Element Plus 组件以 El 开头)
|
|
||||||
// allowComponentPrefixes: ['El']
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// 针对非 Vue 文件禁用 Vue 规则
|
// 针对非 Vue 文件禁用 Vue 规则
|
||||||
@ -48,6 +49,11 @@ module.exports = {
|
|||||||
// 'error',
|
// 'error',
|
||||||
// { ignorePatterns: ['^router$', '^store$'] } // 可选:忽略特定组件名称
|
// { ignorePatterns: ['^router$', '^store$'] } // 可选:忽略特定组件名称
|
||||||
// ],
|
// ],
|
||||||
|
// -------------------- 解决 vue/valid-template-root --------------------
|
||||||
|
// 要求模板必须有且只有一个根元素(必填,否则组件报错)
|
||||||
|
'vue/valid-template-root': 'error',
|
||||||
|
|
||||||
|
// -------------------- 可选:关闭组件命名规则(如需) --------------------
|
||||||
'vue/multi-word-component-names': 'off',
|
'vue/multi-word-component-names': 'off',
|
||||||
// 'vue/multi-word-component-names': [
|
// 'vue/multi-word-component-names': [
|
||||||
// 'error',
|
// 'error',
|
||||||
|
|||||||
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@ -7,6 +7,8 @@
|
|||||||
export {}
|
export {}
|
||||||
declare global {
|
declare global {
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
|
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||||
|
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
|
||||||
const computed: typeof import('vue')['computed']
|
const computed: typeof import('vue')['computed']
|
||||||
const createApp: typeof import('vue')['createApp']
|
const createApp: typeof import('vue')['createApp']
|
||||||
const customRef: typeof import('vue')['customRef']
|
const customRef: typeof import('vue')['customRef']
|
||||||
|
|||||||
8
components.d.ts
vendored
8
components.d.ts
vendored
@ -9,14 +9,22 @@ export {}
|
|||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
ElButton: typeof import('element-plus/es')['ElButton']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
|
ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
|
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||||
|
ElImage: typeof import('element-plus/es')['ElImage']
|
||||||
|
ElInput: typeof import('element-plus/es')['ElInput']
|
||||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||||
|
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||||
Footer: typeof import('./src/components/Footer.vue')['default']
|
Footer: typeof import('./src/components/Footer.vue')['default']
|
||||||
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
||||||
|
Marquee: typeof import('./src/components/Marquee.vue')['default']
|
||||||
Navbar: typeof import('./src/components/Navbar.vue')['default']
|
Navbar: typeof import('./src/components/Navbar.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
Test: typeof import('./src/components/Test.vue')['default']
|
Test: typeof import('./src/components/Test.vue')['default']
|
||||||
|
TextGenerateEffect: typeof import('./src/components/TextGenerateEffect.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
package.json
16
package.json
@ -3,6 +3,12 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"sideEffects": [
|
||||||
|
"src/style.css",
|
||||||
|
"src/styles/global.less",
|
||||||
|
"src/styles/tailwindcss.css",
|
||||||
|
"element-plus/dist/index.css"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host --port 9527",
|
"dev": "vite --host --port 9527",
|
||||||
"build": "vue-tsc -b && vite build",
|
"build": "vue-tsc -b && vite build",
|
||||||
@ -21,12 +27,15 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vueuse/core": "^13.3.0",
|
"@vueuse/core": "^13.4.0",
|
||||||
|
"@vueuse/motion": "^3.0.3",
|
||||||
"axios": "^1.9.0",
|
"axios": "^1.9.0",
|
||||||
"echarts": "^5.6.0",
|
"echarts": "^5.6.0",
|
||||||
"element-plus": "^2.10.1",
|
"element-plus": "^2.10.1",
|
||||||
|
"motion-v": "^1.3.1",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"postcss-px-to-viewport": "^1.1.1",
|
"postcss-px-to-viewport": "^1.1.1",
|
||||||
|
"swiper": "^11.2.10",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-i18n": "^9.8.0",
|
"vue-i18n": "^9.8.0",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.5.1"
|
||||||
@ -43,6 +52,8 @@
|
|||||||
"@vue/eslint-config-typescript": "12.0.0",
|
"@vue/eslint-config-typescript": "12.0.0",
|
||||||
"@vue/tsconfig": "^0.7.0",
|
"@vue/tsconfig": "^0.7.0",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
"eslint": "8.57.1",
|
"eslint": "8.57.1",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
@ -55,8 +66,11 @@
|
|||||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"sass": "^1.89.2",
|
"sass": "^1.89.2",
|
||||||
|
"tailwind-merge": "^3.3.1",
|
||||||
|
"tw-animate-css": "^1.3.4",
|
||||||
"typescript": "5.1.6",
|
"typescript": "5.1.6",
|
||||||
"unplugin-auto-import": "^19.3.0",
|
"unplugin-auto-import": "^19.3.0",
|
||||||
|
"unplugin-element-plus": "^0.10.0",
|
||||||
"unplugin-vue-components": "^28.7.0",
|
"unplugin-vue-components": "^28.7.0",
|
||||||
"vite": "^5.4.19",
|
"vite": "^5.4.19",
|
||||||
"vite-plugin-html": "^3.2.2",
|
"vite-plugin-html": "^3.2.2",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -21,10 +21,15 @@
|
|||||||
|
|
||||||
<!-- 底部信息 -->
|
<!-- 底部信息 -->
|
||||||
<div class="footer-bottom">
|
<div class="footer-bottom">
|
||||||
<p>公司地址:深圳市南山区南山街道阳光科创中心B座33楼</p>
|
<p @click="gotoMapFn(branchData.coord[1], branchData.coord[0], branchData.fullName)">
|
||||||
|
公司地址:{{ branchData.address }}
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
版权所有 <span @click="openReport('https://www.ufutx.com')">©友福同享(深圳)智能科技有限公司</span>
|
版权所有
|
||||||
<span @click="openReport('https://beian.miit.gov.cn/')">粤ICP备12008876号</span>
|
<span @click="gotoMapFn(branchData.coord[1], branchData.coord[0], branchData.fullName)"
|
||||||
|
>©友福同享(深圳)智能科技有限公司</span
|
||||||
|
>
|
||||||
|
<span @click="openReport('https://beian.miit.gov.cn/')"> 粤ICP备12008876号</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
@ -33,20 +38,31 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// 二维码数据
|
// 二维码数据
|
||||||
import { openExternalLink } from '@/utils/navigation.ts'
|
import { openExternalLink } from '@/utils/navigation.ts'
|
||||||
|
import { gotoMapFn } from '@/utils/tools.ts'
|
||||||
|
const branchData = ref({
|
||||||
|
name: '深圳(总部)',
|
||||||
|
title: '深圳',
|
||||||
|
fullName: '友福同享(深圳)智能科技有限公司',
|
||||||
|
address: '深圳市南山区南山街道南山社区南新路阳光科创中心一期A座3301A',
|
||||||
|
phone: '0755-86701981',
|
||||||
|
mission: '集团总部,统筹全国健康服务战略',
|
||||||
|
coord: [113.91535, 22.51409], // 修正后
|
||||||
|
isHeadquarters: true,
|
||||||
|
labelPosition: 'bottom'
|
||||||
|
})
|
||||||
const qrItems = [
|
const qrItems = [
|
||||||
{
|
{
|
||||||
src: 'https://images.health.ufutx.com/202506/12/cc651222ac2e5f63185dec1f31d176ae.png',
|
src: 'https://image.fulllinkai.com/202406/28/eb66da5936cf4dc21765f0d6672b88db.png',
|
||||||
alt: '友福同享二维码',
|
alt: '友福同享二维码',
|
||||||
title: '友福同享'
|
title: '友福同享'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: 'https://images.health.ufutx.com/202506/12/cc651222ac2e5f63185dec1f31d176ae.png', // 示例地址,需替换为实际二维码
|
src: 'https://images.health.ufutx.com/202507/02/394fd3572a92341b538351db421444da.png', // 示例地址,需替换为实际二维码
|
||||||
alt: '福恋二维码',
|
alt: '福恋二维码',
|
||||||
title: '福恋'
|
title: '福恋'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
src: 'https://images.health.ufutx.com/202506/12/cc651222ac2e5f63185dec1f31d176ae.png', // 示例地址,需替换为实际二维码
|
src: 'https://image.fulllinkai.com/202406/28/8b042a92a2226ee618282e5a04e140ef.jpeg', // 示例地址,需替换为实际二维码
|
||||||
alt: '友福公众号二维码',
|
alt: '友福公众号二维码',
|
||||||
title: '友福公众号'
|
title: '友福公众号'
|
||||||
}
|
}
|
||||||
@ -60,7 +76,7 @@ const openReport = (URL: string) => {
|
|||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.footer {
|
.footer {
|
||||||
width: 100vw;
|
width: 100%;
|
||||||
background-color: #0b101b;
|
background-color: #0b101b;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
//padding: @space-xl @container-padding;
|
//padding: @space-xl @container-padding;
|
||||||
|
|||||||
113
src/components/Marquee.vue
Normal file
113
src/components/Marquee.vue
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="containerRef" :class="['marquee-container relative overflow-hidden', containerClass]">
|
||||||
|
<div
|
||||||
|
ref="contentRef"
|
||||||
|
class="marquee-content flex gap-[50px] whitespace-nowrap"
|
||||||
|
:style="{
|
||||||
|
'--marquee-gap': '50px',
|
||||||
|
'--initial-offset': initialOffset + 'px' // 传递初始偏移变量
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div ref="originalRef" class="original-content flex gap-[50px]">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
<div class="clone-content flex gap-[50px]">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, watchEffect } from 'vue'
|
||||||
|
|
||||||
|
// 接收初始偏移量props
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
duration: number
|
||||||
|
reverse?: boolean
|
||||||
|
repeatCount?: number | string
|
||||||
|
pauseOnHover?: boolean
|
||||||
|
containerClass?: string
|
||||||
|
initialOffset?: number // 新增:初始偏移量(px,负数向左偏)
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
reverse: false,
|
||||||
|
repeatCount: 3,
|
||||||
|
pauseOnHover: true,
|
||||||
|
initialOffset: 0, // 默认无偏移
|
||||||
|
containerClass: '' // 添加默认值为空字符串
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const containerRef = ref<HTMLDivElement | null>(null)
|
||||||
|
const contentRef = ref<HTMLDivElement | null>(null)
|
||||||
|
const originalRef = ref<HTMLDivElement | null>(null)
|
||||||
|
const originalWidth = ref(0)
|
||||||
|
|
||||||
|
// 计算单份内容宽度
|
||||||
|
const calculateWidth = () => {
|
||||||
|
if (originalRef.value) {
|
||||||
|
originalWidth.value = originalRef.value.offsetWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态生成动画(包含初始偏移)
|
||||||
|
const updateAnimation = () => {
|
||||||
|
if (!contentRef.value || !originalRef.value) return
|
||||||
|
|
||||||
|
// 动画方向
|
||||||
|
const direction = props.reverse ? 'reverse' : ''
|
||||||
|
contentRef.value.style.animation = `marquee ${props.duration}s linear infinite ${direction}`
|
||||||
|
|
||||||
|
// 关键帧:从初始偏移位置开始滚动
|
||||||
|
const style = document.createElement('style')
|
||||||
|
style.id = 'marquee-keyframes'
|
||||||
|
style.textContent = `
|
||||||
|
@keyframes marquee {
|
||||||
|
0% { transform: translateX(var(--initial-offset)); }
|
||||||
|
100% { transform: translateX(calc(var(--initial-offset) - ${originalWidth.value}px)); }
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// 替换旧关键帧
|
||||||
|
const existingStyle = document.head.querySelector('#marquee-keyframes')
|
||||||
|
if (existingStyle) document.head.removeChild(existingStyle)
|
||||||
|
document.head.appendChild(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化与监听
|
||||||
|
onMounted(() => {
|
||||||
|
calculateWidth()
|
||||||
|
updateAnimation()
|
||||||
|
})
|
||||||
|
watchEffect(() => {
|
||||||
|
calculateWidth()
|
||||||
|
updateAnimation()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 悬停暂停逻辑
|
||||||
|
watchEffect(() => {
|
||||||
|
if (containerRef.value && props.pauseOnHover) {
|
||||||
|
containerRef.value.addEventListener('mouseenter', () => {
|
||||||
|
if (contentRef.value) contentRef.value.style.animationPlayState = 'paused'
|
||||||
|
})
|
||||||
|
containerRef.value.addEventListener('mouseleave', () => {
|
||||||
|
if (contentRef.value) contentRef.value.style.animationPlayState = 'running'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.marquee-content {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
.original-content,
|
||||||
|
.clone-content {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -21,13 +21,17 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- 语言切换 -->
|
<!-- 语言切换 -->
|
||||||
<div class="language-switch"><span>English</span> | <span>中文</span> | <span>繁體</span></div>
|
<!-- <div class="language-switch"><span>中文</span></div>-->
|
||||||
|
<div class="language-switch" @click="changeLanguage">
|
||||||
|
<span>English</span> | <span>中文</span> | <span>繁體</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ElNotification } from 'element-plus'
|
||||||
// import { computed } from 'vue'
|
// import { computed } from 'vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -42,7 +46,13 @@ const navItems = [
|
|||||||
{ path: '/ecosystem', label: '生态合作' },
|
{ path: '/ecosystem', label: '生态合作' },
|
||||||
{ path: '/about', label: '关于我们' }
|
{ path: '/about', label: '关于我们' }
|
||||||
]
|
]
|
||||||
|
const changeLanguage = () => {
|
||||||
|
ElNotification({
|
||||||
|
title: '系统提示',
|
||||||
|
message: '翻译文件正在处理中,请稍后重试~',
|
||||||
|
type: 'primary'
|
||||||
|
})
|
||||||
|
}
|
||||||
// 跳转方法
|
// 跳转方法
|
||||||
const handleNavigate = (path: string) => {
|
const handleNavigate = (path: string) => {
|
||||||
console.log(path)
|
console.log(path)
|
||||||
@ -73,6 +83,7 @@ const isActive = (path: string) => {
|
|||||||
z-index: 999;
|
z-index: 999;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-logo {
|
.navbar-logo {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
height: 29px;
|
height: 29px;
|
||||||
@ -80,6 +91,7 @@ const isActive = (path: string) => {
|
|||||||
//top: 0;
|
//top: 0;
|
||||||
//left: 0;
|
//left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导航容器(居中)
|
// 导航容器(居中)
|
||||||
.navbar-container {
|
.navbar-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -121,8 +133,10 @@ const isActive = (path: string) => {
|
|||||||
// 激活态/ hover 态
|
// 激活态/ hover 态
|
||||||
&.active,
|
&.active,
|
||||||
&:hover {
|
&:hover {
|
||||||
|
//&.active {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: @primary-color;
|
color: @primary-color;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
width: 100%; // 下划线展开
|
width: 100%; // 下划线展开
|
||||||
}
|
}
|
||||||
@ -132,7 +146,9 @@ const isActive = (path: string) => {
|
|||||||
|
|
||||||
// 语言切换(可选动画)
|
// 语言切换(可选动画)
|
||||||
.language-switch {
|
.language-switch {
|
||||||
color: #666;
|
width: 150px;
|
||||||
|
color: @text-color;
|
||||||
|
font-size: @font-size-md;
|
||||||
transition: color 0.3s ease;
|
transition: color 0.3s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|||||||
50
src/components/TextGenerateEffect.vue
Normal file
50
src/components/TextGenerateEffect.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="cn('leading-snug tracking-wide', props.class)">
|
||||||
|
<div ref="scope">
|
||||||
|
<span v-for="(word, idx) in wordsArray" :key="word + idx" class="inline-block" :style="spanStyle">
|
||||||
|
{{ word }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, type HTMLAttributes, onMounted, ref } from 'vue'
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
words: string
|
||||||
|
filter?: boolean
|
||||||
|
duration?: number
|
||||||
|
delay?: number
|
||||||
|
class: HTMLAttributes['class']
|
||||||
|
}>(),
|
||||||
|
{ duration: 0.7, delay: 0, filter: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
const scope = ref(null)
|
||||||
|
const wordsArray = computed(() => props.words.split(' '))
|
||||||
|
|
||||||
|
const spanStyle = computed(() => ({
|
||||||
|
opacity: 0,
|
||||||
|
filter: props.filter ? 'blur(10px)' : 'none',
|
||||||
|
transition: `opacity ${props.duration}s, filter ${props.duration}s`
|
||||||
|
}))
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (scope.value) {
|
||||||
|
const spans = (scope.value as HTMLElement).querySelectorAll('span')
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
spans.forEach((span: HTMLElement, index: number) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
span.style.opacity = '1'
|
||||||
|
span.style.filter = props.filter ? 'blur(0px)' : 'none'
|
||||||
|
}, index * 200)
|
||||||
|
})
|
||||||
|
}, props.delay)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
195
src/data/realCases.ts
Normal file
195
src/data/realCases.ts
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
export interface RealCase {
|
||||||
|
username: string
|
||||||
|
case: string
|
||||||
|
avatar: string
|
||||||
|
result: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const realCases: RealCase[] = [
|
||||||
|
{
|
||||||
|
username: '吴子昂',
|
||||||
|
case: '老家信号差,用离线功能下载健康课程,爷爷学八段锦时视频可放慢带字幕。商城买的太极服质量很好,数据等有网自动同步。',
|
||||||
|
avatar: 'https://picsum.photos/id/525/200/200',
|
||||||
|
result: '爷爷坚持3个月后,血压从150/90mmHg降至135/85mmHg,学会独立操作App。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '郑雅琪',
|
||||||
|
case: '孕期用「胎动计数」功能监测,32周时发现胎动异常,App提醒就医。商城买的孕妇枕缓解腰痛,产后用「泌乳曲线」记录。',
|
||||||
|
avatar: 'https://picsum.photos/id/526/200/200',
|
||||||
|
result: '顺产顺利,奶量从300ml/天增至600ml/天,宝宝体重增长达标。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '王大宇',
|
||||||
|
case: '冠心病术后用「心率预警」功能,监测到静息心率连续3天超85次/分钟。商城买的心脏监测手环很准,App建议就医调整用药。',
|
||||||
|
avatar: 'https://picsum.photos/id/527/200/200',
|
||||||
|
result: '及时发现药物副作用,调整后心率稳定在70-75次/分钟,未再发生胸闷。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '刘思涵',
|
||||||
|
case: '用「儿童健康」板块记录孩子发育,AI发现大宝语言发育滞后,推荐亲子阅读和语言游戏。商城买的绘本很适合孩子。',
|
||||||
|
avatar: 'https://picsum.photos/id/528/200/200',
|
||||||
|
result: '3个月后大宝词汇量从50个增至200个,疫苗接种率100%,未再发生过敏反应。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '赵晓鹏',
|
||||||
|
case: '外卖员开启「骑手模式」,App根据接单量提醒补水休息。商城买的防水外卖箱很实用,摔倒时路人通过App联系紧急联系人。',
|
||||||
|
avatar: 'https://picsum.photos/id/529/200/200',
|
||||||
|
result: '夏季未中暑,摔伤后1小时内就医,恢复周期缩短3天,同行adoption率达60%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '孙梦琪',
|
||||||
|
case: '用睡眠分析功能监测,发现夜间觉醒次数多与打鼾相关。商城买的止鼾器很有效,App建议换枕头高度并推送白噪音。',
|
||||||
|
avatar: 'https://picsum.photos/id/530/200/200',
|
||||||
|
result: '入睡时间从60分钟缩至20分钟,深睡眠时间延长1.2小时,睡眠评分从65升至82。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '钱建国',
|
||||||
|
case: '奶奶用「语音问诊」描述腿疼症状,医生判断为关节炎并推荐药膏。商城买的关节贴缓解疼痛,App查询医保报销比例和社保余额。',
|
||||||
|
avatar: 'https://picsum.photos/id/531/200/200',
|
||||||
|
result: '用药1周后疼痛缓解,医保报销计算准确,避免跑社保局3次。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '高雨桐',
|
||||||
|
case: '瑜伽教练用体脂率数据和体态评估功能,为会员定制训练计划。商城买的瑜伽砖质量很好,通过班级群同步课程和饮食方案。',
|
||||||
|
avatar: 'https://picsum.photos/id/532/200/200',
|
||||||
|
result: '会员平均体脂率下降7%,肌肉量增加2.3kg,课程续费率提升40%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '罗子轩',
|
||||||
|
case: '用「家庭药箱」记录药品保质期,孩子误服成人药时,通过急救指南处理后送医。商城买的儿童退烧药很安全。',
|
||||||
|
avatar: 'https://picsum.photos/id/533/200/200',
|
||||||
|
result: '药品过期提醒准确率100%,误服事件处理及时,未造成不良后果。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '谢雅楠',
|
||||||
|
case: '过敏性鼻炎患者用「季节健康」功能,接收花粉预警并学习社区脱敏方法。商城买的防过敏口罩很透气,坚持生理盐水洗鼻。',
|
||||||
|
avatar: 'https://picsum.photos/id/534/200/200',
|
||||||
|
result: '春季过敏症状减轻80%,抗组胺药使用量减少60%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '杨明远',
|
||||||
|
case: '忙碌白领用「轻体检」功能,5分钟完成心率、代谢检测,得分偏低后App推荐并预约体检机构。商城买的体检套餐很划算。',
|
||||||
|
avatar: 'https://picsum.photos/id/535/200/200',
|
||||||
|
result: '及时发现血脂异常,干预后甘油三酯从2.8mmol/L降至1.7mmol/L,节省2小时找机构时间。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '曹晓琳',
|
||||||
|
case: '为父母设置用药闹钟,母亲忘买降压药时,App跳转附近药店配送。商城买的血压计很精准,同步推送关节炎护理知识。',
|
||||||
|
avatar: 'https://picsum.photos/id/536/200/200',
|
||||||
|
result: '用药依从性达100%,血压稳定在130/80mmHg,关节炎发作频率减少50%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '秦宇航',
|
||||||
|
case: '焦虑症患者定期做心理测评,AI推荐正念冥想。商城买的减压魔方很解压,社区匿名分享经验并监测睡眠改善情况。',
|
||||||
|
avatar: 'https://picsum.photos/id/537/200/200',
|
||||||
|
result: '焦虑量表评分从24分降至12分,深睡眠时间延长1小时,停药后未复发。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '朱晓婷',
|
||||||
|
case: '失眠患者用睡眠分析发现夜间觉醒多,通过App推荐的白噪音和泡脚方案调整。商城买的泡脚桶很舒适。',
|
||||||
|
avatar: 'https://picsum.photos/id/538/200/200',
|
||||||
|
result: '睡眠效率从65%提升至88%,入睡潜伏期从60分钟缩至20分钟。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '沈子昂',
|
||||||
|
case: '徒步时遇暴雨迷路,「紧急求助」功能发送定位,用「伤口处理」视频处理队友擦伤。商城买的户外急救包很齐全。',
|
||||||
|
avatar: 'https://picsum.photos/id/539/200/200',
|
||||||
|
result: '2小时内获救,伤口处理规范未感染,同行者均学会基础急救。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '杨紫涵',
|
||||||
|
case: '宝妈用「疫苗提醒」功能记录宝宝接种时间,10个月时AI发现漏种手足口疫苗。商城买的婴儿车很轻便,推送社区医院预约链接。',
|
||||||
|
avatar: 'https://picsum.photos/id/560/200/200',
|
||||||
|
result: '宝宝疫苗接种率100%,未患传染病,辅食接受度从30%提升至80%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '李俊浩',
|
||||||
|
case: '高血压患者绑定电子血压计,AI分析数据发现晨起血压偏高。商城买的降压茶很有效,推荐「睡前1小时禁水」方案。',
|
||||||
|
avatar: 'https://picsum.photos/id/561/200/200',
|
||||||
|
result: '6个月后晨起血压从150/95mmHg降至135/85mmHg,降压药剂量减少1/3。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '张梦琪',
|
||||||
|
case: '瑜伽馆用「班级群」功能同步课程表,AI体态评估帮学员纠正驼背。商城买的瑜伽垫防滑效果好,每周推送针对性训练视频。',
|
||||||
|
avatar: 'https://picsum.photos/id/562/200/200',
|
||||||
|
result: '学员平均体态评分从62分升至85分,课程续费率从50%提高至90%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '王浩宇',
|
||||||
|
case: '户外博主在无人区徒步,「紧急求助」发送卫星定位。商城买的卫星电话很可靠,用离线地图找到水源,「体能监测」提醒及时补充能量。',
|
||||||
|
avatar: 'https://picsum.photos/id/563/200/200',
|
||||||
|
result: '48小时内获救,未出现脱水症状,装备负重减少3kg,徒步时间延长2天。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '陈雨欣',
|
||||||
|
case: '抑郁症患者每周做心理测评,AI推荐正念冥想和「阳光暴露」计划。商城买的抗抑郁书籍很有帮助,社区匿名区分享康复日记。',
|
||||||
|
avatar: 'https://picsum.photos/id/564/200/200',
|
||||||
|
result: '6个月后抑郁量表评分从35分降至12分,户外活动时间从每周2小时增至10小时。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '赵天宇',
|
||||||
|
case: 'IT公司用「团队健康看板」监测员工久坐时长,每小时推送拉伸提醒。商城买的颈椎按摩器员工很喜欢,季度组织「健康挑战赛」。',
|
||||||
|
avatar: 'https://picsum.photos/id/565/200/200',
|
||||||
|
result: '员工腰肌劳损发病率从25%降至8%,平均每日步数从4000步增至8000步。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '林晓燕',
|
||||||
|
case: '更年期女性用睡眠监测发现潮热影响睡眠。商城买的更年期调理保健品很有效,App推荐「大豆异黄酮食谱」和「睡前冷敷」法。',
|
||||||
|
avatar: 'https://picsum.photos/id/566/200/200',
|
||||||
|
result: '潮热次数从每晚5次减至1次,睡眠时间从4小时延长至6.5小时。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '郑博文',
|
||||||
|
case: '脂肪肝患者用饮食库记录每日摄入,AI限制高脂食物。商城买的护肝片性价比高,推荐「快走30分钟」计划,社区分享「肝部按摩」视频。',
|
||||||
|
avatar: 'https://picsum.photos/id/567/200/200',
|
||||||
|
result: '3个月后转氨酶从80U/L降至45U/L,肝脂肪浸润程度从中度转为轻度。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '吴佳琪',
|
||||||
|
case: '护士用「轮班模式」调整睡眠提醒,夜班后推荐「光照疗法」补觉。商城买的遮光眼罩很实用,社区同行分享「护眼贴选购指南」。',
|
||||||
|
avatar: 'https://picsum.photos/id/568/200/200',
|
||||||
|
result: '睡眠效率从55%提升至82%,干眼症症状评分从18分降至6分。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '孙浩宇',
|
||||||
|
case: '为父母绑定智能手表,心率>100次/分钟时同步提醒子女。商城买的智能手环功能齐全,用药闹钟每日8点弹窗+电话提醒。',
|
||||||
|
avatar: 'https://picsum.photos/id/569/200/200',
|
||||||
|
result: '父亲漏服药次数从每月4次降至0次,2次心率异常及时就医,避免严重后果。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '刘思远',
|
||||||
|
case: '考研党用「专注模式」屏蔽娱乐软件,每日6点推送起床提醒。商城买的记忆枕很舒适,护眼功能每40分钟提醒远眺。',
|
||||||
|
avatar: 'https://picsum.photos/id/570/200/200',
|
||||||
|
result: '日均学习时长从6小时增至8小时,视力从4.8恢复至5.0,未出现颈椎疼痛。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '唐雨桐',
|
||||||
|
case: '乳腺癌术后用AI推荐的「肩部活动度训练」,每日记录康复数据。商城买的术后康复内衣很舒适,社区找到同类患者交流经验。',
|
||||||
|
avatar: 'https://picsum.photos/id/571/200/200',
|
||||||
|
result: '3个月后手臂上举角度从60°增至160°,淋巴水肿发生率为0,心理状态评分提升50%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '冯梓轩',
|
||||||
|
case: '餐厅老板用App管理员工健康证,到期前30天提醒。商城买的食品检测试剂很精准,批量导入员工信息后生成「健康档案看板」。',
|
||||||
|
avatar: 'https://picsum.photos/id/572/200/200',
|
||||||
|
result: '健康证过期率从30%降至0,通过食药监检查,员工工伤率减少40%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '黄梦琪',
|
||||||
|
case: '自闭症儿童妈妈用「感统训练游戏」视频教学。商城买的感统训练器材很专业,App记录孩子眼神接触时长,社区家长分享「社交故事」制作方法。',
|
||||||
|
avatar: 'https://picsum.photos/id/573/200/200',
|
||||||
|
result: '6个月后孩子眼神接触时长从5秒/次增至20秒/次,能听懂简单指令。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '周博文',
|
||||||
|
case: '货车司机开启「疲劳驾驶监测」,连续驾驶4小时强制提醒休息。商城买的腰部按摩靠垫很舒适,离线地图提前预警施工路段。',
|
||||||
|
avatar: 'https://picsum.photos/id/574/200/200',
|
||||||
|
result: '未发生交通事故,违章次数减少60%,腰背痛发生率从70%降至20%。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '徐雅婷',
|
||||||
|
case: '茶艺师用「护嗓计划」每日3次盐水漱口。商城买的专业护嗓茶效果好,嗓音测评功能监测声带状态,社区分享「润喉茶」配方。',
|
||||||
|
avatar: 'https://picsum.photos/id/575/200/200',
|
||||||
|
result: '声带小结缩小80%,连续授课4小时嗓音无嘶哑,客户满意度提升35%。'
|
||||||
|
}
|
||||||
|
]
|
||||||
182
src/data/userFeedbacks.ts
Normal file
182
src/data/userFeedbacks.ts
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
export interface UserFeedback {
|
||||||
|
username: string
|
||||||
|
feedback: string
|
||||||
|
avatar: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const userFeedbacks: UserFeedback[] = [
|
||||||
|
{
|
||||||
|
username: '周雨桐',
|
||||||
|
feedback:
|
||||||
|
'产后用了三个月,AI催乳食谱和商城里的吸奶器帮我解决了哺乳难题!社区背奶妈妈的经验超实用,但视频加载偶尔卡顿,希望优化网络适配。',
|
||||||
|
avatar: 'https://picsum.photos/id/510/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '马子昂',
|
||||||
|
feedback:
|
||||||
|
'作为糖友必须夸!血糖仪同步太方便,商城里的无糖食品选择多,社区糖友的杂粮饭配方救了我,但希望加「食物相克」提醒。',
|
||||||
|
avatar: 'https://picsum.photos/id/511/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '徐晓冉',
|
||||||
|
feedback:
|
||||||
|
'帮独居爷爷装的,语音助手太贴心了!说「查血压」就出结果,商城的电子血压计性价比高。守护模式让我上班安心,但希望增加「一键呼叫社区医生」按钮。',
|
||||||
|
avatar: 'https://picsum.photos/id/512/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '郭子轩',
|
||||||
|
feedback:
|
||||||
|
'程序员久坐党狂喜!每小时拉伸提醒救了我的腰,商城里的人体工学椅超棒,但理疗馆推荐偶尔不准。云端同步换手机不丢数据,这点比其他App强太多。',
|
||||||
|
avatar: 'https://picsum.photos/id/513/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '林巧巧',
|
||||||
|
feedback:
|
||||||
|
'孕期全靠它缓解焦虑!胎动计数比医院的胎心监护还方便,商城的防辐射服质量好。但社区广告有点多,希望减少干扰。',
|
||||||
|
avatar: 'https://picsum.photos/id/514/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '董子健',
|
||||||
|
feedback:
|
||||||
|
'健身党实测,同步运动数据后AI调的训练计划比私教科学!商城的蛋白粉价格实惠,但步频提醒有点灵敏,偶尔正常跑步也报警。',
|
||||||
|
avatar: 'https://picsum.photos/id/515/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '田晓梅',
|
||||||
|
feedback:
|
||||||
|
'管理全家健康档案太省心!商城的儿童益生菌效果好,但家庭共享权限不够细,老公想改娃的疫苗记录改不了,必须我操作。',
|
||||||
|
avatar: 'https://picsum.photos/id/516/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '冯建国',
|
||||||
|
feedback:
|
||||||
|
'退休后学健康知识就靠它!真人医生讲的颈椎操比朋友圈靠谱,商城的按摩器爸妈很喜欢。但视频不能倍速,对我们老人有点慢。',
|
||||||
|
avatar: 'https://picsum.photos/id/517/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '肖雅婷',
|
||||||
|
feedback:
|
||||||
|
'AI问诊比药店药师专业!商城的护眼仪缓解了我的干眼症,但夜间模式不够暗,看久了还是累。希望加「常用药提醒」。',
|
||||||
|
avatar: 'https://picsum.photos/id/518/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '梁宇航',
|
||||||
|
feedback:
|
||||||
|
'程序员救星!商城的颈椎按摩仪超好用,但推荐的人体工学椅有点贵,希望加平价替代款。数据云端存换电脑不丢,全部门都被我安利了。',
|
||||||
|
avatar: 'https://picsum.photos/id/519/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '蒋欣怡',
|
||||||
|
feedback:
|
||||||
|
'过敏体质终于有救了!商城的防过敏面膜超赞,但口罩推荐链接太少,每次都要自己搜。社区同过敏原的人分享的食谱超实用。',
|
||||||
|
avatar: 'https://picsum.photos/id/520/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '宋明辉',
|
||||||
|
feedback:
|
||||||
|
'冠心病患者安心了!商城的心脏监测手环很准,但急救指南字体有点小,紧急时看不清。每周心脏报告比病历还全,子女看了也放心。',
|
||||||
|
avatar: 'https://picsum.photos/id/521/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '韩雨菲',
|
||||||
|
feedback:
|
||||||
|
'自由职业者平衡工作神器!商城的时间管理手册帮我提高效率,但时间管理提醒有点吵,希望能调音量。健康周报让我看到进步。',
|
||||||
|
avatar: 'https://picsum.photos/id/522/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '顾子轩',
|
||||||
|
feedback:
|
||||||
|
'异地看病一条龙服务太方便!商城的旅行急救包很实用,但医保报销计算不准,上次多算了200。医生调电子档案不用重复说病史。',
|
||||||
|
avatar: 'https://picsum.photos/id/523/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '潘晓婷',
|
||||||
|
feedback:
|
||||||
|
'教师护嗓神器!商城的润喉糖效果好,但发声练习视频有点短,希望加完整版。社区老师分享的技巧让我讲课省力多了。',
|
||||||
|
avatar: 'https://picsum.photos/id/524/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '杨紫涵',
|
||||||
|
feedback:
|
||||||
|
'带娃神器!商城的婴儿背带解放双手,但疫苗提醒偶尔延迟。社区宝妈的辅食食谱超实用,10个月宝宝终于肯吃蔬菜泥了。',
|
||||||
|
avatar: 'https://picsum.photos/id/540/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '李俊浩',
|
||||||
|
feedback:
|
||||||
|
'高血压患者用了半年,商城的电子血压计超准!但偶尔会漏传数据,得手动刷新。社区病友说的「芹菜汁降压法」试了有用。',
|
||||||
|
avatar: 'https://picsum.photos/id/541/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '张梦琪',
|
||||||
|
feedback: '瑜伽馆老板必装!商城的瑜伽垫质量超好,班级群同步课程表比微信群清楚,但学员打卡数据偶尔延迟。',
|
||||||
|
avatar: 'https://picsum.photos/id/542/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '王浩宇',
|
||||||
|
feedback:
|
||||||
|
'户外博主实测,商城的户外急救包很全!紧急求助功能在无人区也能发定位,但离线地图精度一般,上次走错路绕了2公里。',
|
||||||
|
avatar: 'https://picsum.photos/id/543/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '陈雨欣',
|
||||||
|
feedback: '抑郁症康复中,商城的减压香薰很助眠!心理测评量表很专业,但冥想音频有点少,希望加自然音效。',
|
||||||
|
avatar: 'https://picsum.photos/id/544/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '赵天宇',
|
||||||
|
feedback:
|
||||||
|
'IT公司采购给员工用,商城的颈椎按摩器员工超喜欢!久坐提醒让腰肌劳损发病率降了40%,但团队健康数据看板权限太严。',
|
||||||
|
avatar: 'https://picsum.photos/id/545/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '林晓燕',
|
||||||
|
feedback:
|
||||||
|
'更年期用它调睡眠,商城的褪黑素软糖效果好!但夜间模式切换有点卡顿,偶尔闪屏。社区阿姨分享的「大豆异黄酮食谱」试了三周。',
|
||||||
|
avatar: 'https://picsum.photos/id/546/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '郑博文',
|
||||||
|
feedback:
|
||||||
|
'脂肪肝患者靠它逆转!商城的护肝片性价比高,AI推的低脂食谱让我三个月转氨酶从80降到45,但饮食库中餐馆菜太少。',
|
||||||
|
avatar: 'https://picsum.photos/id/547/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '吴佳琪',
|
||||||
|
feedback: '护士夜班必备!商城的蒸汽眼罩缓解眼疲劳,睡眠修复功能帮我补觉效率提高50%,但轮班模式切换后数据要手动改。',
|
||||||
|
avatar: 'https://picsum.photos/id/548/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '孙浩宇',
|
||||||
|
feedback: '给爸妈买的智能手表绑定后,商城的血压计质量很好!心率异常立刻提醒我,但手表续航有点短,得天天充。',
|
||||||
|
avatar: 'https://picsum.photos/id/549/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '刘思远',
|
||||||
|
feedback:
|
||||||
|
'考研党用它管理作息,商城的护眼台灯很实用!每天6点起床提醒比闹钟温柔,但专注模式会被电话打断,希望加「免打扰时段」。',
|
||||||
|
avatar: 'https://picsum.photos/id/550/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '唐雨桐',
|
||||||
|
feedback: '乳腺癌术后康复靠它!商城的义乳很舒适,AI推荐的康复操比医院教的详细,练三个月手臂活动度恢复90%。',
|
||||||
|
avatar: 'https://picsum.photos/id/551/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '冯梓轩',
|
||||||
|
feedback:
|
||||||
|
'餐厅老板用它管理员工健康,商城的食品温度计很精准!食品从业者体检提醒超及时,但批量导入员工信息有点麻烦。',
|
||||||
|
avatar: 'https://picsum.photos/id/552/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '黄梦琪',
|
||||||
|
feedback:
|
||||||
|
'自闭症儿童妈妈福音!商城的感统训练器材很专业,AI推的「感统训练游戏」让孩子眼神接触多了,但视频没有字幕。',
|
||||||
|
avatar: 'https://picsum.photos/id/553/200/200'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
username: '周博文',
|
||||||
|
feedback: '货车司机必备!商城的腰部靠垫很舒适,疲劳驾驶提醒比副驾还灵,上次差点睡着被及时叫醒。但离线地图更新慢。',
|
||||||
|
avatar: 'https://picsum.photos/id/554/200/200'
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -7,8 +7,12 @@
|
|||||||
<!-- <main class="layout-main">-->
|
<!-- <main class="layout-main">-->
|
||||||
<!-- <slot></slot>-->
|
<!-- <slot></slot>-->
|
||||||
<!-- </main>-->
|
<!-- </main>-->
|
||||||
<router-view></router-view>
|
<!-- <router-view></router-view>-->
|
||||||
|
<!-- 核心路由出口,根据meta.keepAlive决定是否缓存 -->
|
||||||
|
<keep-alive>
|
||||||
|
<router-view v-if="$route.meta.keepAlive" />
|
||||||
|
</keep-alive>
|
||||||
|
<router-view v-if="!$route.meta.keepAlive" />
|
||||||
<!-- 页脚 -->
|
<!-- 页脚 -->
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
30
src/main.ts
30
src/main.ts
@ -1,42 +1,42 @@
|
|||||||
// src/main.ts
|
// src/main.ts
|
||||||
import { ViteSSG } from 'vite-ssg'
|
import { ViteSSG } from 'vite-ssg'
|
||||||
import { createWebHistory } from 'vue-router'
|
import { createWebHashHistory } from 'vue-router'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import routes from './router/routes'
|
import routes from './router/routes'
|
||||||
import i18n from './locales/i18n' // 导入i18n配置
|
import i18n from './locales/i18n' // 导入i18n配置
|
||||||
import './style.css'
|
import './style.css'
|
||||||
import '@/styles/global.less' // 引入全局样式
|
import '@/styles/global.less' // 引入全局样式
|
||||||
import '@/styles/tailwindcss.less' // tailwindcss.less
|
import '@/styles/tailwindcss.css' // 引入tailwindcss样式
|
||||||
// 修正:明确 meta.title 的类型为 string
|
// 修正:明确 meta.title 的类型为 string
|
||||||
|
// 1. 引入 Element Plus 核心库和全局样式
|
||||||
// 引入 element-plus 核心库
|
import ElementPlus from 'element-plus'
|
||||||
// import ElementPlus from 'element-plus'
|
import 'element-plus/dist/index.css' // 手动引入默认样式(覆盖自动导入的样式冲突)
|
||||||
// 引入 element-plus 全局样式(可根据需求选择是否自定义主题,这里先引入默认样式)
|
// 2. 引入国际化语言包(确保路径正确)
|
||||||
import 'element-plus/dist/index.css'
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||||
// 如果你需要使用 Element Plus 提供的国际化(i18n)功能,还需引入对应的语言包,比如中文
|
|
||||||
|
|
||||||
// 修正:使用正确的语言包路径(从 es/locale/lang 导入)
|
|
||||||
// import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
|
||||||
// 使用 ElementPlus 插件,并配置国际化等选项(这里以配置中文为例)
|
// 使用 ElementPlus 插件,并配置国际化等选项(这里以配置中文为例)
|
||||||
|
import { MotionPlugin } from '@vueuse/motion'
|
||||||
|
|
||||||
declare module 'vue-router' {
|
declare module 'vue-router' {
|
||||||
interface RouteMeta {
|
interface RouteMeta {
|
||||||
title?: string // 明确指定为 string 类型
|
title?: string // 明确指定为 string 类型
|
||||||
requiresAuth?: boolean
|
requiresAuth?: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createApp = ViteSSG(
|
export const createApp = ViteSSG(
|
||||||
App,
|
App,
|
||||||
{
|
{
|
||||||
history: createWebHistory(),
|
history: createWebHashHistory(),
|
||||||
routes,
|
routes,
|
||||||
base: import.meta.env.BASE_URL || '/'
|
base: import.meta.env.BASE_URL || '/'
|
||||||
},
|
},
|
||||||
ctx => {
|
ctx => {
|
||||||
// 安装 i18n 插件
|
// 安装 i18n 插件
|
||||||
ctx.app.use(i18n)
|
ctx.app.use(i18n)
|
||||||
// ctx.app.use(ElementPlus, {
|
ctx.app.use(MotionPlugin)
|
||||||
// locale: zhCn
|
ctx.app.use(ElementPlus, {
|
||||||
// })
|
locale: zhCn
|
||||||
|
})
|
||||||
|
|
||||||
// 路由守卫:设置页面标题
|
// 路由守卫:设置页面标题
|
||||||
ctx.router.beforeEach((to, _from, next) => {
|
ctx.router.beforeEach((to, _from, next) => {
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
// src/router/index.ts
|
// src/router/index.ts
|
||||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
import routes from './routes'
|
import routes from './routes'
|
||||||
|
// import setPageTitle from '@/utils/set-page-title.ts'cd
|
||||||
|
// const isProduction = import.meta.env.MODE === 'production'
|
||||||
|
// const history = isProduction
|
||||||
|
// ? createWebHashHistory() // 线上:带#
|
||||||
|
// : createWebHistory() // 本地:无#
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
routes,
|
routes,
|
||||||
@ -19,9 +23,18 @@ const router = createRouter({
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.beforeEach((_to, _from, next) => {
|
router.beforeEach((_to, _from, next) => {
|
||||||
// 添加下划线
|
// setPageTitle(_to.meta.title)
|
||||||
// document.title = to.meta.title || '极简官网' // 确保meta.title类型正确
|
|
||||||
|
if (_to.name === 'ArticleDetail' && _from.name === 'News') {
|
||||||
|
// 清除News组件的缓存
|
||||||
|
const cachedComponents = getCurrentInstance()?.appContext.config.globalProperties.$keepAlive?.cache
|
||||||
|
if (cachedComponents) {
|
||||||
|
delete cachedComponents['News']
|
||||||
|
}
|
||||||
|
}
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// / 添加日志,验证路由模式
|
||||||
|
// console.log('路由模式:', router.history)
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
@ -15,14 +15,77 @@ const routes: RouteRecordRaw[] = [
|
|||||||
path: '/',
|
path: '/',
|
||||||
component: () => import('@/layout/Layout.vue'), // 动态导入
|
component: () => import('@/layout/Layout.vue'), // 动态导入
|
||||||
children: [
|
children: [
|
||||||
{ path: '', name: 'Home', component: () => import('@/views/Home/Home.vue') },
|
{
|
||||||
{ path: 'news', name: 'News', component: () => import('@/views/News/News.vue') },
|
path: '',
|
||||||
{ path: 'news/:id', name: 'ArticleDetail', component: () => import('@/views/News/ArticleDetail.vue') },
|
name: 'Home',
|
||||||
{ path: 'network', name: 'Network', component: () => import('@/views/Network/Network.vue') },
|
meta: {
|
||||||
{ path: 'dating', name: 'Dating', component: () => import('@/views/Dating/Dating.vue') },
|
keepAlive: false
|
||||||
{ path: 'app', name: 'App', component: () => import('@/views/App/App.vue') },
|
},
|
||||||
{ path: 'ecosystem', name: 'Ecosystem', component: () => import('@/views/Ecosystem/Ecosystem.vue') },
|
component: () => import('@/views/Home/Home.vue')
|
||||||
{ path: 'about', name: 'About', component: () => import('@/views/About/About.vue') }
|
},
|
||||||
|
{
|
||||||
|
path: 'news',
|
||||||
|
name: 'News',
|
||||||
|
meta: {
|
||||||
|
title: '友福动态',
|
||||||
|
keepAlive: false
|
||||||
|
},
|
||||||
|
component: () => import('@/views/News/News.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'articleDetail/:id',
|
||||||
|
name: 'articleDetail',
|
||||||
|
meta: {
|
||||||
|
title: '文章详情',
|
||||||
|
keepAlive: false // 详情页不缓存
|
||||||
|
},
|
||||||
|
component: () => import('@/views/News/ArticleDetail.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'network',
|
||||||
|
name: 'Network',
|
||||||
|
meta: {
|
||||||
|
title: 'AI健康',
|
||||||
|
keepAlive: false
|
||||||
|
},
|
||||||
|
component: () => import('@/views/Network/Network.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'dating',
|
||||||
|
name: 'Dating',
|
||||||
|
meta: {
|
||||||
|
title: 'AI婚恋',
|
||||||
|
keepAlive: false
|
||||||
|
},
|
||||||
|
component: () => import('@/views/Dating/Dating.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'app',
|
||||||
|
name: 'App',
|
||||||
|
meta: {
|
||||||
|
title: '友福同享APP',
|
||||||
|
keepAlive: false
|
||||||
|
},
|
||||||
|
component: () => import('@/views/App/App.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'ecosystem',
|
||||||
|
name: 'Ecosystem',
|
||||||
|
meta: {
|
||||||
|
title: '生态合作',
|
||||||
|
keepAlive: false
|
||||||
|
},
|
||||||
|
component: () => import('@/views/Ecosystem/Ecosystem.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'about',
|
||||||
|
name: 'About',
|
||||||
|
meta: {
|
||||||
|
title: '关于我们',
|
||||||
|
keepAlive: false
|
||||||
|
},
|
||||||
|
component: () => import('@/views/About/About.vue')
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
|
|||||||
@ -317,4 +317,37 @@ html, body {
|
|||||||
|
|
||||||
.btn-glow:hover::before {
|
.btn-glow:hover::before {
|
||||||
left: 100%;
|
left: 100%;
|
||||||
|
}
|
||||||
|
.btn-success-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-success-glow:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 0 20px #aaeec4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-success-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-success-glow:hover::before {
|
||||||
|
left: 100%;
|
||||||
}
|
}
|
||||||
@ -1,13 +1,13 @@
|
|||||||
// src/utils/navigation.ts
|
// src/utils/navigation.ts
|
||||||
import { useRouter } from 'vue-router'
|
import router from '../router/index.ts' // 直接导入已创建的路由实例
|
||||||
|
import type { RouteLocationRaw } from 'vue-router'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 内部路由跳转(简化版)
|
* 内部路由跳转(简化版)
|
||||||
* @param to - 路由路径或名称
|
* @param to - 路由路径或名称
|
||||||
* @param replace - 是否替换当前历史记录
|
* @param replace - 是否替换当前历史记录
|
||||||
*/
|
*/
|
||||||
export const navigateTo = (to: string | { name: string }, replace = false) => {
|
export const navigateTo = (to: RouteLocationRaw, replace = false) => {
|
||||||
const router = useRouter()
|
|
||||||
replace ? router.replace(to) : router.push(to)
|
replace ? router.replace(to) : router.push(to)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,14 +23,29 @@ export const openExternalLink = (url: string, target: '_blank' | '_self' = '_bla
|
|||||||
window.location.href = url
|
window.location.href = url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 在新窗口打开内部路由页面
|
||||||
|
* @param to - 内部路由参数(路径或命名路由对象)
|
||||||
|
*/
|
||||||
|
export const openNewWindow = (to: RouteLocationRaw) => {
|
||||||
|
console.log('路由实例:', router) // 应输出一个包含 routes、options 等属性的对象,而非 undefined
|
||||||
|
try {
|
||||||
|
// 使用导入的 router 实例调用 resolve
|
||||||
|
const routeLocation = router.resolve(to)
|
||||||
|
// 拼接完整URL(当前域名 + 路由路径)
|
||||||
|
const fullUrl = `${window.location.origin}${routeLocation.href}`
|
||||||
|
// 新窗口打开
|
||||||
|
window.open(fullUrl, '_blank', 'noopener,noreferrer')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('新窗口打开路由失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 返回上一页
|
* 返回上一页
|
||||||
*/
|
*/
|
||||||
// export const goBack = () => {
|
export const goBack = () => {
|
||||||
// useRouter().back()
|
router.back()
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// <template>
|
// <template>
|
||||||
// <div>
|
// <div>
|
||||||
// <button @click="goToProduct(123)">查看产品</button>
|
// <button @click="goToProduct(123)">查看产品</button>
|
||||||
|
|||||||
@ -41,13 +41,13 @@ service.interceptors.request.use(
|
|||||||
|
|
||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
(response: AxiosResponse<ApiResponse>) => {
|
(response: AxiosResponse<any>) => {
|
||||||
const res = response.data
|
const res = response.data
|
||||||
if (res.code !== 200) {
|
if (res.code !== 0) {
|
||||||
showError(res.message || '请求失败')
|
showError(res.message || '请求失败')
|
||||||
return Promise.reject(new Error(res.message || '请求失败'))
|
return Promise.reject(new Error(res.message || '请求失败'))
|
||||||
}
|
}
|
||||||
return res.data
|
return res
|
||||||
},
|
},
|
||||||
(error: AxiosError<ApiResponse>) => {
|
(error: AxiosError<ApiResponse>) => {
|
||||||
console.error('响应错误:', error)
|
console.error('响应错误:', error)
|
||||||
|
|||||||
5
src/utils/set-page-title.ts
Normal file
5
src/utils/set-page-title.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const pageDefaultTitle = '友福同享智能科技官网'
|
||||||
|
export default function setPageTitle(routerTitle?: string): void {
|
||||||
|
console.log(routerTitle)
|
||||||
|
document.title = routerTitle ? `${routerTitle} | ${pageDefaultTitle}` : `${pageDefaultTitle}`
|
||||||
|
}
|
||||||
54
src/utils/tools.ts
Normal file
54
src/utils/tools.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { openExternalLink } from '@/utils/navigation.ts'
|
||||||
|
/**
|
||||||
|
* 下载FloveApp(根据设备自动切换链接)
|
||||||
|
* - 安卓设备:下载APK文件
|
||||||
|
* - 苹果设备(iOS):跳转App Store
|
||||||
|
*/
|
||||||
|
export const downloadFloveApp = () => {
|
||||||
|
// 判断设备类型(iOS/Android)
|
||||||
|
const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent)
|
||||||
|
|
||||||
|
// 根据设备选择链接
|
||||||
|
const url = isIOS
|
||||||
|
? 'https://apps.apple.com/cn/app/%E7%A6%8F%E6%81%8B/id1483551530' // 苹果App Store
|
||||||
|
: 'https://ufutx-image.oss-cn-shenzhen.aliyuncs.com/apk/flove_fulllink.apk' // 安卓APK
|
||||||
|
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
|
||||||
|
// 苹果跳转App Store无需指定download(避免下载无效文件),安卓指定文件名
|
||||||
|
if (!isIOS) {
|
||||||
|
link.download = 'flove_fulllink.apk'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理跨域和安全配置
|
||||||
|
if (link.href.indexOf(location.origin) !== 0) {
|
||||||
|
link.target = '_blank' // 跨域链接打开新窗口,避免浏览器拦截
|
||||||
|
link.rel = 'noopener noreferrer' // 增强安全性,防止新窗口篡改原页面
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发下载/跳转
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
// 延迟移除,避免部分浏览器因立即移除导致跳转失败
|
||||||
|
setTimeout(() => {
|
||||||
|
document.body.removeChild(link)
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 跳转地图
|
||||||
|
* @param latitude 纬度
|
||||||
|
* @param longitude 经度
|
||||||
|
* @param detail 详情
|
||||||
|
*/
|
||||||
|
export 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`
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -34,7 +34,7 @@ import BranchDistribution from '@/views/About/sections/BranchDistribution.vue'
|
|||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.about-page {
|
.about-page {
|
||||||
width: 100%;
|
//width: 100%;
|
||||||
overflow-x: hidden;
|
//overflow-x: hidden;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="banner">
|
<section class="banner">
|
||||||
<div class="banner-bg">
|
<div v-motion-fade-visible class="banner-bg">
|
||||||
<!-- 替换为实际背景图路径 -->
|
<!-- 替换为实际背景图路径 -->
|
||||||
<img src="https://images.health.ufutx.com/202506/27/ae38015f070eeb51347359577acf1063.png" alt="Banner背景" />
|
<img src="https://images.health.ufutx.com/202506/27/ae38015f070eeb51347359577acf1063.png" alt="Banner背景" />
|
||||||
</div>
|
</div>
|
||||||
@ -66,6 +66,7 @@
|
|||||||
|
|
||||||
.banner-bg {
|
.banner-bg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 830px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|||||||
@ -64,7 +64,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted, nextTick } from 'vue'
|
import { ref, computed, onMounted, nextTick } from 'vue'
|
||||||
import BranchMap from './BranchMap.vue'
|
import BranchMap from './BranchMap.vue'
|
||||||
import { openExternalLink } from '@/utils/navigation.ts'
|
import { gotoMapFn } from '@/utils/tools.ts'
|
||||||
// 子公司数据(使用ECharts坐标格式)
|
// 子公司数据(使用ECharts坐标格式)
|
||||||
const branchList = [
|
const branchList = [
|
||||||
{
|
{
|
||||||
@ -126,17 +126,6 @@ const handleMapClick = (index: number) => {
|
|||||||
activeIndex.value = index
|
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 calculateSliderPosition = () => {
|
||||||
const activeTab = tabsRef.value[activeIndex.value]
|
const activeTab = tabsRef.value[activeIndex.value]
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { ref, onMounted, watch, nextTick, onUnmounted } from 'vue'
|
|||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import chinaJson from '@/assets/map/china.json'
|
import chinaJson from '@/assets/map/china.json'
|
||||||
|
|
||||||
echarts.registerMap('china', chinaJson)
|
echarts.registerMap('china', chinaJson as any)
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
branchList: Array<{
|
branchList: Array<{
|
||||||
@ -166,7 +166,8 @@ const updateChart = () => {
|
|||||||
const headquartersIndex = getHeadquartersIndex()
|
const headquartersIndex = getHeadquartersIndex()
|
||||||
const option = myChart.getOption() as echarts.EChartsOption
|
const option = myChart.getOption() as echarts.EChartsOption
|
||||||
|
|
||||||
if (option.series && option.series[1]) {
|
// if (option.series && option.series[1]) {
|
||||||
|
if (option.series && Array.isArray(option.series) && option.series[1]) {
|
||||||
option.series[1].data = props.branchList.map((item, index) => ({
|
option.series[1].data = props.branchList.map((item, index) => ({
|
||||||
...item,
|
...item,
|
||||||
value: item.coord,
|
value: item.coord,
|
||||||
|
|||||||
@ -75,14 +75,14 @@ const timelineData = [
|
|||||||
.timeline-header {
|
.timeline-header {
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
.main-title {
|
.main-title {
|
||||||
font-size: 28px;
|
font-size: 32px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #333;
|
color: @text-color;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.sub-title {
|
.sub-title {
|
||||||
font-size: 14px;
|
font-size: 20px;
|
||||||
color: #999;
|
color: @text-color-secondary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@ const valueTabs = [
|
|||||||
title: '团队精神',
|
title: '团队精神',
|
||||||
name: 'TeamSpirit',
|
name: 'TeamSpirit',
|
||||||
content: ['开放沟通、互相尊重,人人都是关键角色', '注重跨部门协作,共同承担责任', '团队一起面对挑战、共享成功'],
|
content: ['开放沟通、互相尊重,人人都是关键角色', '注重跨部门协作,共同承担责任', '团队一起面对挑战、共享成功'],
|
||||||
image: 'https://images.health.ufutx.com/202506/20/136362c2dff3844304dd1e96bd36ee03.png'
|
image: 'https://images.health.ufutx.com/202507/02/eb71edac0faa7282c999b1d9ebbb5962.png'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '创始人精神',
|
title: '创始人精神',
|
||||||
|
|||||||
@ -3,37 +3,83 @@
|
|||||||
<h2 class="section-title">资质认证</h2>
|
<h2 class="section-title">资质认证</h2>
|
||||||
<p class="section-subtitle">成立至今获得多项荣誉</p>
|
<p class="section-subtitle">成立至今获得多项荣誉</p>
|
||||||
<div class="carousel-container">
|
<div class="carousel-container">
|
||||||
<!-- <button class="carousel-btn prev" @click="slide(-1)">‹</button>-->
|
<div class="carousel-btn prev"></div>
|
||||||
<div class="certificate-section">
|
<div class="certificate-section">
|
||||||
<div class="certificate-list">
|
<div class="certificate-list">
|
||||||
<div
|
<Marquee
|
||||||
v-for="(src, index) in certificateImgs"
|
:duration="60"
|
||||||
:key="index"
|
:reverse="false"
|
||||||
class="certificate-item"
|
repeatCount="3"
|
||||||
@mouseenter="activeIndex = index"
|
pause-on-hover
|
||||||
@mouseleave="activeIndex = -1"
|
container-class="h-56 bg-white rounded-lg shadow-sm p-4"
|
||||||
|
:initial-offset="0"
|
||||||
>
|
>
|
||||||
<img :src="src" alt="certificate" :class="{ 'scale-up': activeIndex === index }" />
|
<div
|
||||||
</div>
|
v-for="(src, index) in certificateImgs"
|
||||||
|
:key="index"
|
||||||
|
class="certificate-item"
|
||||||
|
@mouseenter="activeIndex = index"
|
||||||
|
@mouseleave="activeIndex = -1"
|
||||||
|
>
|
||||||
|
<el-image
|
||||||
|
:ref="
|
||||||
|
(el: any) => {
|
||||||
|
imageRefs[index] = el
|
||||||
|
}
|
||||||
|
"
|
||||||
|
:src="src"
|
||||||
|
alt="certificate"
|
||||||
|
class="certificate-image"
|
||||||
|
:zoom-rate="1.2"
|
||||||
|
:preview-src-list="certificateImgs"
|
||||||
|
show-progress
|
||||||
|
preview-teleported
|
||||||
|
:initial-index="index"
|
||||||
|
:class="{ 'scale-up': activeIndex === index }"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-show="activeIndex === index"
|
||||||
|
v-motion-pop-visible
|
||||||
|
class="certificate-preview"
|
||||||
|
@click.stop="handleClick(index)"
|
||||||
|
>
|
||||||
|
<p class="_text">预览</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Marquee>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <button class="carousel-btn next" @click="slide(1)">›</button>-->
|
<div class="carousel-btn next"></div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import Marquee from '@/components/Marquee.vue'
|
||||||
|
import type { ImageInstance } from 'element-plus'
|
||||||
|
// 创建数组ref存储每个图片实例
|
||||||
|
const imageRefs = ref<(ImageInstance | null)[]>([])
|
||||||
|
|
||||||
const certificateImgs = [
|
const certificateImgs = [
|
||||||
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
||||||
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
||||||
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png', // 中间证书
|
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png', // 中间证书
|
||||||
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
||||||
|
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
||||||
|
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
||||||
|
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png',
|
||||||
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png'
|
'https://images.health.ufutx.com/202506/20/6972bf0f5da9af6ec4f2b8fba404d59e.png'
|
||||||
]
|
]
|
||||||
|
|
||||||
const activeIndex = ref(-1)
|
const activeIndex = ref(-1)
|
||||||
|
// 点击处理函数(接收索引参数)
|
||||||
|
const handleClick = (index: number) => {
|
||||||
|
const image = imageRefs.value[index]
|
||||||
|
if (image) {
|
||||||
|
image.showPreview() // 调用对应图片的预览方法
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@ -73,20 +119,19 @@ const activeIndex = ref(-1)
|
|||||||
}
|
}
|
||||||
.carousel-btn {
|
.carousel-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 46%;
|
||||||
transform: translateY(-50%);
|
//flex-shrink: 0;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
width: 45px;
|
||||||
color: #fff;
|
height: 60px;
|
||||||
border: none;
|
background-size: cover;
|
||||||
padding: 10px 15px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: @font-size-lg;
|
|
||||||
|
|
||||||
&.prev {
|
&.prev {
|
||||||
left: 20px;
|
left: 70px;
|
||||||
|
background-image: url('https://images.health.ufutx.com/202507/02/9094a60740fb3dfd8f71cf5ebaeefcf7.png');
|
||||||
}
|
}
|
||||||
&.next {
|
&.next {
|
||||||
right: 20px;
|
width: 45px;
|
||||||
|
right: 70px;
|
||||||
|
background-image: url('https://images.health.ufutx.com/202507/02/6e2c89ad18e8f8f813a71870e1ed473c.png');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,43 +139,96 @@ const activeIndex = ref(-1)
|
|||||||
//background: red;
|
//background: red;
|
||||||
}
|
}
|
||||||
.certificate-section {
|
.certificate-section {
|
||||||
padding: 172px 0px;
|
padding: 122px 0px;
|
||||||
|
|
||||||
|
&&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 60px;
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
&&::before {
|
||||||
|
left: 160px;
|
||||||
|
//background: linear-gradient(to right, #dadddf, transparent);
|
||||||
|
}
|
||||||
//position: absolute;
|
//position: absolute;
|
||||||
//top: 0;
|
//top: 0;
|
||||||
.certificate-list {
|
.certificate-list {
|
||||||
display: flex;
|
max-width: 1561px;
|
||||||
|
height: 460px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
//background: red;
|
||||||
gap: 16px;
|
margin: 0 auto;
|
||||||
margin: 0px auto;
|
//margin-left: 100px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
// 关键:强制水平布局,禁止换行
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row; /* 明确水平方向 */
|
||||||
|
flex-wrap: nowrap; /* 禁止换行 */
|
||||||
|
overflow: hidden; /* 隐藏超出容器的部分 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.certificate-item {
|
.certificate-item {
|
||||||
transition: all 0.3s ease;
|
width: 288px; /* 固定宽度,确保能在一行放下多个 */
|
||||||
cursor: pointer;
|
flex-shrink: 0; /* 禁止收缩,保证宽度不变 */
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* 增加轻微阴影,提升视觉层次 */
|
||||||
img {
|
margin-right: 16px;
|
||||||
|
cursor: pointer; /* 提示可交互 */
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); /* 卡片整体过渡 */
|
||||||
|
.certificate-image {
|
||||||
width: 288px;
|
width: 288px;
|
||||||
height: auto;
|
|
||||||
border: 4px solid transparent;
|
|
||||||
transform-origin: bottom center; /* 核心:设置缩放原点为底部中心 */
|
transform-origin: bottom center; /* 核心:设置缩放原点为底部中心 */
|
||||||
transition:
|
transition:
|
||||||
transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94),
|
transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94),
|
||||||
border-color 0.3s ease;
|
border-color 0.3s ease;
|
||||||
}
|
}
|
||||||
|
.certificate-preview {
|
||||||
|
position: absolute;
|
||||||
|
top: -20px;
|
||||||
|
left: 0;
|
||||||
|
width: 288px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 1;
|
||||||
|
//background: red;
|
||||||
|
align-items: center;
|
||||||
|
._text {
|
||||||
|
font-size: 18px;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 32px;
|
||||||
|
border-radius: 50px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 放大样式(中间默认 + hover触发)
|
// 放大样式(中间默认 + hover触发)
|
||||||
.scale-up {
|
.scale-up {
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
//z-index: 10;
|
|
||||||
transform-origin: bottom center; /* 新增,设置缩放原点为底部中心 */
|
transform-origin: bottom center; /* 新增,设置缩放原点为底部中心 */
|
||||||
z-index: 10;
|
//box-shadow: 0 8px 24px rgba(75, 137, 220, 0.2);
|
||||||
border-color: #4b89dc;
|
}
|
||||||
box-shadow: 0 8px 24px rgba(75, 137, 220, 0.2);
|
.scale-up-preview {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
opacity: 1;
|
||||||
|
//transform: translateY(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 穿透 Marquee 容器的事件拦截
|
||||||
|
:deep(.marquee-container) {
|
||||||
|
/* 根据 Marquee 实际类名调整 */
|
||||||
|
pointer-events: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保滚动轨道不阻止事件
|
||||||
|
:deep(.marquee-track) {
|
||||||
|
pointer-events: auto !important;
|
||||||
|
}
|
||||||
// 响应式适配
|
// 响应式适配
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.certificate-list {
|
.certificate-list {
|
||||||
|
|||||||
@ -15,17 +15,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const healthItems = [
|
const healthItems = [
|
||||||
{
|
{
|
||||||
icon: 'https://images.health.ufutx.com/202506/20/10c734494721ea0a60c3b9c3ebd82a60.png',
|
icon: 'https://images.health.ufutx.com/202506/30/f0356813f3eda8e37f303a44ae3d70b8.png',
|
||||||
title: '生命科学+AI的深度融合',
|
title: '生命科学+AI的深度融合',
|
||||||
desc: '让人体健康管理像科研一样自然'
|
desc: '让人体健康管理像科研一样自然'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'https://images.health.ufutx.com/202506/20/10c734494721ea0a60c3b9c3ebd82a60.png',
|
icon: 'https://images.health.ufutx.com/202506/30/cfb74da07ad90521f3a108c6450f88c7.png',
|
||||||
title: '万亿级产业新基建',
|
title: '万亿级产业新基建',
|
||||||
desc: '从个人健康到城市级智慧医疗的完整生态'
|
desc: '从个人健康到城市级智慧医疗的完整生态'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'https://images.health.ufutx.com/202506/20/10c734494721ea0a60c3b9c3ebd82a60.png',
|
icon: 'https://images.health.ufutx.com/202506/30/572c91788ea274174a8bd8fe77e52c08.png',
|
||||||
title: '人人都拥有的数字健康管家',
|
title: '人人都拥有的数字健康管家',
|
||||||
desc: '让真实有效的健康管理普惠全民'
|
desc: '让真实有效的健康管理普惠全民'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="banner">
|
<section class="banner">
|
||||||
<div class="banner-bg">
|
<div v-motion-fade-visible class="banner-bg">
|
||||||
<!-- 替换为实际背景图路径 -->
|
<!-- 替换为实际背景图路径 -->
|
||||||
<img src="https://images.health.ufutx.com/202506/13/19ee6e89c397511fef5ba05d9798cc76.png" alt="Banner背景" />
|
<img src="https://images.health.ufutx.com/202506/13/19ee6e89c397511fef5ba05d9798cc76.png" alt="Banner背景" />
|
||||||
</div>
|
</div>
|
||||||
@ -66,6 +66,7 @@ const newsList = [
|
|||||||
|
|
||||||
.banner-bg {
|
.banner-bg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 830px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|||||||
@ -21,8 +21,10 @@
|
|||||||
<div class="device-info">
|
<div class="device-info">
|
||||||
<h3 class="device-title">{{ navList[activeIndex].center.title }}</h3>
|
<h3 class="device-title">{{ navList[activeIndex].center.title }}</h3>
|
||||||
<h3 class="device-subtitle">{{ navList[activeIndex].center.subtitle }}</h3>
|
<h3 class="device-subtitle">{{ navList[activeIndex].center.subtitle }}</h3>
|
||||||
|
|
||||||
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<p class="device-desc" v-html="navList[activeIndex].center.description"></p>
|
<p class="device-desc" v-html="navList[activeIndex].center.description"></p>
|
||||||
<div class="download-btn" @click="openReport">立即下载</div>
|
<div class="btn-success-glow download-btn" @click="openReport">立即下载</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -38,7 +40,7 @@ const navList = ref([
|
|||||||
{
|
{
|
||||||
text: '健康手环',
|
text: '健康手环',
|
||||||
active: true,
|
active: true,
|
||||||
icon: 'https://images.health.ufutx.com/202506/18/4aae244f94bbf8bf352e8ab8e2270a81.png',
|
icon: 'https://images.health.ufutx.com/202507/02/4aae244f94bbf8bf352e8ab8e2270a81.png',
|
||||||
center: {
|
center: {
|
||||||
navLabel: '健康手环', // 导航栏显示文字
|
navLabel: '健康手环', // 导航栏显示文字
|
||||||
title: '健康手环', // 页面主标题
|
title: '健康手环', // 页面主标题
|
||||||
@ -138,12 +140,12 @@ const handleSelect = (index: number) => {
|
|||||||
background-size: contain;
|
background-size: contain;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
opacity: 0.6;
|
//opacity: 0.8;
|
||||||
transition: opacity 0.3s;
|
transition: opacity 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-text {
|
.nav-text {
|
||||||
font-size: 26px;
|
font-size: 20px;
|
||||||
color: @text-color-secondary;
|
color: @text-color-secondary;
|
||||||
transition: color 0.3s;
|
transition: color 0.3s;
|
||||||
}
|
}
|
||||||
@ -228,7 +230,7 @@ const handleSelect = (index: number) => {
|
|||||||
|
|
||||||
.download-btn {
|
.download-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 16px 30px;
|
padding: 14px 30px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
@ -236,7 +238,6 @@ const handleSelect = (index: number) => {
|
|||||||
background: #18ca6e;
|
background: #18ca6e;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,8 +7,10 @@
|
|||||||
<div class="device-info">
|
<div class="device-info">
|
||||||
<h3 class="device-title">{{ props.device.title }}</h3>
|
<h3 class="device-title">{{ props.device.title }}</h3>
|
||||||
<h3 class="device-subtitle">AI精准个性化健康方案服务</h3>
|
<h3 class="device-subtitle">AI精准个性化健康方案服务</h3>
|
||||||
|
|
||||||
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<p class="device-desc" v-html="props.device.desc"></p>
|
<p class="device-desc" v-html="props.device.desc"></p>
|
||||||
<div class="download-btn" @click="openReport">立即下载</div>
|
<div class="btn-success-glow download-btn" @click="openReport">立即下载</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -97,7 +99,7 @@ const openReport = () => {
|
|||||||
|
|
||||||
.download-btn {
|
.download-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 16px 30px;
|
padding: 14px 30px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
@ -105,7 +107,12 @@ const openReport = () => {
|
|||||||
background: #18ca6e;
|
background: #18ca6e;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
//font-weight: bold;
|
||||||
|
|
||||||
|
&&:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 0 20px #18ca6e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
跨出社交圈,“一分钟演讲”<br />
|
跨出社交圈,“一分钟演讲”<br />
|
||||||
立即让未来的灵魂伴侣更了解你,轻松打开话题
|
立即让未来的灵魂伴侣更了解你,轻松打开话题
|
||||||
</p>
|
</p>
|
||||||
<div class="download-btn" @click="openReport">立即下载</div>
|
<div class="btn-success-glow download-btn" @click="openReport">立即下载</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="speech-img">
|
<div class="speech-img">
|
||||||
<!-- <img src="@/assets/speech-app.png" alt="演讲界面" />-->
|
<!-- <img src="@/assets/speech-app.png" alt="演讲界面" />-->
|
||||||
@ -67,7 +67,7 @@ const openReport = () => {
|
|||||||
|
|
||||||
.download-btn {
|
.download-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 16px 30px;
|
padding: 14px 30px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
@ -75,7 +75,7 @@ const openReport = () => {
|
|||||||
background: #18ca6e;
|
background: #18ca6e;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: bold;
|
//font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,43 +3,19 @@
|
|||||||
<div class="tags-header">
|
<div class="tags-header">
|
||||||
<h2 class="tags-title">友福AI婚恋-专属单身标签</h2>
|
<h2 class="tags-title">友福AI婚恋-专属单身标签</h2>
|
||||||
<p class="tags-subtitle">Right Beside You, They Love Each Other!</p>
|
<p class="tags-subtitle">Right Beside You, They Love Each Other!</p>
|
||||||
<!-- <el-button type="primary" class="download-btn">立即下载</el-button>-->
|
<div class="btn-glow download-btn" @click="downloadFloveApp()">立即下载</div>
|
||||||
<div class="btn-glow download-btn">立即下载</div>
|
|
||||||
<div class="tags-icon">
|
<div class="tags-icon">
|
||||||
<img src="https://images.health.ufutx.com/202506/18/3b16ca61dc63eb22c102aed934301c0a.png" alt="" />
|
<img src="https://images.health.ufutx.com/202506/18/3b16ca61dc63eb22c102aed934301c0a.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="tags-carousel">-->
|
|
||||||
<!-- <div class="tag-item" v-for="(item, i) in tags" :key="i">-->
|
|
||||||
<!-- <img :src="item.img" alt="单身标签" class="tag-img" />-->
|
|
||||||
<!-- <p class="tag-desc">{{ item.desc }}</p>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// 18 import { ElButton } from 'element-plus'
|
import { downloadFloveApp } from '@/utils/tools.js'
|
||||||
|
|
||||||
// const tags = [
|
|
||||||
// {
|
|
||||||
// img: '@/assets/tag-1.png',
|
|
||||||
// desc: '霍小楠 • 27岁硕士 • 生活博主'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// img: '@/assets/tag-2.png',
|
|
||||||
// desc: '李浩然 • 30岁医生 • 运动达人'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// img: '@/assets/tag-3.png',
|
|
||||||
// desc: '苏晓萱 • 25岁设计师 • 文艺青年'
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@import '@/styles/global.less';
|
|
||||||
|
|
||||||
.ai-tags {
|
.ai-tags {
|
||||||
padding: 100px 192px;
|
padding: 100px 192px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -60,12 +36,12 @@
|
|||||||
}
|
}
|
||||||
.download-btn {
|
.download-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 16px 30px;
|
padding: 14px 30px;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
background: var(--Style, #1060ff);
|
background: var(--Style, #1060ff);
|
||||||
color: var(--ffffff, #fff);
|
color: var(--ffffff, #fff);
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 500;
|
//font-weight: 500;
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="banner">
|
<section class="banner">
|
||||||
<div class="banner-bg">
|
<div v-motion-fade-visible class="banner-bg">
|
||||||
<!-- 替换为实际背景图路径 -->
|
<!-- 替换为实际背景图路径 -->
|
||||||
<img src="https://images.health.ufutx.com/202506/13/100bcb7820a3cac2f8de6f50d0404460.png" alt="Banner背景" />
|
<img src="https://images.health.ufutx.com/202506/13/100bcb7820a3cac2f8de6f50d0404460.png" alt="Banner背景" />
|
||||||
</div>
|
</div>
|
||||||
@ -66,6 +66,7 @@
|
|||||||
|
|
||||||
.banner-bg {
|
.banner-bg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 830px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|||||||
@ -22,24 +22,24 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const points = [
|
const points = [
|
||||||
{
|
{
|
||||||
icon: 'https://images.health.ufutx.com/202506/18/2bf6cfbc4fef2c4d8e276e95398405a0.png',
|
icon: 'https://images.health.ufutx.com/202507/02/fb92625096f65beda47a97daaec64879.png',
|
||||||
title: '传统婚介困境',
|
title: '传统婚介困境',
|
||||||
desc: '效率低/规则混乱'
|
desc: '效率低/规则混乱'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'https://images.health.ufutx.com/202506/18/2bf6cfbc4fef2c4d8e276e95398405a0.png',
|
icon: 'https://images.health.ufutx.com/202507/02/09d30d86a53a86ee26faa9be50bbd24c.png',
|
||||||
title: '资料真假难辨',
|
title: '资料真假难辨',
|
||||||
desc: '生物特征+社交轨迹验证'
|
desc: '生物特征核验+社交轨迹交叉验证'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'https://images.health.ufutx.com/202506/18/2bf6cfbc4fef2c4d8e276e95398405a0.png',
|
icon: 'https://images.health.ufutx.com/202507/02/1a19cab6581b311e815002b859b8e440.png',
|
||||||
title: '匹配维度单一',
|
title: '匹配维度单一',
|
||||||
desc: '多维度开放模型'
|
desc: '多维度开放模型'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'https://images.health.ufutx.com/202506/18/2bf6cfbc4fef2c4d8e276e95398405a0.png',
|
icon: 'https://images.health.ufutx.com/202507/02/83b119df621a38fd9c9d0199c54ed2fa.png',
|
||||||
title: '售后服务缺失',
|
title: '售后服务缺失',
|
||||||
desc: '关系认证及延伸服务'
|
desc: '关系认知疏导及关怀服务'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<section class="success-stories">
|
<section class="success-stories">
|
||||||
<h2 class="section-title">就在你身边,他们相爱啦!</h2>
|
<h2 class="section-title">就在你身边,他们相爱啦!</h2>
|
||||||
<p class="section-subtitle">Right Beside You, They Love Each Other!</p>
|
<p class="section-subtitle">Right Beside You, They Love Each Other!</p>
|
||||||
<div class="download-btn btn-glow">立即下载</div>
|
<div class="download-btn btn-glow" @click="downloadFloveApp()">立即下载</div>
|
||||||
<div class="stories-icon">
|
<div class="stories-icon">
|
||||||
<img src="https://images.health.ufutx.com/202506/18/1a837037ce7fb8502a211a01e19fbf55.png" alt="" />
|
<img src="https://images.health.ufutx.com/202506/18/1a837037ce7fb8502a211a01e19fbf55.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
@ -25,6 +25,7 @@
|
|||||||
// { img: '@/assets/story-5.jpg' },
|
// { img: '@/assets/story-5.jpg' },
|
||||||
// { img: '@/assets/story-6.jpg' }
|
// { img: '@/assets/story-6.jpg' }
|
||||||
// ]
|
// ]
|
||||||
|
import { downloadFloveApp } from '@/utils/tools.ts'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@ -49,12 +50,12 @@
|
|||||||
|
|
||||||
.download-btn {
|
.download-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 16px 30px;
|
padding: 14px 30px;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
background: var(--Style, #1060ff);
|
background: var(--Style, #1060ff);
|
||||||
color: var(--ffffff, #fff);
|
color: var(--ffffff, #fff);
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 500;
|
//font-weight: 500;
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,14 +35,14 @@ import TalentTraining from './sections/TalentTraining.vue'
|
|||||||
import CityPartner from './sections/CityPartner.vue'
|
import CityPartner from './sections/CityPartner.vue'
|
||||||
const cooperateData = {
|
const cooperateData = {
|
||||||
title: '合作咨询',
|
title: '合作咨询',
|
||||||
desc: '欢迎健康产业链上下游企业,以及希望利用AI技术 升级健康产品与服务的企业与我们洽谈合作,共创产业新价值',
|
desc: '欢迎健康产业链上下游企业,以及希望利用AI技术<br> 升级健康产品与服务的企业与我们洽谈合作,共创产业新价值',
|
||||||
img: 'https://images.health.ufutx.com/202506/18/2e9c9d64bdcf03fbe5041720f03033ca.png'
|
img: 'https://images.health.ufutx.com/202506/20/c60d98038ab065c2e92dc67b938d45e2.png'
|
||||||
}
|
}
|
||||||
|
|
||||||
const cooperateDataV2 = {
|
const cooperateDataV2 = {
|
||||||
title: '合作咨询',
|
title: '合作咨询',
|
||||||
desc: '提供专属健康服务和解决方案',
|
desc: '提供专属健康服务和解决方案',
|
||||||
img: 'https://images.health.ufutx.com/202506/18/2e9c9d64bdcf03fbe5041720f03033ca.png'
|
img: 'https://images.health.ufutx.com/202506/20/c60d98038ab065c2e92dc67b938d45e2.png'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="banner">
|
<section class="banner">
|
||||||
<div class="banner-bg">
|
<div v-motion-fade-visible class="banner-bg">
|
||||||
<!-- 替换为实际背景图路径 -->
|
<!-- 替换为实际背景图路径 -->
|
||||||
<img src="https://images.health.ufutx.com/202506/13/7c87ebff15ce960d0e58473f401fa91b.png" alt="Banner背景" />
|
<img src="https://images.health.ufutx.com/202506/13/7c87ebff15ce960d0e58473f401fa91b.png" alt="Banner背景" />
|
||||||
</div>
|
</div>
|
||||||
@ -66,6 +66,7 @@
|
|||||||
|
|
||||||
.banner-bg {
|
.banner-bg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 830px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|||||||
@ -209,7 +209,7 @@ const currentIdx = ref(0)
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.desc {
|
.desc {
|
||||||
font-size: 16px;
|
font-size: 20px;
|
||||||
color: @text-color-secondary;
|
color: @text-color-secondary;
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="cooperation-consult">
|
<section class="cooperation-consult" :style="{ backgroundImage: `url(${props.device.img})` }">
|
||||||
<div class="consult-content">
|
<div class="consult-content">
|
||||||
<p class="consult-text">
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
{{ props.device.desc }}
|
<p class="consult-text" v-html="props.device.desc"></p>
|
||||||
</p>
|
<div class="consult-btn" @click="openCooperationDialog">{{ props.device.title }}</div>
|
||||||
<div class="consult-btn">{{ props.device.title }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<CooperationDialog ref="cooperationDialogRef" />
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import CooperationDialog from '@/views/Ecosystem/sections/CooperationDialog.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
device: {
|
device: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -17,10 +19,15 @@ const props = defineProps({
|
|||||||
default: () => ({
|
default: () => ({
|
||||||
title: '合作咨询',
|
title: '合作咨询',
|
||||||
desc: '欢迎健康产业链上下游企业,以及希望利用AI技术 升级健康产品与服务的企业与我们洽谈合作,共创产业新价值',
|
desc: '欢迎健康产业链上下游企业,以及希望利用AI技术 升级健康产品与服务的企业与我们洽谈合作,共创产业新价值',
|
||||||
img: 'https://images.health.ufutx.com/202506/18/2e9c9d64bdcf03fbe5041720f03033ca.png'
|
img: 'https://images.health.ufutx.com/202506/20/c60d98038ab065c2e92dc67b938d45e2.png'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const cooperationDialogRef = ref<InstanceType<typeof CooperationDialog>>()
|
||||||
|
|
||||||
|
const openCooperationDialog = () => {
|
||||||
|
cooperationDialogRef.value?.openDialog()
|
||||||
|
}
|
||||||
// // 18 import { ElButton } from 'element-plus'
|
// // 18 import { ElButton } from 'element-plus'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -46,9 +53,14 @@ const props = defineProps({
|
|||||||
color: #313fa8;
|
color: #313fa8;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
padding: 6px 36px;
|
padding: 16px 36px;
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
transition: all 0.2s;
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 10px rgba(189, 189, 189, 0.8);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
200
src/views/Ecosystem/sections/CooperationDialog.vue
Normal file
200
src/views/Ecosystem/sections/CooperationDialog.vue
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 控制弹框显示与隐藏的变量,假设为dialogVisible,需要在script中定义 -->
|
||||||
|
<div class="custom-dialog-wrapper">
|
||||||
|
<el-dialog v-model="dialogVisible" width="600px" :show-close="false">
|
||||||
|
<template #header>
|
||||||
|
<div class="dialog-header">合作咨询</div>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<div class="form-container">
|
||||||
|
<el-form ref="ruleFormRef" label-width="80px" :label-position="labelPosition" :model="form" :rules="rules">
|
||||||
|
<el-form-item label="您的姓名" prop="name">
|
||||||
|
<el-input v-model="form.name" placeholder="请输入联系人姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="联系方式" prop="mobile">
|
||||||
|
<el-input v-model="form.mobile" placeholder="请输入联系电话" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="您的需求" prop="demand">
|
||||||
|
<el-input
|
||||||
|
v-model="form.demand"
|
||||||
|
type="textarea"
|
||||||
|
:rows="4"
|
||||||
|
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||||
|
placeholder="请写明您的具体需求,以便我们安排形影顾问与您联系"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<div class="cancel-btn" @click="dialogVisible = false">取消</div>
|
||||||
|
<el-button type="primary" class="confirm-btn" @click="handleSubmit(ruleFormRef)">提交</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
// 引入 ElDialog、ElForm 等组件,如果你使用的是自动导入,可不用手动引入
|
||||||
|
// import { ElDialog, ElForm, ElFormItem, ElInput, ElButton } from 'element-plus';
|
||||||
|
const labelPosition = ref('top')
|
||||||
|
import request from '@/utils/request'
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
|
const dialogVisible = ref<boolean>(false)
|
||||||
|
const ruleFormRef = ref()
|
||||||
|
const form = reactive({
|
||||||
|
name: '',
|
||||||
|
mobile: '',
|
||||||
|
demand: ''
|
||||||
|
})
|
||||||
|
const rules = reactive<any>({
|
||||||
|
name: [{ required: true, message: 'Please enter the form information', trigger: 'blur' }],
|
||||||
|
mobile: [{ required: true, message: 'Please enter the form information', trigger: 'blur' }],
|
||||||
|
demand: [{ required: true, message: 'Please enter the form information', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const handleSubmit = async (formEl: any) => {
|
||||||
|
// 这里可编写提交逻辑,比如调用接口将form数据发送到后端
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid: any, fields: any) => {
|
||||||
|
if (valid) {
|
||||||
|
console.log('提交的数据:', form)
|
||||||
|
try {
|
||||||
|
const res = request.post('/go/api/:plat/v1/consult/apply', form)
|
||||||
|
console.log('用户列表:', res)
|
||||||
|
ElMessageBox.confirm('提交成功!', {
|
||||||
|
showCancelButton: false,
|
||||||
|
type: 'success',
|
||||||
|
confirmButtonClass: 'confirmButtonClass'
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// 提交成功后可关闭弹框
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 可在此处添加清空表单逻辑
|
||||||
|
form.name = ''
|
||||||
|
form.mobile = ''
|
||||||
|
form.demand = ''
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('请求失败:', error)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('error submit!', fields)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法用于外部控制弹框显示,比如在父组件中调用
|
||||||
|
defineExpose({
|
||||||
|
openDialog: () => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="less">
|
||||||
|
.confirmButtonClass {
|
||||||
|
display: flex;
|
||||||
|
padding: 16px 50px;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 0.5px solid var(--1060-ff, #1060ff);
|
||||||
|
color: var(--1060-ff, #1060ff);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirmButtonClass {
|
||||||
|
background: var(--1060-ff, #1060ff);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style scoped lang="less">
|
||||||
|
:deep(.el-dialog) {
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 50px 70px;
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 14px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__wrapper,
|
||||||
|
.el-textarea__inner {
|
||||||
|
display: flex;
|
||||||
|
padding: 18px 16px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
align-self: stretch;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 0.5px solid #b2b3b5;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 在你的全局样式文件中 */
|
||||||
|
|
||||||
|
.el-input__inner::placeholder,
|
||||||
|
.el-textarea__inner::placeholder {
|
||||||
|
color: var(--b-2-b-3-b-5, #b2b3b5);
|
||||||
|
text-align: left;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-textarea__inner {
|
||||||
|
min-height: 142px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-header {
|
||||||
|
font-size: 22px;
|
||||||
|
color: @text-color;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 30px;
|
||||||
|
|
||||||
|
.cancel-btn,
|
||||||
|
.confirm-btn {
|
||||||
|
display: flex;
|
||||||
|
width: 172px;
|
||||||
|
height: 57px;
|
||||||
|
padding: 16px 50px;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 0.5px solid var(--1060-ff, #1060ff);
|
||||||
|
color: var(--1060-ff, #1060ff);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-btn {
|
||||||
|
background: var(--1060-ff, #1060ff);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -98,7 +98,7 @@ const trainings = [
|
|||||||
}
|
}
|
||||||
.item-desc {
|
.item-desc {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: @font-size-sm;
|
font-size: @font-size-lg;
|
||||||
color: @text-color-secondary;
|
color: @text-color-secondary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,11 @@
|
|||||||
<div class="home-page">
|
<div class="home-page">
|
||||||
<!-- Banner 模块-->
|
<!-- Banner 模块-->
|
||||||
<BannerCarousel />
|
<BannerCarousel />
|
||||||
<!-- 核心价值模块-->
|
<!-- <!– 核心价值模块–>-->
|
||||||
<CoreValue />
|
<CoreValue />
|
||||||
<!-- 应用场景模块-->
|
<!-- <!– 应用场景模块–>-->
|
||||||
<UseCases />
|
<UseCases />
|
||||||
<!-- 全球服务模块-->
|
<!-- <!– 全球服务模块–>-->
|
||||||
<GlobalService />
|
<GlobalService />
|
||||||
<!-- 客户反馈模块-->
|
<!-- 客户反馈模块-->
|
||||||
<CustomerFeedback />
|
<CustomerFeedback />
|
||||||
@ -15,13 +15,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts" name="Home">
|
||||||
import BannerCarousel from './sections/BannerCarousel.vue'
|
import BannerCarousel from './sections/BannerCarousel.vue'
|
||||||
import CoreValue from './sections/CoreValue.vue'
|
import CoreValue from './sections/CoreValue.vue'
|
||||||
import UseCases from './sections/UseCases.vue'
|
import UseCases from './sections/UseCases.vue'
|
||||||
import GlobalService from './sections/GlobalService.vue'
|
import GlobalService from './sections/GlobalService.vue'
|
||||||
import CustomerFeedback from './sections/CustomerFeedback.vue'
|
import CustomerFeedback from './sections/CustomerFeedback.vue'
|
||||||
import Partners from './sections/Partners.vue'
|
import Partners from './sections/Partners.vue'
|
||||||
|
|
||||||
|
// 组件首次加载时触发(只执行1次)
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('Home 页面首次加载(未从缓存中恢复)')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 组件从缓存中激活时触发(每次返回页面执行)
|
||||||
|
onActivated(() => {
|
||||||
|
console.log('Home 页面从缓存中激活(缓存生效)')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 组件被缓存时触发(每次离开页面执行)
|
||||||
|
onDeactivated(() => {
|
||||||
|
console.log('Home 页面被缓存(缓存生效)')
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="banner">
|
<section class="banner">
|
||||||
<div class="banner-bg">
|
<div v-motion-fade-visible class="banner-bg">
|
||||||
<!-- 替换为实际背景图路径 -->
|
<!-- 替换为实际背景图路径 -->
|
||||||
<img src="https://images.health.ufutx.com/202506/12/e6ea04327d2b5dbd9e4ae441431018df.png" alt="Banner背景" />
|
<img src="https://images.health.ufutx.com/202506/12/e6ea04327d2b5dbd9e4ae441431018df.png" alt="Banner背景" />
|
||||||
</div>
|
</div>
|
||||||
@ -28,7 +28,7 @@
|
|||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts" name="BannerCarousel">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
const activeIndex = ref<number | null>(null)
|
const activeIndex = ref<number | null>(null)
|
||||||
@ -72,6 +72,7 @@ const newsList = [
|
|||||||
|
|
||||||
.banner-bg {
|
.banner-bg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 830px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|||||||
@ -1,150 +1,179 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="feedback-section">
|
<section class="feedback-section">
|
||||||
<div class="feedback-title">客户反馈</div>
|
<div class="feedback-title">客户反馈</div>
|
||||||
|
|
||||||
|
<!-- 跑马灯容器:去掉换行,强制内容单行显示 -->
|
||||||
<div class="feedback-list">
|
<div class="feedback-list">
|
||||||
<div v-for="(item, index) in feedbackList" :key="index" class="feedback-card">
|
<Marquee
|
||||||
<div class="avatar-container">
|
:duration="360"
|
||||||
<img :src="item.avatar" alt="avatar" class="avatar" />
|
:reverse="false"
|
||||||
|
repeatCount="3"
|
||||||
|
pause-on-hover
|
||||||
|
container-class="h-56 bg-white rounded-lg shadow-sm p-4"
|
||||||
|
>
|
||||||
|
<!-- 内容卡片:直接作为Marquee的子元素,不嵌套额外div -->
|
||||||
|
<div v-for="(item, index) in feedbackList[0]" :key="`${item.username}-${index}`" class="feedback-card">
|
||||||
|
<el-popover placement="right-end" title="" :width="320" trigger="hover" popper-class="custom-popover">
|
||||||
|
<template #default>
|
||||||
|
<div class="_userinfo">
|
||||||
|
<div class="_userPic"><img :src="item.avatar" alt="avatar" class="avatar" /></div>
|
||||||
|
<div class="_username">{{ item.username }}</div>
|
||||||
|
</div>
|
||||||
|
<TextGenerateEffect class="_comment" :words="item.feedback" />
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<div class="popover-container">
|
||||||
|
<div class="avatar-container">
|
||||||
|
<img :src="item.avatar" alt="avatar" class="avatar" />
|
||||||
|
</div>
|
||||||
|
<div class="feedback-info">
|
||||||
|
<p class="username">{{ item.username }}</p>
|
||||||
|
<p class="comment">{{ item.feedback }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
<div class="feedback-info">
|
</Marquee>
|
||||||
<p class="username">{{ item.username }}</p>
|
</div>
|
||||||
<p class="comment">{{ item.comment }}</p>
|
<div class="feedback-list" style="margin-top: 40px">
|
||||||
|
<Marquee
|
||||||
|
:duration="360"
|
||||||
|
:reverse="true"
|
||||||
|
repeatCount="3"
|
||||||
|
pause-on-hover
|
||||||
|
container-class="h-56 bg-white rounded-lg shadow-sm p-4"
|
||||||
|
>
|
||||||
|
<!-- 内容卡片:直接作为Marquee的子元素,不嵌套额外div -->
|
||||||
|
<div v-for="(item, index) in feedbackList[1]" :key="`${item.username}-${index}`" class="feedback-card">
|
||||||
|
<el-popover placement="right-end" title="" :width="320" trigger="hover" popper-class="custom-popover">
|
||||||
|
<template #default>
|
||||||
|
<div class="_userinfo">
|
||||||
|
<div class="_userPic"><el-image :src="item.avatar" alt="avatar" class="avatar" /></div>
|
||||||
|
<div class="_username">{{ item.username }}</div>
|
||||||
|
</div>
|
||||||
|
<TextGenerateEffect class="_comment" :words="item.feedback" />
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<div class="popover-container">
|
||||||
|
<div class="avatar-container">
|
||||||
|
<img :src="item.avatar" alt="avatar" class="avatar" />
|
||||||
|
</div>
|
||||||
|
<div class="feedback-info">
|
||||||
|
<p class="username">{{ item.username }}</p>
|
||||||
|
<p class="comment">{{ item.feedback }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Marquee>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// 模拟假数据(头像统一使用你提供的链接)
|
// 模拟假数据(头像统一使用你提供的链接)
|
||||||
const feedbackList = [
|
import Marquee from '@/components/Marquee.vue'
|
||||||
{
|
import TextGenerateEffect from '@/components/TextGenerateEffect.vue'
|
||||||
username: '章小样',
|
import { userFeedbacks } from '@/data/userFeedbacks.ts'
|
||||||
comment: '操作简单,容易上手',
|
// 添加泛型类型 T 表示数组元素的类型
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
function splitArrayRandomly<T>(arr: T[], ratio = 0.5): [T[], T[]] {
|
||||||
},
|
// 复制原数组避免修改
|
||||||
{
|
const shuffled = [...arr]
|
||||||
username: '章小样',
|
|
||||||
comment: '界面简约清晰,功能强大',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '预约操作简单方便,客户体验好评',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '操作简单,容易上手',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
// Fisher-Yates 洗牌算法
|
||||||
|
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1))
|
||||||
|
;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算分割点(默认为 50%)
|
||||||
|
const splitIndex = Math.round(shuffled.length * ratio)
|
||||||
|
|
||||||
|
// 分割数组
|
||||||
|
return [shuffled.slice(0, splitIndex), shuffled.slice(splitIndex)]
|
||||||
|
}
|
||||||
|
|
||||||
|
const feedbackList = reactive(splitArrayRandomly(userFeedbacks))
|
||||||
|
|
||||||
|
console.log('数组1:', feedbackList[0]) // 例如: [3, 7, 2, 5]
|
||||||
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
// 基础变量(可继承项目全局样式)
|
// 基础变量
|
||||||
@bg-color: #f9fbff;
|
@bg-color: #f9fbff;
|
||||||
@card-bg: #ffffff;
|
@card-bg: #ffffff;
|
||||||
@radius: 12px;
|
@radius: 12px;
|
||||||
@padding: 16px;
|
@padding: 16px;
|
||||||
@gap: 50px;
|
|
||||||
@avatar-size: 60px;
|
@avatar-size: 60px;
|
||||||
@subtext-color: #999;
|
@subtext-color: #999;
|
||||||
@transition: all 0.3s ease;
|
@transition: all 0.3s ease;
|
||||||
|
|
||||||
.feedback-section {
|
.feedback-section {
|
||||||
background-color: @bg-color;
|
background-color: @bg-color;
|
||||||
.px(100px);
|
padding: 0 0 100px 0; /* 改用标准padding写法,避免自定义.px()可能的问题 */
|
||||||
text-align: center;
|
text-align: center;
|
||||||
.pb(100px);
|
//background: bisque;
|
||||||
|
position: relative;
|
||||||
|
&&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 60px;
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
&&::before {
|
||||||
|
left: 100px;
|
||||||
|
background: linear-gradient(to right, #f9fbff, transparent);
|
||||||
|
}
|
||||||
.feedback-title {
|
.feedback-title {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: @text-color;
|
padding: 100px 0 60px;
|
||||||
.pb(60px);
|
|
||||||
.pt(100px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 跑马灯容器:关键修改——禁止换行,确保内容单行滚动
|
||||||
.feedback-list {
|
.feedback-list {
|
||||||
|
//width: 100vw;
|
||||||
|
max-width: 1820px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-left: 100px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
// 关键:强制水平布局,禁止换行
|
||||||
|
padding: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-direction: row; /* 明确水平方向 */
|
||||||
justify-content: center;
|
flex-wrap: nowrap; /* 禁止换行 */
|
||||||
gap: @gap;
|
overflow: hidden; /* 隐藏超出容器的部分 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 反馈卡片:固定宽度,确保排列整齐
|
||||||
.feedback-card {
|
.feedback-card {
|
||||||
display: flex;
|
.feedback-popper {
|
||||||
align-items: center;
|
border-radius: 320px !important;
|
||||||
padding: @padding;
|
}
|
||||||
|
width: 320px; /* 固定宽度,确保能在一行放下多个 */
|
||||||
|
//max-width: 320px;
|
||||||
|
flex-shrink: 0; /* 禁止收缩,保证宽度不变 */
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
background: var(--ffffff, #fff);
|
background: #fff;
|
||||||
transition: @transition;
|
//transition: @transition;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* 增加轻微阴影,提升视觉层次 */
|
||||||
|
margin-right: 50px;
|
||||||
|
cursor: pointer; /* 提示可交互 */
|
||||||
|
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); /* 卡片整体过渡 */
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: translateY(-4px);
|
transform: translateY(-4px);
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
}
|
}
|
||||||
|
.popover-container {
|
||||||
|
padding: @padding;
|
||||||
|
display: flex; /* 卡片内部水平排列头像和文字 */
|
||||||
|
flex-direction: row; /* 明确水平方向 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
.avatar-container {
|
.avatar-container {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
@ -154,33 +183,86 @@ const feedbackList = [
|
|||||||
height: @avatar-size;
|
height: @avatar-size;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
border: 2px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.feedback-info {
|
.feedback-info {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
max-width: calc(100% - @avatar-size - 12px); /* 限制文本区域宽度 */
|
||||||
|
|
||||||
.username {
|
.username {
|
||||||
font-size: 18px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: @text-color;
|
margin-bottom: 6px;
|
||||||
margin-bottom: 4px;
|
white-space: nowrap; /* 用户名不换行 */
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment {
|
.comment {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: @subtext-color;
|
color: @subtext-color;
|
||||||
line-height: 1.4;
|
line-height: 1.5;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2; /* 固定2行文本 */
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
/* 过渡动画:重点控制max-height */
|
||||||
|
max-height: 42px; /* 14px*1.5*2=42px(刚好2行高度) */
|
||||||
|
transition: max-height 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 响应式适配
|
// 响应式适配
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
.feedback-section {
|
||||||
|
padding: 0 20px 60px; /* 缩小移动端内边距 */
|
||||||
|
}
|
||||||
.feedback-card {
|
.feedback-card {
|
||||||
width: 100%;
|
width: 220px; /* 移动端缩小卡片宽度 */
|
||||||
max-width: 320px;
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.custom-popover {
|
||||||
|
/* 修改圆角(核心) */
|
||||||
|
border-radius: 18px !important; /* 根据需求调整数值,如8px、16px */
|
||||||
|
|
||||||
|
/* 可选:修改边框 */
|
||||||
|
border: 1px solid #e5e7eb !important;
|
||||||
|
|
||||||
|
/* 可选:修改阴影 */
|
||||||
|
box-shadow: 0 4px 16px rgba(79, 79, 79, 0.08) !important;
|
||||||
|
|
||||||
|
/* 可选:修改内部边距 */
|
||||||
|
padding: 22px !important;
|
||||||
|
|
||||||
|
._userinfo {
|
||||||
|
.flex();
|
||||||
|
align-items: center;
|
||||||
|
.mb(12px);
|
||||||
|
}
|
||||||
|
._userPic {
|
||||||
|
width: 62px;
|
||||||
|
height: 62px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 4px solid #f9fbff;
|
||||||
|
box-shadow: 0 0 16px rgba(49, 49, 49, 0.18);
|
||||||
|
.mr(10px);
|
||||||
|
}
|
||||||
|
._username {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: @text-color;
|
||||||
|
}
|
||||||
|
._comment {
|
||||||
|
font-size: 16px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
color: @text-color-secondary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
7
src/views/Home/sections/ReviewCard.vue
Normal file
7
src/views/Home/sections/ReviewCard.vue
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
||||||
@ -2,11 +2,25 @@
|
|||||||
<section class="scene-section">
|
<section class="scene-section">
|
||||||
<h2 class="scene-title">友福同享AI健康解决方案应用场景</h2>
|
<h2 class="scene-title">友福同享AI健康解决方案应用场景</h2>
|
||||||
<div class="scene-list">
|
<div class="scene-list">
|
||||||
<div v-for="(item, index) in sceneList" :key="index" class="scene-item">
|
<!-- 遍历场景项,通过selectedIndex控制默认选中状态 -->
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in sceneList"
|
||||||
|
:key="index"
|
||||||
|
class="scene-item"
|
||||||
|
:class="{ active: selectedIndex === index }"
|
||||||
|
@mouseenter="selectedIndex = index"
|
||||||
|
@mouseleave="
|
||||||
|
() => {
|
||||||
|
if (index !== defaultIndex) selectedIndex = defaultIndex
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
<div class="scene-inner">
|
<div class="scene-inner">
|
||||||
<img :src="item.icon" alt="场景图标" class="scene-icon" />
|
<div class="scene-content">
|
||||||
<p class="scene-name">{{ item.name }}</p>
|
<img :src="item.icon" alt="场景图标" class="scene-icon" />
|
||||||
<p class="scene-desc">{{ item.desc }}</p>
|
<p class="scene-name">{{ item.name }}</p>
|
||||||
|
<p class="scene-desc">{{ item.desc }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -14,33 +28,41 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
// 场景数据
|
||||||
const sceneList = [
|
const sceneList = [
|
||||||
{
|
{
|
||||||
name: '地区政府/社区健康服务',
|
name: '地区政府/社区健康服务',
|
||||||
desc: '提供社区健康管理解决方案,提升居民健康水平,降低医疗成本。',
|
desc: '提供社区健康管理解决方案,提升居民健康水平,降低医疗成本。',
|
||||||
icon: 'https://images.health.ufutx.com/202506/12/d2b5ca33bd970f64a6301fa75ae2eb22.png'
|
icon: 'https://images.health.ufutx.com/202506/30/87f66f9deca9c217d3f86d7d7c5d25c9.png'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '医院体检中心/健康管理机构',
|
name: '医院体检中心/健康管理机构',
|
||||||
desc: '智能化健康评估系统,提升体检效率,优化健康管理流程。',
|
desc: '智能化健康评估系统,提升体检效率,优化健康管理流程。',
|
||||||
icon: 'https://images.health.ufutx.com/202506/12/d2b5ca33bd970f64a6301fa75ae2eb22.png'
|
icon: 'https://images.health.ufutx.com/202506/30/32b9067c68fc706ab7596c621720f847.png'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '企业员工健康管理',
|
name: '企业员工健康管理', // 默认选中第3项(索引2)
|
||||||
desc: '降低企业医疗成本,提升员工健康与生产力。',
|
desc: '降低企业医疗成本,提升员工健康与生产力。',
|
||||||
icon: 'https://images.health.ufutx.com/202506/12/d2b5ca33bd970f64a6301fa75ae2eb22.png'
|
icon: 'https://images.health.ufutx.com/202506/30/1de2a31aa67aa92ed7c5d59de0936bbf.png'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '健康产业链供应商',
|
name: '健康产业链供应商',
|
||||||
desc: '连接健康产业上下游,提供精准数据分析和市场洞察。',
|
desc: '连接健康产业上下游,提供精准数据分析和市场洞察。',
|
||||||
icon: 'https://images.health.ufutx.com/202506/12/d2b5ca33bd970f64a6301fa75ae2eb22.png'
|
icon: 'https://images.health.ufutx.com/202506/30/ddbb65cf7004bb06982e0bbfa4e9bdb1.png'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '健康管理专业培训',
|
name: '健康管理专业培训',
|
||||||
desc: '提供专业健康管理培训课程,培养行业人才,提升服务质量。',
|
desc: '提供专业健康管理培训课程,培养行业人才,提升服务质量。',
|
||||||
icon: 'https://images.health.ufutx.com/202506/12/d2b5ca33bd970f64a6301fa75ae2eb22.png'
|
icon: 'https://images.health.ufutx.com/202506/30/0bc22b00e61752cab79bad46318a680c.png'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// 默认选中第3项(索引2)
|
||||||
|
const defaultIndex = 2
|
||||||
|
// 当前选中索引(响应式)
|
||||||
|
const selectedIndex = ref(defaultIndex)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@ -68,69 +90,88 @@ const sceneList = [
|
|||||||
.scene-item {
|
.scene-item {
|
||||||
width: 284px;
|
width: 284px;
|
||||||
height: 336px;
|
height: 336px;
|
||||||
perspective: 1000px; // 3D透视效果
|
perspective: 1000px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transform: translateZ(0); /* 硬件加速 */
|
||||||
|
|
||||||
|
// 激活状态(默认选中/悬停)共用样式
|
||||||
|
&.active .scene-inner,
|
||||||
|
&:hover .scene-inner {
|
||||||
|
//box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
//transform: translateY(-10px) scale(1.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active .scene-content,
|
||||||
|
&:hover .scene-content {
|
||||||
|
//background-color: #e6f0ff;
|
||||||
|
background: linear-gradient(180deg, #fff 0%, #ecf2ff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active .scene-icon,
|
||||||
|
&:hover .scene-icon {
|
||||||
|
transform: scale(1.1);
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active .scene-name,
|
||||||
|
&:hover .scene-name {
|
||||||
|
//color: @primary-color;
|
||||||
|
transform: translateY(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active .scene-desc,
|
||||||
|
&:hover .scene-desc {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
max-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
.scene-inner {
|
.scene-inner {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0px 16px;
|
//background-color: #fff;
|
||||||
|
background: linear-gradient(180deg, #fff 0%, #ecf2ff 100%);
|
||||||
|
border-radius: @border-radius-md;
|
||||||
|
overflow: hidden;
|
||||||
|
//box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||||
|
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16px;
|
padding: 40px 16px;
|
||||||
background: linear-gradient(180deg, #fff 0%, #ecf2ff 100%);
|
height: 100%;
|
||||||
border-radius: @border-radius-md;
|
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||||
transition: all 0.5s cubic-bezier(0.25, 0.8, 0.25, 1); // 平滑过渡
|
|
||||||
|
|
||||||
// 初始状态
|
|
||||||
.scene-icon {
|
|
||||||
width: 150px;
|
|
||||||
transition: all 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.scene-name {
|
|
||||||
font-size: @font-size-md;
|
|
||||||
font-weight: @font-weight-medium;
|
|
||||||
color: @text-color;
|
|
||||||
transition: all 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.scene-desc {
|
|
||||||
font-size: @font-size-sm;
|
|
||||||
color: @text-color-light;
|
|
||||||
line-height: 1.4;
|
|
||||||
max-height: 0;
|
|
||||||
opacity: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
||||||
margin-top: -10px; // 初始位置向上偏移
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 悬停状态
|
.scene-icon {
|
||||||
&:hover .scene-inner {
|
width: 150px;
|
||||||
transform: translateY(-10px) scale(1.05);
|
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||||
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
|
margin-bottom: 20px;
|
||||||
background: linear-gradient(180deg, #fff 0%, #e6f0ff 100%);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover .scene-icon {
|
.scene-name {
|
||||||
transform: scale(1.1);
|
font-size: @font-size-md;
|
||||||
margin-bottom: 8px;
|
font-weight: @font-weight-medium;
|
||||||
|
color: @text-color;
|
||||||
|
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover .scene-name {
|
.scene-desc {
|
||||||
color: @primary-color;
|
font-size: @font-size-sm;
|
||||||
transform: translateY(5px);
|
color: @text-color-secondary;
|
||||||
}
|
line-height: 1.4;
|
||||||
|
opacity: 0;
|
||||||
&:hover .scene-desc {
|
|
||||||
max-height: 100px;
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(10px);
|
transform: translateY(10px);
|
||||||
|
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,26 @@
|
|||||||
<section class="banner">
|
<section class="banner">
|
||||||
<div class="banner-bg">
|
<div class="banner-bg">
|
||||||
<!-- 替换为实际背景图路径 -->
|
<!-- 替换为实际背景图路径 -->
|
||||||
<img src="https://images.health.ufutx.com/202506/13/c963e7b0e605f16d139fb88789f3a452.png" alt="Banner背景" />
|
<el-image
|
||||||
|
v-motion-fade-visible
|
||||||
|
lazy
|
||||||
|
src="https://images.health.ufutx.com/202507/02/c963e7b0e605f16d139fb88789f3a452.png"
|
||||||
|
>
|
||||||
|
<template #placeholder>
|
||||||
|
<div class="placeholder-content">
|
||||||
|
<p>加载中...</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 加载失败的占位内容 -->
|
||||||
|
<template #error>
|
||||||
|
<div class="error-content">
|
||||||
|
<i class="el-icon-picture-outline" />
|
||||||
|
<p>图片加载失败</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
<!-- <img alt="Banner背景" />-->
|
||||||
</div>
|
</div>
|
||||||
<div class="news-panel">
|
<div class="news-panel">
|
||||||
<div
|
<div
|
||||||
@ -72,11 +91,12 @@ const newsList = [
|
|||||||
|
|
||||||
.banner-bg {
|
.banner-bg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 830px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,7 +161,21 @@ const newsList = [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
:deep(.el-image__placeholder) {
|
||||||
|
/* 关键:占满图片容器 */
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
background-color: red; /* 可选:添加背景色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义占位内容样式 */
|
||||||
|
.placeholder-content {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
// 响应式适配
|
// 响应式适配
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.banner-content {
|
.banner-content {
|
||||||
|
|||||||
@ -2,103 +2,103 @@
|
|||||||
<section class="feedback-section">
|
<section class="feedback-section">
|
||||||
<div class="feedback-title">真实客户案例</div>
|
<div class="feedback-title">真实客户案例</div>
|
||||||
<div class="feedback-list">
|
<div class="feedback-list">
|
||||||
<div v-for="(item, index) in feedbackList" :key="index" class="feedback-card">
|
<Marquee
|
||||||
<div class="avatar-container">
|
:duration="360"
|
||||||
<img :src="item.avatar" alt="avatar" class="avatar" />
|
:reverse="false"
|
||||||
|
repeatCount="3"
|
||||||
|
pause-on-hover
|
||||||
|
container-class="h-56 bg-white rounded-lg shadow-sm p-4"
|
||||||
|
:initial-offset="0"
|
||||||
|
>
|
||||||
|
<!-- 内容卡片:直接作为Marquee的子元素,不嵌套额外div -->
|
||||||
|
<div v-for="(item, index) in feedbackList[0]" :key="`${item.username}-${index}`" class="feedback-card">
|
||||||
|
<el-popover placement="right-end" :width="320" trigger="hover" popper-class="custom-popover">
|
||||||
|
<template #default>
|
||||||
|
<div class="_userinfo">
|
||||||
|
<div class="_userPic"><img :src="item.avatar" alt="avatar" class="avatar" /></div>
|
||||||
|
<div class="_username">{{ item.username }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="_comment">{{ item.case }}</div>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<div class="popover-container">
|
||||||
|
<div class="avatar-container">
|
||||||
|
<img :src="item.avatar" alt="avatar" class="avatar" />
|
||||||
|
</div>
|
||||||
|
<div class="feedback-info">
|
||||||
|
<!-- <p class="username">{{ item.username }}</p>-->
|
||||||
|
<p class="comment">{{ item.result }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
<div class="feedback-info">
|
</Marquee>
|
||||||
<!-- <p class="username">{{ item.username }}</p>-->
|
</div>
|
||||||
<p class="comment text-2-line-ellipsis">{{ item.comment }}</p>
|
<div class="feedback-list" style="margin-top: 40px">
|
||||||
|
<Marquee
|
||||||
|
:duration="360"
|
||||||
|
:reverse="false"
|
||||||
|
repeatCount="3"
|
||||||
|
pause-on-hover
|
||||||
|
container-class="h-56 bg-white rounded-lg shadow-sm p-4"
|
||||||
|
:initial-offset="-300"
|
||||||
|
>
|
||||||
|
<!-- 内容卡片:直接作为Marquee的子元素,不嵌套额外div -->
|
||||||
|
<div v-for="(item, index) in feedbackList[1]" :key="`${item.username}-${index}`" class="feedback-card">
|
||||||
|
<el-popover placement="right-end" :width="320" trigger="hover" popper-class="custom-popover">
|
||||||
|
<template #default>
|
||||||
|
<div class="_userinfo">
|
||||||
|
<div class="_userPic"><img :src="item.avatar" alt="avatar" class="avatar" /></div>
|
||||||
|
<div class="_username">{{ item.username }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="_comment">{{ item.case }}</div>
|
||||||
|
</template>
|
||||||
|
<template #reference>
|
||||||
|
<div class="popover-container">
|
||||||
|
<div class="avatar-container">
|
||||||
|
<img :src="item.avatar" alt="avatar" class="avatar" />
|
||||||
|
</div>
|
||||||
|
<div class="feedback-info">
|
||||||
|
<!-- <p class="username">{{ item.username }}</p>-->
|
||||||
|
<p class="comment">{{ item.result }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Marquee>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// 模拟假数据(头像统一使用你提供的链接)
|
// 模拟假数据(头像统一使用你提供的链接)
|
||||||
const feedbackList = [
|
// import TextGenerateEffect from '@/components/TextGenerateEffect.vue'
|
||||||
{
|
import Marquee from '@/components/Marquee.vue'
|
||||||
username: '章小样',
|
import { realCases } from '@/data/realCases.ts'
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
// 添加泛型类型 T 表示数组元素的类型
|
||||||
},
|
function splitArrayRandomly<T>(arr: T[], ratio = 0.5): [T[], T[]] {
|
||||||
{
|
// 复制原数组避免修改
|
||||||
username: '章小样',
|
const shuffled = [...arr]
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
// Fisher-Yates 洗牌算法
|
||||||
},
|
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||||
{
|
const j = Math.floor(Math.random() * (i + 1))
|
||||||
username: '章小样',
|
;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '预约操作简单方便,客户体验好评',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '章小样',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
username: '派小喵萌宠',
|
|
||||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
|
||||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
// 计算分割点(默认为 50%)
|
||||||
|
const splitIndex = Math.round(shuffled.length * ratio)
|
||||||
|
|
||||||
|
// 分割数组
|
||||||
|
return [shuffled.slice(0, splitIndex), shuffled.slice(splitIndex)]
|
||||||
|
}
|
||||||
|
|
||||||
|
const feedbackList = reactive(splitArrayRandomly(realCases))
|
||||||
|
|
||||||
|
console.log('数组1:', feedbackList[0]) // 例如: [3, 7, 2, 5]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@ -112,66 +112,114 @@ const feedbackList = [
|
|||||||
@subtext-color: #999;
|
@subtext-color: #999;
|
||||||
@transition: all 0.3s ease;
|
@transition: all 0.3s ease;
|
||||||
|
|
||||||
|
// 基础变量
|
||||||
|
@bg-color: #f9fbff;
|
||||||
|
@card-bg: #ffffff;
|
||||||
|
@radius: 12px;
|
||||||
|
@padding: 16px;
|
||||||
|
@avatar-size: 60px;
|
||||||
|
@subtext-color: #999;
|
||||||
|
@transition: all 0.3s ease;
|
||||||
|
|
||||||
.feedback-section {
|
.feedback-section {
|
||||||
background-color: @bg-color;
|
background-color: @bg-color;
|
||||||
.px(100px);
|
padding: 0 0 100px 0; /* 改用标准padding写法,避免自定义.px()可能的问题 */
|
||||||
text-align: center;
|
text-align: center;
|
||||||
.pb(100px);
|
//background: bisque;
|
||||||
|
position: relative;
|
||||||
|
&&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 60px;
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
&&::before {
|
||||||
|
left: 100px;
|
||||||
|
background: linear-gradient(to right, #f9fbff, transparent);
|
||||||
|
}
|
||||||
.feedback-title {
|
.feedback-title {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: @text-color;
|
padding: 100px 0 60px;
|
||||||
.pb(60px);
|
|
||||||
.pt(100px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 跑马灯容器:关键修改——禁止换行,确保内容单行滚动
|
||||||
.feedback-list {
|
.feedback-list {
|
||||||
|
//width: 100vw;
|
||||||
|
max-width: 1820px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-left: 100px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
// 关键:强制水平布局,禁止换行
|
||||||
|
padding: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-direction: row; /* 明确水平方向 */
|
||||||
justify-content: center;
|
flex-wrap: nowrap; /* 禁止换行 */
|
||||||
gap: @gap;
|
overflow: hidden; /* 隐藏超出容器的部分 */
|
||||||
}
|
}
|
||||||
|
// 反馈卡片:固定宽度,确保排列整齐
|
||||||
.feedback-card {
|
.feedback-card {
|
||||||
transition: @transition;
|
width: 362px; /* 固定宽度,确保能在一行放下多个 */
|
||||||
display: flex;
|
//max-width: 320px;
|
||||||
padding: 16px;
|
flex-shrink: 0; /* 禁止收缩,保证宽度不变 */
|
||||||
align-items: center;
|
|
||||||
gap: 20px;
|
|
||||||
border-radius: 100px;
|
border-radius: 100px;
|
||||||
background: #f3f5f7;
|
background: #f3f5f7;
|
||||||
|
//transition: @transition;
|
||||||
|
//box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* 增加轻微阴影,提升视觉层次 */
|
||||||
|
margin-right: 60px;
|
||||||
|
cursor: pointer; /* 提示可交互 */
|
||||||
|
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); /* 卡片整体过渡 */
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: translateY(-4px);
|
transform: translateY(-4px);
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
}
|
}
|
||||||
|
.popover-container {
|
||||||
|
padding: @padding;
|
||||||
|
display: flex; /* 卡片内部水平排列头像和文字 */
|
||||||
|
flex-direction: row; /* 明确水平方向 */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
.avatar-container {
|
.avatar-container {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
//margin-right: 12px;
|
margin-right: 20px;
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
width: @avatar-size;
|
width: @avatar-size;
|
||||||
height: @avatar-size;
|
height: @avatar-size;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
border: 2px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.feedback-info {
|
.feedback-info {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
max-width: calc(100% - @avatar-size - 12px); /* 限制文本区域宽度 */
|
||||||
|
|
||||||
.username {
|
.username {
|
||||||
font-size: 18px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: @text-color;
|
margin-bottom: 6px;
|
||||||
margin-bottom: 4px;
|
white-space: nowrap; /* 用户名不换行 */
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment {
|
.comment {
|
||||||
width: 250px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: @text-color;
|
color: @text-color;
|
||||||
line-height: 1.4;
|
line-height: 1.5;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2; /* 固定2行文本 */
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
/* 过渡动画:重点控制max-height */
|
||||||
|
max-height: 42px; /* 14px*1.5*2=42px(刚好2行高度) */
|
||||||
|
transition: max-height 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,3 +233,42 @@ const feedbackList = [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.custom-popover {
|
||||||
|
/* 修改圆角(核心) */
|
||||||
|
border-radius: 18px !important; /* 根据需求调整数值,如8px、16px */
|
||||||
|
|
||||||
|
/* 可选:修改边框 */
|
||||||
|
border: 1px solid #e5e7eb !important;
|
||||||
|
|
||||||
|
/* 可选:修改阴影 */
|
||||||
|
box-shadow: 0 4px 16px rgba(79, 79, 79, 0.08) !important;
|
||||||
|
|
||||||
|
/* 可选:修改内部边距 */
|
||||||
|
padding: 22px !important;
|
||||||
|
._userinfo {
|
||||||
|
.flex();
|
||||||
|
align-items: center;
|
||||||
|
.mb(12px);
|
||||||
|
}
|
||||||
|
._userPic {
|
||||||
|
width: 62px;
|
||||||
|
height: 62px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 4px solid #f3f5f7;
|
||||||
|
box-shadow: 0 0 16px rgba(79, 79, 79, 0.08);
|
||||||
|
.mr(10px);
|
||||||
|
}
|
||||||
|
._username {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: @text-color;
|
||||||
|
}
|
||||||
|
._comment {
|
||||||
|
font-size: 16px;
|
||||||
|
color: @text-color-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="core-value">
|
<section class="core-value">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- <h3 class="section-title">核心价值</h3>-->
|
<h3 class="section-title">友福七维AI健康修复体系</h3>
|
||||||
<!-- <p class="section-desc">友福同享AI健康解决方案应用场景</p>-->
|
<p class="section-desc">七大核心维度</p>
|
||||||
<!-- 替换为实际图示路径 -->
|
<!-- 替换为实际图示路径 -->
|
||||||
<img
|
<img
|
||||||
src="https://images.health.ufutx.com/202506/17/28710422aa9cf68a38cfbd19abd7ebf0.png"
|
src="https://images.health.ufutx.com/202507/02/37b46d4591aa3244f62320bd60e07549.png"
|
||||||
alt="七大核心维度"
|
alt="七大核心维度"
|
||||||
class="diagram"
|
class="diagram"
|
||||||
/>
|
/>
|
||||||
@ -32,12 +32,13 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
color: @text-color;
|
color: @text-color;
|
||||||
|
.mt(50px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-desc {
|
.section-desc {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
color: @text-color-secondary;
|
color: @text-color-secondary;
|
||||||
margin-bottom: 60px;
|
//margin-bottom: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.diagram {
|
.diagram {
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
>
|
>
|
||||||
<div class="scene-inner">
|
<div class="scene-inner">
|
||||||
<img :src="item.icon" alt="场景图标" class="scene-icon" />
|
<img :src="item.icon" alt="场景图标" class="scene-icon" />
|
||||||
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
<p class="scene-name" v-html="item.name"></p>
|
<p class="scene-name" v-html="item.name"></p>
|
||||||
<p v-if="activeIndex === index" class="scene-desc">{{ item.desc }}</p>
|
<p v-if="activeIndex === index" class="scene-desc">{{ item.desc }}</p>
|
||||||
</div>
|
</div>
|
||||||
@ -71,8 +72,8 @@ onMounted(() => {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: #f5f7fe;
|
background-color: #f5f7fe;
|
||||||
.pt(80+42px);
|
.pt(80+42px);
|
||||||
.pb(80-42px);
|
//.pb(80-42px);
|
||||||
|
height: 580px;
|
||||||
.scene-list {
|
.scene-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
|||||||
@ -1,65 +1,153 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="article-content">
|
<section class="article-content">
|
||||||
<!-- 文章头部信息 -->
|
<!-- 加载状态 -->
|
||||||
<div class="article-header">
|
<div v-if="loading" class="loading-container">
|
||||||
<h1 class="article-title">数字健康领域的长期主义者:未来医疗100强友福同享持续领跑</h1>
|
<p>加载中...</p>
|
||||||
<div class="meta-info">
|
</div>
|
||||||
<span>发布时间:2025-06-20</span>
|
|
||||||
<span>浏览次数:8604</span>
|
<!-- 错误状态 -->
|
||||||
|
<div v-else-if="error" class="error-container">
|
||||||
|
<p>加载失败,请稍后重试</p>
|
||||||
|
<button @click="fetchArticleDetail">重新加载</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文章内容(数据加载成功后显示) -->
|
||||||
|
<div v-else>
|
||||||
|
<!-- 文章头部信息 -->
|
||||||
|
<div class="article-header">
|
||||||
|
<h1 class="article-title">
|
||||||
|
<TextGenerateEffect :words="article.title" class="" />
|
||||||
|
</h1>
|
||||||
|
<div class="meta-info">
|
||||||
|
<span>发布时间:{{ article.create_time }}</span>
|
||||||
|
<span>浏览次数:{{ article.read_num }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 封面图 -->
|
<!-- 封面图 -->
|
||||||
<div class="article-banner">
|
<div v-motion-fade-visible class="article-banner">
|
||||||
<img src="https://images.health.ufutx.com/202506/20/9fd62f318b50764c02c58356dc426d44.png" alt="AI健康领域" />
|
<!-- <img :src="article.pic" alt="文章封面" class="banner-img" />-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 正文内容 -->
|
<!-- 正文内容(富文本渲染) -->
|
||||||
<div class="article-body">
|
|
||||||
<p>
|
|
||||||
《1分钟演讲》是一款创新的智能辅助应用,专注于强化公众演讲技能,助力用户高效构思并精准传达思想。它集演讲与实战练习于一体,为用户提供全方位、一站式的自我提升平台。1分钟演讲,这个看似简短却充满力量的表达方式,是真实自我与世界快速沟通的桥梁,也是能快速缩短社交距离、增进信任的神奇钥匙。无论是事业发展、社交拓展、寻找灵魂伴侣,还是个人品牌建设,这一功能都能成为你强而有力的社交工具,帮助你快速脱颖而出,让更多人认识并记住你。友福同享凭借多年在全病程管理、“AI+医疗”领域的卓越成就,稳列未来医疗100强榜单第一梯队!同时,微脉自主研发的CareAI荣膺最佳数字技术产品,获2025未来医疗100强创新奖。
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||||
「未来医疗100强」榜单以前瞻性、专业性和国际视野为核心,被誉为“医疗创新领域的风向标”,代表未来5-10年全球医疗产业的新势力与变革方向。
|
<div class="article-body" v-html="article.content"></div>
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
“让医疗服务不再难”
|
|
||||||
是微脉始终如一的使命。微脉从全人群、全方位、全周期出发,专攻医疗服务的现有之短板和就医者的健康服务需求缺口,补足诊后、检后、术后、院后管理空白。
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
在突破医疗健康行业各阶段难点,拓展数字健康领域可能性上,微脉做了许多从0到1的创造和尝试✨,致力于打造中国特色的管理式医疗健康组织(C-CMO)。
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
未来,友福同享将持续深化"AI+全病程管理"创新模式,助力公立医院高质量发展,加快构建"预防-诊疗-康复"全周期健康服务生态,让优质医疗服务惠及更多百姓。
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// 若需动态加载,可在此处通过接口请求数据
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import request from '@/utils/request' // 假设已有封装的axios实例
|
||||||
|
import TextGenerateEffect from '@/components/TextGenerateEffect.vue'
|
||||||
|
|
||||||
|
// 路由参数获取(从URL中提取:plat和:id)
|
||||||
|
const route = useRoute()
|
||||||
|
// const plat = route.params.plat as string // 平台标识(如"default")
|
||||||
|
const articleId = route.params.id as string // 文章ID
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const loading = ref(true) // 加载状态
|
||||||
|
const error = ref(false) // 错误状态
|
||||||
|
const article = ref({
|
||||||
|
title: '', // 文章标题
|
||||||
|
create_time: '', // 发布时间(格式:YYYY-MM-DD)
|
||||||
|
read_num: 0, // 浏览次数
|
||||||
|
pic: '', // 封面图URL
|
||||||
|
content: '' // 正文内容(HTML格式)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 从接口获取文章详情
|
||||||
|
const fetchArticleDetail = async () => {
|
||||||
|
loading.value = true
|
||||||
|
error.value = false
|
||||||
|
try {
|
||||||
|
// 接口请求(拼接plat和id参数)
|
||||||
|
const res = await request.get(`/go/api/:plat/v1/article/${articleId}/detail`)
|
||||||
|
|
||||||
|
// 假设接口返回格式:{ code: 0, data: { title, publishTime, views, cover, content } }
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
const data = res.data
|
||||||
|
// 赋值到响应式变量
|
||||||
|
article.value = data
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message || '获取文章详情失败')
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error('文章详情请求失败:', err)
|
||||||
|
error.value = true
|
||||||
|
ElMessage.error(err.message || '加载失败,请重试')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面挂载时请求数据
|
||||||
|
onMounted(() => {
|
||||||
|
fetchArticleDetail()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.article-content {
|
.article-content {
|
||||||
padding: 200px 192px 100px 192px;
|
padding: 200px 192px 100px;
|
||||||
//max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
// 标题区域
|
max-width: 1920px;
|
||||||
|
|
||||||
|
// 加载状态样式
|
||||||
|
.loading-container {
|
||||||
|
min-height: 500px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: @text-color-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误状态样式
|
||||||
|
.error-container {
|
||||||
|
min-height: 500px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
color: #f56c6c;
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 6px 16px;
|
||||||
|
border: 1px solid @primary-color;
|
||||||
|
color: @primary-color;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: @primary-color;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文章头部
|
||||||
.article-header {
|
.article-header {
|
||||||
padding-bottom: 30px;
|
padding-bottom: 30px;
|
||||||
border-bottom: 0.3px solid #b5b5b5;
|
border-bottom: 0.3px solid #b5b5b5;
|
||||||
|
|
||||||
.article-title {
|
.article-title {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: @text-color;
|
color: @text-color;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
line-height: 32px;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.meta-info {
|
.meta-info {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: @text-color-secondary;
|
color: @text-color-secondary;
|
||||||
@ -75,7 +163,8 @@
|
|||||||
// 封面图
|
// 封面图
|
||||||
.article-banner {
|
.article-banner {
|
||||||
margin: 30px 0;
|
margin: 30px 0;
|
||||||
img {
|
|
||||||
|
.banner-img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -83,28 +172,52 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 正文排版
|
// 正文内容(富文本样式适配)
|
||||||
.article-body {
|
.article-body {
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 35px;
|
||||||
p {
|
p {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #666;
|
color: #666;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
text-indent: 2em; // 首行缩进(可选)
|
text-indent: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 适配富文本中的图片
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 适配富文本中的标题
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
margin: 24px 0 16px;
|
||||||
|
color: @text-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 响应式适配
|
// 响应式适配
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
padding: 40px 20px;
|
padding: 40px 20px;
|
||||||
|
|
||||||
.article-header {
|
.article-header {
|
||||||
.article-title {
|
.article-title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
.meta-info {
|
||||||
|
font-size: 14px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.article-body {
|
.article-body {
|
||||||
p {
|
p {
|
||||||
text-indent: 0; // 移动端取消缩进
|
text-indent: 0;
|
||||||
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,131 +1,198 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 整体布局:导航 + Banner + 内容 + 页脚 -->
|
|
||||||
<div class="page-container">
|
<div class="page-container">
|
||||||
<!-- 已有Banner组件(保持设计中的顶部视觉) -->
|
<!-- 已有Banner组件 -->
|
||||||
<BannerCarousel />
|
<BannerCarousel />
|
||||||
|
|
||||||
<!-- 核心内容区 -->
|
<!-- 核心内容区 -->
|
||||||
<div class="news-content">
|
<div class="news-content">
|
||||||
<!-- 标签切换(友福动态 / 媒体报道) -->
|
<!-- 标签切换(动态加载) -->
|
||||||
<el-tabs v-model="activeTab" class="news-tabs" @tab-click="resetPage">
|
<el-tabs v-model="activeTab" class="news-tabs" @tab-change="resetPage">
|
||||||
<el-tab-pane label="友福动态" name="dynamic"></el-tab-pane>
|
<el-tab-pane v-for="item in categories" :key="item.name" :label="item.name" :name="item.name">
|
||||||
<el-tab-pane label="媒体报道" name="report"></el-tab-pane>
|
<template #label>
|
||||||
|
<div class="categories-label">{{ item.name }}</div>
|
||||||
|
</template>
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
<!-- 新闻列表 -->
|
<!-- 新闻列表(数据加载后显示) -->
|
||||||
<div class="news-list">
|
<div v-if="!loading && newsData.length > 0" class="news-list">
|
||||||
<div v-for="(item, idx) in filteredNews" :key="idx" class="news-item">
|
<div v-for="(item, idx) in filteredNews" :key="idx" class="news-item">
|
||||||
<img :src="item.cover" alt="新闻封面" class="news-cover" />
|
<img :src="item.pic" alt="image" class="news-cover" />
|
||||||
<div class="news-info">
|
<div class="news-info">
|
||||||
<h3 class="news-title">{{ item.title }}</h3>
|
<h3 class="news-title">{{ item.title }}</h3>
|
||||||
<h3 class="news-label">友福新闻</h3>
|
<h3 class="news-label">{{ item.publisher }}</h3>
|
||||||
<div class="news-wrap" @click="goToArticle">
|
<div class="news-wrap" @click="openArticleInNewWindow(item.id)">
|
||||||
<div class="view-btn">查看详情</div>
|
<div class="view-btn">查看详情</div>
|
||||||
<div class="news-date">
|
<div class="news-date">
|
||||||
<img
|
<img
|
||||||
class="icon"
|
class="icon"
|
||||||
src="https://images.health.ufutx.com/202506/13/c5e3552a870fd254610290bbabce5e30.png"
|
src="https://images.health.ufutx.com/202506/13/c5e3552a870fd254610290bbabce5e30.png"
|
||||||
/>
|
/>
|
||||||
<p>{{ item.date }}</p>
|
<p>{{ item.create_time }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 无数据时显示占位图(加载完成且数据为空) -->
|
||||||
<!-- 分页(Element Plus 分页组件) -->
|
<div v-else-if="!loading && newsData.length === 0" class="empty-state">
|
||||||
|
<img
|
||||||
|
src="https://images.health.ufutx.com/202507/02/259f20509b57b36199ef7619f8d63733.png"
|
||||||
|
alt="暂无数据"
|
||||||
|
class="empty-img"
|
||||||
|
/>
|
||||||
|
<p class="empty-text">暂无内容</p>
|
||||||
|
</div>
|
||||||
|
<!-- 加载状态 -->
|
||||||
|
<div v-else class="loading-container">
|
||||||
|
<!-- <el-spinner size="large"></el-spinner>-->
|
||||||
|
<p>加载中...</p>
|
||||||
|
</div>
|
||||||
|
<!-- 分页 -->
|
||||||
<div class="pagination-wrap">
|
<div class="pagination-wrap">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page="currentPage"
|
:current-page="currentPage"
|
||||||
:page-sizes="[10, 20, 50]"
|
:page-sizes="[10, 20, 50]"
|
||||||
:page-size="pageSize"
|
:page-size="pageSize"
|
||||||
layout="total, sizes, prev, pager, next, jumper"
|
background
|
||||||
|
layout="total,prev, pager, next"
|
||||||
:total="totalCount"
|
:total="totalCount"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handlePageChange"
|
@current-change="handlePageChange"
|
||||||
></el-pagination>
|
>
|
||||||
|
</el-pagination>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
// 引入已有组件(需确保路径正确)
|
import { ElMessage } from 'element-plus'
|
||||||
import BannerCarousel from '@/views/News/sections/BannerCarousel.vue'
|
import BannerCarousel from '@/views/News/sections/BannerCarousel.vue'
|
||||||
|
import request from '@/utils/request' // 假设已有请求工具函数
|
||||||
|
|
||||||
// 模拟新闻数据(根据设计图,友福动态和媒体报道的差异)
|
// 路由相关
|
||||||
const dynamicNews = [
|
// import { useRoute, useRouter } from 'vue-router'
|
||||||
{
|
import { openNewWindow } from '@/utils/navigation.ts'
|
||||||
cover: 'https://images.health.ufutx.com/202506/13/b604685780bdb4ea4906e751b14590ec.png', // 替换为实际封面图
|
|
||||||
title: '体管理年:政策驱动,AI+全利管理重塑健康服务体系...',
|
|
||||||
date: '2025-06-02',
|
|
||||||
type: 'dynamic'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cover: 'https://images.health.ufutx.com/202506/13/73e74b753e7fc7c8b00cecc0535a6a91.png',
|
|
||||||
title: '权威媒体专访:友福同享的创新健康生态',
|
|
||||||
date: '2025-05-30',
|
|
||||||
type: 'report'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const reportNews = [
|
|
||||||
{
|
|
||||||
cover: 'https://images.health.ufutx.com/202506/13/73e74b753e7fc7c8b00cecc0535a6a91.png',
|
|
||||||
title: '媒体报道:友福同享如何用AI颠覆健康管理?',
|
|
||||||
date: '2025-06-01',
|
|
||||||
type: 'report'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
// 循环添加数据到两个数组
|
// const route = useRoute()
|
||||||
for (let i = 0; i < 15; i++) {
|
// const router = useRouter()
|
||||||
const newsItem = {
|
|
||||||
cover: 'https://images.health.ufutx.com/202506/13/b604685780bdb4ea4906e751b14590ec.png',
|
|
||||||
title: `友福动态:健康管理服务升级发布会圆满成功 ${i + 1}`,
|
|
||||||
date: `2025-05-${28 - i}`,
|
|
||||||
type: 'dynamic'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 同时添加到两个数组
|
|
||||||
dynamicNews.push(newsItem)
|
|
||||||
reportNews.push({ ...newsItem, type: 'report' }) // 复制对象并修改 type
|
|
||||||
}
|
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
const activeTab = ref('dynamic') // 默认显示“友福动态”
|
const activeTab = ref('') // 激活标签
|
||||||
const currentPage = ref(1)
|
const currentPage = ref(1) // 当前页码
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(15) // 每页条数
|
||||||
const totalCount = ref(502) // 设计图中的“共502条”
|
const totalCount = ref(0) // 总数据量
|
||||||
|
const loading = ref(false) // 加载状态
|
||||||
|
const categories = ref<Array<any>>([]) // 标签分类
|
||||||
|
const newsData = ref<Array<any>>([]) // 新闻数据
|
||||||
|
|
||||||
// 计算当前显示的新闻(根据标签切换)
|
// 计算当前显示的新闻(带分页)
|
||||||
const filteredNews = computed(() => {
|
const filteredNews = computed(() => {
|
||||||
const list = activeTab.value === 'dynamic' ? dynamicNews : reportNews
|
|
||||||
// 模拟分页截取(实际需结合后端接口)
|
|
||||||
const start = (currentPage.value - 1) * pageSize.value
|
const start = (currentPage.value - 1) * pageSize.value
|
||||||
return list.slice(start, start + pageSize.value)
|
return newsData.value.slice(start, start + pageSize.value)
|
||||||
})
|
})
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
|
|
||||||
// 1. 初始化路由实例
|
// 跳转详情页(携带文章ID)
|
||||||
const router = useRouter()
|
const openArticleInNewWindow = (id: number) => {
|
||||||
|
openNewWindow(`/articleDetail/${id}`)
|
||||||
// 2. 跳转方法(命名路由方式,需提前配置路由)
|
|
||||||
const goToArticle = () => {
|
|
||||||
router.push({
|
|
||||||
path: '/news/12' // 也可直接写路径
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取标签分类列表
|
||||||
|
const fetchCategories = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
// 从接口获取标签分类(:plat从路由参数获取)
|
||||||
|
const res = await request.get(`/go/api/:plat/v1/article/category/list`)
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
categories.value = res.data || []
|
||||||
|
// 设置默认激活标签(如果有数据)
|
||||||
|
if (categories.value.length > 0) {
|
||||||
|
activeTab.value = categories.value[0].name
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || '获取分类失败')
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('获取分类列表失败', error)
|
||||||
|
ElMessage.error('网络错误,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取新闻列表数据
|
||||||
|
const fetchNewsList = async (category_id: string, page: number) => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
// 接口参数(type根据标签分类传递)
|
||||||
|
const params = {
|
||||||
|
category_id: category_id,
|
||||||
|
page
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用新闻列表接口
|
||||||
|
const res = await request.get(`/go/api/:plat/v1/article/list`, params)
|
||||||
|
|
||||||
|
if (res.code === 0) {
|
||||||
|
newsData.value = res.data.data || []
|
||||||
|
console.log(newsData.value)
|
||||||
|
totalCount.value = res.data.total_count || 0
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || '获取新闻失败')
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('获取新闻列表失败', error)
|
||||||
|
ElMessage.error('网络错误,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标签切换时重置页码并加载数据
|
||||||
|
const resetPage = () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
if (activeTab.value) {
|
||||||
|
loadNewsData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载新闻数据(整合标签和分页参数)
|
||||||
|
const loadNewsData = () => {
|
||||||
|
if (!activeTab.value) return
|
||||||
|
// 假设标签分类的name对应新闻接口的type参数
|
||||||
|
console.log(activeTab.value)
|
||||||
|
const category = categories.value.find(item => item.name === activeTab.value)
|
||||||
|
if (category) {
|
||||||
|
fetchNewsList(category.id || '', currentPage.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 分页事件
|
// 分页事件
|
||||||
const handleSizeChange = (val: number) => {
|
const handleSizeChange = (val: number) => {
|
||||||
pageSize.value = val
|
pageSize.value = val
|
||||||
currentPage.value = 1
|
currentPage.value = 1
|
||||||
|
loadNewsData()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePageChange = (val: number) => {
|
const handlePageChange = (val: number) => {
|
||||||
currentPage.value = val
|
currentPage.value = val
|
||||||
|
loadNewsData()
|
||||||
}
|
}
|
||||||
const resetPage = () => {
|
|
||||||
currentPage.value = 1 // 切换标签时重置页码
|
// 组件挂载时加载分类和新闻数据
|
||||||
}
|
onMounted(async () => {
|
||||||
|
await fetchCategories()
|
||||||
|
if (activeTab.value) {
|
||||||
|
loadNewsData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听标签切换,重新加载数据
|
||||||
|
// watch(activeTab, () => {
|
||||||
|
// loadNewsData()
|
||||||
|
// })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@ -136,18 +203,32 @@ const resetPage = () => {
|
|||||||
background-color: @bg-color;
|
background-color: @bg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 内容区容器 */
|
|
||||||
.news-content {
|
.news-content {
|
||||||
max-width: 1920px;
|
max-width: 1920px;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载状态样式 */
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 300px;
|
||||||
|
color: @text-color-secondary;
|
||||||
|
|
||||||
|
.el-spinner {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 标签切换样式(还原设计的蓝色下划线) */
|
/* 标签切换样式(还原设计的蓝色下划线) */
|
||||||
.news-tabs {
|
.news-tabs {
|
||||||
.pt(50px);
|
padding-top: 50px;
|
||||||
//align-items: center;
|
.categories-label {
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
:deep(.el-tabs__nav-wrap) {
|
:deep(.el-tabs__nav-wrap) {
|
||||||
//margin-bottom: 1.04167vw;
|
|
||||||
&:after {
|
&:after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -169,7 +250,10 @@ const resetPage = () => {
|
|||||||
|
|
||||||
:deep(.el-tabs__header) {
|
:deep(.el-tabs__header) {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
.el-tabs__nav {
|
.el-tabs__nav {
|
||||||
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
|
||||||
@ -184,34 +268,43 @@ const resetPage = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.news-tabs {
|
// 响应式适配
|
||||||
// 关键:让选项卡居中
|
@media (max-width: @tablet-breakpoint) {
|
||||||
:deep(.el-tabs__header) {
|
:deep(.el-tabs__item) {
|
||||||
width: 100%; // 占满容器宽度,为居中提供基础
|
margin-right: @space-md;
|
||||||
.el-tabs__nav {
|
font-size: @font-size-lg;
|
||||||
justify-content: center; // 水平居中对齐
|
}
|
||||||
|
|
||||||
|
:deep(.el-tabs__active-bar) {
|
||||||
|
bottom: -15px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: @mobile-breakpoint) {
|
||||||
|
:deep(.el-tabs__item) {
|
||||||
|
margin-right: @space-sm;
|
||||||
|
font-size: @font-size-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tabs__active-bar) {
|
||||||
|
bottom: -10px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 新闻列表 */
|
/* 新闻列表 */
|
||||||
.news-list {
|
.news-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 50px;
|
gap: 50px;
|
||||||
.px(192px);
|
padding: 100px 192px 0;
|
||||||
.pt(100px);
|
|
||||||
|
|
||||||
.news-item {
|
.news-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
transition: @transition;
|
|
||||||
border-bottom: 0.3px solid #b5b5b5;
|
border-bottom: 0.3px solid #b5b5b5;
|
||||||
.pb(50px);
|
padding-bottom: 50px;
|
||||||
&:hover {
|
|
||||||
//box-shadow: @shadow-hover;
|
|
||||||
//transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-cover {
|
.news-cover {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
@ -220,19 +313,12 @@ const resetPage = () => {
|
|||||||
border-radius: @border-radius-md;
|
border-radius: @border-radius-md;
|
||||||
margin-right: 30px;
|
margin-right: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.news-info {
|
.news-info {
|
||||||
.news-wrap {
|
|
||||||
.flex-between();
|
|
||||||
}
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.pt(20px);
|
padding-top: 20px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
.news-label {
|
|
||||||
font-size: @font-size-sm;
|
|
||||||
color: @text-color-secondary;
|
|
||||||
.mt(13px);
|
|
||||||
.mb(76px);
|
|
||||||
}
|
|
||||||
.news-title {
|
.news-title {
|
||||||
font-size: @font-size-lg;
|
font-size: @font-size-lg;
|
||||||
font-weight: @font-weight-medium;
|
font-weight: @font-weight-medium;
|
||||||
@ -240,231 +326,184 @@ const resetPage = () => {
|
|||||||
margin-bottom: @space-sm;
|
margin-bottom: @space-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
.news-date {
|
.news-label {
|
||||||
font-size: @font-size-sm;
|
font-size: @font-size-sm;
|
||||||
color: @text-color-light;
|
color: @text-color-secondary;
|
||||||
display: flex; // 启用 Flex 布局
|
margin-top: 13px;
|
||||||
align-items: center; // 子元素垂直居中
|
margin-bottom: 76px;
|
||||||
gap: 8px;
|
}
|
||||||
.icon {
|
|
||||||
width: 18px;
|
.news-wrap {
|
||||||
height: 18px;
|
display: flex;
|
||||||
object-fit: contain;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.view-btn {
|
||||||
|
padding: 6px 16px;
|
||||||
|
color: @primary-dark;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--1060-ff, #1060ff);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-date {
|
||||||
|
font-size: @font-size-sm;
|
||||||
|
color: @text-color-secondary;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.view-btn {
|
}
|
||||||
display: flex;
|
}
|
||||||
padding: 6px 16px;
|
|
||||||
justify-content: center;
|
// 响应式适配
|
||||||
align-items: center;
|
@media (max-width: @tablet-breakpoint) {
|
||||||
gap: 10px;
|
padding: @space-xl @space-md 0;
|
||||||
color: @primary-dark;
|
|
||||||
border-radius: 4px;
|
.news-item {
|
||||||
border: 1px solid var(--1060-ff, #1060ff);
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: @space-lg;
|
||||||
|
|
||||||
|
.news-cover {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: @space-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-info .news-wrap {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: @space-sm;
|
||||||
|
|
||||||
|
.view-btn {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-date {
|
||||||
|
order: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: @mobile-breakpoint) {
|
||||||
|
padding: @space-lg @space-md 0;
|
||||||
|
gap: @space-xl;
|
||||||
|
|
||||||
|
.news-item {
|
||||||
|
padding-bottom: @space-lg;
|
||||||
|
|
||||||
|
.news-cover {
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-info .news-title {
|
||||||
|
font-size: @font-size-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-info .news-label {
|
||||||
|
margin-bottom: @space-md;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//// Less 样式
|
|
||||||
//.vertical-center {
|
|
||||||
// display: flex; // 启用 Flex 布局
|
|
||||||
// align-items: center; // 子元素垂直居中
|
|
||||||
// gap: 8px; // 图标与文字的间距(替代 margin,更优雅)
|
|
||||||
//
|
|
||||||
// .center-icon {
|
|
||||||
// width: 20px; // 图标尺寸
|
|
||||||
// height: 20px;
|
|
||||||
// object-fit: contain; // 保持图标比例,避免拉伸
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// .center-text {
|
|
||||||
// font-size: @font-size-sm; // 继承全局变量
|
|
||||||
// color: @text-color-light;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
/* 分页样式 */
|
/* 分页样式 */
|
||||||
.pagination-wrap {
|
.pagination-wrap {
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
.pb(170px);
|
padding-bottom: 170px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
:deep(.el-pager li.is-active) {
|
:deep(.el-pager li.is-active) {
|
||||||
color: @primary-dark;
|
color: @primary-dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-pagination {
|
.el-pagination {
|
||||||
.el-pagination__total {
|
.el-pagination__total {
|
||||||
color: @text-color-light;
|
color: @text-color-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-pager li {
|
.el-pager li.active {
|
||||||
&.active {
|
background-color: @primary-color;
|
||||||
background-color: @primary-color;
|
color: #fff;
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-pagination__sizes {
|
.el-pagination__sizes {
|
||||||
margin: 0 @space-md;
|
margin: 0 @space-md;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式适配(平板以下) */
|
// 响应式适配
|
||||||
//@media (max-width: @tablet-breakpoint) {
|
@media (max-width: @mobile-breakpoint) {
|
||||||
// .news-item {
|
|
||||||
// flex-direction: column;
|
|
||||||
// align-items: flex-end;
|
|
||||||
// .news-cover {
|
|
||||||
// width: 100%;
|
|
||||||
// height: auto;
|
|
||||||
// margin: 0 0 @space-md 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
/* 响应式适配(细分平板和手机端) */
|
|
||||||
@media (max-width: @tablet-breakpoint) {
|
|
||||||
/* 平板端(768px-1024px)适配 */
|
|
||||||
.news-content {
|
|
||||||
padding: @space-xl @space-md; // 减少两侧边距
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-tabs {
|
|
||||||
:deep(.el-tabs__item) {
|
|
||||||
margin-right: @space-md; // 减少标签间距
|
|
||||||
font-size: @font-size-lg; // 缩小标签字体
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-tabs__active-bar) {
|
|
||||||
bottom: -15px !important; // 调整下划线位置
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-list {
|
|
||||||
.px(@space-lg); // 减少新闻列表左右边距
|
|
||||||
.pt(@space-xl); // 调整顶部间距
|
|
||||||
|
|
||||||
.news-item {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start; // 左对齐
|
|
||||||
gap: @space-lg; // 增加内容间距
|
|
||||||
|
|
||||||
.news-cover {
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
margin-bottom: @space-lg; // 图片与文字间距
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-info {
|
|
||||||
.news-title {
|
|
||||||
font-size: @font-size-md; // 缩小标题字体
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-label {
|
|
||||||
.mb(@space-md); // 调整标签间距
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-wrap {
|
|
||||||
flex-direction: column; // 日期和按钮垂直排列
|
|
||||||
gap: @space-sm; // 增加间距
|
|
||||||
|
|
||||||
.view-btn {
|
|
||||||
align-self: flex-start; // 按钮左对齐
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-date {
|
|
||||||
order: -1; // 日期显示在按钮上方
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.pagination-wrap {
|
|
||||||
.el-pagination {
|
|
||||||
.el-pagination__sizes {
|
|
||||||
margin: 0 @space-sm; // 缩小尺寸选择器间距
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: @mobile-breakpoint) {
|
|
||||||
/* 手机端(<768px)适配 */
|
|
||||||
.news-content {
|
|
||||||
padding: @space-lg; // 进一步减少边距
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-tabs {
|
|
||||||
:deep(.el-tabs__item) {
|
|
||||||
margin-right: @space-sm; // 标签间距最小化
|
|
||||||
font-size: @font-size-md; // 手机端标签字体
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-tabs__active-bar) {
|
|
||||||
bottom: -10px !important; // 调整下划线位置
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-list {
|
|
||||||
.px(@space-md); // 最小化左右边距
|
|
||||||
gap: @space-xl; // 新闻项间距适中
|
|
||||||
|
|
||||||
.news-item {
|
|
||||||
.pb(@space-lg); // 减少底部边距
|
|
||||||
|
|
||||||
.news-cover {
|
|
||||||
height: 180px; // 固定图片高度
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-info {
|
|
||||||
.news-title {
|
|
||||||
font-size: @font-size-md; // 标题字体
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-label {
|
|
||||||
.mb(@space-md); // 标签间距
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-wrap {
|
|
||||||
.view-btn {
|
|
||||||
width: 80px; // 缩小按钮宽度
|
|
||||||
padding: @space-xs @space-sm; // 按钮内边距
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-date {
|
|
||||||
font-size: @font-size-xs; // 最小化日期字体
|
|
||||||
.icon {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 分页组件适配 */
|
|
||||||
.pagination-wrap {
|
|
||||||
.el-pagination {
|
.el-pagination {
|
||||||
.el-pagination__total {
|
.el-pagination__total {
|
||||||
font-size: @font-size-xs; // 缩小总条数字体
|
font-size: @font-size-xs;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-pager li {
|
.el-pager li {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
line-height: 28px;
|
line-height: 28px;
|
||||||
font-size: @font-size-xs; // 页码字体
|
font-size: @font-size-xs;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-pagination__sizes {
|
.el-pagination__sizes {
|
||||||
margin: 0 @space-xs; // 尺寸选择器间距
|
margin: 0 @space-xs;
|
||||||
|
|
||||||
.el-input {
|
.el-input {
|
||||||
font-size: @font-size-xs; // 下拉框字体
|
font-size: @font-size-xs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 无数据占位图样式
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 100px 0; // 与列表区域上下间距保持一致
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.empty-img {
|
||||||
|
width: 300px; // 调整占位图宽度(根据实际图片比例)
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
opacity: 0.8; // 轻微降低透明度,避免过于突兀
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 20px;
|
||||||
|
color: @text-color-secondary;
|
||||||
|
.mt(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式适配
|
||||||
|
@media (max-width: @mobile-breakpoint) {
|
||||||
|
.empty-img {
|
||||||
|
width: 200px; // 移动端缩小图片
|
||||||
|
}
|
||||||
|
.empty-text {
|
||||||
|
font-size: @font-size-md;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pagination {
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-pager li.is-active) {
|
||||||
|
background-color: #1665fc !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<section class="banner">
|
<section class="banner">
|
||||||
<div class="banner-bg">
|
<div v-motion-fade-visible class="banner-bg">
|
||||||
<!-- 替换为实际背景图路径 -->
|
<!-- 替换为实际背景图路径 -->
|
||||||
<img src="https://images.health.ufutx.com/202506/13/25aeff6e015162aeb316983d8bd61558.png" alt="Banner背景" />
|
<img src="https://images.health.ufutx.com/202506/13/25aeff6e015162aeb316983d8bd61558.png" alt="Banner背景" />
|
||||||
</div>
|
</div>
|
||||||
@ -66,6 +66,7 @@ const newsList = [
|
|||||||
|
|
||||||
.banner-bg {
|
.banner-bg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 830px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|||||||
@ -2,43 +2,29 @@
|
|||||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"lib": [
|
"lib": ["ES2022", "DOM"],
|
||||||
"ES2022",
|
|
||||||
"DOM"
|
|
||||||
],
|
|
||||||
// 关键:添加 DOM 类型库
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": ["src/*"]
|
||||||
"src/*"
|
|
||||||
]
|
|
||||||
// 添加路径别名
|
|
||||||
},
|
},
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
// 支持 Vue 的 JSX 语法
|
"types": ["vite/client", "vue", "vue-i18n"],
|
||||||
"types": [
|
"incremental": true,
|
||||||
"vite/client",
|
|
||||||
"vue","vue-i18n"
|
|
||||||
],
|
|
||||||
"incremental": true, // 添加这一行
|
|
||||||
// 新增 Vue 类型声明
|
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
/* Linting */
|
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
// "erasableSyntaxOnly": true, // 移除这个不支持的选项
|
|
||||||
"noFallthroughCasesInSwitch": true
|
"noFallthroughCasesInSwitch": true
|
||||||
// "noUncheckedSideEffectImports": true
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
// 新增:自动导入的类型定义(根目录)
|
||||||
|
"auto-imports.d.ts",
|
||||||
|
// 新增:自动注册的组件类型定义(根目录)
|
||||||
|
"components.d.ts",
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
"src/**/*.d.ts",
|
"src/**/*.d.ts",
|
||||||
"src/**/*.tsx",
|
"src/**/*.tsx",
|
||||||
"src/**/*.vue",
|
"src/**/*.vue",
|
||||||
// 必须包含 Vue 文件
|
|
||||||
"vite.config.ts",
|
"vite.config.ts",
|
||||||
// 包含 Vite 配置文件
|
|
||||||
"src/main.ts"
|
"src/main.ts"
|
||||||
// 包含入口文件
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -8,10 +8,12 @@ import Components from 'unplugin-vue-components/vite'
|
|||||||
// 引入 ElementPlus 相关解析器
|
// 引入 ElementPlus 相关解析器
|
||||||
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||||
|
|
||||||
|
// import ElementPlus from 'unplugin-element-plus/vite'
|
||||||
import legacy from '@vitejs/plugin-legacy'
|
import legacy from '@vitejs/plugin-legacy'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
|
// ElementPlus(),
|
||||||
vue(),
|
vue(),
|
||||||
|
|
||||||
// 仅在生产环境启用 legacy 插件
|
// 仅在生产环境启用 legacy 插件
|
||||||
@ -29,19 +31,31 @@ export default defineConfig({
|
|||||||
// 自动导入 Vue 相关函数,以及 ElementPlus 的相关函数等
|
// 自动导入 Vue 相关函数,以及 ElementPlus 的相关函数等
|
||||||
resolvers: [
|
resolvers: [
|
||||||
ElementPlusResolver({
|
ElementPlusResolver({
|
||||||
importStyle: 'sass',
|
importStyle: false, // 关闭自动导入样式(手动引入 index.css)
|
||||||
directives: true // 导入指令
|
directives: true // 导入 Element Plus 指令(如 v-loading)
|
||||||
})
|
})
|
||||||
]
|
// ElementPlusResolver({
|
||||||
|
// importStyle: 'sass',
|
||||||
|
// directives: true // 导入指令
|
||||||
|
// })
|
||||||
|
],
|
||||||
|
dts: true // 生成 auto-imports.d.ts(让 ESLint 识别自动导入的 API)
|
||||||
}),
|
}),
|
||||||
Components({
|
Components({
|
||||||
// 自动导入 ElementPlus 的组件
|
|
||||||
resolvers: [
|
resolvers: [
|
||||||
ElementPlusResolver({
|
ElementPlusResolver({
|
||||||
importStyle: 'sass',
|
importStyle: false // 同上,避免与手动引入的样式冲突
|
||||||
directives: true
|
|
||||||
})
|
})
|
||||||
],
|
], // 自动解析 Element Plus 组件
|
||||||
|
dts: true, // 生成 components.d.ts(关键:让 ESLint 识别组件)
|
||||||
|
include: [/\.vue$/, /\.vue\?vue/, /\.tsx$/], // 确保覆盖所有组件文件
|
||||||
|
// 自动导入 ElementPlus 的组件
|
||||||
|
// resolvers: [
|
||||||
|
// ElementPlusResolver({
|
||||||
|
// importStyle: 'sass',
|
||||||
|
// directives: true
|
||||||
|
// })
|
||||||
|
// ],
|
||||||
dirs: ['src/components'] // 自动扫描组件目录
|
dirs: ['src/components'] // 自动扫描组件目录
|
||||||
}),
|
}),
|
||||||
// 开发环境暂时禁用图片压缩插件
|
// 开发环境暂时禁用图片压缩插件
|
||||||
@ -82,13 +96,13 @@ export default defineConfig({
|
|||||||
// external: ['element-plus', 'element-plus/dist/index.css'], // 排除 Element Plus
|
// external: ['element-plus', 'element-plus/dist/index.css'], // 排除 Element Plus
|
||||||
// external: ['element-plus'], // 排除 Element Plus 从打包中
|
// external: ['element-plus'], // 排除 Element Plus 从打包中
|
||||||
output: {
|
output: {
|
||||||
manualChunks: undefined // 取消手动分割,使用 Vite 自动策略
|
// manualChunks: undefined // 取消手动分割,使用 Vite 自动策略
|
||||||
// manualChunks(id) {
|
manualChunks(id) {
|
||||||
// if (id.includes('node_modules')) {
|
if (id.includes('node_modules')) {
|
||||||
// 将第三方库单独分包(如 axios、vue 等)
|
// 将第三方库单独分包(如 axios、vue 等)
|
||||||
// return id.split('node_modules/')[1].split('/')[0]
|
return id.split('node_modules/')[1].split('/')[0]
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user