원클릭으로
y-sso-frontend-standards
强制遵循Y-SSO前端开发规范:Vue组件规范、CSS变量使用、BEM命名、导入顺序、文件结构等。仅在修改 frontend/src/ 目录下文件时调用。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
强制遵循Y-SSO前端开发规范:Vue组件规范、CSS变量使用、BEM命名、导入顺序、文件结构等。仅在修改 frontend/src/ 目录下文件时调用。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | y-sso-frontend-standards |
| description | 强制遵循Y-SSO前端开发规范:Vue组件规范、CSS变量使用、BEM命名、导入顺序、文件结构等。仅在修改 frontend/src/ 目录下文件时调用。 |
必须调用此技能当:
d:\www\web\aicode\y-sso-system\frontend\src\ 目录下的任何文件建议调用此技能当:
src/
├── api/ # API接口定义
├── assets/ # 静态资源
├── components/ # 通用组件
│ ├── common/ # 基础组件 (BaseButton.vue)
│ ├── layout/ # 布局组件 (AppHeader.vue)
│ └── business/ # 业务组件 (UserProfile.vue)
├── pages/ # 页面组件(核心目录)
├── styles/ # 样式文件(核心目录)
│ ├── base/ # 基础样式 (variables.css)
│ ├── components/ # 组件样式
│ ├── layout/ # 布局样式
│ ├── pages/ # 页面样式
│ └── utilities/ # 工具类
├── utils/ # 工具函数
└── stores/ # 状态管理
| 文件类型 | 放置位置 | 命名规范 | 示例 |
|---|---|---|---|
| 页面文件 | pages/业务目录/ | kebab-case | user-create.vue |
| 通用组件 | components/common/ | PascalCase | BaseButton.vue |
| 业务组件 | components/business/ | PascalCase | UserProfile.vue |
| 样式文件 | styles/对应分类/ | kebab-case | buttons.css |
| 工具函数 | utils/ | camelCase | formatDate.js |
<template>
<!-- 语义化HTML标签优先 -->
<div class="组件名">
<!-- 内容区域 -->
</div>
</template>
<script setup>
// 1. Vue内置API
import { ref, computed, onMounted } from 'vue'
// 2. 第三方库
import { ElMessage } from 'element-plus'
// 3. 内部组件
import BaseButton from '@/components/common/BaseButton.vue'
// 4. 工具函数和API
import { userApi } from '@/api'
import { formatDate } from '@/utils/format'
// 5. 状态管理
import { useAuthStore } from '@/stores/auth'
// Props定义(必须)
const props = defineProps({
// 明确定义每个prop的类型和验证
})
// Emits定义(必须)
const emit = defineEmits(['success', 'error'])
// 状态变量
const loading = ref(false)
const data = ref(null)
// 计算属性
const isValid = computed(() => {
return data.value && data.value.length > 0
})
// 生命周期
onMounted(() => {
fetchData()
})
// 方法定义
const fetchData = async () => {
loading.value = true
try {
const response = await userApi.getList()
data.value = response.data
} catch (error) {
ElMessage.error('获取数据失败')
} finally {
loading.value = false
}
}
</script>
<!-- 样式部分:尽量省略 -->
<style scoped>
/* 仅当必须时添加,且使用CSS变量 */
.组件名 {
padding: var(--spacing-lg);
}
</style>
<script setup>语法styles/目录中添加样式文件styles/base/目录中,创建新的公共样式/* 颜色变量 */
color: var(--primary);
background-color: var(--light-gray);
/* 间距变量 */
margin: var(--spacing-md);
padding: var(--card-padding);
/* 字体变量 */
font-size: var(--font-size-lg);
line-height: var(--line-height);
:root {
/* 主色调 */
--primary: 72, 190, 206;
--secondary: 139, 132, 118;
--success: 174, 204, 52;
--danger: 229, 94, 64;
--warning: 235, 195, 63;
--info: 83, 90, 231;
/* 中性色 */
--light: 229, 227, 224;
--dark: 72, 68, 61;
--white: #ffffff;
/* 背景色 */
--bodybg-color: #f9f9f9;
--light-gray: #f4f7f8;
/* 间距 */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
/* 组件间距 */
--card-padding: 1.5rem;
--section-margin: 1.5rem;
}
必须使用预定义的字体变量,禁止硬编码字体大小和字重
| 变量名 | 值 | 使用场景 |
|---|---|---|
--el-font-size-xxl | 22px | 大标题、数字展示 |
--el-font-size-xl | 20px | 页面主标题 |
--el-font-size-lg | 18px | 卡片标题、重要信息 |
--el-font-size-md | 16px | 小标题、强调文本 |
--el-font-size-base | 14px | 正文、默认文本 |
--el-font-size-sm | 13px | 辅助文本、描述信息 |
--el-font-size-xs | 12px | 标签、提示信息 |
| 变量名 | 值 | 使用场景 |
|---|---|---|
--el-font-weight-extra-bold | 600 | 标题、强调 |
--el-font-weight-bold | 500 | 半粗体、标签 |
--el-font-weight-medium | 400 | 正常文本 |
--el-font-weight-regular | 300 | 轻量文本 |
| 变量名 | 值 | 使用场景 |
|---|---|---|
--c-line-height-xs | 1 | 紧凑布局 |
--c-line-height-sm | 1.2 | 标题、短文本 |
--c-line-height-md | 1.4 | 正文、段落 |
--c-line-height-lg | 1.6 | 宽松文本 |
--c-line-height-xl | 2 | 大段文字、阅读模式 |
/* ✅ 正确:使用CSS变量 */
.card-title {
font-size: var(--el-font-size-lg);
font-weight: var(--el-font-weight-extra-bold);
line-height: var(--c-line-height-sm);
}
.text-secondary {
font-size: var(--el-font-size-xs);
color: var(--el-text-color-secondary);
}
/* ❌ 错误:硬编码值 */
.card-title {
font-size: 18px;
font-weight: 600;
line-height: 1.4;
}
.text-secondary {
font-size: 12px;
color: #909399;
}
所有字体变量定义在 src/styles/themes.css 中:
/* ===== 字体大小 ===== */
--el-font-size-xxl: 22px;
--el-font-size-xl: 20px;
--el-font-size-lg: 18px;
--el-font-size-md: 16px;
--el-font-size-base: 14px;
--el-font-size-sm: 13px;
--el-font-size-xs: 12px;
/* ===== 字体权重变量 ===== */
--el-font-weight-extra-bold: 600;
--el-font-weight-bold: 500;
--el-font-weight-medium: 400;
--el-font-weight-regular: 300;
/* ===== 行高变量 ===== */
--c-line-height-xs: 1;
--c-line-height-sm: 1.2;
--c-line-height-md: 1.4;
--c-line-height-lg: 1.6;
--c-line-height-xl: 2;
/* Block(块) */
.user-card {}
/* Element(元素) */
.user-card__header {}
.user-card__content {}
/* Modifier(修饰符) */
.user-card--primary {}
.user-card--large {}
:deep() 选择器:对于 Element Plus 组件,使用 :deep() 进行样式穿透:deep() 选择器,避免全局样式冲突/* Element Plus 表格样式 */
.data-card :deep(.el-table) {
background-color: var(--white);
border: none;
border-radius: var(--app-border-radius);
}
.data-card :deep(.el-table thead th) {
background-color: var(--light-gray);
border-bottom: 1px solid var(--border_color);
color: var(--font-color);
font-size: var(--font-size-sm);
}
// 1. Vue内置API
import { ref, computed, watch, onMounted } from 'vue'
// 2. 第三方库
import { ElMessage, ElLoading } from 'element-plus'
// 3. 内部组件
import BaseButton from '@/components/common/BaseButton.vue'
import BaseCard from '@/components/common/BaseCard.vue'
// 4. 工具函数和API
import { userApi } from '@/api'
import { formatDate, validatePhone } from '@/utils/format'
// 5. 状态管理
import { useAuthStore } from '@/stores/auth'
import { useUserStore } from '@/stores/user'
必须使用 @/ 路径别名导入项目内部模块,禁止相对路径导入
| 导入类型 | 正确写法 ✅ | 错误写法 ❌ |
|---|---|---|
| API | import { userApi } from '@/api' | import { userApi } from '../api' |
| 组件 | import BaseButton from '@/components/common/BaseButton.vue' | import BaseButton from '../../components/common/BaseButton.vue' |
| 工具函数 | import { formatDate } from '@/utils/format' | import { formatDate } from '../utils/format' |
| Store | import { useAuthStore } from '@/stores/auth' | import { useAuthStore } from '../stores/auth' |
优势:
../../../ 这种难以维护的相对路径配置说明:
vite.config.js 中已配置 @ 别名指向 src 目录:
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
}
// 1. Props定义
const props = defineProps({...})
// 2. Emits定义
const emit = defineEmits([...])
// 3. 状态变量
const loading = ref(false)
const data = ref(null)
// 4. 计算属性
const isValid = computed(() => {...})
// 5. 监听器
watch(data, (newVal) => {...})
// 6. 生命周期钩子
onMounted(() => {...})
// 7. 方法定义
const handleSubmit = async () => {...}
' 或反引号 `,避免使用双引号 "const 或 let,避免使用 var| 类型 | 规范 | 示例 |
|---|---|---|
| 变量/函数 | camelCase | userName, fetchData |
| 常量 | UPPER_SNAKE_CASE | API_BASE_URL |
| 类/构造函数 | PascalCase | UserService |
| 布尔值 | is/has/can前缀 | isActive, hasPermission |
async/await 处理异步操作try {
const response = await apiCall()
// 处理成功响应
} catch (error) {
ElMessage.error(getErrorMessage(error, '操作失败'))
} finally {
loading.value = false
}
Element Plus 组件使用规范已独立到单独文件,详见 element-plus-components.md。
核心原则:
:deep() 选择器进行样式穿透.el-xxx 类名!important!important(极端情况除外).el-xxx类名的样式userName和user-name混用)data、item、component)在修改 frontend/src/ 目录下的文件时,必须检查:
<script setup>语法?简洁、一致、可维护
Enforce form validation before submit. Validate first, return early on failure, and only then run the async submit logic inside try/catch so validation errors aren’t swallowed and misreported.
强制遵循Element Plus开发规范:使用CSS变量而非硬编码值、不修改组件自带样式、不使用内联样式、使用标准CSS类和scoped样式。在涉及Element Plus样式修改时必须调用此技能。
一站式 UI/UX 优化专家,自动执行完整的设计优化流程。Invoke when user wants comprehensive UI/UX improvements, full page optimization, or 'make this look professional'.
Set up and run end-to-end (E2E) tests for web applications using Playwright. Invoke when user wants to create E2E tests, set up testing framework, or run automated browser tests.
YWeb DDD 分层架构与 API 设计规范。在创建或修改 API 路由、Service 层、领域模型、DTO 时使用。涵盖瘦 API 原则、服务层拆分、Model 设计、DTO 转换、响应格式等。
YWeb ORM 使用规范。在编写数据库模型定义、CRUD 操作、查询过滤、分页、软删除、事务管理、批量操作、关系定义等数据层代码时使用。基于 SQLAlchemy 的 Active Record 模式。