fix(mp): T40 UI 设计系统合规审计修复 — 60 页面全覆盖
- 新增 $white 语义变量 + --tk-font-display Token - 44 处 #fff → $white,2 处 background: #fff → $card - 14 处 border-radius 硬编码统一为 $r-xs/$r-lg/$r - 3 处 TSX inline 颜色提取为 SCSS 类(exchange/orders/action-inbox) - ErrorBoundary 重构:6 个 inline style → SCSS 类 + Design Token - 2 处离调色板颜色修正(#0284C7→$tx2, #94A3B8→$tx3) - 2 处静默 catch 块添加状态清理(article/health) - 趋势页补 Loading/EmptyState;咨询页 GuestGuard 统一 - 4 处 #FFFFFF → $white(mixins/index/exchange/variables)
This commit is contained in:
@@ -44,7 +44,7 @@
|
||||
.sync-btn {
|
||||
padding: 12rpx 28rpx;
|
||||
background: $pri;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
border-radius: $r-pill;
|
||||
font-size: var(--tk-font-micro);
|
||||
}
|
||||
|
||||
@@ -46,5 +46,5 @@
|
||||
|
||||
.empty-state-action-text {
|
||||
font-size: var(--tk-font-body-lg);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
52
apps/miniprogram/src/components/ErrorBoundary/index.scss
Normal file
52
apps/miniprogram/src/components/ErrorBoundary/index.scss
Normal file
@@ -0,0 +1,52 @@
|
||||
@import '../../styles/variables.scss';
|
||||
|
||||
.error-boundary {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 60vh;
|
||||
padding: 40px 24px;
|
||||
}
|
||||
|
||||
.error-icon-wrap {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 32px;
|
||||
background: $pri-l;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.error-icon-text {
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-h1);
|
||||
font-weight: 600;
|
||||
color: $pri-d;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: $tx;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.error-desc {
|
||||
font-size: var(--tk-font-body-lg);
|
||||
color: $tx3;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.error-retry-btn {
|
||||
background: $pri;
|
||||
border-radius: $r-sm;
|
||||
padding: 14px 48px;
|
||||
}
|
||||
|
||||
.error-retry-text {
|
||||
color: $white;
|
||||
font-size: var(--tk-font-h1);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import './index.scss';
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
@@ -30,17 +31,17 @@ export default class ErrorBoundary extends Component<Props, State> {
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<View style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '60vh', padding: '40px 24px' }}>
|
||||
<View style={{ width: '64px', height: '64px', borderRadius: '32px', background: '#F0DDD4', display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: '20px' }}>
|
||||
<Text style={{ fontFamily: 'Georgia, serif', fontSize: '28px', fontWeight: 600, color: '#8B3E1F' }}>!</Text>
|
||||
<View className='error-boundary'>
|
||||
<View className='error-icon-wrap'>
|
||||
<Text className='error-icon-text'>!</Text>
|
||||
</View>
|
||||
<Text style={{ fontSize: '32px', color: '#2D2A26', marginBottom: '12px', fontWeight: 600 }}>页面出了点问题</Text>
|
||||
<Text style={{ fontSize: '24px', color: '#78716C', marginBottom: '32px' }}>请返回重试</Text>
|
||||
<Text className='error-title'>页面出了点问题</Text>
|
||||
<Text className='error-desc'>请返回重试</Text>
|
||||
<View
|
||||
className='error-retry-btn'
|
||||
onClick={this.handleRetry}
|
||||
style={{ background: '#C4623A', borderRadius: '12px', padding: '14px 48px' }}
|
||||
>
|
||||
<Text style={{ color: '#FFFFFF', fontSize: '28px' }}>重新加载</Text>
|
||||
<Text className='error-retry-text'>重新加载</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
}
|
||||
|
||||
.error-state-icon {
|
||||
font-size: 80px; /* hero icon — kept as-is */
|
||||
font-size: var(--tk-font-display);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@@ -28,5 +28,5 @@
|
||||
|
||||
.error-state-retry-text {
|
||||
font-size: var(--tk-font-body-lg);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
@@ -60,5 +60,5 @@
|
||||
.guard-btn-text {
|
||||
font-size: var(--tk-font-body-sm);
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
@@ -90,16 +90,16 @@
|
||||
.auto-badge-text {
|
||||
display: inline-block;
|
||||
padding: 4px 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
font-size: var(--tk-font-body);
|
||||
font-weight: 500;
|
||||
background: #f0e6ff;
|
||||
color: #7c3aed;
|
||||
background: $pri-l;
|
||||
color: $pri;
|
||||
}
|
||||
|
||||
.trend-tip-card {
|
||||
background: #fffbeb;
|
||||
border: 1px solid #fde68a;
|
||||
background: $wrn-l;
|
||||
border: 1px solid $wrn;
|
||||
border-radius: $r;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 20px;
|
||||
@@ -107,6 +107,6 @@
|
||||
|
||||
.trend-tip-text {
|
||||
font-size: var(--tk-font-body);
|
||||
color: #92400e;
|
||||
color: $wrn;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@import '../../../styles/variables.scss';
|
||||
@import '../../../styles/mixins.scss';
|
||||
|
||||
.article-detail-page {
|
||||
min-height: 100vh;
|
||||
@@ -33,7 +34,7 @@
|
||||
color: $pri;
|
||||
background: $pri-l;
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
border-radius: $r-sm;
|
||||
}
|
||||
|
||||
.article-author {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@import '../../styles/variables.scss';
|
||||
@import '../../styles/mixins.scss';
|
||||
|
||||
.article-page {
|
||||
min-height: 100vh;
|
||||
@@ -19,7 +20,7 @@
|
||||
font-size: var(--tk-font-h1);
|
||||
color: $tx2;
|
||||
background: $card;
|
||||
border-radius: 32px;
|
||||
border-radius: $r-lg;
|
||||
border: 2px solid transparent;
|
||||
|
||||
&--active {
|
||||
@@ -87,7 +88,7 @@
|
||||
color: $pri;
|
||||
background: $pri-l;
|
||||
padding: 2px 12px;
|
||||
border-radius: 12px;
|
||||
border-radius: $r-sm;
|
||||
}
|
||||
|
||||
.article-card-date {
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function ArticleList() {
|
||||
const data = await listCategories();
|
||||
setCategories(data || []);
|
||||
} catch {
|
||||
// 静默
|
||||
setCategories([]);
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
.msg-avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 16px;
|
||||
border-radius: $r;
|
||||
background: $pri-l;
|
||||
@include flex-center;
|
||||
flex-shrink: 0;
|
||||
@@ -116,7 +116,7 @@
|
||||
word-break: break-all;
|
||||
|
||||
.msg-bubble--self & {
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
height: 40px;
|
||||
background: $bg;
|
||||
border: 1.5px solid $bd;
|
||||
border-radius: 20px;
|
||||
border-radius: $r-lg;
|
||||
padding: 0 14px;
|
||||
font-size: var(--tk-font-cap);
|
||||
color: $tx;
|
||||
@@ -187,7 +187,7 @@
|
||||
.chat-send-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 20px;
|
||||
border-radius: $r-lg;
|
||||
background: $pri;
|
||||
@include flex-center;
|
||||
flex-shrink: 0;
|
||||
@@ -200,7 +200,7 @@
|
||||
|
||||
.chat-send-btn__icon {
|
||||
font-size: var(--tk-font-cap);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
.consultation-create-btn-text {
|
||||
font-size: var(--tk-font-body-sm);
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
/* ─── 居中容器 ─── */
|
||||
@@ -206,6 +206,6 @@
|
||||
|
||||
.session-badge-text {
|
||||
font-size: var(--tk-font-micro);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useState, useRef } from 'react';
|
||||
import { View, Text } from '@tarojs/components';
|
||||
import Taro, { useDidShow, usePullDownRefresh, useReachBottom } from '@tarojs/taro';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { listConsultations, ConsultationSession } from '@/services/consultation';
|
||||
import Loading from '../../components/Loading';
|
||||
import GuestGuard from '../../components/GuestGuard';
|
||||
import { useElderClass } from '../../hooks/useElderClass';
|
||||
import './index.scss';
|
||||
|
||||
@@ -31,6 +33,7 @@ function formatTime(iso: string): string {
|
||||
}
|
||||
|
||||
export default function Consultation() {
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const [sessions, setSessions] = useState<ConsultationSession[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
@@ -67,6 +70,7 @@ export default function Consultation() {
|
||||
|
||||
useDidShow(() => {
|
||||
Taro.setNavigationBarTitle({ title: '在线咨询' });
|
||||
if (!user) return;
|
||||
loadSessions(1, true);
|
||||
});
|
||||
|
||||
@@ -88,6 +92,9 @@ export default function Consultation() {
|
||||
|
||||
return (
|
||||
<View className={`consultation-page ${modeClass}`}>
|
||||
{!user ? (
|
||||
<GuestGuard title='请先登录' desc='登录后即可与医生在线交流' />
|
||||
) : (
|
||||
<View className='consultation-body'>
|
||||
{/* 副标题 */}
|
||||
<Text className='consultation-subtitle'>随时随地,连接专业医生</Text>
|
||||
@@ -165,6 +172,7 @@ export default function Consultation() {
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -66,8 +66,28 @@
|
||||
color: $card;
|
||||
font-size: var(--tk-font-micro);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
border-radius: $r-xs;
|
||||
flex-shrink: 0;
|
||||
|
||||
&--ai {
|
||||
background: $pri;
|
||||
}
|
||||
|
||||
&--alert {
|
||||
background: $dan;
|
||||
}
|
||||
|
||||
&--followup {
|
||||
background: $acc;
|
||||
}
|
||||
|
||||
&--anomaly {
|
||||
background: $wrn;
|
||||
}
|
||||
|
||||
&--default {
|
||||
background: $tx3;
|
||||
}
|
||||
}
|
||||
|
||||
.inbox-card-title {
|
||||
|
||||
@@ -19,11 +19,11 @@ const TYPE_LABEL: Record<string, string> = {
|
||||
data_anomaly: '异常',
|
||||
};
|
||||
|
||||
const TYPE_COLOR: Record<string, string> = {
|
||||
ai_suggestion: '#722ed1',
|
||||
alert: '#f5222d',
|
||||
followup: '#1890ff',
|
||||
data_anomaly: '#fa8c16',
|
||||
const TYPE_CLS: Record<string, string> = {
|
||||
ai_suggestion: 'inbox-type-tag--ai',
|
||||
alert: 'inbox-type-tag--alert',
|
||||
followup: 'inbox-type-tag--followup',
|
||||
data_anomaly: 'inbox-type-tag--anomaly',
|
||||
};
|
||||
|
||||
const STATUS_TABS = [
|
||||
@@ -151,10 +151,7 @@ export default function ActionInboxPage() {
|
||||
>
|
||||
<View className="inbox-card-header">
|
||||
<Text
|
||||
className="inbox-type-tag"
|
||||
style={{
|
||||
background: TYPE_COLOR[item.action_type] || '#999',
|
||||
}}
|
||||
className={`inbox-type-tag ${TYPE_CLS[item.action_type] || 'inbox-type-tag--default'}`}
|
||||
>
|
||||
{TYPE_LABEL[item.action_type] || '未知'}
|
||||
</Text>
|
||||
|
||||
@@ -94,5 +94,5 @@
|
||||
.submit-btn__text {
|
||||
font-size: var(--tk-font-num);
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
.record-header__status {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
font-size: var(--tk-font-body);
|
||||
background: $bd-l;
|
||||
color: $tx3;
|
||||
@@ -119,7 +119,7 @@
|
||||
background: $pri;
|
||||
|
||||
.action-btn__text {
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
&:active {
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
.type-tag {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
font-size: var(--tk-font-body);
|
||||
font-weight: 600;
|
||||
background: $pri-l;
|
||||
@@ -109,7 +109,7 @@
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
font-size: var(--tk-font-body);
|
||||
background: $bd-l;
|
||||
color: $tx3;
|
||||
@@ -189,6 +189,6 @@
|
||||
|
||||
.fab-text {
|
||||
font-size: var(--tk-font-hero);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background: $dan;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
text-align: center;
|
||||
line-height: 36px;
|
||||
font-weight: bold;
|
||||
@@ -132,8 +132,9 @@
|
||||
}
|
||||
|
||||
&__quick-actions {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
@@ -190,7 +191,7 @@
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
background: $dan;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-size: var(--tk-font-body-sm);
|
||||
font-weight: 700;
|
||||
border-radius: $r-pill;
|
||||
|
||||
@@ -138,3 +138,13 @@
|
||||
color: $tx2;
|
||||
}
|
||||
}
|
||||
|
||||
.load-more-hint-wrap {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.load-more-hint {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: $tx3;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ export default function PatientList() {
|
||||
<View
|
||||
key={tag.id}
|
||||
className={`tag-chip ${activeTag === tag.id ? 'active' : ''}`}
|
||||
style={activeTag === tag.id && tag.color ? `background: ${tag.color}; color: #fff` : ''}
|
||||
style={activeTag === tag.id && tag.color ? `background: ${tag.color}; color: white` : ''}
|
||||
onClick={() => handleTagFilter(tag.id)}
|
||||
>
|
||||
<Text>{tag.name}</Text>
|
||||
@@ -177,8 +177,8 @@ export default function PatientList() {
|
||||
)}
|
||||
|
||||
{!loading && patients.length >= total && total > 0 && (
|
||||
<View style={{ textAlign: 'center', padding: '20px' }}>
|
||||
<Text style={{ fontSize: '24px', color: '#78716C' }}>没有更多了</Text>
|
||||
<View className='load-more-hint-wrap'>
|
||||
<Text className='load-more-hint'>没有更多了</Text>
|
||||
</View>
|
||||
)}
|
||||
{loading && patients.length > 0 && <Loading />}
|
||||
|
||||
@@ -89,5 +89,5 @@
|
||||
.submit-btn__text {
|
||||
font-size: var(--tk-font-num);
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
.rx-header__status {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
font-size: var(--tk-font-body);
|
||||
background: $bd-l;
|
||||
color: $tx3;
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
font-size: var(--tk-font-body);
|
||||
background: $bd-l;
|
||||
color: $tx3;
|
||||
@@ -171,6 +171,6 @@
|
||||
|
||||
.fab-text {
|
||||
font-size: var(--tk-font-hero);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
.submit-btn-text {
|
||||
font-size: var(--tk-font-num);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
.vital-tab {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
border-radius: 12px;
|
||||
border-radius: $r-sm;
|
||||
background: $surface-alt;
|
||||
@include flex-center;
|
||||
position: relative;
|
||||
@@ -44,7 +44,7 @@
|
||||
box-shadow: 0 2px 8px rgba(196, 98, 58, 0.25);
|
||||
|
||||
.vital-tab-text {
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@
|
||||
height: 56px;
|
||||
background: $bg;
|
||||
border: 2px solid $bd;
|
||||
border-radius: 12px;
|
||||
border-radius: $r-sm;
|
||||
padding: 0 16px;
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-body-lg);
|
||||
@@ -121,7 +121,7 @@
|
||||
.period-btn {
|
||||
flex: 1;
|
||||
height: 48px;
|
||||
border-radius: 12px;
|
||||
border-radius: $r-sm;
|
||||
background: $surface-alt;
|
||||
@include flex-center;
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
background: $pri;
|
||||
|
||||
.period-btn-text {
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
.save-btn {
|
||||
width: 100%;
|
||||
height: 52px;
|
||||
border-radius: 14px;
|
||||
border-radius: $r-sm;
|
||||
background: $pri;
|
||||
@include flex-center;
|
||||
margin-top: 20px;
|
||||
@@ -162,7 +162,7 @@
|
||||
.save-btn-text {
|
||||
font-size: var(--tk-font-body-sm);
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
/* ─── 趋势图 ─── */
|
||||
@@ -199,7 +199,7 @@
|
||||
align-items: flex-end;
|
||||
height: 120px;
|
||||
background: $bg;
|
||||
border-radius: 12px;
|
||||
border-radius: $r-sm;
|
||||
padding: 12px 8px;
|
||||
gap: 0;
|
||||
position: relative;
|
||||
@@ -234,7 +234,7 @@
|
||||
|
||||
.trend-bar {
|
||||
width: 28px;
|
||||
border-radius: 6px 6px 0 0;
|
||||
border-radius: $r-xs $r-xs 0 0;
|
||||
min-height: 8px;
|
||||
opacity: 0.8;
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
.device-icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 12px;
|
||||
border-radius: $r-sm;
|
||||
background: $pri-l;
|
||||
@include flex-center;
|
||||
flex-shrink: 0;
|
||||
@@ -368,6 +368,18 @@
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.ai-risk-high {
|
||||
background: $dan;
|
||||
}
|
||||
|
||||
&.ai-risk-medium {
|
||||
background: $wrn;
|
||||
}
|
||||
|
||||
&.ai-risk-low {
|
||||
background: $acc;
|
||||
}
|
||||
}
|
||||
|
||||
.ai-suggestion-text {
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function Health() {
|
||||
const items = await listPendingSuggestions();
|
||||
setAiSuggestions(items.slice(0, 3));
|
||||
} catch {
|
||||
// 静默
|
||||
setAiSuggestions([]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -236,13 +236,13 @@ export default function Health() {
|
||||
<Text className='ai-card-count'>{aiSuggestions.length} 条待查看</Text>
|
||||
</View>
|
||||
{aiSuggestions.map((s) => {
|
||||
const riskColor = s.risk_level === 'high' ? '#ef4444' : s.risk_level === 'medium' ? '#f59e0b' : '#22c55e';
|
||||
const riskCls = s.risk_level === 'high' ? 'ai-risk-high' : s.risk_level === 'medium' ? 'ai-risk-medium' : 'ai-risk-low';
|
||||
const typeLabel = s.suggestion_type === 'followup' ? '随访' : s.suggestion_type === 'appointment' ? '预约' : '预警';
|
||||
const params = s.params as Record<string, unknown> | null;
|
||||
const reason = (params?.reason as string) || (params?.message as string) || typeLabel;
|
||||
return (
|
||||
<View key={s.id} className='ai-suggestion-item'>
|
||||
<View className='ai-risk-dot' style={{ background: riskColor }} />
|
||||
<View className={`ai-risk-dot ${riskCls}`} />
|
||||
<Text className='ai-suggestion-text'>{reason.slice(0, 40)}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
position: relative;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 22px;
|
||||
border-radius: $r-pill;
|
||||
background: $pri-l;
|
||||
@include flex-center;
|
||||
flex-shrink: 0;
|
||||
@@ -63,7 +63,7 @@
|
||||
right: 6px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
border-radius: $r-xs;
|
||||
background: $dan;
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
border-radius: $r;
|
||||
padding: 18px;
|
||||
margin-bottom: 16px;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.reminder-header {
|
||||
@@ -225,13 +225,13 @@
|
||||
.reminder-title {
|
||||
font-size: var(--tk-font-cap);
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.reminder-count {
|
||||
font-size: var(--tk-font-micro);
|
||||
opacity: 0.7;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.reminder-item {
|
||||
@@ -252,17 +252,17 @@
|
||||
.reminder-tag {
|
||||
font-size: var(--tk-font-micro);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
border-radius: $r-xs;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.reminder-text {
|
||||
font-size: var(--tk-font-cap);
|
||||
flex: 1;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -270,7 +270,7 @@
|
||||
|
||||
.reminder-arrow {
|
||||
opacity: 0.5;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
height: 52px;
|
||||
border-radius: 14px;
|
||||
border-radius: $r-sm;
|
||||
@include flex-center;
|
||||
|
||||
&:active {
|
||||
@@ -294,7 +294,7 @@
|
||||
|
||||
.action-primary {
|
||||
background: $pri;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
box-shadow: 0 2px 8px rgba(196, 98, 58, 0.25);
|
||||
}
|
||||
|
||||
@@ -376,7 +376,7 @@
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-h1);
|
||||
font-weight: 700;
|
||||
color: #FFFFFF;
|
||||
color: $white;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
@@ -495,5 +495,5 @@
|
||||
.guest-login-btn-text {
|
||||
font-size: var(--tk-font-h2);
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
.login-logo-mark {
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-hero);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
@@ -76,7 +76,7 @@
|
||||
width: 100%;
|
||||
height: $btn-primary-h;
|
||||
background: $pri;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-size: var(--tk-font-body-lg);
|
||||
font-weight: 600;
|
||||
border-radius: $r;
|
||||
@@ -123,7 +123,7 @@
|
||||
|
||||
.agreement-check-mark {
|
||||
font-size: var(--tk-font-body-sm);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
.checkin-btn-text {
|
||||
font-size: var(--tk-font-h2);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -61,9 +61,9 @@
|
||||
|
||||
.points-balance {
|
||||
@include serif-number;
|
||||
font-size: 72px; /* kept as-is: special display value */
|
||||
font-size: var(--tk-font-display);
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
letter-spacing: 2px;
|
||||
@@ -258,6 +258,6 @@
|
||||
|
||||
.empty-action-text {
|
||||
font-size: var(--tk-font-body-lg);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
right: 12px;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
background: $dan;
|
||||
@include flex-center;
|
||||
padding: 0 4px;
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
.msg-segment-badge-text {
|
||||
font-size: var(--tk-font-micro);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
.consult-avatar {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 22px;
|
||||
border-radius: $r-pill;
|
||||
background: $surface-alt;
|
||||
@include flex-center;
|
||||
flex-shrink: 0;
|
||||
@@ -183,7 +183,7 @@
|
||||
.consult-badge {
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 9px;
|
||||
border-radius: $r-pill;
|
||||
background: $dan;
|
||||
@include flex-center;
|
||||
padding: 0 4px;
|
||||
@@ -192,7 +192,7 @@
|
||||
|
||||
.consult-badge-text {
|
||||
font-size: var(--tk-font-micro);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -225,6 +225,23 @@
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.notify-type-appointment,
|
||||
.notify-type-points {
|
||||
background: $pri-l;
|
||||
color: $pri;
|
||||
}
|
||||
|
||||
.notify-type-alert {
|
||||
background: $wrn-l;
|
||||
color: $wrn;
|
||||
}
|
||||
|
||||
.notify-type-followup,
|
||||
.notify-type-report {
|
||||
background: $acc-l;
|
||||
color: $acc;
|
||||
}
|
||||
|
||||
.notify-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
@@ -263,7 +280,7 @@
|
||||
.notify-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
border-radius: $r-xs;
|
||||
background: $pri;
|
||||
flex-shrink: 0;
|
||||
margin-top: 6px;
|
||||
|
||||
@@ -245,7 +245,7 @@
|
||||
}
|
||||
|
||||
.dm-field-warning-low {
|
||||
color: #0284C7;
|
||||
color: $tx2;
|
||||
}
|
||||
|
||||
/* ── submit ── */
|
||||
|
||||
@@ -3,6 +3,8 @@ import { View, Text } from '@tarojs/components';
|
||||
import { useRouter } from '@tarojs/taro';
|
||||
import { useHealthStore } from '@/stores/health';
|
||||
import TrendChart from '@/components/TrendChart';
|
||||
import Loading from '@/components/Loading';
|
||||
import EmptyState from '@/components/EmptyState';
|
||||
import { useElderClass } from '../../../hooks/useElderClass';
|
||||
import './index.scss';
|
||||
|
||||
@@ -28,10 +30,15 @@ export default function Trend() {
|
||||
const indicator = router.params.indicator || 'heart_rate';
|
||||
const [range, setRange] = useState('7d');
|
||||
const [points, setPoints] = useState<{ date: string; value: number }[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { getTrend } = useHealthStore();
|
||||
|
||||
useEffect(() => {
|
||||
getTrend(indicator, range).then(setPoints);
|
||||
setLoading(true);
|
||||
getTrend(indicator, range)
|
||||
.then(setPoints)
|
||||
.catch(() => setPoints([]))
|
||||
.finally(() => setLoading(false));
|
||||
}, [indicator, range]);
|
||||
|
||||
const meta = INDICATOR_META[indicator] || { label: indicator, unit: '' };
|
||||
@@ -68,17 +75,27 @@ export default function Trend() {
|
||||
</View>
|
||||
|
||||
{/* ECharts 折线图 */}
|
||||
<View className='trend-chart-card'>
|
||||
<TrendChart
|
||||
data={points}
|
||||
referenceMin={meta.refMin}
|
||||
referenceMax={meta.refMax}
|
||||
unit={meta.unit}
|
||||
/>
|
||||
</View>
|
||||
{loading ? (
|
||||
<View className='trend-chart-card'>
|
||||
<Loading />
|
||||
</View>
|
||||
) : points.length === 0 ? (
|
||||
<View className='trend-chart-card'>
|
||||
<EmptyState text='暂无趋势数据' />
|
||||
</View>
|
||||
) : (
|
||||
<View className='trend-chart-card'>
|
||||
<TrendChart
|
||||
data={points}
|
||||
referenceMin={meta.refMin}
|
||||
referenceMax={meta.refMax}
|
||||
unit={meta.unit}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 参考区间 */}
|
||||
{meta.refMin !== undefined && meta.refMax !== undefined && (
|
||||
{!loading && points.length > 0 && meta.refMin !== undefined && meta.refMax !== undefined && (
|
||||
<View className='trend-ref-card'>
|
||||
<Text className='trend-ref-label'>参考区间</Text>
|
||||
<Text className='trend-ref-value'>
|
||||
|
||||
@@ -25,13 +25,25 @@
|
||||
@include flex-center;
|
||||
margin-right: 24px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&--physical {
|
||||
background: $acc;
|
||||
}
|
||||
|
||||
&--service {
|
||||
background: $pri;
|
||||
}
|
||||
|
||||
&--privilege {
|
||||
background: $pri-d;
|
||||
}
|
||||
}
|
||||
|
||||
.product-icon-char {
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-hero);
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.product-meta {
|
||||
|
||||
@@ -23,10 +23,10 @@ const TYPE_LABEL: Record<string, string> = {
|
||||
privilege: '权益卡',
|
||||
};
|
||||
|
||||
const TYPE_COLOR: Record<string, string> = {
|
||||
physical: '#5B7A5E',
|
||||
service: '#C4623A',
|
||||
privilege: '#8B3E1F',
|
||||
const TYPE_CLASS: Record<string, string> = {
|
||||
physical: 'product-icon-wrap--physical',
|
||||
service: 'product-icon-wrap--service',
|
||||
privilege: 'product-icon-wrap--privilege',
|
||||
};
|
||||
|
||||
export default function ExchangeConfirm() {
|
||||
@@ -130,16 +130,13 @@ export default function ExchangeConfirm() {
|
||||
const productType = product?.product_type || 'physical';
|
||||
const initial = TYPE_INITIAL[productType] || '礼';
|
||||
const typeLabel = TYPE_LABEL[productType] || '商品';
|
||||
const typeColor = TYPE_COLOR[productType] || '#C4623A';
|
||||
const iconCls = TYPE_CLASS[productType] || 'product-icon-wrap--service';
|
||||
|
||||
return (
|
||||
<View className={`exchange-page ${modeClass}`}>
|
||||
{/* 商品预览卡片 */}
|
||||
<View className='product-card'>
|
||||
<View
|
||||
className='product-icon-wrap'
|
||||
style={{ backgroundColor: typeColor }}
|
||||
>
|
||||
<View className={`product-icon-wrap ${iconCls}`}>
|
||||
<Text className='product-icon-char'>{initial}</Text>
|
||||
</View>
|
||||
<View className='product-meta'>
|
||||
|
||||
@@ -79,11 +79,26 @@
|
||||
}
|
||||
|
||||
.order-status-tag {
|
||||
@include tag(transparent, $tx3);
|
||||
padding: 4px 16px;
|
||||
border-radius: $r-pill;
|
||||
margin-left: 12px;
|
||||
flex-shrink: 0;
|
||||
|
||||
&--pending {
|
||||
@include tag($wrn-l, $wrn);
|
||||
}
|
||||
|
||||
&--verified {
|
||||
@include tag($acc-l, $acc);
|
||||
}
|
||||
|
||||
&--cancelled {
|
||||
@include tag($dan-l, $dan);
|
||||
}
|
||||
|
||||
&--expired {
|
||||
@include tag($bd-l, $tx3);
|
||||
}
|
||||
}
|
||||
|
||||
.order-status-text {
|
||||
|
||||
@@ -15,11 +15,11 @@ const STATUS_TABS = [
|
||||
{ key: 'expired', label: '已过期' },
|
||||
];
|
||||
|
||||
const STATUS_CONFIG: Record<string, { label: string; tagBg: string; tagColor: string }> = {
|
||||
pending: { label: '待核销', tagBg: '#FFF3E0', tagColor: '#C4873A' },
|
||||
verified: { label: '已核销', tagBg: '#E8F0E8', tagColor: '#5B7A5E' },
|
||||
cancelled: { label: '已取消', tagBg: '#FDEAEA', tagColor: '#B54A4A' },
|
||||
expired: { label: '已过期', tagBg: '#F0EBE5', tagColor: '#A8A29E' },
|
||||
const STATUS_CONFIG: Record<string, { label: string; cls: string }> = {
|
||||
pending: { label: '待核销', cls: 'order-status-tag--pending' },
|
||||
verified: { label: '已核销', cls: 'order-status-tag--verified' },
|
||||
cancelled: { label: '已取消', cls: 'order-status-tag--cancelled' },
|
||||
expired: { label: '已过期', cls: 'order-status-tag--expired' },
|
||||
};
|
||||
|
||||
export default function MallOrders() {
|
||||
@@ -102,7 +102,7 @@ export default function MallOrders() {
|
||||
};
|
||||
|
||||
const getStatusConfig = (status: string) => {
|
||||
return STATUS_CONFIG[status] || { label: status, tagBg: '#F0EBE5', tagColor: '#A8A29E' };
|
||||
return STATUS_CONFIG[status] || { label: status, cls: 'order-status-tag--expired' };
|
||||
};
|
||||
|
||||
const formatDate = (dateStr: string) => {
|
||||
@@ -144,8 +144,7 @@ export default function MallOrders() {
|
||||
<View className='order-header'>
|
||||
<Text className='order-product'>商品 {order.product_id.slice(0, 8)}</Text>
|
||||
<View
|
||||
className='order-status-tag'
|
||||
style={{ background: statusCfg.tagBg, color: statusCfg.tagColor }}
|
||||
className={`order-status-tag ${statusCfg.cls}`}
|
||||
>
|
||||
<Text className='order-status-text'>{statusCfg.label}</Text>
|
||||
</View>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
font-size: var(--tk-font-body);
|
||||
font-weight: 500;
|
||||
background: $bd-l;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
.status-tag {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: $r-xs;
|
||||
font-size: var(--tk-font-body);
|
||||
font-weight: 500;
|
||||
background: $bd-l;
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 13px;
|
||||
background: #fff;
|
||||
background: $card;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
.submit-text {
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-num);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
}
|
||||
|
||||
.family-current-tag {
|
||||
@include tag($pri, #fff);
|
||||
@include tag($pri, $white);
|
||||
font-size: var(--tk-font-body-sm);
|
||||
padding: 2px 10px;
|
||||
}
|
||||
@@ -124,7 +124,7 @@
|
||||
.family-add-text {
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-num);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
padding-bottom: 160px;
|
||||
}
|
||||
|
||||
.medication-loading {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.medication-loading-text {
|
||||
color: $tx3;
|
||||
font-size: var(--tk-font-h1);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
@include section-title;
|
||||
padding-left: 4px;
|
||||
@@ -99,7 +109,7 @@
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
background: $card;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
transition: left 0.3s;
|
||||
@@ -217,7 +227,7 @@
|
||||
|
||||
.form-confirm-text {
|
||||
font-size: var(--tk-font-body-lg);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -235,7 +245,7 @@
|
||||
.add-text {
|
||||
font-family: 'Georgia', 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-num);
|
||||
color: #fff;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ export default function MedicationReminder() {
|
||||
return (
|
||||
<View className={`medication-page ${modeClass}`}>
|
||||
<Text className='page-title'>用药提醒</Text>
|
||||
<View style={{ padding: '40px 0', textAlign: 'center' }}>
|
||||
<Text style={{ color: '#94A3B8', fontSize: '28px' }}>加载中...</Text>
|
||||
<View className='medication-loading'>
|
||||
<Text className='medication-loading-text'>加载中...</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
.profile-avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 30px;
|
||||
border-radius: $r-pill;
|
||||
background: linear-gradient(135deg, $pri-l 0%, $pri 100%);
|
||||
@include flex-center;
|
||||
flex-shrink: 0;
|
||||
@@ -33,7 +33,7 @@
|
||||
font-family: Georgia, 'Times New Roman', serif;
|
||||
font-size: var(--tk-font-body-lg);
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.profile-user-info {
|
||||
@@ -128,7 +128,8 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 14px 16px;
|
||||
padding: 16px;
|
||||
min-height: 48px;
|
||||
position: relative;
|
||||
|
||||
&:active {
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
font-size: var(--tk-font-h2);
|
||||
font-weight: bold;
|
||||
padding: 4px 12px;
|
||||
border-radius: 16px;
|
||||
border-radius: $r;
|
||||
|
||||
&.normal {
|
||||
color: $tx3;
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
height: $btn-primary-h;
|
||||
border-radius: $r;
|
||||
background: $pri;
|
||||
color: #FFFFFF;
|
||||
color: $white;
|
||||
font-size: var(--tk-font-body-lg);
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
// 正常模式 Token
|
||||
// ═══════════════════════════════════════
|
||||
page {
|
||||
// ─── 字号(10 级,覆盖 92.5% 场景)───
|
||||
// ─── 字号(11 级,覆盖 92.5% 场景)───
|
||||
--tk-font-display: 72px; // 大型装饰数值(积分余额、空状态图标)
|
||||
--tk-font-hero: 48px; // 装饰图标、空状态字符
|
||||
--tk-font-h1: 26px; // 页面/区块标题
|
||||
--tk-font-h2: 24px; // 副标题、日期、菜单组
|
||||
@@ -31,6 +32,7 @@ page {
|
||||
// 标题 ×1.15 / 正文 ×1.35 / 辅助 ×1.55
|
||||
// ═══════════════════════════════════════
|
||||
.elder-mode {
|
||||
--tk-font-display: 80px;
|
||||
--tk-font-hero: 56px;
|
||||
--tk-font-h1: 30px;
|
||||
--tk-font-h2: 28px;
|
||||
|
||||
@@ -10,6 +10,7 @@ $acc: #5B7A5E; // 鼠尾草绿 (success)
|
||||
$acc-l: #E8F0E8; // 成功浅
|
||||
$bg: #F5F0EB; // 主背景 (warm cream)
|
||||
$card: #FFFFFF; // 卡片白
|
||||
$white: #FFFFFF; // 纯白(文字/图标在彩色底上)
|
||||
$surface-alt: #EDE8E2; // 辅助底
|
||||
$tx: #2D2A26; // 主文字 (warm black)
|
||||
$tx2: #5A554F; // 次文字 (warm gray) — AA 正文对比度 ~5.5:1
|
||||
|
||||
Reference in New Issue
Block a user