feat: 20250704
This commit is contained in:
parent
76c246deec
commit
09c3be2a0c
@ -1,5 +1,2 @@
|
||||
# .env.development (开发环境)
|
||||
VITE_API_BASE_URL = 'http://localhost:3000/api'
|
||||
|
||||
# .env.production (生产环境)
|
||||
VITE_API_BASE_URL = 'https://your-api-domain.com/api'
|
||||
VITE_API_BASE_URL = 'http://health.ufutx.net'
|
||||
|
||||
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'], // 显式注册所有插件
|
||||
rules: {
|
||||
'vue/no-v-html': 'warn', // 从 error 改为 warn(或 'off' 完全关闭)
|
||||
|
||||
// 限制 v-html 使用,仅允许明确标记为安全的内容
|
||||
// 'vue/no-v-html': ['warn', { allow: ['trusted', 'safe'] }],
|
||||
|
||||
// 允许使用 router-link 和 router-view 组件
|
||||
'vue/no-undef-components': [
|
||||
'error',
|
||||
@ -31,16 +36,12 @@ module.exports = {
|
||||
ignorePatterns: [
|
||||
'router-link',
|
||||
'router-view',
|
||||
'ElTabs',
|
||||
'ElTabPane',
|
||||
'ElButton',
|
||||
'ElPagination',
|
||||
// 添加其他使用的 Element Plus 组件
|
||||
'RouterLink',
|
||||
'RouterView'
|
||||
'RouterView',
|
||||
'el-.*',
|
||||
'El.*'
|
||||
]
|
||||
// 允许的组件前缀(Element Plus 组件以 El 开头)
|
||||
// allowComponentPrefixes: ['El']
|
||||
}
|
||||
],
|
||||
// 针对非 Vue 文件禁用 Vue 规则
|
||||
@ -48,6 +49,11 @@ module.exports = {
|
||||
// 'error',
|
||||
// { ignorePatterns: ['^router$', '^store$'] } // 可选:忽略特定组件名称
|
||||
// ],
|
||||
// -------------------- 解决 vue/valid-template-root --------------------
|
||||
// 要求模板必须有且只有一个根元素(必填,否则组件报错)
|
||||
'vue/valid-template-root': 'error',
|
||||
|
||||
// -------------------- 可选:关闭组件命名规则(如需) --------------------
|
||||
'vue/multi-word-component-names': 'off',
|
||||
// 'vue/multi-word-component-names': [
|
||||
// 'error',
|
||||
|
||||
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@ -7,6 +7,8 @@
|
||||
export {}
|
||||
declare global {
|
||||
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 createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
|
||||
8
components.d.ts
vendored
8
components.d.ts
vendored
@ -9,14 +9,22 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
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']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
Footer: typeof import('./src/components/Footer.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']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
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,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"sideEffects": [
|
||||
"src/style.css",
|
||||
"src/styles/global.less",
|
||||
"src/styles/tailwindcss.css",
|
||||
"element-plus/dist/index.css"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "vite --host --port 9527",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
@ -21,12 +27,15 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vueuse/core": "^13.3.0",
|
||||
"@vueuse/core": "^13.4.0",
|
||||
"@vueuse/motion": "^3.0.3",
|
||||
"axios": "^1.9.0",
|
||||
"echarts": "^5.6.0",
|
||||
"element-plus": "^2.10.1",
|
||||
"motion-v": "^1.3.1",
|
||||
"pinia": "^2.1.7",
|
||||
"postcss-px-to-viewport": "^1.1.1",
|
||||
"swiper": "^11.2.10",
|
||||
"vue": "^3.5.13",
|
||||
"vue-i18n": "^9.8.0",
|
||||
"vue-router": "^4.5.1"
|
||||
@ -43,6 +52,8 @@
|
||||
"@vue/eslint-config-typescript": "12.0.0",
|
||||
"@vue/tsconfig": "^0.7.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
@ -55,8 +66,11 @@
|
||||
"postcss-px-to-viewport-8-plugin": "^1.2.5",
|
||||
"prettier": "^3.5.3",
|
||||
"sass": "^1.89.2",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tw-animate-css": "^1.3.4",
|
||||
"typescript": "5.1.6",
|
||||
"unplugin-auto-import": "^19.3.0",
|
||||
"unplugin-element-plus": "^0.10.0",
|
||||
"unplugin-vue-components": "^28.7.0",
|
||||
"vite": "^5.4.19",
|
||||
"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">
|
||||
<p>公司地址:深圳市南山区南山街道阳光科创中心B座33楼</p>
|
||||
<p @click="gotoMapFn(branchData.coord[1], branchData.coord[0], branchData.fullName)">
|
||||
公司地址:{{ branchData.address }}
|
||||
</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>
|
||||
</div>
|
||||
</footer>
|
||||
@ -33,20 +38,31 @@
|
||||
<script setup lang="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 = [
|
||||
{
|
||||
src: 'https://images.health.ufutx.com/202506/12/cc651222ac2e5f63185dec1f31d176ae.png',
|
||||
src: 'https://image.fulllinkai.com/202406/28/eb66da5936cf4dc21765f0d6672b88db.png',
|
||||
alt: '友福同享二维码',
|
||||
title: '友福同享'
|
||||
},
|
||||
{
|
||||
src: 'https://images.health.ufutx.com/202506/12/cc651222ac2e5f63185dec1f31d176ae.png', // 示例地址,需替换为实际二维码
|
||||
src: 'https://images.health.ufutx.com/202507/02/394fd3572a92341b538351db421444da.png', // 示例地址,需替换为实际二维码
|
||||
alt: '福恋二维码',
|
||||
title: '福恋'
|
||||
},
|
||||
{
|
||||
src: 'https://images.health.ufutx.com/202506/12/cc651222ac2e5f63185dec1f31d176ae.png', // 示例地址,需替换为实际二维码
|
||||
src: 'https://image.fulllinkai.com/202406/28/8b042a92a2226ee618282e5a04e140ef.jpeg', // 示例地址,需替换为实际二维码
|
||||
alt: '友福公众号二维码',
|
||||
title: '友福公众号'
|
||||
}
|
||||
@ -60,7 +76,7 @@ const openReport = (URL: string) => {
|
||||
|
||||
<style scoped lang="less">
|
||||
.footer {
|
||||
width: 100vw;
|
||||
width: 100%;
|
||||
background-color: #0b101b;
|
||||
color: #fff;
|
||||
//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>
|
||||
|
||||
<!-- 语言切换 -->
|
||||
<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>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElNotification } from 'element-plus'
|
||||
// import { computed } from 'vue'
|
||||
|
||||
const router = useRouter()
|
||||
@ -42,7 +46,13 @@ const navItems = [
|
||||
{ path: '/ecosystem', label: '生态合作' },
|
||||
{ path: '/about', label: '关于我们' }
|
||||
]
|
||||
|
||||
const changeLanguage = () => {
|
||||
ElNotification({
|
||||
title: '系统提示',
|
||||
message: '翻译文件正在处理中,请稍后重试~',
|
||||
type: 'primary'
|
||||
})
|
||||
}
|
||||
// 跳转方法
|
||||
const handleNavigate = (path: string) => {
|
||||
console.log(path)
|
||||
@ -73,6 +83,7 @@ const isActive = (path: string) => {
|
||||
z-index: 999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.navbar-logo {
|
||||
width: 160px;
|
||||
height: 29px;
|
||||
@ -80,6 +91,7 @@ const isActive = (path: string) => {
|
||||
//top: 0;
|
||||
//left: 0;
|
||||
}
|
||||
|
||||
// 导航容器(居中)
|
||||
.navbar-container {
|
||||
width: 100%;
|
||||
@ -121,8 +133,10 @@ const isActive = (path: string) => {
|
||||
// 激活态/ hover 态
|
||||
&.active,
|
||||
&:hover {
|
||||
//&.active {
|
||||
font-weight: bold;
|
||||
color: @primary-color;
|
||||
|
||||
&::after {
|
||||
width: 100%; // 下划线展开
|
||||
}
|
||||
@ -132,7 +146,9 @@ const isActive = (path: string) => {
|
||||
|
||||
// 语言切换(可选动画)
|
||||
.language-switch {
|
||||
color: #666;
|
||||
width: 150px;
|
||||
color: @text-color;
|
||||
font-size: @font-size-md;
|
||||
transition: color 0.3s ease;
|
||||
|
||||
&: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">-->
|
||||
<!-- <slot></slot>-->
|
||||
<!-- </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 />
|
||||
</div>
|
||||
|
||||
30
src/main.ts
30
src/main.ts
@ -1,42 +1,42 @@
|
||||
// src/main.ts
|
||||
import { ViteSSG } from 'vite-ssg'
|
||||
import { createWebHistory } from 'vue-router'
|
||||
import { createWebHashHistory } from 'vue-router'
|
||||
import App from './App.vue'
|
||||
import routes from './router/routes'
|
||||
import i18n from './locales/i18n' // 导入i18n配置
|
||||
import './style.css'
|
||||
import '@/styles/global.less' // 引入全局样式
|
||||
import '@/styles/tailwindcss.less' // tailwindcss.less
|
||||
import '@/styles/tailwindcss.css' // 引入tailwindcss样式
|
||||
// 修正:明确 meta.title 的类型为 string
|
||||
|
||||
// 引入 element-plus 核心库
|
||||
// import ElementPlus from 'element-plus'
|
||||
// 引入 element-plus 全局样式(可根据需求选择是否自定义主题,这里先引入默认样式)
|
||||
import 'element-plus/dist/index.css'
|
||||
// 如果你需要使用 Element Plus 提供的国际化(i18n)功能,还需引入对应的语言包,比如中文
|
||||
|
||||
// 修正:使用正确的语言包路径(从 es/locale/lang 导入)
|
||||
// import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
// 1. 引入 Element Plus 核心库和全局样式
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css' // 手动引入默认样式(覆盖自动导入的样式冲突)
|
||||
// 2. 引入国际化语言包(确保路径正确)
|
||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||
// 使用 ElementPlus 插件,并配置国际化等选项(这里以配置中文为例)
|
||||
import { MotionPlugin } from '@vueuse/motion'
|
||||
|
||||
declare module 'vue-router' {
|
||||
interface RouteMeta {
|
||||
title?: string // 明确指定为 string 类型
|
||||
requiresAuth?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export const createApp = ViteSSG(
|
||||
App,
|
||||
{
|
||||
history: createWebHistory(),
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
base: import.meta.env.BASE_URL || '/'
|
||||
},
|
||||
ctx => {
|
||||
// 安装 i18n 插件
|
||||
ctx.app.use(i18n)
|
||||
// ctx.app.use(ElementPlus, {
|
||||
// locale: zhCn
|
||||
// })
|
||||
ctx.app.use(MotionPlugin)
|
||||
ctx.app.use(ElementPlus, {
|
||||
locale: zhCn
|
||||
})
|
||||
|
||||
// 路由守卫:设置页面标题
|
||||
ctx.router.beforeEach((to, _from, next) => {
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
// src/router/index.ts
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
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({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
@ -19,9 +23,18 @@ const router = createRouter({
|
||||
})
|
||||
|
||||
router.beforeEach((_to, _from, next) => {
|
||||
// 添加下划线
|
||||
// document.title = to.meta.title || '极简官网' // 确保meta.title类型正确
|
||||
// setPageTitle(_to.meta.title)
|
||||
|
||||
if (_to.name === 'ArticleDetail' && _from.name === 'News') {
|
||||
// 清除News组件的缓存
|
||||
const cachedComponents = getCurrentInstance()?.appContext.config.globalProperties.$keepAlive?.cache
|
||||
if (cachedComponents) {
|
||||
delete cachedComponents['News']
|
||||
}
|
||||
}
|
||||
next()
|
||||
})
|
||||
|
||||
// / 添加日志,验证路由模式
|
||||
// console.log('路由模式:', router.history)
|
||||
export default router
|
||||
|
||||
@ -15,14 +15,77 @@ const routes: RouteRecordRaw[] = [
|
||||
path: '/',
|
||||
component: () => import('@/layout/Layout.vue'), // 动态导入
|
||||
children: [
|
||||
{ path: '', name: 'Home', component: () => import('@/views/Home/Home.vue') },
|
||||
{ path: 'news', name: 'News', component: () => import('@/views/News/News.vue') },
|
||||
{ path: 'news/:id', name: 'ArticleDetail', component: () => import('@/views/News/ArticleDetail.vue') },
|
||||
{ path: 'network', name: 'Network', component: () => import('@/views/Network/Network.vue') },
|
||||
{ path: 'dating', name: 'Dating', component: () => import('@/views/Dating/Dating.vue') },
|
||||
{ path: 'app', name: 'App', component: () => import('@/views/App/App.vue') },
|
||||
{ path: 'ecosystem', name: 'Ecosystem', component: () => import('@/views/Ecosystem/Ecosystem.vue') },
|
||||
{ path: 'about', name: 'About', component: () => import('@/views/About/About.vue') }
|
||||
{
|
||||
path: '',
|
||||
name: 'Home',
|
||||
meta: {
|
||||
keepAlive: false
|
||||
},
|
||||
component: () => import('@/views/Home/Home.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')
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
|
||||
@ -318,3 +318,36 @@ html, body {
|
||||
.btn-glow:hover::before {
|
||||
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
|
||||
import { useRouter } from 'vue-router'
|
||||
import router from '../router/index.ts' // 直接导入已创建的路由实例
|
||||
import type { RouteLocationRaw } from 'vue-router'
|
||||
|
||||
/**
|
||||
* 内部路由跳转(简化版)
|
||||
* @param to - 路由路径或名称
|
||||
* @param replace - 是否替换当前历史记录
|
||||
*/
|
||||
export const navigateTo = (to: string | { name: string }, replace = false) => {
|
||||
const router = useRouter()
|
||||
export const navigateTo = (to: RouteLocationRaw, replace = false) => {
|
||||
replace ? router.replace(to) : router.push(to)
|
||||
}
|
||||
|
||||
@ -23,14 +23,29 @@ export const openExternalLink = (url: string, target: '_blank' | '_self' = '_bla
|
||||
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 = () => {
|
||||
// useRouter().back()
|
||||
// }
|
||||
//
|
||||
export const goBack = () => {
|
||||
router.back()
|
||||
}
|
||||
// <template>
|
||||
// <div>
|
||||
// <button @click="goToProduct(123)">查看产品</button>
|
||||
|
||||
@ -41,13 +41,13 @@ service.interceptors.request.use(
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
(response: AxiosResponse<ApiResponse>) => {
|
||||
(response: AxiosResponse<any>) => {
|
||||
const res = response.data
|
||||
if (res.code !== 200) {
|
||||
if (res.code !== 0) {
|
||||
showError(res.message || '请求失败')
|
||||
return Promise.reject(new Error(res.message || '请求失败'))
|
||||
}
|
||||
return res.data
|
||||
return res
|
||||
},
|
||||
(error: AxiosError<ApiResponse>) => {
|
||||
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">
|
||||
.about-page {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
//width: 100%;
|
||||
//overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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背景" />
|
||||
</div>
|
||||
@ -66,6 +66,7 @@
|
||||
|
||||
.banner-bg {
|
||||
width: 100%;
|
||||
height: 830px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
|
||||
@ -64,7 +64,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, nextTick } from 'vue'
|
||||
import BranchMap from './BranchMap.vue'
|
||||
import { openExternalLink } from '@/utils/navigation.ts'
|
||||
import { gotoMapFn } from '@/utils/tools.ts'
|
||||
// 子公司数据(使用ECharts坐标格式)
|
||||
const branchList = [
|
||||
{
|
||||
@ -126,17 +126,6 @@ const handleMapClick = (index: number) => {
|
||||
activeIndex.value = index
|
||||
}
|
||||
|
||||
const gotoMapFn = (latitude: any, longitude: any, detail: any) => {
|
||||
console.log(latitude, longitude, detail)
|
||||
|
||||
openExternalLink(
|
||||
// `http://maps.googleapis.com/maps/api/staticmap?center=${latitude},${longitude}&zoom=14&size=400x300&sensor=false`
|
||||
// `http://maps.google.com/map/api/staticmap?center=${latitude},${longitude}&size=640*640&sensor=true`
|
||||
`https://uri.amap.com/marker?position=${longitude},${latitude}&name=${detail}`,
|
||||
'_blank'
|
||||
// `http://api.map.baidu.com/marker?location=${latitude},${longitude}&name==${detail}&output=html`
|
||||
)
|
||||
}
|
||||
// 计算滑块位置
|
||||
const calculateSliderPosition = () => {
|
||||
const activeTab = tabsRef.value[activeIndex.value]
|
||||
|
||||
@ -7,7 +7,7 @@ import { ref, onMounted, watch, nextTick, onUnmounted } from 'vue'
|
||||
import * as echarts from 'echarts'
|
||||
import chinaJson from '@/assets/map/china.json'
|
||||
|
||||
echarts.registerMap('china', chinaJson)
|
||||
echarts.registerMap('china', chinaJson as any)
|
||||
|
||||
const props = defineProps<{
|
||||
branchList: Array<{
|
||||
@ -166,7 +166,8 @@ const updateChart = () => {
|
||||
const headquartersIndex = getHeadquartersIndex()
|
||||
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) => ({
|
||||
...item,
|
||||
value: item.coord,
|
||||
|
||||
@ -75,14 +75,14 @@ const timelineData = [
|
||||
.timeline-header {
|
||||
margin-bottom: 50px;
|
||||
.main-title {
|
||||
font-size: 28px;
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
color: @text-color;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.sub-title {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
font-size: 20px;
|
||||
color: @text-color-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ const valueTabs = [
|
||||
title: '团队精神',
|
||||
name: 'TeamSpirit',
|
||||
content: ['开放沟通、互相尊重,人人都是关键角色', '注重跨部门协作,共同承担责任', '团队一起面对挑战、共享成功'],
|
||||
image: 'https://images.health.ufutx.com/202506/20/136362c2dff3844304dd1e96bd36ee03.png'
|
||||
image: 'https://images.health.ufutx.com/202507/02/eb71edac0faa7282c999b1d9ebbb5962.png'
|
||||
},
|
||||
{
|
||||
title: '创始人精神',
|
||||
|
||||
@ -3,9 +3,17 @@
|
||||
<h2 class="section-title">资质认证</h2>
|
||||
<p class="section-subtitle">成立至今获得多项荣誉</p>
|
||||
<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-list">
|
||||
<Marquee
|
||||
:duration="60"
|
||||
:reverse="false"
|
||||
repeatCount="3"
|
||||
pause-on-hover
|
||||
container-class="h-56 bg-white rounded-lg shadow-sm p-4"
|
||||
:initial-offset="0"
|
||||
>
|
||||
<div
|
||||
v-for="(src, index) in certificateImgs"
|
||||
:key="index"
|
||||
@ -13,27 +21,65 @@
|
||||
@mouseenter="activeIndex = index"
|
||||
@mouseleave="activeIndex = -1"
|
||||
>
|
||||
<img :src="src" alt="certificate" :class="{ 'scale-up': activeIndex === index }" />
|
||||
<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>
|
||||
<!-- <button class="carousel-btn next" @click="slide(1)">›</button>-->
|
||||
</div>
|
||||
<div class="carousel-btn next"></div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import Marquee from '@/components/Marquee.vue'
|
||||
import type { ImageInstance } from 'element-plus'
|
||||
// 创建数组ref存储每个图片实例
|
||||
const imageRefs = ref<(ImageInstance | null)[]>([])
|
||||
|
||||
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'
|
||||
]
|
||||
|
||||
const activeIndex = ref(-1)
|
||||
// 点击处理函数(接收索引参数)
|
||||
const handleClick = (index: number) => {
|
||||
const image = imageRefs.value[index]
|
||||
if (image) {
|
||||
image.showPreview() // 调用对应图片的预览方法
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@ -73,20 +119,19 @@ const activeIndex = ref(-1)
|
||||
}
|
||||
.carousel-btn {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 10px 15px;
|
||||
cursor: pointer;
|
||||
font-size: @font-size-lg;
|
||||
|
||||
top: 46%;
|
||||
//flex-shrink: 0;
|
||||
width: 45px;
|
||||
height: 60px;
|
||||
background-size: cover;
|
||||
&.prev {
|
||||
left: 20px;
|
||||
left: 70px;
|
||||
background-image: url('https://images.health.ufutx.com/202507/02/9094a60740fb3dfd8f71cf5ebaeefcf7.png');
|
||||
}
|
||||
&.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;
|
||||
}
|
||||
.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;
|
||||
//top: 0;
|
||||
.certificate-list {
|
||||
display: flex;
|
||||
max-width: 1561px;
|
||||
height: 460px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
margin: 0px auto;
|
||||
//background: red;
|
||||
margin: 0 auto;
|
||||
//margin-left: 100px;
|
||||
box-sizing: border-box;
|
||||
// 关键:强制水平布局,禁止换行
|
||||
display: flex;
|
||||
flex-direction: row; /* 明确水平方向 */
|
||||
flex-wrap: nowrap; /* 禁止换行 */
|
||||
overflow: hidden; /* 隐藏超出容器的部分 */
|
||||
}
|
||||
|
||||
.certificate-item {
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 288px; /* 固定宽度,确保能在一行放下多个 */
|
||||
flex-shrink: 0; /* 禁止收缩,保证宽度不变 */
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* 增加轻微阴影,提升视觉层次 */
|
||||
margin-right: 16px;
|
||||
cursor: pointer; /* 提示可交互 */
|
||||
position: relative;
|
||||
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); /* 卡片整体过渡 */
|
||||
.certificate-image {
|
||||
width: 288px;
|
||||
height: auto;
|
||||
border: 4px solid transparent;
|
||||
transform-origin: bottom center; /* 核心:设置缩放原点为底部中心 */
|
||||
transition:
|
||||
transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94),
|
||||
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触发)
|
||||
.scale-up {
|
||||
transform: scale(1.1);
|
||||
//z-index: 10;
|
||||
transform-origin: bottom center; /* 新增,设置缩放原点为底部中心 */
|
||||
z-index: 10;
|
||||
border-color: #4b89dc;
|
||||
box-shadow: 0 8px 24px rgba(75, 137, 220, 0.2);
|
||||
//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) {
|
||||
.certificate-list {
|
||||
|
||||
@ -15,17 +15,17 @@
|
||||
<script setup lang="ts">
|
||||
const healthItems = [
|
||||
{
|
||||
icon: 'https://images.health.ufutx.com/202506/20/10c734494721ea0a60c3b9c3ebd82a60.png',
|
||||
icon: 'https://images.health.ufutx.com/202506/30/f0356813f3eda8e37f303a44ae3d70b8.png',
|
||||
title: '生命科学+AI的深度融合',
|
||||
desc: '让人体健康管理像科研一样自然'
|
||||
},
|
||||
{
|
||||
icon: 'https://images.health.ufutx.com/202506/20/10c734494721ea0a60c3b9c3ebd82a60.png',
|
||||
icon: 'https://images.health.ufutx.com/202506/30/cfb74da07ad90521f3a108c6450f88c7.png',
|
||||
title: '万亿级产业新基建',
|
||||
desc: '从个人健康到城市级智慧医疗的完整生态'
|
||||
},
|
||||
{
|
||||
icon: 'https://images.health.ufutx.com/202506/20/10c734494721ea0a60c3b9c3ebd82a60.png',
|
||||
icon: 'https://images.health.ufutx.com/202506/30/572c91788ea274174a8bd8fe77e52c08.png',
|
||||
title: '人人都拥有的数字健康管家',
|
||||
desc: '让真实有效的健康管理普惠全民'
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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背景" />
|
||||
</div>
|
||||
@ -66,6 +66,7 @@ const newsList = [
|
||||
|
||||
.banner-bg {
|
||||
width: 100%;
|
||||
height: 830px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
|
||||
@ -21,8 +21,10 @@
|
||||
<div class="device-info">
|
||||
<h3 class="device-title">{{ navList[activeIndex].center.title }}</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>
|
||||
<div class="download-btn" @click="openReport">立即下载</div>
|
||||
<div class="btn-success-glow download-btn" @click="openReport">立即下载</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -38,7 +40,7 @@ const navList = ref([
|
||||
{
|
||||
text: '健康手环',
|
||||
active: true,
|
||||
icon: 'https://images.health.ufutx.com/202506/18/4aae244f94bbf8bf352e8ab8e2270a81.png',
|
||||
icon: 'https://images.health.ufutx.com/202507/02/4aae244f94bbf8bf352e8ab8e2270a81.png',
|
||||
center: {
|
||||
navLabel: '健康手环', // 导航栏显示文字
|
||||
title: '健康手环', // 页面主标题
|
||||
@ -138,12 +140,12 @@ const handleSelect = (index: number) => {
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
opacity: 0.6;
|
||||
//opacity: 0.8;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.nav-text {
|
||||
font-size: 26px;
|
||||
font-size: 20px;
|
||||
color: @text-color-secondary;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
@ -228,7 +230,7 @@ const handleSelect = (index: number) => {
|
||||
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
padding: 16px 30px;
|
||||
padding: 14px 30px;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
border-radius: 100px;
|
||||
@ -236,7 +238,6 @@ const handleSelect = (index: number) => {
|
||||
background: #18ca6e;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,8 +7,10 @@
|
||||
<div class="device-info">
|
||||
<h3 class="device-title">{{ props.device.title }}</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>
|
||||
<div class="download-btn" @click="openReport">立即下载</div>
|
||||
<div class="btn-success-glow download-btn" @click="openReport">立即下载</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -97,7 +99,7 @@ const openReport = () => {
|
||||
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
padding: 16px 30px;
|
||||
padding: 14px 30px;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
border-radius: 100px;
|
||||
@ -105,7 +107,12 @@ const openReport = () => {
|
||||
background: #18ca6e;
|
||||
color: #fff;
|
||||
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 />
|
||||
立即让未来的灵魂伴侣更了解你,轻松打开话题
|
||||
</p>
|
||||
<div class="download-btn" @click="openReport">立即下载</div>
|
||||
<div class="btn-success-glow download-btn" @click="openReport">立即下载</div>
|
||||
</div>
|
||||
<div class="speech-img">
|
||||
<!-- <img src="@/assets/speech-app.png" alt="演讲界面" />-->
|
||||
@ -67,7 +67,7 @@ const openReport = () => {
|
||||
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
padding: 16px 30px;
|
||||
padding: 14px 30px;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
border-radius: 100px;
|
||||
@ -75,7 +75,7 @@ const openReport = () => {
|
||||
background: #18ca6e;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
//font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,43 +3,19 @@
|
||||
<div class="tags-header">
|
||||
<h2 class="tags-title">友福AI婚恋-专属单身标签</h2>
|
||||
<p class="tags-subtitle">Right Beside You, They Love Each Other!</p>
|
||||
<!-- <el-button type="primary" class="download-btn">立即下载</el-button>-->
|
||||
<div class="btn-glow download-btn">立即下载</div>
|
||||
<div class="btn-glow download-btn" @click="downloadFloveApp()">立即下载</div>
|
||||
<div class="tags-icon">
|
||||
<img src="https://images.health.ufutx.com/202506/18/3b16ca61dc63eb22c102aed934301c0a.png" alt="" />
|
||||
</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>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 18 import { ElButton } from 'element-plus'
|
||||
|
||||
// const tags = [
|
||||
// {
|
||||
// img: '@/assets/tag-1.png',
|
||||
// desc: '霍小楠 • 27岁硕士 • 生活博主'
|
||||
// },
|
||||
// {
|
||||
// img: '@/assets/tag-2.png',
|
||||
// desc: '李浩然 • 30岁医生 • 运动达人'
|
||||
// },
|
||||
// {
|
||||
// img: '@/assets/tag-3.png',
|
||||
// desc: '苏晓萱 • 25岁设计师 • 文艺青年'
|
||||
// }
|
||||
// ]
|
||||
import { downloadFloveApp } from '@/utils/tools.js'
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@import '@/styles/global.less';
|
||||
|
||||
.ai-tags {
|
||||
padding: 100px 192px;
|
||||
text-align: center;
|
||||
@ -60,12 +36,12 @@
|
||||
}
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
padding: 16px 30px;
|
||||
padding: 14px 30px;
|
||||
border-radius: 100px;
|
||||
background: var(--Style, #1060ff);
|
||||
color: var(--ffffff, #fff);
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
//font-weight: 500;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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背景" />
|
||||
</div>
|
||||
@ -66,6 +66,7 @@
|
||||
|
||||
.banner-bg {
|
||||
width: 100%;
|
||||
height: 830px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
|
||||
@ -22,24 +22,24 @@
|
||||
<script setup lang="ts">
|
||||
const points = [
|
||||
{
|
||||
icon: 'https://images.health.ufutx.com/202506/18/2bf6cfbc4fef2c4d8e276e95398405a0.png',
|
||||
icon: 'https://images.health.ufutx.com/202507/02/fb92625096f65beda47a97daaec64879.png',
|
||||
title: '传统婚介困境',
|
||||
desc: '效率低/规则混乱'
|
||||
},
|
||||
{
|
||||
icon: 'https://images.health.ufutx.com/202506/18/2bf6cfbc4fef2c4d8e276e95398405a0.png',
|
||||
icon: 'https://images.health.ufutx.com/202507/02/09d30d86a53a86ee26faa9be50bbd24c.png',
|
||||
title: '资料真假难辨',
|
||||
desc: '生物特征+社交轨迹验证'
|
||||
desc: '生物特征核验+社交轨迹交叉验证'
|
||||
},
|
||||
{
|
||||
icon: 'https://images.health.ufutx.com/202506/18/2bf6cfbc4fef2c4d8e276e95398405a0.png',
|
||||
icon: 'https://images.health.ufutx.com/202507/02/1a19cab6581b311e815002b859b8e440.png',
|
||||
title: '匹配维度单一',
|
||||
desc: '多维度开放模型'
|
||||
},
|
||||
{
|
||||
icon: 'https://images.health.ufutx.com/202506/18/2bf6cfbc4fef2c4d8e276e95398405a0.png',
|
||||
icon: 'https://images.health.ufutx.com/202507/02/83b119df621a38fd9c9d0199c54ed2fa.png',
|
||||
title: '售后服务缺失',
|
||||
desc: '关系认证及延伸服务'
|
||||
desc: '关系认知疏导及关怀服务'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<section class="success-stories">
|
||||
<h2 class="section-title">就在你身边,他们相爱啦!</h2>
|
||||
<p class="section-subtitle">Right Beside You, They Love Each Other!</p>
|
||||
<div class="download-btn btn-glow">立即下载</div>
|
||||
<div class="download-btn btn-glow" @click="downloadFloveApp()">立即下载</div>
|
||||
<div class="stories-icon">
|
||||
<img src="https://images.health.ufutx.com/202506/18/1a837037ce7fb8502a211a01e19fbf55.png" alt="" />
|
||||
</div>
|
||||
@ -25,6 +25,7 @@
|
||||
// { img: '@/assets/story-5.jpg' },
|
||||
// { img: '@/assets/story-6.jpg' }
|
||||
// ]
|
||||
import { downloadFloveApp } from '@/utils/tools.ts'
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@ -49,12 +50,12 @@
|
||||
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
padding: 16px 30px;
|
||||
padding: 14px 30px;
|
||||
border-radius: 100px;
|
||||
background: var(--Style, #1060ff);
|
||||
color: var(--ffffff, #fff);
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
//font-weight: 500;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
|
||||
@ -35,14 +35,14 @@ import TalentTraining from './sections/TalentTraining.vue'
|
||||
import CityPartner from './sections/CityPartner.vue'
|
||||
const cooperateData = {
|
||||
title: '合作咨询',
|
||||
desc: '欢迎健康产业链上下游企业,以及希望利用AI技术 升级健康产品与服务的企业与我们洽谈合作,共创产业新价值',
|
||||
img: 'https://images.health.ufutx.com/202506/18/2e9c9d64bdcf03fbe5041720f03033ca.png'
|
||||
desc: '欢迎健康产业链上下游企业,以及希望利用AI技术<br> 升级健康产品与服务的企业与我们洽谈合作,共创产业新价值',
|
||||
img: 'https://images.health.ufutx.com/202506/20/c60d98038ab065c2e92dc67b938d45e2.png'
|
||||
}
|
||||
|
||||
const cooperateDataV2 = {
|
||||
title: '合作咨询',
|
||||
desc: '提供专属健康服务和解决方案',
|
||||
img: 'https://images.health.ufutx.com/202506/18/2e9c9d64bdcf03fbe5041720f03033ca.png'
|
||||
img: 'https://images.health.ufutx.com/202506/20/c60d98038ab065c2e92dc67b938d45e2.png'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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背景" />
|
||||
</div>
|
||||
@ -66,6 +66,7 @@
|
||||
|
||||
.banner-bg {
|
||||
width: 100%;
|
||||
height: 830px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
|
||||
@ -209,7 +209,7 @@ const currentIdx = ref(0)
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.desc {
|
||||
font-size: 16px;
|
||||
font-size: 20px;
|
||||
color: @text-color-secondary;
|
||||
line-height: 34px;
|
||||
white-space: pre-wrap;
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
<template>
|
||||
<section class="cooperation-consult">
|
||||
<section class="cooperation-consult" :style="{ backgroundImage: `url(${props.device.img})` }">
|
||||
<div class="consult-content">
|
||||
<p class="consult-text">
|
||||
{{ props.device.desc }}
|
||||
</p>
|
||||
<div class="consult-btn">{{ props.device.title }}</div>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<p class="consult-text" v-html="props.device.desc"></p>
|
||||
<div class="consult-btn" @click="openCooperationDialog">{{ props.device.title }}</div>
|
||||
</div>
|
||||
<CooperationDialog ref="cooperationDialogRef" />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import CooperationDialog from '@/views/Ecosystem/sections/CooperationDialog.vue'
|
||||
|
||||
const props = defineProps({
|
||||
device: {
|
||||
type: Object,
|
||||
@ -17,10 +19,15 @@ const props = defineProps({
|
||||
default: () => ({
|
||||
title: '合作咨询',
|
||||
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'
|
||||
</script>
|
||||
|
||||
@ -46,9 +53,14 @@ const props = defineProps({
|
||||
color: #313fa8;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
padding: 6px 36px;
|
||||
padding: 16px 36px;
|
||||
border-radius: 100px;
|
||||
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 {
|
||||
text-align: left;
|
||||
font-size: @font-size-sm;
|
||||
font-size: @font-size-lg;
|
||||
color: @text-color-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
<div class="home-page">
|
||||
<!-- Banner 模块-->
|
||||
<BannerCarousel />
|
||||
<!-- 核心价值模块-->
|
||||
<!-- <!– 核心价值模块–>-->
|
||||
<CoreValue />
|
||||
<!-- 应用场景模块-->
|
||||
<!-- <!– 应用场景模块–>-->
|
||||
<UseCases />
|
||||
<!-- 全球服务模块-->
|
||||
<!-- <!– 全球服务模块–>-->
|
||||
<GlobalService />
|
||||
<!-- 客户反馈模块-->
|
||||
<CustomerFeedback />
|
||||
@ -15,13 +15,28 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts" name="Home">
|
||||
import BannerCarousel from './sections/BannerCarousel.vue'
|
||||
import CoreValue from './sections/CoreValue.vue'
|
||||
import UseCases from './sections/UseCases.vue'
|
||||
import GlobalService from './sections/GlobalService.vue'
|
||||
import CustomerFeedback from './sections/CustomerFeedback.vue'
|
||||
import Partners from './sections/Partners.vue'
|
||||
|
||||
// 组件首次加载时触发(只执行1次)
|
||||
onMounted(() => {
|
||||
console.log('Home 页面首次加载(未从缓存中恢复)')
|
||||
})
|
||||
|
||||
// 组件从缓存中激活时触发(每次返回页面执行)
|
||||
onActivated(() => {
|
||||
console.log('Home 页面从缓存中激活(缓存生效)')
|
||||
})
|
||||
|
||||
// 组件被缓存时触发(每次离开页面执行)
|
||||
onDeactivated(() => {
|
||||
console.log('Home 页面被缓存(缓存生效)')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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背景" />
|
||||
</div>
|
||||
@ -28,7 +28,7 @@
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
<script setup lang="ts" name="BannerCarousel">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const activeIndex = ref<number | null>(null)
|
||||
@ -72,6 +72,7 @@ const newsList = [
|
||||
|
||||
.banner-bg {
|
||||
width: 100%;
|
||||
height: 830px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
|
||||
@ -1,150 +1,179 @@
|
||||
<template>
|
||||
<section class="feedback-section">
|
||||
<div class="feedback-title">客户反馈</div>
|
||||
|
||||
<!-- 跑马灯容器:去掉换行,强制内容单行显示 -->
|
||||
<div class="feedback-list">
|
||||
<div v-for="(item, index) in feedbackList" :key="index" class="feedback-card">
|
||||
<Marquee
|
||||
:duration="360"
|
||||
: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.comment }}</p>
|
||||
<p class="comment">{{ item.feedback }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
</Marquee>
|
||||
</div>
|
||||
<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>
|
||||
</Marquee>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 模拟假数据(头像统一使用你提供的链接)
|
||||
const feedbackList = [
|
||||
{
|
||||
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'
|
||||
},
|
||||
{
|
||||
username: '派小喵萌宠',
|
||||
comment: '操作简单,容易上手',
|
||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
import Marquee from '@/components/Marquee.vue'
|
||||
import TextGenerateEffect from '@/components/TextGenerateEffect.vue'
|
||||
import { userFeedbacks } from '@/data/userFeedbacks.ts'
|
||||
// 添加泛型类型 T 表示数组元素的类型
|
||||
function splitArrayRandomly<T>(arr: T[], ratio = 0.5): [T[], T[]] {
|
||||
// 复制原数组避免修改
|
||||
const shuffled = [...arr]
|
||||
|
||||
// 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">
|
||||
// 基础变量(可继承项目全局样式)
|
||||
// 基础变量
|
||||
@bg-color: #f9fbff;
|
||||
@card-bg: #ffffff;
|
||||
@radius: 12px;
|
||||
@padding: 16px;
|
||||
@gap: 50px;
|
||||
@avatar-size: 60px;
|
||||
@subtext-color: #999;
|
||||
@transition: all 0.3s ease;
|
||||
|
||||
.feedback-section {
|
||||
background-color: @bg-color;
|
||||
.px(100px);
|
||||
padding: 0 0 100px 0; /* 改用标准padding写法,避免自定义.px()可能的问题 */
|
||||
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 {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: @text-color;
|
||||
.pb(60px);
|
||||
.pt(100px);
|
||||
padding: 100px 0 60px;
|
||||
}
|
||||
|
||||
// 跑马灯容器:关键修改——禁止换行,确保内容单行滚动
|
||||
.feedback-list {
|
||||
//width: 100vw;
|
||||
max-width: 1820px;
|
||||
margin: 0 auto;
|
||||
margin-left: 100px;
|
||||
box-sizing: border-box;
|
||||
// 关键:强制水平布局,禁止换行
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: @gap;
|
||||
flex-direction: row; /* 明确水平方向 */
|
||||
flex-wrap: nowrap; /* 禁止换行 */
|
||||
overflow: hidden; /* 隐藏超出容器的部分 */
|
||||
}
|
||||
|
||||
// 反馈卡片:固定宽度,确保排列整齐
|
||||
.feedback-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: @padding;
|
||||
.feedback-popper {
|
||||
border-radius: 320px !important;
|
||||
}
|
||||
width: 320px; /* 固定宽度,确保能在一行放下多个 */
|
||||
//max-width: 320px;
|
||||
flex-shrink: 0; /* 禁止收缩,保证宽度不变 */
|
||||
border-radius: 16px;
|
||||
background: var(--ffffff, #fff);
|
||||
transition: @transition;
|
||||
|
||||
background: #fff;
|
||||
//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 {
|
||||
transform: translateY(-4px);
|
||||
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 {
|
||||
flex-shrink: 0;
|
||||
margin-right: 12px;
|
||||
@ -154,33 +183,86 @@ const feedbackList = [
|
||||
height: @avatar-size;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 2px solid #f0f0f0;
|
||||
}
|
||||
}
|
||||
|
||||
.feedback-info {
|
||||
text-align: left;
|
||||
max-width: calc(100% - @avatar-size - 12px); /* 限制文本区域宽度 */
|
||||
|
||||
.username {
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: @text-color;
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 6px;
|
||||
white-space: nowrap; /* 用户名不换行 */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.comment {
|
||||
font-size: 14px;
|
||||
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) {
|
||||
.feedback-section {
|
||||
padding: 0 20px 60px; /* 缩小移动端内边距 */
|
||||
}
|
||||
.feedback-card {
|
||||
width: 100%;
|
||||
max-width: 320px;
|
||||
width: 220px; /* 移动端缩小卡片宽度 */
|
||||
}
|
||||
}
|
||||
</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>
|
||||
|
||||
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,45 +2,67 @@
|
||||
<section class="scene-section">
|
||||
<h2 class="scene-title">友福同享AI健康解决方案应用场景</h2>
|
||||
<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-content">
|
||||
<img :src="item.icon" alt="场景图标" class="scene-icon" />
|
||||
<p class="scene-name">{{ item.name }}</p>
|
||||
<p class="scene-desc">{{ item.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 场景数据
|
||||
const sceneList = [
|
||||
{
|
||||
name: '地区政府/社区健康服务',
|
||||
desc: '提供社区健康管理解决方案,提升居民健康水平,降低医疗成本。',
|
||||
icon: 'https://images.health.ufutx.com/202506/12/d2b5ca33bd970f64a6301fa75ae2eb22.png'
|
||||
icon: 'https://images.health.ufutx.com/202506/30/87f66f9deca9c217d3f86d7d7c5d25c9.png'
|
||||
},
|
||||
{
|
||||
name: '医院体检中心/健康管理机构',
|
||||
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: '降低企业医疗成本,提升员工健康与生产力。',
|
||||
icon: 'https://images.health.ufutx.com/202506/12/d2b5ca33bd970f64a6301fa75ae2eb22.png'
|
||||
icon: 'https://images.health.ufutx.com/202506/30/1de2a31aa67aa92ed7c5d59de0936bbf.png'
|
||||
},
|
||||
{
|
||||
name: '健康产业链供应商',
|
||||
desc: '连接健康产业上下游,提供精准数据分析和市场洞察。',
|
||||
icon: 'https://images.health.ufutx.com/202506/12/d2b5ca33bd970f64a6301fa75ae2eb22.png'
|
||||
icon: 'https://images.health.ufutx.com/202506/30/ddbb65cf7004bb06982e0bbfa4e9bdb1.png'
|
||||
},
|
||||
{
|
||||
name: '健康管理专业培训',
|
||||
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>
|
||||
|
||||
<style scoped lang="less">
|
||||
@ -68,69 +90,88 @@ const sceneList = [
|
||||
.scene-item {
|
||||
width: 284px;
|
||||
height: 336px;
|
||||
perspective: 1000px; // 3D透视效果
|
||||
perspective: 1000px;
|
||||
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 {
|
||||
position: relative;
|
||||
width: 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;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
background: linear-gradient(180deg, #fff 0%, #ecf2ff 100%);
|
||||
border-radius: @border-radius-md;
|
||||
transition: all 0.5s cubic-bezier(0.25, 0.8, 0.25, 1); // 平滑过渡
|
||||
padding: 40px 16px;
|
||||
height: 100%;
|
||||
transition: all 0.4s 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);
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.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);
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.scene-desc {
|
||||
font-size: @font-size-sm;
|
||||
color: @text-color-light;
|
||||
color: @text-color-secondary;
|
||||
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; // 初始位置向上偏移
|
||||
}
|
||||
}
|
||||
|
||||
// 悬停状态
|
||||
&:hover .scene-inner {
|
||||
transform: translateY(-10px) scale(1.05);
|
||||
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.1);
|
||||
background: linear-gradient(180deg, #fff 0%, #e6f0ff 100%);
|
||||
}
|
||||
|
||||
&:hover .scene-icon {
|
||||
transform: scale(1.1);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
&:hover .scene-name {
|
||||
color: @primary-color;
|
||||
transform: translateY(5px);
|
||||
}
|
||||
|
||||
&:hover .scene-desc {
|
||||
max-height: 100px;
|
||||
opacity: 1;
|
||||
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">
|
||||
<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 class="news-panel">
|
||||
<div
|
||||
@ -72,11 +91,12 @@ const newsList = [
|
||||
|
||||
.banner-bg {
|
||||
width: 100%;
|
||||
height: 830px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
height: 100%;
|
||||
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) {
|
||||
.banner-content {
|
||||
|
||||
@ -2,103 +2,103 @@
|
||||
<section class="feedback-section">
|
||||
<div class="feedback-title">真实客户案例</div>
|
||||
<div class="feedback-list">
|
||||
<div v-for="(item, index) in feedbackList" :key="index" class="feedback-card">
|
||||
<Marquee
|
||||
:duration="360"
|
||||
: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 text-2-line-ellipsis">{{ item.comment }}</p>
|
||||
<p class="comment">{{ item.result }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
</Marquee>
|
||||
</div>
|
||||
<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>
|
||||
</Marquee>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 模拟假数据(头像统一使用你提供的链接)
|
||||
const feedbackList = [
|
||||
{
|
||||
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'
|
||||
},
|
||||
{
|
||||
username: '派小喵萌宠',
|
||||
comment: '交付与实施阶段很专业,坚持每天汇报进度和风险,并提出很多合理建议~',
|
||||
avatar: 'https://images.health.ufutx.com/202506/12/1c0c9dad7586e6fd00ab781064acc822.png'
|
||||
// import TextGenerateEffect from '@/components/TextGenerateEffect.vue'
|
||||
import Marquee from '@/components/Marquee.vue'
|
||||
import { realCases } from '@/data/realCases.ts'
|
||||
|
||||
// 添加泛型类型 T 表示数组元素的类型
|
||||
function splitArrayRandomly<T>(arr: T[], ratio = 0.5): [T[], T[]] {
|
||||
// 复制原数组避免修改
|
||||
const shuffled = [...arr]
|
||||
|
||||
// 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(realCases))
|
||||
|
||||
console.log('数组1:', feedbackList[0]) // 例如: [3, 7, 2, 5]
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@ -112,66 +112,114 @@ const feedbackList = [
|
||||
@subtext-color: #999;
|
||||
@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 {
|
||||
background-color: @bg-color;
|
||||
.px(100px);
|
||||
padding: 0 0 100px 0; /* 改用标准padding写法,避免自定义.px()可能的问题 */
|
||||
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 {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: @text-color;
|
||||
.pb(60px);
|
||||
.pt(100px);
|
||||
padding: 100px 0 60px;
|
||||
}
|
||||
|
||||
// 跑马灯容器:关键修改——禁止换行,确保内容单行滚动
|
||||
.feedback-list {
|
||||
//width: 100vw;
|
||||
max-width: 1820px;
|
||||
margin: 0 auto;
|
||||
margin-left: 100px;
|
||||
box-sizing: border-box;
|
||||
// 关键:强制水平布局,禁止换行
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: @gap;
|
||||
flex-direction: row; /* 明确水平方向 */
|
||||
flex-wrap: nowrap; /* 禁止换行 */
|
||||
overflow: hidden; /* 隐藏超出容器的部分 */
|
||||
}
|
||||
|
||||
// 反馈卡片:固定宽度,确保排列整齐
|
||||
.feedback-card {
|
||||
transition: @transition;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
width: 362px; /* 固定宽度,确保能在一行放下多个 */
|
||||
//max-width: 320px;
|
||||
flex-shrink: 0; /* 禁止收缩,保证宽度不变 */
|
||||
border-radius: 100px;
|
||||
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 {
|
||||
transform: translateY(-4px);
|
||||
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 {
|
||||
flex-shrink: 0;
|
||||
//margin-right: 12px;
|
||||
margin-right: 20px;
|
||||
|
||||
.avatar {
|
||||
width: @avatar-size;
|
||||
height: @avatar-size;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 2px solid #f0f0f0;
|
||||
}
|
||||
}
|
||||
|
||||
.feedback-info {
|
||||
text-align: left;
|
||||
max-width: calc(100% - @avatar-size - 12px); /* 限制文本区域宽度 */
|
||||
|
||||
.username {
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: @text-color;
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 6px;
|
||||
white-space: nowrap; /* 用户名不换行 */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.comment {
|
||||
width: 250px;
|
||||
font-size: 14px;
|
||||
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 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>
|
||||
<section class="core-value">
|
||||
<div class="container">
|
||||
<!-- <h3 class="section-title">核心价值</h3>-->
|
||||
<!-- <p class="section-desc">友福同享AI健康解决方案应用场景</p>-->
|
||||
<h3 class="section-title">友福七维AI健康修复体系</h3>
|
||||
<p class="section-desc">七大核心维度</p>
|
||||
<!-- 替换为实际图示路径 -->
|
||||
<img
|
||||
src="https://images.health.ufutx.com/202506/17/28710422aa9cf68a38cfbd19abd7ebf0.png"
|
||||
src="https://images.health.ufutx.com/202507/02/37b46d4591aa3244f62320bd60e07549.png"
|
||||
alt="七大核心维度"
|
||||
class="diagram"
|
||||
/>
|
||||
@ -32,12 +32,13 @@
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
color: @text-color;
|
||||
.mt(50px);
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
font-size: 20px;
|
||||
color: @text-color-secondary;
|
||||
margin-bottom: 60px;
|
||||
//margin-bottom: 60px;
|
||||
}
|
||||
|
||||
.diagram {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
>
|
||||
<div class="scene-inner">
|
||||
<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 v-if="activeIndex === index" class="scene-desc">{{ item.desc }}</p>
|
||||
</div>
|
||||
@ -71,8 +72,8 @@ onMounted(() => {
|
||||
text-align: center;
|
||||
background-color: #f5f7fe;
|
||||
.pt(80+42px);
|
||||
.pb(80-42px);
|
||||
|
||||
//.pb(80-42px);
|
||||
height: 580px;
|
||||
.scene-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
|
||||
@ -1,65 +1,153 @@
|
||||
<template>
|
||||
<section class="article-content">
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="loading-container">
|
||||
<p>加载中...</p>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<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">数字健康领域的长期主义者:未来医疗100强友福同享持续领跑</h1>
|
||||
<h1 class="article-title">
|
||||
<TextGenerateEffect :words="article.title" class="" />
|
||||
</h1>
|
||||
<div class="meta-info">
|
||||
<span>发布时间:2025-06-20</span>
|
||||
<span>浏览次数:8604</span>
|
||||
<span>发布时间:{{ article.create_time }}</span>
|
||||
<span>浏览次数:{{ article.read_num }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 封面图 -->
|
||||
<div class="article-banner">
|
||||
<img src="https://images.health.ufutx.com/202506/20/9fd62f318b50764c02c58356dc426d44.png" alt="AI健康领域" />
|
||||
<div v-motion-fade-visible class="article-banner">
|
||||
<!-- <img :src="article.pic" alt="文章封面" class="banner-img" />-->
|
||||
</div>
|
||||
|
||||
<!-- 正文内容 -->
|
||||
<div class="article-body">
|
||||
<p>
|
||||
《1分钟演讲》是一款创新的智能辅助应用,专注于强化公众演讲技能,助力用户高效构思并精准传达思想。它集演讲与实战练习于一体,为用户提供全方位、一站式的自我提升平台。1分钟演讲,这个看似简短却充满力量的表达方式,是真实自我与世界快速沟通的桥梁,也是能快速缩短社交距离、增进信任的神奇钥匙。无论是事业发展、社交拓展、寻找灵魂伴侣,还是个人品牌建设,这一功能都能成为你强而有力的社交工具,帮助你快速脱颖而出,让更多人认识并记住你。友福同享凭借多年在全病程管理、“AI+医疗”领域的卓越成就,稳列未来医疗100强榜单第一梯队!同时,微脉自主研发的CareAI荣膺最佳数字技术产品,获2025未来医疗100强创新奖。
|
||||
</p>
|
||||
<!-- 正文内容(富文本渲染) -->
|
||||
|
||||
<p>
|
||||
「未来医疗100强」榜单以前瞻性、专业性和国际视野为核心,被誉为“医疗创新领域的风向标”,代表未来5-10年全球医疗产业的新势力与变革方向。
|
||||
</p>
|
||||
|
||||
<p>
|
||||
“让医疗服务不再难”
|
||||
是微脉始终如一的使命。微脉从全人群、全方位、全周期出发,专攻医疗服务的现有之短板和就医者的健康服务需求缺口,补足诊后、检后、术后、院后管理空白。
|
||||
</p>
|
||||
<p>
|
||||
在突破医疗健康行业各阶段难点,拓展数字健康领域可能性上,微脉做了许多从0到1的创造和尝试✨,致力于打造中国特色的管理式医疗健康组织(C-CMO)。
|
||||
</p>
|
||||
<p>
|
||||
未来,友福同享将持续深化"AI+全病程管理"创新模式,助力公立医院高质量发展,加快构建"预防-诊疗-康复"全周期健康服务生态,让优质医疗服务惠及更多百姓。
|
||||
</p>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div class="article-body" v-html="article.content"></div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<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>
|
||||
|
||||
<style scoped lang="less">
|
||||
.article-content {
|
||||
padding: 200px 192px 100px 192px;
|
||||
//max-width: 1200px;
|
||||
padding: 200px 192px 100px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
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 {
|
||||
padding-bottom: 30px;
|
||||
border-bottom: 0.3px solid #b5b5b5;
|
||||
|
||||
.article-title {
|
||||
font-size: 32px;
|
||||
font-weight: 400;
|
||||
color: @text-color;
|
||||
margin-bottom: 10px;
|
||||
line-height: 32px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
font-size: 18px;
|
||||
color: @text-color-secondary;
|
||||
@ -75,7 +163,8 @@
|
||||
// 封面图
|
||||
.article-banner {
|
||||
margin: 30px 0;
|
||||
img {
|
||||
|
||||
.banner-img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
@ -83,28 +172,52 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 正文排版
|
||||
// 正文内容(富文本样式适配)
|
||||
.article-body {
|
||||
font-weight: 400;
|
||||
line-height: 35px;
|
||||
p {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
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) {
|
||||
padding: 40px 20px;
|
||||
|
||||
.article-header {
|
||||
.article-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
.meta-info {
|
||||
font-size: 14px;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.article-body {
|
||||
p {
|
||||
text-indent: 0; // 移动端取消缩进
|
||||
text-indent: 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,131 +1,198 @@
|
||||
<template>
|
||||
<!-- 整体布局:导航 + Banner + 内容 + 页脚 -->
|
||||
<div class="page-container">
|
||||
<!-- 已有Banner组件(保持设计中的顶部视觉) -->
|
||||
<!-- 已有Banner组件 -->
|
||||
<BannerCarousel />
|
||||
|
||||
<!-- 核心内容区 -->
|
||||
<div class="news-content">
|
||||
<!-- 标签切换(友福动态 / 媒体报道) -->
|
||||
<el-tabs v-model="activeTab" class="news-tabs" @tab-click="resetPage">
|
||||
<el-tab-pane label="友福动态" name="dynamic"></el-tab-pane>
|
||||
<el-tab-pane label="媒体报道" name="report"></el-tab-pane>
|
||||
<!-- 标签切换(动态加载) -->
|
||||
<el-tabs v-model="activeTab" class="news-tabs" @tab-change="resetPage">
|
||||
<el-tab-pane v-for="item in categories" :key="item.name" :label="item.name" :name="item.name">
|
||||
<template #label>
|
||||
<div class="categories-label">{{ item.name }}</div>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</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">
|
||||
<img :src="item.cover" alt="新闻封面" class="news-cover" />
|
||||
<img :src="item.pic" alt="image" class="news-cover" />
|
||||
<div class="news-info">
|
||||
<h3 class="news-title">{{ item.title }}</h3>
|
||||
<h3 class="news-label">友福新闻</h3>
|
||||
<div class="news-wrap" @click="goToArticle">
|
||||
<h3 class="news-label">{{ item.publisher }}</h3>
|
||||
<div class="news-wrap" @click="openArticleInNewWindow(item.id)">
|
||||
<div class="view-btn">查看详情</div>
|
||||
<div class="news-date">
|
||||
<img
|
||||
class="icon"
|
||||
src="https://images.health.ufutx.com/202506/13/c5e3552a870fd254610290bbabce5e30.png"
|
||||
/>
|
||||
<p>{{ item.date }}</p>
|
||||
<p>{{ item.create_time }}</p>
|
||||
</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">
|
||||
<el-pagination
|
||||
:current-page="currentPage"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
background
|
||||
layout="total,prev, pager, next"
|
||||
:total="totalCount"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
></el-pagination>
|
||||
>
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<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 request from '@/utils/request' // 假设已有请求工具函数
|
||||
|
||||
// 模拟新闻数据(根据设计图,友福动态和媒体报道的差异)
|
||||
const dynamicNews = [
|
||||
{
|
||||
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'
|
||||
}
|
||||
]
|
||||
// 路由相关
|
||||
// import { useRoute, useRouter } from 'vue-router'
|
||||
import { openNewWindow } from '@/utils/navigation.ts'
|
||||
|
||||
// 循环添加数据到两个数组
|
||||
for (let i = 0; i < 15; i++) {
|
||||
const newsItem = {
|
||||
cover: 'https://images.health.ufutx.com/202506/13/b604685780bdb4ea4906e751b14590ec.png',
|
||||
title: `友福动态:健康管理服务升级发布会圆满成功 ${i + 1}`,
|
||||
date: `2025-05-${28 - i}`,
|
||||
type: 'dynamic'
|
||||
}
|
||||
// const route = useRoute()
|
||||
// const router = useRouter()
|
||||
|
||||
// 同时添加到两个数组
|
||||
dynamicNews.push(newsItem)
|
||||
reportNews.push({ ...newsItem, type: 'report' }) // 复制对象并修改 type
|
||||
}
|
||||
// 响应式数据
|
||||
const activeTab = ref('dynamic') // 默认显示“友福动态”
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const totalCount = ref(502) // 设计图中的“共502条”
|
||||
const activeTab = ref('') // 激活标签
|
||||
const currentPage = ref(1) // 当前页码
|
||||
const pageSize = ref(15) // 每页条数
|
||||
const totalCount = ref(0) // 总数据量
|
||||
const loading = ref(false) // 加载状态
|
||||
const categories = ref<Array<any>>([]) // 标签分类
|
||||
const newsData = ref<Array<any>>([]) // 新闻数据
|
||||
|
||||
// 计算当前显示的新闻(根据标签切换)
|
||||
// 计算当前显示的新闻(带分页)
|
||||
const filteredNews = computed(() => {
|
||||
const list = activeTab.value === 'dynamic' ? dynamicNews : reportNews
|
||||
// 模拟分页截取(实际需结合后端接口)
|
||||
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. 初始化路由实例
|
||||
const router = useRouter()
|
||||
|
||||
// 2. 跳转方法(命名路由方式,需提前配置路由)
|
||||
const goToArticle = () => {
|
||||
router.push({
|
||||
path: '/news/12' // 也可直接写路径
|
||||
})
|
||||
// 跳转详情页(携带文章ID)
|
||||
const openArticleInNewWindow = (id: number) => {
|
||||
openNewWindow(`/articleDetail/${id}`)
|
||||
}
|
||||
|
||||
// 获取标签分类列表
|
||||
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) => {
|
||||
pageSize.value = val
|
||||
currentPage.value = 1
|
||||
loadNewsData()
|
||||
}
|
||||
|
||||
const handlePageChange = (val: number) => {
|
||||
currentPage.value = val
|
||||
loadNewsData()
|
||||
}
|
||||
const resetPage = () => {
|
||||
currentPage.value = 1 // 切换标签时重置页码
|
||||
}
|
||||
|
||||
// 组件挂载时加载分类和新闻数据
|
||||
onMounted(async () => {
|
||||
await fetchCategories()
|
||||
if (activeTab.value) {
|
||||
loadNewsData()
|
||||
}
|
||||
})
|
||||
|
||||
// 监听标签切换,重新加载数据
|
||||
// watch(activeTab, () => {
|
||||
// loadNewsData()
|
||||
// })
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@ -136,18 +203,32 @@ const resetPage = () => {
|
||||
background-color: @bg-color;
|
||||
}
|
||||
|
||||
/* 内容区容器 */
|
||||
.news-content {
|
||||
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 {
|
||||
.pt(50px);
|
||||
//align-items: center;
|
||||
|
||||
padding-top: 50px;
|
||||
.categories-label {
|
||||
font-size: 32px;
|
||||
}
|
||||
:deep(.el-tabs__nav-wrap) {
|
||||
//margin-bottom: 1.04167vw;
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@ -169,7 +250,10 @@ const resetPage = () => {
|
||||
|
||||
:deep(.el-tabs__header) {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
|
||||
.el-tabs__nav {
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
|
||||
@ -184,34 +268,43 @@ const resetPage = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.news-tabs {
|
||||
// 关键:让选项卡居中
|
||||
:deep(.el-tabs__header) {
|
||||
width: 100%; // 占满容器宽度,为居中提供基础
|
||||
.el-tabs__nav {
|
||||
justify-content: center; // 水平居中对齐
|
||||
|
||||
// 响应式适配
|
||||
@media (max-width: @tablet-breakpoint) {
|
||||
:deep(.el-tabs__item) {
|
||||
margin-right: @space-md;
|
||||
font-size: @font-size-lg;
|
||||
}
|
||||
|
||||
: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 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 50px;
|
||||
.px(192px);
|
||||
.pt(100px);
|
||||
padding: 100px 192px 0;
|
||||
|
||||
.news-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: @transition;
|
||||
border-bottom: 0.3px solid #b5b5b5;
|
||||
.pb(50px);
|
||||
&:hover {
|
||||
//box-shadow: @shadow-hover;
|
||||
//transform: translateY(-2px);
|
||||
}
|
||||
padding-bottom: 50px;
|
||||
|
||||
.news-cover {
|
||||
width: 500px;
|
||||
@ -220,19 +313,12 @@ const resetPage = () => {
|
||||
border-radius: @border-radius-md;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.news-info {
|
||||
.news-wrap {
|
||||
.flex-between();
|
||||
}
|
||||
width: 100%;
|
||||
.pt(20px);
|
||||
padding-top: 20px;
|
||||
text-align: left;
|
||||
.news-label {
|
||||
font-size: @font-size-sm;
|
||||
color: @text-color-secondary;
|
||||
.mt(13px);
|
||||
.mb(76px);
|
||||
}
|
||||
|
||||
.news-title {
|
||||
font-size: @font-size-lg;
|
||||
font-weight: @font-weight-medium;
|
||||
@ -240,231 +326,184 @@ const resetPage = () => {
|
||||
margin-bottom: @space-sm;
|
||||
}
|
||||
|
||||
.news-label {
|
||||
font-size: @font-size-sm;
|
||||
color: @text-color-secondary;
|
||||
margin-top: 13px;
|
||||
margin-bottom: 76px;
|
||||
}
|
||||
|
||||
.news-wrap {
|
||||
display: flex;
|
||||
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-light;
|
||||
display: flex; // 启用 Flex 布局
|
||||
align-items: center; // 子元素垂直居中
|
||||
color: @text-color-secondary;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式适配
|
||||
@media (max-width: @tablet-breakpoint) {
|
||||
padding: @space-xl @space-md 0;
|
||||
|
||||
.news-item {
|
||||
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 {
|
||||
display: flex;
|
||||
padding: 6px 16px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: @primary-dark;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--1060-ff, #1060ff);
|
||||
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 {
|
||||
margin-top: 50px;
|
||||
.pb(170px);
|
||||
padding-bottom: 170px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
:deep(.el-pager li.is-active) {
|
||||
color: @primary-dark;
|
||||
}
|
||||
|
||||
.el-pagination {
|
||||
.el-pagination__total {
|
||||
color: @text-color-light;
|
||||
}
|
||||
|
||||
.el-pager li {
|
||||
&.active {
|
||||
.el-pager li.active {
|
||||
background-color: @primary-color;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__sizes {
|
||||
margin: 0 @space-md;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式适配(平板以下) */
|
||||
//@media (max-width: @tablet-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 {
|
||||
// 响应式适配
|
||||
@media (max-width: @mobile-breakpoint) {
|
||||
.el-pagination {
|
||||
.el-pagination__total {
|
||||
font-size: @font-size-xs; // 缩小总条数字体
|
||||
font-size: @font-size-xs;
|
||||
}
|
||||
|
||||
.el-pager li {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
font-size: @font-size-xs; // 页码字体
|
||||
font-size: @font-size-xs;
|
||||
}
|
||||
|
||||
.el-pagination__sizes {
|
||||
margin: 0 @space-xs; // 尺寸选择器间距
|
||||
margin: 0 @space-xs;
|
||||
|
||||
.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>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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背景" />
|
||||
</div>
|
||||
@ -66,6 +66,7 @@ const newsList = [
|
||||
|
||||
.banner-bg {
|
||||
width: 100%;
|
||||
height: 830px;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
|
||||
@ -2,43 +2,29 @@
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"lib": [
|
||||
"ES2022",
|
||||
"DOM"
|
||||
],
|
||||
// 关键:添加 DOM 类型库
|
||||
"lib": ["ES2022", "DOM"],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
// 添加路径别名
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"jsx": "preserve",
|
||||
// 支持 Vue 的 JSX 语法
|
||||
"types": [
|
||||
"vite/client",
|
||||
"vue","vue-i18n"
|
||||
],
|
||||
"incremental": true, // 添加这一行
|
||||
// 新增 Vue 类型声明
|
||||
"types": ["vite/client", "vue", "vue-i18n"],
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
// "erasableSyntaxOnly": true, // 移除这个不支持的选项
|
||||
"noFallthroughCasesInSwitch": true
|
||||
// "noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": [
|
||||
// 新增:自动导入的类型定义(根目录)
|
||||
"auto-imports.d.ts",
|
||||
// 新增:自动注册的组件类型定义(根目录)
|
||||
"components.d.ts",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
// 必须包含 Vue 文件
|
||||
"vite.config.ts",
|
||||
// 包含 Vite 配置文件
|
||||
"src/main.ts"
|
||||
// 包含入口文件
|
||||
]
|
||||
}
|
||||
@ -8,10 +8,12 @@ import Components from 'unplugin-vue-components/vite'
|
||||
// 引入 ElementPlus 相关解析器
|
||||
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||
|
||||
// import ElementPlus from 'unplugin-element-plus/vite'
|
||||
import legacy from '@vitejs/plugin-legacy'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
// ElementPlus(),
|
||||
vue(),
|
||||
|
||||
// 仅在生产环境启用 legacy 插件
|
||||
@ -29,19 +31,31 @@ export default defineConfig({
|
||||
// 自动导入 Vue 相关函数,以及 ElementPlus 的相关函数等
|
||||
resolvers: [
|
||||
ElementPlusResolver({
|
||||
importStyle: 'sass',
|
||||
directives: true // 导入指令
|
||||
importStyle: false, // 关闭自动导入样式(手动引入 index.css)
|
||||
directives: true // 导入 Element Plus 指令(如 v-loading)
|
||||
})
|
||||
]
|
||||
// ElementPlusResolver({
|
||||
// importStyle: 'sass',
|
||||
// directives: true // 导入指令
|
||||
// })
|
||||
],
|
||||
dts: true // 生成 auto-imports.d.ts(让 ESLint 识别自动导入的 API)
|
||||
}),
|
||||
Components({
|
||||
// 自动导入 ElementPlus 的组件
|
||||
resolvers: [
|
||||
ElementPlusResolver({
|
||||
importStyle: 'sass',
|
||||
directives: true
|
||||
importStyle: false // 同上,避免与手动引入的样式冲突
|
||||
})
|
||||
],
|
||||
], // 自动解析 Element Plus 组件
|
||||
dts: true, // 生成 components.d.ts(关键:让 ESLint 识别组件)
|
||||
include: [/\.vue$/, /\.vue\?vue/, /\.tsx$/], // 确保覆盖所有组件文件
|
||||
// 自动导入 ElementPlus 的组件
|
||||
// resolvers: [
|
||||
// ElementPlusResolver({
|
||||
// importStyle: 'sass',
|
||||
// directives: true
|
||||
// })
|
||||
// ],
|
||||
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 从打包中
|
||||
output: {
|
||||
manualChunks: undefined // 取消手动分割,使用 Vite 自动策略
|
||||
// manualChunks(id) {
|
||||
// if (id.includes('node_modules')) {
|
||||
// manualChunks: undefined // 取消手动分割,使用 Vite 自动策略
|
||||
manualChunks(id) {
|
||||
if (id.includes('node_modules')) {
|
||||
// 将第三方库单独分包(如 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