第一发布版本,logo,图片优化

This commit is contained in:
Jafeng 2026-04-30 16:08:32 +08:00
parent c5c9cb5cee
commit e63b67ea7b
20 changed files with 219 additions and 89 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
public/assets/客服.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
public/assets/广附一.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/assets/服务商.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
public/assets/震元.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -60,7 +60,7 @@ const handleCategoryKeydown = (event, index) => {
</aside>
<div id="case-panel" class="case-grid" role="tabpanel" :aria-label="active">
<article v-for="item in filteredCases" :key="`${active}-${item.name}`" class="case-card">
<div :class="['case-logo-slot', { 'case-logo-slot--placeholder': !item.logo }]">
<div :class="['case-logo-slot', item.logoFit && `case-logo-slot--${item.logoFit}`, { 'case-logo-slot--placeholder': !item.logo }]">
<img v-if="item.logo" :src="item.logo" :alt="`${item.name.replace(/\n/g, '')} logo`" />
<span v-else :class="['case-logo-fallback', `case-logo--${item.tone}`]">{{ item.short }}</span>
</div>

View File

@ -25,21 +25,15 @@ import SectionTitle from './SectionTitle.vue'
<div class="contact-manager-grid">
<article class="manager-card">
<div class="manager-copy">
<span class="manager-icon">
<IconMark name="user" :size="22" />
</span>
<p><strong>客户成功经理王经理</strong><br /></p>
</div>
<QrPlaceholder label="王经理个人码" small />
<QrPlaceholder image="/assets/王经理二维码.jpg" label="扫码联系王经理" />
</article>
<article class="manager-card">
<div class="manager-copy">
<span class="manager-icon">
<IconMark name="user" :size="22" />
</span>
<p><strong>客户成功经理罗经理</strong><br /></p>
</div>
<QrPlaceholder label="罗经理个人码" small />
<QrPlaceholder image="/assets/罗经理二维码.png" label="扫码联系罗经理" />
</article>
</div>
</div>

View File

@ -2,10 +2,11 @@
<footer class="site-footer">
<div class="container footer-inner">
<div class="footer-brand">
<img src="/assets/logo.png" alt="柚康 logo" />
<img class="footer-logo" src="/assets/logo.png" alt="柚康科技 logo" />
<span>
<strong>柚康</strong>
<em>企业微信服务商标识</em>
<strong>柚康科技</strong>
<i class="brand-separator" aria-hidden="true"></i>
<img class="brand-service" src="/assets/服务商.png" alt="企业微信服务商" />
</span>
</div>
<p>© 2026 杭州柚康科技有限公司 版权所有</p>

View File

@ -85,11 +85,12 @@ onBeforeUnmount(() => {
<template>
<header class="site-header">
<div class="container header-inner">
<a class="brand" href="#home" aria-label="柚康首页" @click.prevent="scrollToTarget('home')">
<img src="/assets/logo.png" alt="柚康 logo" class="brand-logo" />
<a class="brand" href="#home" aria-label="柚康科技首页" @click.prevent="scrollToTarget('home')">
<img src="/assets/logo.png" alt="柚康科技 logo" class="brand-logo" />
<span class="brand-copy">
<strong>柚康</strong>
<em>企业微信服务商标识</em>
<strong>柚康科技</strong>
<i class="brand-separator" aria-hidden="true"></i>
<img class="brand-service" src="/assets/服务商.png" alt="企业微信服务商" />
</span>
</a>
<button

View File

@ -1,5 +1,6 @@
<script setup>
const props = defineProps({
image: { type: String, default: '' },
label: { type: String, default: '二维码占位' },
small: { type: Boolean, default: false }
})
@ -7,7 +8,8 @@ const props = defineProps({
<template>
<div class="qr-wrap" :class="{ 'qr-wrap--small': small }" role="img" :aria-label="props.label">
<div class="qr-fake">
<img v-if="image" class="qr-image" :src="image" :alt="props.label" />
<div v-else class="qr-fake">
<span class="qr-corner tl"></span>
<span class="qr-corner tr"></span>
<span class="qr-corner bl"></span>

View File

@ -1,17 +1,22 @@
<script setup>
import { computed, ref } from 'vue'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { solutions } from '../data/homepage'
import QrPlaceholder from './QrPlaceholder.vue'
const activeKey = ref(solutions[0].key)
const isMobile = ref(false)
const activeIndex = computed(() => solutions.findIndex(item => item.key === activeKey.value))
const activeSolution = computed(() => solutions[activeIndex.value] ?? solutions[0])
let mobileMediaQuery
const selectSolution = (index) => {
if (!isMobile.value) return
activeKey.value = solutions[index]?.key ?? solutions[0].key
}
const handleTabKeydown = (event, index) => {
if (!isMobile.value) return
const keyMap = {
ArrowRight: 1,
ArrowDown: 1,
@ -35,6 +40,20 @@ const handleTabKeydown = (event, index) => {
selectSolution(nextIndex)
document.getElementById(`solution-tab-${solutions[nextIndex].key}`)?.focus()
}
const updateViewportMode = () => {
isMobile.value = mobileMediaQuery.matches
}
onMounted(() => {
mobileMediaQuery = window.matchMedia('(max-width: 860px)')
updateViewportMode()
mobileMediaQuery.addEventListener('change', updateViewportMode)
})
onBeforeUnmount(() => {
mobileMediaQuery?.removeEventListener('change', updateViewportMode)
})
</script>
<template>
@ -46,23 +65,24 @@ const handleTabKeydown = (event, index) => {
:key="solution.key"
:id="`solution-tab-${solution.key}`"
type="button"
:class="['solution-tab', { active: solution.key === activeKey }]"
:class="['solution-tab', { active: isMobile && solution.key === activeKey }]"
role="tab"
:aria-selected="solution.key === activeKey"
:aria-selected="isMobile ? solution.key === activeKey : undefined"
aria-controls="solution-panel"
:tabindex="solution.key === activeKey ? 0 : -1"
:tabindex="isMobile ? (solution.key === activeKey ? 0 : -1) : -1"
@click="selectSolution(index)"
@keydown="handleTabKeydown($event, index)"
>
{{ solution.tab }}
</button>
<span class="tab-indicator" :style="{ transform: `translateX(${activeIndex * 100}%)` }"></span>
<span v-if="isMobile" class="tab-indicator" :style="{ transform: `translateX(${activeIndex * 100}%)` }"></span>
</div>
<div class="solution-grid solution-grid--desktop">
<article
v-for="solution in solutions"
:key="solution.key"
:id="`solution-card-${solution.key}`"
class="solution-card"
>
<div class="solution-card-top">
@ -74,8 +94,8 @@ const handleTabKeydown = (event, index) => {
</ol>
<p v-else class="solution-personal-text">{{ solution.points[0] }}</p>
<div class="solution-qr-row">
<span>具体咨询</span>
<QrPlaceholder :label="solution.qrLabel" :title="`${solution.tab}咨询二维码`" />
<span v-if="solution.key !== 'personal'">具体咨询</span>
<QrPlaceholder :image="solution.qrImage" :label="solution.qrLabel" :title="`${solution.tab}咨询二维码`" />
</div>
</article>
</div>
@ -98,8 +118,8 @@ const handleTabKeydown = (event, index) => {
</ol>
<p v-else class="solution-personal-text">{{ activeSolution.points[0] }}</p>
<div class="solution-qr-row">
<span>具体咨询</span>
<QrPlaceholder :label="activeSolution.qrLabel" :title="`${activeSolution.tab}咨询二维码`" />
<span v-if="activeSolution.key !== 'personal'">具体咨询</span>
<QrPlaceholder :image="activeSolution.qrImage" :label="activeSolution.qrLabel" :title="`${activeSolution.tab}咨询二维码`" />
</div>
</article>
</div>

View File

@ -10,22 +10,22 @@ export const features = [
{
icon: 'user-flow',
title: '前端运营获客',
items: ['公众号/视频号互动引流', '个人号承接', '团队微信池', '活动裂变', '企业微信能力融合']
items: ['公众号/视频三方引流', '个人号添加', '团队码添加', '活动码添加', '企业微信能力融合']
},
{
icon: 'clipboard',
title: '中端服务承接',
items: ['患者建档、管理画像', '管理服务流程', '日诊断评估', '日访持续执行', '宣教、随访、复诊']
items: ['健康档案、健康画像', '管理服务团队', '回访计划管理', '回访跟进执行', '宣教、满意度、随访','复诊提醒、治疗预约']
},
{
icon: 'chart',
title: '后端跟进管理',
items: ['复诊/随访流程分组', 'SOP任务引擎', '管理协作闭环', '任务分配下达', '运营管理支撑']
items: ['患者团队分配及分组', 'SOP任务引擎', '管理路径模板库', '任务分配下达', '运营管理驾驶舱', '员工服务积分' ]
},
{
icon: 'ai',
title: '全端数智赋能',
items: ['体效营销体系及引擎', '话术智能客服训练', 'Youcan AI大模型', 'AI客服助手-小柚', '精细化客服多图层']
items: ['标签画像体系及引擎', '话术宣教量表知识库', 'Youcan AI大模型', 'AI客服助手-小柚', '柚康全程服务经理']
}
]
@ -35,35 +35,36 @@ export const solutions = [
tab: '机构云服务版',
title: '版本优势',
points: ['快速开通、快速培训、快速上线', '按年付费、费用低', '享受平台功能持续升级服务', '支持管理患者档案数据的导出'],
qrLabel: '柚康企业微信客服二维码'
qrLabel: '柚康企业微信客服二维码',
qrImage: '/assets/客服.png'
},
{
key: 'local',
tab: '机构本地部署版',
title: '版本优势',
points: ['支持本地服务器部署及内部业务系统对接', '数据本地化管理', '大规模长期使用,性价比高'],
qrLabel: '柚康企业微信客服二维码'
qrLabel: '柚康企业微信客服二维码',
qrImage: '/assets/客服.png'
},
{
key: 'personal',
tab: '个人云服务版',
title: '医生/护士/助理免费开通',
points: ['如果您是医生、护士、医生助理,现在即可免费开通使用:'],
qrLabel: '柚助二维码'
qrLabel: '柚助手小程序',
qrImage: '/assets/小程序码.png'
}
]
export const caseCategories = ['国家医学中心', '公立医院', '妇幼保健客户', '医疗集团客户']
export const cases = [
{ short: '骨', logo: '', name: '国家骨科医学中心\n上海市第六人民医院', tone: 'blue', category: '国家医学中心' },
{ short: '呼', logo: '', name: '国家呼吸医学中心\n广州医科大学附属第一医院', tone: 'orange', category: '国家医学中心' },
{ short: '广', logo: '', name: '广医口腔', tone: 'blue', category: '公立医院' },
{ short: '广', logo: '', name: '广医口腔', tone: 'blue', category: '公立医院' },
{ short: '丹', logo: '', name: '中丹红互联网医院', tone: 'red', category: '公立医院' },
{ short: '十', logo: '', name: '圣德', tone: 'green', category: '妇幼保健客户' },
{ short: '中', logo: '', name: '中信医疗', tone: 'red', category: '医疗集团客户' },
{ short: 'Z', logo: '', name: '浙江震元', tone: 'cyan', category: '医疗集团客户' },
{ short: '骨', logo: '/assets/上海六院.png', logoFit: 'round', name: '国家骨科医学中心\n上海市第六人民医院', tone: 'blue', category: '国家医学中心' },
{ short: '呼', logo: '/assets/广附一.gif', logoFit: 'wide', name: '国家呼吸医学中心\n广州医科大学附属第一医院', tone: 'orange', category: '国家医学中心' },
{ short: '广', logo: '/assets/广医口腔logo.png', logoFit: 'round', name: '广医口腔', tone: 'blue', category: '公立医院' },
{ short: '十', logo: '/assets/圣德logo.png', name: '圣德', tone: 'green', category: '医疗集团客户' },
{ short: '中', logo: '/assets/中信医疗logo.jpg', logoFit: 'wide', name: '中信医疗', tone: 'red', category: '医疗集团客户' },
{ short: 'Z', logo: '/assets/震元.png', logoFit: 'wide', name: '浙江震元', tone: 'cyan', category: '医疗集团客户' },
{ short: '合', logo: '', name: '合禾', tone: 'green', category: '医疗集团客户' },
{ short: '…', logo: '', name: '更多案例\n……', tone: 'gray', category: '医疗集团客户' }
{ short: '丹', logo: '', name: '中丹红互联网医院', tone: 'red', category: '医疗集团客户' },
]

View File

@ -90,12 +90,17 @@ button {
.brand-copy,
.footer-brand span {
display: grid;
line-height: 1.1;
display: inline-flex;
align-items: center;
gap: 10px;
line-height: 1;
}
.brand-copy strong,
.footer-brand strong {
display: inline-flex;
align-items: center;
min-height: 28px;
font-size: 25px;
letter-spacing: 0.04em;
}
@ -108,6 +113,30 @@ button {
font-size: 12px;
}
.brand-service {
width: auto;
height: 24px;
display: block;
object-fit: contain;
box-shadow: none;
border-radius: 0;
}
.brand-separator {
width: 1px;
height: 24px;
display: block;
background: rgba(31, 35, 44, 0.16);
}
.footer-brand .brand-separator {
height: 20px;
}
.footer-brand .brand-service {
height: 20px;
}
.nav-links {
display: flex;
align-items: center;
@ -467,7 +496,7 @@ button {
.solution-tabs {
position: relative;
display: none;
display: grid;
grid-template-columns: repeat(3, 1fr);
width: 100%;
min-height: 58px;
@ -486,25 +515,26 @@ button {
background: transparent;
color: #4e5664;
font-weight: 800;
cursor: pointer;
cursor: default;
border-radius: 12px;
transition: color 0.2s ease;
}
.solution-tab.active {
color: #fff;
color: #4e5664;
}
.tab-indicator {
position: absolute;
z-index: 1;
z-index: 3;
left: 6px;
top: 6px;
top: auto;
bottom: 7px;
width: calc((100% - 12px) / 3);
height: calc(100% - 12px);
border-radius: 12px;
height: 3px;
border-radius: 999px;
background: linear-gradient(90deg, var(--brand), #ff9d22);
box-shadow: 0 12px 24px rgba(255, 138, 0, 0.24);
box-shadow: none;
transition: transform 0.26s ease;
}
@ -520,7 +550,7 @@ button {
}
.solution-card {
min-height: 286px;
min-height: 330px;
padding: 27px 24px 22px;
border-radius: 20px;
background: rgba(255, 255, 255, 0.9);
@ -561,13 +591,13 @@ button {
}
.solution-qr-row {
margin-top: 18px;
display: flex;
align-items: end;
justify-content: space-between;
gap: 20px;
margin-top: 22px;
display: grid;
justify-items: center;
gap: 10px;
color: #4e5664;
font-size: 14px;
font-size: 15px;
text-align: center;
}
.qr-wrap {
@ -578,8 +608,8 @@ button {
.qr-fake {
position: relative;
width: 94px;
height: 94px;
width: 116px;
height: 116px;
border: 7px solid #fff;
background:
linear-gradient(90deg, #111 10px, transparent 10px 16px, #111 16px 22px, transparent 22px 31px, #111 31px 38px, transparent 38px 47px, #111 47px 54px, transparent 54px 64px, #111 64px 72px, transparent 72px),
@ -589,6 +619,16 @@ button {
box-shadow: inset 0 0 0 1px #111, 0 6px 14px rgba(0,0,0,.08);
}
.qr-image {
width: 116px;
height: 116px;
display: block;
object-fit: contain;
border: 7px solid #fff;
background: #fff;
box-shadow: 0 6px 14px rgba(0,0,0,.08);
}
.qr-corner {
position: absolute;
width: 26px;
@ -609,7 +649,7 @@ button {
.qr-corner.bl { left: 6px; bottom: 6px; }
.qr-label {
max-width: 118px;
max-width: 136px;
margin: 0;
color: #66707d;
font-size: 12px;
@ -623,6 +663,12 @@ button {
border-width: 6px;
}
.qr-wrap--small .qr-image {
width: 78px;
height: 78px;
border-width: 6px;
}
.qr-wrap--small .qr-label {
display: none;
}
@ -666,16 +712,17 @@ button {
.case-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 16px;
grid-template-columns: repeat(2, minmax(0, 360px));
justify-content: center;
gap: 18px;
}
.case-card {
min-height: 86px;
height: 116px;
display: flex;
align-items: center;
gap: 14px;
padding: 16px 18px;
gap: 16px;
padding: 18px 20px;
border: 1px solid rgba(31, 35, 44, 0.07);
border-radius: 14px;
background: #fff;
@ -684,29 +731,58 @@ button {
}
.case-logo-slot {
flex: 0 0 auto;
width: 48px;
height: 48px;
display: grid;
place-items: center;
flex: 0 0 92px;
width: 92px;
height: 66px;
position: relative;
display: block;
padding: 9px 12px;
border-radius: 12px;
background: #fff;
border: 1px solid rgba(31, 35, 44, 0.07);
overflow: hidden;
}
.case-logo-slot img {
position: absolute;
inset: 0;
width: calc(100% - 24px);
height: calc(100% - 18px);
margin: auto;
max-width: 100%;
max-height: 100%;
display: block;
object-fit: contain;
object-position: center;
}
.case-logo-slot--round img {
width: 52px;
height: 52px;
max-width: 52px;
max-height: 52px;
object-fit: contain;
}
.case-logo-slot--wide img {
width: 76px;
height: 40px;
max-width: 76px;
max-height: 40px;
}
.case-logo-fallback {
width: 48px;
height: 48px;
position: absolute;
inset: 0;
width: 52px;
height: 52px;
margin: auto;
display: grid;
place-items: center;
border-radius: 14px;
border-radius: 13px;
color: #fff;
font-weight: 900;
font-size: 18px;
font-size: 19px;
}
.case-logo--blue { background: linear-gradient(135deg, #2e6bd4, #153d93); }
@ -719,9 +795,11 @@ button {
.case-card p {
margin: 0;
color: #2f3540;
line-height: 1.45;
line-height: 1.55;
white-space: pre-line;
font-size: 14px;
font-size: 16px;
text-align: left;
align-self: center;
}
.contact-section {
@ -765,9 +843,9 @@ button {
}
.manager-card {
display: flex;
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
justify-content: space-between;
gap: 24px;
padding: 22px 26px;
border-radius: 18px;
@ -820,10 +898,11 @@ button {
color: var(--text);
}
.footer-brand img {
.footer-logo {
width: 44px;
height: 44px;
border-radius: 12px;
object-fit: contain;
}
.footer-brand strong {
@ -848,7 +927,8 @@ button {
grid-template-columns: repeat(2, 1fr);
}
.case-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-columns: repeat(2, minmax(0, 340px));
justify-content: center;
}
}
@ -857,9 +937,12 @@ button {
width: min(100% - 28px, var(--container));
}
.site-header {
position: static;
position: sticky;
top: 0;
z-index: 80;
}
.header-inner {
position: relative;
height: auto;
padding: 16px 0;
flex-wrap: wrap;
@ -873,13 +956,17 @@ button {
margin-left: auto;
}
.nav-links {
width: 100%;
position: absolute;
left: 0;
right: 0;
top: calc(100% + 10px);
z-index: 90;
display: none;
padding: 6px;
padding: 10px;
border-radius: 15px;
background: #fff;
border: 1px solid rgba(255, 138, 0, 0.12);
box-shadow: var(--shadow-sm);
box-shadow: 0 22px 48px rgba(31, 35, 44, 0.14);
}
.nav-links.open {
display: grid;
@ -930,6 +1017,12 @@ button {
min-height: 50px;
padding: 5px;
}
.solution-tab {
cursor: pointer;
}
.solution-tab.active {
color: #fff;
}
.solution-tab {
min-height: 40px;
padding: 0 6px;
@ -937,10 +1030,14 @@ button {
line-height: 1.25;
}
.tab-indicator {
z-index: 1;
left: 5px;
top: 5px;
bottom: auto;
width: calc((100% - 10px) / 3);
height: calc(100% - 10px);
border-radius: 12px;
box-shadow: 0 12px 24px rgba(255, 138, 0, 0.24);
}
.case-layout {
grid-template-columns: 1fr;
@ -990,10 +1087,24 @@ button {
.case-grid {
grid-template-columns: 1fr;
}
.solution-qr-row,
.case-card {
height: auto;
min-height: 112px;
gap: 15px;
padding: 18px;
}
.case-logo-slot {
flex-basis: 88px;
width: 88px;
height: 64px;
}
.case-card p {
font-size: 16px;
}
.manager-card {
flex-direction: column;
align-items: flex-start;
grid-template-columns: 1fr;
justify-items: center;
text-align: center;
}
.address-row {
justify-content: flex-start;