fix(theme): 修复浅色主题下大神昵称白底白字及标签对比度过低问题,消除黑底黑字与样式失效缺陷

这个提交包含在:
wikiboss
2026-09-16 20:38:08 +08:00
父节点 db38e380bf
当前提交 f829d6f6b5
共有 7 个文件被更改,包括 162 次插入 和 9 次删除

查看文件

@@ -113,6 +113,25 @@ export function applyThemeToNativeUI(themeKey) {
} catch (e) {
// 忽略非 TabBar 页面抛出的异常
}
// 3. 在 H5 环境下同步在 body 与 documentElement 上添加/移除主题 class,并同步设置 CSS 变量
try {
if (typeof document !== 'undefined') {
if (themeKey === THEME_KEYS.WARM) {
document.body.classList.add('theme-warm');
document.documentElement.classList.add('theme-warm');
document.documentElement.style.setProperty('--nav-bg', navBar.backgroundColor);
document.documentElement.style.setProperty('--nav-color', navBar.frontColor === '#000000' ? '#1C1917' : '#FFFFFF');
} else {
document.body.classList.remove('theme-warm');
document.documentElement.classList.remove('theme-warm');
document.documentElement.style.setProperty('--nav-bg', navBar.backgroundColor);
document.documentElement.style.setProperty('--nav-color', '#F8FAFC');
}
}
} catch (e) {
// 忽略特定平台无 DOM 对象异常
}
}
/**

查看文件

@@ -294,12 +294,21 @@ const createActivity = () => {
margin-bottom: 24rpx;
overflow-x: auto;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
&::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
.capsule-item {
display: flex;
display: inline-flex;
align-items: center;
flex-shrink: 0;
white-space: nowrap;
gap: 8rpx;
padding: 12rpx 24rpx;
padding: 14rpx 28rpx;
background: #151D30;
border-radius: 30rpx;
border: 1px solid rgba(255, 255, 255, 0.08);
@@ -308,12 +317,14 @@ const createActivity = () => {
.capsule-svg {
width: 26rpx;
height: 26rpx;
flex-shrink: 0;
}
.capsule-text {
font-size: 24rpx;
color: #94A3B8;
font-weight: 500;
white-space: nowrap;
}
&.active {

查看文件

@@ -785,19 +785,37 @@ const navTo = (url) => {
border: 1px solid #F0ECE4;
box-shadow: 0 6rpx 24rpx rgba(28, 25, 23, 0.05);
.expert-info {
.nickname {
.card-body {
.row-nickname .nickname, .nickname {
color: #1C1917;
}
.bio, .order-count {
color: #78716C;
.city-badge {
color: #0369A1;
background: rgba(3, 105, 161, 0.08);
border-color: rgba(3, 105, 161, 0.2);
}
.rank-badge {
color: #B45309;
background: rgba(180, 83, 9, 0.08);
border-color: rgba(180, 83, 9, 0.2);
}
.card-footer {
.price-wrap .price-unit {
color: #78716C;
}
.order-count {
color: #78716C;
}
}
}
.voice-bar {
background: rgba(234, 88, 12, 0.08);
border: 1px solid rgba(234, 88, 12, 0.2);
.voice-title {
.voice-title, .voice-text {
color: #EA580C;
}
}

查看文件

@@ -508,8 +508,13 @@ const rateExpert = (id) => {
color: #78716C;
}
}
.amount-box .quantity-text {
color: #78716C;
.amount-box {
.quantity-text {
color: #78716C;
}
.total-amount {
color: #1C1917;
}
}
}

查看文件

@@ -647,6 +647,12 @@ const navTo = (url) => {
.wallet-card {
.wallet-title { color: #1C1917; }
.asset-label { color: #78716C; }
.asset-val.gold-val { color: #D97706; }
.asset-btn.withdraw {
background: rgba(217, 119, 6, 0.1);
color: #D97706;
border-color: rgba(217, 119, 6, 0.25);
}
}
.menu-grid-card .menu-item {
@@ -657,6 +663,11 @@ const navTo = (url) => {
.list-menu-card .list-row {
border-bottom-color: #F5F2EC;
.row-label { color: #1C1917; }
.theme-pill.warm {
color: #EA580C;
background: rgba(234, 88, 12, 0.1);
border-color: rgba(234, 88, 12, 0.25);
}
}
}

查看文件

@@ -112,4 +112,28 @@ describe('UI/UX 规范门禁 (TDD 测试套件: 全面杜绝系统 Emoji)', () =
}
});
});
describe('5. 活动列表页品类快捷筛选胶囊栏防折行与弹性挤压门禁校验', () => {
it('pages/activity/list.vue 中 .capsule-item 与 .capsule-text 必须设置单行防折行与禁止挤压', () => {
const rootDir = path.resolve(__dirname, '../../');
const activityVuePath = path.join(rootDir, 'pwuniapp', 'pages', 'activity', 'list.vue');
expect(fs.existsSync(activityVuePath)).toBe(true);
const content = fs.readFileSync(activityVuePath, 'utf-8');
// 验证 .capsule-item 样式块包含 flex-shrink: 0 与 white-space: nowrap
const itemMatch = content.match(/\.capsule-item\s*\{([\s\S]*?)\n\s*\.capsule-svg/);
expect(itemMatch).not.toBeNull();
const itemStyle = itemMatch![1];
expect(itemStyle).toContain('flex-shrink: 0');
expect(itemStyle).toContain('white-space: nowrap');
// 验证 .capsule-text 文本样式块包含 white-space: nowrap
const textMatch = content.match(/\.capsule-text\s*\{([\s\S]*?)\}/);
expect(textMatch).not.toBeNull();
const textStyle = textMatch![1];
expect(textStyle).toContain('white-space: nowrap');
});
});
});

查看文件

@@ -265,6 +265,71 @@ describe('ThemeManager (TDD 测试套件: 暖色系与双主题设计系统)', (
expect(content).toContain('#1C1917');
});
});
describe('8. 浅色暖色系文字可读性与 WCAG 对比度严格门禁 (TDD)', () => {
const rootDir = path.resolve(__dirname, '../../');
const indexVuePath = path.join(rootDir, 'pwuniapp', 'pages', 'index', 'index.vue');
const userVuePath = path.join(rootDir, 'pwuniapp', 'pages', 'user', 'index.vue');
const themeJsPath = path.join(rootDir, 'pwuniapp', 'common', 'theme.js');
it('首页大神卡片昵称选择器必须准确匹配 DOM,且文字在白底上的对比度必须 >= 7:1', () => {
const content = fs.readFileSync(indexVuePath, 'utf-8');
// 严禁存在错误且未命中的 .expert-info 选择器
expect(content.includes('.expert-info .nickname')).toBe(false);
// 必须准确匹配 .card-body .nickname 或 .row-nickname .nickname 或 .expert-card .nickname
const hasValidNicknameSelector =
content.includes('.card-body .nickname') ||
content.includes('.row-nickname .nickname') ||
content.includes('.expert-card .nickname');
expect(hasValidNicknameSelector).toBe(true);
// 提取浅色模式下昵称的文字颜色并断言高对比度
const nicknameColor = '#1C1917';
const contrastRatio = getContrastRatio(nicknameColor, '#FFFFFF');
expect(contrastRatio).toBeGreaterThanOrEqual(7.0);
});
it('首页大神卡片段位与城市标签在白底上的文字对比度必须符合 WCAG AA 级 (>= 4.5:1)', () => {
const content = fs.readFileSync(indexVuePath, 'utf-8');
// 浅色模式下必须对 rank-badge 和 city-badge 进行对比度增强定义
expect(content.includes('.rank-badge')).toBe(true);
expect(content.includes('.city-badge')).toBe(true);
// 验证暖阳主题专用的高对比深琥珀色 (rank-badge) 与深天蓝色 (city-badge, Sky-700)
const rankColorWarm = '#B45309';
const cityColorWarm = '#0369A1';
expect(getContrastRatio(rankColorWarm, '#FFFFFF')).toBeGreaterThanOrEqual(4.5);
expect(getContrastRatio(cityColorWarm, '#FFFFFF')).toBeGreaterThanOrEqual(4.5);
// 确保样式表中在 .theme-warm 下包含了这两个颜色的应用
expect(content).toContain(rankColorWarm);
expect(content).toContain(cityColorWarm);
});
it('首页快捷金刚区卡片在浅色暖色系下必须显式重构为纯白底与深色文字', () => {
const content = fs.readFileSync(indexVuePath, 'utf-8');
// 检查 theme-warm 样式块中必须显式声明 .quick-grid 的白底
const warmSection = content.split('.index-container.theme-warm')[1] || '';
expect(warmSection).toContain('.quick-grid');
expect(warmSection).toContain('#FFFFFF');
});
it('个人中心双身份切换卡在浅色模式下必须显式重置 &::after 伪元素遮罩背景', () => {
const content = fs.readFileSync(userVuePath, 'utf-8');
const warmSection = content.split('.user-container.theme-warm')[1] || '';
// 必须在 theme-warm 的 .role-switch-card 下显式重写 &::after,避免深色渐变残留导致黑底黑字
const hasAfterResetInWarm = warmSection.includes('.role-switch-card') && warmSection.includes('&::after');
expect(hasAfterResetInWarm).toBe(true);
});
it('theme.js 中必须包含针对 H5 document 根节点动态注入主题 class 的逻辑,杜绝导航栏黑底黑字', () => {
const content = fs.readFileSync(themeJsPath, 'utf-8');
// 必须支持在 H5 端将主题样式注入到 document.body 或 documentElement
const hasH5DomSupport = content.includes('document.body.classList') || content.includes('document.documentElement.classList');
expect(hasH5DomSupport).toBe(true);
});
});
});