diff --git a/docs/UIUX设计系统与约束规范文档.md b/docs/UIUX设计系统与约束规范文档.md index d22340a..d3b0440 100644 --- a/docs/UIUX设计系统与约束规范文档.md +++ b/docs/UIUX设计系统与约束规范文档.md @@ -9,11 +9,11 @@ ### 1.1 风格定位:Cyber-Esports Dark Elegance(暗夜流光电竞风) - **核心气质**:高端电竞质感、沉浸式互动、年轻潮酷、信息轻盈清晰。 - **避免的设计反模式(Anti-Patterns to Avoid)**: - - ❌ 杜绝花哨刺眼的廉价荧光大撞色; - - ❌ 杜绝使用任何系统 Emoji 代替产品功能操作图标(全部采用统一风格的矢量 SVG 图标); - - ❌ 杜绝点击无反馈或延迟过长(点击态需在 100ms 内给予 0.98 缩放或透明度微反馈); - - ❌ 杜绝按钮或卡片按压时引起页面排版位移(Layout Shift / CLS 必须 < 0.1); - - ❌ 杜绝纯依靠单一颜色传递状态(成功/失败/在线必须辅以图标或文字辅助标签)。 + - [严禁] 杜绝花哨刺眼的廉价荧光大撞色; + - [严禁] 杜绝使用任何系统 Emoji 代替产品功能操作图标(全部采用统一风格的矢量 SVG 图标); + - [严禁] 杜绝点击无反馈或延迟过长(点击态需在 100ms 内给予 0.98 缩放或透明度微反馈); + - [严禁] 杜绝按钮或卡片按压时引起页面排版位移(Layout Shift / CLS 必须 < 0.1); + - [严禁] 杜绝纯依靠单一颜色传递状态(成功/失败/在线必须辅以图标或文字辅助标签)。 --- diff --git a/pwuniapp/common/icons.js b/pwuniapp/common/icons.js index 31116db..fbd06d0 100644 --- a/pwuniapp/common/icons.js +++ b/pwuniapp/common/icons.js @@ -207,5 +207,21 @@ export const ICONS = { + `), + + female: svgToUri(` + + + + + + `), + + male: svgToUri(` + + + + + `) }; diff --git a/pwuniapp/pages/index/index.vue b/pwuniapp/pages/index/index.vue index 0a233c3..a8dd074 100644 --- a/pwuniapp/pages/index/index.vue +++ b/pwuniapp/pages/index/index.vue @@ -33,7 +33,7 @@ @@ -106,7 +106,9 @@ {{ expert.nickname }} - {{ expert.gender === 'female' ? '♀' : '♂' }} + + + {{ expert.rankTag }} @@ -540,17 +542,23 @@ const navTo = (url) => { } .gender-tag { - font-size: 20rpx; - padding: 2rpx 8rpx; + width: 32rpx; + height: 32rpx; border-radius: 8rpx; + display: inline-flex; + align-items: center; + justify-content: center; &.female { background: rgba(236, 72, 153, 0.2); - color: #F472B6; } &.male { background: rgba(59, 130, 246, 0.2); - color: #60A5FA; + } + + .gender-svg { + width: 20rpx; + height: 20rpx; } } } diff --git a/server/tests/no-emoji.spec.ts b/server/tests/no-emoji.spec.ts new file mode 100644 index 0000000..e71d19c --- /dev/null +++ b/server/tests/no-emoji.spec.ts @@ -0,0 +1,74 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +describe('UI/UX 规范门禁 (TDD 测试套件: 全面杜绝系统 Emoji)', () => { + const rootDir = path.resolve(__dirname, '../../'); + const uniPagesDir = path.join(rootDir, 'pwuniapp', 'pages'); + const docsDir = path.join(rootDir, 'docs'); + + // 严格 Emoji 正则:匹配所有系统 Emoji、符号表情及特殊 Pictographic 字符 + const emojiRegex = /(?:\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u2600-\u27BF])/u; + + function getAllFiles(dir: string, extFilter: string[]): string[] { + if (!fs.existsSync(dir)) return []; + let results: string[] = []; + const list = fs.readdirSync(dir); + for (const item of list) { + const fullPath = path.join(dir, item); + const stat = fs.statSync(fullPath); + if (stat.isDirectory()) { + results = results.concat(getAllFiles(fullPath, extFilter)); + } else if (extFilter.some(ext => item.endsWith(ext))) { + results.push(fullPath); + } + } + return results; + } + + describe('1. 首页 (index.vue) 杜绝系统 Emoji 校验', () => { + it('首页横幅与卡片中不应含有 ⚡ 或任何系统 Emoji', () => { + const indexVuePath = path.join(uniPagesDir, 'index', 'index.vue'); + const content = fs.readFileSync(indexVuePath, 'utf-8'); + + // 验证不包含 ⚡ 闪电 Emoji + expect(content).not.toContain('⚡'); + + // 验证不包含裸写的 ♀ / ♂ 字符(防止系统字体回退为彩色系统 Emoji) + expect(content).not.toContain('♀'); + expect(content).not.toContain('♂'); + }); + }); + + describe('2. 前端 pages 目录下所有页面全局无 Emoji 校验', () => { + it('所有 .vue 页面组件模板与文本中严禁包含任何 Emoji 字符', () => { + const vueFiles = getAllFiles(uniPagesDir, ['.vue']); + const violations: { file: string; line: number; text: string }[] = []; + + for (const file of vueFiles) { + const content = fs.readFileSync(file, 'utf-8'); + const lines = content.split('\n'); + lines.forEach((line, idx) => { + if (emojiRegex.test(line)) { + violations.push({ + file: path.relative(rootDir, file), + line: idx + 1, + text: line.trim() + }); + } + }); + } + + expect(violations).toEqual([]); + }); + }); + + describe('3. UIUX 约束规范文档纯净度校验', () => { + it('设计规范文档中严禁使用 ❌ 系统 Emoji', () => { + const docFiles = getAllFiles(docsDir, ['.md']); + for (const file of docFiles) { + const content = fs.readFileSync(file, 'utf-8'); + expect(content).not.toContain('❌'); + } + }); + }); +});