Files
hms/docs/design/miniprogram/design-system.html
iven 1265935fa3 chore: 设计规格文档 + 销售数据 + 脚本工具 + 根目录 monorepo 配置
- docs/: 设计规格、讨论记录、销售数据、健康管理文档
- scripts/: 辅助脚本
- package.json + pnpm-lock.yaml: monorepo 根配置
2026-04-28 00:20:37 +08:00

318 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HMS 设计系统 · 温润东方风</title>
<script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, 'PingFang SC', 'Helvetica Neue', sans-serif; background: #F5F0EB; color: #2D2A26; line-height: 1.6; }
:root {
--bg: #F5F0EB;
--surface: #FFFFFF;
--surface-alt: #EDE8E2;
--text-primary: #2D2A26;
--text-secondary: #7A756E;
--text-tertiary: #A8A29E;
--accent: #C4623A;
--accent-light: #F0DDD4;
--accent-dark: #8B3E1F;
--success: #5B7A5E;
--success-light: #E8F0E8;
--warning: #C4873A;
--warning-light: #FFF3E0;
--danger: #B54A4A;
--danger-light: #FDEAEA;
--border: #E8E2DC;
--border-light: #F0EBE5;
--shadow: 0 1px 4px rgba(45,42,38,0.06);
--shadow-md: 0 4px 16px rgba(45,42,38,0.08);
--radius: 12px;
--radius-sm: 8px;
--radius-lg: 16px;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const dsStyles = {
page: { maxWidth: 1200, margin: '0 auto', padding: '60px 40px' },
title: { fontFamily: '"Noto Serif SC", serif', fontSize: 36, fontWeight: 700, color: '#2D2A26', marginBottom: 8 },
subtitle: { fontSize: 16, color: '#7A756E', marginBottom: 48, letterSpacing: '0.02em' },
section: { marginBottom: 56 },
sectionTitle: { fontFamily: '"Noto Serif SC", serif', fontSize: 22, fontWeight: 600, color: '#2D2A26', marginBottom: 24, paddingBottom: 12, borderBottom: '1px solid #E8E2DC' },
row: { display: 'flex', gap: 16, flexWrap: 'wrap', marginBottom: 16 },
card: { background: '#fff', borderRadius: 12, padding: 24, boxShadow: '0 1px 4px rgba(45,42,38,0.06)' },
};
/* ─── 色彩系统 ─── */
const ColorSwatch = ({ name, hex, desc, light }) => (
<div style={{ flex: '0 0 160px' }}>
<div style={{
height: 80, borderRadius: 12, background: hex,
border: light ? '1px solid #E8E2DC' : 'none',
marginBottom: 8, boxShadow: hex === '#FFFFFF' ? '0 1px 4px rgba(0,0,0,0.08)' : 'none',
}} />
<div style={{ fontSize: 13, fontWeight: 600, color: '#2D2A26' }}>{name}</div>
<div style={{ fontSize: 12, color: '#7A756E', fontFamily: 'monospace' }}>{hex}</div>
{desc && <div style={{ fontSize: 11, color: '#A8A29E', marginTop: 2 }}>{desc}</div>}
</div>
);
const ColorSection = () => {
const colors = [
{ name: '背景', hex: '#F5F0EB', desc: 'warm cream', light: true },
{ name: '卡片', hex: '#FFFFFF', desc: 'surface', light: true },
{ name: '辅助底', hex: '#EDE8E2', desc: 'surface-alt', light: true },
{ name: '主文字', hex: '#2D2A26', desc: 'warm black' },
{ name: '次文字', hex: '#7A756E', desc: 'warm gray' },
{ name: '淡文字', hex: '#A8A29E', desc: 'tertiary' },
{ name: '边框', hex: '#E8E2DC', desc: 'border', light: true },
];
const accent = [
{ name: '强调色', hex: '#C4623A', desc: 'terracotta' },
{ name: '强调浅', hex: '#F0DDD4', desc: 'accent-light', light: true },
{ name: '强调深', hex: '#8B3E1F', desc: 'accent-dark' },
];
const status = [
{ name: '成功', hex: '#5B7A5E', desc: 'sage green' },
{ name: '警告', hex: '#C4873A', desc: 'warm amber' },
{ name: '危险', hex: '#B54A4A', desc: 'muted red' },
{ name: '成功浅', hex: '#E8F0E8', desc: 'success-light', light: true },
{ name: '警告浅', hex: '#FFF3E0', desc: 'warning-light', light: true },
{ name: '危险浅', hex: '#FDEAEA', desc: 'danger-light', light: true },
];
return (
<div style={dsStyles.section}>
<div style={dsStyles.sectionTitle}>色彩</div>
<div style={{ fontSize: 13, color: '#7A756E', marginBottom: 16 }}>
温润米底 + 赤土橙贯穿全场单一 accent 不多色色值从 oklch 定义保证和谐
</div>
<div style={dsStyles.row}>
{colors.map(c => <ColorSwatch key={c.hex} {...c} />)}
</div>
<div style={{ fontSize: 14, fontWeight: 600, color: '#2D2A26', margin: '20px 0 12px' }}>强调色</div>
<div style={dsStyles.row}>
{accent.map(c => <ColorSwatch key={c.hex} {...c} />)}
</div>
<div style={{ fontSize: 14, fontWeight: 600, color: '#2D2A26', margin: '20px 0 12px' }}>状态色</div>
<div style={dsStyles.row}>
{status.map(c => <ColorSwatch key={c.hex} {...c} />)}
</div>
</div>
);
};
/* ─── 字体系统 ─── */
const TypographySection = () => {
const sizes = [
{ name: '大标题', style: { fontFamily: '"Noto Serif SC", serif', fontSize: 28, fontWeight: 700 } },
{ name: '标题', style: { fontFamily: '"Noto Serif SC", serif', fontSize: 22, fontWeight: 600 } },
{ name: '小标题', style: { fontFamily: '"Noto Serif SC", serif', fontSize: 17, fontWeight: 600 } },
{ name: '正文', style: { fontFamily: '-apple-system, "PingFang SC", sans-serif', fontSize: 15, fontWeight: 400 } },
{ name: '辅助文字', style: { fontFamily: '-apple-system, "PingFang SC", sans-serif', fontSize: 13, fontWeight: 400, color: '#7A756E' } },
{ name: '数据大号', style: { fontFamily: '"Noto Serif SC", serif', fontSize: 36, fontWeight: 700, color: '#C4623A' } },
{ name: '数据中号', style: { fontFamily: '"Noto Serif SC", serif', fontSize: 24, fontWeight: 600 } },
{ name: '数据单位', style: { fontFamily: '-apple-system, "PingFang SC", sans-serif', fontSize: 13, fontWeight: 400, color: '#A8A29E' } },
];
return (
<div style={dsStyles.section}>
<div style={dsStyles.sectionTitle}>字体</div>
<div style={{ fontSize: 13, color: '#7A756E', marginBottom: 20 }}>
衬线 display (Noto Serif SC) 用于标题和数据数字系统无衬线用于正文字重对比鲜明
</div>
<div style={{ background: '#fff', borderRadius: 12, padding: 28, boxShadow: '0 1px 4px rgba(45,42,38,0.06)' }}>
{sizes.map(s => (
<div key={s.name} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '12px 0', borderBottom: '1px solid #F0EBE5' }}>
<div style={s.style}>{s.name}</div>
<div style={{ fontSize: 12, color: '#A8A29E', fontFamily: 'monospace' }}>
{s.style.fontSize}px / {s.style.fontWeight} {s.style.fontFamily?.includes('Serif') ? '· serif' : '· sans'}
</div>
</div>
))}
</div>
</div>
);
};
/* ─── 间距与圆角 ─── */
const SpacingSection = () => {
const spacings = [4, 8, 12, 16, 20, 24, 32, 40, 48];
const radii = [
{ name: 'sm', value: 8 },
{ name: 'md', value: 12 },
{ name: 'lg', value: 16 },
{ name: 'xl', value: 20 },
{ name: 'pill', value: 999 },
];
return (
<div style={dsStyles.section}>
<div style={dsStyles.sectionTitle}>间距与圆角</div>
<div style={{ display: 'flex', gap: 32, flexWrap: 'wrap' }}>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 13, color: '#7A756E', marginBottom: 12 }}>间距基准 4px</div>
<div style={{ display: 'flex', alignItems: 'flex-end', gap: 8 }}>
{spacings.map(s => (
<div key={s} style={{ textAlign: 'center' }}>
<div style={{ width: s, height: s, background: '#C4623A', borderRadius: 2, opacity: 0.6 }} />
<div style={{ fontSize: 10, color: '#A8A29E', marginTop: 4 }}>{s}</div>
</div>
))}
</div>
</div>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 13, color: '#7A756E', marginBottom: 12 }}>圆角</div>
<div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
{radii.map(r => (
<div key={r.name} style={{ textAlign: 'center' }}>
<div style={{ width: 48, height: 48, border: '2px solid #C4623A', borderRadius: r.value === 999 ? 24 : r.value }} />
<div style={{ fontSize: 10, color: '#A8A29E', marginTop: 4 }}>{r.name} ({r.value})</div>
</div>
))}
</div>
</div>
</div>
</div>
);
};
/* ─── 组件库 ─── */
const ComponentSection = () => {
const buttonStyles = {
row: { display: 'flex', gap: 12, alignItems: 'center', marginBottom: 16, flexWrap: 'wrap' },
primary: { padding: '10px 28px', background: '#C4623A', color: '#fff', border: 'none', borderRadius: 12, fontSize: 15, fontWeight: 600, cursor: 'pointer' },
secondary: { padding: '10px 28px', background: 'transparent', color: '#C4623A', border: '1.5px solid #C4623A', borderRadius: 12, fontSize: 15, fontWeight: 600, cursor: 'pointer' },
ghost: { padding: '10px 28px', background: 'transparent', color: '#7A756E', border: '1.5px solid #E8E2DC', borderRadius: 12, fontSize: 15, fontWeight: 500, cursor: 'pointer' },
disabled: { padding: '10px 28px', background: '#EDE8E2', color: '#A8A29E', border: 'none', borderRadius: 12, fontSize: 15, fontWeight: 500 },
small: { padding: '6px 16px', background: '#C4623A', color: '#fff', border: 'none', borderRadius: 8, fontSize: 13, fontWeight: 600 },
};
const tagStyles = {
success: { display: 'inline-block', padding: '3px 10px', borderRadius: 6, fontSize: 12, fontWeight: 500, background: '#E8F0E8', color: '#5B7A5E' },
warning: { display: 'inline-block', padding: '3px 10px', borderRadius: 6, fontSize: 12, fontWeight: 500, background: '#FFF3E0', color: '#C4873A' },
danger: { display: 'inline-block', padding: '3px 10px', borderRadius: 6, fontSize: 12, fontWeight: 500, background: '#FDEAEA', color: '#B54A4A' },
default: { display: 'inline-block', padding: '3px 10px', borderRadius: 6, fontSize: 12, fontWeight: 500, background: '#F0EBE5', color: '#7A756E' },
};
return (
<div style={dsStyles.section}>
<div style={dsStyles.sectionTitle}>组件</div>
<div style={{ display: 'flex', gap: 24, flexDirection: 'column' }}>
{/* 按钮 */}
<div style={dsStyles.card}>
<div style={{ fontSize: 13, fontWeight: 600, color: '#2D2A26', marginBottom: 12 }}>按钮</div>
<div style={buttonStyles.row}>
<button style={buttonStyles.primary}>主要操作</button>
<button style={buttonStyles.secondary}>次要操作</button>
<button style={buttonStyles.ghost}>取消</button>
<button style={buttonStyles.disabled}>禁用</button>
<button style={buttonStyles.small}>小按钮</button>
</div>
</div>
{/* 标签 */}
<div style={dsStyles.card}>
<div style={{ fontSize: 13, fontWeight: 600, color: '#2D2A26', marginBottom: 12 }}>状态标签</div>
<div style={{ display: 'flex', gap: 8 }}>
<span style={tagStyles.success}>正常</span>
<span style={tagStyles.warning}>偏高</span>
<span style={tagStyles.danger}>异常</span>
<span style={tagStyles.default}>待处理</span>
</div>
</div>
{/* 数据卡片 */}
<div style={dsStyles.card}>
<div style={{ fontSize: 13, fontWeight: 600, color: '#2D2A26', marginBottom: 12 }}>健康数据卡片</div>
<div style={{ display: 'flex', gap: 12 }}>
{[
{ label: '血压', value: '120/80', unit: 'mmHg', status: '正常', statusType: 'success' },
{ label: '心率', value: '72', unit: 'bpm', status: '正常', statusType: 'success' },
{ label: '血糖', value: '6.8', unit: 'mmol/L', status: '偏高', statusType: 'warning' },
].map(item => (
<div key={item.label} style={{ flex: 1, background: '#F5F0EB', borderRadius: 12, padding: 16, textAlign: 'center' }}>
<div style={{ fontSize: 13, color: '#7A756E', marginBottom: 8 }}>{item.label}</div>
<div style={{ fontFamily: '"Noto Serif SC", serif', fontSize: 28, fontWeight: 700, color: '#2D2A26' }}>{item.value}</div>
<div style={{ fontSize: 12, color: '#A8A29E', margin: '4px 0 8px' }}>{item.unit}</div>
<span style={tagStyles[item.statusType]}>{item.status}</span>
</div>
))}
</div>
</div>
{/* 列表项 */}
<div style={dsStyles.card}>
<div style={{ fontSize: 13, fontWeight: 600, color: '#2D2A26', marginBottom: 12 }}>列表项</div>
<div style={{ borderRadius: 12, border: '1px solid #E8E2DC', overflow: 'hidden' }}>
{[
{ title: '预约2026-04-28 上午', sub: '王医生 · 心内科 · 待确认' },
{ title: '随访:血压监测', sub: '每日记录血压数据 · 截止 05-01' },
{ title: '报告:血常规检验', sub: '2026-04-25 · 已出结果' },
].map((item, i) => (
<div key={i} style={{
display: 'flex', alignItems: 'center', padding: '16px 20px',
borderBottom: i < 2 ? '1px solid #F0EBE5' : 'none',
}}>
<div style={{ flex: 1 }}>
<div style={{ fontSize: 15, fontWeight: 500, color: '#2D2A26', marginBottom: 2 }}>{item.title}</div>
<div style={{ fontSize: 13, color: '#7A756E' }}>{item.sub}</div>
</div>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" style={{ color: '#A8A29E', flexShrink: 0 }}>
<path d="M6 4l4 4-4 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</div>
))}
</div>
</div>
{/* 图标风格 */}
<div style={dsStyles.card}>
<div style={{ fontSize: 13, fontWeight: 600, color: '#2D2A26', marginBottom: 12 }}>图标风格 · 线性 1.5px</div>
<div style={{ display: 'flex', gap: 24 }}>
{[
{ label: '首页', path: 'M8 2l6 5v7a1 1 0 01-1 1H3a1 1 0 01-1-1V7l6-5z' },
{ label: '心率', path: 'M2 8h3l2-4 3 8 2-4h2' },
{ label: '预约', path: 'M3 4h10v9a1 1 0 01-1 1H4a1 1 0 01-1-1V4zM3 4V2M13 4V2M6 7h4M6 10h2' },
{ label: '消息', path: 'M2 4a1 1 0 011-1h10a1 1 0 011 1v6a1 1 0 01-1 1H5l-3 3V4z' },
{ label: '我的', path: 'M8 8a3 3 0 100-6 3 3 0 000 6zM3 14a5 5 0 0110 0' },
].map(ico => (
<div key={ico.label} style={{ textAlign: 'center' }}>
<svg width="24" height="24" viewBox="0 0 16 16" fill="none" stroke="#7A756E" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d={ico.path} />
</svg>
<div style={{ fontSize: 11, color: '#A8A29E', marginTop: 4 }}>{ico.label}</div>
</div>
))}
</div>
</div>
</div>
</div>
);
};
/* ─── 渲染 ─── */
const App = () => (
<div style={dsStyles.page}>
<div style={dsStyles.title}>HMS 健康管理 · 设计系统</div>
<div style={dsStyles.subtitle}>温润东方风 Kenya Hara 式克制留白 · 赤土橙 #C4623A 贯穿全场</div>
<ColorSection />
<TypographySection />
<SpacingSection />
<ComponentSection />
</div>
);
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>