/**
* 规范摘要模块
*
* 提供完整的规范要点,用于代码生成时的强制约束
* 这些规则会被注入到代码生成的 prompt 中,确保 AI 严格遵循
*
* ⚠️ 重要:此文件的规则必须与 data/standards 目录下的规范文档保持同步
*
* 规范来源:
* - 01-project: naming.md, structure.md, version-detection.md
* - 02-vue: basic.md, component.md, examples.md, performance.md, state-management.md
* - 03-css: index.md
* - 04-api: ajax.md, ejs-api.md, util.md
* - 05-typescript: index.md
* - 06-mock: index.md
* - 07-router: index.md
*/
/**
* 核心规范要点 - 必须严格遵循
* 来源:data/standards/01-project 至 data/standards/07-router
*/
export const CORE_STANDARDS = {
// ============================================================
// 01-project: 项目规范
// ============================================================
naming: {
title: '命名规范 (01-project/naming.md)',
rules: [
'页面 Vue 文件:小写字母 + 数字 + 下划线,如 user_list.vue',
'通用组件:PascalCase(大驼峰),如 UserCard.vue',
'变量/函数:camelCase(小驼峰),如 userName, getUserInfo()',
'常量:UPPER_SNAKE_CASE,如 MAX_COUNT, API_BASE_URL',
'模块目录:小写字母 + 下划线,如 user_center',
'图片资源:img_ 前缀 + 描述,如 img_logo.png',
'图标资源:icon_ 前缀 + 描述,如 icon_home.svg',
'禁止使用中文、特殊字符命名文件',
'禁止使用 var 声明变量,优先 const,需重新赋值时用 let',
],
},
structure: {
title: '项目结构规范 (01-project/structure.md)',
rules: [
'页面组件放置在 src/pages/[module_name]/ 下',
'样式文件必须放置在 css/ 子目录,如 css/[module_name].scss',
'静态资源放置在 static/[module_name]/ 下',
'每个模块必须包含:[page].vue, css/[module].scss, router.js',
'可选文件:store.js/store.ts, mock.js, images/',
'Vue 文件中禁止直接编写 CSS 代码,必须使用 @import 引入',
'必须添加 scoped 属性限制样式作用域',
],
},
// ============================================================
// 02-vue: Vue 开发规范
// ============================================================
vue: {
title: 'Vue 基础规范 (02-vue/basic.md)',
rules: [
'缩进使用 4 个空格,禁止使用 tab',
'每行不超过 120 个字符',
'console.log 必须包含描述信息,禁止空 console.log()',
'console 代码与其他逻辑之间需有空行',
'优先使用 const,仅在需要重新赋值时使用 let,禁止使用 var',
'禁止使用废弃标签:<font>, <center>, <b>, <i>',
'禁止使用废弃属性:align, valign, bgcolor, width/height(非img)',
],
},
fileHeader: {
title: '文件头部注释规范 (02-vue/basic.md)',
template: `<!--
* @作者: [作者名]
* @创建时间: [YYYY-MM-DD HH:mm:ss]
* @修改时间: [YYYY-MM-DD HH:mm:ss]
* @版本: [1.0]
* @版权: 国泰新点软件股份有限公司
* @描述: [页面功能描述]
-->`,
rules: [
'每个 Vue 文件必须包含头部注释',
'头部注释位于文件最顶部,<template> 标签之前',
'所有字段都是必填项:@作者、@创建时间、@修改时间、@版本、@版权、@描述',
'@版权 固定为:国泰新点软件股份有限公司',
'@创建时间/@修改时间 格式:YYYY-MM-DD HH:mm:ss',
],
},
codeComment: {
title: '代码注释规范 (02-vue/basic.md)',
rules: [
'变量注释必须使用中文,如:// 用户名',
'函数上方必须有注释说明功能和参数',
'TODO 格式:// TODO: 待办内容(标记人,时间)',
'删除代码时必须说明原因:// 已删除:原因说明',
'禁止保留无说明的注释代码',
],
},
globalVars: {
title: '全局变量使用规范 (02-vue/basic.md)',
rules: [
'❌ 禁止 import { Config } from "@shared",直接使用 Config',
'❌ 禁止 import { Util } from "@shared",直接使用 Util',
'❌ 禁止 import { ejs } from "@shared",直接使用 ejs',
'✅ Config.serverUrl 获取服务器地址',
'✅ Util.ajax() 发起网络请求',
'✅ Util.string.isMobile() 验证手机号',
'✅ Util.string.isEmail() 验证邮箱',
'✅ Util.string.isIdCard() 验证身份证',
'✅ Util.uuid() 生成唯一标识',
'✅ ejs.ui.toast() 显示提示信息',
'✅ ejs.ui.showWaiting() / ejs.ui.closeWaiting() 加载提示',
'✅ ejs.page.open() 页面跳转',
'✅ ejs.page.close() 关闭页面',
],
},
component: {
title: '组件使用规范 (02-vue/component.md)',
rules: [
'em-field readonly 状态必须同时添加 is-link 和 clickable 属性',
'em-field textarea 类型必须添加 :autosize="{ minHeight: 24 }" 属性',
'em-field 输入框必须添加 placeholder 属性',
'em-button 表单提交必须使用 native-type="submit"(非 form-type)',
'em-radio 使用插槽显示文字:<em-radio name="value">文字</em-radio>',
'⚠️ em-radio/em-checkbox/em-switch 等在 em-field 中必须使用 #input 插槽包裹',
'⚠️ em-uploader/em-stepper/em-rate/em-slider 在 em-field 中必须使用 #input 插槽包裹',
'em-picker 必须添加 show-toolbar 属性',
'Props 必须指定类型和默认值',
'禁止直接修改 props,使用 emit 通知父组件',
'优先使用 EJS API 而非组件(如日期选择用 ejs.ui.pickDate)',
'⚠️ 表单校验 validator 函数必须定义在 methods/script 中,不能在模板中直接使用全局变量',
],
},
vue3: {
title: 'Vue3 特定规范 (02-vue/component.md)',
rules: [
'必须使用 <script setup> 语法',
'使用 TypeScript 时添加 lang="ts"',
'使用 defineProps 和 withDefaults 定义 Props',
'使用 defineEmits 定义事件',
'使用 ref() 和 reactive() 定义响应式数据',
'非渲染数据不需要响应式(如常量、定时器引用)',
'样式穿透使用 :deep(.class) 语法',
'获取路由参数使用 onLoad((options) => {})',
],
},
vue2: {
title: 'Vue2 特定规范 (02-vue/component.md)',
rules: [
'使用 Options API',
'data 必须是返回对象的函数',
'Props 使用对象形式定义,包含 type 和 default',
'数组和对象的 default 必须是工厂函数:() => []',
'样式穿透使用 ::v-deep .class 语法',
'获取路由参数使用 Util.getExtraDataByKey()',
],
},
// ============================================================
// 03-css: CSS 规范
// ============================================================
css: {
title: 'CSS/SCSS 规范 (03-css/index.md)',
rules: [
'使用 BEM 命名规范:block__element--modifier',
'class/id 使用小写字母 + 中划线,禁止驼峰和大写',
'样式文件放在 css/ 目录下',
'使用 @import 引入样式文件',
'添加 scoped 属性限制样式作用域',
'颜色值简写:#666666 → #666',
'0 值不加单位:margin: 0',
'避免深层嵌套(不超过 3 层)',
'禁止使用 !important(除非覆盖第三方库)',
'禁止使用标签选择器和通配符选择器',
'CSS 书写顺序:位置属性 → 大小属性 → 文字属性 → 背景边框 → 其他',
],
},
// ============================================================
// 04-api: API 规范
// ============================================================
api: {
title: 'API 调用规范 (04-api/ajax.md)',
rules: [
'使用 Util.ajax() 发起请求,禁止使用 fetch 或 axios',
'url 使用 Config.serverUrl + 接口路径',
'data 中的复杂参数使用 JSON.stringify()',
'使用 dataPath: "custom" 指定数据路径',
'必须处理错误情况(catch)',
'请求前显示 ejs.ui.showWaiting(),完成后 ejs.ui.closeWaiting()',
'文件上传使用 Util.upload()',
],
},
ejsApi: {
title: 'EJS API 规范 (04-api/ejs-api.md)',
rules: [
'优先使用 EJS API 而非组件',
'消息提示:ejs.ui.toast()',
'确认对话框:ejs.ui.confirm()',
'加载提示:ejs.ui.showWaiting() / ejs.ui.closeWaiting()',
'日期选择:ejs.ui.pickDate()',
'时间选择:ejs.ui.pickTime()',
'日期时间选择:ejs.ui.pickDateTime()',
'页面跳转:ejs.page.open()',
'同模块跳转:ejs.page.open("./路由名称")',
'跨模块跳转:ejs.page.open("../模块名称/路由名称")',
],
},
util: {
title: 'Util 工具规范 (04-api/util.md)',
rules: [
'禁止 import Util,直接使用',
'手机号验证:Util.string.isMobile(str)',
'固定电话验证:Util.string.isTel(str)',
'电话验证(手机+固话):Util.string.isPhone(str)',
'邮箱验证:Util.string.isEmail(str)',
'邮政编码验证:Util.string.isPostCode(str)',
'身份证验证:Util.string.isIdCard(str)',
'组织机构代码验证:Util.string.isOrgCode(str)',
'生成 UUID:Util.uuid()',
'Cookie 操作:Util.cookie.set/get/remove()',
'网络请求:Util.ajax(options)',
'文件上传:Util.upload(options)',
'获取页面传参(Vue2):Util.getExtraDataByKey(key)',
],
},
// ============================================================
// 06-mock: Mock 规范
// ============================================================
mock: {
title: 'Mock 数据规范 (06-mock/index.md)',
rules: [
'使用 import Mock from "@mock" 导入',
'mock.js 放在模块目录下',
'resultData 必须是数组格式',
'methodUrl 格式:/rest/api/[module]/[action]',
'output 使用 Mock.mock() 包装',
'status 结构:{ code: 1, text: "成功" }(code 为 1 代表成功)',
'业务数据直接平铺或放在 custom 字段中',
'数组生成语法:"infolist|10-20": [{}]',
'常用方法:Mock.Random.guid(), cname(), csentence(), date(), integer(), image()',
'❌ 禁止使用 Mock.Random.mobile()(不存在此方法)',
'✅ 手机号生成方式:使用字符串模板 "1" + Mock.Random.string("number", 10)',
'✅ 或使用正则模式:/^1[3-9]\\d{9}$/',
],
},
// ============================================================
// 07-router: 路由规范
// ============================================================
router: {
title: '路由规范 (07-router/index.md)',
rules: [
'router.js 放在模块目录下',
'router.js 中无需 import 组件',
'routes 必须是数组格式',
'path 必须与 vue 文件名对应',
'有效参数仅 path 和 style',
'path 格式:pages/[module_name]/[page_name]',
'style.navigationBarTitleText 设置导航栏标题',
'分包配置:options.autoSubPackages = true',
],
},
// ============================================================
// 05-typescript: TypeScript 规范
// ============================================================
typescript: {
title: 'TypeScript 规范 (05-typescript/index.md)',
rules: [
'必须显式声明变量类型',
'❌ 禁止使用 any 类型,使用 unknown 或具体类型',
'接口命名:PascalCase + I 前缀,如 IUserInfo',
'类型命名:PascalCase + T 前缀,如 TStatus',
'优先使用 interface 而非 type(支持扩展和合并)',
'❌ 避免使用 enum,使用 const 对象 + as const',
'Props 必须配合接口定义类型',
'使用 Partial、Required、Pick、Omit 等工具类型',
],
},
// ============================================================
// 版本检测规范
// ============================================================
versionDetection: {
title: '版本检测规范 (01-project/version-detection.md)',
rules: [
'⚠️ 生成代码前必须确认 Vue 版本',
'检查 package.json 中 vue 依赖版本',
'vue ^2.x.x → Vue2 Options API',
'vue ^3.x.x → Vue3 Composition API + <script setup>',
'Vue2 样式穿透:::v-deep .class',
'Vue3 样式穿透::deep(.class)',
'Vue2 状态管理:Vuex (store.js)',
'Vue3 状态管理:Pinia (store.ts)',
'Vue2 获取路由参数:Util.getExtraDataByKey(key)',
'Vue3 获取路由参数:onLoad((options) => {})',
],
},
// ============================================================
// 性能优化规范
// ============================================================
performance: {
title: '性能优化规范 (02-vue/performance.md)',
rules: [
'频繁切换使用 v-show,条件很少改变使用 v-if',
'使用 computed 替代 methods 调用(有缓存)',
'适当使用 keep-alive 缓存组件',
'非关键组件使用动态加载 defineAsyncComponent',
'图片使用 WebP 格式并启用懒加载',
'避免深层嵌套(CSS 不超过 3 层)',
],
},
// ============================================================
// 状态管理规范
// ============================================================
stateManagement: {
title: '状态管理规范 (02-vue/state-management.md)',
rules: [
'Vue2 使用 Vuex,Vue3 使用 Pinia',
'Store 文件放在对应模块目录下',
'Vuex 必须使用 namespaced: true',
'Pinia Store 命名:use + 模块名 + Store',
'优先使用 props/emit,避免滥用全局状态',
'使用 getter 获取派生状态',
'变量和方法必须添加中文注释',
],
},
};
/**
* 生成完整的规范检查清单
* 用于代码生成后的自检
*/
export function generateChecklist(vueVersion?: "2" | "3"): string {
let checklist = `
## ✅ M8 代码规范检查清单
### 01-project 项目规范
- [ ] 页面 Vue 文件使用小写 + 下划线命名(如 user_list.vue)
- [ ] 通用组件使用 PascalCase 命名(如 UserCard.vue)
- [ ] 变量/函数使用 camelCase,常量使用 UPPER_SNAKE_CASE
- [ ] 禁止使用 var,优先 const,需重新赋值时用 let
- [ ] 样式文件放在 css/ 子目录
- [ ] 图片资源使用 img_ 前缀
### 02-vue Vue 规范
- [ ] 文件顶部包含完整的头部注释(@作者、@创建时间、@修改时间、@版本、@版权、@描述)
- [ ] 使用 4 空格缩进,每行不超过 120 字符
- [ ] console.log 必须包含描述信息
- [ ] 变量有中文注释说明
- [ ] 全局变量(Config、Util、ejs)直接使用,禁止 import
`;
if (vueVersion === "3" || !vueVersion) {
checklist += `- [ ] Vue3 使用 <script setup> 语法
- [ ] TypeScript 显式声明类型
- [ ] 使用 defineProps 和 withDefaults
- [ ] 使用 Pinia 进行状态管理
`;
}
if (vueVersion === "2" || !vueVersion) {
checklist += `- [ ] Vue2 使用 Options API
- [ ] data 必须是返回对象的函数
- [ ] Props 指定类型和默认值
- [ ] 使用 Vuex 进行状态管理
`;
}
checklist += `- [ ] readonly 输入框添加 is-link 和 clickable 属性
- [ ] 优先使用 EJS API 而非组件
### ⚠️ 表单组件特殊规范
- [ ] em-radio/em-checkbox/em-switch 在 em-field 中使用 #input 插槽包裹
- [ ] em-uploader/em-stepper/em-rate/em-slider 在 em-field 中使用 #input 插槽包裹
- [ ] 表单校验 validator 函数定义在 methods/script 中,不在模板中直接使用 Util
### 03-css CSS 规范
- [ ] 使用 BEM 命名规范(block__element--modifier)
- [ ] class 使用小写字母 + 中划线
`;
if (vueVersion === "3" || !vueVersion) {
checklist += `- [ ] 样式穿透使用 :deep(.class)\n`;
}
if (vueVersion === "2" || !vueVersion) {
checklist += `- [ ] 样式穿透使用 ::v-deep .class\n`;
}
checklist += `- [ ] 遵循 CSS 书写顺序(位置→大小→文字→背景边框→其他)
- [ ] 避免使用 !important
- [ ] 嵌套不超过 3 层
### 04-api API 规范
- [ ] 使用 Util.ajax() 发起请求,禁止使用 fetch 或 axios
- [ ] url 使用 Config.serverUrl + 接口路径
- [ ] 请求参数使用 JSON.stringify()
- [ ] 必须处理错误情况(catch)
- [ ] 请求前后使用 ejs.ui.showWaiting/closeWaiting
- [ ] 优先使用 EJS API(toast、confirm、pickDate 等)
### 05-typescript TypeScript 规范
- [ ] 显式声明变量类型
- [ ] 未使用 any 类型
- [ ] 接口使用 I 前缀,类型使用 T 前缀
- [ ] 使用常量对象替代枚举
### 06-mock Mock 规范
- [ ] mock.js 放在模块目录下
- [ ] resultData 为数组格式
- [ ] 使用 import Mock from '@mock'
- [ ] methodUrl 格式:/rest/api/[module]/[action]
- [ ] output 使用 Mock.mock() 包装
- [ ] ❌ 未使用 Mock.Random.mobile()(不存在此方法)
- [ ] ✅ 手机号使用 '1' + Mock.Random.string('number', 10) 生成
### 07-router 路由规范
- [ ] router.js 放在模块目录下
- [ ] routes 为数组格式
- [ ] path 与 vue 文件名匹配
- [ ] 未在 router.js 中 import 组件
`;
return checklist;
}