Files
hms/docs/design/mp-09-profile-other.html
iven aa27c5174c docs(mp): 新增小程序全页面 HTML 原型 + UI 优化指南
- 新增 12 个核心页面原型(登录/首页/咨询/预约/商城/健康等)
- 新增医生端分包原型(核心 + 临床两个分包)
- 新增 AI 客服对话页原型
- 新增 MP UI 优化指南文档
- 更新 wiki 基础设施和小程序文档
2026-05-17 00:51:07 +08:00

481 lines
29 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"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #1a1a1a; font-family: -apple-system, 'PingFang SC', sans-serif; display: flex; flex-direction: column; align-items: center; padding: 40px 20px; gap: 24px; }
.page-title { color: #999; font-size: 13px; letter-spacing: 0.15em; text-transform: uppercase; }
.note { color: #666; font-size: 12px; max-width: 900px; text-align: center; line-height: 1.8; }
.screens { display: flex; gap: 40px; flex-wrap: wrap; justify-content: center; align-items: flex-start; }
.screen-wrap { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.screen-label { color: #888; font-size: 12px; font-style: italic; }
</style>
</head>
<body>
<div class="page-title">HMS 小程序 · 个人中心其他页面</div>
<div class="note">温润东方风设计系统 — 个人中心子页面原型。6 个屏幕:家庭管理 / 添加家庭成员 / 知情同意 / 事件记录 / 长者模式 / 设置。</div>
<div id="root"></div>
<script type="text/babel">
// ─── 设计 Token ───
const T = {
pri: '#C4623A', priL: '#F0DDD4', priD: '#8B3E1F',
bg: '#F5F0EB', card: '#FFFFFF', surface: '#EDE8E2',
tx: '#2D2A26', tx2: '#5A554F', tx3: '#78716C',
bd: '#E8E2DC', bdL: '#F0EBE5',
acc: '#5B7A5E', accL: '#E8F0E8',
wrn: '#C4873A', wrnL: '#FFF3E0',
dan: '#B54A4A', danL: '#FDEAEA',
serif: "Georgia, 'Times New Roman', serif",
sans: "-apple-system, 'PingFang SC', sans-serif",
r: 16, rSm: 12, rXs: 8,
};
// ─── iOS 设备框 ───
const iosFrameStyles = {
wrapper: { display: 'inline-block', padding: 12, background: '#000', borderRadius: 60, boxShadow: '0 0 0 2px #1f2937, 0 20px 60px rgba(0,0,0,0.3)', position: 'relative' },
screen: { position: 'relative', borderRadius: 48, overflow: 'hidden', background: '#fff' },
statusBar: { position: 'absolute', top: 0, left: 0, right: 0, height: 54, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 32px', fontSize: 16, fontWeight: 600, fontFamily: '-apple-system, "SF Pro Text", sans-serif', zIndex: 20, pointerEvents: 'none' },
dynamicIsland: { position: 'absolute', top: 12, left: '50%', transform: 'translateX(-50%)', width: 124, height: 36, background: '#000', borderRadius: 999, zIndex: 30 },
content: { position: 'absolute', top: 54, left: 0, right: 0, bottom: 34, overflow: 'auto' },
homeIndicator: { position: 'absolute', bottom: 10, left: '50%', transform: 'translateX(-50%)', width: 140, height: 5, background: 'rgba(0,0,0,0.3)', borderRadius: 999, zIndex: 10 },
};
function IosFrame({ children, width = 340, height = 740, time = '9:41', battery = 85, darkStatus = false }) {
const statusColor = darkStatus ? '#fff' : '#000';
return (
<div style={iosFrameStyles.wrapper}>
<div style={{ ...iosFrameStyles.screen, width, height }}>
<div style={{ ...iosFrameStyles.statusBar, color: statusColor }}>
<span>{time}</span>
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<svg width="16" height="12" viewBox="0 0 16 12" fill="none"><path d="M8 11.5a1 1 0 100-2 1 1 0 000 2z" fill={statusColor}/><path d="M3 7.5a7 7 0 0110 0" stroke={statusColor} strokeWidth="1.3" fill="none" strokeLinecap="round"/><path d="M1 4.5a11 11 0 0114 0" stroke={statusColor} strokeWidth="1.3" fill="none" strokeLinecap="round" opacity="0.7"/></svg>
<div style={{ width: 26, height: 12, border: `1.5px solid ${statusColor}`, borderRadius: 3, padding: 1, position: 'relative' }}>
<div style={{ width: `${battery}%`, height: '100%', background: statusColor, borderRadius: 1 }} />
</div>
</div>
</div>
<div style={iosFrameStyles.dynamicIsland} />
<div style={iosFrameStyles.content}>{children}</div>
<div style={iosFrameStyles.homeIndicator} />
</div>
</div>
);
}
// ─── 导航栏组件 ───
function NavBar({ title, dark = false }) {
const color = dark ? '#fff' : T.tx;
return (
<div style={{ height: 44, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', borderBottom: `1px solid ${T.bdL}`, background: dark ? 'transparent' : T.card }}>
<svg style={{ position: 'absolute', left: 16, top: 12 }} width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
<span style={{ fontFamily: T.serif, fontSize: 17, fontWeight: 700, color }}>{title}</span>
</div>
);
}
// ─── 右箭头图标 ───
function ArrowRight({ color = T.tx3 }) {
return <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"/></svg>;
}
// ─── 开关组件 ───
function Toggle({ on = false, color = T.pri }) {
return (
<div style={{ width: 48, height: 28, borderRadius: 14, background: on ? color : '#D1D5DB', position: 'relative', transition: 'background 0.2s', flexShrink: 0 }}>
<div style={{ width: 24, height: 24, borderRadius: 12, background: '#fff', position: 'absolute', top: 2, left: on ? 22 : 2, boxShadow: '0 1px 3px rgba(0,0,0,0.15)', transition: 'left 0.2s' }} />
</div>
);
}
// ═══════════════════════════════════════════════════════════════
// 屏幕1家庭管理
// ═══════════════════════════════════════════════════════════════
function FamilyPage() {
const patients = [
{ name: '张三', relation: '本人', phone: '138****1234', isDefault: true, color: T.pri },
{ name: '张父', relation: '父亲', phone: '139****5678', isDefault: false, color: T.acc },
{ name: '张母', relation: '母亲', phone: '136****9012', isDefault: false, color: T.wrn },
];
return (
<div style={{ background: T.bg, minHeight: '100%', fontFamily: T.sans }}>
<NavBar title="就诊人管理" />
<div style={{ padding: '16px' }}>
{patients.map((p, i) => (
<div key={i} style={{ background: T.card, borderRadius: T.r, padding: 16, marginBottom: 12, boxShadow: '0 1px 4px rgba(0,0,0,0.04)', display: 'flex', alignItems: 'center', gap: 12 }}>
{/* 头像 */}
<div style={{ width: 48, height: 48, borderRadius: 24, background: p.isDefault ? T.priL : T.surface, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<span style={{ fontSize: 18, fontWeight: 700, color: p.isDefault ? T.priD : T.tx2, fontFamily: T.serif }}>{p.name[0]}</span>
</div>
{/* 信息 */}
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
<span style={{ fontSize: 16, fontWeight: 600, color: T.tx }}>{p.name}</span>
<span style={{ fontSize: 12, color: T.tx3, background: T.surface, padding: '2px 8px', borderRadius: 6 }}>{p.relation}</span>
{p.isDefault && (
<span style={{ fontSize: 11, color: T.priD, background: T.priL, padding: '2px 8px', borderRadius: 6, fontWeight: 600 }}>默认</span>
)}
</div>
<span style={{ fontSize: 13, color: T.tx3 }}>{p.phone}</span>
</div>
{/* 箭头 */}
<ArrowRight />
</div>
))}
{/* 添加就诊人按钮 */}
<div style={{ border: `2px dashed ${T.bd}`, borderRadius: T.r, padding: '16px 0', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, marginTop: 4, cursor: 'pointer' }}>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={T.pri} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
<span style={{ fontSize: 15, color: T.pri, fontWeight: 500 }}>添加就诊人</span>
</div>
</div>
</div>
);
}
// ═══════════════════════════════════════════════════════════════
// 屏幕2添加家庭成员
// ═══════════════════════════════════════════════════════════════
function FamilyAddPage() {
const FieldStyle = { width: '100%', height: 56, background: T.card, border: `1.5px solid ${T.bd}`, borderRadius: T.r, padding: '0 16px', fontSize: 15, color: T.tx, outline: 'none', fontFamily: T.sans };
return (
<div style={{ background: T.bg, minHeight: '100%', fontFamily: T.sans }}>
<NavBar title="添加就诊人" />
<div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 14 }}>
{/* 姓名 */}
<div>
<label style={{ display: 'block', fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>姓名</label>
<input style={FieldStyle} placeholder="请输入真实姓名" />
</div>
{/* 关系 */}
<div>
<label style={{ display: 'block', fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>关系</label>
<div style={{ ...FieldStyle, display: 'flex', alignItems: 'center', justifyContent: 'space-between', color: T.tx3 }}>
<span>请选择关系</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={T.tx3} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
</div>
</div>
{/* 手机号 */}
<div>
<label style={{ display: 'block', fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>手机号</label>
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<div style={{ height: 56, background: T.surface, borderRadius: T.r, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 14px', fontSize: 14, color: T.tx, fontWeight: 600, flexShrink: 0, border: `1.5px solid ${T.bd}` }}>
+86
</div>
<input style={{ ...FieldStyle, flex: 1 }} placeholder="请输入手机号" type="tel" />
</div>
</div>
{/* 身份证号 */}
<div>
<label style={{ display: 'block', fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>身份证号</label>
<input style={FieldStyle} placeholder="请输入身份证号" />
</div>
{/* 出生日期 */}
<div>
<label style={{ display: 'block', fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>出生日期</label>
<div style={{ ...FieldStyle, display: 'flex', alignItems: 'center', justifyContent: 'space-between', color: T.tx3 }}>
<span>请选择出生日期</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={T.tx3} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
</div>
</div>
{/* 性别 */}
<div>
<label style={{ display: 'block', fontSize: 13, color: T.tx2, marginBottom: 6, fontWeight: 500 }}>性别</label>
<div style={{ display: 'flex', gap: 12 }}>
{['男', '女'].map((g, i) => (
<div key={g} style={{ flex: 1, height: 56, borderRadius: T.r, border: i === 0 ? `2px solid ${T.pri}` : `1.5px solid ${T.bd}`, background: i === 0 ? T.priL : T.card, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, cursor: 'pointer' }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={i === 0 ? T.pri : T.tx3} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
{i === 0 ? (<><circle cx="10.5" cy="10.5" r="7"/><line x1="16" y1="16" x2="21" y2="21"/></>) : (<><circle cx="12" cy="12" r="7"/><line x1="8" y1="8" x2="16" y2="16"/></>)}
</svg>
<span style={{ fontSize: 15, fontWeight: 600, color: i === 0 ? T.pri : T.tx2 }}>{g}</span>
</div>
))}
</div>
</div>
{/* 保存按钮 */}
<div style={{ marginTop: 10 }}>
<div style={{ height: 56, borderRadius: T.r, background: T.pri, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: `0 4px 16px rgba(196,98,58,0.3)`, cursor: 'pointer' }}>
<span style={{ fontSize: 17, fontWeight: 600, color: '#fff' }}>保存</span>
</div>
</div>
</div>
</div>
);
}
// ═══════════════════════════════════════════════════════════════
// 屏幕3知情同意
// ═══════════════════════════════════════════════════════════════
function ConsentsPage() {
const consents = [
{ title: '血液透析知情同意书', date: '2025-04-01', status: 'signed', icon: 'blood' },
{ title: '透析血管通路知情同意书', date: '2025-04-01', status: 'signed', icon: 'vein' },
{ title: '数据共享知情同意书', date: '', status: 'pending', icon: 'data' },
];
return (
<div style={{ background: T.bg, minHeight: '100%', fontFamily: T.sans }}>
<NavBar title="知情同意书" />
<div style={{ padding: 16 }}>
{consents.map((c, i) => (
<div key={i} style={{ background: T.card, borderRadius: T.r, padding: 16, marginBottom: 12, boxShadow: '0 1px 4px rgba(0,0,0,0.04)', display: 'flex', alignItems: 'center', gap: 12 }}>
{/* 图标 */}
<div style={{ width: 44, height: 44, borderRadius: T.rSm, background: c.status === 'signed' ? T.accL : T.wrnL, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={c.status === 'signed' ? T.acc : T.wrn} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/>
</svg>
</div>
{/* 信息 */}
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontFamily: T.serif, fontSize: 14, fontWeight: 600, color: T.tx, marginBottom: 4, lineHeight: 1.4 }}>{c.title}</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
{c.date && <span style={{ fontSize: 12, color: T.tx3 }}>{c.date}</span>}
<span style={{ fontSize: 11, fontWeight: 600, color: c.status === 'signed' ? T.acc : T.wrn, background: c.status === 'signed' ? T.accL : T.wrnL, padding: '2px 8px', borderRadius: 6 }}>
{c.status === 'signed' ? '已签署' : '待签署'}
</span>
</div>
</div>
<ArrowRight />
</div>
))}
{/* 底部提示 */}
<div style={{ textAlign: 'center', marginTop: 20, padding: '0 20px' }}>
<p style={{ fontSize: 12, color: T.tx3, lineHeight: 1.8 }}>签署后的同意书具有法律效力请仔细阅读后再签署</p>
</div>
</div>
</div>
);
}
// ═══════════════════════════════════════════════════════════════
// 屏幕4事件记录
// ═══════════════════════════════════════════════════════════════
function EventsPage() {
const events = [
{ date: '5月8日', desc: '开始透析治疗', color: T.pri, bg: T.priL, type: '治疗' },
{ date: '4月15日', desc: '调整透析方案', color: T.acc, bg: T.accL, type: '方案' },
{ date: '3月20日', desc: '完成血管通路手术', color: T.wrn, bg: T.wrnL, type: '手术' },
{ date: '2月10日', desc: '首次门诊', color: T.pri, bg: T.priL, type: '门诊' },
{ date: '2024-12-01', desc: '确诊慢性肾病', color: T.dan, bg: T.danL, type: '诊断' },
];
return (
<div style={{ background: T.bg, minHeight: '100%', fontFamily: T.sans }}>
<NavBar title="事件记录" />
<div style={{ padding: '16px 16px 16px 24px' }}>
{/* 时间线 */}
<div style={{ position: 'relative' }}>
{/* 竖线 */}
<div style={{ position: 'absolute', left: 7, top: 12, bottom: 12, width: 2, background: T.bdL, borderRadius: 1 }} />
{events.map((e, i) => (
<div key={i} style={{ position: 'relative', paddingLeft: 28, marginBottom: i < events.length - 1 ? 20 : 0 }}>
{/* 圆点 */}
<div style={{ position: 'absolute', left: 0, top: 6, width: 16, height: 16, borderRadius: 8, background: e.color, border: `3px solid ${e.bg}`, boxShadow: `0 0 0 2px ${e.bg}`, zIndex: 1 }} />
{/* 事件卡片 */}
<div style={{ background: T.card, borderRadius: T.rSm, padding: 14, boxShadow: '0 1px 4px rgba(0,0,0,0.04)' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 6 }}>
<span style={{ fontSize: 13, color: T.tx3, fontWeight: 500 }}>{e.date}</span>
<span style={{ fontSize: 11, color: e.color, background: e.bg, padding: '2px 8px', borderRadius: 6, fontWeight: 600 }}>{e.type}</span>
</div>
<div style={{ fontSize: 15, fontWeight: 600, color: T.tx, lineHeight: 1.4 }}>{e.desc}</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}
// ═══════════════════════════════════════════════════════════════
// 屏幕5长者模式
// ═══════════════════════════════════════════════════════════════
function ElderModePage() {
return (
<div style={{ background: T.bg, minHeight: '100%', fontFamily: T.sans }}>
<NavBar title="关怀模式" />
<div style={{ padding: 16 }}>
{/* 说明区域 */}
<div style={{ background: T.accL, borderLeft: `4px solid ${T.acc}`, borderRadius: '0 T.rSm T.rSm 0', padding: '14px 16px', marginBottom: 20 }}>
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={T.acc} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0, marginTop: 1 }}>
<circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/>
</svg>
<span style={{ fontSize: 13, color: T.acc, lineHeight: 1.7, fontWeight: 500 }}>开启关怀模式后字体将放大界面更简洁方便阅读</span>
</div>
</div>
{/* 模式开关卡片 */}
<div style={{ background: T.card, borderRadius: T.r, padding: 16, marginBottom: 16, boxShadow: '0 1px 4px rgba(0,0,0,0.04)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{ width: 40, height: 40, borderRadius: 12, background: T.priL, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={T.pri} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
</div>
<div>
<div style={{ fontSize: 16, fontWeight: 600, color: T.tx }}>关怀模式</div>
<div style={{ fontSize: 12, color: T.tx3, marginTop: 2 }}>放大字号简化界面</div>
</div>
</div>
<Toggle on={true} color={T.pri} />
</div>
{/* 字号预览 */}
<div style={{ background: T.card, borderRadius: T.r, padding: 16, marginBottom: 16, boxShadow: '0 1px 4px rgba(0,0,0,0.04)' }}>
<div style={{ fontSize: 13, color: T.tx3, marginBottom: 12, fontWeight: 500 }}>字号预览</div>
{/* 标准字号 */}
<div style={{ marginBottom: 14 }}>
<span style={{ fontSize: 11, color: T.tx3, display: 'block', marginBottom: 4 }}>标准</span>
<div style={{ background: T.surface, borderRadius: T.rXs, padding: '10px 14px' }}>
<span style={{ fontSize: 15, color: T.tx }}>血压 130/85 mmHg</span>
</div>
</div>
{/* 放大字号 */}
<div>
<span style={{ fontSize: 11, color: T.pri, display: 'block', marginBottom: 4, fontWeight: 600 }}>关怀模式</span>
<div style={{ background: T.priL, borderRadius: T.rXs, padding: '12px 14px' }}>
<span style={{ fontSize: 22, color: T.priD, fontWeight: 600 }}>血压 130/85 mmHg</span>
</div>
</div>
</div>
{/* 其他设置 */}
<div style={{ background: T.card, borderRadius: T.r, overflow: 'hidden', boxShadow: '0 1px 4px rgba(0,0,0,0.04)' }}>
{/* 高对比度 */}
<div style={{ padding: '14px 16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: `1px solid ${T.bdL}` }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{ width: 36, height: 36, borderRadius: 10, background: T.surface, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={T.tx2} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a10 10 0 000 20z"/></svg>
</div>
<span style={{ fontSize: 15, color: T.tx, fontWeight: 500 }}>高对比度模式</span>
</div>
<Toggle on={false} />
</div>
{/* 语音播报 */}
<div style={{ padding: '14px 16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{ width: 36, height: 36, borderRadius: 10, background: T.surface, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={T.tx2} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07"/></svg>
</div>
<span style={{ fontSize: 15, color: T.tx, fontWeight: 500 }}>语音播报</span>
</div>
<Toggle on={false} />
</div>
</div>
</div>
</div>
);
}
// ═══════════════════════════════════════════════════════════════
// 屏幕6设置
// ═══════════════════════════════════════════════════════════════
function SettingsPage() {
const settingsGroups = [
[
{ icon: 'shield', iconBg: T.acc, label: '账号与安全', value: '' },
{ icon: 'bell', iconBg: T.wrn, label: '消息通知', value: '' },
{ icon: 'eye', iconBg: T.pri, label: '隐私设置', value: '' },
],
[
{ icon: 'globe', iconBg: '#6B8ABF', label: '语言', value: '简体中文' },
{ icon: 'trash', iconBg: T.tx3, label: '清除缓存', value: '12.3 MB' },
{ icon: 'info', iconBg: T.tx2, label: '关于 HMS', value: '' },
],
];
const iconPaths = {
shield: <><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></>,
bell: <><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></>,
eye: <><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></>,
globe: <><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z"/></>,
trash: <><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></>,
info: <><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></>,
};
return (
<div style={{ background: T.bg, minHeight: '100%', fontFamily: T.sans }}>
<NavBar title="设置" />
<div style={{ padding: 16 }}>
{settingsGroups.map((group, gi) => (
<div key={gi} style={{ background: T.card, borderRadius: T.r, overflow: 'hidden', marginBottom: 16, boxShadow: '0 1px 4px rgba(0,0,0,0.04)' }}>
{group.map((item, ii) => (
<div key={ii} style={{ padding: '14px 16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: ii < group.length - 1 ? `1px solid ${T.bdL}` : 'none' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{ width: 34, height: 34, borderRadius: 10, background: item.iconBg, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">{iconPaths[item.icon]}</svg>
</div>
<span style={{ fontSize: 15, color: T.tx, fontWeight: 500 }}>{item.label}</span>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
{item.value && <span style={{ fontSize: 13, color: T.tx3 }}>{item.value}</span>}
<ArrowRight />
</div>
</div>
))}
</div>
))}
{/* 版本号 + 退出登录 */}
<div style={{ textAlign: 'center', marginTop: 20 }}>
<div style={{ fontSize: 12, color: T.tx3, marginBottom: 16 }}>v1.0.0</div>
<div style={{ height: 48, borderRadius: T.r, border: `1.5px solid ${T.dan}`, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}>
<span style={{ fontSize: 15, fontWeight: 600, color: T.dan }}>退出登录</span>
</div>
</div>
</div>
</div>
);
}
// ═══════════════════════════════════════════════════════════════
// 主渲染
// ═══════════════════════════════════════════════════════════════
function App() {
const screens = [
{ label: '家庭管理', component: <FamilyPage /> },
{ label: '添加家庭成员', component: <FamilyAddPage /> },
{ label: '知情同意', component: <ConsentsPage /> },
{ label: '事件记录', component: <EventsPage /> },
{ label: '长者模式', component: <ElderModePage /> },
{ label: '设置', component: <SettingsPage /> },
];
return (
<div className="screens">
{screens.map((s, i) => (
<div key={i} className="screen-wrap">
<IosFrame width={340} height={740}>
{s.component}
</IosFrame>
<div className="screen-label">{s.label}</div>
</div>
))}
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>