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 @@
{{ banner.tag }}
{{ banner.title }}
- 点击立即参与 ⚡
+ 点击立即参与
@@ -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('❌');
+ }
+ });
+ });
+});