@qilitt-mickey/vue3-temp-skill 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +229 -0
- package/SKILL.md +621 -0
- package/bin/cli.js +579 -0
- package/package.json +46 -0
- package/references/advanced-ui.md +302 -0
- package/references/api-check.md +272 -0
- package/references/base-code-dict.md +48 -0
- package/references/build-optim.md +282 -0
- package/references/code-quality.md +235 -0
- package/references/crud-pages.md +316 -0
- package/references/data-compare.md +501 -0
- package/references/data-mapping.md +213 -0
- package/references/data-screen.md +79 -0
- package/references/data-writeback.md +104 -0
- package/references/detail-page.md +99 -0
- package/references/directives-advanced.md +93 -0
- package/references/download-export.md +68 -0
- package/references/feedback-loading.md +60 -0
- package/references/feedback-ui.md +111 -0
- package/references/file-management.md +132 -0
- package/references/flowchart-g6.md +244 -0
- package/references/form-advanced.md +137 -0
- package/references/graph-relation.md +253 -0
- package/references/http-api.md +188 -0
- package/references/layout-theme.md +540 -0
- package/references/mobile-h5.md +271 -0
- package/references/permission-auth.md +235 -0
- package/references/project-inventory.md +326 -0
- package/references/qrcode-barcode.md +92 -0
- package/references/rich-text.md +73 -0
- package/references/seamless-scroll.md +38 -0
- package/references/tree-table.md +111 -0
- package/references/ui-components.md +161 -0
- package/references/verify-captcha.md +96 -0
- package/references/vue-core.md +209 -0
- package/references/websocket-realtime.md +176 -0
- package/references/workflow-bpmn.md +206 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: build-optim
|
|
3
|
+
description: 规范 Vite 构建配置、代码分割策略、性能优化手段和开发工具链(ESLint、Stylelint、Commitlint)。在修改构建配置或优化工具链时调用。
|
|
4
|
+
scope: project
|
|
5
|
+
tags: [vue3, vite, build, optimization, eslint, stylelint, commitlint, husky, performance]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 构建优化与工程化配置
|
|
9
|
+
|
|
10
|
+
## Vite 构建配置
|
|
11
|
+
|
|
12
|
+
### 核心配置
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// vite.config.ts
|
|
16
|
+
import { defineConfig } from "vite";
|
|
17
|
+
import vue from "@vitejs/plugin-vue";
|
|
18
|
+
import UnoCSS from "unocss/vite";
|
|
19
|
+
import { resolve } from "path";
|
|
20
|
+
|
|
21
|
+
export default defineConfig({
|
|
22
|
+
plugins: [
|
|
23
|
+
vue(),
|
|
24
|
+
UnoCSS(),
|
|
25
|
+
// 自动导入:Element Plus / Vant 组件按需引入
|
|
26
|
+
AutoImport({
|
|
27
|
+
imports: ["vue", "vue-router", "pinia"],
|
|
28
|
+
dts: "src/auto-imports.d.ts",
|
|
29
|
+
}),
|
|
30
|
+
Components({
|
|
31
|
+
resolvers: [
|
|
32
|
+
ElementPlusResolver(),
|
|
33
|
+
VantResolver(),
|
|
34
|
+
],
|
|
35
|
+
dts: "src/components.d.ts",
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
resolve: {
|
|
40
|
+
alias: {
|
|
41
|
+
"@": resolve(__dirname, "src"),
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
build: {
|
|
46
|
+
target: "es2020",
|
|
47
|
+
minify: "oxc",
|
|
48
|
+
sourcemap: false,
|
|
49
|
+
|
|
50
|
+
rollupOptions: {
|
|
51
|
+
output: {
|
|
52
|
+
// 手动分包
|
|
53
|
+
manualChunks: {
|
|
54
|
+
"vue-vendor": ["vue", "vue-router", "pinia"],
|
|
55
|
+
"ui-vendor": ["element-plus"],
|
|
56
|
+
"chart-vendor": ["echarts"],
|
|
57
|
+
},
|
|
58
|
+
// 产物目录结构
|
|
59
|
+
chunkFileNames: "assets/js/[name]-[hash].js",
|
|
60
|
+
entryFileNames: "assets/js/[name]-[hash].js",
|
|
61
|
+
assetFileNames: "assets/[ext]/[name]-[hash].[ext]",
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
// 代码分割阈值
|
|
66
|
+
chunkSizeWarningLimit: 1000,
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// 开发服务器
|
|
70
|
+
server: {
|
|
71
|
+
port: 8848,
|
|
72
|
+
host: true,
|
|
73
|
+
proxy: {
|
|
74
|
+
"/api": {
|
|
75
|
+
target: "http://localhost:8080",
|
|
76
|
+
changeOrigin: true,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 构建约定
|
|
84
|
+
|
|
85
|
+
1. 使用 Vite 8.x(基于 Rolldown 构建引擎),不要使用 Webpack 相关配置。
|
|
86
|
+
2. `manualChunks` 必须将 Vue 生态、UI 库、图表库分开打包。
|
|
87
|
+
3. 压缩使用 `oxc`(Oxc 编译器),不使用 terser。
|
|
88
|
+
4. 生产环境关闭 `sourcemap`。
|
|
89
|
+
5. 静态资源按类型分目录输出(js/css/img/font)。
|
|
90
|
+
6. 单个 chunk 超过 1000KB 时发出警告。
|
|
91
|
+
|
|
92
|
+
## 代码分割策略
|
|
93
|
+
|
|
94
|
+
### 路由级懒加载
|
|
95
|
+
|
|
96
|
+
所有页面组件必须使用动态 `import()` 懒加载:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// 正确
|
|
100
|
+
component: () => import("@/views/system/user/index.vue")
|
|
101
|
+
|
|
102
|
+
// 错误(会导致首屏加载全部页面)
|
|
103
|
+
component: SystemUser
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 大型库按需引入
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// ECharts 按需引入
|
|
110
|
+
import * as echarts from "echarts/core";
|
|
111
|
+
import { BarChart, LineChart, PieChart } from "echarts/charts";
|
|
112
|
+
import { GridComponent, TooltipComponent, TitleComponent } from "echarts/components";
|
|
113
|
+
import { CanvasRenderer } from "echarts/renderers";
|
|
114
|
+
|
|
115
|
+
echarts.use([
|
|
116
|
+
BarChart, LineChart, PieChart,
|
|
117
|
+
GridComponent, TooltipComponent, TitleComponent,
|
|
118
|
+
CanvasRenderer,
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
// 或者使用完整引入(仅在确实需要全部图表类型时)
|
|
122
|
+
// import * as echarts from "echarts";
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 分包建议
|
|
126
|
+
|
|
127
|
+
| 分包名 | 包含内容 | 预估大小 |
|
|
128
|
+
|--------|---------|---------|
|
|
129
|
+
| vue-vendor | vue, vue-router, pinia | ~150KB |
|
|
130
|
+
| ui-vendor | element-plus | ~300KB(按需引入后更小) |
|
|
131
|
+
| chart-vendor | echarts | ~400KB(按需引入后更小) |
|
|
132
|
+
| editor-vendor | wangeditor | ~200KB |
|
|
133
|
+
| workflow-vendor | bpmn-js | ~500KB |
|
|
134
|
+
|
|
135
|
+
## UnoCSS 配置
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// uno.config.ts
|
|
139
|
+
import { defineConfig, presetWind3, presetAttributify, presetRemToPx } from "unocss";
|
|
140
|
+
|
|
141
|
+
export default defineConfig({
|
|
142
|
+
presets: [
|
|
143
|
+
presetWind3(), // Tailwind Wind 兼容
|
|
144
|
+
presetAttributify(), // 属性化模式
|
|
145
|
+
presetRemToPx(), // rem 转 px(适配移动端)
|
|
146
|
+
],
|
|
147
|
+
shortcuts: {
|
|
148
|
+
"flex-center": "flex items-center justify-center",
|
|
149
|
+
"flex-between": "flex items-center justify-between",
|
|
150
|
+
"card-base": "rounded-lg bg-white p-4 shadow-sm",
|
|
151
|
+
},
|
|
152
|
+
safelist: [
|
|
153
|
+
// 动态类名需要加入 safelist
|
|
154
|
+
"text-red-500", "text-green-500", "text-blue-500",
|
|
155
|
+
],
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 代码质量工具链
|
|
160
|
+
|
|
161
|
+
### 工具分工
|
|
162
|
+
|
|
163
|
+
| 工具 | 职责 | 配置文件 |
|
|
164
|
+
|------|------|---------|
|
|
165
|
+
| oxlint | 高速 lint 检查(替代部分 ESLint 规则) | `oxlintrc.json` |
|
|
166
|
+
| ESLint | 代码规范(@antfu/eslint-config) | `eslint.config.ts` |
|
|
167
|
+
| Stylelint | CSS/SCSS 规范 | `stylelint.config.js` |
|
|
168
|
+
| Prettier | 代码格式化 | `prettier.config.js` |
|
|
169
|
+
| Husky | Git Hooks 管理 | `.husky/` |
|
|
170
|
+
| Commitlint | 提交信息规范 | `commitlint.config.js` |
|
|
171
|
+
|
|
172
|
+
### ESLint 配置
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// eslint.config.ts
|
|
176
|
+
import antfu from "@antfu/eslint-config";
|
|
177
|
+
|
|
178
|
+
export default antfu({
|
|
179
|
+
unocss: true,
|
|
180
|
+
vue: true,
|
|
181
|
+
typescript: true,
|
|
182
|
+
rules: {
|
|
183
|
+
"no-console": "warn",
|
|
184
|
+
"no-debugger": "error",
|
|
185
|
+
"vue/no-v-html": "off",
|
|
186
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Stylelint 配置
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
// stylelint.config.js
|
|
195
|
+
export default {
|
|
196
|
+
extends: [
|
|
197
|
+
"stylelint-config-standard-scss",
|
|
198
|
+
"stylelint-config-recess-order",
|
|
199
|
+
],
|
|
200
|
+
rules: {
|
|
201
|
+
"selector-class-pattern": null, // 允许 BEM / kebab-case
|
|
202
|
+
"no-descending-specificity": null,
|
|
203
|
+
"scss/at-mixin-pattern": null,
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Commitlint 规范
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
// commitlint.config.js
|
|
212
|
+
export default {
|
|
213
|
+
extends: ["@commitlint/config-conventional"],
|
|
214
|
+
rules: {
|
|
215
|
+
"type-enum": [2, "always", [
|
|
216
|
+
"feat", // 新功能
|
|
217
|
+
"fix", // 修复
|
|
218
|
+
"docs", // 文档
|
|
219
|
+
"style", // 格式
|
|
220
|
+
"refactor", // 重构
|
|
221
|
+
"perf", // 性能
|
|
222
|
+
"test", // 测试
|
|
223
|
+
"chore", // 构建/工具
|
|
224
|
+
"revert", // 回退
|
|
225
|
+
]],
|
|
226
|
+
"subject-case": [0],
|
|
227
|
+
"subject-max-length": [2, "always", 100],
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Husky Git Hooks
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# .husky/pre-commit
|
|
236
|
+
npx oxlint --fix
|
|
237
|
+
npx lint-staged
|
|
238
|
+
|
|
239
|
+
# .husky/commit-msg
|
|
240
|
+
npx commitlint --edit "$1"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### lint-staged 配置
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
// package.json
|
|
247
|
+
{
|
|
248
|
+
"lint-staged": {
|
|
249
|
+
"*.{vue,ts,tsx,js,jsx}": ["eslint --fix"],
|
|
250
|
+
"*.{css,scss,vue}": ["stylelint --fix"],
|
|
251
|
+
"*.{vue,ts,tsx,js,jsx,css,scss,json,md}": ["prettier --write"]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 工具链约定
|
|
257
|
+
|
|
258
|
+
1. oxlint 负责高速检查,ESLint 负责深度规范,两者互补不冲突。
|
|
259
|
+
2. 提交前自动运行 `oxlint --fix` + `lint-staged`。
|
|
260
|
+
3. 提交信息必须遵循 Conventional Commits 格式:`type(scope): description`。
|
|
261
|
+
4. 不要在代码中使用 `// eslint-disable`,除非有充分理由并附注释说明。
|
|
262
|
+
5. Stylelint 检查 SCSS 和 `<style>` 块中的样式。
|
|
263
|
+
|
|
264
|
+
## 性能优化清单
|
|
265
|
+
|
|
266
|
+
1. 路由懒加载:所有页面组件使用 `() => import()`。
|
|
267
|
+
2. 组件按需引入:Element Plus / Vant 通过 `unplugin-vue-components` 自动导入。
|
|
268
|
+
3. 图片优化:使用 `van-image` 的 `lazy-load` 属性,大屏图片使用 WebP 格式。
|
|
269
|
+
4. 虚拟滚动:超过 1000 行的列表使用 `vxe-table` 的虚拟滚动。
|
|
270
|
+
5. 请求去重:http 封装内置请求去重,相同请求自动取消前一个。
|
|
271
|
+
6. 组件缓存:使用 `<keep-alive>` 缓存频繁切换的页面组件。
|
|
272
|
+
7. 第三方库按需引入:ECharts、lodash 等只引入使用到的模块。
|
|
273
|
+
8. 预加载:关键资源使用 `<link rel="preload">`,非关键资源使用 `<link rel="prefetch">`。
|
|
274
|
+
|
|
275
|
+
## 常见反例
|
|
276
|
+
|
|
277
|
+
- 页面组件不使用懒加载,直接 `import` 静态引入。
|
|
278
|
+
- ECharts 完整引入而不按需导入(增加 400KB+ 体积)。
|
|
279
|
+
- 构建配置中使用 `terser` 而不是 `oxc`(Vite 8 推荐 Oxc)。
|
|
280
|
+
- 没有配置 `manualChunks`,所有依赖打成一个巨大 chunk。
|
|
281
|
+
- 跳过 Git Hooks 直接提交代码(`--no-verify`)。
|
|
282
|
+
- 在代码中大量使用 `eslint-disable` 注释。
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill: code-quality
|
|
3
|
+
description: AI 生成代码的质量审查清单。在生成或修改任何 Vue/TypeScript 代码后,必须对照此清单逐项自查,确保代码符合项目规范。适用于代码审查、AI 代码自检、Code Review 场景。
|
|
4
|
+
scope: project
|
|
5
|
+
tags: [code-review, quality, checklist, lint, typescript, vue3, security, performance]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 代码质量审查清单
|
|
9
|
+
|
|
10
|
+
> **使用说明**:在 AI 生成或修改代码后,逐项对照以下检查点。任何一项不通过,必须修正后再输出。此清单面向"小白"开发者,确保 AI 产出的代码能通过团队 Code Review。
|
|
11
|
+
|
|
12
|
+
## 一、TypeScript 类型检查
|
|
13
|
+
|
|
14
|
+
### 必须通过
|
|
15
|
+
|
|
16
|
+
- [ ] 所有 `props` 有明确的类型定义,不使用 `any`。
|
|
17
|
+
- [ ] 所有 API 返回值声明了泛型类型 `Result<T>`。
|
|
18
|
+
- [ ] `ref()` 和 `reactive()` 声明了类型:`ref<string>("")`、`reactive<FormType>({})`。
|
|
19
|
+
- [ ] 事件处理函数声明了参数类型:`(e: Event)`、`(row: UserInfo)`。
|
|
20
|
+
- [ ] 组件 `defineProps` 使用泛型方式 `defineProps<Props>()`,不使用运行时声明。
|
|
21
|
+
- [ ] 不使用 `@ts-ignore` 或 `@ts-nocheck`,除非有注释说明原因。
|
|
22
|
+
- [ ] 类型定义放在 `type.ts` 或 `types/` 目录,不内联在组件中。
|
|
23
|
+
|
|
24
|
+
### 常见错误示例
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// ❌ 错误:使用 any
|
|
28
|
+
const data = ref<any>(null);
|
|
29
|
+
const list = ref([]); // 推断为 any[]
|
|
30
|
+
|
|
31
|
+
// ✅ 正确:明确类型
|
|
32
|
+
const data = ref<UserInfo | null>(null);
|
|
33
|
+
const list = ref<UserListItem[]>([]);
|
|
34
|
+
|
|
35
|
+
// ❌ 错误:API 无返回类型
|
|
36
|
+
function getList(params) {
|
|
37
|
+
return http.request("post", url, { data: params });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ✅ 正确:声明完整类型
|
|
41
|
+
function getListApi(params: ListQuery): Promise<Result<ListResult>> {
|
|
42
|
+
return http.request<Result<ListResult>>("post", url, { data: params });
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 二、Vue 组件规范检查
|
|
47
|
+
|
|
48
|
+
### 必须通过
|
|
49
|
+
|
|
50
|
+
- [ ] 使用 `<script setup lang="ts">`,不使用 Options API。
|
|
51
|
+
- [ ] 使用 `defineOptions({ name: "ComponentName" })` 声明组件名。
|
|
52
|
+
- [ ] `script` 标签第一行是 `import type { ... } from "./type"`。
|
|
53
|
+
- [ ] Props 和 Emits 类型定义在同目录 `type.ts` 文件中。
|
|
54
|
+
- [ ] 样式使用 `<style lang="scss" scoped>`。
|
|
55
|
+
- [ ] 组件 class 名使用 `re-` 前缀(自定义组件)或有意义的业务前缀。
|
|
56
|
+
- [ ] 没有硬编码中文文案(应使用 `$t()` 或配置化)。
|
|
57
|
+
|
|
58
|
+
### 常见错误示例
|
|
59
|
+
|
|
60
|
+
```vue
|
|
61
|
+
<!-- ❌ 错误:Options API -->
|
|
62
|
+
<script>
|
|
63
|
+
export default {
|
|
64
|
+
data() { return { count: 0 } },
|
|
65
|
+
methods: { increment() { this.count++ } }
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<!-- ✅ 正确:Composition API + script setup -->
|
|
70
|
+
<script setup lang="ts">
|
|
71
|
+
import type { MyComponentProps } from "./type";
|
|
72
|
+
defineOptions({ name: "MyComponent" });
|
|
73
|
+
const props = defineProps<MyComponentProps>();
|
|
74
|
+
const count = ref(0);
|
|
75
|
+
function increment() { count.value++; }
|
|
76
|
+
</script>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 三、API 调用规范检查
|
|
80
|
+
|
|
81
|
+
### 必须通过
|
|
82
|
+
|
|
83
|
+
- [ ] API 调用封装在 `src/api/` 目录的函数中,不在组件中直接写 `http.request`。
|
|
84
|
+
- [ ] 所有接口使用 POST 方法,参数通过 `data` 传递。
|
|
85
|
+
- [ ] 接口函数命名符合 `[动作][模块]Api` 格式。
|
|
86
|
+
- [ ] 接口参数和返回值有完整类型定义。
|
|
87
|
+
- [ ] 下载请求设置了 `responseType: "blob"`。
|
|
88
|
+
- [ ] 敏感数据(密码、身份证号)使用了加密请求 `crypto: true`。
|
|
89
|
+
- [ ] 组件中 API 调用有 `try/finally` 或 `try/catch` 处理异常。
|
|
90
|
+
|
|
91
|
+
### 常见错误示例
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// ❌ 错误:在组件中直接调用 http
|
|
95
|
+
const res = await http.request("post", "/api/user/list", { data: params });
|
|
96
|
+
|
|
97
|
+
// ✅ 正确:封装到 api/ 目录
|
|
98
|
+
// src/api/user.ts
|
|
99
|
+
export function getUserListApi(params: UserQuery) {
|
|
100
|
+
return http.request<Result<UserListResult>>("post", "/api/user/list", { data: params });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ❌ 错误:使用 GET 方法
|
|
104
|
+
http.request("get", "/api/user/list", { params });
|
|
105
|
+
|
|
106
|
+
// ✅ 正确:统一 POST
|
|
107
|
+
http.request("post", "/api/user/list", { data: params });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 四、安全规范检查
|
|
111
|
+
|
|
112
|
+
### 必须通过
|
|
113
|
+
|
|
114
|
+
- [ ] 不在前端代码中硬编码密钥、Token、密码。
|
|
115
|
+
- [ ] 用户输入在提交前做了前端校验(必填、格式、长度)。
|
|
116
|
+
- [ ] XSS 防护:用户输入展示使用 `v-text` 而非 `v-html`,除非已做消毒处理。
|
|
117
|
+
- [ ] 权限按钮使用 `v-auth` 指令控制,不手动判断角色。
|
|
118
|
+
- [ ] 敏感操作(删除、提交)有二次确认弹窗。
|
|
119
|
+
- [ ] 不在前端做安全校验(前端校验仅为体验优化,后端必须同步校验)。
|
|
120
|
+
|
|
121
|
+
### 安全检查清单
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// ❌ 危险:v-html 直接渲染用户输入
|
|
125
|
+
<div v-html="userInput" />
|
|
126
|
+
|
|
127
|
+
// ✅ 安全:使用 v-text 或 {{ }} 插值
|
|
128
|
+
<span v-text="userInput" />
|
|
129
|
+
<span>{{ userInput }}</span>
|
|
130
|
+
|
|
131
|
+
// ❌ 危险:硬编码密钥
|
|
132
|
+
const apiKey = "sk-abc123456";
|
|
133
|
+
|
|
134
|
+
// ✅ 安全:从环境变量或后端获取
|
|
135
|
+
const apiKey = import.meta.env.VITE_API_KEY;
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 五、性能检查
|
|
139
|
+
|
|
140
|
+
### 必须通过
|
|
141
|
+
|
|
142
|
+
- [ ] 页面组件使用 `() => import()` 懒加载。
|
|
143
|
+
- [ ] 列表数据量超过 100 行时使用了分页或虚拟滚动。
|
|
144
|
+
- [ ] 图表组件在 `onUnmounted` 中调用了 `dispose()`。
|
|
145
|
+
- [ ] 没有不必要的 `watch`(能用 `computed` 的场景不用 `watch`)。
|
|
146
|
+
- [ ] `v-for` 循环使用了唯一且稳定的 `:key`,不使用 `index` 作为 key(列表会变动时)。
|
|
147
|
+
- [ ] 大数组操作使用 `computed` 缓存结果,不在 template 中直接调用方法。
|
|
148
|
+
- [ ] 图片使用了懒加载(移动端 `van-image lazy-load`)。
|
|
149
|
+
- [ ] 事件监听器在组件卸载时正确移除(`onUnmounted` 中 `removeEventListener`)。
|
|
150
|
+
|
|
151
|
+
### 常见错误示例
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// ❌ 错误:watch 可以用 computed 替代
|
|
155
|
+
watch(searchText, () => {
|
|
156
|
+
filteredList.value = list.value.filter(item => item.name.includes(searchText.value));
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// ✅ 正确:使用 computed
|
|
160
|
+
const filteredList = computed(() =>
|
|
161
|
+
list.value.filter(item => item.name.includes(searchText.value))
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// ❌ 错误:template 中调用方法(每次渲染都执行)
|
|
165
|
+
<template>{{ getFullName(user) }}</template>
|
|
166
|
+
|
|
167
|
+
// ✅ 正确:使用 computed 缓存
|
|
168
|
+
const fullName = computed(() => `${user.firstName} ${user.lastName}`);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## 六、样式规范检查
|
|
172
|
+
|
|
173
|
+
### 必须通过
|
|
174
|
+
|
|
175
|
+
- [ ] 样式使用 `scoped`,不会污染全局。
|
|
176
|
+
- [ ] 颜色使用 CSS 变量(`var(--el-color-primary)`),不硬编码。
|
|
177
|
+
- [ ] 优先使用 UnoCSS 原子类(`flex-center`、`mb-4`)。
|
|
178
|
+
- [ ] 不使用 `!important`,除非覆盖第三方组件样式且有注释说明。
|
|
179
|
+
- [ ] 不使用深层嵌套选择器(不超过 3 层)。
|
|
180
|
+
- [ ] 移动端不使用固定 `px` 宽度,使用 `rem` 或百分比。
|
|
181
|
+
- [ ] 新增全局样式时,同步在 `dark.scss` 中添加暗黑模式覆盖。
|
|
182
|
+
- [ ] 不直接修改 `--el-color-primary`,而是通过 `setEpThemeColor()` 设置(保证色阶同步更新)。
|
|
183
|
+
- [ ] 使用 `chroma-js` 处理颜色,不使用 `color`、`polished` 等其他库。
|
|
184
|
+
- [ ] 侧边栏相关样式通过 `html[data-theme]` 选择器设置,不写在 `:root` 中。
|
|
185
|
+
- [ ] 覆盖 Element Plus 组件的全局样式放在 `src/styles/element-plus.scss`,不在组件内写。
|
|
186
|
+
|
|
187
|
+
## 七、业务逻辑检查
|
|
188
|
+
|
|
189
|
+
### 必须通过
|
|
190
|
+
|
|
191
|
+
- [ ] 表单提交前调用了 `validate()`。
|
|
192
|
+
- [ ] 删除操作有确认弹窗(`ElMessageBox.confirm` 或 `showConfirmDialog`)。
|
|
193
|
+
- [ ] 提交按钮有 `loading` 状态防止重复提交。
|
|
194
|
+
- [ ] 列表页有加载状态(`v-loading`)。
|
|
195
|
+
- [ ] 空数据有占位提示(`el-empty` 或 `van-empty`)。
|
|
196
|
+
- [ ] 编辑页正确加载并回显了已有数据。
|
|
197
|
+
- [ ] 路由跳转使用了正确的参数传递方式(`query` 而非 `params`)。
|
|
198
|
+
- [ ] 分页切换正确触发了数据加载。
|
|
199
|
+
|
|
200
|
+
## 八、代码风格检查
|
|
201
|
+
|
|
202
|
+
### 必须通过
|
|
203
|
+
|
|
204
|
+
- [ ] 使用 `const` / `let`,不使用 `var`。
|
|
205
|
+
- [ ] 字符串使用双引号(遵循 ESLint 配置),模板字符串用于变量拼接。
|
|
206
|
+
- [ ] 函数和变量使用驼峰命名。
|
|
207
|
+
- [ ] 组件名使用大驼峰(`UserList`),文件名使用短横线(`user-list.vue`)。
|
|
208
|
+
- [ ] 常量使用全大写下划线分隔(`MAX_PAGE_SIZE`)。
|
|
209
|
+
- [ ] 没有未使用的变量、导入或参数。
|
|
210
|
+
- [ ] 没有 `console.log` 残留(生产代码中)。
|
|
211
|
+
|
|
212
|
+
## 审查流程
|
|
213
|
+
|
|
214
|
+
1. **生成代码后**:逐项对照以上清单。
|
|
215
|
+
2. **发现问题**:立即修正,不要输出有问题的代码。
|
|
216
|
+
3. **不确定项**:标注 `// TODO: 需要确认` 注释提醒开发者。
|
|
217
|
+
4. **严重问题**:如果存在安全漏洞或类型错误,必须修正后再输出。
|
|
218
|
+
|
|
219
|
+
## 快速自检命令
|
|
220
|
+
|
|
221
|
+
完成代码修改后,运行以下命令验证:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# TypeScript 类型检查
|
|
225
|
+
npx vue-tsc --noEmit
|
|
226
|
+
|
|
227
|
+
# ESLint 检查
|
|
228
|
+
npx eslint src/ --ext .vue,.ts,.tsx
|
|
229
|
+
|
|
230
|
+
# Stylelint 检查
|
|
231
|
+
npx stylelint "src/**/*.{css,scss,vue}"
|
|
232
|
+
|
|
233
|
+
# 全量检查(推荐)
|
|
234
|
+
pnpm lint
|
|
235
|
+
```
|