diff --git a/website/src/assets/Features/ky/ky-1.png b/website/src/assets/Features/ky/ky-1.png new file mode 100644 index 0000000..b61b490 Binary files /dev/null and b/website/src/assets/Features/ky/ky-1.png differ diff --git a/website/src/assets/Features/ky/ky-2.png b/website/src/assets/Features/ky/ky-2.png new file mode 100644 index 0000000..44069d4 Binary files /dev/null and b/website/src/assets/Features/ky/ky-2.png differ diff --git a/website/src/assets/Features/ky/ky-3.png b/website/src/assets/Features/ky/ky-3.png new file mode 100644 index 0000000..fc05d4b Binary files /dev/null and b/website/src/assets/Features/ky/ky-3.png differ diff --git a/website/src/assets/Features/ky/ky-4.png b/website/src/assets/Features/ky/ky-4.png new file mode 100644 index 0000000..60b7fea Binary files /dev/null and b/website/src/assets/Features/ky/ky-4.png differ diff --git a/website/src/assets/Features/ky/ky-5.png b/website/src/assets/Features/ky/ky-5.png new file mode 100644 index 0000000..c94ea23 Binary files /dev/null and b/website/src/assets/Features/ky/ky-5.png differ diff --git a/website/src/assets/Features/ky/ky-6.png b/website/src/assets/Features/ky/ky-6.png new file mode 100644 index 0000000..6134832 Binary files /dev/null and b/website/src/assets/Features/ky/ky-6.png differ diff --git a/website/src/assets/Features/sk/sk-1.png b/website/src/assets/Features/sk/sk-1.png new file mode 100644 index 0000000..e92ca2b Binary files /dev/null and b/website/src/assets/Features/sk/sk-1.png differ diff --git a/website/src/assets/Features/sk/sk-2.png b/website/src/assets/Features/sk/sk-2.png new file mode 100644 index 0000000..0407d0c Binary files /dev/null and b/website/src/assets/Features/sk/sk-2.png differ diff --git a/website/src/assets/Features/sk/sk-3.png b/website/src/assets/Features/sk/sk-3.png new file mode 100644 index 0000000..93afab9 Binary files /dev/null and b/website/src/assets/Features/sk/sk-3.png differ diff --git a/website/src/assets/Features/sk/sk-4.png b/website/src/assets/Features/sk/sk-4.png new file mode 100644 index 0000000..6d1ea30 Binary files /dev/null and b/website/src/assets/Features/sk/sk-4.png differ diff --git a/website/src/assets/Features/sk/sk-5.png b/website/src/assets/Features/sk/sk-5.png new file mode 100644 index 0000000..4e8738a Binary files /dev/null and b/website/src/assets/Features/sk/sk-5.png differ diff --git a/website/src/assets/Features/sk/sk-6.png b/website/src/assets/Features/sk/sk-6.png new file mode 100644 index 0000000..0de062a Binary files /dev/null and b/website/src/assets/Features/sk/sk-6.png differ diff --git a/website/src/assets/Features/xq/xq-1.jpg b/website/src/assets/Features/xq/xq-1.jpg new file mode 100644 index 0000000..4063e4a Binary files /dev/null and b/website/src/assets/Features/xq/xq-1.jpg differ diff --git a/website/src/assets/Features/xq/xq-2.png b/website/src/assets/Features/xq/xq-2.png new file mode 100644 index 0000000..e085f1f Binary files /dev/null and b/website/src/assets/Features/xq/xq-2.png differ diff --git a/website/src/assets/Features/xq/xq-3.png b/website/src/assets/Features/xq/xq-3.png new file mode 100644 index 0000000..c9cda43 Binary files /dev/null and b/website/src/assets/Features/xq/xq-3.png differ diff --git a/website/src/assets/Features/xq/xq-4.png b/website/src/assets/Features/xq/xq-4.png new file mode 100644 index 0000000..3c7344b Binary files /dev/null and b/website/src/assets/Features/xq/xq-4.png differ diff --git a/website/src/assets/Features/xq/xq-5.png b/website/src/assets/Features/xq/xq-5.png new file mode 100644 index 0000000..bd4c1fc Binary files /dev/null and b/website/src/assets/Features/xq/xq-5.png differ diff --git a/website/src/assets/Features/xq/xq-6.png b/website/src/assets/Features/xq/xq-6.png new file mode 100644 index 0000000..1e84fbc Binary files /dev/null and b/website/src/assets/Features/xq/xq-6.png differ diff --git a/website/src/assets/Features/zh/zh-1.png b/website/src/assets/Features/zh/zh-1.png new file mode 100644 index 0000000..be3fe2a Binary files /dev/null and b/website/src/assets/Features/zh/zh-1.png differ diff --git a/website/src/assets/Features/zh/zh-2.png b/website/src/assets/Features/zh/zh-2.png new file mode 100644 index 0000000..84a5024 Binary files /dev/null and b/website/src/assets/Features/zh/zh-2.png differ diff --git a/website/src/assets/Features/zh/zh-3.png b/website/src/assets/Features/zh/zh-3.png new file mode 100644 index 0000000..88339b2 Binary files /dev/null and b/website/src/assets/Features/zh/zh-3.png differ diff --git a/website/src/assets/Features/zh/zh-4.png b/website/src/assets/Features/zh/zh-4.png new file mode 100644 index 0000000..145645c Binary files /dev/null and b/website/src/assets/Features/zh/zh-4.png differ diff --git a/website/src/assets/Features/zh/zh-5.png b/website/src/assets/Features/zh/zh-5.png new file mode 100644 index 0000000..48dca51 Binary files /dev/null and b/website/src/assets/Features/zh/zh-5.png differ diff --git a/website/src/assets/Features/zh/zh-6.png b/website/src/assets/Features/zh/zh-6.png new file mode 100644 index 0000000..3da4afd Binary files /dev/null and b/website/src/assets/Features/zh/zh-6.png differ diff --git a/website/src/assets/images/Carousel/.svg b/website/src/assets/images/Carousel/.svg new file mode 100644 index 0000000..2131191 --- /dev/null +++ b/website/src/assets/images/Carousel/.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/Points-1.png b/website/src/assets/images/Carousel/Points-1.png new file mode 100644 index 0000000..0ca1a66 Binary files /dev/null and b/website/src/assets/images/Carousel/Points-1.png differ diff --git a/website/src/assets/images/Carousel/Points-1.svg b/website/src/assets/images/Carousel/Points-1.svg new file mode 100644 index 0000000..8ea8042 --- /dev/null +++ b/website/src/assets/images/Carousel/Points-1.svg @@ -0,0 +1 @@ +Memory storage \ No newline at end of file diff --git a/website/src/assets/images/Carousel/Points-2.png b/website/src/assets/images/Carousel/Points-2.png new file mode 100644 index 0000000..c8ff710 Binary files /dev/null and b/website/src/assets/images/Carousel/Points-2.png differ diff --git a/website/src/assets/images/Carousel/Points-2.svg b/website/src/assets/images/Carousel/Points-2.svg new file mode 100644 index 0000000..914400c --- /dev/null +++ b/website/src/assets/images/Carousel/Points-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/Points-3.png b/website/src/assets/images/Carousel/Points-3.png new file mode 100644 index 0000000..e22ee5f Binary files /dev/null and b/website/src/assets/images/Carousel/Points-3.png differ diff --git a/website/src/assets/images/Carousel/Points-3.svg b/website/src/assets/images/Carousel/Points-3.svg new file mode 100644 index 0000000..3b09866 --- /dev/null +++ b/website/src/assets/images/Carousel/Points-3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/Points-4.png b/website/src/assets/images/Carousel/Points-4.png new file mode 100644 index 0000000..8b2ff0a Binary files /dev/null and b/website/src/assets/images/Carousel/Points-4.png differ diff --git a/website/src/assets/images/Carousel/Points-4.svg b/website/src/assets/images/Carousel/Points-4.svg new file mode 100644 index 0000000..2cb7620 --- /dev/null +++ b/website/src/assets/images/Carousel/Points-4.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/Points-5.png b/website/src/assets/images/Carousel/Points-5.png new file mode 100644 index 0000000..f8ef48b Binary files /dev/null and b/website/src/assets/images/Carousel/Points-5.png differ diff --git a/website/src/assets/images/Carousel/Points-5.svg b/website/src/assets/images/Carousel/Points-5.svg new file mode 100644 index 0000000..a7ea075 --- /dev/null +++ b/website/src/assets/images/Carousel/Points-5.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/ky-Points-1.svg b/website/src/assets/images/Carousel/ky-Points-1.svg new file mode 100644 index 0000000..ac7ba5b --- /dev/null +++ b/website/src/assets/images/Carousel/ky-Points-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/ky-Points-3.svg b/website/src/assets/images/Carousel/ky-Points-3.svg new file mode 100644 index 0000000..6427e4f --- /dev/null +++ b/website/src/assets/images/Carousel/ky-Points-3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/sx-Points-2.svg b/website/src/assets/images/Carousel/sx-Points-2.svg new file mode 100644 index 0000000..e8b7bb9 --- /dev/null +++ b/website/src/assets/images/Carousel/sx-Points-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/zh-Points-1.svg b/website/src/assets/images/Carousel/zh-Points-1.svg new file mode 100644 index 0000000..f191c4c --- /dev/null +++ b/website/src/assets/images/Carousel/zh-Points-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/Carousel/zh-Points-2.svg b/website/src/assets/images/Carousel/zh-Points-2.svg new file mode 100644 index 0000000..e5b7593 --- /dev/null +++ b/website/src/assets/images/Carousel/zh-Points-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/src/assets/images/xq/xq3.png b/website/src/assets/images/xq/xq3.png index ee7ae59..d073065 100644 Binary files a/website/src/assets/images/xq/xq3.png and b/website/src/assets/images/xq/xq3.png differ diff --git a/website/src/components/Carousel.jsx b/website/src/components/Carousel.jsx index c5a3999..ebab2d7 100644 --- a/website/src/components/Carousel.jsx +++ b/website/src/components/Carousel.jsx @@ -3,27 +3,34 @@ import { X } from 'lucide-react' export default function Carousel({ images, interval = 4000, themeColor }) { const [current, setCurrent] = useState(0) - const [transitioning, setTransitioning] = useState(false) + const [prevSrc, setPrevSrc] = useState(null) + const [isTransitioning, setIsTransitioning] = useState(false) const [preview, setPreview] = useState(null) const timerRef = useRef(null) + const busyRef = useRef(false) const goTo = useCallback((index) => { - setTransitioning(true) + if (index === current || busyRef.current) return + busyRef.current = true + setPrevSrc(images[current]?.url) + setCurrent(index) + // rAF x2 to ensure the DOM has rendered the new image before starting transition + requestAnimationFrame(() => { + requestAnimationFrame(() => { + setIsTransitioning(true) + }) + }) + // After transition completes setTimeout(() => { - setCurrent(index) - setTimeout(() => setTransitioning(false), 50) - }, 350) - }, []) + setIsTransitioning(false) + setPrevSrc(null) + busyRef.current = false + }, 500) + }, [current, images]) const next = useCallback(() => { - if (transitioning) return goTo((current + 1) % images.length) - }, [current, images.length, transitioning, goTo]) - - const prev = useCallback(() => { - if (transitioning) return - goTo((current - 1 + images.length) % images.length) - }, [current, images.length, transitioning, goTo]) + }, [current, images.length, goTo]) useEffect(() => { if (preview !== null) return @@ -31,13 +38,6 @@ export default function Carousel({ images, interval = 4000, themeColor }) { return () => clearInterval(timerRef.current) }, [next, interval, preview]) - const getIndex = (offset) => { - return (current + offset + images.length) % images.length - } - - const prevIdx = getIndex(-1) - const nextIdx = getIndex(1) - const handleImageClick = (index) => { setPreview(index) } @@ -48,59 +48,50 @@ export default function Carousel({ images, interval = 4000, themeColor }) { return ( <> -
- {/* Left - prev */} +
+ {/* Center - monitor frame (static, no animation) */}
{ handleImageClick(prevIdx); prev() }} - > - -
- - {/* Center - current */} -
handleImageClick(current)} > -
- -
- - {/* Right - next */} -
{ handleImageClick(nextIdx); next() }} - > - + {/* 显示器外框 */} +
+
+ {/* 旧图片 — 交叉淡出 */} + {prevSrc && ( + + )} + {/* 新图片 — 交叉淡入 */} + +
+ {/* 底部下巴 */} +
+ {images[current]?.name || ''} +
+
+ {/* 支架 */} +
+
{/* Dot indicators */} -
+
{images.map((_, i) => (
+ {/* Image name — lines on both sides */} +
+
+ + + {images[current]?.name || ''} + + +
+
+ {/* Preview Modal */} {preview !== null && (
e.stopPropagation()} />
diff --git a/website/src/components/ThemedSvg.jsx b/website/src/components/ThemedSvg.jsx new file mode 100644 index 0000000..9489306 --- /dev/null +++ b/website/src/components/ThemedSvg.jsx @@ -0,0 +1,40 @@ +import { useState, useEffect, useRef } from 'react'; + +/** + * 加载 SVG 文件并将指定颜色替换为主题色后内联渲染 + * @param {string} url - SVG 文件地址 + * @param {string} color - 替换的目标主题色 (hex) + * @param {string} className - 外层容器样式 + */ +export default function ThemedSvg({ url, color, className }) { + const [content, setContent] = useState(''); + const ref = useRef(null); + + useEffect(() => { + let cancelled = false; + fetch(url) + .then(res => res.text()) + .then(text => { + if (cancelled) return; + // 将 undraw 默认紫色 #6c63ff 替换为页面主题色 + const themed = text.replace(/#6c63ff/gi, color); + setContent(themed); + }) + .catch(() => { + if (!cancelled) setContent(''); + }); + return () => { cancelled = true; }; + }, [url, color]); + + if (!content) { + return
; + } + + return ( +
+ ); +} \ No newline at end of file diff --git a/website/src/data/products.js b/website/src/data/products.js index 8ee5f83..f38c255 100644 --- a/website/src/data/products.js +++ b/website/src/data/products.js @@ -1,5 +1,5 @@ import { - Building2, GraduationCap, BookOpen, ClipboardCheck + Building2, GraduationCap, BookOpen, ClipboardCheck, } from 'lucide-react'; export const products = [ @@ -10,9 +10,9 @@ export const products = [ themeColor: '#60ce93', heroImage: new URL('../assets/images/Carousel/xq.png', import.meta.url).href, screenshots: [ - new URL('../assets/images/xq/xq1.png', import.meta.url).href, - new URL('../assets/images/xq/xq2.png', import.meta.url).href, - new URL('../assets/images/xq/xq3.png', import.meta.url).href, + { url: new URL('../assets/images/xq/xq1.png', import.meta.url).href, name: '专业管理' }, + { url: new URL('../assets/images/xq/xq2.png', import.meta.url).href, name: '数据大屏' }, + { url: new URL('../assets/images/xq/xq3.png', import.meta.url).href, name: '辅导员工作台' }, ], themeFrom: '#047857', themeTo: '#34d399', @@ -25,18 +25,25 @@ export const products = [ { num: '100', suffix: '万+', label: '累计签到' }, ], features: [ - { emoji: '📋', title: '实习计划管理', desc: '按学期、专业、班级灵活制定实习计划,绑定不同实习规则,实现多批次差异化管理' }, - { emoji: '📍', title: 'GPS签到+电子围栏', desc: '基于地理位置的真实考勤,自动判断签到有效性,未签到学生一键导出名单' }, - { emoji: '📝', title: '问卷式日志', desc: '预设定向提问模板,引导学生深度反思,"流水账"变"成长档案"' }, - { emoji: '📊', title: '多维鉴定评价', desc: '综合考勤、日志、教师评价、企业反馈,自动生成实习鉴定分数,客观公正' }, - { emoji: '🔄', title: '一键同步教育厅平台', desc: '数据审核后直接同步至"广西职业院校学生实习管理平台",无缝对接省级管理要求' }, - { emoji: '📱', title: '微信小程序加持', desc: '学生通过小程序签到、写日志、上传附件,无需下载额外App,使用门槛极低' }, + { icon: 'CalendarCheck', title: '实习计划管理', desc: '按学期、专业、班级灵活制定实习计划,绑定不同实习规则,实现多批次差异化管理', image: new URL('../assets/Features/xq/xq-1.jpg', import.meta.url).href }, + { icon: 'SearchCheck', title: 'GPS签到+电子围栏', desc: '基于地理位置的真实考勤,自动判断签到有效性,未签到学生一键导出名单', image: new URL('../assets/Features/xq/xq-2.png', import.meta.url).href }, + { icon: 'ScrollText', title: '问卷式日志', desc: '预设定向提问模板,引导学生深度反思,"流水账"变"成长档案"', image: new URL('../assets/Features/xq/xq-3.png', import.meta.url).href, small: true }, + { icon: 'FileDigit', title: '多维鉴定评价', desc: '综合考勤、日志、教师评价、企业反馈,自动生成实习鉴定分数,客观公正', image: new URL('../assets/Features/xq/xq-4.png', import.meta.url).href }, + { icon: 'GitBranch', title: '一键同步教育厅平台', desc: '数据审核后直接同步至"广西职业院校学生实习管理平台",无缝对接省级管理要求', image: new URL('../assets/Features/xq/xq-5.png', import.meta.url).href }, + { icon: 'Layers', title: '微信小程序加持', desc: '学生通过小程序签到、写日志、上传附件,无需下载额外App,使用门槛极低', + image: new URL('../assets/Features/xq/xq-6.png', import.meta.url).href, small: true }, ], - painPointsTitle: '校企益邦解决的核心问题', + painPointsTitle: '校企益邦\n解决的核心问题', painPoints: [ - { title: '没有统一的方案执行,学校难以管控学生的实习情况', desc: '平台提供丰富的实习规则定制,涵盖签到、汇报、评价、考核等要求。定制后的实习规则可作为实习要求模板应用于多个实习计划,管理不同批次的学生,省去重复配置众多实习要求的麻烦,体现模板化。' }, - { title: '学生信息采集工作量大,授课教师苦不堪言', desc: '将学生实习信息采集工作分配给学生完成,指导老师只需对这些信息进行审核,减少老师在实习信息采集和整理环节的工作,保障信息准确性、规范性的同时,提高了信息收集效率。' }, - { title: '学生配合的积极性较低,提交的数据不达标', desc: '实习日志采用"问卷式",有指向性地采集学生实习日志,让学生即使面对需要频繁提交的日志,也有汇报方向,减少"流水账式"汇报,提升汇报效果。' }, + { + url: new URL('../assets/images/Carousel/zh-points-1.svg', import.meta.url).href, + title: '没有统一的方案执行,学校难以管控学生的实习情况', desc: '平台提供丰富的实习规则定制,涵盖签到、汇报、评价、考核等要求。定制后的实习规则可作为实习要求模板应用于多个实习计划,管理不同批次的学生,省去重复配置众多实习要求的麻烦,体现模板化。', }, + { + url: new URL('../assets/images/Carousel/Points-2.svg', import.meta.url).href, + title: '学生信息采集工作量大,授课教师苦不堪言', desc: '将学生实习信息采集工作分配给学生完成,指导老师只需对这些信息进行审核,减少老师在实习信息采集和整理环节的工作,保障信息准确性、规范性的同时,提高了信息收集效率。', }, + { + url: new URL('../assets/images/Carousel/Points-3.svg', import.meta.url).href, + title: '学生配合的积极性较低,提交的数据不达标', desc: '实习日志采用"问卷式",有指向性地采集学生实习日志,让学生即使面对需要频繁提交的日志,也有汇报方向,减少"流水账式"汇报,提升汇报效果。', }, ], target: '职业院校教务处、实习管理科、各院系指导教师', faq: [ @@ -53,9 +60,9 @@ export const products = [ themeColor: '#0c86cf', heroImage: new URL('../assets/images/Carousel/ky.png', import.meta.url).href, screenshots: [ - new URL('../assets/images/ky/ky1.png', import.meta.url).href, - new URL('../assets/images/ky/ky2.jpeg', import.meta.url).href, - new URL('../assets/images/ky/ky3.jpeg', import.meta.url).href, + { url: new URL('../assets/images/ky/ky1.png', import.meta.url).href, name: '个人科研画像' }, + { url: new URL('../assets/images/ky/ky2.jpeg', import.meta.url).href, name: '经办跟踪' }, + { url: new URL('../assets/images/ky/ky3.jpeg', import.meta.url).href, name: '消息推送' }, ], themeFrom: '#075985', themeTo: '#38bdf8', @@ -68,20 +75,20 @@ export const products = [ { num: '8000', suffix: '+', label: '登记成果' }, ], features: [ - { emoji: '📝', title: '在线申报审批', desc: '项目申报、审核、立项全流程在线办理,智能校验引擎自动检查相似度和限项规则' }, - { emoji: '🔍', title: '智能查重防重复', desc: '项目名称相似度超80%自动拦截,同一主持人月度限申报1次,杜绝重复申报' }, - { emoji: '💰', title: '经费精细管控', desc: '纵向/横向分类管理,预算—报销实时关联,超预算自动预警,经费使用透明合规' }, - { emoji: '🏆', title: '成果自动赋分', desc: '论文、专利、著作按级别自动量化评分,一次登记多处复用,告别重复填报' }, - { emoji: '⏰', title: '关键节点预警', desc: '经费超期、结题到期、审批退回等场景自动推送提醒,确保每个环节不遗漏' }, - { emoji: '📄', title: '年度报表一键导出', desc: '科研成果统计、项目经费汇总等年度报表自动生成,效率提升数十倍' }, + { icon: 'FileStack', title: '在线申报审批', desc: '项目申报、审核、立项全流程在线办理,智能校验引擎自动检查相似度和限项规则', image: new URL('../assets/Features/ky/ky-1.png', import.meta.url).href }, + { icon: 'SearchCheck', title: '智能查重防重复', desc: '项目名称相似度超80%自动拦截,同一主持人月度限申报1次,杜绝重复申报', image: new URL('../assets/Features/ky/ky-2.png', import.meta.url).href }, + { icon: 'Banknote', title: '经费精细管控', desc: '纵向/横向分类管理,预算—报销实时关联,超预算自动预警,经费使用透明合规', image: new URL('../assets/Features/ky/ky-3.png', import.meta.url).href }, + { icon: 'TrendingUp', title: '成果自动赋分', desc: '论文、专利、著作按级别自动量化评分,一次登记多处复用,告别重复填报', image: new URL('../assets/Features/ky/ky-4.png', import.meta.url).href }, + { icon: 'Bell', title: '关键节点预警', desc: '经费超期、结题到期、审批退回等场景自动推送提醒,确保每个环节不遗漏', image: new URL('../assets/Features/ky/ky-5.png', import.meta.url).href }, + { icon: 'FileDigit', title: '年度报表一键导出', desc: '科研成果统计、项目经费汇总等年度报表自动生成,效率提升数十倍', image: new URL('../assets/Features/ky/ky-6.png', import.meta.url).href }, ], - painPointsTitle: '科研管理系统解决的核心问题', + painPointsTitle: '科研管理系统\n解决的核心问题', painPoints: [ - { title: '传统科研管理流程繁琐,纸质办公效率低下', desc: '全流程数字化,实现科研项目申报、审批、结题的全程在线办理,消除纸质办公,提升工作效率。' }, - { title: '项目申报审核工作量大,人工审核成本高', desc: '智能校验引擎,内置项目查重(相似度检测)、限项检查、预算自动配套计算规则,大幅降低人工审核成本。' }, - { title: '科研经费管理复杂,预算与报销脱节', desc: '经费精细化管控,支持纵向/横向经费分类管理,实时关联预算与报销进度,确保经费使用规范透明。' }, - { title: '科研成果统计困难,年度报表制作耗时', desc: '成果分值量化,自动根据奖励办法对论文、专利、著作等成果进行赋分,支持一键导出年度统计报表。' }, - { title: '项目进度监控不及时,关键节点容易遗漏', desc: '多维度预警,集成短信通知与站内提醒,涵盖预算超期、结题预警、流程回退等关键节点。' }, + { url: new URL('../assets/images/Carousel/Points-1.svg', import.meta.url).href, title: '传统科研管理流程繁琐,纸质办公效率低下', desc: '全流程数字化,实现科研项目申报、审批、结题的全程在线办理,消除纸质办公,提升工作效率。'}, + { url: new URL('../assets/images/Carousel/ky-Points-1.svg', import.meta.url).href, title: '项目申报审核工作量大,人工审核成本高', desc: '智能校验引擎,内置项目查重(相似度检测)、限项检查、预算自动配套计算规则,大幅降低人工审核成本。' }, + { url: new URL('../assets/images/Carousel/ky-Points-3.svg', import.meta.url).href, title: '科研经费管理复杂,预算与报销脱节', desc: '经费精细化管控,支持纵向/横向经费分类管理,实时关联预算与报销进度,确保经费使用规范透明。' }, + { url: new URL('../assets/images/Carousel/Points-4.svg', import.meta.url).href, title: '科研成果统计困难,年度报表制作耗时', desc: '成果分值量化,自动根据奖励办法对论文、专利、著作等成果进行赋分,支持一键导出年度统计报表。' }, + { url: new URL('../assets/images/Carousel/Points-5.svg', import.meta.url).href, title: '项目进度监控不及时,关键节点容易遗漏', desc: '多维度预警,集成短信通知与站内提醒,涵盖预算超期、结题预警、流程回退等关键节点。' }, ], target: '高校科研处、财务处、各院系教师及科研项目负责人', faq: [ @@ -99,9 +106,9 @@ export const products = [ heroImage: new URL('../assets/images/Carousel/zh.png', import.meta.url).href, heroSize: 'small', screenshots: [ - new URL('../assets/images/zh/zh1.png', import.meta.url).href, - new URL('../assets/images/zh/zh2.png', import.meta.url).href, - new URL('../assets/images/zh/zh3.jpeg', import.meta.url).href, + { url: new URL('../assets/images/zh/zh1.png', import.meta.url).href, name: '消息推送' }, + { url: new URL('../assets/images/zh/zh2.png', import.meta.url).href, name: '数据大屏' }, + { url: new URL('../assets/images/zh/zh3.jpeg', import.meta.url).href, name: '发展党员管理' }, ], themeFrom: '#7f1d1d', themeTo: '#dc2626', @@ -114,27 +121,34 @@ export const products = [ { num: '200', suffix: '+', label: '考核指标' }, ], features: [ - { emoji: '📊', title: '三级考核指标', desc: '灵活构建校—院—支部三级指标树,分值自动汇总,考核部门与执行部门逐一对应' }, - { emoji: '📋', title: '三会一课数字化', desc: '通知—签到—记录全流程闭环,二维码签到5分钟刷新,杜绝"代签""补签"' }, - { emoji: '✍️', title: '万能工作记录', desc: '不受模块限制,任何业务工作均可灵活录入并关联考核指标,实现考核全覆盖' }, - { emoji: '🔔', title: '实时进度看板', desc: '领导层穿透查看各项指标完成进度,哪项落后一目了然,变"年底算账"为"过程管控"' }, - { emoji: '👥', title: '发展党员管理', desc: '内置入党全流程节点模型,支持自定义配置,关键节点到期自动提醒支部管理员' }, - { emoji: '📡', title: '党建数据中心', desc: '全校党建数据可视化大屏——组织健康度、党员活跃度、重点工作督办一览无余' }, + { icon: 'Pyramid', title: '三级考核指标', desc: '灵活构建校—院—支部三级指标树,分值自动汇总,考核部门与执行部门逐一对应', image: new URL('../assets/Features/zh/zh-1.png', import.meta.url).href }, + { icon: 'CalendarCheck', title: '三会一课数字化', desc: '通知—签到—记录全流程闭环,二维码签到5分钟刷新,杜绝"代签""补签"', image: new URL('../assets/Features/zh/zh-2.png', import.meta.url).href }, + { icon: 'ScrollText', title: '万能工作记录', desc: '不受模块限制,任何业务工作均可灵活录入并关联考核指标,实现考核全覆盖', image: new URL('../assets/Features/zh/zh-3.png', import.meta.url).href }, + { icon: 'ChartBar', title: '实时进度看板', desc: '领导层穿透查看各项指标完成进度,哪项落后一目了然,变"年底算账"为"过程管控"', image: new URL('../assets/Features/zh/zh-4.png', import.meta.url).href }, + { icon: 'Database', title: '发展党员管理', desc: '内置入党全流程节点模型,支持自定义配置,关键节点到期自动提醒支部管理员', image: new URL('../assets/Features/zh/zh-5.png', import.meta.url).href }, + { icon: 'Activity', title: '党建数据中心', desc: '全校党建数据可视化大屏——组织健康度、党员活跃度、重点工作督办一览无余', image: new URL('../assets/Features/zh/zh-6.png', import.meta.url).href }, ], - painPointsTitle: '智慧党建平台解决的核心问题', + painPointsTitle: '智慧党建平台\n解决的核心问题', painPoints: [ - { title: '党建工作与教学业务“两张皮”,考核指标繁杂多样,难以实现全口径统一管理', desc: '构建“专用模块+通用记录”的双重支撑体系。对于标准化党务,通过“三会一课”、“党员活动”等模块自动关联;对于教学科研等系统中无特定管理模块的考核任务,利用“工作记录”模块作为万能适配器进行灵活录入并关联指标。确保每一项考核指标(无论党务或业务)都有据可查,实现党建考核的100%全覆盖。' }, { - title: ' 年终考核“突击补材料”,重复填表耗时耗力,数据难追溯', - desc: '推行“过程资产化”管理,日常工作(如会议、活动)录入即并关联考核指标,年终无需盘点,数据自动生成,拒绝重复劳动。' + url: new URL('../assets/images/Carousel/zh-Points-1.svg', import.meta.url).href, + title: '党建工作与教学业务”两张皮”,考核指标繁杂多样,难以实现全口径统一管理', + desc: '构建”专用模块+通用记录”的双重支撑体系。对于标准化党务,通过”三会一课”、”党员活动”等模块自动关联;对于教学科研等系统中无特定管理模块的考核任务,利用”工作记录”模块作为万能适配器进行灵活录入并关联指标。确保每一项考核指标(无论党务或业务)都有据可查,实现党建考核的100%全覆盖。'}, + { + url: new URL('../assets/images/Carousel/zh-Points-2.svg', import.meta.url).href, + title: ' 年终考核”突击补材料”,重复填表耗时耗力,数据难追溯', + desc: '推行”过程资产化”管理,日常工作(如会议、活动)录入即并关联考核指标,年终无需盘点,数据自动生成,拒绝重复劳动。', + + }, + { url: new URL('../assets/images/Carousel/Points-3.svg', import.meta.url).href, title: '”三会一课”组织难、签到难、记录难,合规性监管滞后', + desc: '提供移动端全流程闭环,支持一键发布通知、现场扫码签到、会议纪要即时编辑上传,确保组织生活规范、留痕、可查。', + }, { - title: '“三会一课”组织难、签到难、记录难,合规性监管滞后', - desc: '提供移动端全流程闭环,支持一键发布通知、现场扫码签到、会议纪要即时编辑上传,确保组织生活规范、留痕、可查。' - }, - { - title: '党建考核存在“层级衰减”与“管理盲区”,平时进度看不见,年底检查来不及', - desc: '构建分层级可视化考核体系。系统打破科层壁垒,领导层通过“完成情况看板”直观监测各指标的实时进度一键穿透查看明细;执行层通过“指标明细”精准对应“自评”与“佐证材料”,明确“谁来做、谁来考、通过什么材料佐证”。让考核从“年底算总账”变为“全过程透明化管控”,确保压力无损传导至基层末梢。' + url: new URL('../assets/images/Carousel/Points-4.svg', import.meta.url).href, + title: '党建考核存在”层级衰减”与”管理盲区”,平时进度看不见,年底检查来不及', + desc: '构建分层级可视化考核体系。系统打破科层壁垒,领导层通过”完成情况看板”直观监测各指标的实时进度一键穿透查看明细;执行层通过”指标明细”精准对应”自评”与”佐证材料”,明确”谁来做、谁来考、通过什么材料佐证”。让考核从”年底算总账”变为”全过程透明化管控”,确保压力无损传导至基层末梢。', + }, ], target: '高校党委组织部、各二级党委/党总支、基层党支部', @@ -152,9 +166,9 @@ export const products = [ themeColor: '#8b50ee', heroImage: new URL('../assets/images/Carousel/sk.png', import.meta.url).href, screenshots: [ - new URL('../assets/images/sk/sk1.png', import.meta.url).href, - new URL('../assets/images/sk/sk2.jpeg', import.meta.url).href, - new URL('../assets/images/sk/sk3.jpeg', import.meta.url).href, + { url: new URL('../assets/images/sk/sk1.png', import.meta.url).href, name: '数据大屏' }, + { url: new URL('../assets/images/sk/sk2.jpeg', import.meta.url).href, name: '角色管理' }, + { url: new URL('../assets/images/sk/sk3.jpeg', import.meta.url).href, name: '消息推送' }, ], themeFrom: '#5b21b6', themeTo: '#a78bfa', @@ -167,23 +181,25 @@ export const products = [ { num: '200', suffix: '万+', label: '累计咖豆' }, ], features: [ - { emoji: '📦', title: '三级精细管理', desc: '项目→模块→任务三级结构,权重灵活分配,实训教学内容标准化、可复用' }, - { emoji: '🫘', title: '咖豆积分引擎', desc: '成绩自动转换为虚拟积分,支持积分排行、兑换、晋级,让学习像游戏一样上瘾' }, - { emoji: '⭐', title: '五级自动晋级', desc: '自定义等级名称、门槛积分和专属权益,达标自动晋升,成长路径一目了然' }, - { emoji: '🎯', title: '动态技能画像', desc: '基于任务完成情况自动生成个人雷达图,技能点逐一点亮,优势短板清晰可见' }, - { emoji: '📈', title: '人才培养驾驶舱', desc: '全校实训数据一屏呈现——项目热度、参与度、完成率、经费使用,决策有据可依' }, - { emoji: '🎁', title: '积分商城', desc: '咖豆可兑换实物或虚拟礼品,构建"学、练、评、换"完整激励闭环' }, + { icon: 'Layers', title: '三级精细管理', desc: '项目→模块→任务三级结构,权重灵活分配,实训教学内容标准化、可复用', image: new URL('../assets/Features/sk/sk-1.png', import.meta.url).href }, + { icon: 'Database', title: '咖豆积分引擎', desc: '成绩自动转换为虚拟积分,支持积分排行、兑换、晋级,让学习像游戏一样上瘾', image: new URL('../assets/Features/sk/sk-2.png', import.meta.url).href }, + { icon: 'TrendingUp', title: '五级自动晋级', desc: '自定义等级名称、门槛积分和专属权益,达标自动晋升,成长路径一目了然', small: true, image: new URL('../assets/Features/sk/sk-3.png', import.meta.url).href }, + { icon: 'Activity', title: '动态技能画像', desc: '基于任务完成情况自动生成个人雷达图,技能点逐一点亮,优势短板清晰可见', small: true, image: new URL('../assets/Features/sk/sk-4.png', import.meta.url).href }, + { icon: 'ChartBar', title: '人才培养驾驶舱', desc: '全校实训数据一屏呈现——项目热度、参与度、完成率、经费使用,决策有据可依', image: new URL('../assets/Features/sk/sk-5.png', import.meta.url).href }, + { icon: 'Banknote', title: '积分商城', desc: '咖豆可兑换实物或虚拟礼品,构建"学、练、评、换"完整激励闭环', small: true, image: new URL('../assets/Features/sk/sk-6.png', import.meta.url).href }, ], painPoints: [ - { title: '人才培养模式落地难,教学管理与“五级进阶”理念脱节。', - desc: '系统内置“项目-模块-任务”三级结构与积分晋级规则,将抽象的“五级进阶”理念转化为可量化、可执行、可追踪的线上流程。学生通过完成任务获得积分,自动点亮技能点,实现逐级晋升,确保培养模式的精准落地。' }, + { - title: ' 实训项目数据散落,缺乏统一管理与深度分析', - desc: '建立统一的校级实训项目库,实现项目创建、审批、排课、执行到归档的全生命周期管理。同时,建设可视化数据大屏,为管理层提供各学院项目数量、学生参与度、完成情况等全景决策数据。' }, - { - title: '技能成长过程不可视,学生缺乏明确的学习目标和动力。', - desc: '系统根据学生参与的实训任务、积分获取情况,自动生成动态的个人技能画像。学生可以直观看到自己已掌握的“技能点”以及距离下一等级的差距,明确优势与不足,并获得持续进阶的动力。' }, - + url: new URL('../assets/images/Carousel/sx-Points-2.svg', import.meta.url).href, title: '人才培养模式落地难,教学管理与”五级进阶”理念脱节。', + desc: '系统内置”项目-模块-任务”三级结构与积分晋级规则,将抽象的”五级进阶”理念转化为可量化、可执行、可追踪的线上流程。学生通过完成任务获得积分,自动点亮技能点,实现逐级晋升,确保培养模式的精准落地。', }, + { url: new URL('../assets/images/Carousel/Points-2.svg', import.meta.url).href, + title: ' 实训项目数据散落,缺乏统一管理与深度分析', + desc: '建立统一的校级实训项目库,实现项目创建、审批、排课、执行到归档的全生命周期管理。同时,建设可视化数据大屏,为管理层提供各学院项目数量、学生参与度、完成情况等全景决策数据。', }, + { url: new URL('../assets/images/Carousel/Points-3.svg', import.meta.url).href, + title: '技能成长过程不可视,学生缺乏明确的学习目标和动力。', + desc: '系统根据学生参与的实训任务、积分获取情况,自动生成动态的个人技能画像。学生可以直观看到自己已掌握的”技能点”以及距离下一等级的差距,明确优势与不足,并获得持续进阶的动力。', }, + ], target: '商科专业群、实训中心、教务处', faq: [ diff --git a/website/src/index.css b/website/src/index.css index 658dbb1..a3a937b 100644 --- a/website/src/index.css +++ b/website/src/index.css @@ -69,3 +69,109 @@ body { text-shadow: 0 2px 40px rgba(0, 162, 234, 0.25), 0 0 80px rgba(0, 162, 234, 0.15); } + +/* ── 台式显示器外框 ── */ +.monitor-frame { + position: relative; + background: #1a1a2e; + border-radius: 8px; + padding: 6px 6px 3px 6px; + box-shadow: + 0 0 0 1px #2a2a3e, + 0 2px 12px rgba(0, 0, 0, 0.3); + max-width: 750px; + margin: 0 auto; +} + +.monitor-screen { + border-radius: 3px; + overflow: hidden; + background: #000; + height: 180px; +} + +.monitor-chin { + display: flex; + align-items: center; + justify-content: center; + padding: 5px 0 2px 0; +} + +.monitor-chin-label { + font-size: 9px; + font-weight: 500; + color: #666; + letter-spacing: 0.06em; + white-space: nowrap; +} + +.monitor-stand-neck { + width: 24px; + height: 18px; + background: linear-gradient(180deg, #2a2a3e 0%, #222236 100%); + margin: 0 auto; + border-radius: 0 0 4px 4px; +} + +.monitor-stand-base { + width: 100px; + height: 5px; + margin: 0 auto; + border-radius: 3px; + background: var(--monitor-theme, #60ce93); + box-shadow: 0 1px 4px rgba(0,0,0,0.2); +} + +/* sm */ +@media (min-width: 640px) { + .monitor-frame { + max-width: 700px; + border-radius: 10px; + padding: 8px 8px 4px 8px; + box-shadow: + 0 0 0 1.5px #2a2a3e, + 0 3px 16px rgba(0, 0, 0, 0.3); + } + .monitor-screen { + border-radius: 3px; + height: 260px; + } + .monitor-chin { padding: 6px 0 3px 0; } + .monitor-chin-label { font-size: 10px; } + .monitor-stand-neck { width: 30px; height: 24px; border-radius: 0 0 5px 5px; } + .monitor-stand-base { width: 130px; height: 7px; border-radius: 4px; } +} + +/* md */ +@media (min-width: 768px) { + .monitor-frame { + max-width: 780px; + border-radius: 12px; + padding: 10px 10px 6px 10px; + box-shadow: + 0 0 0 2px #2a2a3e, + 0 4px 24px rgba(0, 0, 0, 0.3); + } + .monitor-screen { + border-radius: 4px; + height: 360px; + } + .monitor-chin { padding: 8px 0 4px 0; } + .monitor-chin-label { font-size: 11px; } + .monitor-stand-neck { width: 36px; height: 30px; border-radius: 0 0 6px 6px; } + .monitor-stand-base { width: 150px; height: 8px; border-radius: 4px; } +} + +/* lg */ +@media (min-width: 1024px) { + .monitor-frame { max-width: 820px; } + .monitor-screen { height: 440px; } +} + +/* xl */ +@media (min-width: 1280px) { + .monitor-frame { max-width: 860px; } + .monitor-screen { height: 500px; } + .monitor-stand-neck { width: 40px; height: 36px; } + .monitor-stand-base { width: 180px; height: 10px; border-radius: 5px; } +} diff --git a/website/src/pages/Home.jsx b/website/src/pages/Home.jsx index db43426..60e8d38 100644 --- a/website/src/pages/Home.jsx +++ b/website/src/pages/Home.jsx @@ -172,80 +172,103 @@ export default function Home() {
{/* Right: text */} -
+
{(activeCapability !== null ? [capabilities[activeCapability]] : capabilities).map((c, i) => { const idx = activeCapability !== null ? activeCapability : i const color = products[idx]?.themeColor || '#043b8f' const isActive = activeCapability === idx return ( -
setActiveCapability(idx)}> + ? { + backgroundColor: '#fff', + borderColor: color + '20', + boxShadow: `0 12px 40px -8px ${color}18, 0 4px 12px ${color}0a, 0 0 0 1px ${color}10`, + transform: 'scale(1.02)', + zIndex: 10, + padding: '2rem', + } + : { + backgroundColor: '#fafbfc', + borderColor: 'transparent', + boxShadow: 'none', + transform: 'scale(0.97)', + zIndex: 1, + padding: '1.25rem', + opacity: 0.55, + }} + onClick={() => setActiveCapability(idx)} + onMouseEnter={(e) => { if (!isActive) { e.currentTarget.style.opacity = '0.8'; e.currentTarget.style.transform = 'scale(0.98)'; }}} + onMouseLeave={(e) => { if (!isActive) { e.currentTarget.style.opacity = '0.55'; e.currentTarget.style.transform = 'scale(0.97)'; }}}> {/* Left accent line */} - {isActive && ( -
- )} +
{/* Decorative corner blobs */}
-
- {/* Number badge row */} -
- + 0{idx + 1} -
- {/* Product icon */} - {React.createElement(products[idx].icon, { - className: "w-4 h-4 transition-all duration-300", - style: { color: isActive ? color : '#cbd5e1' } - })} + ? { backgroundColor: color, boxShadow: `0 4px 12px ${color}30`, width: '2.5rem', height: '2.5rem' } + : { backgroundColor: color + '08', width: '2rem', height: '2rem' }}> + {React.createElement(products[idx].icon, { + className: isActive ? "w-5 h-5" : "w-4 h-4", + style: { color: isActive ? '#fff' : color + '60' } + })} + +
+ Core Capability +
+
{/* Title */} -

{c.title}

- {/* Subtitle */} -

{c.sub}

- {/* Divider */} -
- {/* Description */} -

{c.desc}

- {/* Tags */} - {c.tip && ( -
- {c.tip.split('、').map((t, ti) => ( - - {t} - - ))} -
- )} - {/* View more link */} +

{c.title}

+ {/* Subtitle - only active */} {isActive && ( -
- e.stopPropagation()} - className="inline-flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium transition-all duration-300" - style={{ color: color, backgroundColor: color + '0a' }} - onMouseEnter={(e) => { e.target.style.backgroundColor = color + '1a'; }} - onMouseLeave={(e) => { e.target.style.backgroundColor = color + '0a'; }}> - 查看全部 - - -
+

{c.sub}

+ )} + {/* Divider */} +
+ {/* Description - only active */} + {isActive && ( + <> +

{c.desc}

+ {/* Tags */} + {c.tip && ( +
+ {c.tip.split('、').map((t, ti) => ( + + {t} + + ))} +
+ )} + {/* View more link */} +
+ e.stopPropagation()} + className="inline-flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-semibold transition-all duration-300 hover:shadow-sm" + style={{ color: '#fff', backgroundColor: color }} + onMouseEnter={(e) => { e.target.style.filter = 'brightness(1.1)'; }} + onMouseLeave={(e) => { e.target.style.filter = 'brightness(1)'; }}> + 查看全部 + + +
+ )}
) diff --git a/website/src/pages/ProductPage.jsx b/website/src/pages/ProductPage.jsx index 7dec215..62f8c1e 100644 --- a/website/src/pages/ProductPage.jsx +++ b/website/src/pages/ProductPage.jsx @@ -1,9 +1,17 @@ -import { useParams, Link } from 'react-router-dom' -import { ChevronDown, ArrowRight, Shield, Clock, Headphones, AlertCircle } from 'lucide-react' -import { getProduct } from '../data/products' -import ScrollReveal from '../components/ScrollReveal' -import StatNumber from '../components/StatNumber' -import Carousel from '../components/Carousel' +import { useParams, Link } from "react-router-dom" +import { ChevronDown, ArrowRight, Shield, Clock, Headphones, AlertCircle, GitBranch, FileStack, MessageCircleX, FileDigit, SearchCheck, Banknote, ChartBar, Bell, Layers, ScrollText, CalendarCheck, TrendingUp, Pyramid, Database, Activity, Star } from "lucide-react" +import { getProduct } from "../data/products" +import ScrollReveal from "../components/ScrollReveal" +import StatNumber from "../components/StatNumber" +import Carousel from "../components/Carousel" +import ThemedSvg from "../components/ThemedSvg" + +// 图标映射表 — 所有图标均来自 Lucide React (MIT License,免费商用) +const iconMap = { + GitBranch, FileStack, MessageCircleX, FileDigit, SearchCheck, + Banknote, ChartBar, Bell, Layers, ScrollText, CalendarCheck, + TrendingUp, Pyramid, Database, Activity, +} export default function ProductPage() { const { slug } = useParams() @@ -42,26 +50,26 @@ export default function ProductPage() { > {/* ── Hero ── */}
-
+
{/* Desktop: left image + right card */} -
+
{/* Image - left */} -
+
{product.heroImage && ( - + )}
{/* Content - right */} -
- -

+
+ +

{product.name}

-

+

{product.slogan}

{product.stats && ( -
+
{product.stats.map((s, i) => (
@@ -108,75 +116,182 @@ export default function ProductPage() {

- {/* ── Brief ── */} -
-
+ {/* ── Brief / 产品简介 ── */} +
+
-
- {/* Floating decorative shapes */} -
-
-
+ {/* ═══ 折角卡片 ═══ */} +
-

- {product.brief} -

-
- - {product.tags && ( -
- {product.tags.map((tag, i) => ( - - {tag} - - - - - - ))} + {/* ── 右上折角 ── */} +
+ {/* 折角在卡片上投下的阴影 */} +
+ {/* 折角主体 — 品牌色渐变,模拟纸张背面 */} +
+ {/* 折角内面高光 */} +
+ {/* 折痕线 */} +
+ {/* 图标 */} +
- )} + + {/* ── 内容区 ── */} +
+ {/* 顶部装饰线 + 标签 */} +
+ + + Brief + +
+ + {/* 标题 */} +

+ 产品简介 +

+ + {/* 正文 */} +

+ {product.brief} +

+ + {/* ═══ 底部标签 ═══ */} + {product.tags && ( +
+ {product.tags.map((tag, i) => ( + + {tag} + + ))} +
+ )} +
+
{/* ── Pain Points ── */} {product.painPoints && product.painPoints.length > 0 && ( -
-
- -
-
- - Pain Points -
-

- {product.painPointsTitle || `${product.name}解决的核心问题`} -

-

深入理解管理难题,提供经过实战验证的解决方案

-
-
-
+
+ {/* ── 标题区 ── */} +
+ + + Pain Points & Solutions + + +

+ {product.painPointsTitle || `${product.name}\n解决的核心问题`} +

+

+ 直击业务痛点,提供经过实战验证的完整解决方案 +

+
+ +
+ + {/* ── 响应式布局:移动端堆叠,md+ 左右对半 ── */} +
{product.painPoints.map((item, i) => ( - -
-
- {/* Pain point */} -
-
- -
-

{item.title}

-
- {/* Solution */} -
- 解决方案 -

{item.desc}

+
+ {/* ═══ 配图 ═══ */} +
+
+ {item.url ? ( + item.url.endsWith('.svg') ? ( + + ) : ( + {item.title} + ) + ) : ( +
+ 暂无配图 +
+ )}
- + + {/* ═══ 文字 ═══ */} +
+
+ {/* ── 痛点书签卡 ── */} +
+
+
+ 痛点 +
+
+
+

+ {item.title} +

+
+
+
+ + {/* ── 解决方案书签卡 ── */} +
+
+
+ 解决方案 +
+
+
+

+ {item.desc} +

+
+
+
+
+
+
))}
@@ -184,23 +299,24 @@ export default function ProductPage() { )} {/* ── Core Features ── */} -
-
+
+
- - Core Features + + Core Features +
-

+

核心功能

{product.target && ( -
- 适用对象: +
+ 适用对象
{product.target.split('、').map((t, i) => ( - {t.trim()} + {t.trim()} ))}
@@ -208,23 +324,139 @@ export default function ProductPage() {
-
+ {/* ── 桌面端:每个功能一行卡片(左文字 + 右截图) ── */} +
{product.features.map((f, i) => ( -
-
-
-
+
+ {/* hover 边框光 */} +
-
-
- 0{i + 1} -
+ {/* 文字区 */} +
+ {/* 序号 + 标签 */} +
+ + {f.icon && iconMap[f.icon] ? (() => { const Icon = iconMap[f.icon]; return })() : {String(i + 1).padStart(2, '0')}} + +
+ Core Feature +
-

{f.title}

-

{f.desc}

+ {/* 标题 */} +

+ {f.title} +

+ {/* 分隔线 */} +
+ {/* 描述 */} +

+ {f.desc} +

+ + {/* 截图区 */} +
+ {f.image ? ( +
+ {f.small ? ( + /* 手机模型外壳 */ +
+
+
+
+ + +
+
+
+ {f.title} +
+
+
+
+
+
+ ) : ( + /* 浏览器窗口效果 */ +
+
+ + + + {f.title} +
+ {f.title} +
+ )} +
+ ) : ( +
+
+ + + +
+
+ 暂无截图 +
+
+ )} +
+
+ + ))} +
+ + {/* ── 移动端:紧凑卡片 ── */} +
+ {product.features.map((f, i) => ( + +
+
+
+ + {f.icon && iconMap[f.icon] ? (() => { const Icon = iconMap[f.icon]; return })() : {String(i + 1).padStart(2, '0')}} + + 核心功能 +
+

{f.title}

+

{f.desc}

+
+ {f.image && ( +
+ {f.small ? ( +
+
+
+
+ + +
+
+
+ {f.title} +
+
+
+
+
+
+ ) : ( +
+
+ + + + {f.title} +
+ {f.title} +
+ )} +
+ )}
))} @@ -239,7 +471,7 @@ export default function ProductPage() {
- + Product Showcase

@@ -254,15 +486,16 @@ export default function ProductPage() { )} {/* ── Advantages ── */} -
+
- - Why Choose Us + + Why Choose Us +
-

+

为什么选择我们

@@ -275,21 +508,45 @@ export default function ProductPage() { { icon: Headphones, title: '专属服务', desc: '7×24 小时响应,专属客户经理全程陪伴' }, ].map((item, i) => ( -
-
-
-
+
+ {/* 顶部品牌色条 — hover 时滑入 */} +
+ {/* 底部品牌色条 — 始终可见 */} +
-
-
-
- +
+ {/* 图标 — 大圆形容器 */} +
+
+
-
-

{item.title}

-

{item.desc}

+ + {/* 标题 */} +

+ {item.title} +

+ + {/* 分隔线 */} +
+ + {/* 描述 */} +

+ {item.desc} +

@@ -305,7 +562,7 @@ export default function ProductPage() {
- + FAQ

@@ -325,7 +582,7 @@ export default function ProductPage() { Q{i + 1}

{item.q}

-
+