SectionScenes.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. <template>
  2. <section class="section-scenes relative overflow-hidden py-28" ref="sectionRef">
  3. <!-- 背景 -->
  4. <div class="absolute inset-0" style="background: linear-gradient(180deg, #ffffff 0%, #f8f5ff 50%, #f0f4ff 100%);"></div>
  5. <!-- 背景装饰圆 -->
  6. <div class="absolute inset-0 pointer-events-none overflow-hidden">
  7. <div class="scene-bg-orb scene-bg-orb-1"></div>
  8. <div class="scene-bg-orb scene-bg-orb-2"></div>
  9. </div>
  10. <div class="relative z-10 max-w-7xl mx-auto px-6">
  11. <!-- 标题 -->
  12. <div class="text-center mb-16 reveal-up" :class="{ 'is-visible': isVisible }">
  13. <span class="inline-flex items-center gap-2 bg-violet-50 border border-violet-200 text-violet-600 text-xs font-bold px-4 py-1.5 rounded-full mb-5 tracking-widest uppercase">
  14. <span class="w-1.5 h-1.5 bg-violet-500 rounded-full animate-pulse"></span>
  15. {{ $t('scenes.badge') }}
  16. </span>
  17. <h2 class="text-5xl lg:text-6xl font-black text-gray-900 mb-5 leading-tight">
  18. {{ $t('scenes.title') }}<span class="scenes-gradient-text">{{ $t('scenes.subtitle') }}</span>
  19. </h2>
  20. <p class="text-gray-500 text-lg max-w-2xl mx-auto leading-relaxed">
  21. {{ $t('scenes.description') }}
  22. </p>
  23. </div>
  24. <!-- 场景切换 Tab -->
  25. <div class="flex flex-wrap justify-center gap-3 mb-14 reveal-up" :class="{ 'is-visible': isVisible }" style="transition-delay: 0.15s;">
  26. <button
  27. v-for="(scene, i) in scenes"
  28. :key="i"
  29. @click="switchScene(i)"
  30. class="scene-tab-btn"
  31. :class="activeScene === i ? 'scene-tab-active' : 'scene-tab-inactive'"
  32. >
  33. <span class="scene-tab-icon">{{ scene.icon }}</span>
  34. <span>{{ scene.name }}</span>
  35. <span class="scene-tab-count" :class="activeScene === i ? 'scene-tab-count-active' : ''">{{ scene.count }}</span>
  36. </button>
  37. </div>
  38. <!-- 主展示区 -->
  39. <div class="grid grid-cols-1 lg:grid-cols-2 gap-8 items-stretch reveal-up" :class="{ 'is-visible': isVisible }" style="transition-delay: 0.3s;">
  40. <!-- 左侧:场景可视化 -->
  41. <div class="scene-visual-card" ref="visualCardRef" @mousemove="onCardMouseMove" @mouseleave="onCardMouseLeave">
  42. <!-- 图片层 -->
  43. <div class="scene-img-wrapper">
  44. <Transition name="scene-zoom">
  45. <img
  46. :key="activeScene"
  47. :src="currentScene.img"
  48. :alt="currentScene.name"
  49. class="scene-img"
  50. />
  51. </Transition>
  52. <div class="scene-img-overlay"></div>
  53. <!-- 顶部效率标签 -->
  54. <div class="scene-efficiency-badge">
  55. <span class="text-3xl font-black text-white">{{ currentScene.efficiency }}</span>
  56. <div>
  57. <div class="text-white text-xs font-bold">{{$t('scenes.metrics.efficiencyImprovement')}}</div>
  58. <div class="text-white/60 text-xs">{{ currentScene.efficiencyLabel }}</div>
  59. </div>
  60. </div>
  61. <!-- 场景名称 -->
  62. <div class="scene-bottom-info">
  63. <div class="flex items-center gap-3 mb-2">
  64. <span class="text-3xl">{{ currentScene.icon }}</span>
  65. <h3 class="text-white text-2xl font-black">{{ currentScene.name }}</h3>
  66. </div>
  67. <p class="text-white/70 text-sm leading-relaxed mb-4">{{ currentScene.desc }}</p>
  68. <!-- 三项指标 -->
  69. <div class="grid grid-cols-3 gap-3">
  70. <div v-for="metric in currentScene.metrics" :key="metric.label"
  71. class="scene-metric-card">
  72. <div class="text-white font-black text-lg">{{ metric.value }}</div>
  73. <div class="text-white/50 text-xs mt-0.5">{{ metric.label }}</div>
  74. </div>
  75. </div>
  76. </div>
  77. </div>
  78. <!-- 底部工具标签 -->
  79. <div class="scene-tools-bar">
  80. <span class="text-white/40 text-xs mr-2">{{$t('scenes.toolsTitle')}}</span>
  81. <Transition name="tools-fade">
  82. <div :key="activeScene" class="flex flex-wrap gap-2">
  83. <span v-for="(tool, ti) in currentScene.tools" :key="tool"
  84. class="scene-tool-tag"
  85. :style="{ animationDelay: `${ti * 0.05}s` }">
  86. {{ tool }}
  87. </span>
  88. </div>
  89. </Transition>
  90. </div>
  91. </div>
  92. <!-- 右侧:步骤流程 -->
  93. <div class="flex flex-col">
  94. <!-- 描述 -->
  95. <div class="mb-6">
  96. <Transition name="text-slide" mode="out-in">
  97. <div :key="activeScene">
  98. <h3 class="text-2xl font-black text-gray-900 mb-2">{{ currentScene.name }}</h3>
  99. <p class="text-gray-500 text-base leading-relaxed">{{ currentScene.longDesc }}</p>
  100. </div>
  101. </Transition>
  102. </div>
  103. <!-- 步骤列表(工作流节点卡片风格)-->
  104. <div class="flex-1">
  105. <Transition name="steps-fade" mode="out-in">
  106. <div :key="activeScene" class="wf-steps-container">
  107. <div
  108. v-for="(step, idx) in currentScene.steps"
  109. :key="step.title"
  110. class="wf-step-row"
  111. :style="{ animationDelay: `${idx * 0.1}s` }"
  112. >
  113. <!-- 左侧:连接线 + 节点圆 -->
  114. <div class="wf-step-spine">
  115. <!-- 连接线(非最后一项才显示)-->
  116. <div v-if="idx < currentScene.steps.length - 1" class="wf-spine-line">
  117. <!-- 流动粒子 -->
  118. <div class="wf-spine-particle" :style="{ animationDelay: `${idx * 0.4}s` }"></div>
  119. </div>
  120. <!-- 节点圆 -->
  121. <div class="wf-step-node"
  122. :class="step.done ? 'wf-node-done' : 'wf-node-pending'"
  123. @click="activeStep = activeStep === idx ? -1 : idx">
  124. <span v-if="step.done" class="wf-node-check">✓</span>
  125. <span v-else class="wf-node-num">{{ idx + 1 }}</span>
  126. <!-- 脉冲环(未完成节点)-->
  127. <div v-if="!step.done" class="wf-node-pulse"></div>
  128. </div>
  129. </div>
  130. <!-- 右侧:节点卡片 -->
  131. <div class="wf-step-card"
  132. :class="activeStep === idx ? 'wf-step-card-active' : 'wf-step-card-inactive'"
  133. @click="activeStep = activeStep === idx ? -1 : idx">
  134. <!-- 卡片顶部 -->
  135. <div class="wf-step-card-top">
  136. <div class="wf-step-card-title">{{ step.title }}</div>
  137. <div class="wf-step-card-badges">
  138. <span class="wf-step-time-badge">⏱ {{ step.time }}</span>
  139. <span class="wf-step-status-badge" :class="step.done ? 'wf-status-done' : 'wf-status-pending'">
  140. {{ step.done ? $t('scenes.status.completed') : $t('scenes.status.pending') }}
  141. </span>
  142. </div>
  143. </div>
  144. <!-- 描述 -->
  145. <div class="wf-step-card-desc">{{ step.desc }}</div>
  146. <!-- 展开标签 -->
  147. <Transition name="tags-expand">
  148. <div v-if="activeStep === idx" class="wf-step-tags">
  149. <span v-for="tag in step.tags" :key="tag" class="wf-step-tag">{{ tag }}</span>
  150. </div>
  151. </Transition>
  152. </div>
  153. </div>
  154. </div>
  155. </Transition>
  156. </div>
  157. <!-- CTA 按钮 -->
  158. <div class="mt-6 flex gap-3">
  159. <button class="scene-cta-primary flex-1">
  160. {{ $t('scenes.cta.experience') }} · {{ currentScene.name }} →
  161. </button>
  162. <button class="scene-cta-secondary px-5">
  163. {{ $t('scenes.cta.viewCases') }}
  164. </button>
  165. </div>
  166. </div>
  167. </div>
  168. </div>
  169. </section>
  170. </template>
  171. <script setup>
  172. import { ref, computed, onMounted } from 'vue'
  173. import { useI18n } from 'vue-i18n'
  174. const { t } = useI18n()
  175. const activeScene = ref(0)
  176. const activeStep = ref(0)
  177. const isVisible = ref(false)
  178. const sectionRef = ref(null)
  179. const visualCardRef = ref(null)
  180. onMounted(() => {
  181. const observer = new IntersectionObserver(
  182. (entries) => { entries.forEach(e => { if (e.isIntersecting) { isVisible.value = true; observer.unobserve(e.target) } }) },
  183. { threshold: 0.1 }
  184. )
  185. if (sectionRef.value) observer.observe(sectionRef.value)
  186. })
  187. function onCardMouseMove(e) {
  188. const card = visualCardRef.value
  189. if (!card) return
  190. const rect = card.getBoundingClientRect()
  191. const x = (e.clientX - rect.left) / rect.width - 0.5
  192. const y = (e.clientY - rect.top) / rect.height - 0.5
  193. card.style.transform = `perspective(1000px) rotateY(${x * 8}deg) rotateX(${-y * 6}deg) scale(1.02)`
  194. }
  195. function onCardMouseLeave() {
  196. if (visualCardRef.value) {
  197. visualCardRef.value.style.transform = 'perspective(1000px) rotateY(0deg) rotateX(0deg) scale(1)'
  198. }
  199. }
  200. const scenes = [
  201. {
  202. icon: '✍️', name: t('scenes.scenes.contentCreation.name'), count: '428x',
  203. efficiency: '10x', efficiencyLabel: t('scenes.scenes.contentCreation.efficiencyLabel'),
  204. img: 'https://images.unsplash.com/photo-1455390582262-044cdead277a?w=800&h=600&fit=crop&q=80',
  205. desc:t('scenes.scenes.contentCreation.desc'),
  206. longDesc: t('scenes.scenes.contentCreation.longDesc'),
  207. metrics: [
  208. { value: '10x', label: t('scenes.scenes.contentCreation.metrics.0.label') },
  209. { value: t('scenes.metrics.platformCount'), label: t('scenes.scenes.contentCreation.metrics.1.label') },
  210. { value: '<5min', label: t('scenes.scenes.contentCreation.metrics.2.label') }],
  211. tools: ['GPT-4', 'Claude', t('scenes.platforms.wechat'), t('scenes.platforms.xiaohongshu'), t('scenes.platforms.douyin'), 'n8n'],
  212. steps: [
  213. { title: t('scenes.scenes.contentCreation.steps.0.title'), desc: t('scenes.scenes.contentCreation.steps.0.desc'), time: '10s', done: true, tags: [t('scenes.tags.batchExpansion'), t('scenes.tags.topicAnalysis')] },
  214. { title: t('scenes.scenes.contentCreation.steps.1.title'), desc: t('scenes.scenes.contentCreation.steps.1.desc'), time: '40s', done: true, tags: ['GPT-4', 'Claude', t('scenes.tags.autoImage')] },
  215. { title: t('scenes.scenes.contentCreation.steps.2.title'), desc: t('scenes.scenes.contentCreation.steps.2.desc'), time: '20s', done: true, tags: [t('scenes.tags.formatConversion'), t('scenes.tags.autoTypesetting')] },
  216. { title: t('scenes.scenes.contentCreation.steps.3.title'), desc: t('scenes.scenes.contentCreation.steps.3.desc'), time: '5s', done: false, tags: [t('scenes.tags.multiPlatform'), t('scenes.tags.scheduledPublishing')] }
  217. ]
  218. },
  219. {
  220. icon: '🤖', name: t('scenes.scenes.customerService.name'), count: '528x',
  221. efficiency: '95%', efficiencyLabel: t('scenes.scenes.customerService.efficiencyLabel'),
  222. img: 'https://images.unsplash.com/photo-1596526131083-e8c633c948d2?w=800&h=600&fit=crop&q=80',
  223. desc: t('scenes.scenes.customerService.desc'),
  224. longDesc: t('scenes.scenes.customerService.longDesc'),
  225. metrics: [{ value: '95%', label: t('scenes.scenes.customerService.metrics.0.label') }, { value: '7×24h', label: t('scenes.scenes.customerService.metrics.1.label') }, { value: '<2s', label: t('scenes.scenes.customerService.metrics.2.label') }],
  226. tools: ['FastGPT', 'Coze', t('scenes.platforms.wechat'), t('scenes.platforms.feishu'), t('scenes.platforms.dingtalk'), 'Zendesk'],
  227. steps: [
  228. { title: t('scenes.scenes.customerService.steps.0.title'), desc: t('scenes.scenes.customerService.steps.0.desc'), time: '5min', done: true, tags: [t('scenes.tags.pdfParsing'), t('scenes.tags.vectorization'),t('scenes.tags.autoUpdate')] },
  229. { title: t('scenes.scenes.customerService.steps.1.title'), desc: t('scenes.scenes.customerService.steps.1.desc'), time: '0.1s', done: true, tags: ['NLU', t('scenes.tags.multiTurnDialogue')] },
  230. { title: t('scenes.scenes.customerService.steps.2.title'), desc: t('scenes.scenes.customerService.steps.2.desc'), time: '1.5s', done: true, tags: ['RAG检索', t('scenes.tags.contextUnderstanding')] },
  231. { title: t('scenes.scenes.customerService.steps.3.title'), desc: t('scenes.scenes.customerService.steps.3.desc'), time: t('scenes.tags.realTime'), done: false, tags: [t('scenes.tags.intelligentTransfer'),t('scenes.tags.contextTransfer')] }
  232. ]
  233. },
  234. {
  235. icon: '📊', name: t('scenes.scenes.dataAnalysis.name'), count: '368x',
  236. efficiency: '8h→20min', efficiencyLabel: t('scenes.scenes.dataAnalysis.efficiencyLabel'),
  237. img: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=800&h=600&fit=crop&q=80',
  238. desc: t('scenes.scenes.dataAnalysis.desc'),
  239. longDesc: t('scenes.scenes.dataAnalysis.longDesc'),
  240. metrics: [{ value: '8h→20min', label: t('scenes.scenes.dataAnalysis.metrics.0.label') }, { value: t('scenes.metrics.dataSources'), label: t('scenes.scenes.dataAnalysis.metrics.1.label') }, { value: t('scenes.tags.autoPush'), label: t('scenes.scenes.dataAnalysis.metrics.2.label') }],
  241. tools: ['n8n', 'Python', 'MySQL', 'Google Sheets', t('scenes.platforms.feishu'), 'Slack'],
  242. steps: [
  243. { title: t('scenes.scenes.dataAnalysis.steps.0.title'), desc: t('scenes.scenes.dataAnalysis.steps.0.desc'), time: '2min', done: true, tags: ['MySQL', 'API', 'Excel'] },
  244. { title: t('scenes.scenes.dataAnalysis.steps.1.title'), desc: t('scenes.scenes.dataAnalysis.steps.1.desc'), time: '3min', done: true, tags: [t('scenes.tags.deduplication'), t('scenes.tags.deduplication'), t('scenes.tags.anomalyDetection')] },
  245. { title: t('scenes.scenes.dataAnalysis.steps.2.title'), desc: t('scenes.scenes.dataAnalysis.steps.2.desc'), time: '5min', done: true, tags: [t('scenes.tags.trendAnalysis'), t('scenes.tags.aiPrediction')] },
  246. { title: t('scenes.scenes.dataAnalysis.steps.3.title'), desc: t('scenes.scenes.dataAnalysis.steps.3.desc'), time: '1min', done: false, tags: [t('scenes.tags.chartGeneration'), t('scenes.tags.scheduledPush')] }
  247. ]
  248. },
  249. {
  250. icon: '💼', name: t('scenes.scenes.sales.name'), count: '268x',
  251. efficiency: '3x', efficiencyLabel: t('scenes.scenes.sales.efficiencyLabel'),
  252. img: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=800&h=600&fit=crop&q=80',
  253. desc: t('scenes.scenes.sales.desc'),
  254. longDesc: t('scenes.scenes.sales.longDesc'),
  255. metrics: [{ value: '3x', label: t('scenes.scenes.sales.metrics.0.label') }, { value: t('scenes.tags.autoFollowUp'), label: t('scenes.scenes.sales.metrics.1.label') }, { value: t('scenes.tags.personalization'), label: t('scenes.scenes.sales.metrics.2.label') }],
  256. tools: ['Coze', 'Dify', 'Salesforce', t('scenes.platforms.wechatWork'),, t('scenes.platforms.feishu'), 'HubSpot'],
  257. steps: [
  258. { title: t('scenes.scenes.sales.steps.0.title'), desc: t('scenes.scenes.sales.steps.0.desc'), time: t('scenes.tags.realTime'), done: true, tags: [t('scenes.tags.behaviorAnalysis'), t('scenes.tags.intentScoring')] },
  259. { title: t('scenes.scenes.sales.steps.1.title'), desc: t('scenes.scenes.sales.steps.1.desc'), time: '5min', done: true, tags: [t('scenes.tags.personalization'), t('scenes.tags.autoSending')] },
  260. { title: t('scenes.scenes.sales.steps.2.title'), desc: t('scenes.scenes.sales.steps.2.desc'), time: t('scenes.tags.auto'), done: true, tags: [t('scenes.tags.intelligentReminder'), t('scenes.tags.crmSync')] },
  261. { title: t('scenes.scenes.sales.steps.3.title'), desc: t('scenes.scenes.sales.steps.3.desc'), time: '2min', done: false, tags: [t('scenes.tags.planCustomization'), t('scenes.tags.pdfGeneration')] }
  262. ]
  263. }
  264. ]
  265. const currentScene = computed(() => scenes[activeScene.value])
  266. const stepAnimating = ref(false)
  267. function switchScene(idx) {
  268. if (activeScene.value === idx) return
  269. stepAnimating.value = true
  270. activeScene.value = idx
  271. activeStep.value = 0
  272. // 切换后重置动画状态
  273. setTimeout(() => { stepAnimating.value = false }, 100)
  274. }
  275. </script>
  276. <style scoped>
  277. /* 背景光晕 */
  278. .scene-bg-orb {
  279. position: absolute;
  280. border-radius: 50%;
  281. filter: blur(100px);
  282. pointer-events: none;
  283. }
  284. .scene-bg-orb-1 {
  285. width: 600px; height: 600px;
  286. top: -200px; right: -100px;
  287. background: radial-gradient(circle, rgba(139,92,246,0.12) 0%, transparent 70%);
  288. animation: orbFloat 14s ease-in-out infinite;
  289. }
  290. .scene-bg-orb-2 {
  291. width: 500px; height: 500px;
  292. bottom: -150px; left: -100px;
  293. background: radial-gradient(circle, rgba(59,130,246,0.1) 0%, transparent 70%);
  294. animation: orbFloat 18s ease-in-out infinite reverse;
  295. }
  296. @keyframes orbFloat {
  297. 0%, 100% { transform: translate(0, 0); }
  298. 50% { transform: translate(25px, -35px); }
  299. }
  300. /* 渐变文字 */
  301. .scenes-gradient-text {
  302. background: linear-gradient(135deg, #7c3aed 0%, #4f46e5 50%, #0ea5e9 100%);
  303. -webkit-background-clip: text;
  304. background-clip: text;
  305. -webkit-text-fill-color: transparent;
  306. }
  307. /* Tab 按钮 */
  308. .scene-tab-btn {
  309. display: flex;
  310. align-items: center;
  311. gap: 8px;
  312. padding: 10px 20px;
  313. border-radius: 50px;
  314. font-size: 14px;
  315. font-weight: 600;
  316. transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  317. cursor: pointer;
  318. position: relative;
  319. overflow: hidden;
  320. }
  321. .scene-tab-active {
  322. background: linear-gradient(135deg, #7c3aed, #4f46e5);
  323. color: white;
  324. box-shadow: 0 8px 24px rgba(124,58,237,0.35);
  325. transform: scale(1.05);
  326. }
  327. .scene-tab-inactive {
  328. background: white;
  329. color: #6b7280;
  330. border: 1px solid #e5e7eb;
  331. }
  332. .scene-tab-inactive:hover {
  333. border-color: #c4b5fd;
  334. color: #7c3aed;
  335. background: #faf5ff;
  336. transform: translateY(-2px);
  337. box-shadow: 0 4px 12px rgba(124,58,237,0.1);
  338. }
  339. .scene-tab-icon {
  340. font-size: 16px;
  341. transition: transform 0.3s ease;
  342. }
  343. .scene-tab-btn:hover .scene-tab-icon {
  344. transform: scale(1.2);
  345. }
  346. .scene-tab-count {
  347. font-size: 11px;
  348. padding: 2px 6px;
  349. border-radius: 20px;
  350. background: rgba(0,0,0,0.08);
  351. color: inherit;
  352. opacity: 0.7;
  353. }
  354. .scene-tab-count-active {
  355. background: rgba(255,255,255,0.2);
  356. }
  357. /* 视觉卡片 */
  358. .scene-visual-card {
  359. border-radius: 24px;
  360. overflow: hidden;
  361. background: #111827;
  362. min-height: 480px;
  363. display: flex;
  364. flex-direction: column;
  365. transition: transform 0.15s ease;
  366. box-shadow: 0 25px 60px rgba(0,0,0,0.25);
  367. }
  368. .scene-img-wrapper {
  369. position: relative;
  370. flex: 1;
  371. overflow: hidden;
  372. }
  373. .scene-img {
  374. position: absolute;
  375. inset: 0;
  376. width: 100%;
  377. height: 100%;
  378. object-fit: cover;
  379. opacity: 0.55;
  380. }
  381. .scene-img-overlay {
  382. position: absolute;
  383. inset: 0;
  384. background: linear-gradient(to top, #111827 0%, rgba(17,24,39,0.4) 50%, transparent 100%);
  385. }
  386. .scene-efficiency-badge {
  387. position: absolute;
  388. top: 20px; left: 20px;
  389. display: flex;
  390. align-items: center;
  391. gap: 10px;
  392. background: rgba(0,0,0,0.55);
  393. backdrop-filter: blur(8px);
  394. border: 1px solid rgba(255,255,255,0.1);
  395. border-radius: 16px;
  396. padding: 10px 16px;
  397. }
  398. .scene-bottom-info {
  399. position: absolute;
  400. bottom: 0; left: 0; right: 0;
  401. padding: 24px;
  402. }
  403. .scene-metric-card {
  404. background: rgba(255,255,255,0.08);
  405. backdrop-filter: blur(8px);
  406. border: 1px solid rgba(255,255,255,0.1);
  407. border-radius: 14px;
  408. padding: 10px;
  409. text-align: center;
  410. }
  411. .scene-tools-bar {
  412. background: rgba(17,24,39,0.95);
  413. border-top: 1px solid rgba(255,255,255,0.06);
  414. padding: 14px 20px;
  415. display: flex;
  416. align-items: center;
  417. flex-wrap: wrap;
  418. gap: 8px;
  419. }
  420. .scene-tool-tag {
  421. font-size: 11px;
  422. background: rgba(255,255,255,0.08);
  423. color: rgba(255,255,255,0.7);
  424. border: 1px solid rgba(255,255,255,0.1);
  425. padding: 4px 10px;
  426. border-radius: 20px;
  427. cursor: pointer;
  428. transition: all 0.2s ease;
  429. animation: tagFadeIn 0.3s ease both;
  430. }
  431. .scene-tool-tag:hover {
  432. background: rgba(139,92,246,0.2);
  433. border-color: rgba(139,92,246,0.4);
  434. color: #c4b5fd;
  435. }
  436. @keyframes tagFadeIn {
  437. from { opacity: 0; transform: scale(0.8); }
  438. to { opacity: 1; transform: scale(1); }
  439. }
  440. /* ===== 工作流节点卡片步骤风格 ===== */
  441. .wf-steps-container {
  442. display: flex;
  443. flex-direction: column;
  444. gap: 0;
  445. }
  446. .wf-step-row {
  447. display: flex;
  448. gap: 14px;
  449. align-items: flex-start;
  450. animation: stepFadeIn 0.4s ease both;
  451. }
  452. @keyframes stepFadeIn {
  453. from { opacity: 0; transform: translateX(-12px); }
  454. to { opacity: 1; transform: translateX(0); }
  455. }
  456. /* 左侧连接线 + 节点圆 */
  457. .wf-step-spine {
  458. display: flex;
  459. flex-direction: column;
  460. align-items: center;
  461. flex-shrink: 0;
  462. width: 32px;
  463. padding-top: 4px;
  464. }
  465. .wf-spine-line {
  466. flex: 1;
  467. width: 2px;
  468. min-height: 40px;
  469. background: linear-gradient(180deg, rgba(124,58,237,0.3), rgba(79,70,229,0.1));
  470. border-radius: 2px;
  471. position: relative;
  472. overflow: hidden;
  473. margin: 4px 0;
  474. order: 2;
  475. }
  476. .wf-spine-particle {
  477. position: absolute;
  478. top: -6px;
  479. left: 50%;
  480. transform: translateX(-50%);
  481. width: 4px; height: 4px;
  482. border-radius: 50%;
  483. background: #7c3aed;
  484. box-shadow: 0 0 6px #7c3aed;
  485. animation: particleFall 2s linear infinite;
  486. }
  487. @keyframes particleFall {
  488. 0% { top: -6px; opacity: 0; }
  489. 10% { opacity: 1; }
  490. 90% { opacity: 0.8; }
  491. 100% { top: 100%; opacity: 0; }
  492. }
  493. /* 节点圆 */
  494. .wf-step-node {
  495. position: relative;
  496. width: 32px; height: 32px;
  497. border-radius: 50%;
  498. display: flex;
  499. align-items: center;
  500. justify-content: center;
  501. font-size: 12px;
  502. font-weight: 800;
  503. cursor: pointer;
  504. transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  505. flex-shrink: 0;
  506. order: 1;
  507. z-index: 2;
  508. }
  509. .wf-node-done {
  510. background: linear-gradient(135deg, #10B981, #059669);
  511. color: white;
  512. box-shadow: 0 4px 12px rgba(16,185,129,0.35);
  513. }
  514. .wf-node-done:hover {
  515. transform: scale(1.15);
  516. box-shadow: 0 6px 18px rgba(16,185,129,0.45);
  517. }
  518. .wf-node-pending {
  519. background: linear-gradient(135deg, #7c3aed, #4f46e5);
  520. color: white;
  521. box-shadow: 0 4px 12px rgba(124,58,237,0.35);
  522. }
  523. .wf-node-pending:hover {
  524. transform: scale(1.15);
  525. box-shadow: 0 6px 18px rgba(124,58,237,0.45);
  526. }
  527. .wf-node-check { font-size: 13px; }
  528. .wf-node-num { font-size: 11px; }
  529. /* 节点脉冲环 */
  530. .wf-node-pulse {
  531. position: absolute;
  532. inset: -4px;
  533. border-radius: 50%;
  534. border: 2px solid rgba(124,58,237,0.4);
  535. animation: nodePulse 2s ease-in-out infinite;
  536. }
  537. @keyframes nodePulse {
  538. 0%, 100% { transform: scale(1); opacity: 0.6; }
  539. 50% { transform: scale(1.3); opacity: 0; }
  540. }
  541. /* 右侧卡片 */
  542. .wf-step-card {
  543. flex: 1;
  544. border-radius: 14px;
  545. border: 1px solid transparent;
  546. padding: 12px 14px;
  547. cursor: pointer;
  548. transition: all 0.3s ease;
  549. margin-bottom: 10px;
  550. }
  551. .wf-step-card-active {
  552. background: linear-gradient(135deg, rgba(124,58,237,0.06), rgba(79,70,229,0.04));
  553. border-color: rgba(124,58,237,0.25);
  554. box-shadow: 0 4px 20px rgba(124,58,237,0.1), inset 0 1px 0 rgba(255,255,255,0.8);
  555. }
  556. .wf-step-card-inactive {
  557. background: #fafafa;
  558. border-color: #f0f0f0;
  559. }
  560. .wf-step-card-inactive:hover {
  561. background: #faf5ff;
  562. border-color: rgba(196,181,253,0.5);
  563. box-shadow: 0 2px 12px rgba(124,58,237,0.06);
  564. }
  565. .wf-step-card-top {
  566. display: flex;
  567. align-items: center;
  568. justify-content: space-between;
  569. margin-bottom: 5px;
  570. gap: 8px;
  571. }
  572. .wf-step-card-title {
  573. font-size: 13px;
  574. font-weight: 700;
  575. color: #1f2937;
  576. flex: 1;
  577. }
  578. .wf-step-card-badges {
  579. display: flex;
  580. align-items: center;
  581. gap: 5px;
  582. flex-shrink: 0;
  583. }
  584. .wf-step-time-badge {
  585. font-size: 10px;
  586. font-weight: 600;
  587. color: #6b7280;
  588. background: #f3f4f6;
  589. padding: 2px 6px;
  590. border-radius: 100px;
  591. font-family: monospace;
  592. }
  593. .wf-step-status-badge {
  594. font-size: 10px;
  595. font-weight: 700;
  596. padding: 2px 7px;
  597. border-radius: 100px;
  598. }
  599. .wf-status-done {
  600. background: rgba(16,185,129,0.1);
  601. color: #059669;
  602. }
  603. .wf-status-pending {
  604. background: rgba(124,58,237,0.1);
  605. color: #7c3aed;
  606. animation: statusBlink 2s ease-in-out infinite;
  607. }
  608. @keyframes statusBlink {
  609. 0%, 100% { opacity: 1; }
  610. 50% { opacity: 0.5; }
  611. }
  612. .wf-step-card-desc {
  613. font-size: 12px;
  614. color: #6b7280;
  615. line-height: 1.5;
  616. }
  617. .wf-step-tags {
  618. display: flex;
  619. flex-wrap: wrap;
  620. gap: 5px;
  621. margin-top: 8px;
  622. }
  623. .wf-step-tag {
  624. font-size: 10px;
  625. font-weight: 600;
  626. padding: 2px 8px;
  627. background: rgba(124,58,237,0.08);
  628. color: #7c3aed;
  629. border: 1px solid rgba(124,58,237,0.15);
  630. border-radius: 100px;
  631. }
  632. /* CTA 按钮 */
  633. .scene-cta-primary {
  634. background: linear-gradient(135deg, #7c3aed, #4f46e5);
  635. color: white;
  636. font-size: 14px;
  637. font-weight: 700;
  638. padding: 14px 24px;
  639. border-radius: 16px;
  640. transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  641. position: relative;
  642. overflow: hidden;
  643. }
  644. .scene-cta-primary::before {
  645. content: '';
  646. position: absolute;
  647. inset: 0;
  648. background: linear-gradient(135deg, rgba(255,255,255,0.1), transparent);
  649. opacity: 0;
  650. transition: opacity 0.3s ease;
  651. }
  652. .scene-cta-primary:hover {
  653. box-shadow: 0 12px 32px rgba(124,58,237,0.4);
  654. transform: translateY(-2px);
  655. }
  656. .scene-cta-primary:hover::before { opacity: 1; }
  657. .scene-cta-secondary {
  658. padding: 14px;
  659. border-radius: 16px;
  660. border: 1px solid #e5e7eb;
  661. color: #6b7280;
  662. font-size: 14px;
  663. font-weight: 600;
  664. transition: all 0.3s ease;
  665. }
  666. .scene-cta-secondary:hover {
  667. border-color: #c4b5fd;
  668. color: #7c3aed;
  669. background: #faf5ff;
  670. }
  671. /* 过渡动画 */
  672. .scene-zoom-enter-active { transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); }
  673. .scene-zoom-leave-active { transition: all 0.3s ease; }
  674. .scene-zoom-enter-from { opacity: 0; transform: scale(1.08); }
  675. .scene-zoom-leave-to { opacity: 0; transform: scale(0.95); }
  676. .text-slide-enter-active { transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); }
  677. .text-slide-leave-active { transition: all 0.25s ease; }
  678. .text-slide-enter-from { opacity: 0; transform: translateY(12px); }
  679. .text-slide-leave-to { opacity: 0; transform: translateY(-8px); }
  680. .steps-fade-enter-active { transition: all 0.4s ease; }
  681. .steps-fade-leave-active { transition: all 0.2s ease; }
  682. .steps-fade-enter-from { opacity: 0; }
  683. .steps-fade-leave-to { opacity: 0; }
  684. .tools-fade-enter-active { transition: all 0.3s ease; }
  685. .tools-fade-leave-active { transition: all 0.2s ease; }
  686. .tools-fade-enter-from { opacity: 0; }
  687. .tools-fade-leave-to { opacity: 0; }
  688. .tags-expand-enter-active { transition: all 0.3s ease; }
  689. .tags-expand-leave-active { transition: all 0.2s ease; }
  690. .tags-expand-enter-from { opacity: 0; transform: translateY(-4px); }
  691. .tags-expand-leave-to { opacity: 0; transform: translateY(-4px); }
  692. /* 滚动动画 */
  693. .reveal-up {
  694. opacity: 0;
  695. transform: translateY(40px);
  696. transition: opacity 0.8s ease, transform 0.8s ease;
  697. }
  698. .reveal-up.is-visible {
  699. opacity: 1;
  700. transform: translateY(0);
  701. }
  702. /* ===== 响应式 ===== */
  703. /* 标题响应式 */
  704. .section-scenes h2 {
  705. font-size: clamp(2rem, 5vw, 3.75rem);
  706. }
  707. /* 平板(≤1024px)*/
  708. @media (max-width: 1024px) {
  709. .section-scenes { padding-top: 5rem; padding-bottom: 5rem; }
  710. .scene-visual-card { min-height: 380px; }
  711. }
  712. /* 手机横屏 / 小平板(≤768px)*/
  713. @media (max-width: 768px) {
  714. .section-scenes { padding-top: 4rem; padding-bottom: 4rem; }
  715. .section-scenes .max-w-7xl { padding-left: 1rem; padding-right: 1rem; }
  716. .scene-tab-btn { padding: 8px 14px; font-size: 13px; }
  717. .scene-visual-card { min-height: 300px; }
  718. .scene-efficiency-badge { top: 12px; left: 12px; padding: 8px 12px; }
  719. .scene-efficiency-badge .text-3xl { font-size: 1.5rem; }
  720. .scene-bottom-info { padding: 16px; }
  721. .scene-bottom-info h3 { font-size: 1.25rem; }
  722. .scene-bottom-info p { font-size: 0.8rem; }
  723. .scene-metric-card { padding: 8px 6px; }
  724. .scene-metric-card .text-lg { font-size: 1rem; }
  725. .scene-tools-bar { padding: 10px 14px; }
  726. .scene-step-item { padding: 10px 12px; gap: 10px; }
  727. .scene-step-num { width: 30px; height: 30px; font-size: 12px; }
  728. .scene-cta-primary, .scene-cta-secondary { padding: 11px 18px; font-size: 13px; }
  729. }
  730. /* 手机竖屏(≤480px)*/
  731. @media (max-width: 480px) {
  732. .section-scenes { padding-top: 3rem; padding-bottom: 3rem; }
  733. .scene-tab-btn { padding: 7px 11px; font-size: 12px; gap: 5px; }
  734. .scene-tab-icon { font-size: 13px; }
  735. .scene-tab-count { display: none; }
  736. .scene-visual-card { min-height: 240px; }
  737. .scene-efficiency-badge { display: none; }
  738. .scene-bottom-info { padding: 12px; }
  739. .scene-bottom-info h3 { font-size: 1.1rem; }
  740. .scene-bottom-info .grid-cols-3 { grid-template-columns: repeat(3, 1fr); gap: 6px; }
  741. .scene-step-item { padding: 8px 10px; gap: 8px; }
  742. .scene-step-num { width: 26px; height: 26px; font-size: 11px; border-radius: 8px; }
  743. .scene-cta-primary, .scene-cta-secondary { padding: 10px 14px; font-size: 12px; }
  744. }
  745. /* 极小屏(≤360px)*/
  746. @media (max-width: 360px) {
  747. .scene-tab-btn { padding: 6px 9px; font-size: 11px; }
  748. .scene-visual-card { min-height: 200px; }
  749. .scene-step-num { width: 24px; height: 24px; font-size: 10px; }
  750. }
  751. </style>