feat: 沙香科技官网 v2.2 基线(深色科技风/双语/局域网+公网双部署)

This commit is contained in:
dafe
2026-11-02 14:57:08 +08:00
commit 924bca9f98
91 changed files with 1632 additions and 0 deletions

12
.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
# 工作日志不入库(用户要求 PROGRESS 不提交)
docs/PROGRESS.md
# 源资料:17MB 的 PPT 原件(素材已提取到 assets,需要时从原文件恢复)
产品手册.pptx
.~产品手册.pptx
# macOS
.DS_Store
# 生成物备份(原图原件,可从 PPT / 用户素材重新生成)
assets/img/qrcode-orig.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

646
assets/css/style.css Normal file
View File

@@ -0,0 +1,646 @@
/* ============================================================
沙香科技官网 v2 — 深色科技风
设计语言(2026 范式):极光渐变 + 噪点 + Bento 网格 + 发光描边
品牌色取自 logo:深蓝底 + 红;辅助青蓝呼应产品摄影冷色调
============================================================ */
:root {
--bg-0: #04070f;
--bg-1: #070b16;
--bg-2: rgba(148, 178, 255, 0.04);
--line: rgba(148, 178, 255, 0.14);
--text: #e9eef8;
--muted: #93a0b8;
--brand: #ff3d5a;
--cyan: #4cc3ff;
--grad: linear-gradient(96deg, var(--cyan), var(--brand));
--radius: 16px;
--container: 1180px;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
background: var(--bg-0);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"PingFang SC", "Hiragino Sans GB", "Noto Sans SC", "Microsoft YaHei", sans-serif;
line-height: 1.7;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
/* 噪点颗粒:消除渐变色带、增加质感(subtle grain) */
body::after {
content: "";
position: fixed;
inset: 0;
z-index: 2000;
pointer-events: none;
opacity: 0.04;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
.container { max-width: var(--container); margin: 0 auto; padding: 0 24px; }
.grad-text {
background: var(--grad);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
/* ============================================================
导航
============================================================ */
.site-header {
position: fixed;
inset: 0 0 auto 0;
z-index: 100;
transition: background 0.3s, backdrop-filter 0.3s, border-color 0.3s;
border-bottom: 1px solid transparent;
}
.site-header.scrolled {
background: rgba(4, 7, 15, 0.78);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border-color: var(--line);
}
.nav-wrap { display: flex; align-items: center; gap: 20px; height: 68px; }
.brand { flex-shrink: 0; }
/* 反白版 logo(tools/make_logo_light.py):黑字提亮为白、彩色保留色相,深底页面直接融合 */
.brand-logo { height: 38px; width: auto; }
.nav { display: flex; align-items: center; gap: 26px; margin-left: auto; font-size: 14.5px; }
.nav a { color: var(--muted); transition: color 0.2s; }
.nav a:hover { color: var(--text); }
.nav-cta {
padding: 7px 18px;
border: 1px solid var(--line);
border-radius: 999px;
color: var(--text) !important;
transition: border-color 0.2s, box-shadow 0.2s;
}
.nav-cta:hover { border-color: var(--brand); box-shadow: 0 0 18px rgba(255, 61, 90, 0.25); }
.lang-toggle {
background: none;
border: 1px solid var(--line);
color: var(--muted);
border-radius: 999px;
width: 44px;
height: 32px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: color 0.2s, border-color 0.2s;
flex-shrink: 0;
}
.lang-toggle:hover { color: var(--text); border-color: var(--cyan); }
.menu-toggle { display: none; flex-direction: column; gap: 5px; background: none; border: none; cursor: pointer; padding: 6px; }
.menu-toggle span { width: 22px; height: 2px; background: var(--text); border-radius: 2px; transition: transform 0.25s, opacity 0.25s; }
.menu-toggle.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.menu-toggle.open span:nth-child(2) { opacity: 0; }
.menu-toggle.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* ============================================================
Hero — 极光 + 网格(无照片,对比度完全可控)
============================================================ */
.hero { position: relative; min-height: 92vh; display: flex; align-items: center; overflow: hidden; }
/* 三团极光:青 / 品红 / 深蓝,各自缓慢漂移呼吸 */
.aurora { position: absolute; inset: -20%; filter: blur(90px); }
.aurora i { position: absolute; border-radius: 50%; opacity: 0.5; }
.aurora i:nth-child(1) {
width: 44vw; height: 44vw; left: -6%; top: -12%;
background: radial-gradient(circle, rgba(76, 195, 255, 0.55), transparent 65%);
animation: drift1 14s ease-in-out infinite alternate;
}
.aurora i:nth-child(2) {
width: 40vw; height: 40vw; right: -8%; top: 8%;
background: radial-gradient(circle, rgba(255, 61, 90, 0.38), transparent 65%);
animation: drift2 18s ease-in-out infinite alternate;
}
.aurora i:nth-child(3) {
width: 46vw; height: 46vw; left: 28%; bottom: -26%;
background: radial-gradient(circle, rgba(64, 72, 220, 0.4), transparent 65%);
animation: drift3 22s ease-in-out infinite alternate;
}
@keyframes drift1 { to { transform: translate(9vw, 7vh) scale(1.15); } }
@keyframes drift2 { to { transform: translate(-8vw, 10vh) scale(0.9); } }
@keyframes drift3 { to { transform: translate(6vw, -8vh) scale(1.1); } }
/* 科技网格:向下的渐隐遮罩 */
.hero-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(76, 195, 255, 0.06) 1px, transparent 1px),
linear-gradient(90deg, rgba(76, 195, 255, 0.06) 1px, transparent 1px);
background-size: 56px 56px;
mask-image: linear-gradient(180deg, transparent 0%, #000 40%, transparent 92%);
-webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 40%, transparent 92%);
}
.hero-inner { position: relative; z-index: 1; padding-top: 68px; }
.hero-eyebrow {
font-size: 14px;
letter-spacing: 0.2em;
color: var(--cyan);
font-weight: 600;
margin-bottom: 22px;
display: flex;
align-items: center;
gap: 12px;
}
/* eyebrow 前的脉冲光点:生命感 */
.hero-eyebrow::before {
content: "";
width: 9px; height: 9px;
border-radius: 50%;
background: var(--cyan);
box-shadow: 0 0 12px 2px rgba(76, 195, 255, 0.8);
animation: pulse 2.2s ease-in-out infinite;
}
@keyframes pulse { 50% { opacity: 0.35; } }
.hero-title {
font-size: clamp(42px, 7vw, 84px);
font-weight: 800;
line-height: 1.15;
letter-spacing: 0.01em;
margin-bottom: 26px;
text-wrap: balance;
}
.hero-sub { max-width: 640px; color: var(--muted); font-size: 17px; margin-bottom: 40px; }
.hero-actions { display: flex; gap: 16px; flex-wrap: wrap; }
.btn {
display: inline-block;
padding: 13px 34px;
border-radius: 999px;
font-size: 15.5px;
font-weight: 600;
transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
}
.btn-primary {
background: var(--grad);
color: #fff;
box-shadow: 0 8px 30px rgba(76, 195, 255, 0.28);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 12px 44px rgba(255, 61, 90, 0.4); }
.btn-ghost { border: 1px solid var(--line); color: var(--text); }
.btn-ghost:hover { border-color: var(--cyan); transform: translateY(-2px); }
/* ============================================================
技术词条跑马灯
============================================================ */
.marquee {
border-block: 1px solid var(--line);
background: rgba(148, 178, 255, 0.03);
overflow: hidden;
position: relative;
}
/* 两侧渐隐,词条像从光雾里滚出 */
.marquee::before, .marquee::after {
content: "";
position: absolute;
top: 0; bottom: 0;
width: 120px;
z-index: 1;
pointer-events: none;
}
.marquee::before { left: 0; background: linear-gradient(90deg, var(--bg-0), transparent); }
.marquee::after { right: 0; background: linear-gradient(-90deg, var(--bg-0), transparent); }
.marquee-track {
display: flex;
gap: 48px;
width: max-content;
padding: 16px 0;
animation: scroll 36s linear infinite;
}
.marquee-track span {
font-size: 14px;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--muted);
white-space: nowrap;
display: flex;
align-items: center;
gap: 48px;
}
.marquee-track span::after { content: "✦"; color: var(--brand); font-size: 11px; }
@keyframes scroll { to { transform: translateX(-50%); } }
/* ============================================================
区块通用
============================================================ */
.section { padding: 104px 0; }
.section-alt {
background: var(--bg-1);
/* 顶部一条极细渐变分隔线,代替粗边框 */
border-block: 1px solid transparent;
border-image: linear-gradient(90deg, transparent, rgba(76, 195, 255, 0.35), transparent) 1;
}
.section-head { margin-bottom: 52px; max-width: 780px; }
.eyebrow {
font-size: 13px;
font-weight: 700;
letter-spacing: 0.28em;
color: var(--brand);
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 10px;
}
.eyebrow::before { content: ""; width: 22px; height: 1px; background: var(--brand); }
.section-head h2 { font-size: clamp(30px, 4vw, 44px); font-weight: 800; line-height: 1.25; }
.section-desc { color: var(--muted); margin-top: 16px; font-size: 16.5px; }
/* ============================================================
关于 — Bento 网格
============================================================ */
.bento { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: auto; gap: 18px; }
.bento-text { grid-column: 1 / 3; padding: 30px 32px; }
.bento-photo { grid-column: 3 / 5; min-height: 300px; }
.bento-stat { padding: 22px; }
.bento-text, .bento-photo, .bento-stat {
border-radius: var(--radius);
border: 1px solid var(--line);
background: var(--bg-2);
position: relative;
overflow: hidden;
}
/* Bento 卡顶部一线品牌光 */
.bento-text::before, .bento-photo::before, .bento-stat::before {
content: "";
position: absolute;
inset: 0 0 auto 0;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(76, 195, 255, 0.5), transparent);
}
.bento-text p { color: var(--muted); margin-bottom: 16px; font-size: 15px; }
.bento-text p:first-child { color: var(--text); }
/* 完整显示不裁剪:PPT 原图左右各约 40% 会被 cover 裁掉(CCTV 标志即因此丢失) */
.bento-photo { display: flex; }
.bento-photo img {
width: 100%;
height: auto;
max-height: 100%;
object-fit: contain;
margin: auto;
border-radius: 8px;
}
.bento-stat strong { display: block; font-size: 19px; margin-bottom: 5px; }
.bento-stat span { font-size: 13px; color: var(--muted); }
.bento-stat:hover { border-color: rgba(76, 195, 255, 0.45); transition: border-color 0.25s; }
/* ============================================================
痛点
============================================================ */
.pain-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; margin-bottom: 52px; }
.pain-grid-3 { grid-template-columns: repeat(3, 1fr); }
.pain {
border: 1px solid var(--line);
border-radius: 12px;
padding: 16px 18px;
background: var(--bg-2);
}
/* 左上角缺角高亮条:批次感 */
.pain::before {
content: "";
display: block;
width: 26px; height: 3px;
border-radius: 2px;
background: var(--grad);
margin-bottom: 10px;
}
.pain h4 { font-size: 15px; margin-bottom: 4px; }
.pain p { font-size: 13px; color: var(--muted); }
/* ============================================================
产品卡 — 发光描边 + 镂空图
============================================================ */
.product-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; }
.product-grid-3 { grid-template-columns: repeat(3, 1fr); }
.card {
position: relative;
border-radius: var(--radius);
overflow: hidden;
background:
linear-gradient(var(--bg-1), var(--bg-1)) padding-box,
linear-gradient(140deg, rgba(76, 195, 255, 0.4), rgba(148, 178, 255, 0.08) 40%, rgba(255, 61, 90, 0.35)) border-box;
border: 1px solid transparent;
transition: transform 0.25s, box-shadow 0.25s, background 0.25s;
}
.card:hover {
transform: translateY(-6px);
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5), 0 0 30px rgba(76, 195, 255, 0.12);
background:
linear-gradient(var(--bg-1), var(--bg-1)) padding-box,
linear-gradient(140deg, rgba(76, 195, 255, 0.75), rgba(148, 178, 255, 0.15) 40%, rgba(255, 61, 90, 0.65)) border-box;
}
/* 镂空产品图的舞台:底部品牌辉光托底 */
.product-media {
display: flex;
align-items: center;
justify-content: center;
padding: 34px 28px;
min-height: 250px;
background:
radial-gradient(90% 70% at 50% 105%, rgba(76, 195, 255, 0.16), transparent 60%),
radial-gradient(50% 40% at 50% 100%, rgba(255, 61, 90, 0.10), transparent 70%),
var(--bg-0);
}
.product-media img {
max-height: 230px;
width: auto;
max-width: 100%;
filter: drop-shadow(0 18px 30px rgba(0, 0, 0, 0.55));
transition: transform 0.3s;
}
.card:hover .product-media img { transform: scale(1.06); }
/* 背景复杂的实拍图:不镂空,统一描边容器 */
.product-media img.framed {
border-radius: 12px;
border: 1px solid rgba(233, 238, 248, 0.22);
box-shadow: 0 14px 36px rgba(0, 0, 0, 0.45);
filter: none;
}
.product-body { padding: 20px 22px 24px; }
.product-body h3 { font-size: 17px; margin-bottom: 12px; }
.product-note { font-size: 13.5px; color: var(--muted); margin-bottom: 12px; }
/* 功能标签:等宽网格对齐,杜绝换行参差 */
.tags {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
gap: 7px;
}
.tags span {
font-size: 12px;
color: var(--cyan);
background: rgba(76, 195, 255, 0.08);
border: 1px solid rgba(76, 195, 255, 0.22);
padding: 5px 4px;
border-radius: 8px;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 英文模式:标签词更长,放宽格子并缩小字号防截断 */
html[lang="en"] .tags { grid-template-columns: repeat(auto-fill, minmax(124px, 1fr)); }
html[lang="en"] .tags span { font-size: 11px; }
.feature-row { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; align-items: stretch; }
.product-hero { display: flex; flex-direction: column; }
.product-hero .product-media { flex: 1; min-height: 340px; }
.product-hero .product-media img { max-height: 300px; }
.scene-side { border-radius: var(--radius); border: 1px solid var(--line); object-fit: cover; width: 100%; }
/* ============================================================
场景图
============================================================ */
.scene-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 22px; margin-top: 22px; }
.scene-grid img {
border-radius: var(--radius);
border: 1px solid var(--line);
height: 100%;
object-fit: cover;
transition: transform 0.3s;
}
.scene-grid img:hover { transform: scale(1.015); }
/* ============================================================
平台/定制卡
============================================================ */
.platform-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.platform-media {
position: relative;
background: var(--bg-0);
display: flex;
align-items: flex-end;
justify-content: center;
padding: 22px;
min-height: 230px;
overflow: hidden;
}
.platform-media::before {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(120% 90% at 50% 0%, rgba(76, 195, 255, 0.10), transparent 60%);
}
/* 多图卡:局部滑动展示。截图统一高度、宽度按原始比例自适应,
超宽截图自然超出卡片形成"滑动看局部",宽度永远匹配内容 */
.slider {
display: block;
overflow-x: auto;
scroll-snap-type: x mandatory;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
}
.slider::-webkit-scrollbar { display: none; }
.slides { display: flex; gap: 16px; align-items: flex-end; }
.slides figure {
flex: 0 0 auto;
scroll-snap-align: center;
margin: 0 4px;
display: flex;
justify-content: center;
}
.slides img {
height: 176px;
width: auto;
max-width: none;
border-radius: 10px;
border: 1px solid var(--line);
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
}
/* 手机竖屏截图稍高,底对齐时视觉平衡 */
.slides img.shot-phone { height: 196px; }
/* 指示点 */
.dots {
position: absolute;
left: 0; right: 0; bottom: 8px;
display: flex;
justify-content: center;
gap: 7px;
z-index: 2;
}
.dots button {
width: 7px; height: 7px;
border-radius: 50%;
border: none;
padding: 0;
cursor: pointer;
background: rgba(148, 178, 255, 0.25);
transition: background 0.2s, transform 0.2s;
}
.dots button.active {
background: var(--cyan);
transform: scale(1.35);
box-shadow: 0 0 8px rgba(76, 195, 255, 0.7);
}
.shot-main {
width: 100%;
max-width: 420px;
border-radius: 10px;
border: 1px solid var(--line);
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
}
.shot-wide { max-width: 480px; }
.shot-phone {
width: 96px;
flex-shrink: 0;
border-radius: 12px;
border: 1px solid var(--line);
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
}
.feature-list li {
position: relative;
padding-left: 22px;
font-size: 14px;
color: var(--muted);
margin-bottom: 9px;
}
.feature-list li::before {
content: "";
position: absolute;
left: 0;
top: 9px;
width: 7px;
height: 7px;
border-radius: 2px;
background: var(--grad);
}
/* ============================================================
联系
============================================================ */
.contact {
background:
radial-gradient(70% 100% at 50% 100%, rgba(255, 61, 90, 0.10), transparent 70%),
var(--bg-1);
text-align: center;
}
.contact-inner { max-width: 720px; }
.contact-title {
font-size: clamp(34px, 5vw, 56px);
font-weight: 800;
display: flex;
gap: 22px;
justify-content: center;
flex-wrap: wrap;
}
.contact-sub { color: var(--muted); margin: 18px 0 44px; }
.contact-card {
display: inline-flex;
align-items: center;
gap: 36px;
padding: 32px 44px;
border-radius: 20px;
background:
linear-gradient(var(--bg-1), var(--bg-1)) padding-box,
linear-gradient(140deg, rgba(76, 195, 255, 0.4), rgba(255, 61, 90, 0.4)) border-box;
border: 1px solid transparent;
text-align: left;
}
.qrcode { width: 148px; height: 148px; border-radius: 12px; }
.contact-mail {
font-size: 21px;
font-weight: 700;
background: var(--grad);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
display: inline-block;
margin-bottom: 10px;
}
.contact-mail:hover { filter: brightness(1.2); }
.contact-info p { font-size: 14px; color: var(--muted); margin-bottom: 4px; }
/* ============================================================
Footer
============================================================ */
.site-footer { border-top: 1px solid var(--line); padding: 30px 0; }
.footer-wrap { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 14px; }
.footer-brand { display: flex; align-items: center; gap: 14px; }
.footer-brand .brand-logo { height: 30px; }
.footer-brand span { font-size: 14px; color: var(--muted); }
.footer-copy { font-size: 13px; color: var(--muted); }
/* ============================================================
滚动淡入
============================================================ */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity 0.7s ease, transform 0.7s ease; }
.reveal.visible { opacity: 1; transform: none; }
/* ============================================================
响应式
============================================================ */
@media (max-width: 1024px) {
.product-grid, .pain-grid, .platform-grid { grid-template-columns: repeat(2, 1fr); }
.pain-grid-3 { grid-template-columns: repeat(2, 1fr); }
.bento { grid-template-columns: repeat(2, 1fr); }
.bento-text, .bento-photo { grid-column: 1 / 3; }
.bento-photo { min-height: 240px; }
}
@media (max-width: 768px) {
.section { padding: 72px 0; }
.menu-toggle { display: flex; margin-left: auto; }
.lang-toggle { margin-left: auto; }
.menu-toggle { margin-left: 0; }
.nav {
position: fixed;
top: 68px;
left: 0; right: 0;
flex-direction: column;
align-items: flex-start;
padding: 20px 24px 28px;
gap: 18px;
background: rgba(4, 7, 15, 0.96);
backdrop-filter: blur(16px);
border-bottom: 1px solid var(--line);
display: none;
}
.nav.open { display: flex; }
.hero { min-height: 88vh; }
.hero-sub { font-size: 15.5px; }
.aurora { filter: blur(60px); }
.feature-row, .scene-grid { grid-template-columns: 1fr; }
.stats { gap: 14px; }
.contact-card { flex-direction: column; text-align: center; gap: 20px; padding: 28px; }
}
@media (max-width: 520px) {
.product-grid, .pain-grid, .pain-grid-3, .platform-grid, .bento { grid-template-columns: 1fr; }
.bento-text, .bento-photo { grid-column: auto; }
.hero-actions .btn { width: 100%; text-align: center; }
.product-media { min-height: 210px; }
}
/* 尊重系统减弱动效偏好 */
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.aurora i, .marquee-track, .hero-eyebrow::before { animation: none; }
.reveal { opacity: 1; transform: none; transition: none; }
.card, .btn, .bento-stat { transition: none; }
}

10
assets/favicon.svg Normal file
View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#4cc3ff"/>
<stop offset="1" stop-color="#ff3d5a"/>
</linearGradient>
</defs>
<rect width="64" height="64" rx="14" fill="#070b16"/>
<path d="M45 20H27a8 8 0 0 0 0 16h10a8 8 0 0 1 0 16H19" fill="none" stroke="url(#g)" stroke-width="7" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 442 B

BIN
assets/img/about-base.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
assets/img/about-main.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
assets/img/ai-agent.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

BIN
assets/img/ai-agent.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
assets/img/bt-tag-st02.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
assets/img/building.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
assets/img/building.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
assets/img/cctv.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
assets/img/cctv.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
assets/img/collar-sg03.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
assets/img/digital-twin.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
assets/img/factory-line.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
assets/img/factory.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

BIN
assets/img/factory.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
assets/img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/img/goat.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
assets/img/goat.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
assets/img/hero-bg.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
assets/img/hero-grazing.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

BIN
assets/img/hydro-class.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

BIN
assets/img/hydro-class.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
assets/img/liangchang.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

BIN
assets/img/liangchang.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
assets/img/logo-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
assets/img/logo-light.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
assets/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
assets/img/p-bb03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

BIN
assets/img/p-bb03.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

BIN
assets/img/p-bg01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

BIN
assets/img/p-bg01.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
assets/img/p-hs01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

BIN
assets/img/p-hs01.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/img/p-sg03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
assets/img/p-sg03.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
assets/img/p-sg03mini.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

BIN
assets/img/p-sg03mini.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
assets/img/p-sl01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

BIN
assets/img/p-sl01.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
assets/img/p-st01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

BIN
assets/img/p-st01.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

BIN
assets/img/p-st02.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

BIN
assets/img/p-st02.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
assets/img/qrcode.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
assets/img/qrcode.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

227
assets/js/main.js Normal file
View File

@@ -0,0 +1,227 @@
/* ============================================================
沙香科技官网交互:中英切换 / 滚动淡入 / 导航
中文为 HTML 默认内容(SEO 友好),英文通过本字典替换
============================================================ */
(function () {
'use strict';
/* ---------- 英文字典(key 对应 data-i18n) ---------- */
var EN = {
// 导航
'nav.about': 'About', 'nav.grazing': 'Digital Grazing', 'nav.planting': 'Smart Planting',
'nav.asset': 'Asset Management', 'nav.platform': 'Software Platform',
'nav.custom': 'Custom Development', 'nav.contact': 'Contact Us',
// Hero
'hero.eyebrow': 'Suzhou Shashann Technology · AIoT',
'hero.title1': 'Powering Digital', 'hero.title2': 'Transformation with AIoT',
'hero.sub': 'Artificial intelligence, edge computing, cloud computing and low-power IoT — smart hardware products and digital software platforms that measurably boost efficiency and productivity across industries.',
'hero.cta1': 'Explore Solutions', 'hero.cta2': 'Contact Us',
// 关于
'about.title': 'About Shashann',
'about.p1': 'Suzhou Shashann Technology is an AIoT company dedicated to digital upgrading across industries — combining AI, edge computing, cloud computing and low-power IoT to deliver smart hardware products and digital software service platforms that significantly improve efficiency and productivity while cutting production and management costs.',
'about.p2': 'At the 10th anniversary of the Belt and Road Initiative, our self-developed smart livestock product was named a "China Signature Product" and was featured in episode 6 of the documentary "The Light of Technology". Our portfolio — smart collars, smart ear tags, smart hydroponic grow racks, smart terminals and smart asset tags — is already deployed across smart grazing, smart planting and smart asset management.',
'about.p3': 'Our core team brings deep AIoT expertise and partners with leading universities for continuous innovation, with R&D and production bases in Nanjing, Zhangjiagang and Changzhou, and products sold overseas. Guided by "Customer First, Innovation Driven", we aim to be a trusted, industry-leading AIoT company.',
'about.stat1v': 'China Signature Product', 'about.stat1k': 'Belt & Road 10th Anniversary',
'about.stat2v': 'The Light of Technology', 'about.stat2k': 'Featured in documentary Ep.6',
'about.stat3v': '3 Bases', 'about.stat3k': 'Nanjing · Zhangjiagang · Changzhou',
'about.stat4v': 'Sold Overseas', 'about.stat4k': 'Deployed at scale in many sectors',
// 数字畜牧
'grazing.title': 'Digital Grazing',
'grazing.desc': 'Livestock farming is geographically scattered with long grazing cycles, long dependent on manual inspection and experience. Our collars, ear tags and Bluetooth base stations turn grazing from "by experience" into "by data".',
'grazing.pain1t': 'Low Production Efficiency', 'grazing.pain1d': 'Each herder can only look after a limited number of livestock.',
'grazing.pain2t': 'No Early Warning', 'grazing.pain2d': 'Wide distribution and mobility make status monitoring and traceability difficult.',
'grazing.pain3t': 'Hard Insurance Claims', 'grazing.pain3d': 'Key events like epidemics, deaths and losses lack objective data.',
'grazing.pain4t': 'Ecology Unmeasured', 'grazing.pain4d': 'Grassland capacity and ecological change are hard to quantify and close the loop.',
'grazing.p1n': 'Smart Collar SG03 mini',
'grazing.p2n': 'Smart Collar SG03',
'grazing.p3n': 'Smart Bluetooth Ear Tag ST01',
'grazing.p4n': 'Smart Bluetooth Base Station BG01',
// 智慧种植
'planting.title': 'Smart Planting',
'planting.desc': 'Urban residents increasingly want to grow food at home, and school labor courses and AI education need better carriers. Smart hydroponics is convenient, intelligent and clean — we turn it from an expensive toy into a system that actually grows.',
'planting.pain1t': 'For Users', 'planting.pain1d': 'Beginners fail often; one bad experience kills repurchase.',
'planting.pain2t': 'For Products', 'planting.pain2d': 'Fake intelligence and immature consumables leave no returning revenue.',
'planting.pain3t': 'For the Industry', 'planting.pain3d': 'The category is still seen as an expensive toy with no leading brand.',
'planting.p1n': 'Smart Hydroponic Grow Rack HS01',
'planting.p1note': 'Standalone cabinet design, easy to expand; supports unattended AI mode and manual control.',
// 设备资产
'asset.title': 'Digital Equipment & Asset Management',
'asset.desc': 'Enterprises hold large, widely distributed asset pools that manual ledgers and periodic patrols cannot cover. IoT and AI make full lifecycle management possible — from "reactive repair" to "predictive maintenance".',
'asset.pain1t': 'Invisible Field', 'asset.pain1d': 'Ledgers never match reality; counting assets still means walking around.',
'asset.pain2t': 'No Traceability', 'asset.pain2d': 'Lack of recorded data makes quality issues hard to locate.',
'asset.pain3t': 'Fragmented Systems', 'asset.pain3d': 'Multiple systems, ununified data, weak decision support.',
'asset.pain4t': 'Reactive Maintenance', 'asset.pain4d': 'Repair-after-failure dominates; downtime costs far exceed maintenance.',
'asset.p1n': 'Smart Terminal BB03',
'asset.p1note': 'High-accuracy edge computing that reliably recognizes device/asset state.',
'asset.p2n': 'UWB Smart Tag SL01',
'asset.p2note': 'Works with safety helmets; easy to install.',
'asset.p3n': 'Bluetooth Smart Tag ST02',
// 软件平台
'platform.title': 'Software Platform',
'platform.desc': 'Every hardware line ships with a companion SaaS platform, APP and WeChat mini program — device data flows straight to the cloud, management is not tied to any terminal.',
'platform.s1n': 'Smart Grazing System',
'platform.s1a': 'SaaS platform, APP and WeChat mini program',
'platform.s1b': 'Multi-account ranch management, precision tracking and geofence alarms',
'platform.s1c': 'Livestock vitals monitoring, voice calling and music playback',
'platform.s1d': 'Device management with full lifecycle data and traceability',
'platform.s2n': 'Smart Hydroponics System',
'platform.s2a': 'SaaS platform and APP',
'platform.s2b': 'Multi-account planting management with live status',
'platform.s2c': 'Automatic planting adjustment system',
'platform.s2d': 'AI planting assistant',
'platform.s3n': 'Smart Asset Management System',
'platform.s3a': 'SaaS platform and WeChat mini program',
'platform.s3b': 'Multi-account asset and maintenance management',
'platform.s3c': 'Real-time computation of asset state and location',
'platform.s3d': 'Accurate prediction and maintenance from historical data',
// 定制开发
'custom.title': 'Custom Software Development',
'custom.desc': 'Building on our engineering and simulation expertise, we deliver custom systems for industry clients — from digital twins to multi-agent workflows.',
'custom.s1n': 'Smart Beam Yard System',
'custom.s1a': 'SaaS platform and WeChat mini program',
'custom.s1b': 'Resettlement progress, bridge and production management',
'custom.s1c': 'Material management, multi-sensor data access',
'custom.s1d': 'Digital twin system',
'custom.s2n': 'Intelligent Simulation Platform',
'custom.s2a': 'Browser/server computing platform',
'custom.s2b': 'Structural mechanics simulation',
'custom.s2c': 'Thermal and fluid simulation',
'custom.s2d': 'AI-accelerated simulation',
'custom.s3n': 'Custom AI Agent Systems',
'custom.s3a': 'Multi-agent workflows',
'custom.s3b': 'AI agent optimization',
'custom.s3c': 'Features tailored to customer needs',
// 联系
'contact.motto1': 'Customer First,', 'contact.motto2': 'Innovation Driven',
'contact.sub': 'Scan the QR code, or email us about your digital upgrade needs.',
'contact.company': 'Suzhou Shashann Technology Co., Ltd.',
'contact.loc': 'R&D & Production Bases: Nanjing · Zhangjiagang · Changzhou',
// Footer
'footer.slogan': 'Powering digital transformation with AIoT',
'footer.name': 'Suzhou Shashann Technology Co., Ltd.',
'footer.motto': 'Customer First, Innovation Driven',
// 功能标签(跨产品复用)
'tag.geofence': 'Geofence Alarm', 'tag.find': 'Smart Find', 'tag.vitals': 'Vitals Monitoring',
'tag.wireless': 'Long Battery / Wireless Charging', 'tag.solar': 'Solar Powered', 'tag.voice': 'Voice Calling',
'tag.satellite': 'Satellite Comms', 'tag.herd': 'Smart Herding', 'tag.mesh': 'Mesh Networking',
'tag.lost': 'Loss Alarm', 'tag.led': 'LED Find', 'tag.connect1000': '1000+ Connections',
'tag.hiloc': 'Precision Tracking', 'tag.music': 'Music Playback', 'tag.bind': 'Tag Binding',
'tag.cluster': 'Cluster Alarm',
'tag.sensorx': 'Multi-sensor', 'tag.light': 'Smart Lighting', 'tag.water': 'Auto Water Circulation',
'tag.fert': 'Auto Fertilizing', 'tag.aimode': 'Unattended AI Mode', 'tag.lowpower': 'Ultra-low Power',
'tag.stick': 'Stick & Play', 'tag.rugged': 'Rugged', 'tag.cm': 'Centimeter Positioning',
'tag.fall': 'Fall Detection', 'tag.easy': 'Easy Install', 'tag.buzz': 'Buzzer Alarm'
};
var lang = localStorage.getItem('lang') || 'zh';
/* ---------- 语言切换 ---------- */
var nodes = Array.prototype.slice.call(document.querySelectorAll('[data-i18n]'));
// 首次加载时记录中文原文,供切回使用
nodes.forEach(function (el) { el.setAttribute('data-zh', el.textContent); });
function applyLang(l) {
lang = l;
localStorage.setItem('lang', l);
document.documentElement.lang = l === 'zh' ? 'zh-CN' : 'en';
nodes.forEach(function (el) {
var key = el.getAttribute('data-i18n');
var text = l === 'en' ? EN[key] : el.getAttribute('data-zh');
if (text != null) el.textContent = text;
});
document.getElementById('langToggle').textContent = l === 'zh' ? 'EN' : '中文';
document.title = l === 'zh'
? '苏州沙香科技有限公司 — AIoT 智能硬件与数字化平台'
: 'Suzhou Shashann Technology — AIoT Smart Hardware & Digital Platforms';
}
document.getElementById('langToggle').addEventListener('click', function () {
applyLang(lang === 'zh' ? 'en' : 'zh');
});
applyLang(lang);
/* ---------- 版权当前年份自动跨年(起始年 2023 写死在 HTML) ---------- */
document.getElementById('copyrightYear').textContent = String(new Date().getFullYear());
/* ---------- 导航滚动态 ---------- */
var header = document.getElementById('siteHeader');
function onScroll() { header.classList.toggle('scrolled', window.scrollY > 10); }
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
/* ---------- 移动端菜单 ---------- */
var menuToggle = document.getElementById('menuToggle');
var nav = document.getElementById('siteNav');
menuToggle.addEventListener('click', function () {
var open = nav.classList.toggle('open');
menuToggle.classList.toggle('open', open);
});
// 点击菜单项后自动收起
nav.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
nav.classList.remove('open');
menuToggle.classList.remove('open');
}
});
/* ---------- 多图卡滑动指示点 ---------- */
document.querySelectorAll('.slider').forEach(function (slider) {
var slides = slider.querySelector('.slides');
var figures = Array.prototype.slice.call(slides.querySelectorAll('figure'));
if (figures.length < 2) return; // 单图卡不需要指示点
var dots = document.createElement('div');
dots.className = 'dots';
var buttons = figures.map(function (_, i) {
var b = document.createElement('button');
b.type = 'button';
b.setAttribute('aria-label', 'Slide ' + (i + 1));
b.addEventListener('click', function () {
// 滚到第 i 张居中(配合 scroll-snap-type: x mandatory)
var f = figures[i];
slides.scrollTo({
left: f.offsetLeft - (slides.offsetWidth - f.offsetWidth) / 2,
behavior: 'smooth'
});
});
dots.appendChild(b);
return b;
});
slider.appendChild(dots);
// 初始把第一张居中(无动画;scroll-snap 保证落点合法)
slides.scrollLeft =
figures[0].offsetLeft - (slides.offsetWidth - figures[0].offsetWidth) / 2;
// 滚动时高亮离视口中心最近的图
function update() {
var center = slides.scrollLeft + slides.offsetWidth / 2;
var best = 0, bestDist = Infinity;
figures.forEach(function (f, i) {
var d = Math.abs(f.offsetLeft + f.offsetWidth / 2 - center);
if (d < bestDist) { bestDist = d; best = i; }
});
buttons.forEach(function (b, i) { b.classList.toggle('active', i === best); });
}
slides.addEventListener('scroll', function () {
window.requestAnimationFrame(update);
}, { passive: true });
update();
});
/* ---------- 滚动淡入 ---------- */
if ('IntersectionObserver' in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
io.unobserve(entry.target);
}
});
}, { threshold: 0.12 });
document.querySelectorAll('.reveal').forEach(function (el) { io.observe(el); });
} else {
document.querySelectorAll('.reveal').forEach(function (el) { el.classList.add('visible'); });
}
})();

368
index.html Normal file
View File

@@ -0,0 +1,368 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>苏州沙香科技有限公司 — AIoT 智能硬件与数字化平台</title>
<meta name="description" content="苏州沙香科技是用人工智能、边缘计算、云计算与低功耗物联网技术,为行业数字化升级提供智能硬件产品与软件服务平台的 AIoT 公司。业务覆盖数字畜牧、智慧种植、设备资产管理与定制软件系统开发。">
<meta property="og:title" content="苏州沙香科技有限公司 — AIoT 智能硬件与数字化平台">
<meta property="og:description" content="用 AIoT 驱动产业数字化升级:智能项圈、智能耳标、水培种植架、UWB 标签等自研硬件,与配套 SaaS 平台。">
<meta property="og:type" content="website">
<meta property="og:image" content="assets/img/hero-bg.webp">
<link rel="icon" type="image/png" sizes="180x180" href="assets/img/favicon.png">
<link rel="apple-touch-icon" href="assets/img/favicon.png">
<link rel="stylesheet" href="assets/css/style.css?v=202611021031">
</head>
<body>
<!-- ===================== 导航 ===================== -->
<header class="site-header" id="siteHeader">
<div class="container nav-wrap">
<a href="#top" class="brand">
<img src="assets/img/logo-light.webp" alt="苏州沙香科技" class="brand-logo">
</a>
<nav class="nav" id="siteNav">
<a href="#about" data-i18n="nav.about">关于沙香</a>
<a href="#grazing" data-i18n="nav.grazing">数字畜牧</a>
<a href="#planting" data-i18n="nav.planting">智慧种植</a>
<a href="#asset" data-i18n="nav.asset">设备资产</a>
<a href="#platform" data-i18n="nav.platform">软件平台</a>
<a href="#custom" data-i18n="nav.custom">定制开发</a>
<a href="#contact" class="nav-cta" data-i18n="nav.contact">联系我们</a>
</nav>
<button class="lang-toggle" id="langToggle" aria-label="Switch language">EN</button>
<button class="menu-toggle" id="menuToggle" aria-label="菜单"><span></span><span></span><span></span></button>
</div>
</header>
<main id="top">
<!-- ===================== Hero ===================== -->
<section class="hero">
<div class="aurora" aria-hidden="true"><i></i><i></i><i></i></div>
<div class="hero-grid" aria-hidden="true"></div>
<div class="container hero-inner">
<p class="hero-eyebrow" data-i18n="hero.eyebrow">苏州沙香科技有限公司 · AIoT</p>
<h1 class="hero-title"><span data-i18n="hero.title1">用 AIoT 驱动</span><br><span class="grad-text" data-i18n="hero.title2">产业数字化升级</span></h1>
<p class="hero-sub" data-i18n="hero.sub">人工智能 · 边缘计算 · 云计算 · 低功耗物联网——为各行业提供智能硬件产品与数字化应用软件服务平台,显著提升效率与生产力。</p>
<div class="hero-actions">
<a href="#grazing" class="btn btn-primary" data-i18n="hero.cta1">探索产品方案</a>
<a href="#contact" class="btn btn-ghost" data-i18n="hero.cta2">联系我们</a>
</div>
</div>
</section>
<!-- 技术词条跑马灯(纯英文装饰,呼应各板块 eyebrow) -->
<div class="marquee" aria-hidden="true">
<div class="marquee-track">
<span>AI</span><span>Edge Computing</span><span>Cloud</span><span>Low-Power IoT</span><span>Smart Hardware</span><span>SaaS Platform</span><span>Digital Twin</span><span>AI Agent</span>
<span>AI</span><span>Edge Computing</span><span>Cloud</span><span>Low-Power IoT</span><span>Smart Hardware</span><span>SaaS Platform</span><span>Digital Twin</span><span>AI Agent</span>
</div>
</div>
<!-- ===================== 关于 ===================== -->
<section id="about" class="section">
<div class="container">
<header class="section-head reveal">
<p class="eyebrow">ABOUT SHASHANN</p>
<h2 data-i18n="about.title">关于沙香</h2>
</header>
<div class="bento">
<div class="bento-text reveal">
<p data-i18n="about.p1">苏州沙香科技有限公司是一家 AIoT 科技公司,致力于用人工智能、边缘计算、云计算、低功耗物联网等技术,为各行业的数字化升级提供智能硬件产品和数字化改造等的应用软件服务平台,显著提升其效率及生产力,并能减少各类生产和管理成本。</p>
<p data-i18n="about.p2">在"一带一路"战略项目十周年庆祝活动中,自研的智能畜牧产品被评为"中国名片产品",并参与了大型纪录片《科技之光》第六集的拍摄。自研的其他智能硬件包括智能项圈、智能耳标、智能水培种植架、智能终端、智能资产标签等产品,已经广泛应用在智能放牧、智能种植、智能设备资产管理等多个领域。</p>
<p data-i18n="about.p3">公司核心团队有着丰富的 AIoT 相关技术经验,并与国内一流大学合作,不断进行技术创新。在南京、张家港、常州等地设有研发生产基地,部分产品远销海外。公司秉持"客户第一,创新驱动"的发展理念,努力成为行业领先、值得伙伴信赖的 AIoT 科技企业。</p>
</div>
<div class="bento-photo reveal">
<img src="assets/img/about-base.webp" alt="研发生产基地" loading="lazy">
</div>
<div class="bento-stat reveal"><strong data-i18n="about.stat1v">中国名片产品</strong><span data-i18n="about.stat1k">"一带一路"十周年评选</span></div>
<div class="bento-stat reveal"><strong data-i18n="about.stat2v">《科技之光》</strong><span data-i18n="about.stat2k">大型纪录片第六集拍摄</span></div>
<div class="bento-stat reveal"><strong data-i18n="about.stat3v">3 地基地</strong><span data-i18n="about.stat3k">南京 · 张家港 · 常州</span></div>
<div class="bento-stat reveal"><strong data-i18n="about.stat4v">远销海外</strong><span data-i18n="about.stat4k">多领域规模化应用</span></div>
</div>
</div>
</section>
<!-- ===================== 数字畜牧 ===================== -->
<section id="grazing" class="section section-alt">
<div class="container">
<header class="section-head reveal">
<p class="eyebrow">DIGITAL GRAZING</p>
<h2 data-i18n="grazing.title">数字畜牧</h2>
<p class="section-desc" data-i18n="grazing.desc">畜牧业地域分散、放养周期长,长期依赖人工巡查与经验管理。我们用智能项圈、耳标与蓝牙基站构建数字化放牧体系,让牲畜管理从"靠经验"走向"靠数据"。</p>
</header>
<div class="pain-grid reveal">
<div class="pain"><h4 data-i18n="grazing.pain1t">生产经营效率低</h4><p data-i18n="grazing.pain1d">每个牧民照看管理的牲畜数量有限。</p></div>
<div class="pain"><h4 data-i18n="grazing.pain2t">疫情等风险难预警</h4><p data-i18n="grazing.pain2d">牲畜分布广、流动性强,状态难监测,产业链溯源难。</p></div>
<div class="pain"><h4 data-i18n="grazing.pain3t">保险难理赔</h4><p data-i18n="grazing.pain3d">防疫、死亡、丢失等关键环节缺乏客观数据支撑。</p></div>
<div class="pain"><h4 data-i18n="grazing.pain4t">生态难以量化</h4><p data-i18n="grazing.pain4d">草原承载与生态变化难以评估,规模化经营难以闭环。</p></div>
</div>
<div class="product-grid">
<article class="card product reveal">
<div class="product-media"><img src="assets/img/collar-sg03-mini.webp" alt="智能项圈 SG03 mini" loading="lazy"></div>
<div class="product-body">
<h3 data-i18n="grazing.p1n">智能项圈 SG03 mini</h3>
<div class="tags">
<span data-i18n="tag.geofence">围栏报警</span><span data-i18n="tag.find">智能寻找</span><span data-i18n="tag.vitals">生理监测</span><span data-i18n="tag.wireless">长续航/无线充电</span>
</div>
</div>
</article>
<article class="card product reveal">
<div class="product-media"><img src="assets/img/collar-sg03.webp" alt="智能项圈 SG03" loading="lazy"></div>
<div class="product-body">
<h3 data-i18n="grazing.p2n">智能项圈 SG03</h3>
<div class="tags">
<span data-i18n="tag.solar">太阳能供电</span><span data-i18n="tag.voice">语音召唤</span><span data-i18n="tag.find">智能寻找</span><span data-i18n="tag.vitals">生理监测</span><span data-i18n="tag.satellite">卫星通信</span><span data-i18n="tag.herd">智能驱使</span><span data-i18n="tag.music">音乐播放</span>
</div>
</div>
</article>
<article class="card product reveal">
<div class="product-media"><img src="assets/img/ear-tag-st01.webp" alt="智能蓝牙耳标 ST01" loading="lazy"></div>
<div class="product-body">
<h3 data-i18n="grazing.p3n">智能蓝牙耳标 ST01</h3>
<div class="tags">
<span data-i18n="tag.mesh">集群组网</span><span data-i18n="tag.lost">丢失报警</span><span data-i18n="tag.led">亮灯寻找</span><span data-i18n="tag.vitals">生理监测</span>
</div>
</div>
</article>
<article class="card product reveal">
<div class="product-media"><img src="assets/img/base-station-bg01.webp" alt="智能蓝牙基站 BG01" loading="lazy"></div>
<div class="product-body">
<h3 data-i18n="grazing.p4n">智能蓝牙基站 BG01</h3>
<div class="tags">
<span data-i18n="tag.connect1000">超 1000 连接数</span><span data-i18n="tag.hiloc">高精定位</span><span data-i18n="tag.cluster">集群报警</span><span data-i18n="tag.bind">唯一绑定耳标</span>
</div>
</div>
</article>
</div>
</div>
</section>
<!-- ===================== 智慧种植 ===================== -->
<section id="planting" class="section">
<div class="container">
<header class="section-head reveal">
<p class="eyebrow">SMART PLANTING</p>
<h2 data-i18n="planting.title">智慧种植</h2>
<p class="section-desc" data-i18n="planting.desc">城市居民"在家种菜"的需求正在兴起,中小学劳动课与 AI 思维训练也需要更好的载体。智能水培方便、智能、干净——我们让它从"贵玩具"变成真正种得活、留得住的智能种植系统。</p>
</header>
<div class="pain-grid pain-grid-3 reveal">
<div class="pain"><h4 data-i18n="planting.pain1t">用户层面</h4><p data-i18n="planting.pain1d">种植小白失败率高,一次坏体验直接劝退复购。</p></div>
<div class="pain"><h4 data-i18n="planting.pain2t">产品层面</h4><p data-i18n="planting.pain2d">智能化是伪智能,耗材体系不成熟,厂商赚不到回头钱。</p></div>
<div class="pain"><h4 data-i18n="planting.pain3t">行业层面</h4><p data-i18n="planting.pain3d">品类认知停留在"贵玩具",没有品牌完成心智收割。</p></div>
</div>
<div class="feature-row reveal">
<div class="card product product-hero">
<div class="product-media"><img src="assets/img/hydroponics-hs01.webp" alt="智能水培种植架 HS01" class="framed" loading="lazy"></div>
<div class="product-body">
<h3 data-i18n="planting.p1n">智能水培种植架 HS01</h3>
<p class="product-note" data-i18n="planting.p1note">独立柜设计,方便扩展;支持无人 AI 种植模式与手动控制模式。</p>
<div class="tags">
<span data-i18n="tag.sensorx">多复合传感器</span><span data-i18n="tag.light">智能防日光补光</span><span data-i18n="tag.water">自动水循环</span><span data-i18n="tag.fert">自动施肥</span><span data-i18n="tag.aimode">无人 AI 种植</span>
</div>
</div>
</div>
<img src="assets/img/planting-scene.webp" alt="智慧种植典型场景" class="scene-side" loading="lazy">
</div>
</div>
</section>
<!-- ===================== 设备资产 ===================== -->
<section id="asset" class="section section-alt">
<div class="container">
<header class="section-head reveal">
<p class="eyebrow">DIGITAL ASSET MANAGEMENT</p>
<h2 data-i18n="asset.title">数字设备与资产管理</h2>
<p class="section-desc" data-i18n="asset.desc">企业资产体量大、分布广,传统人工台账与定期巡检难以为继。IoT 与 AI 让设备全生命周期管理成为可能,助力从"被动维修"升级为"预测性运维"。</p>
</header>
<div class="pain-grid reveal">
<div class="pain"><h4 data-i18n="asset.pain1t">现场不可视</h4><p data-i18n="asset.pain1d">资产家底不清,台账与实物长期对不上,盘点靠人跑。</p></div>
<div class="pain"><h4 data-i18n="asset.pain2t">过程不可追溯</h4><p data-i18n="asset.pain2d">缺乏数据留痕,质量问题难以定位。</p></div>
<div class="pain"><h4 data-i18n="asset.pain3t">系统割裂严重</h4><p data-i18n="asset.pain3d">多系统并存,数据不统一,难以支撑决策。</p></div>
<div class="pain"><h4 data-i18n="asset.pain4t">设备运维被动</h4><p data-i18n="asset.pain4d">事后维修为主,停机损失远大于维护成本。</p></div>
</div>
<div class="product-grid product-grid-3">
<article class="card product reveal">
<div class="product-media"><img src="assets/img/terminal-bb03.webp" alt="智能终端 BB03" loading="lazy"></div>
<div class="product-body">
<h3 data-i18n="asset.p1n">智能终端 BB03</h3>
<p class="product-note" data-i18n="asset.p1note">边缘计算算法精度高,准确识别设备/资产当前状态。</p>
<div class="tags">
<span data-i18n="tag.sensorx">多复合传感器</span><span data-i18n="tag.hiloc">高精定位</span><span data-i18n="tag.lowpower">超低功耗</span><span data-i18n="tag.stick">即粘即用</span><span data-i18n="tag.rugged">结实耐用</span>
</div>
</div>
</article>
<article class="card product reveal">
<div class="product-media"><img src="assets/img/uwb-tag-sl01.webp" alt="UWB 智能标签 SL01" loading="lazy"></div>
<div class="product-body">
<h3 data-i18n="asset.p2n">UWB 智能标签 SL01</h3>
<p class="product-note" data-i18n="asset.p2note">可配合安全帽使用,安装方便。</p>
<div class="tags">
<span data-i18n="tag.cm">厘米级定位</span><span data-i18n="tag.fall">跌落报警</span><span data-i18n="tag.lowpower">超低功耗</span><span data-i18n="tag.easy">安装方便</span>
</div>
</div>
</article>
<article class="card product reveal">
<div class="product-media"><img src="assets/img/bt-tag-st02.webp" alt="蓝牙智能标签 ST02" loading="lazy"></div>
<div class="product-body">
<h3 data-i18n="asset.p3n">蓝牙智能标签 ST02</h3>
<div class="tags">
<span data-i18n="tag.led">亮灯寻找</span><span data-i18n="tag.buzz">蜂鸣报警</span><span data-i18n="tag.lowpower">超低功耗</span><span data-i18n="tag.easy">安装方便</span>
</div>
</div>
</article>
</div>
</div>
</section>
<!-- ===================== 软件平台 ===================== -->
<section id="platform" class="section">
<div class="container">
<header class="section-head reveal">
<p class="eyebrow">SOFTWARE PLATFORM</p>
<h2 data-i18n="platform.title">产品配套软件平台</h2>
<p class="section-desc" data-i18n="platform.desc">每一类智能硬件,都有配套的 SaaS 平台、APP 与微信小程序,硬件数据直达云端,管理不受终端限制。</p>
</header>
<div class="platform-grid">
<article class="card platform reveal">
<div class="platform-media slider">
<div class="slides">
<figure><img src="assets/img/platform-grazing-1.webp" alt="智能放牧系统" class="shot-main" loading="lazy"></figure>
<figure><img src="assets/img/platform-grazing-app.webp" alt="智能放牧系统 APP" class="shot-phone" loading="lazy"></figure>
</div>
</div>
<div class="product-body">
<h3 data-i18n="platform.s1n">智能放牧系统</h3>
<ul class="feature-list">
<li data-i18n="platform.s1a">SaaS 平台、APP 与微信小程序</li>
<li data-i18n="platform.s1b">多账户牧场管理,高精定位与围栏报警</li>
<li data-i18n="platform.s1c">牲畜生理状态监测,语音召唤与音乐播放</li>
<li data-i18n="platform.s1d">智能硬件管理,全生命周期数据管理与溯源</li>
</ul>
</div>
</article>
<article class="card platform reveal">
<div class="platform-media slider">
<div class="slides">
<figure><img src="assets/img/platform-planting-1.webp" alt="智能水培种植系统" class="shot-main" loading="lazy"></figure>
<figure><img src="assets/img/platform-planting-2.webp" alt="智能水培种植系统" class="shot-main" loading="lazy"></figure>
</div>
</div>
<div class="product-body">
<h3 data-i18n="platform.s2n">智能水培种植系统</h3>
<ul class="feature-list">
<li data-i18n="platform.s2a">SaaS 平台与 APP</li>
<li data-i18n="platform.s2b">多账户种植管理,种植状态实时展示</li>
<li data-i18n="platform.s2c">自动种植调节系统</li>
<li data-i18n="platform.s2d">AI 智能助手</li>
</ul>
</div>
</article>
<article class="card platform reveal">
<div class="platform-media slider">
<div class="slides">
<figure><img src="assets/img/platform-asset-1.webp" alt="智能设备资产管理系统" class="shot-main" loading="lazy"></figure>
<figure><img src="assets/img/platform-asset-2.webp" alt="智能设备资产管理系统" class="shot-main" loading="lazy"></figure>
</div>
</div>
<div class="product-body">
<h3 data-i18n="platform.s3n">智能设备资产管理系统</h3>
<ul class="feature-list">
<li data-i18n="platform.s3a">SaaS 平台与微信小程序</li>
<li data-i18n="platform.s3b">多账户资产管理与维护管理</li>
<li data-i18n="platform.s3c">资产状态、位置等信息实时计算</li>
<li data-i18n="platform.s3d">根据历史数据精准预测与维护</li>
</ul>
</div>
</article>
</div>
</div>
</section>
<!-- ===================== 定制开发 ===================== -->
<section id="custom" class="section section-alt">
<div class="container">
<header class="section-head reveal">
<p class="eyebrow">CUSTOM DEVELOPMENT</p>
<h2 data-i18n="custom.title">定制软件系统开发</h2>
<p class="section-desc" data-i18n="custom.desc">基于核心团队的工程与仿真能力,面向行业客户提供定制化系统开发:从数字孪生到智能体工作流。</p>
</header>
<div class="platform-grid">
<article class="card platform reveal">
<div class="platform-media slider">
<div class="slides">
<figure><img src="assets/img/custom-liangchang-1.webp" alt="智慧梁场系统" class="shot-main" loading="lazy"></figure>
<figure><img src="assets/img/custom-liangchang-2.webp" alt="智慧梁场系统" class="shot-main" loading="lazy"></figure>
</div>
</div>
<div class="product-body">
<h3 data-i18n="custom.s1n">智慧梁场系统</h3>
<ul class="feature-list">
<li data-i18n="custom.s1a">SaaS 平台与微信小程序</li>
<li data-i18n="custom.s1b">征迁进度、桥梁管理与生产管理</li>
<li data-i18n="custom.s1c">物料管理,多传感器数据接入</li>
<li data-i18n="custom.s1d">数字孪生系统</li>
</ul>
</div>
</article>
<article class="card platform reveal">
<div class="platform-media">
<img src="assets/img/custom-simulation.webp" alt="智能仿真计算平台" class="shot-main shot-wide" loading="lazy">
</div>
<div class="product-body">
<h3 data-i18n="custom.s2n">智能仿真计算平台</h3>
<ul class="feature-list">
<li data-i18n="custom.s2a">BS 架构计算平台</li>
<li data-i18n="custom.s2b">力学仿真计算系统</li>
<li data-i18n="custom.s2c">热与流体仿真计算系统</li>
<li data-i18n="custom.s2d">AI 加速仿真计算系统</li>
</ul>
</div>
</article>
<article class="card platform reveal">
<div class="platform-media">
<img src="assets/img/custom-agent.webp" alt="智能体定制开发系统" class="shot-main shot-wide" loading="lazy">
</div>
<div class="product-body">
<h3 data-i18n="custom.s3n">智能体定制开发系统</h3>
<ul class="feature-list">
<li data-i18n="custom.s3a">多智能体工作流</li>
<li data-i18n="custom.s3b">AI 智能体优化</li>
<li data-i18n="custom.s3c">按客户需求定制功能</li>
</ul>
</div>
</article>
</div>
</div>
</section>
<!-- ===================== 联系 ===================== -->
<section id="contact" class="section contact">
<div class="container contact-inner reveal">
<p class="eyebrow">CONTACT US</p>
<h2 class="contact-title"><span data-i18n="contact.motto1">客户第一</span><span class="grad-text" data-i18n="contact.motto2">创新驱动</span></h2>
<p class="contact-sub" data-i18n="contact.sub">扫描二维码,或发邮件与我们聊聊您的数字化需求。</p>
<div class="contact-card">
<img src="assets/img/qrcode.webp" alt="联系二维码" class="qrcode">
<div class="contact-info">
<a class="contact-mail" href="mailto:contact@shashann.com">contact@shashann.com</a>
<p data-i18n="contact.company">苏州沙香科技有限公司</p>
<p data-i18n="contact.loc">研发生产基地:南京 · 张家港 · 常州</p>
</div>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="container footer-wrap">
<div class="footer-brand">
<img src="assets/img/logo-light.webp" alt="苏州沙香科技" class="brand-logo">
<span data-i18n="footer.slogan">用 AIoT 驱动产业数字化升级</span>
</div>
<p class="footer-copy">© 2023-<span id="copyrightYear">2026</span> <span data-i18n="footer.name">苏州沙香科技有限公司</span> · <span data-i18n="footer.motto">客户第一,创新驱动</span></p>
</div>
</footer>
<script src="assets/js/main.js?v=202611021031"></script>
</body>
</html>

25
tools/deploy.sh Normal file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
# 官网统一部署脚本:bump 静态资源版本号(击穿浏览器缓存)+ 同步双服务器
# 用法: bash tools/deploy.sh
set -euo pipefail
cd "$(dirname "$0")/.."
STAMP=$(date "+%Y%m%d%H%M")
# bump 资源版本参数:HTML 更新(no-cache)会带新 URL,旧缓存自然失效
python3 - "$STAMP" <<'PYEOF'
import re, sys
stamp = sys.argv[1]
path = 'index.html'
html = open(path, encoding='utf-8').read()
# 正则一次性规范化:无论已有无版本参数,统一替换为当前时间戳
html = re.sub(r'assets/css/style\.css(?:\?v=\d+)?\d*', 'assets/css/style.css?v=' + stamp, html)
html = re.sub(r'assets/js/main\.js(?:\?v=\d+)?\d*', 'assets/js/main.js?v=' + stamp, html)
open(path, 'w', encoding='utf-8').write(html)
PYEOF
echo "[deploy] 版本号 ${STAMP},同步公网 + 局域网"
# 注意:assets 不带尾斜杠(带斜杠会把目录拍平,曾导致整站 404)
rsync -a --delete index.html assets ubuntu3:/var/www/shashann-homepage/
rsync -a --delete index.html assets ubuntu:/home/ubuntu/homepage-site/
echo "[deploy] 完成: https://www.shashann.com/ 与 https://192.168.51.66/homepage/"

View File

@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
"""
生成 contact 公共邮箱头像:品牌深底 + 青→红渐变 @ 符号
视觉规范与官网一致(assets/css/style.css 的 --bg/--cyan/--brand)
用法: uv run --with pillow python3 tools/gen_contact_avatar.py
"""
from PIL import Image, ImageDraw, ImageFilter, ImageFont
SIZE = 512
BG = (7, 11, 22) # 官网 --bg-1
CYAN = (76, 195, 255) # 官网 --cyan
RED = (255, 61, 90) # 官网 --brand
OUT = 'assets/brand/contact-avatar.png'
# ---------- 背景:深底 + 左上青辉光 / 右下红辉光 ----------
bg = Image.new('RGB', (SIZE, SIZE), BG)
def glow_blob(box, blur):
blob = Image.new('L', (SIZE, SIZE), 0)
ImageDraw.Draw(blob).ellipse(box, fill=80)
return blob.filter(ImageFilter.GaussianBlur(blur))
bg.paste(Image.new('RGB', (SIZE, SIZE), CYAN), (0, 0), glow_blob((-220, -220, 240, 240), 100))
bg.paste(Image.new('RGB', (SIZE, SIZE), RED), (0, 0), glow_blob((SIZE - 240, SIZE - 240, SIZE + 220, SIZE + 220), 100))
# ---------- 对角渐变图(青 → 红),用作 @ 的填充色 ----------
c1, c2 = CYAN, RED
span = 2 * (SIZE - 1)
grad = Image.new('RGB', (SIZE, SIZE))
grad.putdata([
(
round(c1[0] + (c2[0] - c1[0]) * (x + y) / span),
round(c1[1] + (c2[1] - c1[1]) * (x + y) / span),
round(c1[2] + (c2[2] - c1[2]) * (x + y) / span),
)
for y in range(SIZE) for x in range(SIZE)
])
# ---------- 渲染 @ 文字 mask ----------
# macOS 西文字体按优先级找,@ 字形各字体差异不大
FONT_CANDIDATES = [
'/System/Library/Fonts/SFNS.ttf',
'/System/Library/Fonts/SFNSText.ttf',
'/System/Library/Fonts/Helvetica.ttc',
]
font_path = next((p for p in FONT_CANDIDATES if __import__('os').path.exists(p)), None)
if not font_path:
raise SystemExit('找不到可用系统字体: ' + ', '.join(FONT_CANDIDATES))
font = ImageFont.truetype(font_path, 400)
mask = Image.new('L', (SIZE, SIZE), 0)
ImageDraw.Draw(mask).text((SIZE // 2, SIZE // 2), '@', font=font, fill=255, anchor='mm')
# 自检:@ 必须真的渲染出来了,否则静默输出空底图
ink = sum(1 for v in mask.getdata() if v > 0)
ratio = ink / (SIZE * SIZE)
if not 0.05 < ratio < 0.45:
raise SystemExit(f'@ 渲染异常,墨迹占比 {ratio:.1%}(预期 5%~45%),检查字体 {font_path}')
bg.paste(grad, (0, 0), mask)
import os
os.makedirs(os.path.dirname(OUT), exist_ok=True)
bg.save(OUT, 'PNG', optimize=True)
print(f'完成: {OUT} {SIZE}x{SIZE} @{ratio:.0%} 字体={font_path}')

39
tools/make_favicon.py Normal file
View File

@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
"""
从反白 logo 提取左侧图形生成 favicon(180x180 PNG):
深色圆角底(与站内卡片底色一致)+ 图形居中占 72%
标签栏明暗模式均以深色块呈现,反白图形恒清晰。
用法: uv run --with pillow python3 tools/make_favicon.py
"""
from PIL import Image, ImageDraw
SRC = 'assets/img/logo-light.png'
OUT = 'assets/img/favicon.png'
SIZE = 180
PAD_GRAPHIC = 0.72 # 图形占画布比例
# logo 左侧图形实测内容段(x 投影分析):x[47:224] y[44:260],取 bbox 略收边
CROP = (47, 44, 224, 260)
BG = (7, 11, 22) # 站内 --bg-1
RADIUS = 38
graphic = Image.open(SRC).convert('RGBA').crop(CROP)
canvas = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
# 圆角深色底
mask = Image.new('L', (SIZE, SIZE), 0)
ImageDraw.Draw(mask).rounded_rectangle((0, 0, SIZE, SIZE), RADIUS, fill=255)
canvas.paste(Image.new('RGBA', (SIZE, SIZE), BG + (255,)), (0, 0), mask)
# 图形等比缩放到 72% 高度内居中
target = round(SIZE * PAD_GRAPHIC)
scale = min(target / graphic.width, target / graphic.height)
graphic = graphic.resize((round(graphic.width * scale), round(graphic.height * scale)), Image.LANCZOS)
canvas.alpha_composite(graphic, ((SIZE - graphic.width) // 2, (SIZE - graphic.height) // 2))
# 自检:中心应有不透明图形像素,四角透明
px = canvas.load()
assert px[SIZE // 2, SIZE // 2][3] > 0, '中心无图形'
assert px[2, 2][3] == 0 and px[SIZE - 3, SIZE - 3][3] == 0, '圆角未生效'
canvas.save(OUT, 'PNG', optimize=True)
print(f'完成: {OUT} {SIZE}x{SIZE},图形 {graphic.size}')

71
tools/make_logo_light.py Normal file
View File

@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
"""
生成深色站反白版 logo(logo-light.png):
1. flood-fill 镂空深蓝底(容差 84 = v1 验证成功参数,能吃掉 #000020 底色)
2. 不透明内容亮度反转 L' = 1 - L(黑字→白字,红/青/绿提亮,色相保留)
深色页黑字看不清、白底块又突兀,反白是深色站标准解法。
用法: uv run --with pillow python3 tools/make_logo_light.py
"""
import colorsys
from collections import deque
from PIL import Image
SRC = 'assets/img/logo.png'
OUT = 'assets/img/logo-light.png'
TOL = 84 # 曼哈顿距离容差(v1 实测:清除 83%、红色主体完整保留)
im = Image.open(SRC).convert('RGBA')
w, h = im.size
px = im.load()
# --- flood-fill 清底 ---
corners = [px[0, 0], px[w-1, 0], px[0, h-1], px[w-1, h-1]]
bg = tuple(sum(c[i] for c in corners) // 4 for i in range(3))
def is_bg(p):
if p[3] < 10:
return True
return abs(p[0]-bg[0]) + abs(p[1]-bg[1]) + abs(p[2]-bg[2]) <= TOL
seen = [[False]*w for _ in range(h)]
q = deque()
for x in range(w):
q.extend(((x, 0), (x, h-1)))
for y in range(h):
q.extend(((0, y), (w-1, y)))
cleared = 0
while q:
x, y = q.popleft()
if x < 0 or x >= w or y < 0 or y >= h or seen[y][x]:
continue
seen[y][x] = True
p = px[x, y]
if not is_bg(p):
continue
px[x, y] = (0, 0, 0, 0)
cleared += 1
q.extend(((x+1, y), (x-1, y), (x, y+1), (x, y-1)))
ratio = cleared / (w * h)
assert 0.10 < ratio < 0.92, f'镂空异常: 清除 {ratio:.0%}'
# --- 暗部提亮、亮部保留(logo 含 ~20% 浅色元素,全量反转会把它们变黑) ---
# L' = max(L, 1-L):暗像素翻到亮侧(黑→白),亮像素不动,色相全保留
opaque = [px[x, y] for y in range(h) for x in range(w) if px[x, y][3] > 128]
assert opaque, '镂空后内容为空'
for y in range(h):
for x in range(w):
r, g, b, a = px[x, y]
if a == 0:
continue
hh, ll, ss = colorsys.rgb_to_hls(r / 255, g / 255, b / 255)
r2, g2, b2 = colorsys.hls_to_rgb(hh, max(ll, 1 - ll), ss)
px[x, y] = (round(r2 * 255), round(g2 * 255), round(b2 * 255), a)
im.save(OUT, 'PNG', optimize=True)
# 验证:反白后所有不透明像素亮度下限
final = [px[x, y] for y in range(h) for x in range(w) if px[x, y][3] > 128]
dark = sum(1 for p in final if 0.299*p[0]+0.587*p[1]+0.114*p[2] < 90) / len(final)
print(f'完成: {OUT} 镂空 {ratio:.0%},暗部像素剩 {dark:.1%}(应为 0)')

119
tools/process_images.py Normal file
View File

@@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
"""
从 PPT 提取的原始素材生成网站用图:
1. logo 与 7 张黑底产品图:边缘 flood-fill 镂空(背景变透明,适配深色网页)
2. 水培架图背景复杂(39% 均匀度),不镂空,走统一描边容器展示
3. 截图/场景/照片转 WebP 压缩;二维码保持 PNG 无损
用法: uv run --with pillow python3 tools/process_images.py <pptx解压目录>/ppt/media <输出目录>
"""
import sys
from collections import deque
from pathlib import Path
from PIL import Image
src = Path(sys.argv[1])
out = Path(sys.argv[2])
out.mkdir(parents=True, exist_ok=True)
RENAME = {
'image2.png': 'logo.png', # 原样无损输出(见 PASS_THROUGH)
'image1.jpeg': 'hero-bg.webp', # v2 起不再做 hero 背景,仅作 og:image
'image3.png': 'about-main.webp', # v2 起弃用(PPT 拼贴图有白缝)
'image4.png': 'about-base.webp',
'image5.png': 'collar-sg03-mini.webp',
'image13.png': 'collar-sg03.webp',
'image10.png': 'ear-tag-st01.webp',
'image11.png': 'base-station-bg01.webp',
'image12.png': 'grazing-scene-1.webp',
'image18.png': 'grazing-scene-2.webp',
'image19.png': 'hydroponics-hs01.webp',
'image20.png': 'planting-scene.webp',
'image31.png': 'terminal-bb03.webp',
'image32.png': 'uwb-tag-sl01.webp',
'image33.png': 'bt-tag-st02.webp',
'image29.png': 'asset-scene-1.webp',
'image30.jpeg': 'asset-scene-2.webp',
'image34.png': 'platform-grazing-1.webp',
'image35.png': 'platform-grazing-app.webp',
'image36.png': 'platform-planting-1.webp',
'image37.png': 'platform-planting-2.webp',
'image38.png': 'platform-asset-1.webp',
'image39.png': 'platform-asset-2.webp',
'image40.png': 'custom-liangchang-1.webp',
'image41.png': 'custom-liangchang-2.webp',
'image42.png': 'custom-simulation.webp',
'image43.png': 'custom-agent.webp',
'image44.png': 'qrcode.png',
}
# 这些图做边缘 flood-fill 镂空(检测过:边缘色 96-100% 均匀的纯黑底)
# 注意:logo 不镂空——其底色 #000020 与四角检测色差超容差,v2 曾清成斑驳残留导致看不清
CUTOUT = {
'image5.png', 'image13.png', 'image10.png', 'image11.png',
'image31.png', 'image32.png', 'image33.png',
}
CUTOUT_TOL = 30 # 曼哈顿距离阈值,宁小勿大:黑底纯度高,产品暗部 (#20 系) 距离约 96 不会被误清
def cutout_bg(path: Path, tol: int) -> Image.Image:
"""从画布四边缘 flood-fill 清除均匀底色,只清与边缘连通的背景,不动被包围的内容"""
im = Image.open(path).convert('RGBA')
w, h = im.size
px = im.load()
corners = [px[0, 0], px[w-1, 0], px[0, h-1], px[w-1, h-1]]
bg = tuple(sum(c[i] for c in corners) // 4 for i in range(3))
def is_bg(p):
if p[3] < 10:
return True # 原本就是透明的像素直接视为背景
return abs(p[0]-bg[0]) + abs(p[1]-bg[1]) + abs(p[2]-bg[2]) <= tol
seen = [[False]*w for _ in range(h)]
q = deque()
for x in range(w):
q.extend(((x, 0), (x, h-1)))
for y in range(h):
q.extend(((0, y), (w-1, y)))
cleared = 0
while q:
x, y = q.popleft()
if x < 0 or x >= w or y < 0 or y >= h or seen[y][x]:
continue
seen[y][x] = True
p = px[x, y]
if not is_bg(p):
continue
px[x, y] = (0, 0, 0, 0)
cleared += 1
q.extend(((x+1, y), (x-1, y), (x, y+1), (x, y-1)))
ratio = cleared / (w * h)
# 镂空比例健全性检查:太低=没清干净,太高=误伤内容
if not 0.10 < ratio < 0.92:
raise SystemExit(f'镂空异常 {path.name}: 清除 {ratio:.0%},需人工检查')
return im
# 原样无损拷贝:logo 色块文字经不起有损压缩,二维码必须无损
PASS_THROUGH = {'image2.png', 'image44.png'}
for src_name, dst_name in RENAME.items():
src_path = src / src_name
if not src_path.exists():
print(f' 跳过缺失: {src_name}')
continue
dst_path = out / dst_name
if src_name in PASS_THROUGH:
Image.open(src_path).save(dst_path)
elif src_name in CUTOUT:
im = cutout_bg(src_path, CUTOUT_TOL)
# 镂空图必须带 alpha,webp 无损存 alpha(有损会弄脏半透明边缘)
im.save(dst_path, 'WEBP', quality=100, lossless=True, method=6)
else:
im = Image.open(src_path).convert('RGB')
if im.width > 1600:
im = im.resize((1600, round(im.height * 1600 / im.width)), Image.LANCZOS)
im.save(dst_path, 'WEBP', quality=82, method=6)
kb = dst_path.stat().st_size // 1024
tag = ' [镂空]' if src_name in CUTOUT else ''
print(f' {src_name:14s} -> {dst_name:28s} {kb}KB{tag}')
print(f'完成,共 {len(RENAME)} 张 -> {out}')

View File

@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
"""
处理用户补充的新素材(assets/img 内):
- 7 张透明底产品图 p-*:无损 WebP 保留 alpha(已是镂空,无需再处理)
- p-hs01 背景复杂不透明:有损压缩(页面走 framed 描边容器)
- 12 张照片 JPG:有损 WebP(宽度 >1600 的缩到 1600)
- qr-wechat.png 二维码:不处理,HTML 直接引用原 PNG
原图不删除(用户提供的源文件)。用法: uv run --with pillow python3 tools/process_new_assets.py
"""
from pathlib import Path
from PIL import Image
IMG = Path('assets/img')
# 已检测为真透明的产品图(透明像素 37%~88%)
ALPHA_PRODUCTS = [
'p-bb03.png', 'p-bg01.png', 'p-sg03.png', 'p-sg03mini.png',
'p-sl01.png', 'p-st01.png', 'p-st02.png',
]
# 有损压缩的照片/截图
PHOTOS = [
'p-hs01.png', # 背景复杂不透明,同照片处理
'ai-agent.jpg', 'app-livestock.jpg', 'building.jpg', 'cctv.jpg',
'digital-twin.jpg', 'factory-line.jpg', 'factory.jpg', 'goat.jpg',
'hero-grazing.jpg', 'hydro-class.jpg', 'liangchang.jpg',
'machine-install.jpg', 'platform-asset.jpg', 'platform-hydro.jpg',
'platform-pasture.jpg',
]
for name in ALPHA_PRODUCTS:
src = IMG / name
dst = IMG / (name[:-4] + '.webp')
im = Image.open(src).convert('RGBA')
# 自检:透明像素占比必须显著,否则说明误判为透明图
trans = sum(1 for p in im.getdata() if p[3] < 250) / (im.width * im.height)
assert trans > 0.2, f'{name} 透明像素仅 {trans:.0%},不符合透明底预期'
im.save(dst, 'WEBP', lossless=True, method=6)
print(f'{name:18s} -> {dst.name:22s} 透明{trans:.0%} {dst.stat().st_size // 1024}KB')
for name in PHOTOS:
src = IMG / name
dst = IMG / (name[:-4] + '.webp')
im = Image.open(src).convert('RGB')
if im.width > 1600:
im = im.resize((1600, round(im.height * 1600 / im.width)), Image.LANCZOS)
im.save(dst, 'WEBP', quality=82, method=6)
print(f'{name:18s} -> {dst.name:22s} {im.width}x{im.height} {dst.stat().st_size // 1024}KB')
print('完成')