Files
hms/apps/miniprogram/src/pages/pkg-health/device-sync/index.scss
iven a24c18155f feat(mp): BLE 血氧仪支持 + 服务发现增强
- 新增 Pulse Oximeter Service (0x1822) 支持,含 SFLOAT 解析
- 连接后自动扫描全部服务,发现并订阅已知健康 UUID
- 设备同步页展示已发现的服务和可用数据类型标签
- 新增 BLEDiscoveredService / BLEDiscoveredCharacteristic 类型
2026-05-25 13:43:16 +08:00

989 lines
17 KiB
SCSS
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.
@import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss';
// PageShell 已接管min-height, background, safe-bottom
// NavBar 由 Taro 原生页面配置处理index.config.ts navigationBarTitleText
// ─── Body ───
.ds-body {
padding: 0 var(--tk-gap-lg) calc(var(--tk-tabbar-space) + 20px);
&--center {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 60vh;
padding-top: 0;
}
}
// ─── Hero ───
.ds-hero {
background: linear-gradient(135deg, $pri 0%, $pri-d 100%);
margin: 0 calc(var(--tk-gap-lg) * -1);
padding: var(--tk-gap-2xl) var(--tk-gap-lg) var(--tk-gap-xl);
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: var(--tk-gap-lg);
}
.ds-hero__icon {
width: 72px;
height: 72px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.15);
@include flex-center;
margin-bottom: var(--tk-section-gap);
}
.ds-hero__bt {
font-size: 24px;
font-weight: 700;
color: $white;
font-family: Georgia, 'Times New Roman', serif;
}
.ds-hero__title {
@include section-title;
color: $white;
font-family: Georgia, 'Times New Roman', serif;
margin-bottom: var(--tk-gap-xs);
}
.ds-hero__desc {
font-size: var(--tk-font-body-sm);
color: rgba(255, 255, 255, 0.75);
text-align: center;
}
// ─── 设备类型标签 ───
.ds-types {
margin-bottom: var(--tk-gap-md);
}
.ds-types__label {
display: block;
font-size: var(--tk-font-body-sm);
font-weight: 600;
color: $tx;
margin-bottom: var(--tk-gap-sm);
padding-left: 2px;
}
.ds-types__row {
display: flex;
gap: var(--tk-gap-xs);
}
.ds-type-tag {
display: flex;
align-items: center;
gap: 6px;
background: $card;
border: 1px solid $bd-l;
border-radius: $r-xs;
padding: 8px 12px;
}
.ds-type-tag__dot {
width: 8px;
height: 8px;
border-radius: 50%;
&--heart { background: $dan; }
&--bp { background: $pri; }
&--glu { background: $wrn; }
}
.ds-type-tag__text {
font-size: var(--tk-font-cap);
color: $tx2;
}
// ─── 上次同步信息 ───
.ds-sync-info {
margin-bottom: var(--tk-gap-sm) !important;
}
.ds-sync-info__inner {
display: flex;
align-items: center;
gap: var(--tk-gap-md);
}
.ds-sync-info__icon-wrap {
width: 36px;
height: 36px;
border-radius: 50%;
background: $acc-l;
@include flex-center;
flex-shrink: 0;
}
.ds-sync-info__check {
font-size: 16px;
color: $acc;
font-weight: 700;
}
.ds-sync-info__text {
flex: 1;
display: flex;
flex-direction: column;
}
.ds-sync-info__title {
font-size: var(--tk-font-body-sm);
font-weight: 500;
color: $tx;
}
.ds-sync-info__time {
font-size: var(--tk-font-cap);
color: $tx3;
margin-top: 2px;
}
.ds-sync-info__badge {
background: $acc-l;
border-radius: $r-xs;
padding: 4px 10px;
font-size: var(--tk-font-cap);
color: $acc;
font-weight: 500;
}
// ─── 待上传警告 ───
.ds-warning {
background: $wrn-l;
border-radius: $r-sm;
padding: 12px var(--tk-gap-md);
display: flex;
align-items: center;
gap: 10px;
margin-bottom: var(--tk-gap-lg);
}
.ds-warning__icon {
width: 20px;
height: 20px;
border-radius: 50%;
background: $wrn;
color: $white;
font-size: 12px;
font-weight: 700;
@include flex-center;
flex-shrink: 0;
}
.ds-warning__text {
font-size: var(--tk-font-cap);
color: $wrn;
font-weight: 500;
}
// ─── 扫描按钮 ───
.ds-scan-btn-wrap {
margin-top: var(--tk-gap-md);
}
// ─── 设备列表 ───
.ds-devices {
margin-top: var(--tk-gap-lg);
}
.ds-devices__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--tk-gap-sm);
}
.ds-devices__count {
font-size: var(--tk-font-body-sm);
font-weight: 600;
color: $tx;
}
.ds-devices__rescan {
font-size: var(--tk-font-cap);
color: $pri;
font-weight: 500;
}
.ds-device-card {
display: flex;
align-items: center;
gap: 14px;
background: $card;
border-radius: $r-sm;
padding: var(--tk-gap-md);
margin-bottom: 10px;
border: 1px solid $bd-l;
}
.ds-device-card__icon {
width: 44px;
height: 44px;
border-radius: $r-sm;
background: $pri-l;
@include flex-center;
flex-shrink: 0;
}
.ds-device-card__bt {
font-size: 14px;
font-weight: 700;
color: $pri;
font-family: Georgia, 'Times New Roman', serif;
}
.ds-device-card__info {
flex: 1;
display: flex;
flex-direction: column;
}
.ds-device-card__name {
font-size: var(--tk-font-body);
font-weight: 600;
color: $tx;
}
.ds-device-card__adapter {
font-size: var(--tk-font-cap);
color: $tx3;
margin-top: 3px;
}
.ds-device-card__signal {
display: flex;
align-items: flex-end;
gap: 2px;
height: 16px;
margin-right: 6px;
}
.ds-signal-bar {
width: 3px;
border-radius: 1px;
background: $bd;
&--active {
background: $acc;
}
}
.ds-device-card__arrow {
font-size: 18px;
color: $tx3;
font-weight: 300;
}
.ds-device-card--generic {
border-style: dashed;
border-color: $bd;
.ds-device-card__icon {
background: $surface-alt;
}
}
.ds-devices__empty-hint {
margin-top: var(--tk-gap-md);
background: $card;
border-radius: $r-sm;
padding: 14px var(--tk-gap-md);
border: 1px dashed $bd;
display: flex;
align-items: center;
gap: 10px;
}
.ds-devices__empty-icon {
width: 32px;
height: 32px;
border-radius: 50%;
background: $surface-alt;
@include flex-center;
font-size: 14px;
color: $tx3;
flex-shrink: 0;
}
.ds-devices__empty-title {
display: block;
font-size: var(--tk-font-cap);
color: $tx2;
}
.ds-devices__empty-desc {
display: block;
font-size: var(--tk-font-cap);
color: $tx3;
margin-top: 2px;
}
// 空结果提示框(扫描完成但 0 设备)
.ds-devices--empty {
display: flex;
flex-direction: column;
gap: var(--tk-gap-md);
}
.ds-devices__empty-box {
background: $card;
border-radius: $r;
border: 2px dashed $bd;
padding: var(--tk-gap-xl) var(--tk-gap-lg);
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: var(--tk-gap-xs);
}
.ds-devices__empty-box-icon {
width: 48px;
height: 48px;
border-radius: 50%;
background: $wrn-l;
color: $wrn;
font-size: 22px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: var(--tk-gap-xs);
}
.ds-devices__empty-box-title {
font-size: var(--tk-font-body);
font-weight: 600;
color: $tx;
}
.ds-devices__empty-box-desc {
font-size: var(--tk-font-body-sm);
color: $tx3;
line-height: 1.5;
}
.ds-devices__rescan-wrap {
margin-top: var(--tk-gap-xs);
}
// ─── 脉冲扫描动画 ───
.ds-pulse {
position: relative;
width: 140px;
height: 140px;
margin-bottom: var(--tk-gap-2xl);
}
.ds-pulse__ring {
position: absolute;
border-radius: 50%;
border: 2px solid $pri-l;
animation: ds-pulse-ring 2s ease-out infinite;
&--1 { top: 0; left: 0; width: 140px; height: 140px; }
&--2 { top: 15px; left: 15px; width: 110px; height: 110px; animation-delay: 0.5s; }
}
.ds-pulse__center {
position: absolute;
top: 30px;
left: 30px;
width: 80px;
height: 80px;
border-radius: 50%;
background: $pri-l;
@include flex-center;
animation: ds-pulse-dot 2s ease-in-out infinite;
}
.ds-pulse__bt {
font-size: 24px;
font-weight: 700;
color: $pri;
font-family: Georgia, 'Times New Roman', serif;
}
.ds-pulse__title {
font-family: Georgia, 'Times New Roman', serif;
font-size: var(--tk-font-h2);
font-weight: 700;
color: $tx;
margin-bottom: var(--tk-gap-xs);
text-align: center;
}
.ds-pulse__hint {
font-size: var(--tk-font-body-sm);
color: $tx3;
text-align: center;
}
@keyframes ds-pulse-ring {
0% { transform: scale(0.8); opacity: 0.6; }
50% { transform: scale(1.3); opacity: 0; }
100% { transform: scale(0.8); opacity: 0; }
}
@keyframes ds-pulse-dot {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
// ─── 连接动画 ───
.ds-connect-anim {
position: relative;
width: 100px;
height: 100px;
margin-bottom: 28px;
}
.ds-connect-anim__ring {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border-radius: 50%;
border: 3px solid $bd-l;
border-top-color: $pri;
animation: ds-connect-spin 1s linear infinite;
}
.ds-connect-anim__center {
position: absolute;
top: 20px;
left: 20px;
width: 60px;
height: 60px;
border-radius: 50%;
background: $pri-l;
@include flex-center;
}
.ds-connect-anim__bt {
font-size: 18px;
font-weight: 700;
color: $pri;
font-family: Georgia, 'Times New Roman', serif;
}
.ds-connect-anim__title {
font-family: Georgia, 'Times New Roman', serif;
font-size: var(--tk-font-body-lg);
font-weight: 700;
color: $tx;
margin-bottom: 6px;
text-align: center;
}
.ds-connect-anim__sub {
font-size: var(--tk-font-body-sm);
color: $tx3;
text-align: center;
}
@keyframes ds-connect-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
// ─── 步骤指示器 ───
.ds-steps {
display: flex;
align-items: center;
gap: 8px;
margin-top: var(--tk-gap-xl);
}
.ds-steps__dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: $bd;
&--done { background: $acc; }
&--active {
background: $pri;
animation: ds-pulse-dot 1s ease-in-out infinite;
}
}
.ds-steps__label {
font-size: var(--tk-font-cap);
color: $tx3;
&--done { color: $tx3; }
&--active { color: $pri; font-weight: 500; }
}
.ds-steps__line {
width: 24px;
height: 1px;
background: $bd;
&--active { background: $pri; }
}
// ─── 已连接状态卡 ───
.ds-connected-status {
background: linear-gradient(135deg, $acc 0%, $acc-d 100%);
border-radius: $r;
padding: var(--tk-gap-md);
display: flex;
align-items: center;
gap: 12px;
margin-bottom: var(--tk-gap-md);
}
.ds-connected-status__icon {
width: 40px;
height: 40px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
@include flex-center;
flex-shrink: 0;
}
.ds-connected-status__bt {
font-size: 14px;
font-weight: 700;
color: $white;
font-family: Georgia, 'Times New Roman', serif;
}
.ds-connected-status__info {
flex: 1;
}
.ds-connected-status__name {
font-size: var(--tk-font-body);
font-weight: 600;
color: $white;
}
.ds-connected-status__sub {
font-size: var(--tk-font-cap);
color: rgba(255, 255, 255, 0.7);
margin-top: 2px;
}
.ds-connected-status__badge {
background: rgba(255, 255, 255, 0.2);
border-radius: $r-xs;
padding: 4px 10px;
font-size: var(--tk-font-cap);
color: $white;
}
// ─── 最新读数卡片 ───
.ds-latest-reading {
margin-bottom: var(--tk-gap-md) !important;
}
.ds-latest-reading__icon-wrap {
width: 52px;
height: 52px;
border-radius: $r-sm;
@include flex-center;
flex-shrink: 0;
&--heart {
background: rgba($dan, 0.06);
}
}
.ds-latest-reading__heart {
font-size: 28px;
color: $dan;
}
.ds-latest-reading__body {
flex: 1;
margin-left: var(--tk-gap-md);
}
.ds-latest-reading__label {
display: block;
font-size: var(--tk-font-cap);
color: $tx3;
}
.ds-latest-reading__values {
display: flex;
align-items: baseline;
gap: 4px;
margin-top: 4px;
}
.ds-latest-reading__num {
font-family: Georgia, 'Times New Roman', serif;
font-size: 36px;
font-weight: 700;
color: $tx;
@include serif-number;
}
.ds-latest-reading__unit {
font-size: var(--tk-font-body-sm);
color: $tx3;
}
// ─── 历史读数 ───
.ds-history {
margin-bottom: var(--tk-gap-md);
}
.ds-history__title {
display: block;
font-size: var(--tk-font-body-sm);
font-weight: 600;
color: $tx;
margin-bottom: var(--tk-gap-sm);
padding-left: 2px;
}
.ds-history__list {
background: $card;
border-radius: $r-sm;
overflow: hidden;
box-shadow: $shadow-sm;
}
.ds-history__row {
display: flex;
align-items: center;
padding: 12px var(--tk-gap-md);
border-bottom: 1px solid $bd-l;
&--last {
border-bottom: none;
}
}
.ds-history__type {
width: 90px;
font-size: var(--tk-font-body-sm);
color: $tx2;
}
.ds-history__val-wrap {
flex: 1;
display: flex;
align-items: baseline;
gap: 3px;
}
.ds-history__val {
font-family: Georgia, 'Times New Roman', serif;
font-size: 20px;
font-weight: 700;
color: $tx;
@include serif-number;
}
.ds-history__unit {
font-size: var(--tk-font-cap);
color: $tx3;
}
.ds-history__count {
display: block;
text-align: center;
margin-top: var(--tk-gap-sm);
font-size: var(--tk-font-cap);
color: $tx3;
}
// ─── 操作按钮 ───
.ds-actions {
display: flex;
gap: var(--tk-gap-sm);
margin-top: var(--tk-section-gap);
}
.ds-actions__upload {
flex: 1;
background: $pri;
border-radius: $r-sm;
padding: 14px;
@include flex-center;
box-shadow: $shadow-btn;
}
.ds-actions__upload-text {
color: $white;
font-size: var(--tk-font-body-lg);
font-weight: 600;
}
.ds-actions__disconnect {
width: 52px;
background: $dan-l;
border-radius: $r-sm;
@include flex-center;
}
.ds-actions__disconnect-icon {
font-size: 16px;
color: $dan;
font-weight: 700;
}
// ─── 同步完成 ───
.ds-done {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 var(--tk-gap-lg);
}
.ds-done__icon {
width: 80px;
height: 80px;
border-radius: 50%;
background: $acc-l;
@include flex-center;
margin-bottom: var(--tk-gap-xl);
}
.ds-done__check {
font-size: 32px;
color: $acc;
font-weight: 700;
}
.ds-done__title {
font-family: Georgia, 'Times New Roman', serif;
font-size: var(--tk-font-h1);
font-weight: 700;
color: $tx;
margin-bottom: var(--tk-gap-xs);
}
.ds-done__desc {
font-size: var(--tk-font-body-sm);
color: $tx3;
text-align: center;
margin-bottom: var(--tk-gap-lg);
}
.ds-done__stats {
display: flex;
gap: 12px;
width: 100%;
margin-bottom: var(--tk-gap-xl);
}
.ds-done__stat {
flex: 1;
background: $card;
border-radius: $r-sm;
padding: var(--tk-gap-md);
text-align: center;
border: 1px solid $bd-l;
}
.ds-done__stat-num {
display: block;
font-family: Georgia, 'Times New Roman', serif;
font-size: var(--tk-font-num);
font-weight: 700;
color: $tx;
&--pri { color: $pri; }
&--acc { color: $acc; font-size: var(--tk-font-body-lg); }
}
.ds-done__stat-label {
display: block;
font-size: var(--tk-font-cap);
color: $tx3;
margin-top: 4px;
}
// ─── 错误页面 ───
.ds-error-page {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 var(--tk-gap-lg);
}
.ds-error-page__icon {
width: 80px;
height: 80px;
border-radius: 50%;
background: $dan-l;
@include flex-center;
margin-bottom: var(--tk-gap-xl);
}
.ds-error-page__x {
font-size: 28px;
color: $dan;
font-weight: 700;
}
.ds-error-page__title {
font-family: Georgia, 'Times New Roman', serif;
font-size: var(--tk-font-h2);
font-weight: 700;
color: $tx;
margin-bottom: var(--tk-gap-xs);
}
.ds-error-page__desc {
font-size: var(--tk-font-body-sm);
color: $tx3;
text-align: center;
max-width: 260px;
margin-bottom: var(--tk-gap-lg);
}
.ds-error-page__detail {
width: 100%;
background: $card;
border-radius: $r-sm;
padding: var(--tk-gap-md);
border: 1px solid $bd-l;
margin-bottom: var(--tk-gap-lg);
}
.ds-error-page__detail-title {
display: flex;
align-items: center;
gap: 8px;
font-size: var(--tk-font-cap);
font-weight: 500;
color: $tx;
margin-bottom: 12px;
}
.ds-error-page__detail-row {
display: flex;
justify-content: space-between;
padding: 4px 0;
margin-bottom: 4px;
&--last {
margin-bottom: 0;
}
}
.ds-error-page__detail-label {
font-size: var(--tk-font-cap);
color: $tx3;
}
.ds-error-page__detail-value {
font-size: var(--tk-font-cap);
color: $tx;
}
.ds-error-page__back {
width: 100%;
border-radius: $r-sm;
padding: 14px;
@include flex-center;
margin-top: 10px;
border: 1px solid $bd;
}
.ds-error-page__back-text {
color: $tx2;
font-size: var(--tk-font-body);
font-weight: 500;
}
// ─── 加载态 ───
.ds-loading {
@include flex-center;
flex-direction: column;
padding: 64px 24px;
gap: var(--tk-gap-md);
}
.ds-loading__spinner {
width: 40px;
height: 40px;
border-radius: 50%;
border: 3px solid $bd-l;
border-top-color: $pri;
animation: ds-connect-spin 1s linear infinite;
}
.ds-loading__text {
font-size: var(--tk-font-body-lg);
color: $tx2;
}
// ─── 服务发现信息 ───
.ds-services-info {
margin-bottom: var(--tk-gap-md) !important;
}
.ds-services-info__title {
display: block;
font-size: var(--tk-font-body-sm);
font-weight: 600;
color: $tx;
margin-bottom: var(--tk-gap-sm);
}
.ds-services-info__caps {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.ds-cap-tag {
display: flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
border-radius: $r-xs;
font-size: var(--tk-font-cap);
&--on {
background: rgba($acc, 0.08);
color: $acc;
}
&--off {
background: $surface-alt;
color: $tx3;
}
}
.ds-cap-tag__dot {
font-size: 10px;
}
.ds-cap-tag__text {
font-size: var(--tk-font-cap);
}
.ds-services-info__hint {
margin-top: var(--tk-gap-sm);
background: $wrn-l;
border-radius: $r-xs;
padding: 8px 12px;
}
.ds-services-info__hint-text {
font-size: var(--tk-font-cap);
color: $wrn;
line-height: 1.5;
}